fix: [rd] 방화셔터 3D 패널 극한 압축

- 슬라이더 라벨+값+슬라이더를 한 행으로 통합
- 부품 토글 4열 grid로 변경 (2행으로 압축)
- 조명 프리셋 버튼 제거, 조명색 color picker로 교체
- 배경색 버튼 14px로 축소, 조명+배경 한 행 배치
- 전체 패딩/간격 최소화
This commit is contained in:
김보곤
2026-03-08 20:02:42 +09:00
parent 4522f19d40
commit eb004fe399

View File

@@ -267,63 +267,40 @@
<!-- ========== 3D TAB CONTROLS ========== -->
<div id="ctrl3D" class="hidden">
<section class="fs-section space-y-3">
<h2 class="text-sm font-black text-white flex items-center gap-2">
<span class="fs-badge bg-cyan-600" style="width:1.25rem;height:1.25rem;font-size:0.5rem;">3D</span>
3D 설정
</h2>
<div>
<div class="flex items-center justify-between mb-1">
<label class="text-[11px] text-slate-400 font-bold">개폐율</label>
<span id="shutterPosLabel" class="text-[11px] text-blue-400 font-black">100%</span>
</div>
<input type="range" id="shutterPos" min="0" max="100" value="100" class="w-full accent-blue-500" style="height:4px;" oninput="fs3dShutterPos(this.value)">
<section class="fs-section" style="padding:0.75rem 1rem;">
<!-- 개폐율: 한 행 -->
<div class="flex items-center gap-2 mb-1">
<label class="text-[10px] text-slate-500 font-bold shrink-0" style="width:24px;">개폐</label>
<input type="range" id="shutterPos" min="0" max="100" value="100" class="flex-1 accent-blue-500" style="height:3px;" oninput="fs3dShutterPos(this.value)">
<span id="shutterPosLabel" class="text-[10px] text-blue-400 font-black shrink-0" style="width:28px;text-align:right;">100%</span>
</div>
<div>
<div class="flex items-center justify-between mb-1">
<label class="text-[11px] text-slate-400 font-bold">투명도</label>
<span id="opacityLabel" class="text-[11px] text-blue-400 font-black">30%</span>
</div>
<input type="range" id="caseOpacity" min="0" max="100" value="30" class="w-full accent-blue-500" style="height:4px;" oninput="fs3dOpacity(this.value)">
<!-- 투명도: 한 행 -->
<div class="flex items-center gap-2 mb-2">
<label class="text-[10px] text-slate-500 font-bold shrink-0" style="width:24px;">투명</label>
<input type="range" id="caseOpacity" min="0" max="100" value="30" class="flex-1 accent-blue-500" style="height:3px;" oninput="fs3dOpacity(this.value)">
<span id="opacityLabel" class="text-[10px] text-blue-400 font-black shrink-0" style="width:28px;text-align:right;">30%</span>
</div>
<div class="border-t border-slate-800 pt-2">
<label class="text-[11px] text-slate-500 font-bold mb-1.5 block">부품</label>
<div class="grid grid-cols-2 gap-x-3 gap-y-1">
<div class="flex items-center justify-between"><span class="text-[11px] text-slate-400">박스</span><div class="fs-toggle active" onclick="fsToggle3d(this,'case')"></div></div>
<div class="flex items-center justify-between"><span class="text-[11px] text-slate-400">샤프트</span><div class="fs-toggle active" onclick="fsToggle3d(this,'shaft')"></div></div>
<div class="flex items-center justify-between"><span class="text-[11px] text-slate-400">모터</span><div class="fs-toggle active" onclick="fsToggle3d(this,'motor')"></div></div>
<div class="flex items-center justify-between"><span class="text-[11px] text-slate-400">레일</span><div class="fs-toggle active" onclick="fsToggle3d(this,'rails')"></div></div>
<div class="flex items-center justify-between"><span class="text-[11px] text-slate-400">슬랫</span><div class="fs-toggle active" onclick="fsToggle3d(this,'slats')"></div></div>
<div class="flex items-center justify-between"><span class="text-[11px] text-slate-400">하장바</span><div class="fs-toggle active" onclick="fsToggle3d(this,'bottomBar')"></div></div>
<div class="flex items-center justify-between"><span class="text-[11px] text-slate-400">벽</span><div class="fs-toggle active" onclick="fsToggle3d(this,'wall')"></div></div>
</div>
<!-- 부품: 4열 compact grid -->
<div class="grid gap-x-0.5 gap-y-0.5 mb-2" style="grid-template-columns:repeat(4,auto);">
<div class="flex items-center gap-0.5"><div class="fs-toggle active" onclick="fsToggle3d(this,'case')"></div><span class="text-[10px] text-slate-500">박스</span></div>
<div class="flex items-center gap-0.5"><div class="fs-toggle active" onclick="fsToggle3d(this,'shaft')"></div><span class="text-[10px] text-slate-500">샤프트</span></div>
<div class="flex items-center gap-0.5"><div class="fs-toggle active" onclick="fsToggle3d(this,'motor')"></div><span class="text-[10px] text-slate-500">모터</span></div>
<div class="flex items-center gap-0.5"><div class="fs-toggle active" onclick="fsToggle3d(this,'rails')"></div><span class="text-[10px] text-slate-500">레일</span></div>
<div class="flex items-center gap-0.5"><div class="fs-toggle active" onclick="fsToggle3d(this,'slats')"></div><span class="text-[10px] text-slate-500">슬랫</span></div>
<div class="flex items-center gap-0.5"><div class="fs-toggle active" onclick="fsToggle3d(this,'bottomBar')"></div><span class="text-[10px] text-slate-500">하장바</span></div>
<div class="flex items-center gap-0.5"><div class="fs-toggle active" onclick="fsToggle3d(this,'wall')"></div><span class="text-[10px] text-slate-500">벽</span></div>
</div>
<div class="border-t border-slate-800 pt-2">
<div class="flex items-center gap-2">
<label class="text-[11px] text-slate-500 font-bold shrink-0">조명</label>
<div class="flex gap-1 flex-1">
<button class="fs-btn fs-btn-ghost active flex-1" style="padding:0.25rem 0.5rem;font-size:0.625rem;" data-light="default" onclick="fs3dLight('default')">기본</button>
<button class="fs-btn fs-btn-ghost flex-1" style="padding:0.25rem 0.5rem;font-size:0.625rem;" data-light="studio" onclick="fs3dLight('studio')">스튜디오</button>
<button class="fs-btn fs-btn-ghost flex-1" style="padding:0.25rem 0.5rem;font-size:0.625rem;" data-light="outdoor" onclick="fs3dLight('outdoor')">야외</button>
</div>
</div>
</div>
<div class="border-t border-slate-800 pt-2">
<div class="flex items-center gap-2">
<label class="text-[11px] text-slate-500 font-bold shrink-0">배경</label>
<div class="flex gap-1 flex-1">
<button onclick="fs3dBg('#ffffff')" class="w-5 h-5 rounded border border-slate-600 hover:border-blue-400 shrink-0" style="background:#fff"></button>
<button onclick="fs3dBg('#f0f0f0')" class="w-5 h-5 rounded border border-slate-600 hover:border-blue-400 shrink-0" style="background:#f0f0f0"></button>
<button onclick="fs3dBg('#808080')" class="w-5 h-5 rounded border border-slate-600 hover:border-blue-400 shrink-0" style="background:#808080"></button>
<button onclick="fs3dBg('#303030')" class="w-5 h-5 rounded border border-slate-600 hover:border-blue-400 shrink-0" style="background:#303030"></button>
<button onclick="fs3dBg('#1a1a2e')" class="w-5 h-5 rounded border border-slate-600 hover:border-blue-400 shrink-0" style="background:#1a1a2e"></button>
<button onclick="fs3dBg('#000000')" class="w-5 h-5 rounded border border-slate-600 hover:border-blue-400 shrink-0" style="background:#000"></button>
</div>
<!-- 조명색 + 배경색: 한 행 -->
<div class="flex items-center gap-3 border-t border-slate-800 pt-1.5">
<div class="flex items-center gap-1"><label class="text-[10px] text-slate-500 font-bold">조명</label><input type="color" id="lightColor" value="#ffffff" class="w-4 h-4 rounded cursor-pointer border-0 p-0" style="background:none;" onchange="fs3dLightColor(this.value)"></div>
<div class="flex items-center gap-1">
<label class="text-[10px] text-slate-500 font-bold">배경</label>
<button onclick="fs3dBg('#ffffff')" class="w-3.5 h-3.5 rounded border border-slate-600 hover:border-blue-400" style="background:#fff"></button>
<button onclick="fs3dBg('#f0f0f0')" class="w-3.5 h-3.5 rounded border border-slate-600 hover:border-blue-400" style="background:#f0f0f0"></button>
<button onclick="fs3dBg('#808080')" class="w-3.5 h-3.5 rounded border border-slate-600 hover:border-blue-400" style="background:#808080"></button>
<button onclick="fs3dBg('#303030')" class="w-3.5 h-3.5 rounded border border-slate-600 hover:border-blue-400" style="background:#303030"></button>
<button onclick="fs3dBg('#1a1a2e')" class="w-3.5 h-3.5 rounded border border-slate-600 hover:border-blue-400" style="background:#1a1a2e"></button>
<button onclick="fs3dBg('#000')" class="w-3.5 h-3.5 rounded border border-slate-600 hover:border-blue-400" style="background:#000"></button>
</div>
</div>
</section>
@@ -1152,24 +1129,11 @@ function fs3dBuild() {
S.td.show[key] = el.classList.contains('active');
if (meshes[key]) meshes[key].visible = S.td.show[key];
};
window.fs3dLight = function(preset) {
S.td.lightPreset = preset;
document.querySelectorAll('[data-light]').forEach(btn => {
btn.classList.toggle('active', btn.dataset.light === preset);
btn.style.color = btn.dataset.light === preset ? '#3b82f6' : '';
btn.style.borderColor = btn.dataset.light === preset ? '#3b82f6' : '';
});
window.fs3dLightColor = function(color) {
if (!scene) return;
const lights = scene.children.filter(c => c.isLight);
const presets = {
default: { ambient: 0.4, dir: 0.8 },
studio: { ambient: 0.3, dir: 1.0 },
outdoor: { ambient: 0.6, dir: 0.5 },
};
const p = presets[preset] || presets.default;
lights.forEach(l => {
if (l.isAmbientLight) l.intensity = p.ambient;
if (l.isDirectionalLight) l.intensity = p.dir;
const c = new THREE.Color(color);
scene.children.forEach(l => {
if (l.isDirectionalLight) l.color.copy(c);
});
};
window.fs3dBg = function(color) {