refactor: [fire-shutter] 좌측패널 UI 구조 개선 - 4탭→3탭+상단 설정바

This commit is contained in:
김보곤
2026-03-09 10:27:47 +09:00
parent 020a4e60fe
commit bcbfa77699

View File

@@ -45,43 +45,32 @@
<div class="flex" style="gap:1.25rem; height:calc(100vh - 96px);">
<!-- LEFT PANEL: 30% -->
<div class="custom-scrollbar" style="width:30%; flex-shrink:0; overflow-y:auto; padding-right:0.5rem;">
<!-- Tab Buttons (2x2 grid) -->
<div class="grid gap-1 mb-4 bg-slate-900/50 p-1.5 rounded-xl border border-slate-800" style="grid-template-columns:1fr 1fr;">
<button id="tabSettings" class="px-3 py-2 rounded-lg font-black text-xs transition-all flex items-center gap-1.5 justify-center bg-blue-600 text-white" onclick="fsSwitch('Settings')">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>
설정
</button>
<button id="tabGuideRail" class="px-3 py-2 rounded-lg font-black text-xs transition-all flex items-center gap-1.5 justify-center text-slate-400 hover:text-white hover:bg-slate-800" onclick="fsSwitch('GuideRail')">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="18" rx="1"/><rect x="14" y="3" width="7" height="18" rx="1"/></svg>
가이드레일
</button>
<button id="tabShutterBox" class="px-3 py-2 rounded-lg font-black text-xs transition-all flex items-center gap-1.5 justify-center text-slate-400 hover:text-white hover:bg-slate-800" onclick="fsSwitch('ShutterBox')">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="8" rx="2"/><path d="M6 12v4"/><path d="M18 12v4"/></svg>
셔터박스
</button>
<button id="tab3D" class="px-3 py-2 rounded-lg font-black text-xs transition-all flex items-center gap-1.5 justify-center text-slate-400 hover:text-white hover:bg-slate-800" onclick="fsSwitch('3D')">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
3D 렌더링
</button>
</div>
<!-- ========== SETTINGS TAB CONTROLS ========== -->
<div id="ctrlSettings">
<section class="fs-section space-y-5">
<h2 class="text-lg font-black text-white flex items-center gap-3">
<span class="fs-badge bg-blue-600">S</span>
기본 설정
</h2>
<div>
<label class="fs-label">제품 유형</label>
<select id="productType" class="fs-select" onchange="fsOnProductType()">
<option value="steel">강판형 (Steel Slat)</option>
<option value="screen">스크린형 (Screen/Fabric)</option>
<!-- ========== TOP: 기본 설정 (항상 표시) ========== -->
<div class="fs-section mb-3" style="padding:0.75rem 1rem;">
<div class="flex gap-2 items-end">
<div style="flex:1.2;">
<label class="fs-label">유형</label>
<select id="productType" class="fs-select" style="font-size:0.75rem;padding:0.375rem 0.5rem;" onchange="fsOnProductType()">
<option value="steel">강판형</option>
<option value="screen">스크린형</option>
</select>
</div>
<div>
<div style="flex:1;">
<label class="fs-label"> W0</label>
<input type="number" id="openWidth" class="fs-input" style="font-size:0.75rem;padding:0.375rem 0.5rem;" value="2000" onchange="fsCalc()">
</div>
<div style="flex:1;">
<label class="fs-label">높이 H0</label>
<input type="number" id="openHeight" class="fs-input" style="font-size:0.75rem;padding:0.375rem 0.5rem;" value="3000" onchange="fsCalc()">
</div>
<div style="flex:0.5;">
<label class="fs-label">수량</label>
<input type="number" id="quantity" class="fs-input" style="font-size:0.75rem;padding:0.375rem 0.5rem;" value="1" min="1" onchange="fsCalc()">
</div>
</div>
<!-- 접기/펼치기 상세 영역 -->
<div id="settingsDetail" class="hidden mt-3 pt-3 border-t border-slate-700/50">
<div class="mb-3">
<label class="fs-label">제품 모델</label>
<select id="productModel" class="fs-select" onchange="fsOnModelChange()">
<optgroup label="강판형">
@@ -94,56 +83,46 @@
</optgroup>
</select>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="fs-label">개구부 W0 (mm)</label>
<input type="number" id="openWidth" class="fs-input" value="2000" onchange="fsCalc()">
</div>
<div>
<label class="fs-label">개구부 높이 H0 (mm)</label>
<input type="number" id="openHeight" class="fs-input" value="3000" onchange="fsCalc()">
</div>
</div>
<div>
<label class="fs-label">수량</label>
<input type="number" id="quantity" class="fs-input" value="1" min="1" onchange="fsCalc()">
</div>
</section>
<!-- Auto-Calculated -->
<section class="fs-section space-y-3 mt-4">
<h2 class="text-lg font-black text-white flex items-center gap-3">
<span class="fs-badge bg-emerald-600">C</span>
자동 계산
</h2>
<div class="space-y-1">
<div class="space-y-1 mb-3">
<div class="fs-calc-row"><span class="fs-calc-label">제작 (W1)</span><span id="calcW1" class="fs-calc-value">2110 mm</span></div>
<div class="fs-calc-row"><span class="fs-calc-label">제작 높이 (H1)</span><span id="calcH1" class="fs-calc-value">3350 mm</span></div>
<div class="fs-calc-row"><span class="fs-calc-label">면적 (M)</span><span id="calcArea" class="fs-calc-value">7.07 </span></div>
<div class="fs-calc-row"><span class="fs-calc-label">중량 (K)</span><span id="calcWeight" class="fs-calc-value">176.7 kg</span></div>
<div class="fs-calc-row"><span class="fs-calc-label">면적</span><span id="calcArea" class="fs-calc-value">7.07 </span></div>
<div class="fs-calc-row"><span class="fs-calc-label">중량</span><span id="calcWeight" class="fs-calc-value">176.7 kg</span></div>
<div class="fs-calc-row"><span class="fs-calc-label">권장 모터</span><span id="calcMotor" class="fs-calc-value text-blue-400">300K (4")</span></div>
<div class="fs-calc-row" style="border:none;"><span class="fs-calc-label">가이드레일 조합</span><span id="calcRailCombo" class="fs-calc-value text-amber-400">3,305mm × 2</span></div>
<div class="fs-calc-row" style="border:none;"><span class="fs-calc-label">레일 조합</span><span id="calcRailCombo" class="fs-calc-value text-amber-400">3,305mm × 2</span></div>
</div>
</section>
<div class="pt-2 border-t border-slate-700/30 space-y-2">
<span class="text-[10px] text-slate-500 font-bold">프리셋</span>
<div class="flex gap-2">
<select id="presetSelect" class="fs-select flex-1" style="font-size:0.75rem;"><option value="">-- 선택 --</option></select>
<button class="fs-btn fs-btn-primary" style="font-size:0.65rem;padding:0.375rem 0.5rem;" onclick="fsLoadPreset()">불러오기</button>
</div>
<div class="flex gap-2">
<input type="text" id="presetName" class="fs-input flex-1" style="font-size:0.75rem;" placeholder="프리셋 이름">
<button class="fs-btn fs-btn-primary" style="font-size:0.65rem;padding:0.375rem 0.5rem;" onclick="fsSavePreset()">저장</button>
<button class="fs-btn fs-btn-ghost" style="font-size:0.65rem;padding:0.375rem 0.5rem;" onclick="fsDeletePreset()">삭제</button>
</div>
</div>
</div>
<button onclick="var d=$('settingsDetail');d.classList.toggle('hidden');this.querySelector('span').textContent=d.classList.contains('hidden')?'상세 설정 ▼':'상세 설정 ▲';" class="w-full mt-2 text-[11px] text-slate-500 hover:text-slate-300 font-bold text-center py-1 border-t border-slate-700/30 transition-colors">
<span>상세 설정 ▼</span>
</button>
</div>
<!-- Preset -->
<section class="fs-section space-y-3 mt-4">
<h2 class="text-sm font-black text-slate-400 flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/></svg>
프리셋
</h2>
<div class="flex gap-2">
<select id="presetSelect" class="fs-select flex-1"><option value="">-- 선택 --</option></select>
<button class="fs-btn fs-btn-primary" onclick="fsLoadPreset()">불러오기</button>
</div>
<div class="flex gap-2">
<input type="text" id="presetName" class="fs-input flex-1" placeholder="프리셋 이름">
<button class="fs-btn fs-btn-primary" onclick="fsSavePreset()">저장</button>
<button class="fs-btn fs-btn-ghost" onclick="fsDeletePreset()">삭제</button>
</div>
</section>
<!-- Tab Buttons (1x3) -->
<div class="grid gap-1 mb-3 bg-slate-900/50 p-1.5 rounded-xl border border-slate-800" style="grid-template-columns:1fr 1fr 1fr;">
<button id="tabGuideRail" class="px-3 py-2 rounded-lg font-black text-xs transition-all flex items-center gap-1.5 justify-center text-slate-400 hover:text-white hover:bg-slate-800" onclick="fsSwitch('GuideRail')">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="18" rx="1"/><rect x="14" y="3" width="7" height="18" rx="1"/></svg>
가이드레일
</button>
<button id="tabShutterBox" class="px-3 py-2 rounded-lg font-black text-xs transition-all flex items-center gap-1.5 justify-center text-slate-400 hover:text-white hover:bg-slate-800" onclick="fsSwitch('ShutterBox')">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="8" rx="2"/><path d="M6 12v4"/><path d="M18 12v4"/></svg>
셔터박스
</button>
<button id="tab3D" class="px-3 py-2 rounded-lg font-black text-xs transition-all flex items-center gap-1.5 justify-center text-slate-400 hover:text-white hover:bg-slate-800" onclick="fsSwitch('3D')">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
3D 렌더링
</button>
</div>
<!-- ========== GUIDE RAIL TAB CONTROLS ========== -->
@@ -222,11 +201,11 @@
</div>
<div>
<label class="fs-label">케이스 높이 (mm)</label>
<input type="number" id="sbHeight" class="fs-input" value="380" step="10" onchange="fsRender()">
<input type="number" id="sbHeight" class="fs-input" value="550" step="10" onchange="fsRender()">
</div>
<div>
<label class="fs-label">케이스 깊이 (mm)</label>
<input type="number" id="sbDepth" class="fs-input" value="520" step="10" onchange="fsRender()">
<input type="number" id="sbDepth" class="fs-input" value="650" step="10" onchange="fsRender()">
</div>
<div>
<label class="fs-label">강판 두께 (mm)</label>
@@ -456,9 +435,9 @@
// ============================
window.fsSwitch = function(tab) {
S.tab = tab;
const tabs = ['Settings','GuideRail','ShutterBox','3D'];
const tabBtnIds = ['tabSettings','tabGuideRail','tabShutterBox','tab3D'];
const ctrlIds = ['ctrlSettings','ctrlGuideRail','ctrlShutterBox','ctrl3D'];
const tabs = ['GuideRail','ShutterBox','3D'];
const tabBtnIds = ['tabGuideRail','tabShutterBox','tab3D'];
const ctrlIds = ['ctrlGuideRail','ctrlShutterBox','ctrl3D'];
tabs.forEach((t,i) => {
const btn = $(tabBtnIds[i]);
const ctrl = $(ctrlIds[i]);