fix(sw): 2026-10-21 SW design review and responsive header without More from 760px

User-approved design review (2026-10-21):
- SW Header: from 760px up nothing moves into More; the five menus stay with their
  titles (titles and values ellipsize), file name shrinks to 96px. Open next to the
  logo no longer blocks field shrinking above 760px (760/768 overflow fixed, also for
  configured `controls` headers). Dropdown yellow ring inside the button, black seam.
- Property Bar values as read-only red text; property popup "=" labels, read-only
  black values, per-entry hover with pointer.
- Home Menu recent files (3 rows, path + name caption, empty preview), Footer + slot
  guide off by default, Viewer file list without icons, Storybook widths 1920-760.
- Tests: old More expectations (integrated-improvement, keyboard-dismiss,
  footer-popup-viewer-refinement, storybook-cleanup-stage1) moved to the new rule;
  functional checks kept.
This commit is contained in:
shkim4 committed 2026-10-21 17:29:25 +09:00
1 parent a25d2b31c5
commit 2fc1b3e108
37 files changed
+447 -211

No files matched your search

+16 -11
View File
@@ -190,7 +190,7 @@ export const Overview: Story = {
render: () => <SWHeaderOverview initial={{ ...figmaArgs, ...callbacks }}
fixtures={{ documents: SAMPLE_DOCUMENTS, layers: PROPERTY_LAYERS, colors: FIGMA_COLORS, userColors: FIGMA_USER_COLORS,
lineTypes: PROPERTY_LINE_TYPES, lineWeights: FIGMA_LINE_WEIGHTS, textStyles: FIGMA_TEXT_STYLES, dimensionStyles: FIGMA_DIMENSION_STYLES }}
propertyGroups={PROPERTY_GROUPS} propertyFixture={propertyFixture} propertySelection={propertySelection} barFixture={BAR_FIXTURE}
propertyGroups={PROPERTY_GROUPS} propertyFixture={propertyFixture} propertySelection={propertySelection} barFixture={BAR_FIXTURE} barTitle={BAR_TITLE}
homeMenuSections={OVERVIEW_HOME_MENU} />,
}
@@ -422,7 +422,7 @@ export function ComposedDemo() {
onPanelToggle={() => { setActiveMenu(null); setPanel(next => !next); record(`onPropertyPanelOpenChange(${!panel})`) }} />
</div>
</div>
{bar && <SWHeaderPropertyBar selection={propertySelection("circle")} properties={panelProperties.filter(item => BAR_FIXTURE.some(barItem => barItem.id === item.id))}
{bar && <SWHeaderPropertyBar selection={{ ...propertySelection("circle"), title: BAR_TITLE }} properties={BAR_FIXTURE.flatMap(barItem => panelProperties.filter(item => item.id === barItem.id)).map(item => ({ ...item, readOnly: true }))}
onPropertyChange={(property, next) => change(property.id, next, "onPropertyChange")} />}
{panel && <SWHeaderPropertyPanel id={panelId} anchorRef={detailRef} selection={propertySelection("circle")} properties={panelProperties} groups={PROPERTY_GROUPS}
menus={{ ...menus, layers: availableLayers.map(layer => ({ ...layer, id: layer.name })) }}
@@ -776,7 +776,9 @@ function StyleHeader({ onLog, showState, ...props }: StyleHostProps) {
)
}
const MORE_WIDTHS = [1440, 768, 390]
// 2026-10-21: same widths as the SW Footer Responsive More. From 760px no More; the five menus stay in the header
// (그리기모드 text hides, then the file name and values shorten).
const MORE_WIDTHS = [1920, 1440, 1280, 950, 860, 760]
export const ResponsiveMore: Story = {
name: "Responsive More",
@@ -802,17 +804,17 @@ const PROPERTY_GROUPS: SWHeaderPropertyGroup[] = [
const PROPERTY_FIXTURE: SWHeaderProperty[] = [
{ id: "layer", name: "레이어", value: "0_Layer_Cludmark", type: "text", groupId: "common", picker: "layer", validate: draft => draft.length <= 40 },
{ id: "color", name: "색상", value: "255,229,0", type: "color", groupId: "common" },
{ id: "line", name: "선스타일", value: "Continuous", type: "select", groupId: "common", unit: "(ByL)", linePreview: true, options: [{ id: "Continuous", name: "Continuous" }, { id: "CENTER", name: "CENTER" }, { id: "HIDDEN", name: "HIDDEN" }] },
{ id: "weight", name: "선가중치", value: "0.25", type: "number", groupId: "common", min: 0 },
{ id: "line", name: "선꼴", value: "Continuous", type: "select", groupId: "common", unit: "(ByL)", linePreview: true, options: [{ id: "Continuous", name: "Continuous" }, { id: "CENTER", name: "CENTER" }, { id: "HIDDEN", name: "HIDDEN" }] },
{ id: "weight", name: "선가중치", value: "0.25", type: "number", groupId: "common", min: 0, annotation: "(ByD, ByL)" },
{ id: "scale", name: "선축적", value: "1.0000", type: "number", groupId: "common", min: .0001, decimals: 4, unit: "(LTscale:1)" },
{ id: "opacity", name: "투명도", value: "0.25", type: "slider", groupId: "common", min: 0, max: 1, step: .01, annotation: "(ByL)", unit: "%" },
{ id: "link", name: "하이퍼링크", value: "--", type: "text", groupId: "common" },
{ id: "thickness", name: "두께", value: "0.25", type: "number", groupId: "common", unit: "mm", min: 0 },
{ id: "material", name: "재료", value: "-", type: "computed", groupId: "common", unit: "(ByL)" },
{ id: "circumference", name: "원주", value: "0.25", type: "computed", groupId: "shape", graphicSlot: "circumference" },
{ id: "circumference", name: "원주", value: "0.25", type: "number", groupId: "shape", graphicSlot: "circumference", min: 0 },
{ id: "diameter", name: "지름", value: "8.1502", type: "number", groupId: "shape", graphicSlot: "diameter", min: 0 },
{ id: "radius", name: "반지름", value: "4.0526", type: "number", groupId: "shape", graphicSlot: "radius", min: 0 },
{ id: "area", name: "면적", value: "51.5962", type: "computed", groupId: "shape", graphicSlot: "area" },
{ id: "area", name: "면적", value: "51.5962", type: "number", groupId: "shape", graphicSlot: "area", min: 0 },
{ id: "x", name: "X", value: "48.0808", type: "number", groupId: "position" },
{ id: "y", name: "Y", value: "14.9160", type: "number", groupId: "position" },
{ id: "z", name: "Z", value: "0.0000", type: "number", groupId: "position" },
@@ -886,11 +888,14 @@ export const KGuide: Story = {
parameters: { controls: { disable: true } },
render: () => <StoryPage><StoryPageHeader kicker={KICKER} title="K 가이드 반복 애니메이션" description="기존 K 버튼 Hover/Focus → 원본 이미지 Pan·Zoom 반복. 영역을 벗어나면 정지, 재진입은 처음부터. Reduced Motion은 정지 이미지." /><div className="sw-story-property-room"><SWHeader {...figmaArgs} {...callbacks} /></div></StoryPage>,
}
/* 2026-10-21: the property Bar shows the object's calculated values in this order; they are not edited there (computed,
plain text without focus). The Bar's object text is the object type only (원). */
const BAR_TITLE = "원"
const BAR_FIXTURE: SWHeaderProperty[] = [
{ id: "radius", name: "반지름", value: "4.0526", type: "number", groupId: "shape", min: 0 },
{ id: "diameter", name: "지름", value: "8.1052", type: "number", groupId: "shape", min: 0 },
{ id: "circumference", name: "원주", value: "8.1052", type: "number", groupId: "shape", min: 0 },
{ id: "area", name: "면적", value: "51.5962", type: "number", groupId: "shape", min: 0 },
{ id: "radius", name: "반지름", value: "4.0526", type: "computed", groupId: "shape" },
{ id: "diameter", name: "지름", value: "8.1052", type: "computed", groupId: "shape" },
{ id: "circumference", name: "원주", value: "8.1052", type: "computed", groupId: "shape" },
{ id: "area", name: "면적", value: "51.5962", type: "computed", groupId: "shape" },
]
/* Property panel: the four Figma states with the same component and host data. */
const PROPERTY_STATES: { example: PropertyExample; title: string }[] = [