fix(storybook): align viewer property popup card layout
Deploy Storybook / deploy (push) Successful in 1m13s
Deploy Storybook / deploy (push) Successful in 1m13s
This commit is contained in:
1 parent
e492a84f1d
commit
4551edfd82
3 files changed
+19
-14
No files matched your search
@@ -25,13 +25,13 @@ SWViewerPanel (= SWPopup, .hm-sw-property.hm-sw-viewer-panel) ← 테두리
|
||||
|---|---|---|---|---|---|---|
|
||||
| Footer 위 구분선 | 스크롤 본문과 하단 버튼 영역 분리 | `.hm-sw-viewer-panel__footer` | `border-top: 1px solid var(--hm-sw-viewer-panel-inner-border)`(#948871), `padding: 7px`, `gap: 8px`, 오른쪽 정렬 | `footer` Prop이 있고 접힘(`collapsed`)이 아닐 때만 렌더링 | 공통 | `SW/Viewer › Viewer Header`의 `모듈 구성 · 라이선스 고지` modal(`AboutPanel`, `확인` 버튼). Settings Popup 3개에는 footer 없음 |
|
||||
| 전체 레이어 행 아래 선 | 고정 행(검색·전체 레이어)과 레이어 목록 분리 | `.sw-viewer-story-layers .sw-viewer-story-all` | `border-bottom: 1px solid var(--hm-sw-property-table)`(#d2c8b4), `padding-bottom: 8px`(실측 `padding: 0 6px 8px 0`) | 레이어 Popup에만 해당. 검색과 전체 레이어 사이에는 선 없음 | **Storybook 전용** | Settings Popup › `레이어 (9개)` |
|
||||
| 속성 행 사이 선 | 속성 키/값 행 구분 | `.sw-viewer-story-props > div` | `border-bottom: 1px solid var(--hm-sw-viewer-panel-inner-border)`(#948871), `padding: 6px 0`, `gap: 12px` | 각 그룹의 **마지막 행에도** 선이 있음(실측 9행 모두) | **Storybook 전용** | Settings Popup › `속성` |
|
||||
| 속성 행 사이 선 | 속성 키/값 행 구분 | `.sw-viewer-story-props > div` | `border-bottom: 1px solid var(--hm-sw-property-table)`(#d2c8b4), `padding: 6px 0`, `gap: 12px`, 이름 왼쪽·값 오른쪽(말줄임) | 각 Card의 마지막 행에는 선 없음(2026-10-23, 뷰어 화면 기준) | **Storybook 전용** | Settings Popup › `속성` |
|
||||
|
||||
## 3. 선이 표시되지 않는 영역
|
||||
|
||||
| 영역 | 목적 | 선택자 | 실제 값 | 조건·예외 | 구분 | Storybook 예시 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Plain Section | 패널 본문에 카드 없이 콘텐츠를 바로 배치 | `.hm-sw-viewer-section[data-surface="plain"]` | 전용 규칙 없음 → 기본 `.hm-sw-viewer-section`만 적용: `display: flex; flex-direction: column; gap: 12px`, 테두리·배경·padding 0 | `SWViewerSection surface="plain"`을 명시했을 때 | 공통 | 레이어 Popup의 목록 Section, 속성 Popup의 `일반 정보`·`기하 속성` |
|
||||
| Plain Section | 패널 본문에 카드 없이 콘텐츠를 바로 배치 | `.hm-sw-viewer-section[data-surface="plain"]` | 전용 규칙 없음 → 기본 `.hm-sw-viewer-section`만 적용: `display: flex; flex-direction: column; gap: 12px`, 테두리·배경·padding 0 | `SWViewerSection surface="plain"`을 명시했을 때 | 공통 | 레이어 Popup의 목록 Section |
|
||||
| 제목줄 ↔ 본문 경계 | — | `.hm-sw-property__titlebar` / `.hm-sw-property__body` | 경계선 없음. 제목줄은 배경 그라데이션, 본문은 위쪽 inset 하이라이트(§5)로만 구분 | 모든 패널 | 공통(SWPopup) | Settings Popup 전체 |
|
||||
| 검색 ↔ 전체 레이어 | 고정 행 두 개 | `.sw-viewer-story-toolbar` | 선 없음, `gap: 12px 4px` | 레이어 Popup | Storybook 전용 | `레이어 (9개)` |
|
||||
| 레이어 목록 행 사이 | 레이어 항목 나열 | `.sw-viewer-story-list`, `li` | 선 없음, 목록 `gap: 4px`, 행 `padding: 4px 6px` | — | Storybook 전용 | `레이어 (9개)` |
|
||||
@@ -42,7 +42,7 @@ SWViewerPanel (= SWPopup, .hm-sw-property.hm-sw-viewer-panel) ← 테두리
|
||||
| 영역 | 목적 | 선택자 | Border | Background | Radius | Padding·기타 | 조건·예외 | 구분 | 예시 |
|
||||
|---|---|---|---|---|---|---|---|---|---|
|
||||
| 패널 프레임 | 팝업 전체 외곽 | `.hm-sw-property`(SWPopup) + `.hm-sw-viewer-panel` | `1px solid var(--hm-sw-property-border)`(#a67d03) + `box-shadow: inset 0 0 0 1px #000`(안쪽 검정 1px) | `var(--hm-sw-property-surface)`(#e4dbc9) | 4px | padding 0, `overflow: hidden` | 모든 SWViewerPanel. modal이면 뒤에 `.hm-sw-viewer-panel-backdrop`(`rgba(0,0,0,.1)`) | 공통(SWPopup 그대로) | Settings Popup 3개 |
|
||||
| Card Section | 설정 그룹 묶음 | `.hm-sw-viewer-section[data-surface="card"]` | `1px solid var(--hm-sw-viewer-panel-inner-border)`(#948871) | `var(--hm-sw-viewer-panel-field-background)`(#f1ece1) | `var(--hm-sw-viewer-radius)` 4px | `padding: var(--hm-sw-viewer-panel-spacing)` 12px, `gap: 12px`, `box-shadow: inset 0 1px 0 #fff`, `margin-top: 0`(2026-10-23: 그룹 박스 사이는 본문 gap 8px만, 소비 앱 단일 class의 상단 여백 무시) | `SWViewerSection`의 **기본값**(`surface` 생략 시 card). plain Section의 상단 여백은 유지 | 공통 | `옵션`의 `선가중치`·`표시`·`2.5D` |
|
||||
| Card Section | 설정 그룹 묶음 | `.hm-sw-viewer-section[data-surface="card"]` | `1px solid var(--hm-sw-viewer-panel-inner-border)`(#948871) | `var(--hm-sw-viewer-panel-field-background)`(#f1ece1) | `var(--hm-sw-viewer-radius)` 4px | `padding: var(--hm-sw-viewer-panel-spacing)` 12px, `gap: 12px`, `box-shadow: inset 0 1px 0 #fff`, `margin-top: 0`(2026-10-23: 그룹 박스 사이는 본문 gap 8px만, 소비 앱 단일 class의 상단 여백 무시) | `SWViewerSection`의 **기본값**(`surface` 생략 시 card). plain Section의 상단 여백은 유지 | 공통 | `옵션`의 `선가중치`·`표시`·`2.5D`, `속성`의 `일반 정보 (GENERAL)`·`기하 속성 (GEOMETRY)`(2026-10-23) |
|
||||
| 검색 입력 | 레이어 검색 | `.hm-sw-theme .hm-sw-viewer-input[type="search"]` | `1px solid var(--hm-sw-viewer-panel-inner-border)` | field-background #f1ece1 | 4px | 80px 기본 폭, 높이 28px, `padding: 0 10px` | `type="search"`만. 값 입력(§5)과 다름 | 공통 | `레이어 (9개)` |
|
||||
| 패널 버튼 outline | 보조 버튼 | `.hm-sw-theme .hm-sw-viewer-button` | `1px solid var(--hm-sw-viewer-panel-primary)`(#123328) | #fff (`primary`는 #123328) | 4px | 높이 24px, `padding: 0 8px` | 제목줄의 `variant="ghost"`는 테두리·배경 없음(26 × 26) | 공통 | `모듈 구성` modal의 `확인`(primary). Settings Popup에는 ghost만 |
|
||||
|
||||
@@ -54,9 +54,9 @@ SWViewerPanel (= SWPopup, .hm-sw-property.hm-sw-viewer-panel) ← 테두리
|
||||
| 본문 | 스크롤 콘텐츠 영역 | `.hm-sw-property__body` + `.hm-sw-viewer-panel .hm-sw-property__body` | `padding: 7px 7px 0`, `border-bottom: 8px solid transparent`(스크롤 영역 밖 하단 여백), `gap: 8px`, `box-shadow: inset 0 2px 2px rgba(255,255,255,.6)`, 배경은 프레임 surface | 접힘이면 `display: none` | 공통(SWPopup 7px + 뷰어 하단 8px 덮어쓰기) | 전체 |
|
||||
| Field | 라벨 + 컨트롤 행 | `.hm-sw-viewer-field`, `__row` | 선·배경 없음, field `gap: 6px`, row `gap: 8px`, `min-height: 20px` | disabled면 `opacity: .5` | 공통 | `옵션` |
|
||||
| 값 입력·단위 칸 | 숫자 입력 | `.hm-sw-viewer-input:not([type="search"])`, `.hm-sw-viewer-field__control:has(> unit)` | 기본 **투명 테두리**(1px transparent), radius 2px, 높이 28px. Hover/편집 시에만 `--hm-sw-property-field-hover-border-color` 테두리, 편집 중 배경 `--hm-sw-property-field-editing-background` | 상태가 바뀔 때만 박스로 보임 | 공통 | `옵션`의 `표시 배율`(px/mm) |
|
||||
| Badge | 개수·유형 표시 | `.hm-sw-viewer-badge` | 테두리 없음, `background: var(--hm-sw-viewer-panel-badge-background)`(#d2c8b4), radius 4px, `padding: 2px 8px` | — | 공통 | 레이어 개수, `LINE · h=2F1A` |
|
||||
| Badge | 개수·유형 표시 | `.hm-sw-viewer-badge` | 테두리 없음, `background: var(--hm-sw-viewer-panel-badge-background)`(#d2c8b4), radius 4px, `padding: 2px 8px` | — | 공통 | 레이어 개수, `LINE · h=2F1A`(`속성` 맨 위, Card 밖, 자기 폭) |
|
||||
| 레이어 행 Hover | 행 강조 | `.sw-viewer-story-list li:hover` | `background: rgba(154,146,132,.25)`, radius 3px | Hover일 때만. 숨긴 레이어는 `opacity: .45` | Storybook 전용 | `레이어 (9개)` |
|
||||
| 속성 그룹 간격 | 두 속성 그룹 분리 | `.sw-viewer-story-props-next` | `margin-top: var(--hm-sw-viewer-panel-spacing)` 12px(본문 gap 8px과 합쳐 20px) | 두 번째 그룹 | Storybook 전용 | `속성` |
|
||||
| 속성 그룹 간격 | 두 속성 그룹 분리 | Card Section 사이 | 본문 `gap` 8px만(Card `margin-top: 0`, 2026-10-23 `.sw-viewer-story-props-next` 제거) | 두 Card 사이 | Storybook 전용 | `속성` |
|
||||
| Hint | 보조 설명 | `.hm-sw-viewer-hint` | 선·배경 없음, 12px | — | 공통 | `옵션` |
|
||||
| 빈 상태 | 선택 없음 안내 | `.sw-viewer-story-empty` | 선·배경 없음, `padding: 40px 0`, 가운데 정렬 | `PropertiesPanel selected={false}` | Storybook 전용 | `SW/Viewer › States` 등 |
|
||||
| Resize Grip | 크기 조절 | `.hm-sw-viewer-panel__resize` | 14 × 14, inner-border 색 빗금 그라데이션(선 아님) | `resizable` 이고 접힘이 아닐 때 | 공통 | 전체 |
|
||||
@@ -65,8 +65,8 @@ SWViewerPanel (= SWPopup, .hm-sw-property.hm-sw-viewer-panel) ← 테두리
|
||||
|
||||
1. **Card가 기본값인 이유:** `SWViewerSection`의 기본 `surface`는 `card`입니다. 그러나 레이어·속성 Popup은 모두 `plain`을 명시하고, card는 `옵션` Popup만 씁니다. 어느 콘텐츠에 card/plain을 쓰는지에 대한 디자인 기준 문서는 확인되지 않았습니다.
|
||||
2. **레이어 구분선 위치:** "전체 레이어 행 아래 `#d2c8b4` 1px 선, 검색과 사이에는 없음" 규칙은 `packages/sw/ai/VIEWER.md`에 소비 앱 규칙으로 적혀 있습니다. 실제 구현은 Storybook/예제의 소비 앱 CSS뿐이고 패키지 공통 스타일은 아닙니다.
|
||||
3. **구분선 색 두 가지:** 레이어 구분선은 `--hm-sw-property-table`(#d2c8b4)이고, 속성 행 선·Footer 선·Card 테두리는 `--hm-sw-viewer-panel-inner-border`(#948871)입니다. 용도별로 색을 나누는 기준은 문서화되어 있지 않습니다.
|
||||
4. **속성 행 마지막 선:** 각 그룹의 마지막 행에도 아래 선이 그려집니다(Storybook 전용 CSS). 의도인지 확인되지 않았습니다.
|
||||
3. **구분선 색 두 가지:** 레이어 구분선·속성 행 선(2026-10-23)은 `--hm-sw-property-table`(#d2c8b4)이고, Footer 선·Card 테두리는 `--hm-sw-viewer-panel-inner-border`(#948871)입니다. 용도별로 색을 나누는 기준은 문서화되어 있지 않습니다.
|
||||
4. **속성 행 마지막 선:** 2026-10-23 뷰어 화면 기준으로 각 Card의 마지막 행에는 선을 그리지 않습니다(Storybook 전용 CSS).
|
||||
5. **Footer 예시 부족:** Footer 구분선은 대표 Settings Popup에 없습니다. `Viewer Header` Story의 modal에서만 보이며, 비-modal 패널 Footer의 디자인 기준 화면은 확인되지 않았습니다.
|
||||
6. **입력 박스 두 형태:** 검색 입력은 항상 테두리 박스이고, 값 입력은 Hover/편집 때만 테두리가 생깁니다(2026-10-22 사용자 요청 주석). 다른 텍스트 입력(예: 검색이 아닌 일반 text)에 어느 쪽을 쓸지는 `type="search"` 여부로만 갈립니다.
|
||||
7. **Card 안쪽 하이라이트:** `box-shadow: inset 0 1px 0 #fff`는 하드코드 값이고 대응 토큰이 없습니다.
|
||||
@@ -194,6 +194,8 @@ export function OptionsPanel({ demo, ...placement }: { demo: ViewerDemo } & Pane
|
||||
)
|
||||
}
|
||||
|
||||
// 2026-10-23 (user request, viewer screenshot layout; same data): the id badge above two card groups.
|
||||
const ENTITY_ID = "LINE · h=2F1A"
|
||||
const ENTITY_ROWS: [string, string][] = [["유형", "LINE"], ["레이어", "CX-BORD-LIN1"], ["색상", "ByLayer"], ["선종류", "Continuous"]]
|
||||
const GEOMETRY_ROWS: [string, string][] = [["시작 X", "18432.512"], ["시작 Y", "2210.004"], ["끝 X", "18992.040"], ["끝 Y", "2210.004"], ["길이", "559.528"]]
|
||||
|
||||
@@ -205,8 +207,9 @@ export function PropertiesPanel({ demo, selected = true, ...placement }: { demo:
|
||||
<SWViewerPanel title="속성" open={demo.panels.properties} onClose={() => demo.toggle("properties", false)} {...placement}
|
||||
headerActions={selected ? <SWViewerButton variant="ghost" aria-label="선택 확대" title="선택 확대" onClick={() => demo.record("zoomToSelection (미연결)")}><ZoomIn size={16} /></SWViewerButton> : undefined}>
|
||||
{selected ? <>
|
||||
<SWViewerSection surface="plain" title="일반 정보 (General)"><SWViewerBadge>LINE · h=2F1A</SWViewerBadge>{rows(ENTITY_ROWS)}</SWViewerSection>
|
||||
<SWViewerSection surface="plain" title="기하 속성 (Geometry)" className="sw-viewer-story-props-next">{rows(GEOMETRY_ROWS)}</SWViewerSection>
|
||||
<SWViewerBadge className="sw-viewer-story-props-id">{ENTITY_ID}</SWViewerBadge>
|
||||
<SWViewerSection title="일반 정보 (General)">{rows(ENTITY_ROWS)}</SWViewerSection>
|
||||
<SWViewerSection title="기하 속성 (Geometry)">{rows(GEOMETRY_ROWS)}</SWViewerSection>
|
||||
</> : (
|
||||
<div className="sw-viewer-story-empty"><MousePointerClick size={24} aria-hidden="true" />도면에서 객체(엔티티)를 클릭하면<br />상세 속성이 표시됩니다</div>
|
||||
)}
|
||||
|
||||
@@ -34,12 +34,14 @@
|
||||
/* Visibility button around the public SWLayerVisibilityIcon (header bulb art, 20 x 20); 24 x 24 hit area kept. */
|
||||
.sw-viewer-story-bulb { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 4px; cursor: pointer; }
|
||||
.sw-viewer-story-bulb:hover { background: rgba(154, 146, 132, 0.3); }
|
||||
/* 속성 Popup (2026-10-23): the id badge above the card groups (own width); the groups are default card Sections, so the
|
||||
8px body gap alone separates them. Rows: name left, value right (ellipsis), thin property-table rule between rows. */
|
||||
.sw-viewer-story-props-id { align-self: flex-start; max-width: 100%; }
|
||||
.sw-viewer-story-props { margin: 0; }
|
||||
/* Property groups read as separate blocks: the panel spacing token on top of the shared 8px body gap (20px in all). */
|
||||
.sw-viewer-story-props-next { margin-top: var(--hm-sw-viewer-panel-spacing); }
|
||||
.sw-viewer-story-props > div { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--hm-sw-viewer-panel-inner-border); font-size: 14px; }
|
||||
.sw-viewer-story-props dt { color: var(--hm-sw-viewer-panel-label); font-weight: 500; }
|
||||
.sw-viewer-story-props dd { margin: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--hm-sw-viewer-panel-text); user-select: all; }
|
||||
.sw-viewer-story-props > div { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--hm-sw-property-table); font-size: 14px; }
|
||||
.sw-viewer-story-props > div:last-child { border-bottom: 0; }
|
||||
.sw-viewer-story-props dt { flex-shrink: 0; color: var(--hm-sw-viewer-panel-label); font-weight: 500; }
|
||||
.sw-viewer-story-props dd { min-width: 0; margin: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; text-align: right; color: var(--hm-sw-viewer-panel-text); user-select: all; }
|
||||
.sw-viewer-story-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 40px 0; text-align: center; font-size: 12px; color: var(--hm-sw-viewer-panel-label); }
|
||||
.sw-viewer-story-steps { margin: 0; padding-left: 20px; font-size: 14px; }
|
||||
.sw-viewer-story-context { display: flex; align-items: center; justify-content: center; height: 160px; border: 1px dashed #9a9284; border-radius: 4px; background: #f5f0e5; color: #3e3523; font-size: 13px; }
|
||||
|
||||
Reference in new issue
Block a user