fix(viewer): compact left panel typography and layout so it fits without scrolling

- Panel text reduced to 14px (headings, labels, buttons) and 13px (notes, specs).
- Hint notes removed; part selection moved into a closed disclosure (summary shows selected part).
- Pattern list in four columns; section rhythm tightened.
- At 1440x900 and 1920x1080 the panel fits without scrolling. Below ~830px height it still scrolls.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A5Cun3RHQKna9qxE6ybZ4A
This commit is contained in:
Claude committed 2026-10-21 23:47:52 +00:00
1 parent e254718309
commit 7e4c79c86d
1 file changed
+47 -29
+47 -29
View File
@@ -102,7 +102,7 @@ body {
}
h1, h2, p, dl, dd, dt { margin: 0; }
h1 { font-size: var(--prism-type-title-sm); line-height: var(--prism-lh-title); font-weight: 700; color: var(--prism-text-heading); }
h2 { font-size: var(--prism-type-body-lg); line-height: var(--prism-lh-title); font-weight: 700; color: var(--prism-text-heading); margin-block: var(--prism-space-300) var(--prism-space-100); }
h2 { font-size: var(--prism-type-body-sm); line-height: var(--prism-lh-title); font-weight: 700; color: var(--prism-text-heading); margin-block: var(--prism-space-150) var(--prism-space-050); }
.rail h2:first-child { margin-block-start: 0; }
/* 포커스: 3px 링 + 오프셋 2px, :focus-visible 전용 (FC-1·FC-2) */
@@ -139,7 +139,7 @@ h2 { font-size: var(--prism-type-body-lg); line-height: var(--prism-lh-title); f
/* 셸: 좌측 내비 레일 + 뷰포트 (W1) */
.shell { flex: 1; min-height: 0; display: grid; grid-template-columns: 17.5rem minmax(0, 1fr); }
.rail {
overflow: auto; padding: var(--prism-space-200);
overflow: auto; padding: var(--prism-space-150);
background: var(--prism-bg-card); border-inline-end: var(--prism-stroke-hairline) solid var(--prism-border-default);
}
.stage { position: relative; min-width: 0; min-height: 0; }
@@ -148,7 +148,7 @@ h2 { font-size: var(--prism-type-body-lg); line-height: var(--prism-lh-title); f
/* 버튼 — primary 화면당 1개 (BT-1), 히트 영역 44px (HT-1) */
button {
font: inherit; font-size: var(--prism-type-body); font-weight: 500; line-height: 1.2;
font: inherit; font-size: var(--prism-type-body-sm); font-weight: 500; line-height: 1.2;
min-height: 2.75rem; padding: var(--prism-space-050) var(--prism-space-100); white-space: nowrap;
border: var(--prism-stroke-hairline) solid var(--prism-border-default); border-radius: var(--prism-radius-md);
background: var(--prism-bg-card); color: var(--prism-text-body); cursor: pointer;
@@ -161,10 +161,11 @@ button.quiet { background: transparent; border-color: transparent; color: var(--
/* 체크박스 행 — 히트 영역 44px */
.opt {
display: flex; align-items: center; gap: var(--prism-space-100);
min-height: 2.75rem; cursor: pointer; color: var(--prism-text-body);
min-height: 2.75rem; cursor: pointer; color: var(--prism-text-body); font-size: var(--prism-type-body-sm);
}
.opt input[type="checkbox"] { width: 1.25rem; height: 1.25rem; margin: 0; flex: none; accent-color: var(--prism-text-heading); }
.pats { display: grid; grid-template-columns: 1fr 1fr; column-gap: var(--prism-space-100); }
.pats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); column-gap: var(--prism-space-050); }
.pats .opt { gap: var(--prism-space-050); white-space: nowrap; }
.sw {
width: var(--prism-space-200); height: var(--prism-space-200); flex: none;
border-radius: var(--prism-radius-sm); border: var(--prism-stroke-hairline) solid var(--prism-border-default);
@@ -192,23 +193,37 @@ button.quiet { background: transparent; border-color: transparent; color: var(--
pointer-events: auto; cursor: pointer; width: 1.25rem; height: 1.25rem; border-radius: 50%;
background: var(--prism-text-heading); border: var(--prism-stroke-regular) solid var(--prism-bg-card);
}
.sta { font-weight: 700; font-variant-numeric: tabular-nums; margin-block: var(--prism-space-050) var(--prism-space-100); }
.sta { font-size: var(--prism-type-body-sm); font-weight: 700; font-variant-numeric: tabular-nums; margin-block: var(--prism-space-050) var(--prism-space-100); }
/* 개폐 (component.disclosure) — 부품 선택은 기본 접힘 */
.disc { margin-block-start: var(--prism-space-150); border-top: var(--prism-stroke-hairline) solid var(--prism-border-default); padding-block-start: var(--prism-space-050); }
.disc > summary {
display: flex; align-items: center; justify-content: space-between; gap: var(--prism-space-100);
min-height: 2.75rem; cursor: pointer; list-style: none; font-size: var(--prism-type-body-sm); font-weight: 700; color: var(--prism-text-heading);
}
.disc > summary::-webkit-details-marker { display: none; }
.disc > summary > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.disc > summary::after { content: "+"; flex: none; font-weight: 500; color: var(--prism-text-subtle); }
.disc[open] > summary::after { content: "−"; }
.disc > summary:focus-visible { outline: var(--prism-focus-ring) solid var(--prism-text-heading); outline-offset: var(--prism-focus-offset); }
.disc > *:not(summary) { margin-block-start: var(--prism-space-100); }
/* 선택 목록 */
select {
font: inherit; font-size: var(--prism-type-body); width: 100%; min-height: 2.75rem;
font: inherit; font-size: var(--prism-type-body-sm); width: 100%; min-height: 2.75rem;
padding: var(--prism-space-050) var(--prism-space-100); border-radius: var(--prism-radius-md);
border: var(--prism-stroke-hairline) solid var(--prism-border-default);
background: var(--prism-bg-card); color: var(--prism-text-body);
}
.label { display: block; margin-block-end: var(--prism-space-050); color: var(--prism-text-subtle); font-size: var(--prism-type-caption); line-height: var(--prism-lh-caption); }
.note { color: var(--prism-text-subtle); font-size: var(--prism-type-caption); line-height: var(--prism-lh-caption); max-inline-size: var(--prism-measure-max); margin-block-start: var(--prism-space-100); }
.empty { color: var(--prism-text-subtle); font-size: var(--prism-type-body-sm); margin-block-start: var(--prism-space-100); }
.empty { color: var(--prism-text-subtle); font-size: var(--prism-type-caption); margin-block-start: var(--prism-space-100); }
/* 명세표 (specsheet) — 항목 말미 고정 위치, 열 구성 동일 (SS-1·SS-2) */
.spec {
display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--prism-space-050) var(--prism-space-150);
font-size: var(--prism-type-body-sm); line-height: var(--prism-lh-body); font-variant-numeric: tabular-nums;
font-size: var(--prism-type-caption); line-height: var(--prism-lh-caption); font-variant-numeric: tabular-nums;
}
.spec dt { color: var(--prism-text-subtle); }
.spec dd { overflow-wrap: anywhere; color: var(--prism-text-body); }
@@ -270,8 +285,7 @@ select {
<div class="shell">
<nav class="rail" aria-label="모델 제어">
<h2>시점</h2>
<div class="btn-grid">
<div class="btn-grid" role="group" aria-label="시점">
<button type="button" class="primary" id="btnStart">종단 보기</button>
<button type="button" id="btnAll">전체 맞추기</button>
</div>
@@ -287,31 +301,29 @@ select {
<button type="button" id="btnWin">구간 맞추기</button>
<button type="button" id="btnWinReset" class="quiet">구간 전체</button>
</div>
<p class="note">슬라이더는 5 m 단위로 움직입니다.</p>
<h2>지보패턴</h2>
<div class="pats" id="pats"></div>
<p class="note">라이닝과 굴착 여유대를 패턴별로 켜고 끕니다.</p>
<h2>구성요소</h2>
<div id="comps"></div>
<h2>부품 선택</h2>
<label class="label" for="pickSel">목록에서 부품 고르기</label>
<select id="pickSel">
<option value="">선택 없음</option>
</select>
<dl class="spec" id="detailSpec" hidden style="margin-block-start:var(--prism-space-150)"></dl>
<p class="empty" id="detailEmpty">부품을 클릭하거나 목록에서 고르면 속성이 표시됩니다.</p>
<div class="btn-grid" style="margin-block-start:var(--prism-space-150)">
<button type="button" id="btnFitSel">선택 맞추기</button>
<button type="button" id="btnDesel" class="quiet">선택 해제</button>
<button type="button" id="btnHideSel">선택 숨기기</button>
<button type="button" id="btnIsoSel">선택만 보기</button>
<button type="button" id="btnShowAll" class="quiet wide">모두 보기</button>
</div>
<label class="opt" style="margin-block-start:var(--prism-space-150)"><input type="checkbox" id="wire"> 와이어프레임으로 보기</label>
<p class="note">드래그 회전 · 휠 확대 · 클릭 선택 · Esc 선택 해제</p>
<details class="disc" id="partDisc">
<summary><span id="partSummary">부품 선택</span></summary>
<select id="pickSel" aria-label="부품 목록에서 고르기">
<option value="">선택 없음</option>
</select>
<dl class="spec" id="detailSpec" hidden></dl>
<p class="empty" id="detailEmpty">부품을 클릭하거나 목록에서 고르면 속성이 표시됩니다.</p>
<div class="btn-grid" style="margin-block-start:var(--prism-space-100)">
<button type="button" id="btnFitSel">선택 맞추기</button>
<button type="button" id="btnDesel" class="quiet">선택 해제</button>
<button type="button" id="btnHideSel">선택 숨기기</button>
<button type="button" id="btnIsoSel">선택만 보기</button>
<button type="button" id="btnShowAll" class="quiet wide">모두 보기</button>
</div>
<label class="opt" style="margin-block-start:var(--prism-space-050)"><input type="checkbox" id="wire"> 와이어프레임으로 보기</label>
</details>
</nav>
<main id="main" class="stage">
@@ -467,6 +479,11 @@ function startView() {
controls.update();
}
// 부품 선택 개폐 상태 저장 (DC-3)
const DISC_KEY = 'prism-viewer-part-open';
try { $('partDisc').open = localStorage.getItem(DISC_KEY) === '1'; } catch (e) { /* 무시 */ }
$('partDisc').addEventListener('toggle', () => { try { localStorage.setItem(DISC_KEY, $('partDisc').open ? '1' : '0'); } catch (e) { /* 무시 */ } });
// ── 부품 상세 (명세표) ──
function specRows(u) {
return [
@@ -497,6 +514,7 @@ function setSelected(m) {
selected = m;
if (m) m.material.emissive.set(tok('--prism-text-heading'));
$('pickSel').value = m ? String(m.userData.idx) : '';
$('partSummary').textContent = m ? '부품 선택 · ' + m.userData.id : '부품 선택 · 선택 없음';
applyVisibility();
renderDetail(m ? m.userData : null);
}