refactor: 작업실 HTML에서 CSS·JS를 별도 파일로 분리 — 내용 변경 없음
- web-ui/html/workshop-app.html 147KB → 9KB (구조만) - web-ui/css/workshop-app.css(24KB), web-ui/js/app/workshop-app.js(114KB, classic script라 인라인 onclick 전역 핸들러 그대로) - 분리 내용은 바이트 단위로 원문과 동일함을 검증, 실브라우저 하네스 38개 항목 통과 - vm 저장 로직 테스트는 분리된 JS를 읽도록 변경, 조립 하네스 기본 경로를 폴더 정돈 후 위치로 갱신 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ import http from 'http';
|
||||
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'asmui-'));
|
||||
process.env.SMALLCLAW_DATA_DIR = tmp;
|
||||
const OUT = process.env.SHOT_DIR || '/tmp';
|
||||
const SRC_SCAD = process.env.SRC_SCAD || '/srv/homeclaw/.smallclaw/users/papa/workspace/workshop/proj_scan_dental/CAD/print/scanner-rig.scad';
|
||||
const SRC_SCAD = process.env.SRC_SCAD || '/srv/homeclaw/.smallclaw/users/papa/workspace/workshop/proj_scan_dental/CAD/scanner-rig.scad';
|
||||
(async () => {
|
||||
const { registerWorkshopRoutes } = await import('../../src/gateway/routes/routes-workshop');
|
||||
const { chromium } = require('playwright-core');
|
||||
|
||||
@@ -142,9 +142,9 @@ describe('workshop_project 도구', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ── 프런트엔드 저장 로직(workshop-app.html 상태/저장 구간을 vm으로 실행) ──────────────
|
||||
describe('workshop-app.html 저장 로직', () => {
|
||||
const html = fs.readFileSync(path.join(__dirname, '../web-ui/html/workshop-app.html'), 'utf-8').split('\n');
|
||||
// ── 프런트엔드 저장 로직(workshop-app.js 상태/저장 구간을 vm으로 실행) ──────────────
|
||||
describe('workshop-app.js 저장 로직', () => {
|
||||
const html = fs.readFileSync(path.join(__dirname, '../web-ui/js/app/workshop-app.js'), 'utf-8').split('\n'); // 2026-09-25 HTML에서 분리된 스크립트
|
||||
const start = html.findIndex(l => l.startsWith('function escAttr'));
|
||||
const from = html.findIndex(l => l.startsWith('let workshopData='));
|
||||
const to = html.findIndex(l => l.startsWith('// ── Tabs'));
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
/* 작업실 앱 스타일 — workshop-app.html에서 분리(2026-09-25, 내용 변경 없음). */
|
||||
html,body{height:100%;margin:0;padding:0;}
|
||||
body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;display:flex;flex-direction:column;overflow:hidden;height:100dvh;}
|
||||
|
||||
.rb-hdr{display:flex;align-items:center;gap:8px;padding:6px 12px;background:var(--panel);border-bottom:1px solid var(--line);flex-shrink:0;}
|
||||
.rb-hdr h1{font-size:13px;font-weight:700;margin:0;}
|
||||
.rb-hdr-sp{flex:1;}
|
||||
.hdr-btn{background:none;border:1.5px solid var(--line);border-radius:6px;padding:3px 9px;font-size:11px;color:var(--muted);cursor:pointer;font-family:inherit;transition:.15s;}
|
||||
.hdr-btn:hover{border-color:#f59e0b;color:#f59e0b;}
|
||||
.rb-save-indicator{font-size:10px;color:var(--muted);transition:.3s;flex-shrink:0;}
|
||||
.ws-project-select{background:var(--panel-2);border:1px solid var(--line);border-radius:6px;padding:4px 8px;font-size:12px;font-weight:700;color:var(--text);font-family:inherit;outline:none;max-width:220px;}
|
||||
.ws-project-select:focus{border-color:#f59e0b;}
|
||||
|
||||
.rb-budget{display:flex;gap:0;border-bottom:1px solid var(--line);background:var(--panel);flex-shrink:0;flex-wrap:wrap;}
|
||||
.rb-budget-item{flex:1;min-width:120px;padding:8px 14px;border-right:1px solid var(--line);}
|
||||
.rb-budget-item:last-child{border-right:none;}
|
||||
.rb-budget-item.total{background:rgba(245,158,11,.06);}
|
||||
.rb-budget-target{display:flex;align-items:center;gap:4px;margin-top:2px;}
|
||||
.rb-budget-target input{width:110px;background:var(--panel-2);border:1px solid var(--line);border-radius:5px;padding:2px 6px;font-size:13px;font-weight:700;color:var(--text);font-family:inherit;outline:none;}
|
||||
.rb-budget-target input:focus{border-color:#f59e0b;}
|
||||
.rb-gauge{height:5px;background:var(--line);border-radius:3px;overflow:hidden;margin-top:6px;}
|
||||
.rb-gauge>i{display:block;height:100%;width:0;background:#22c55e;transition:width .3s,background .3s;}
|
||||
.rb-gauge.warn>i{background:#f59e0b;}
|
||||
.rb-gauge.over>i{background:#ef4444;}
|
||||
.rb-gauge-text{font-size:10px;color:var(--muted);margin-top:3px;}
|
||||
.rb-gauge-text.over{color:#ef4444;font-weight:700;}
|
||||
.rb-budget-label{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;}
|
||||
.rb-budget-val{font-size:15px;font-weight:700;margin-top:2px;}
|
||||
|
||||
.rb-layout{flex:1;display:flex;min-height:0;overflow:hidden;}
|
||||
.rb-main{flex:1;display:flex;flex-direction:column;min-width:0;overflow:hidden;}
|
||||
|
||||
.rb-tabs{display:flex;border-bottom:1px solid var(--line);background:var(--panel);flex-shrink:0;padding:0 14px;}
|
||||
.rb-tab-btn{background:none;border:none;border-bottom:2px solid transparent;padding:8px 14px;font-size:12px;font-weight:600;color:var(--muted);cursor:pointer;font-family:inherit;transition:.15s;margin-bottom:-1px;}
|
||||
.rb-tab-btn.active{color:#f59e0b;border-bottom-color:#f59e0b;}
|
||||
.rb-tab-btn:hover:not(.active){color:var(--text);}
|
||||
.rb-body{flex:1;overflow-y:auto;padding:14px;min-height:0;}
|
||||
.rb-pane{display:none;}
|
||||
.rb-pane.active{display:block;}
|
||||
|
||||
/* ── 채팅 패널 ── */
|
||||
.rb-resize{width:4px;flex-shrink:0;background:var(--line);cursor:col-resize;transition:.15s;}
|
||||
.rb-resize:hover,.rb-resize.dragging{background:#f59e0b;}
|
||||
.rb-chat{width:340px;flex-shrink:0;display:flex;flex-direction:column;border-left:1px solid var(--line);background:var(--panel);min-height:0;}
|
||||
.rb-chat-hdr{display:flex;align-items:center;padding:6px 10px;border-bottom:1px solid var(--line);flex-shrink:0;gap:6px;}
|
||||
.rb-chat-label{font-size:10px;font-weight:700;color:#f59e0b;text-transform:uppercase;letter-spacing:.07em;flex-shrink:0;}
|
||||
.rb-chat-clear{background:none;border:none;cursor:pointer;font-size:14px;color:var(--muted);padding:2px 4px;transition:.12s;flex-shrink:0;}
|
||||
.rb-chat-clear:hover{color:#ef4444;}
|
||||
.rb-msgs{flex:1;overflow-y:auto;padding:10px;display:flex;flex-direction:column;gap:8px;}
|
||||
.rb-msgs::-webkit-scrollbar{width:3px;}
|
||||
.rb-msgs::-webkit-scrollbar-thumb{background:var(--line);border-radius:3px;}
|
||||
.rb-msg{display:flex;flex-direction:column;}
|
||||
.rb-msg.user{align-items:flex-end;}
|
||||
.rb-msg.assistant{align-items:flex-start;}
|
||||
.rb-msg.system{align-items:center;}
|
||||
.rb-bubble{padding:7px 11px;border-radius:10px;font-size:12px;line-height:1.55;max-width:93%;word-break:break-word;}
|
||||
.rb-msg.user .rb-bubble{background:#3d2c05;color:#fde9b8;border-radius:10px 10px 3px 10px;}
|
||||
.rb-msg.assistant .rb-bubble{background:var(--panel-2);border:1px solid var(--line);border-radius:10px 10px 10px 3px;}
|
||||
.rb-msg.system .rb-bubble{background:transparent;color:var(--muted);font-size:11px;}
|
||||
.rb-bubble p{margin:3px 0;}
|
||||
.rb-bubble h3{font-size:13px;margin:6px 0 3px;}
|
||||
.rb-bubble ul,.rb-bubble ol{padding-left:16px;margin:3px 0;}
|
||||
.rb-bubble pre{background:var(--bg);border:1px solid var(--line);border-radius:6px;padding:8px;overflow-x:auto;font-size:11px;margin:6px 0;}
|
||||
.rb-bubble strong{font-weight:700;}
|
||||
.rb-typing{display:flex;gap:3px;align-items:center;padding:6px 10px;}
|
||||
.rb-dot{width:5px;height:5px;background:var(--muted);border-radius:50%;animation:rbDot 1.2s ease-in-out infinite;}
|
||||
.rb-dot:nth-child(2){animation-delay:.2s;}.rb-dot:nth-child(3){animation-delay:.4s;}
|
||||
@keyframes rbDot{0%,80%,100%{transform:scale(.5);opacity:.4;}40%{transform:scale(1);opacity:1;}}
|
||||
.rb-input-bar{flex-shrink:0;padding:8px;border-top:1px solid var(--line);display:flex;gap:6px;align-items:flex-end;}
|
||||
.rb-textarea{flex:1;background:var(--panel-2);border:1px solid var(--line);border-radius:8px;padding:7px 10px;font-size:12px;color:var(--text);font-family:inherit;resize:none;min-height:34px;max-height:120px;outline:none;transition:.15s;}
|
||||
.rb-textarea:focus{border-color:#f59e0b;}
|
||||
.rb-send{background:#7c4a03;border:none;border-radius:8px;padding:7px 13px;font-size:12px;color:#fff;cursor:pointer;font-family:inherit;font-weight:700;transition:.15s;flex-shrink:0;}
|
||||
.rb-send:hover:not(:disabled){background:#9a5c03;}
|
||||
.rb-send:disabled{opacity:.5;cursor:not-allowed;}
|
||||
|
||||
.rb-model-pill{position:relative;flex-shrink:0;}
|
||||
.rb-model-pill-btn{background:none;border:1px solid var(--line);border-radius:6px;padding:2px 8px;font-size:10px;font-weight:700;color:var(--muted);cursor:pointer;font-family:inherit;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:.15s;}
|
||||
.rb-model-pill-btn:hover{border-color:#f59e0b;color:#f59e0b;}
|
||||
.rb-model-dropdown{display:none;position:absolute;top:100%;right:0;margin-top:4px;background:var(--panel-2);border:1px solid var(--line);border-radius:8px;box-shadow:0 4px 16px rgba(0,0,0,.35);min-width:200px;max-height:280px;overflow-y:auto;z-index:50;padding:4px;}
|
||||
.rb-model-dropdown.open{display:block;}
|
||||
.rb-model-opt{padding:6px 10px;font-size:12px;border-radius:5px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--text);}
|
||||
.rb-model-opt:hover{background:var(--panel);}
|
||||
.rb-model-opt.current{color:#f59e0b;font-weight:700;}
|
||||
.rb-model-dropdown-msg{padding:6px 10px;font-size:11px;color:var(--muted);}
|
||||
|
||||
/* ── 충돌 배너 / 모달 / 부품 표·툴바 / 진행률 (2026-09-24 업그레이드) ── */
|
||||
.rb-conflict{display:none;background:rgba(239,68,68,.12);border-bottom:1px solid rgba(239,68,68,.4);padding:7px 14px;font-size:12px;color:#fca5a5;align-items:center;gap:10px;flex-wrap:wrap;flex-shrink:0;}
|
||||
.rb-conflict b{color:#fecaca;}
|
||||
.rb-conflict button{background:none;border:1px solid rgba(239,68,68,.6);border-radius:6px;padding:3px 10px;font-size:11px;color:#fecaca;cursor:pointer;font-family:inherit;}
|
||||
.rb-conflict button:hover{background:rgba(239,68,68,.25);}
|
||||
.rb-modal-bg{display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:200;align-items:center;justify-content:center;padding:16px;}
|
||||
.rb-modal-bg.open{display:flex;}
|
||||
.rb-modal{background:var(--panel);border:1px solid var(--line);border-radius:12px;width:min(560px,100%);max-height:80dvh;display:flex;flex-direction:column;box-shadow:0 12px 40px rgba(0,0,0,.5);}
|
||||
.rb-modal-hdr{display:flex;align-items:center;padding:12px 16px;border-bottom:1px solid var(--line);font-size:13px;font-weight:700;}
|
||||
.rb-modal-hdr button{margin-left:auto;background:none;border:none;color:var(--muted);font-size:16px;cursor:pointer;}
|
||||
.rb-modal-body{padding:12px 16px;overflow-y:auto;font-size:12px;}
|
||||
.rb-modal-body h4{margin:12px 0 6px;font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;}
|
||||
.rb-modal-body h4:first-child{margin-top:0;}
|
||||
.rb-hist-row{display:flex;align-items:center;gap:10px;padding:7px 0;border-bottom:1px solid var(--line);}
|
||||
.rb-hist-row:last-child{border-bottom:none;}
|
||||
.rb-hist-row .when{font-weight:600;min-width:130px;}
|
||||
.rb-hist-row .sum{flex:1;color:var(--muted);font-size:11px;}
|
||||
.rb-hist-row button{background:none;border:1px solid var(--line);border-radius:6px;padding:3px 10px;font-size:11px;color:var(--muted);cursor:pointer;font-family:inherit;}
|
||||
.rb-hist-row button:hover{border-color:#f59e0b;color:#f59e0b;}
|
||||
.rb-empty{color:var(--muted);padding:10px 0;font-size:12px;}
|
||||
.rb-parts-bar{display:flex;gap:8px;align-items:center;margin-bottom:10px;flex-wrap:wrap;}
|
||||
.rb-chip{background:none;border:1px solid var(--line);border-radius:14px;padding:3px 11px;font-size:11px;color:var(--muted);cursor:pointer;font-family:inherit;}
|
||||
.rb-chip:hover{border-color:#f59e0b;color:#f59e0b;}
|
||||
.rb-chip.active{background:rgba(245,158,11,.15);border-color:#f59e0b;color:#f59e0b;font-weight:700;}
|
||||
.rb-parts-bar select{background:var(--panel-2);border:1px solid var(--line);border-radius:6px;padding:4px 8px;font-size:11px;color:var(--text);font-family:inherit;outline:none;}
|
||||
.rb-seg{display:inline-flex;border:1px solid var(--line);border-radius:6px;overflow:hidden;}
|
||||
.rb-seg button{background:none;border:none;padding:4px 10px;font-size:11px;color:var(--muted);cursor:pointer;font-family:inherit;}
|
||||
.rb-seg button.active{background:rgba(245,158,11,.15);color:#f59e0b;font-weight:700;}
|
||||
.rb-ptable{width:100%;border-collapse:collapse;font-size:12px;}
|
||||
.rb-ptable th{text-align:left;font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;padding:6px 6px;border-bottom:1px solid var(--line);white-space:nowrap;}
|
||||
.rb-ptable th.sortable{cursor:pointer;}
|
||||
.rb-ptable th.sortable:hover{color:#f59e0b;}
|
||||
.rb-ptable td{padding:3px 4px;border-bottom:1px solid var(--line);vertical-align:middle;}
|
||||
.rb-ptable input[type=text],.rb-ptable input[type=number],.rb-ptable select{width:100%;box-sizing:border-box;background:transparent;border:1px solid transparent;border-radius:5px;padding:4px 6px;font-size:12px;color:var(--text);font-family:inherit;outline:none;}
|
||||
.rb-ptable input:hover,.rb-ptable select:hover{border-color:var(--line);}
|
||||
.rb-ptable input:focus,.rb-ptable select:focus{border-color:#f59e0b;background:var(--panel-2);}
|
||||
.rb-ptable td.num{text-align:right;white-space:nowrap;}
|
||||
.rb-ptable td.sub{text-align:right;white-space:nowrap;color:var(--muted);padding-right:8px;}
|
||||
.rb-ptable tfoot td{font-weight:700;border-bottom:none;padding-top:8px;}
|
||||
.rb-price-line{font-size:11px;color:var(--muted);margin-top:8px;}
|
||||
.rb-price-line .down{color:#4ade80;font-weight:700;}
|
||||
.rb-price-line .up{color:#f87171;font-weight:700;}
|
||||
.rb-mini-btn{background:none;border:1px solid var(--line);border-radius:6px;padding:4px 10px;font-size:11px;color:var(--muted);cursor:pointer;font-family:inherit;}
|
||||
.rb-mini-btn:hover{border-color:#f59e0b;color:#f59e0b;}
|
||||
.rb-prog{height:6px;background:var(--line);border-radius:3px;overflow:hidden;}
|
||||
.rb-prog>i{display:block;height:100%;background:#22c55e;transition:width .3s;}
|
||||
.rb-prog-all{margin-bottom:14px;}
|
||||
.rb-prog-all .rb-prog{height:8px;}
|
||||
.rb-prog-label{font-size:11px;color:var(--muted);margin-bottom:5px;display:flex;justify-content:space-between;}
|
||||
.rb-phase-count{font-size:10px;color:var(--muted);flex-shrink:0;}
|
||||
.rb-phase-prog{width:60px;flex-shrink:0;}
|
||||
.rb-task-row input.rb-due{flex:0 0 auto;width:118px;background:var(--panel-2);border:1px solid var(--line);border-radius:5px;padding:3px 5px;font-size:11px;color:var(--muted);font-family:inherit;outline:none;}
|
||||
.rb-task-row input.rb-due.overdue{border-color:#ef4444;color:#f87171;}
|
||||
.rb-task-row input.rb-due.soon{border-color:#f59e0b;color:#f59e0b;}
|
||||
.rb-price-item{display:flex;gap:8px;padding:5px 0;border-bottom:1px solid var(--line);}
|
||||
.rb-price-item span:first-child{flex:1;}
|
||||
.rb-attach-wrap{position:relative;flex-shrink:0;}
|
||||
.rb-attach-btn{background:none;border:1px solid var(--line);border-radius:8px;padding:6px 8px;font-size:13px;color:var(--muted);cursor:pointer;}
|
||||
.rb-attach-btn:hover{border-color:#f59e0b;color:#f59e0b;}
|
||||
.rb-attach-pop{display:none;position:absolute;bottom:100%;left:0;margin-bottom:6px;background:var(--panel-2);border:1px solid var(--line);border-radius:10px;box-shadow:0 4px 16px rgba(0,0,0,.4);width:250px;max-height:280px;overflow-y:auto;z-index:60;padding:8px;}
|
||||
.rb-attach-pop.open{display:block;}
|
||||
.rb-attach-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:6px;}
|
||||
.rb-attach-grid img{width:100%;aspect-ratio:1/1;object-fit:cover;border-radius:6px;cursor:pointer;border:1px solid var(--line);}
|
||||
.rb-attach-grid img:hover{border-color:#f59e0b;}
|
||||
.rb-file-thumb img.stl-thumb{object-fit:contain;background:#2b2b2b;}
|
||||
.rb-hdr-check{font-size:10px;color:var(--muted);display:flex;align-items:center;gap:3px;cursor:pointer;flex-shrink:0;}
|
||||
/* ── 조립 설명서 탭 ── */
|
||||
.asm-sec{border:1px solid var(--line);border-radius:10px;background:var(--panel);margin-bottom:14px;}
|
||||
.asm-sec-hdr{display:flex;align-items:center;gap:8px;padding:9px 12px;border-bottom:1px solid var(--line);font-size:12px;font-weight:700;flex-wrap:wrap;}
|
||||
.asm-sec-body{padding:10px 12px;}
|
||||
.asm-row{display:flex;gap:6px;align-items:center;margin-bottom:6px;flex-wrap:wrap;}
|
||||
.asm-row input[type=text],.asm-row input[type=number],.asm-row select,.asm-step textarea{background:var(--panel-2);border:1px solid var(--line);border-radius:6px;padding:5px 8px;font-size:12px;color:var(--text);font-family:inherit;outline:none;}
|
||||
.asm-row input:focus,.asm-row select:focus,.asm-step textarea:focus{border-color:#f59e0b;}
|
||||
.asm-part .num,.asm-chip .num{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:22px;border-radius:11px;background:#f59e0b;color:#fff;font-weight:700;font-size:11px;padding:0 5px;flex-shrink:0;}
|
||||
.asm-part input.off{width:58px;}
|
||||
.asm-step{border:1px solid var(--line);border-radius:8px;padding:8px 10px;margin-bottom:8px;background:var(--panel-2);}
|
||||
.asm-step textarea{width:100%;box-sizing:border-box;min-height:54px;resize:vertical;margin-top:4px;line-height:1.5;}
|
||||
.asm-chips{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0;}
|
||||
.asm-chip{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--line);border-radius:14px;padding:2px 10px 2px 4px;font-size:11px;cursor:pointer;background:var(--panel);user-select:none;}
|
||||
.asm-chip.on{border-color:#f59e0b;background:rgba(245,158,11,.12);}
|
||||
.asm-chip input{display:none;}
|
||||
.asm-lbl{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin-top:6px;}
|
||||
.asm-imgs{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:8px;margin-top:8px;}
|
||||
.asm-imgs figure{margin:0;border:1px solid var(--line);border-radius:8px;overflow:hidden;background:#fff;}
|
||||
.asm-imgs img{display:block;width:100%;height:auto;}
|
||||
.asm-imgs figcaption{font-size:10px;color:#666;text-align:center;padding:2px;}
|
||||
.asm-warn{font-size:11px;color:#f59e0b;margin-top:6px;}
|
||||
.asm-mods{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px;}
|
||||
@media (max-width:900px){
|
||||
.rb-budget-target input{width:90px;}
|
||||
.rb-ptable{font-size:11px;}
|
||||
}
|
||||
@media (max-width:900px){
|
||||
.rb-layout{flex-direction:column;}
|
||||
.rb-resize{display:none;}
|
||||
.rb-chat{width:auto;height:38vh;border-left:none;border-top:1px solid var(--line);}
|
||||
}
|
||||
|
||||
/* ── 부품 카드 ── */
|
||||
.rb-part-card{border:1px solid var(--line);border-radius:10px;margin-bottom:8px;overflow:hidden;background:var(--panel);}
|
||||
.rb-part-hdr{display:flex;align-items:center;gap:8px;padding:9px 12px;cursor:pointer;user-select:none;}
|
||||
.rb-part-hdr:hover{background:rgba(245,158,11,.05);}
|
||||
.rb-part-chevron{font-size:10px;color:var(--muted);transition:transform .15s;flex-shrink:0;}
|
||||
.rb-part-card.expanded .rb-part-chevron{transform:rotate(90deg);}
|
||||
.rb-part-name{flex:1;font-size:13px;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
||||
.rb-part-badge{font-size:10px;padding:2px 8px;border-radius:10px;flex-shrink:0;font-weight:700;}
|
||||
.rb-part-badge.st-검토중{background:rgba(107,114,128,.15);color:#9ca3af;}
|
||||
.rb-part-badge.st-주문완료{background:rgba(59,130,246,.15);color:#60a5fa;}
|
||||
.rb-part-badge.st-보유{background:rgba(34,197,94,.15);color:#4ade80;}
|
||||
.rb-part-sub{font-size:12px;color:var(--muted);flex-shrink:0;min-width:80px;text-align:right;}
|
||||
.rb-part-body{display:none;padding:4px 12px 12px;border-top:1px solid var(--line);}
|
||||
.rb-part-card.expanded .rb-part-body{display:block;}
|
||||
.rb-part-row{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;}
|
||||
.rb-part-field{display:flex;flex-direction:column;gap:2px;}
|
||||
.rb-part-field label{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;}
|
||||
.rb-part-field input[type=text],.rb-part-field input[type=number],.rb-part-field select{background:var(--panel-2);border:1px solid var(--line);border-radius:6px;padding:5px 8px;font-size:12px;color:var(--text);font-family:inherit;outline:none;}
|
||||
.rb-part-field input:focus,.rb-part-field select:focus{border-color:#f59e0b;}
|
||||
.rb-part-field.grow{flex:1;min-width:120px;}
|
||||
.rb-part-field.qty{width:64px;}
|
||||
.rb-part-field.price{width:110px;}
|
||||
.rb-part-field.status{width:100px;}
|
||||
.rb-part-links{margin-top:10px;}
|
||||
.rb-part-links label{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;}
|
||||
.rb-link-row{display:flex;gap:6px;margin-top:6px;align-items:center;}
|
||||
.rb-link-row input[type=text]{flex:1;background:var(--panel-2);border:1px solid var(--line);border-radius:6px;padding:5px 8px;font-size:12px;color:var(--text);font-family:inherit;outline:none;}
|
||||
.rb-link-row input:focus{border-color:#f59e0b;}
|
||||
.rb-link-row input.rb-link-label{flex:0 0 110px;}
|
||||
.rb-link-open{background:none;border:1px solid var(--line);border-radius:6px;padding:4px 8px;font-size:11px;color:var(--muted);text-decoration:none;flex-shrink:0;}
|
||||
.rb-link-open:hover{border-color:#f59e0b;color:#f59e0b;}
|
||||
.rb-link-add{margin-top:6px;background:none;border:1px dashed var(--line);border-radius:6px;padding:4px 10px;font-size:11px;color:var(--muted);cursor:pointer;font-family:inherit;}
|
||||
.rb-link-add:hover{border-color:#f59e0b;color:#f59e0b;}
|
||||
.rb-part-actions{display:flex;justify-content:flex-end;margin-top:8px;}
|
||||
.rb-del-btn{background:none;border:1px solid var(--line);border-radius:6px;cursor:pointer;font-size:11px;color:var(--muted);padding:4px 10px;}
|
||||
.rb-del-btn:hover{color:#ef4444;border-color:#ef4444;}
|
||||
.rb-add-btn{margin-top:10px;background:rgba(245,158,11,.1);border:1px solid rgba(245,158,11,.3);border-radius:6px;padding:5px 12px;font-size:11px;color:#f59e0b;cursor:pointer;font-family:inherit;font-weight:700;}
|
||||
.rb-add-btn:hover{background:rgba(245,158,11,.25);}
|
||||
|
||||
/* ── 작업(단계) ── */
|
||||
.rb-phase{border:1px solid var(--line);border-radius:8px;margin-bottom:12px;overflow:hidden;}
|
||||
.rb-phase-hdr{display:flex;align-items:center;gap:6px;padding:8px 10px;background:var(--panel);}
|
||||
.rb-phase-name{flex:1;background:transparent;border:none;font-size:13px;font-weight:700;color:var(--text);font-family:inherit;outline:none;}
|
||||
.rb-phase-tasks{padding:6px 10px 10px;}
|
||||
.rb-task-row{display:flex;align-items:center;gap:6px;padding:3px 0;}
|
||||
.rb-task-row input[type=text]{flex:1;background:var(--panel-2);border:1px solid var(--line);border-radius:5px;padding:4px 8px;font-size:12px;color:var(--text);font-family:inherit;outline:none;}
|
||||
.rb-task-row input[type=text]:focus{border-color:#f59e0b;}
|
||||
.rb-task-row input[type=text].done{text-decoration:line-through;color:var(--muted);}
|
||||
.rb-task-add,.rb-phase-add{background:none;border:1px dashed var(--line);border-radius:6px;padding:5px 10px;font-size:11px;color:var(--muted);cursor:pointer;font-family:inherit;margin-top:4px;}
|
||||
.rb-task-add:hover,.rb-phase-add:hover{border-color:#f59e0b;color:#f59e0b;}
|
||||
|
||||
/* ── 장비 위젯 ── */
|
||||
.rb-equip-grid{display:flex;gap:14px;flex-wrap:wrap;}
|
||||
.rb-equip-card{flex:1;min-width:300px;max-width:480px;border:1px solid var(--line);border-radius:10px;overflow:hidden;background:var(--panel);}
|
||||
.rb-equip-hdr{display:flex;align-items:center;gap:6px;padding:8px 12px;border-bottom:1px solid var(--line);font-size:12px;font-weight:700;}
|
||||
.rb-equip-dot{width:7px;height:7px;border-radius:50%;background:#6b7280;flex-shrink:0;}
|
||||
.rb-equip-dot.on{background:#22c55e;}
|
||||
.rb-equip-dot.off{background:#ef4444;}
|
||||
.rb-equip-refresh{margin-left:auto;background:none;border:none;cursor:pointer;font-size:12px;color:var(--muted);}
|
||||
.rb-equip-refresh:hover{color:#f59e0b;}
|
||||
.rb-equip-frame-wrap{width:100%;aspect-ratio:16/9;background:#000;display:flex;align-items:center;justify-content:center;overflow:hidden;position:relative;}
|
||||
.rb-equip-frame-wrap img{width:100%;height:100%;object-fit:contain;}
|
||||
.rb-equip-frame-wrap .rb-equip-placeholder{color:#666;font-size:11px;}
|
||||
.rb-equip-live-btn{position:absolute;right:8px;bottom:8px;background:rgba(0,0,0,.55);color:#fff;border:1px solid rgba(255,255,255,.3);border-radius:6px;padding:4px 10px;font-size:11px;cursor:pointer;z-index:2;}
|
||||
.rb-equip-live-btn:hover{background:rgba(245,158,11,.85);border-color:transparent;}
|
||||
.rb-equip-live-btn.on{background:rgba(239,68,68,.8);border-color:transparent;}
|
||||
.rb-equip-status{padding:8px 12px;font-size:11px;color:var(--muted);line-height:1.7;}
|
||||
.rb-equip-status b{color:var(--text);}
|
||||
|
||||
/* ── 메모 ── */
|
||||
.rb-notes{width:100%;height:calc(100dvh - 220px);box-sizing:border-box;background:var(--panel);border:1px solid var(--line);border-radius:8px;padding:12px 14px;font-size:12px;color:var(--text);font-family:inherit;resize:none;outline:none;line-height:1.7;}
|
||||
.rb-notes:focus{border-color:#f59e0b;}
|
||||
|
||||
/* ── 파일 ── */
|
||||
.rb-files-toolbar{display:flex;gap:8px;align-items:center;margin-bottom:10px;flex-wrap:wrap;}
|
||||
.rb-files-toolbar select{background:var(--panel-2);border:1px solid var(--line);border-radius:6px;padding:5px 8px;font-size:12px;color:var(--text);font-family:inherit;outline:none;}
|
||||
.rb-upload-btn{background:rgba(245,158,11,.1);border:1px solid rgba(245,158,11,.3);border-radius:6px;padding:5px 12px;font-size:11px;color:#f59e0b;cursor:pointer;font-weight:700;display:inline-flex;align-items:center;gap:4px;}
|
||||
.rb-upload-btn:hover{background:rgba(245,158,11,.25);}
|
||||
.rb-files-dropzone{border:2px dashed var(--line);border-radius:10px;padding:18px;text-align:center;font-size:12px;color:var(--muted);margin-bottom:14px;transition:.15s;}
|
||||
.rb-files-dropzone.dragover{border-color:#f59e0b;color:#f59e0b;background:rgba(245,158,11,.05);}
|
||||
.rb-files-empty{font-size:12px;color:var(--muted);padding:20px 0;text-align:center;}
|
||||
.rb-files-group{margin-bottom:18px;}
|
||||
.rb-files-group-hdr{display:flex;align-items:center;gap:8px;margin-bottom:8px;}
|
||||
.rb-files-group-name{font-size:12px;font-weight:700;color:var(--text);}
|
||||
.rb-files-group-count{font-size:10px;color:var(--muted);}
|
||||
.rb-files-group-del{margin-left:auto;background:none;border:none;cursor:pointer;font-size:11px;color:var(--muted);}
|
||||
.rb-files-group-del:hover{color:#ef4444;}
|
||||
.rb-files-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px;}
|
||||
.rb-file-card{border:1px solid var(--line);border-radius:8px;overflow:hidden;background:var(--panel);position:relative;}
|
||||
.rb-file-thumb{width:100%;aspect-ratio:1/1;background:var(--panel-2);display:flex;align-items:center;justify-content:center;overflow:hidden;}
|
||||
.rb-file-thumb img{width:100%;height:100%;object-fit:cover;}
|
||||
.rb-file-thumb .rb-file-icon{font-size:28px;opacity:.6;}
|
||||
.rb-file-info{padding:6px 8px;}
|
||||
.rb-file-name{font-size:11px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
||||
.rb-file-size{font-size:10px;color:var(--muted);}
|
||||
.rb-file-del{position:absolute;top:4px;right:4px;background:rgba(0,0,0,.55);border:none;border-radius:5px;color:#fff;font-size:10px;padding:2px 5px;cursor:pointer;opacity:0;transition:.15s;}
|
||||
.rb-file-card:hover .rb-file-del{opacity:1;}
|
||||
.rb-file-del:hover{background:#ef4444;}
|
||||
.rb-file-card a{display:block;color:inherit;text-decoration:none;}
|
||||
/* STL 카드 전용 — 슬라이서로 보낼 파일 다중선택 체크박스(좌상단). 평소엔 델버튼처럼
|
||||
숨어있다 호버 시 보이되, 체크된 상태면 계속 보임(선택 중임을 표시). */
|
||||
.rb-file-stl-sel{position:absolute;top:4px;left:4px;z-index:2;width:16px;height:16px;cursor:pointer;opacity:0;transition:.15s;accent-color:#f59e0b;}
|
||||
.rb-file-card:hover .rb-file-stl-sel,.rb-file-stl-sel:checked{opacity:1;}
|
||||
.rb-file-card.stl-selected{outline:2px solid #f59e0b;outline-offset:-1px;}
|
||||
+2
-2433
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user