feat(sw): measured header compaction, gauge recolor, popup menu and story cleanups
Deploy Storybook / deploy (push) Successful in 1m12s
Deploy Storybook / deploy (push) Successful in 1m12s
- SWHeader (760-1799px): pictures hide one at a time by measured room (치수 아이콘, 선 그림, 글꼴명, 색상 칩, 레이어 상태 아이콘), then the file name narrows 310 -> 96px, then values ellipsize; re-fit after web fonts load. 가중치/스케일 columns grow for longer values. - Gauge style B / property window range: Figma controll_bar_new 633:77827 colors, ring and shadow on the previous size (6px track, 14px thumb). - Property window: editable text values (e.g. 하이퍼링크) get the editing face like numbers. - SW Header › Logo: same cases, order and layout as SW Viewer › Logo (ID kept). - Storybook inner: 80vw from 1920px. Responsive More 1920px rows use the page's usable width (container sw-story-page) and span 1920px when there is room. - SW/Popup sidebar: Property Panel only; Custom Content / Multiple Popups tagged verification. - SW Viewer Settings Popup: 축척 지정 demo popup removed, frame 620px. - Tests: inventory / simplification sidebar expectations, Popup-only unit select check. Verified: check:ai-docs PASS, changed test syntax, headless Chrome checks of header compaction, Responsive 1920 rows (1920 hidden / 2560, 3840 shown), Popup sidebar, Settings Popup. Not verified: integrated-visual baselines (not updated), full regression, changed tests not run.
This commit is contained in:
1 parent
c1549b2b4f
commit
6d46289fc5
13 files changed
+133
-94
No files matched your search
@@ -43,6 +43,13 @@ const subControls: readonly SWHeaderSubControlId[] = ["documentNew", "documentOp
|
||||
const isMenu = (id: string): id is SWHeaderMenuId => id in menuSlot
|
||||
/** Header width from which nothing moves into More (2026-10-21): the header compresses instead. Below it, as before. */
|
||||
const MORE_BELOW = 760
|
||||
/** File name width from 760px up: Figma 310px, smallest 96px (sw.css .hm-sw-header__document). */
|
||||
const DOCUMENT_MAX = 310
|
||||
const DOCUMENT_MIN = 96
|
||||
/** Field pictures that hide one at a time while the header lacks room (sw.css [data-compact]). */
|
||||
const COMPACT_LEVELS = 5
|
||||
/** From this header width the Figma field boxes apply (sw.css "Responsive"). */
|
||||
const FIGMA_LAYOUT_FROM = 1800
|
||||
|
||||
/**
|
||||
* Order in which visible parts move into More when the measured object area has no room left (on top of the
|
||||
@@ -283,6 +290,43 @@ export const SWHeader = forwardRef<HTMLElement, SWHeaderProps>(function SWHeader
|
||||
}
|
||||
})
|
||||
|
||||
// 2026-10-22 (user request): from 760px to 1800px the space left decides, not fixed widths. While the object area lacks
|
||||
// room, the field pictures hide one at a time (data-compact 1-5: 치수 아이콘, 선 그림, 글꼴명, 색상 칩, 레이어 상태
|
||||
// 아이콘, sw.css), then the file name gives way (310 -> 96px), then the values ellipsize. With room to spare the
|
||||
// pictures stay and the file name keeps 310px.
|
||||
// Measured on every render and again once web fonts finish loading (text widths change, the header size does not).
|
||||
const fitFieldsRef = useRef(() => {})
|
||||
fitFieldsRef.current = () => {
|
||||
const header = fieldsRef.current?.closest<HTMLElement>(".hm-sw-header")
|
||||
const area = panelAnchorRef.current
|
||||
const fields = fieldsRef.current
|
||||
const documentBox = header?.querySelector<HTMLElement>(":scope > .hm-sw-header__bar > .hm-sw-header__document")
|
||||
if (!header || !area || !fields) return
|
||||
const reset = () => { fields.removeAttribute("data-compact"); documentBox?.style.removeProperty("flex-basis") }
|
||||
// From 1800px the fields are the fixed Figma boxes (pictures free no room) and the file name keeps its CSS clamp.
|
||||
if (controls !== undefined || headerWidth < MORE_BELOW || headerWidth >= FIGMA_LAYOUT_FROM) { reset(); return }
|
||||
documentBox?.style.setProperty("flex-basis", `${DOCUMENT_MAX}px`)
|
||||
let level = 0
|
||||
let room = 0
|
||||
for (; level <= COMPACT_LEVELS; level++) {
|
||||
fields.setAttribute("data-compact", String(level))
|
||||
room = measureRoom(header, area)
|
||||
if (room >= 0) break
|
||||
}
|
||||
if (level > COMPACT_LEVELS) fields.setAttribute("data-compact", String(COMPACT_LEVELS))
|
||||
if (room < 0 && documentBox) documentBox.style.setProperty("flex-basis", `${Math.max(DOCUMENT_MIN, DOCUMENT_MAX + room)}px`)
|
||||
}
|
||||
useLayoutEffect(() => fitFieldsRef.current())
|
||||
useEffect(() => {
|
||||
const fonts = typeof document === "undefined" ? undefined : document.fonts
|
||||
if (!fonts) return
|
||||
let active = true
|
||||
const refit = () => { if (active) fitFieldsRef.current() }
|
||||
fonts.addEventListener("loadingdone", refit)
|
||||
void fonts.ready.then(refit)
|
||||
return () => { active = false; fonts.removeEventListener("loadingdone", refit) }
|
||||
}, [])
|
||||
|
||||
// Logo (home) menu: SWHeader owns its open state; a logo click toggles it instead of calling onHomeClick.
|
||||
const homeMenuId = useId()
|
||||
const homeButtonRef = useRef<HTMLElement | null>(null)
|
||||
|
||||
@@ -241,7 +241,9 @@ export function PropertyEditor({ property, onChange, menus }: { property: SWHead
|
||||
<div className="hm-sw-property__row" data-property-id={property.id} data-type={type} data-disabled={disabled || undefined}>
|
||||
<label htmlFor={inputId} title={property.name}>{property.name}</label>
|
||||
{picker ? <SWHeaderPropertyPickerField picker={picker} property={property} id={inputId} editable={editable} menus={menus} commit={commit} parse={parse} /> : (
|
||||
<div className="hm-sw-property__value" data-field={field} data-on={field && editable && type === "number" ? "edit" : undefined}
|
||||
<div className="hm-sw-property__value" data-field={field}
|
||||
// 2026-10-22: editable text values (e.g. 하이퍼링크) get the same editing face as numbers.
|
||||
data-on={field && editable && (type === "number" || type === "text") ? "edit" : undefined}
|
||||
data-readonly={editable ? undefined : "true"}
|
||||
onMouseDown={field ? focusInput : undefined}>
|
||||
{type === "select" ? (
|
||||
|
||||
Reference in new issue
Block a user