diff --git a/ui/builder.html b/ui/builder.html index 8440a25..e3ee7db 100644 --- a/ui/builder.html +++ b/ui/builder.html @@ -13,240 +13,158 @@ --accent:#4f6ef7;--accent-bg:#eef0ff; --red:#ef4444;--red-bg:#fee2e2; --green:#16a34a;--green-bg:#dcfce7; - --amber:#d97706; - --l1:#4f6ef7;--l1-bg:#eef0ff; - --l2:#8b5cf6;--l2-bg:#f5f0ff; - --l3:#d97706;--l3-bg:#fffbeb; + --l1:#4f6ef7;--l2:#8b5cf6;--l3:#d97706; --r:8px;--sh:0 1px 3px rgba(0,0,0,.08),0 1px 2px rgba(0,0,0,.05); - --sh2:0 4px 12px rgba(0,0,0,.08); - /* dark */ --dk:#1e1e2e;--dk2:#181825;--dk3:#313244;--dk4:#45475a; --dt:#cdd6f4;--dt2:#bac2de;--dt3:#6c7086; } body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);height:100vh;overflow:hidden;display:flex;flex-direction:column;font-size:14px} -/* ── 헤더 ─────────────────────────────────────────────────── */ -.app-header{ - background:var(--surface);border-bottom:1px solid var(--border); - padding:10px 16px;display:flex;align-items:center;gap:10px; - box-shadow:var(--sh);z-index:10;flex-shrink:0 -} +/* ── 헤더 ─────────────────────────────────── */ +.app-header{background:var(--surface);border-bottom:1px solid var(--border);padding:10px 16px;display:flex;align-items:center;gap:10px;box-shadow:var(--sh);z-index:10;flex-shrink:0} .app-header h1{font-size:15px;font-weight:600} .badge{font-size:10px;background:var(--accent-bg);color:var(--accent);padding:2px 7px;border-radius:99px;font-weight:600} .hdr-spacer{flex:1} -.hdr-btn{ - display:flex;align-items:center;gap:5px; - font-size:12px;padding:5px 12px;border-radius:6px;cursor:pointer; - border:1px solid var(--border);background:var(--surface);color:var(--muted); - transition:all .15s;font-weight:500 -} +.hdr-btn{display:flex;align-items:center;gap:5px;font-size:12px;padding:5px 12px;border-radius:6px;cursor:pointer;border:1px solid var(--border);background:var(--surface);color:var(--muted);transition:all .15s;font-weight:500} .hdr-btn:hover{background:var(--surface-alt);color:var(--text);border-color:var(--border-focus)} -/* ── 메인 레이아웃 ────────────────────────────────────────── */ +/* ── 레이아웃 ─────────────────────────────── */ .app-body{display:flex;flex:1;overflow:hidden} - -/* ── 빌더 패널 ────────────────────────────────────────────── */ -.builder-panel{ - width:440px;min-width:320px;background:var(--surface); - border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden -} -.panel-label{ - padding:10px 16px 8px;font-size:10px;font-weight:700; - text-transform:uppercase;letter-spacing:.08em;color:var(--muted); - border-bottom:1px solid var(--border);flex-shrink:0;background:var(--surface-alt) -} +.builder-panel{width:460px;min-width:340px;background:var(--surface);border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden} +.panel-label{padding:10px 16px 8px;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);border-bottom:1px solid var(--border);flex-shrink:0;background:var(--surface-alt)} .builder-scroll{flex:1;overflow-y:auto;padding:14px} .builder-scroll::-webkit-scrollbar{width:5px} .builder-scroll::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px} -/* ── 설정 카드 ───────────────────────────────────────────── */ -.config-card{ - background:var(--surface-alt);border:1px solid var(--border); - border-radius:var(--r);padding:11px 13px;margin-bottom:14px -} -.config-card-title{ - font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em; - color:var(--muted);margin-bottom:10px;display:flex;align-items:center;gap:5px;cursor:pointer -} +/* ── 구분자 설정 카드 ─────────────────────── */ +.config-card{background:var(--surface-alt);border:1px solid var(--border);border-radius:var(--r);padding:11px 13px;margin-bottom:14px} +.config-card-title{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);margin-bottom:10px;display:flex;align-items:center;gap:5px} .config-row{display:flex;align-items:center;gap:8px;margin-bottom:8px} .config-row:last-child{margin-bottom:0} .config-lbl{font-size:12px;color:var(--muted);width:48px;flex-shrink:0} -.mark-input{ - width:56px;text-align:center;font-size:15px;border:1px solid var(--border); - border-radius:6px;padding:3px 6px;background:var(--surface);cursor:text -} +.mark-input{width:56px;text-align:center;font-size:15px;border:1px solid var(--border);border-radius:6px;padding:3px 6px;background:var(--surface)} .marks-wrap{display:flex;flex-wrap:wrap;gap:5px;flex:1} -.mark-chip{ - display:flex;align-items:center;gap:3px;background:var(--surface); - border:1px solid var(--border);border-radius:6px;padding:2px 5px -} +.mark-chip{display:flex;align-items:center;gap:3px;background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:2px 5px} .mark-chip .lvl{font-size:9px;color:var(--muted);font-weight:700} .mark-chip input{width:46px;font-size:14px;border:none;outline:none;text-align:center;background:transparent} .mark-chip .rm{cursor:pointer;color:var(--muted);font-size:11px;padding:0 2px;line-height:1} .mark-chip .rm:hover{color:var(--red)} -.btn-add-mark{ - font-size:11px;padding:3px 9px;background:var(--accent-bg);color:var(--accent); - border:1px dashed var(--accent);border-radius:6px;cursor:pointer;font-weight:600;align-self:center -} +.btn-add-mark{font-size:11px;padding:3px 9px;background:var(--accent-bg);color:var(--accent);border:1px dashed var(--accent);border-radius:6px;cursor:pointer;font-weight:600;align-self:center} .btn-add-mark:hover{background:var(--accent);color:#fff;border-style:solid} -/* ── 제목 입력 ────────────────────────────────────────────── */ +/* ── 제목 입력 ────────────────────────────── */ .field-label{font-size:11px;font-weight:600;color:var(--muted);margin-bottom:5px;letter-spacing:.04em;text-transform:uppercase} -.title-wrap{ - display:flex;align-items:center;gap:7px;background:var(--surface-alt); - border:1.5px solid var(--border);border-radius:var(--r);padding:7px 11px; - margin-bottom:14px;transition:border-color .15s -} +.title-wrap{display:flex;align-items:center;gap:7px;background:var(--surface-alt);border:1.5px solid var(--border);border-radius:var(--r);padding:7px 11px;margin-bottom:14px;transition:border-color .15s} .title-wrap:focus-within{border-color:var(--border-focus);background:var(--surface)} .title-mark{font-size:16px;flex-shrink:0} .title-wrap input{border:none;outline:none;font-size:13px;flex:1;background:transparent;font-weight:500} .title-wrap input::placeholder{color:var(--muted);font-weight:400} -/* ── 섹션 추가 버튼 ───────────────────────────────────────── */ -.btn-add-sec{ - display:flex;align-items:center;justify-content:center;gap:7px; - width:100%;padding:9px;background:var(--accent-bg);color:var(--accent); - border:1.5px dashed var(--accent);border-radius:var(--r);cursor:pointer; - font-size:12px;font-weight:600;margin-bottom:12px;transition:all .15s -} +/* ── 버튼 ─────────────────────────────────── */ +.btn-add-sec{display:flex;align-items:center;justify-content:center;gap:7px;width:100%;padding:9px;background:var(--accent-bg);color:var(--accent);border:1.5px dashed var(--accent);border-radius:var(--r);cursor:pointer;font-size:12px;font-weight:600;margin-bottom:12px;transition:all .15s} .btn-add-sec:hover{background:var(--accent);color:#fff;border-style:solid} - -/* ── 섹션 카드 ────────────────────────────────────────────── */ -.sec-list{display:flex;flex-direction:column;gap:9px} -.sec-card{ - border:1.5px solid var(--border);border-radius:var(--r); - background:var(--surface);box-shadow:var(--sh);overflow:visible -} -.sec-card[data-level="1"]{border-left:3px solid var(--l1)} -.sec-card[data-level="2"]{border-left:3px solid var(--l2);margin-left:14px} -.sec-card[data-level="3"]{border-left:3px solid var(--l3);margin-left:28px} -.sec-head{ - display:flex;align-items:center;gap:7px;padding:7px 9px; - background:var(--surface-alt);border-bottom:1px solid var(--border) -} -.sec-mark{font-size:13px;flex-shrink:0} -.sec-name{ - flex:1;border:none;outline:none;font-size:13px;font-weight:500; - background:transparent;min-width:0 -} -.sec-name::placeholder{color:var(--muted);font-weight:400} -.iBtn{ - width:22px;height:22px;display:flex;align-items:center;justify-content:center; - border-radius:4px;border:none;cursor:pointer;font-size:12px; - background:transparent;color:var(--muted);transition:all .1s;flex-shrink:0 -} +.iBtn{width:22px;height:22px;display:flex;align-items:center;justify-content:center;border-radius:4px;border:none;cursor:pointer;font-size:12px;background:transparent;color:var(--muted);transition:all .1s;flex-shrink:0} .iBtn:hover{background:var(--red-bg);color:var(--red)} .iBtn.up:hover,.iBtn.dn:hover{background:var(--accent-bg);color:var(--accent)} -.sec-body{padding:9px} - -/* ── 이름 그룹 ────────────────────────────────────────────── */ -.grp{border:1px solid var(--border);border-radius:6px;padding:8px;margin-bottom:7px;background:var(--surface-alt)} -.grp-head{display:flex;align-items:center;gap:6px;margin-bottom:6px} -.grp-cat-lbl{font-size:10px;color:var(--muted);flex-shrink:0;font-weight:600;text-transform:uppercase;letter-spacing:.04em} -.grp-cat{ - flex:1;font-size:12px;border:1px solid var(--border); - border-radius:4px;padding:3px 7px;background:var(--surface) -} -.grp-cat:focus{outline:none;border-color:var(--border-focus)} -.grp-cat::placeholder{color:var(--muted)} -.grp-names{ - width:100%;min-height:44px;font-size:12px;border:1px solid var(--border); - border-radius:4px;padding:5px 7px;resize:vertical;font-family:inherit; - background:var(--surface);line-height:1.55; -} -.grp-names:focus{outline:none;border-color:var(--border-focus)} -.grp-hint{font-size:10px;color:var(--muted);margin-top:3px} - -/* ── 그룹 옵션 (구분자 / 한 줄) ─────────────────────────── */ -.grp-opts{display:flex;flex-direction:column;gap:5px;margin-top:6px;padding-top:6px;border-top:1px dashed var(--border)} -.opt-row{display:flex;align-items:center;gap:6px} -.opt-lbl{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);width:40px;flex-shrink:0} -.sep-chips{display:flex;gap:3px;flex-wrap:wrap} -.sep-chip{ - font-size:11px;padding:2px 8px;border-radius:4px;border:1px solid var(--border); - background:var(--surface);color:var(--muted);cursor:pointer;font-weight:500; - transition:all .1s;white-space:nowrap -} -.sep-chip:hover{border-color:var(--accent);color:var(--accent)} -.sep-chip.on{background:var(--accent);color:#fff;border-color:var(--accent)} -.sep-custom{ - width:52px;font-size:11px;border:1px solid var(--border);border-radius:4px; - padding:2px 5px;background:var(--surface);text-align:center -} -.sep-custom:focus{outline:none;border-color:var(--border-focus)} -.npl-input{ - width:46px;font-size:12px;border:1px solid var(--border);border-radius:4px; - padding:2px 5px;text-align:center;background:var(--surface) -} -.npl-input:focus{outline:none;border-color:var(--border-focus)} -.npl-input:disabled{background:var(--surface-alt);color:var(--muted)} - -/* ── 섹션 하단 액션 ──────────────────────────────────────── */ -.sec-actions{display:flex;gap:5px;flex-wrap:wrap;padding-top:2px} -.sBtn{ - font-size:11px;padding:3px 9px;border-radius:4px;border:1px solid; - cursor:pointer;font-weight:600;transition:all .12s -} +.sBtn{font-size:11px;padding:3px 9px;border-radius:4px;border:1px solid;cursor:pointer;font-weight:600;transition:all .12s} .sBtn.blue{background:var(--accent-bg);color:var(--accent);border-color:var(--accent)} .sBtn.blue:hover{background:var(--accent);color:#fff} .sBtn.green{background:var(--green-bg);color:var(--green);border-color:var(--green)} .sBtn.green:hover{background:var(--green);color:#fff} + +/* ── 섹션 카드 ────────────────────────────── */ +.sec-list{display:flex;flex-direction:column;gap:9px} +.sec-card{border:1.5px solid var(--border);border-radius:var(--r);background:var(--surface);box-shadow:var(--sh);overflow:visible} +.sec-card[data-level="1"]{border-left:3px solid var(--l1)} +.sec-card[data-level="2"]{border-left:3px solid var(--l2);margin-left:14px} +.sec-card[data-level="3"]{border-left:3px solid var(--l3);margin-left:28px} +.sec-head{display:flex;align-items:center;gap:7px;padding:7px 9px;background:var(--surface-alt);border-bottom:1px solid var(--border)} +.sec-mark{font-size:13px;flex-shrink:0} +.sec-name-input{flex:1;border:none;outline:none;font-size:13px;font-weight:500;background:transparent;min-width:0} +.sec-name-input::placeholder{color:var(--muted);font-weight:400} +.sec-body{padding:9px} +.sec-actions{display:flex;gap:5px;flex-wrap:wrap;margin-top:2px} .children-list{display:flex;flex-direction:column;gap:8px;margin-top:9px} -/* ── 미리보기 패널 ────────────────────────────────────────── */ +/* ── 그룹(LIST) 카드 ──────────────────────── */ +.grp{border:1px solid var(--border);border-radius:6px;padding:8px;margin-bottom:7px;background:var(--surface-alt)} +.grp-head{display:flex;align-items:center;gap:6px;margin-bottom:6px} +.grp-type-badge{font-size:10px;font-weight:700;color:var(--muted);background:var(--surface);border:1px solid var(--border);border-radius:4px;padding:1px 6px;text-transform:uppercase;letter-spacing:.04em} +.grp-cat-badge{font-size:11px;color:var(--accent);background:var(--accent-bg);border-radius:4px;padding:1px 7px;font-weight:600;white-space:nowrap;max-width:100px;overflow:hidden;text-overflow:ellipsis} +.grp-names{width:100%;min-height:44px;font-size:12px;border:1px solid var(--border);border-radius:4px;padding:5px 7px;resize:vertical;font-family:inherit;background:var(--surface);line-height:1.55} +.grp-names:focus{outline:none;border-color:var(--border-focus)} + +/* ── 구분자 / 한 줄 옵션 ──────────────────── */ +.grp-opts{display:flex;flex-direction:column;gap:5px;margin-top:6px;padding-top:6px;border-top:1px dashed var(--border)} +.opt-row{display:flex;align-items:center;gap:6px} +.opt-lbl{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);width:40px;flex-shrink:0} +.sep-chips{display:flex;gap:3px;flex-wrap:wrap} +.sep-chip{font-size:11px;padding:2px 8px;border-radius:4px;border:1px solid var(--border);background:var(--surface);color:var(--muted);cursor:pointer;font-weight:500;transition:all .1s;white-space:nowrap} +.sep-chip:hover{border-color:var(--accent);color:var(--accent)} +.sep-chip.on{background:var(--accent);color:#fff;border-color:var(--accent)} +.sep-custom{width:52px;font-size:11px;border:1px solid var(--border);border-radius:4px;padding:2px 5px;background:var(--surface);text-align:center} +.sep-custom:focus{outline:none;border-color:var(--border-focus)} +.npl-input{width:46px;font-size:12px;border:1px solid var(--border);border-radius:4px;padding:2px 5px;text-align:center;background:var(--surface)} +.npl-input:focus{outline:none;border-color:var(--border-focus)} +.npl-input:disabled{background:var(--surface-alt);color:var(--muted)} + +/* ── 노드 설정 패널 ───────────────────────── */ +.node-settings{margin:6px 0} +.ns-toggle{ + display:flex;align-items:center;gap:5px;padding:5px 9px; + font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase; + color:var(--muted);cursor:pointer;background:var(--surface-alt); + border:1px solid var(--border);border-radius:5px;transition:all .12s;user-select:none +} +.ns-toggle:hover{color:var(--accent);border-color:var(--accent);background:var(--accent-bg)} +.ns-toggle.open{border-radius:5px 5px 0 0;border-bottom-color:transparent;color:var(--accent);background:var(--accent-bg);border-color:var(--accent)} +.ns-arrow{font-size:8px;transition:transform .15s} +.ns-dot{width:6px;height:6px;border-radius:50%;background:var(--accent);flex-shrink:0} +.ns-body{border:1px solid var(--accent);border-top:none;border-radius:0 0 5px 5px;background:var(--surface);padding:10px;display:flex;flex-direction:column;gap:10px} +.ns-section{} +.ns-section-lbl{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);margin-bottom:6px;display:flex;align-items:center;justify-content:space-between} +.ns-deco-grid{display:grid;grid-template-columns:1fr 1fr;gap:5px} +.ns-field{display:flex;flex-direction:column;gap:2px} +.ns-field-lbl{font-size:10px;color:var(--muted)} +.ns-field-inp{font-size:12px;border:1px solid var(--border);border-radius:4px;padding:3px 6px;background:var(--surface-alt)} +.ns-field-inp:focus{outline:none;border-color:var(--border-focus);background:#fff} +.ns-attr-row{display:flex;gap:4px;margin-bottom:4px;align-items:center} +.ns-attr-key{width:90px;font-size:12px;border:1px solid var(--border);border-radius:4px;padding:3px 6px;background:var(--surface-alt)} +.ns-attr-val{flex:1;font-size:12px;border:1px solid var(--border);border-radius:4px;padding:3px 6px;background:var(--surface-alt)} +.ns-attr-key:focus,.ns-attr-val:focus{outline:none;border-color:var(--border-focus);background:#fff} +.ns-empty{font-size:11px;color:var(--muted);font-style:italic;padding:2px 0} +.ns-value-row{display:flex;gap:6px;align-items:center} +.ns-dtype{flex:0 0 auto;min-width:130px;font-size:12px;border:1px solid var(--border);border-radius:4px;padding:3px 6px;background:var(--surface-alt)} +.ns-dtype:focus{outline:none;border-color:var(--border-focus)} +.ns-value-inp{flex:1;font-size:12px;border:1px solid var(--border);border-radius:4px;padding:3px 6px;background:var(--surface-alt)} +.ns-value-inp:focus{outline:none;border-color:var(--border-focus);background:#fff} +.ns-add-btn{font-size:10px;padding:1px 7px} + +/* ── 미리보기 패널 ────────────────────────── */ .preview-panel{flex:1;display:flex;flex-direction:column;overflow:hidden;background:var(--dk)} -.preview-head{ - display:flex;align-items:center;gap:7px;padding:9px 14px; - background:var(--dk2);border-bottom:1px solid var(--dk3);flex-shrink:0 -} +.preview-head{display:flex;align-items:center;gap:7px;padding:9px 14px;background:var(--dk2);border-bottom:1px solid var(--dk3);flex-shrink:0} .tabs{display:flex;gap:2px} -.tab{ - font-size:12px;padding:4px 11px;border-radius:5px;cursor:pointer; - color:var(--dt3);border:none;background:transparent;font-weight:500;transition:all .15s -} +.tab{font-size:12px;padding:4px 11px;border-radius:5px;cursor:pointer;color:var(--dt3);border:none;background:transparent;font-weight:500;transition:all .15s} .tab.active{background:var(--dk3);color:var(--dt)} .p-spacer{flex:1} -.copy-btn{ - display:flex;align-items:center;gap:5px;font-size:12px; - padding:5px 11px;background:var(--dk3);color:var(--dt2); - border:1px solid var(--dk4);border-radius:6px;cursor:pointer;transition:all .15s;font-weight:500 -} +.copy-btn{display:flex;align-items:center;gap:5px;font-size:12px;padding:5px 11px;background:var(--dk3);color:var(--dt2);border:1px solid var(--dk4);border-radius:6px;cursor:pointer;transition:all .15s;font-weight:500} .copy-btn:hover{background:var(--dk4)} .copy-btn.ok{background:#1a3a2a;color:#a6e3a1;border-color:#a6e3a1} .preview-body{flex:1;overflow-y:auto;padding:20px 22px} .preview-body::-webkit-scrollbar{width:5px} .preview-body::-webkit-scrollbar-track{background:var(--dk)} .preview-body::-webkit-scrollbar-thumb{background:var(--dk4);border-radius:3px} -.preview-text{ - font-family:'Cascadia Code','Fira Code','Consolas',monospace; - font-size:13px;line-height:1.75;color:var(--dt);white-space:pre-wrap;word-break:break-word -} +.preview-text{font-family:'Cascadia Code','Fira Code','Consolas',monospace;font-size:13px;line-height:1.75;color:var(--dt);white-space:pre-wrap;word-break:break-word} .preview-text.dim{color:var(--dt3);font-style:italic} +.j-key{color:#89b4fa}.j-str{color:#a6e3a1}.j-num{color:#fab387}.j-bool{color:#f38ba8}.j-null{color:#f38ba8;font-style:italic} -/* JSON 색상 */ -.j-key{color:#89b4fa} -.j-str{color:#a6e3a1} -.j-num{color:#fab387} -.j-bool{color:#f38ba8} -.j-null{color:#f38ba8;font-style:italic} - -/* ── 모달 ──────────────────────────────────────────────────── */ -.overlay{ - position:fixed;inset:0;background:rgba(0,0,0,.45); - display:none;align-items:center;justify-content:center;z-index:200 -} +/* ── 모달 ──────────────────────────────────── */ +.overlay{position:fixed;inset:0;background:rgba(0,0,0,.45);display:none;align-items:center;justify-content:center;z-index:200} .overlay.open{display:flex} -.modal{ - background:var(--surface);border-radius:12px;padding:20px; - width:500px;max-width:92vw;box-shadow:0 20px 60px rgba(0,0,0,.25) -} +.modal{background:var(--surface);border-radius:12px;padding:20px;width:500px;max-width:92vw;box-shadow:0 20px 60px rgba(0,0,0,.25)} .modal h2{font-size:15px;font-weight:700;margin-bottom:6px} .modal p{font-size:12px;color:var(--muted);margin-bottom:10px} -.modal textarea{ - width:100%;height:200px;font-family:monospace;font-size:12px; - border:1.5px solid var(--border);border-radius:6px;padding:9px; - resize:vertical;line-height:1.6 -} +.modal textarea{width:100%;height:200px;font-family:monospace;font-size:12px;border:1.5px solid var(--border);border-radius:6px;padding:9px;resize:vertical;line-height:1.6} .modal textarea:focus{outline:none;border-color:var(--border-focus)} .modal-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:12px} .mBtn{font-size:13px;padding:7px 16px;border-radius:6px;border:1px solid;cursor:pointer;font-weight:600} @@ -254,10 +172,8 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;backgrou .mBtn.ok:hover{background:#3a5ce0} .mBtn.cancel{background:var(--surface);color:var(--muted);border-color:var(--border)} .mBtn.cancel:hover{background:var(--surface-alt)} - -/* ── 분리선 ────────────────────────────────────────────────── */ .sep{height:1px;background:var(--border);margin:12px 0} -input,textarea,button{font-family:inherit} +input,textarea,button,select{font-family:inherit}
@@ -265,7 +181,7 @@ input,textarea,button{font-family:inherit}