@things-factory/figure-ui 10.1.210 → 10.1.212
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/graphql/index.ts +1 -1
- package/client/modeller/angle-dial.ts +1 -1
- package/client/modeller/canvas.ts +1 -1
- package/client/modeller/editor.ts +24 -32
- package/client/modeller/figure-history-panel.ts +1 -1
- package/client/modeller/figure-links.ts +61 -37
- package/client/modeller/figure-parts.ts +3 -3
- package/client/modeller/figure-settings.ts +1 -1
- package/client/modeller/figure-size-editor.ts +41 -4
- package/client/modeller/links.ts +63 -24
- package/client/modeller/live.ts +33 -0
- package/client/modeller/scene-budget.ts +3 -3
- package/client/modeller/thumbnail.ts +1 -1
- package/client/pages/figure-list-page.ts +2 -2
- package/client/pages/figure-modeller-page.ts +4 -4
- package/client/types.ts +2 -2
- package/client/viewparts/figure-thumb.ts +1 -1
- package/dist-client/graphql/index.d.ts +1 -1
- package/dist-client/graphql/index.js +1 -1
- package/dist-client/graphql/index.js.map +1 -1
- package/dist-client/modeller/angle-dial.d.ts +1 -1
- package/dist-client/modeller/angle-dial.js.map +1 -1
- package/dist-client/modeller/canvas.js +1 -1
- package/dist-client/modeller/canvas.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +5 -0
- package/dist-client/modeller/editor.js +24 -32
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/figure-history-panel.d.ts +1 -1
- package/dist-client/modeller/figure-history-panel.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +2 -0
- package/dist-client/modeller/figure-links.js +66 -39
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/figure-parts.d.ts +3 -3
- package/dist-client/modeller/figure-parts.js.map +1 -1
- package/dist-client/modeller/figure-settings.js +1 -1
- package/dist-client/modeller/figure-settings.js.map +1 -1
- package/dist-client/modeller/figure-size-editor.d.ts +3 -1
- package/dist-client/modeller/figure-size-editor.js +45 -4
- package/dist-client/modeller/figure-size-editor.js.map +1 -1
- package/dist-client/modeller/links.d.ts +15 -6
- package/dist-client/modeller/links.js +63 -25
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/live.d.ts +14 -0
- package/dist-client/modeller/live.js +31 -0
- package/dist-client/modeller/live.js.map +1 -1
- package/dist-client/modeller/scene-budget.d.ts +3 -3
- package/dist-client/modeller/scene-budget.js +3 -3
- package/dist-client/modeller/scene-budget.js.map +1 -1
- package/dist-client/modeller/thumbnail.js +1 -1
- package/dist-client/modeller/thumbnail.js.map +1 -1
- package/dist-client/pages/figure-list-page.d.ts +1 -1
- package/dist-client/pages/figure-list-page.js +2 -2
- package/dist-client/pages/figure-list-page.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.d.ts +3 -3
- package/dist-client/pages/figure-modeller-page.js +4 -4
- package/dist-client/pages/figure-modeller-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/types.d.ts +2 -2
- package/dist-client/types.js +1 -1
- package/dist-client/types.js.map +1 -1
- package/dist-client/viewparts/figure-thumb.js +1 -1
- package/dist-client/viewparts/figure-thumb.js.map +1 -1
- package/docs/multipart-response-review-2026-10-24.md +1 -1
- package/docs/response-authoring-2026-10-24.md +4 -4
- package/package.json +6 -6
- package/test/ai-proposal.test.ts +1 -1
- package/test/align.test.ts +1 -1
- package/test/browser/editing.check.mjs +38 -0
- package/test/browser/modeller.check.mjs +55 -0
- package/test/command-preview.test.ts +3 -3
- package/test/fields.test.ts +2 -2
- package/test/first-minute.test.ts +5 -5
- package/test/first-save.test.ts +3 -3
- package/test/gizmo.test.ts +3 -3
- package/test/keys.test.ts +2 -2
- package/test/layout.test.ts +1 -1
- package/test/links.test.ts +53 -14
- package/test/live.test.ts +4 -4
- package/test/material.test.ts +1 -1
- package/test/properties.test.ts +1 -1
- package/test/proposal-record.test.ts +1 -1
- package/test/refusals.test.ts +1 -1
- package/test/resize-with-placement.test.ts +1 -1
- package/test/scene-budget.test.ts +4 -4
- package/test/verdict.test.ts +1 -1
- package/translations/en.json +3 -0
- package/translations/es.json +3 -0
- package/translations/ja.json +3 -0
- package/translations/ko.json +109 -106
- package/translations/ms.json +3 -0
- package/translations/zh.json +3 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-parts.js","sourceRoot":"","sources":["../../client/modeller/figure-parts.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/input/ox-input-file.js'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { DETAIL_LEVELS, PART_LIMIT, type DetailLevel } from '@hatiolab/figure-model'\nimport type { FigurePrimitiveCreation } from '@hatiolab/figure-model'\nimport type { FigureBudgetLine } from './maturity.js'\nimport { partLabelOf } from './fields.js'\n\n/**\n * 도형 팔레트와 부품 목록 — 자산의 것.\n *\n * 팔레트는 목록 위에, 눈 단추는 늘 자리를 차지하고, 조작은 고른 줄에서만 보인다.\n *\n * 부품의 도형은 평가가 준 형상에서 읽은 시작 모양 이름(`kind`)으로 보인다. 「숨김」은 여기서도 **작업대의 것**이다 — 저장되지 않고, 자산의 `visibility`(상태에 따라\n * 보이고 안 보이는 것)와는 다른 것이다. 그것은 속성 패널의 몫이다.\n *\n * 이 컴포넌트는 정본을 만지지 않는다. 무엇을 하겠다는 것만 알린다.\n */\n\n/** 한 줄 — 평가에서 이 패널이 읽는 것만. */\nexport interface FigurePartRow {\n id: string\n /** 시작 모양 이름(`startingShapeKindOfBody`): 상자 · 원기둥 … 아이콘을 고른다. */\n kind: string\n /** 작업대에서 잠깐 가린 것. 저장되지 않는다. */\n hidden?: boolean\n /** 자산이 지금 상태에서 보이지 않는다고 한 것. 저장되는 것이고, 여기서는 표시만 한다. */\n invisible?: boolean\n /** 되풀이한 부품이면 지금 몇 개로 그려지나. 되풀이는 한 부품이다 — 한 줄로 보인다. */\n copies?: number\n /**\n * 바로 붙어 있는 곳: `대상 부품 · 대상 면`. 목록은 평평한 채로 두고 보조 문구로만 적는다 — 순서도 들여쓰기도\n * 붙임 때문에 바뀌지 않는다(ADR-0097 §5.5, 설계자 2026-09-27).\n */\n fastenedTo?: string\n}\n\n/** 시작 모양마다의 아이콘. Material Symbols 이름이다. */\nconst KIND_ICON: Record<string, string> = {\n cube: 'deployed_code',\n cylinder: 'database',\n frustum: 'change_history',\n sphere: 'circle',\n 'rounded-box': 'crop_square',\n 'hollow-box': 'check_box_outline_blank',\n polygon: 'pentagon',\n pyramid: 'details',\n portal: 'door_front'\n}\n\n/** 팔레트 — 저작 API 가 만들 수 있는 것만 보인다. */\n/*\n The palette: starting shapes (ADR-0100 §2.1). A plate and a wall are boxes of a shape a person reaches for, so they are\n starting sizes, not kinds of their own. A rounded box and a box open at the top are not here: they are a box with its\n corners rounded or an inside made, from the part's own 단면 section (§3.3), so the palette does not offer a second way.\n*/\n/* A mesh part is made from a file (`import-mesh`), not from a starting size. */\nexport type FigurePaletteKind = Exclude<FigurePrimitiveCreation['kind'], 'mesh'> | 'plate' | 'wall'\nconst RECIPES: Array<{ kind: FigurePaletteKind; icon: string; label: string }> = [\n { kind: 'box', icon: 'deployed_code', label: 'figure.label.primitive-cube' },\n { kind: 'cylinder', icon: 'database', label: 'figure.label.primitive-cylinder' },\n { kind: 'sphere', icon: 'circle', label: 'figure.label.primitive-sphere' },\n { kind: 'frustum', icon: 'change_history', label: 'figure.label.primitive-frustum' },\n { kind: 'polygon', icon: 'hexagon', label: 'figure.label.primitive-polygon' },\n { kind: 'pyramid', icon: 'details', label: 'figure.label.primitive-pyramid' },\n { kind: 'plate', icon: 'check_box_outline_blank', label: 'figure.label.primitive-plate' },\n { kind: 'wall', icon: 'crop_portrait', label: 'figure.label.primitive-wall' },\n { kind: 'portal', icon: 'door_front', label: 'figure.label.primitive-portal' }\n]\n\n@customElement('figure-parts')\nexport class FigureParts extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n background-color: var(--md-sys-color-surface-container-lowest);\n /* The divider beside it is the editor's frame's (ox-three-pane). */\n color: var(--md-sys-color-on-surface);\n font: var(--label-font, inherit);\n font-size: var(--ui-t-small, 11.5px);\n /* Folds by its own width: the editor gives this column 140 px when it has two columns (UX, 2026-09-24). */\n container-type: inline-size;\n }\n section {\n padding: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n section[list] {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n }\n h3 {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 6px;\n margin: 0 0 6px 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n /* The cost line: the grade's letter in its colour, then what the figure costs. */\n button[model-root] {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-height: 32px;\n padding: 4px 8px;\n border: 1px solid transparent;\n border-radius: 6px;\n background: none;\n font: inherit;\n font-weight: 600;\n text-align: start;\n color: var(--md-sys-color-on-surface);\n cursor: pointer;\n }\n button[model-root] span {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n /* Chosen: a frame and a tint, not colour alone. */\n button[model-root][on] {\n border-color: var(--md-sys-color-primary);\n background: var(--md-sys-color-primary-container);\n }\n button[model-root]:focus-visible {\n outline: 2px solid var(--md-sys-color-primary);\n outline-offset: 1px;\n }\n /* The cost line as a line, not a card; lit under the hand like the rest of the list. */\n button[budget] {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n width: 100%;\n margin: 0 0 6px;\n padding: 4px 6px;\n font: inherit;\n font-size: var(--ui-t-micro, 11px);\n line-height: 1.5;\n text-align: left;\n color: var(--md-sys-color-on-surface-variant);\n background: none;\n border: 1px solid transparent;\n border-radius: 4px;\n cursor: pointer;\n }\n button[budget]:hover {\n background: var(--md-sys-color-surface-container);\n }\n button[budget] b {\n flex: none;\n min-width: 16px;\n text-align: center;\n border-radius: 4px;\n color: var(--md-sys-color-on-primary-container);\n background: var(--md-sys-color-primary-container);\n }\n button[budget][grade='C'] b {\n color: var(--md-sys-color-on-tertiary-container);\n background: var(--md-sys-color-tertiary-container);\n }\n button[budget][grade='D'] {\n border-color: var(--md-sys-color-error);\n }\n button[budget][grade='D'] b {\n color: var(--md-sys-color-on-error);\n background: var(--md-sys-color-error);\n }\n button[budget] em {\n display: block;\n font-style: normal;\n color: var(--md-sys-color-error);\n }\n span[room][full] {\n color: var(--md-sys-color-error);\n font-weight: 600;\n }\n p[full] {\n margin: 4px 0 0;\n font-size: var(--ui-t-micro, 11px);\n color: var(--md-sys-color-error);\n }\n div[level] {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr);\n align-items: center;\n gap: 6px;\n margin: 0 0 6px;\n font-size: var(--ui-t-micro, 11px);\n color: var(--md-sys-color-on-surface-variant);\n }\n /* A field in the side panel's look (side-panel-styles): 26px, a quiet ground, its line only under the hand. */\n div[level] select {\n min-width: 0;\n min-height: 26px;\n padding: 2px 4px;\n font: inherit;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--md-sys-color-on-surface);\n background: var(--md-sys-color-surface-container-low);\n border: 1px solid transparent;\n border-radius: 4px;\n }\n div[level] select:hover:not(:disabled) {\n border-color: var(--md-sys-color-outline-variant);\n }\n small[copies] {\n color: var(--md-sys-color-on-surface-variant);\n }\n span[room] {\n font-size: var(--ui-t-micro, 11px);\n font-weight: 400;\n letter-spacing: 0;\n text-transform: none;\n }\n /* Three to a row, small (user, 2026-09-24): the palette is reached for, not read -- the list below is what grows. */\n div[palette] {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 3px;\n }\n /* A tile with no outline: its icon and name, lit under the hand -- ten outlined tiles were the boxiest part of the screen (user 2026-10-17). */\n button[shape] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1px;\n min-width: 0;\n padding: 5px 1px 4px;\n font: var(--label-font, inherit);\n font-size: var(--ui-t-micro, 11px);\n line-height: 1.2;\n text-align: center;\n overflow-wrap: anywhere;\n /* A tile's name on one line, so the nine stand one height; a long name ends in an ellipsis, its title says it all. */\n white-space: nowrap;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n background: none;\n border: 1px solid transparent;\n border-radius: 4px;\n cursor: pointer;\n }\n /*\n A file brought in is not a starting shape: its own row under the nine, its words on one line. As a tenth tile its\n two-word name broke onto two lines and stood it taller than the rest (2026-10-16).\n */\n button[shape] > span {\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n /*\n The one file picker (ox-input-file, quiet) on that row: a GLB refused or going up is said on the spot. Its button\n wears the tiles' words and lit hand -- the picker's own 13/600 stood louder than the shapes' heading.\n */\n ox-input-file[mesh-file] {\n grid-column: 1 / -1;\n justify-content: center;\n font-size: var(--ui-t-micro, 11px);\n --ox-input-file-action-height: 26px;\n }\n ox-input-file[mesh-file]::part(attach) {\n gap: 6px;\n padding: 0 8px;\n font: var(--label-font, inherit);\n font-size: var(--ui-t-micro, 11px);\n font-weight: 400;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n border-radius: 4px;\n }\n ox-input-file[mesh-file]:not([disabled])::part(attach):hover {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n }\n ox-input-file[mesh-file][disabled]::part(attach) {\n opacity: 0.35;\n }\n ox-input-file[mesh-file] md-icon {\n --md-icon-size: 18px;\n }\n section[shapes].candrop {\n outline: 1px dashed var(--md-sys-color-primary);\n outline-offset: -1px;\n }\n /* An action in the side panel's look: icon and words in the primary colour, no pill. */\n button[recipe-catalog] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 6px;\n margin-left: -6px;\n font: inherit;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--md-sys-color-primary);\n background: none;\n border: 1px solid transparent;\n border-radius: 4px;\n cursor: pointer;\n }\n button[recipe-catalog]:hover:not(:disabled) {\n background: var(--md-sys-color-surface-container);\n }\n button[shape]:hover:not([disabled]) {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-color: transparent;\n }\n button[shape][disabled] {\n opacity: 0.35;\n cursor: default;\n }\n button[shape] md-icon {\n --md-icon-size: 18px;\n }\n ol {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n li {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 6px;\n border-radius: 6px;\n cursor: pointer;\n }\n li:hover {\n background-color: var(--md-sys-color-surface-container);\n }\n li[selected] {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n }\n /*\n Icons by role, three sizes on the whole screen (2026-10-16; there were six): 20 for the bar, the tabs and the\n model's head, 18 for a palette tile, 16 beside words and on a row.\n */\n button[model-root] md-icon {\n --md-icon-size: 20px;\n }\n /* Beside its words, as every icon on a button with words is; without a size it stood at md-icon's own 24. */\n button[recipe-catalog] md-icon {\n --md-icon-size: 16px;\n }\n li md-icon {\n --md-icon-size: 16px;\n flex: none;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n button[eye][all] {\n margin-left: auto;\n opacity: 0.75;\n }\n button[eye][all]:hover {\n opacity: 1;\n }\n button[eye] {\n display: flex;\n flex: none;\n padding: 1px;\n color: inherit;\n background: none;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n opacity: 0;\n }\n li:hover button[eye],\n li[selected] button[eye],\n button[eye][off] {\n opacity: 1;\n }\n button[eye][off] {\n color: var(--md-sys-color-tertiary);\n }\n button[eye] md-icon {\n --md-icon-size: 16px;\n color: inherit;\n }\n li[off] span[label],\n li[off] > md-icon,\n li[invisible] span[label],\n li[invisible] > md-icon {\n opacity: 0.45;\n }\n li[selected] md-icon {\n color: inherit;\n }\n span[label] {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--ui-t-body, 13px);\n }\n span[label] small {\n margin-left: 4px;\n font-size: var(--ui-t-micro, 11px);\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n div[ops] {\n display: none;\n gap: 1px;\n }\n li[selected] div[ops] {\n display: flex;\n }\n div[ops] button {\n display: flex;\n padding: 2px;\n color: inherit;\n background: none;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n }\n div[ops] button:hover:not([disabled]) {\n background-color: var(--md-sys-color-surface-container-lowest);\n }\n div[ops] button[disabled] {\n opacity: 0.3;\n cursor: default;\n }\n div[ops] md-icon {\n --md-icon-size: 16px;\n color: inherit;\n }\n /*\n Under 200 px the selected row's four buttons pushed its name out and the last one past the edge (seen at 140,\n 2026-09-24). They go to a line of their own under the name.\n */\n @container (max-width: 199px) {\n li[selected] {\n flex-wrap: wrap;\n }\n li[selected] div[ops] {\n flex-basis: 100%;\n justify-content: flex-end;\n }\n }\n p[quiet] {\n margin: 0;\n font-size: var(--ui-t-small, 11.5px);\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n `\n ]\n\n @property({ type: Array }) parts: FigurePartRow[] = []\n /** 고른 부품의 id. 자리(index)가 아니다 — 부품은 id 로 안정하게 가리킨다. */\n @property({ type: String }) selected = ''\n /** The model's own name, the list's root: choosing it shows the model's settings (B.1). */\n @property({ type: String }) modelName = ''\n /** 편집할 수 없을 때(불러오는 중 · 저장 중) 팔레트와 조작을 잠근다. */\n @property({ type: Boolean }) locked = false\n /**\n * 이 도형이 치르는 값 — 삼각형 · 묶음 · 한 화면에 몇 대 · 등급. 부품을 더하는 바로 그 자리에서 보여야 로우폴리의\n * 기준이 저작을 이끈다. 등급이 D 면 무엇이 넘쳤는지를 적는다. 누르면 성숙도 탭이 열린다.\n */\n @property({ attribute: false }) budget?: FigureBudgetLine\n /**\n * 디테일 등급(S/M/L)의 부품 한도(사용자 2026-09-24). 부품을 넣기 **전에** 몇 개 남았는지 보이고, 다 차면 팔레트가\n * 잠긴다. 되풀이는 한 부품으로 센다. 등급을 안 정했으면 한도는 없다.\n */\n @property({ attribute: false }) partBudget?: { level: DetailLevel | null; used: number; limit: number | null }\n /** How many recipe templates the catalog holds; none, and the section is not drawn. */\n @property({ type: Number }) recipeCount = 0\n /** How far the GLB being brought in has gone up (0‒1), while it does; the picker shows it. */\n @property({ type: Number }) meshProgress?: number\n\n /* A GLB dragged over the shapes is a part brought in: the section is where it is dropped (page standard §7-1). */\n @query('section[shapes]') private shapes?: HTMLElement\n\n firstUpdated() {\n /* The drop area is drawn by the first render; the picker is told it by the next. */\n this.requestUpdate()\n }\n\n render() {\n const b = this.partBudget\n const full = !!b && b.limit !== null && b.used >= b.limit\n return html`\n <section shapes>\n <h3>${i18next.t('figure.label.shapes')}</h3>\n <div palette>\n ${RECIPES.map(\n recipe => html`\n <button\n shape\n ?disabled=${this.locked || full}\n title=${full ? i18next.t('figure.text.part-limit-reached') : i18next.t(recipe.label)}\n @click=${() => this.ask('add-part', { kind: recipe.kind })}\n >\n <md-icon>${recipe.icon}</md-icon>\n <span>${i18next.t(recipe.label)}</span>\n </button>\n `\n )}\n <ox-input-file\n quiet\n hide-filelist\n mesh-file\n accept=\".glb,model/gltf-binary\"\n .label=${i18next.t('figure.button.import-mesh')}\n title=${full ? i18next.t('figure.text.part-limit-reached') : i18next.t('figure.text.import-mesh-hint')}\n ?disabled=${this.locked || full}\n .dropTarget=${this.shapes}\n .progress=${this.meshProgress}\n @change=${(e: CustomEvent) => {\n const file = (e.detail as File[] | undefined)?.[0]\n if (file) this.ask('import-mesh', { file })\n ;(e.currentTarget as HTMLElement & { reset(): void }).reset()\n }}\n ><md-icon slot=\"icon\">view_in_ar</md-icon></ox-input-file>\n </div>\n ${full ? html`<p full>${i18next.t('figure.text.part-limit-reached-short', { level: b!.level, limit: b!.limit })}</p>` : nothing}\n </section>\n ${this.renderRecipes(full)}\n\n <section list>\n <!--\n The list's root: the model by its name. Choosing it shows the model's settings -- not \"select all\", not \"fit the\n view\" -- the same move as the model name in the properties panel's path (designer 2026-09-27, B.1).\n -->\n <button\n model-root\n aria-pressed=${String(!this.selected)}\n ?on=${!this.selected}\n title=${i18next.t('figure.button.show-model-settings')}\n aria-label=${`${i18next.t('figure.button.show-model-settings')}: ${this.modelName || i18next.t('figure.text.new-figure-name')}`}\n @click=${() => this.dispatchEvent(new CustomEvent('show-model-settings', { bubbles: true, composed: true }))}\n >\n <md-icon>category</md-icon><span>${this.modelName || i18next.t('figure.text.new-figure-name')}</span>\n </button>\n <h3>\n <span>${i18next.t('figure.label.parts')}</span>\n <span room ?full=${full} title=${i18next.t('figure.text.limit-comes-from-level')}\n >${b && b.limit !== null ? i18next.t('figure.text.n-of-limit', { used: b.used, limit: b.limit }) : (b?.used ?? this.parts.length)}</span\n >\n ${this.renderShowAll()}\n </h3>\n ${this.renderLevel()}\n ${this.renderBudget()}\n ${this.parts.length === 0\n ? html`<p quiet>${i18next.t('figure.text.no-parts-yet')}</p>`\n : html`<ol>\n ${this.parts.map((part, index) => this.renderRow(part, index))}\n </ol>`}\n </section>\n `\n }\n\n /** 디테일 등급 — 고르면 한도가 바뀐다. 목록 머리 아래. */\n private renderLevel() {\n const b = this.partBudget\n /* Not before the first part: a level with nothing to limit was the first choice a new figure met (U09). Once set, it shows. */\n if (!b || (!this.parts.length && !b.level)) return nothing\n return html`<div level>\n <label for=\"detail-level\">${i18next.t('figure.label.detail-level')}</label>\n <select\n id=\"detail-level\"\n title=${i18next.t('figure.text.detail-level-explained')}\n .value=${b.level ?? ''}\n ?disabled=${this.locked}\n @change=${(e: Event) => {\n const value = (e.target as HTMLSelectElement).value\n this.dispatchEvent(new CustomEvent('set-detail-level', { detail: { level: value || null }, bubbles: true, composed: true }))\n }}\n >\n <option value=\"\" ?selected=${!b.level}>${i18next.t('figure.label.detail-none')}</option>\n ${DETAIL_LEVELS.map(\n one => html`<option value=${one} ?selected=${one === b.level}>\n ${one} ${i18next.t('figure.label.detail-' + one)} · ${i18next.t('figure.text.n-parts-at-most', { limit: PART_LIMIT[one] })}\n </option>`\n )}\n </select>\n </div>`\n }\n\n private renderBudget() {\n const b = this.budget\n if (!b || !this.parts.length) return nothing\n const over = b.grade === 'D'\n return html`<button\n budget\n grade=${b.grade}\n title=${i18next.t('figure.text.parts-budget-open')}\n @click=${() => this.dispatchEvent(new CustomEvent('show-maturity', { bubbles: true, composed: true }))}\n >\n <b>${b.grade}</b>\n <span>\n <strong performance-cost>${i18next.t('figure.label.performance-cost')}</strong>\n ${i18next.t('figure.text.parts-budget', {\n triangles: b.triangles.toLocaleString(),\n groups: b.groups.toLocaleString(),\n instances: b.instances.toLocaleString()\n })}\n ${over\n ? html`<em\n >${i18next.t('figure.text.parts-budget-over', {\n budget: i18next.t('figure.label.budget-' + b.tightest.key),\n used: b.tightest.used.toLocaleString(),\n limit: b.tightest.limit.toLocaleString()\n })}</em\n >`\n : nothing}\n </span>\n </button>`\n }\n\n /** 한꺼번에 감추고 한꺼번에 되돌린다 — 하나라도 감춰져 있으면 다 되돌리고, 다 보이면 다 감춘다. */\n private renderShowAll() {\n if (this.parts.length === 0) return nothing\n const anyHidden = this.parts.some(part => part.hidden)\n return html`\n <button\n eye\n all\n ?off=${!anyHidden}\n title=${i18next.t(anyHidden ? 'figure.text.show-all-parts' : 'figure.text.hide-all-parts')}\n @click=${(e: Event) => {\n e.stopPropagation()\n this.ask('set-all-parts-hidden', { hidden: !anyHidden })\n }}\n >\n <md-icon>${anyHidden ? 'visibility' : 'visibility_off'}</md-icon>\n </button>\n `\n }\n\n private renderRow(part: FigurePartRow, index: number) {\n const selected = part.id === this.selected\n const off = !!part.hidden\n return html`\n <li\n ?selected=${selected}\n ?off=${off}\n ?invisible=${!!part.invisible}\n @click=${() => this.ask('select-part', { id: part.id })}\n >\n <button\n eye\n ?off=${off}\n title=${i18next.t(off ? 'figure.text.show-this-part' : 'figure.text.hide-this-part')}\n @click=${(e: Event) => {\n e.stopPropagation()\n this.ask('toggle-part-hidden', { id: part.id })\n }}\n >\n <md-icon>${off ? 'visibility_off' : 'visibility'}</md-icon>\n </button>\n <md-icon>${KIND_ICON[part.kind] ?? 'deployed_code'}</md-icon>\n <span label title=${part.id}\n >${partLabelOf(part.id)}${part.copies ? html` <small copies>× ${part.copies}</small>` : nothing}${part.invisible ? html`<small>${i18next.t('figure.label.state-hidden')}</small>` : nothing}${part.fastenedTo\n ? html`<small fastened-to title=${i18next.t('figure.label.fastened-to')}>${part.fastenedTo}</small>`\n : nothing}</span\n >\n ${selected ? this.renderOps(part.id, index) : nothing}\n </li>\n `\n }\n\n /** 고른 줄의 조작. 못 하는 것은 빼지 않고 흐리게 둔다 — 자리가 밀리면 연달아 지우다 엉뚱한 것을 누른다. */\n private renderOps(id: string, index: number) {\n const count = this.parts.length\n const op = (name: string, icon: string, detail: object, enabled = true) => html`\n <button\n op=${name}\n ?disabled=${!enabled || this.locked}\n title=${i18next.t('figure.button.' + name)}\n @click=${(e: Event) => {\n e.stopPropagation()\n if (enabled && !this.locked) this.ask(name, detail)\n }}\n >\n <md-icon>${icon}</md-icon>\n </button>\n `\n return html`\n <div ops>\n ${op('move-part-up', 'arrow_upward', { id, to: index - 1 }, index > 0)}\n ${op('move-part-down', 'arrow_downward', { id, to: index + 1 }, index < count - 1)}\n ${op('duplicate-part', 'content_copy', { id })} ${op('remove-part', 'delete', { id })}\n </div>\n `\n }\n\n /**\n * Recipes (ADR-0095): the catalog of templates -- a door, a roller row -- opened over the modeller, put onto the chosen\n * part in one step.\n */\n private renderRecipes(full: boolean) {\n if (!this.recipeCount) return nothing\n return html`<section recipes>\n <h3>${i18next.t('figure.label.recipes')}</h3>\n <button recipe-catalog ?disabled=${this.locked || full} @click=${() => this.ask('open-recipe-catalog', {})}>\n <md-icon>widgets</md-icon>${i18next.t('figure.button.open-recipe-catalog', { count: this.recipeCount })}\n </button>\n </section>`\n }\n\n /** 정본을 고치지 않는다 — 무엇을 하겠다는 것만 알린다. */\n private ask(what: string, detail: object) {\n this.dispatchEvent(new CustomEvent(what, { detail, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-parts.js","sourceRoot":"","sources":["../../client/modeller/figure-parts.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/input/ox-input-file.js'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { DETAIL_LEVELS, PART_LIMIT, type DetailLevel } from '@hatiolab/figure-model'\nimport type { FigurePrimitiveCreation } from '@hatiolab/figure-model'\nimport type { FigureBudgetLine } from './maturity.js'\nimport { partLabelOf } from './fields.js'\n\n/**\n * 부품 팔레트와 부품 목록 — 자산의 것.\n *\n * 팔레트는 목록 위에, 눈 단추는 늘 자리를 차지하고, 조작은 고른 줄에서만 보인다.\n *\n * 부품은 평가가 준 형상에서 읽은 시작 모양 이름(`kind`)으로 보인다. 「숨김」은 여기서도 **작업대의 것**이다 — 저장되지 않고, 자산의 `visibility`(상태에 따라\n * 보이고 안 보이는 것)와는 다른 것이다. 그것은 속성 패널의 몫이다.\n *\n * 이 컴포넌트는 정본을 만지지 않는다. 무엇을 하겠다는 것만 알린다.\n */\n\n/** 한 줄 — 평가에서 이 패널이 읽는 것만. */\nexport interface FigurePartRow {\n id: string\n /** 시작 모양 이름(`startingShapeKindOfBody`): 상자 · 원기둥 … 아이콘을 고른다. */\n kind: string\n /** 작업대에서 잠깐 가린 것. 저장되지 않는다. */\n hidden?: boolean\n /** 자산이 지금 상태에서 보이지 않는다고 한 것. 저장되는 것이고, 여기서는 표시만 한다. */\n invisible?: boolean\n /** 되풀이한 부품이면 지금 몇 개로 그려지나. 되풀이는 한 부품이다 — 한 줄로 보인다. */\n copies?: number\n /**\n * 바로 붙어 있는 곳: `대상 부품 · 대상 면`. 목록은 평평한 채로 두고 보조 문구로만 적는다 — 순서도 들여쓰기도\n * 붙임 때문에 바뀌지 않는다(ADR-0097 §5.5, 설계자 2026-09-27).\n */\n fastenedTo?: string\n}\n\n/** 시작 모양마다의 아이콘. Material Symbols 이름이다. */\nconst KIND_ICON: Record<string, string> = {\n cube: 'deployed_code',\n cylinder: 'database',\n frustum: 'change_history',\n sphere: 'circle',\n 'rounded-box': 'crop_square',\n 'hollow-box': 'check_box_outline_blank',\n polygon: 'pentagon',\n pyramid: 'details',\n portal: 'door_front'\n}\n\n/** 팔레트 — 저작 API 가 만들 수 있는 것만 보인다. */\n/*\n The palette: starting shapes (ADR-0100 §2.1). A plate and a wall are boxes of a shape a person reaches for, so they are\n starting sizes, not kinds of their own. A rounded box and a box open at the top are not here: they are a box with its\n corners rounded or an inside made, from the part's own 단면 section (§3.3), so the palette does not offer a second way.\n*/\n/* A mesh part is made from a file (`import-mesh`), not from a starting size. */\nexport type FigurePaletteKind = Exclude<FigurePrimitiveCreation['kind'], 'mesh'> | 'plate' | 'wall'\nconst RECIPES: Array<{ kind: FigurePaletteKind; icon: string; label: string }> = [\n { kind: 'box', icon: 'deployed_code', label: 'figure.label.primitive-cube' },\n { kind: 'cylinder', icon: 'database', label: 'figure.label.primitive-cylinder' },\n { kind: 'sphere', icon: 'circle', label: 'figure.label.primitive-sphere' },\n { kind: 'frustum', icon: 'change_history', label: 'figure.label.primitive-frustum' },\n { kind: 'polygon', icon: 'hexagon', label: 'figure.label.primitive-polygon' },\n { kind: 'pyramid', icon: 'details', label: 'figure.label.primitive-pyramid' },\n { kind: 'plate', icon: 'check_box_outline_blank', label: 'figure.label.primitive-plate' },\n { kind: 'wall', icon: 'crop_portrait', label: 'figure.label.primitive-wall' },\n { kind: 'portal', icon: 'door_front', label: 'figure.label.primitive-portal' }\n]\n\n@customElement('figure-parts')\nexport class FigureParts extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n background-color: var(--md-sys-color-surface-container-lowest);\n /* The divider beside it is the editor's frame's (ox-three-pane). */\n color: var(--md-sys-color-on-surface);\n font: var(--label-font, inherit);\n font-size: var(--ui-t-small, 11.5px);\n /* Folds by its own width: the editor gives this column 140 px when it has two columns (UX, 2026-09-24). */\n container-type: inline-size;\n }\n section {\n padding: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n section[list] {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n }\n h3 {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 6px;\n margin: 0 0 6px 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n /* The cost line: the grade's letter in its colour, then what the figure costs. */\n button[model-root] {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-height: 32px;\n padding: 4px 8px;\n border: 1px solid transparent;\n border-radius: 6px;\n background: none;\n font: inherit;\n font-weight: 600;\n text-align: start;\n color: var(--md-sys-color-on-surface);\n cursor: pointer;\n }\n button[model-root] span {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n /* Chosen: a frame and a tint, not colour alone. */\n button[model-root][on] {\n border-color: var(--md-sys-color-primary);\n background: var(--md-sys-color-primary-container);\n }\n button[model-root]:focus-visible {\n outline: 2px solid var(--md-sys-color-primary);\n outline-offset: 1px;\n }\n /* The cost line as a line, not a card; lit under the hand like the rest of the list. */\n button[budget] {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n width: 100%;\n margin: 0 0 6px;\n padding: 4px 6px;\n font: inherit;\n font-size: var(--ui-t-micro, 11px);\n line-height: 1.5;\n text-align: left;\n color: var(--md-sys-color-on-surface-variant);\n background: none;\n border: 1px solid transparent;\n border-radius: 4px;\n cursor: pointer;\n }\n button[budget]:hover {\n background: var(--md-sys-color-surface-container);\n }\n button[budget] b {\n flex: none;\n min-width: 16px;\n text-align: center;\n border-radius: 4px;\n color: var(--md-sys-color-on-primary-container);\n background: var(--md-sys-color-primary-container);\n }\n button[budget][grade='C'] b {\n color: var(--md-sys-color-on-tertiary-container);\n background: var(--md-sys-color-tertiary-container);\n }\n button[budget][grade='D'] {\n border-color: var(--md-sys-color-error);\n }\n button[budget][grade='D'] b {\n color: var(--md-sys-color-on-error);\n background: var(--md-sys-color-error);\n }\n button[budget] em {\n display: block;\n font-style: normal;\n color: var(--md-sys-color-error);\n }\n span[room][full] {\n color: var(--md-sys-color-error);\n font-weight: 600;\n }\n p[full] {\n margin: 4px 0 0;\n font-size: var(--ui-t-micro, 11px);\n color: var(--md-sys-color-error);\n }\n div[level] {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr);\n align-items: center;\n gap: 6px;\n margin: 0 0 6px;\n font-size: var(--ui-t-micro, 11px);\n color: var(--md-sys-color-on-surface-variant);\n }\n /* A field in the side panel's look (side-panel-styles): 26px, a quiet ground, its line only under the hand. */\n div[level] select {\n min-width: 0;\n min-height: 26px;\n padding: 2px 4px;\n font: inherit;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--md-sys-color-on-surface);\n background: var(--md-sys-color-surface-container-low);\n border: 1px solid transparent;\n border-radius: 4px;\n }\n div[level] select:hover:not(:disabled) {\n border-color: var(--md-sys-color-outline-variant);\n }\n small[copies] {\n color: var(--md-sys-color-on-surface-variant);\n }\n span[room] {\n font-size: var(--ui-t-micro, 11px);\n font-weight: 400;\n letter-spacing: 0;\n text-transform: none;\n }\n /* Three to a row, small (user, 2026-09-24): the palette is reached for, not read -- the list below is what grows. */\n div[palette] {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 3px;\n }\n /* A tile with no outline: its icon and name, lit under the hand -- ten outlined tiles were the boxiest part of the screen (user 2026-10-17). */\n button[shape] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1px;\n min-width: 0;\n padding: 5px 1px 4px;\n font: var(--label-font, inherit);\n font-size: var(--ui-t-micro, 11px);\n line-height: 1.2;\n text-align: center;\n overflow-wrap: anywhere;\n /* A tile's name on one line, so the nine stand one height; a long name ends in an ellipsis, its title says it all. */\n white-space: nowrap;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n background: none;\n border: 1px solid transparent;\n border-radius: 4px;\n cursor: pointer;\n }\n /*\n A file brought in is not a starting shape: its own row under the nine, its words on one line. As a tenth tile its\n two-word name broke onto two lines and stood it taller than the rest (2026-10-16).\n */\n button[shape] > span {\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n /*\n The one file picker (ox-input-file, quiet) on that row: a GLB refused or going up is said on the spot. Its button\n wears the tiles' words and lit hand -- the picker's own 13/600 stood louder than the shapes' heading.\n */\n ox-input-file[mesh-file] {\n grid-column: 1 / -1;\n justify-content: center;\n font-size: var(--ui-t-micro, 11px);\n --ox-input-file-action-height: 26px;\n }\n ox-input-file[mesh-file]::part(attach) {\n gap: 6px;\n padding: 0 8px;\n font: var(--label-font, inherit);\n font-size: var(--ui-t-micro, 11px);\n font-weight: 400;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n border-radius: 4px;\n }\n ox-input-file[mesh-file]:not([disabled])::part(attach):hover {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n }\n ox-input-file[mesh-file][disabled]::part(attach) {\n opacity: 0.35;\n }\n ox-input-file[mesh-file] md-icon {\n --md-icon-size: 18px;\n }\n section[shapes].candrop {\n outline: 1px dashed var(--md-sys-color-primary);\n outline-offset: -1px;\n }\n /* An action in the side panel's look: icon and words in the primary colour, no pill. */\n button[recipe-catalog] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 6px;\n margin-left: -6px;\n font: inherit;\n font-size: var(--ui-t-small, 11.5px);\n color: var(--md-sys-color-primary);\n background: none;\n border: 1px solid transparent;\n border-radius: 4px;\n cursor: pointer;\n }\n button[recipe-catalog]:hover:not(:disabled) {\n background: var(--md-sys-color-surface-container);\n }\n button[shape]:hover:not([disabled]) {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-color: transparent;\n }\n button[shape][disabled] {\n opacity: 0.35;\n cursor: default;\n }\n button[shape] md-icon {\n --md-icon-size: 18px;\n }\n ol {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n li {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 6px;\n border-radius: 6px;\n cursor: pointer;\n }\n li:hover {\n background-color: var(--md-sys-color-surface-container);\n }\n li[selected] {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n }\n /*\n Icons by role, three sizes on the whole screen (2026-10-16; there were six): 20 for the bar, the tabs and the\n model's head, 18 for a palette tile, 16 beside words and on a row.\n */\n button[model-root] md-icon {\n --md-icon-size: 20px;\n }\n /* Beside its words, as every icon on a button with words is; without a size it stood at md-icon's own 24. */\n button[recipe-catalog] md-icon {\n --md-icon-size: 16px;\n }\n li md-icon {\n --md-icon-size: 16px;\n flex: none;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n button[eye][all] {\n margin-left: auto;\n opacity: 0.75;\n }\n button[eye][all]:hover {\n opacity: 1;\n }\n button[eye] {\n display: flex;\n flex: none;\n padding: 1px;\n color: inherit;\n background: none;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n opacity: 0;\n }\n li:hover button[eye],\n li[selected] button[eye],\n button[eye][off] {\n opacity: 1;\n }\n button[eye][off] {\n color: var(--md-sys-color-tertiary);\n }\n button[eye] md-icon {\n --md-icon-size: 16px;\n color: inherit;\n }\n li[off] span[label],\n li[off] > md-icon,\n li[invisible] span[label],\n li[invisible] > md-icon {\n opacity: 0.45;\n }\n li[selected] md-icon {\n color: inherit;\n }\n span[label] {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--ui-t-body, 13px);\n }\n span[label] small {\n margin-left: 4px;\n font-size: var(--ui-t-micro, 11px);\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n div[ops] {\n display: none;\n gap: 1px;\n }\n li[selected] div[ops] {\n display: flex;\n }\n div[ops] button {\n display: flex;\n padding: 2px;\n color: inherit;\n background: none;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n }\n div[ops] button:hover:not([disabled]) {\n background-color: var(--md-sys-color-surface-container-lowest);\n }\n div[ops] button[disabled] {\n opacity: 0.3;\n cursor: default;\n }\n div[ops] md-icon {\n --md-icon-size: 16px;\n color: inherit;\n }\n /*\n Under 200 px the selected row's four buttons pushed its name out and the last one past the edge (seen at 140,\n 2026-09-24). They go to a line of their own under the name.\n */\n @container (max-width: 199px) {\n li[selected] {\n flex-wrap: wrap;\n }\n li[selected] div[ops] {\n flex-basis: 100%;\n justify-content: flex-end;\n }\n }\n p[quiet] {\n margin: 0;\n font-size: var(--ui-t-small, 11.5px);\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n `\n ]\n\n @property({ type: Array }) parts: FigurePartRow[] = []\n /** 고른 부품의 id. 자리(index)가 아니다 — 부품은 id 로 안정하게 가리킨다. */\n @property({ type: String }) selected = ''\n /** The model's own name, the list's root: choosing it shows the model's settings (B.1). */\n @property({ type: String }) modelName = ''\n /** 편집할 수 없을 때(불러오는 중 · 저장 중) 팔레트와 조작을 잠근다. */\n @property({ type: Boolean }) locked = false\n /**\n * 이 피규어가 치르는 값 — 삼각형 · 묶음 · 한 화면에 몇 대 · 등급. 부품을 더하는 바로 그 자리에서 보여야 로우폴리의\n * 기준이 저작을 이끈다. 등급이 D 면 무엇이 넘쳤는지를 적는다. 누르면 성숙도 탭이 열린다.\n */\n @property({ attribute: false }) budget?: FigureBudgetLine\n /**\n * 디테일 등급(S/M/L)의 부품 한도(사용자 2026-09-24). 부품을 넣기 **전에** 몇 개 남았는지 보이고, 다 차면 팔레트가\n * 잠긴다. 되풀이는 한 부품으로 센다. 등급을 안 정했으면 한도는 없다.\n */\n @property({ attribute: false }) partBudget?: { level: DetailLevel | null; used: number; limit: number | null }\n /** How many recipe templates the catalog holds; none, and the section is not drawn. */\n @property({ type: Number }) recipeCount = 0\n /** How far the GLB being brought in has gone up (0‒1), while it does; the picker shows it. */\n @property({ type: Number }) meshProgress?: number\n\n /* A GLB dragged over the shapes is a part brought in: the section is where it is dropped (page standard §7-1). */\n @query('section[shapes]') private shapes?: HTMLElement\n\n firstUpdated() {\n /* The drop area is drawn by the first render; the picker is told it by the next. */\n this.requestUpdate()\n }\n\n render() {\n const b = this.partBudget\n const full = !!b && b.limit !== null && b.used >= b.limit\n return html`\n <section shapes>\n <h3>${i18next.t('figure.label.shapes')}</h3>\n <div palette>\n ${RECIPES.map(\n recipe => html`\n <button\n shape\n ?disabled=${this.locked || full}\n title=${full ? i18next.t('figure.text.part-limit-reached') : i18next.t(recipe.label)}\n @click=${() => this.ask('add-part', { kind: recipe.kind })}\n >\n <md-icon>${recipe.icon}</md-icon>\n <span>${i18next.t(recipe.label)}</span>\n </button>\n `\n )}\n <ox-input-file\n quiet\n hide-filelist\n mesh-file\n accept=\".glb,model/gltf-binary\"\n .label=${i18next.t('figure.button.import-mesh')}\n title=${full ? i18next.t('figure.text.part-limit-reached') : i18next.t('figure.text.import-mesh-hint')}\n ?disabled=${this.locked || full}\n .dropTarget=${this.shapes}\n .progress=${this.meshProgress}\n @change=${(e: CustomEvent) => {\n const file = (e.detail as File[] | undefined)?.[0]\n if (file) this.ask('import-mesh', { file })\n ;(e.currentTarget as HTMLElement & { reset(): void }).reset()\n }}\n ><md-icon slot=\"icon\">view_in_ar</md-icon></ox-input-file>\n </div>\n ${full ? html`<p full>${i18next.t('figure.text.part-limit-reached-short', { level: b!.level, limit: b!.limit })}</p>` : nothing}\n </section>\n ${this.renderRecipes(full)}\n\n <section list>\n <!--\n The list's root: the model by its name. Choosing it shows the model's settings -- not \"select all\", not \"fit the\n view\" -- the same move as the model name in the properties panel's path (designer 2026-09-27, B.1).\n -->\n <button\n model-root\n aria-pressed=${String(!this.selected)}\n ?on=${!this.selected}\n title=${i18next.t('figure.button.show-model-settings')}\n aria-label=${`${i18next.t('figure.button.show-model-settings')}: ${this.modelName || i18next.t('figure.text.new-figure-name')}`}\n @click=${() => this.dispatchEvent(new CustomEvent('show-model-settings', { bubbles: true, composed: true }))}\n >\n <md-icon>category</md-icon><span>${this.modelName || i18next.t('figure.text.new-figure-name')}</span>\n </button>\n <h3>\n <span>${i18next.t('figure.label.parts')}</span>\n <span room ?full=${full} title=${i18next.t('figure.text.limit-comes-from-level')}\n >${b && b.limit !== null ? i18next.t('figure.text.n-of-limit', { used: b.used, limit: b.limit }) : (b?.used ?? this.parts.length)}</span\n >\n ${this.renderShowAll()}\n </h3>\n ${this.renderLevel()}\n ${this.renderBudget()}\n ${this.parts.length === 0\n ? html`<p quiet>${i18next.t('figure.text.no-parts-yet')}</p>`\n : html`<ol>\n ${this.parts.map((part, index) => this.renderRow(part, index))}\n </ol>`}\n </section>\n `\n }\n\n /** 디테일 등급 — 고르면 한도가 바뀐다. 목록 머리 아래. */\n private renderLevel() {\n const b = this.partBudget\n /* Not before the first part: a level with nothing to limit was the first choice a new figure met (U09). Once set, it shows. */\n if (!b || (!this.parts.length && !b.level)) return nothing\n return html`<div level>\n <label for=\"detail-level\">${i18next.t('figure.label.detail-level')}</label>\n <select\n id=\"detail-level\"\n title=${i18next.t('figure.text.detail-level-explained')}\n .value=${b.level ?? ''}\n ?disabled=${this.locked}\n @change=${(e: Event) => {\n const value = (e.target as HTMLSelectElement).value\n this.dispatchEvent(new CustomEvent('set-detail-level', { detail: { level: value || null }, bubbles: true, composed: true }))\n }}\n >\n <option value=\"\" ?selected=${!b.level}>${i18next.t('figure.label.detail-none')}</option>\n ${DETAIL_LEVELS.map(\n one => html`<option value=${one} ?selected=${one === b.level}>\n ${one} ${i18next.t('figure.label.detail-' + one)} · ${i18next.t('figure.text.n-parts-at-most', { limit: PART_LIMIT[one] })}\n </option>`\n )}\n </select>\n </div>`\n }\n\n private renderBudget() {\n const b = this.budget\n if (!b || !this.parts.length) return nothing\n const over = b.grade === 'D'\n return html`<button\n budget\n grade=${b.grade}\n title=${i18next.t('figure.text.parts-budget-open')}\n @click=${() => this.dispatchEvent(new CustomEvent('show-maturity', { bubbles: true, composed: true }))}\n >\n <b>${b.grade}</b>\n <span>\n <strong performance-cost>${i18next.t('figure.label.performance-cost')}</strong>\n ${i18next.t('figure.text.parts-budget', {\n triangles: b.triangles.toLocaleString(),\n groups: b.groups.toLocaleString(),\n instances: b.instances.toLocaleString()\n })}\n ${over\n ? html`<em\n >${i18next.t('figure.text.parts-budget-over', {\n budget: i18next.t('figure.label.budget-' + b.tightest.key),\n used: b.tightest.used.toLocaleString(),\n limit: b.tightest.limit.toLocaleString()\n })}</em\n >`\n : nothing}\n </span>\n </button>`\n }\n\n /** 한꺼번에 감추고 한꺼번에 되돌린다 — 하나라도 감춰져 있으면 다 되돌리고, 다 보이면 다 감춘다. */\n private renderShowAll() {\n if (this.parts.length === 0) return nothing\n const anyHidden = this.parts.some(part => part.hidden)\n return html`\n <button\n eye\n all\n ?off=${!anyHidden}\n title=${i18next.t(anyHidden ? 'figure.text.show-all-parts' : 'figure.text.hide-all-parts')}\n @click=${(e: Event) => {\n e.stopPropagation()\n this.ask('set-all-parts-hidden', { hidden: !anyHidden })\n }}\n >\n <md-icon>${anyHidden ? 'visibility' : 'visibility_off'}</md-icon>\n </button>\n `\n }\n\n private renderRow(part: FigurePartRow, index: number) {\n const selected = part.id === this.selected\n const off = !!part.hidden\n return html`\n <li\n ?selected=${selected}\n ?off=${off}\n ?invisible=${!!part.invisible}\n @click=${() => this.ask('select-part', { id: part.id })}\n >\n <button\n eye\n ?off=${off}\n title=${i18next.t(off ? 'figure.text.show-this-part' : 'figure.text.hide-this-part')}\n @click=${(e: Event) => {\n e.stopPropagation()\n this.ask('toggle-part-hidden', { id: part.id })\n }}\n >\n <md-icon>${off ? 'visibility_off' : 'visibility'}</md-icon>\n </button>\n <md-icon>${KIND_ICON[part.kind] ?? 'deployed_code'}</md-icon>\n <span label title=${part.id}\n >${partLabelOf(part.id)}${part.copies ? html` <small copies>× ${part.copies}</small>` : nothing}${part.invisible ? html`<small>${i18next.t('figure.label.state-hidden')}</small>` : nothing}${part.fastenedTo\n ? html`<small fastened-to title=${i18next.t('figure.label.fastened-to')}>${part.fastenedTo}</small>`\n : nothing}</span\n >\n ${selected ? this.renderOps(part.id, index) : nothing}\n </li>\n `\n }\n\n /** 고른 줄의 조작. 못 하는 것은 빼지 않고 흐리게 둔다 — 자리가 밀리면 연달아 지우다 엉뚱한 것을 누른다. */\n private renderOps(id: string, index: number) {\n const count = this.parts.length\n const op = (name: string, icon: string, detail: object, enabled = true) => html`\n <button\n op=${name}\n ?disabled=${!enabled || this.locked}\n title=${i18next.t('figure.button.' + name)}\n @click=${(e: Event) => {\n e.stopPropagation()\n if (enabled && !this.locked) this.ask(name, detail)\n }}\n >\n <md-icon>${icon}</md-icon>\n </button>\n `\n return html`\n <div ops>\n ${op('move-part-up', 'arrow_upward', { id, to: index - 1 }, index > 0)}\n ${op('move-part-down', 'arrow_downward', { id, to: index + 1 }, index < count - 1)}\n ${op('duplicate-part', 'content_copy', { id })} ${op('remove-part', 'delete', { id })}\n </div>\n `\n }\n\n /**\n * Recipes (ADR-0095): the catalog of templates -- a door, a roller row -- opened over the modeller, put onto the chosen\n * part in one step.\n */\n private renderRecipes(full: boolean) {\n if (!this.recipeCount) return nothing\n return html`<section recipes>\n <h3>${i18next.t('figure.label.recipes')}</h3>\n <button recipe-catalog ?disabled=${this.locked || full} @click=${() => this.ask('open-recipe-catalog', {})}>\n <md-icon>widgets</md-icon>${i18next.t('figure.button.open-recipe-catalog', { count: this.recipeCount })}\n </button>\n </section>`\n }\n\n /** 정본을 고치지 않는다 — 무엇을 하겠다는 것만 알린다. */\n private ask(what: string, detail: object) {\n this.dispatchEvent(new CustomEvent(what, { detail, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
@@ -162,7 +162,7 @@ let FigureSettings = class FigureSettings extends localize(i18next)(LitElement)
|
|
|
162
162
|
있나」이기 때문이다. 미리보기가 도면에 놓인 모습을 말하는 자리이므로, 어떤 도면을
|
|
163
163
|
가정하는지가 먼저 정해져야 그 다음이 뜻을 갖는다.
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
피규어 탭의 「배치 기준」과 짝이지 같은 것이 아니다. 저쪽은 이 피규어가 어느 면에
|
|
166
166
|
붙는가(저장된다), 이쪽은 그 면을 가진 도면이 어느 쪽을 기준으로 재는가(저장 안 된다).
|
|
167
167
|
-->
|
|
168
168
|
<section>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-settings.js","sourceRoot":"","sources":["../../client/modeller/figure-settings.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { DEFAULT_VIEW, ENVIRONMENTS, SCENE_REFERENCES } from '@things-factory/figure-viewer/dist-client/figure-view.js'\nimport type { EnvironmentName, ViewSettings } from '@things-factory/figure-viewer/dist-client/figure-view.js'\n\n/**\n * 저작 화면의 **보기 설정**.\n *\n * ## 자산이 아니라 작업대다\n *\n * 여기서 고치는 것은 저장되지 않는다. 조명을 밝게 하고 바닥을 켠 것은 지금 보기 편한\n * 상태일 뿐이다. 그래서 「저장 안 됨」을 화면에 적어 둔다 — 안 적으면 저작자가 조명을\n * 맞춰 두고 그것이 자산에 딸려 간다고 여긴다.\n *\n * ## 값을 들고 있지 않는다\n *\n * 이 패널은 받은 것을 그리고 바뀐 것을 알린다. 정본은 모델러 페이지가 갖는다 — 속성\n * 패널과 같은 방식이다. 여기서 들고 있으면 페이지가 다시 그릴 때 두 벌이 갈린다.\n */\n@customElement('figure-settings')\nexport class FigureSettings extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow-y: auto;\n background-color: var(--md-sys-color-surface-container-lowest);\n color: var(--md-sys-color-on-surface);\n font: var(--label-font, inherit);\n font-size: var(--ui-t-small, 11.5px);\n }\n\n section {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n padding: var(--spacing-large, 12px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n\n /* 속성 패널의 묶음 제목과 같은 규격이다 — 두 탭이 다른 눈금을 쓰면 따로 논다 */\n h3 {\n margin: 0 0 2px 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* 저장되지 않는다는 것을 한 번 말해 둔다 */\n p[quiet] {\n margin: 0;\n font-size: var(--ui-t-micro, 11px);\n line-height: 1.5;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n label[row] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--spacing-medium, 8px);\n cursor: pointer;\n }\n label[row] span {\n display: flex;\n flex-direction: column;\n }\n label[row] em {\n font-style: normal;\n font-size: var(--ui-t-micro, 11px);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n input[type='checkbox'] {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--md-sys-color-primary);\n cursor: pointer;\n }\n\n label[field] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n label[field] > span {\n color: var(--md-sys-color-on-surface-variant);\n }\n\n select,\n input[type='number'],\n input[type='color'] {\n width: 100%;\n padding: 5px 6px;\n font: var(--input-field-font, inherit);\n font-size: var(--ui-t-small, 11.5px);\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 4px;\n }\n input[type='color'] {\n height: 30px;\n padding: 2px;\n cursor: pointer;\n }\n\n /* 값이 옆에 붙어야 끌면서 얼마인지 안다 */\n div[slider] {\n display: flex;\n align-items: center;\n gap: var(--spacing-medium, 8px);\n }\n input[type='range'] {\n flex: 1;\n accent-color: var(--md-sys-color-primary);\n cursor: pointer;\n }\n div[slider] output {\n flex: none;\n width: 2.4em;\n text-align: right;\n font-family: var(--ui-mono, ui-monospace, monospace);\n font-size: var(--ui-t-micro, 11px);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n button[reset] {\n align-self: flex-start;\n padding: 5px 12px;\n font: var(--label-font, inherit);\n font-size: var(--ui-t-small, 11.5px);\n color: var(--md-sys-color-on-surface-variant);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 4px;\n cursor: pointer;\n }\n button[reset]:hover {\n background-color: var(--md-sys-color-surface-container);\n }\n `\n ]\n\n @property({ type: Object }) view: ViewSettings = DEFAULT_VIEW\n\n render() {\n const view = this.view ?? DEFAULT_VIEW\n\n return html`\n <!--\n 놓이는 도면.\n\n 이 묶음이 맨 위인 것은, 나머지가 「어떻게 보이나」인데 이것은 「무엇으로 보고\n 있나」이기 때문이다. 미리보기가 도면에 놓인 모습을 말하는 자리이므로, 어떤 도면을\n 가정하는지가 먼저 정해져야 그 다음이 뜻을 갖는다.\n\n 도형 탭의 「배치 기준」과 짝이지 같은 것이 아니다. 저쪽은 이 도형이 어느 면에\n 붙는가(저장된다), 이쪽은 그 면을 가진 도면이 어느 쪽을 기준으로 재는가(저장 안 된다).\n -->\n <section>\n <h3>${i18next.t('figure.label.assumed-drawing')}</h3>\n <p quiet>${i18next.t('figure.text.view-settings-are-not-saved')}</p>\n\n <label field>\n <span>${i18next.t('figure.label.scene-reference')}</span>\n <select\n .value=${view.placement}\n @change=${(e: Event) =>\n this.put({ placement: (e.target as HTMLSelectElement).value as ViewSettings['placement'] })}\n >\n ${SCENE_REFERENCES.map(\n name => html`<option value=${name} ?selected=${view.placement === name}>\n ${i18next.t(`figure.label.scene-reference-${name}`)}\n </option>`\n )}\n </select>\n </label>\n <p quiet>${i18next.t('figure.text.scene-reference-explained')}</p>\n\n <label field>\n <span>${i18next.t('figure.label.ceiling-height')}</span>\n <input\n type=\"number\"\n min=\"0\"\n step=\"100\"\n .value=${String(view.ceilingHeight)}\n @change=${(e: Event) => this.put({ ceilingHeight: Number((e.target as HTMLInputElement).value) || 0 })}\n />\n </label>\n <p quiet>${i18next.t('figure.text.ceiling-height-explained')}</p>\n </section>\n\n <section>\n <h3>${i18next.t('figure.label.guides')}</h3>\n\n ${this.toggle('grid', view.grid, i18next.t('figure.label.coordinate-ground'), i18next.t('figure.text.coordinate-ground-explained'))}\n ${this.toggle('gridLabels', view.gridLabels, i18next.t('figure.label.axis-labels'))}\n ${this.toggle('floor', view.floor, i18next.t('figure.label.scene-floor'), i18next.t('figure.text.floor-explained'))}\n </section>\n\n <section>\n <h3>${i18next.t('figure.label.environment')}</h3>\n\n <label field>\n <span>${i18next.t('figure.label.preset')}</span>\n <select\n .value=${view.environment}\n @change=${(e: Event) => this.put({ environment: (e.target as HTMLSelectElement).value as EnvironmentName })}\n >\n ${ENVIRONMENTS.map(\n name => html`<option value=${name} ?selected=${view.environment === name}>\n ${i18next.t(`figure.label.environment-${name}`)}\n </option>`\n )}\n </select>\n </label>\n <p quiet>${i18next.t('figure.text.environment-explained')}</p>\n\n <label field>\n <span>${i18next.t('figure.label.sky-color')}</span>\n <input\n type=\"color\"\n .value=${view.skyColor}\n @change=${(e: Event) => this.put({ skyColor: (e.target as HTMLInputElement).value })}\n />\n </label>\n </section>\n\n <section>\n <h3>${i18next.t('figure.label.key-light')}</h3>\n\n ${this.slider('dirLightIntensity', view.dirLightIntensity, i18next.t('figure.label.intensity'), 0, 5, 0.1)}\n ${this.toggle(\n 'dirLightFollowCamera',\n view.dirLightFollowCamera,\n i18next.t('figure.label.follow-camera'),\n i18next.t('figure.text.follow-camera-explained')\n )}\n ${this.toggle('dirShadowEnabled', view.dirShadowEnabled, i18next.t('figure.label.cast-shadow'))}\n ${view.dirLightIntensity === 0 && view.hemiIntensity === 0\n ? html`<p quiet>${i18next.t('figure.text.all-lights-off')}</p>`\n : ''}\n </section>\n\n <section>\n <h3>${i18next.t('figure.label.hemisphere-light')}</h3>\n\n ${this.slider('hemiIntensity', view.hemiIntensity, i18next.t('figure.label.intensity'), 0, 8, 0.1)}\n <p quiet>${i18next.t('figure.text.hemisphere-light-explained')}</p>\n </section>\n\n <section>\n <button reset @click=${() => this.reset()}>${i18next.t('figure.button.reset-view')}</button>\n </section>\n `\n }\n\n private toggle(key: keyof ViewSettings, on: boolean, label: string, hint?: string) {\n return html`\n <label row>\n <span>\n ${label}${hint ? html`<em>${hint}</em>` : ''}\n </span>\n <input\n type=\"checkbox\"\n .checked=${on}\n @change=${(e: Event) => this.put({ [key]: (e.target as HTMLInputElement).checked } as Partial<ViewSettings>)}\n />\n </label>\n `\n }\n\n private slider(key: keyof ViewSettings, value: number, label: string, min: number, max: number, step: number) {\n return html`\n <label field>\n <span>${label}</span>\n <div slider>\n <input\n type=\"range\"\n min=${min}\n max=${max}\n step=${step}\n .value=${String(value)}\n @input=${(e: Event) =>\n this.put({ [key]: Number((e.target as HTMLInputElement).value) } as Partial<ViewSettings>)}\n />\n <output>${value.toFixed(1)}</output>\n </div>\n </label>\n `\n }\n\n /** 처음 값으로 되돌린다. 만지다 길을 잃었을 때 돌아올 자리가 있어야 한다. */\n private reset() {\n this.tell({ ...DEFAULT_VIEW })\n }\n\n private put(patch: Partial<ViewSettings>) {\n this.tell({ ...(this.view ?? DEFAULT_VIEW), ...patch })\n }\n\n /**\n * 바뀐 것을 알린다.\n *\n * **알리기 전에 내 것도 바꿔 둔다.** Lit 은 속성을 다음 렌더에 넣으므로, 같은 프레임에\n * 두 번 고치면 두 번째가 `this.view` 의 옛 값을 읽어 첫 번째를 덮는다. 실제로 그랬다 —\n * 축 가이드를 끄고 바닥판을 켰더니 축 가이드가 도로 켜져 있었고, 화면의 체크 상자와\n * 씬의 상태가 서로 다른 말을 했다.\n *\n * 정본은 여전히 모델러 페이지가 갖는다. 여기 값은 다음 렌더에 같은 것으로 덮인다.\n */\n private tell(view: ViewSettings) {\n this.view = view\n this.dispatchEvent(new CustomEvent('update-view', { detail: { view }, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-settings.js","sourceRoot":"","sources":["../../client/modeller/figure-settings.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { DEFAULT_VIEW, ENVIRONMENTS, SCENE_REFERENCES } from '@things-factory/figure-viewer/dist-client/figure-view.js'\nimport type { EnvironmentName, ViewSettings } from '@things-factory/figure-viewer/dist-client/figure-view.js'\n\n/**\n * 저작 화면의 **보기 설정**.\n *\n * ## 자산이 아니라 작업대다\n *\n * 여기서 고치는 것은 저장되지 않는다. 조명을 밝게 하고 바닥을 켠 것은 지금 보기 편한\n * 상태일 뿐이다. 그래서 「저장 안 됨」을 화면에 적어 둔다 — 안 적으면 저작자가 조명을\n * 맞춰 두고 그것이 자산에 딸려 간다고 여긴다.\n *\n * ## 값을 들고 있지 않는다\n *\n * 이 패널은 받은 것을 그리고 바뀐 것을 알린다. 정본은 모델러 페이지가 갖는다 — 속성\n * 패널과 같은 방식이다. 여기서 들고 있으면 페이지가 다시 그릴 때 두 벌이 갈린다.\n */\n@customElement('figure-settings')\nexport class FigureSettings extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow-y: auto;\n background-color: var(--md-sys-color-surface-container-lowest);\n color: var(--md-sys-color-on-surface);\n font: var(--label-font, inherit);\n font-size: var(--ui-t-small, 11.5px);\n }\n\n section {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n padding: var(--spacing-large, 12px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n\n /* 속성 패널의 묶음 제목과 같은 규격이다 — 두 탭이 다른 눈금을 쓰면 따로 논다 */\n h3 {\n margin: 0 0 2px 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* 저장되지 않는다는 것을 한 번 말해 둔다 */\n p[quiet] {\n margin: 0;\n font-size: var(--ui-t-micro, 11px);\n line-height: 1.5;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n label[row] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--spacing-medium, 8px);\n cursor: pointer;\n }\n label[row] span {\n display: flex;\n flex-direction: column;\n }\n label[row] em {\n font-style: normal;\n font-size: var(--ui-t-micro, 11px);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n input[type='checkbox'] {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--md-sys-color-primary);\n cursor: pointer;\n }\n\n label[field] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n label[field] > span {\n color: var(--md-sys-color-on-surface-variant);\n }\n\n select,\n input[type='number'],\n input[type='color'] {\n width: 100%;\n padding: 5px 6px;\n font: var(--input-field-font, inherit);\n font-size: var(--ui-t-small, 11.5px);\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 4px;\n }\n input[type='color'] {\n height: 30px;\n padding: 2px;\n cursor: pointer;\n }\n\n /* 값이 옆에 붙어야 끌면서 얼마인지 안다 */\n div[slider] {\n display: flex;\n align-items: center;\n gap: var(--spacing-medium, 8px);\n }\n input[type='range'] {\n flex: 1;\n accent-color: var(--md-sys-color-primary);\n cursor: pointer;\n }\n div[slider] output {\n flex: none;\n width: 2.4em;\n text-align: right;\n font-family: var(--ui-mono, ui-monospace, monospace);\n font-size: var(--ui-t-micro, 11px);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n button[reset] {\n align-self: flex-start;\n padding: 5px 12px;\n font: var(--label-font, inherit);\n font-size: var(--ui-t-small, 11.5px);\n color: var(--md-sys-color-on-surface-variant);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 4px;\n cursor: pointer;\n }\n button[reset]:hover {\n background-color: var(--md-sys-color-surface-container);\n }\n `\n ]\n\n @property({ type: Object }) view: ViewSettings = DEFAULT_VIEW\n\n render() {\n const view = this.view ?? DEFAULT_VIEW\n\n return html`\n <!--\n 놓이는 도면.\n\n 이 묶음이 맨 위인 것은, 나머지가 「어떻게 보이나」인데 이것은 「무엇으로 보고\n 있나」이기 때문이다. 미리보기가 도면에 놓인 모습을 말하는 자리이므로, 어떤 도면을\n 가정하는지가 먼저 정해져야 그 다음이 뜻을 갖는다.\n\n 피규어 탭의 「배치 기준」과 짝이지 같은 것이 아니다. 저쪽은 이 피규어가 어느 면에\n 붙는가(저장된다), 이쪽은 그 면을 가진 도면이 어느 쪽을 기준으로 재는가(저장 안 된다).\n -->\n <section>\n <h3>${i18next.t('figure.label.assumed-drawing')}</h3>\n <p quiet>${i18next.t('figure.text.view-settings-are-not-saved')}</p>\n\n <label field>\n <span>${i18next.t('figure.label.scene-reference')}</span>\n <select\n .value=${view.placement}\n @change=${(e: Event) =>\n this.put({ placement: (e.target as HTMLSelectElement).value as ViewSettings['placement'] })}\n >\n ${SCENE_REFERENCES.map(\n name => html`<option value=${name} ?selected=${view.placement === name}>\n ${i18next.t(`figure.label.scene-reference-${name}`)}\n </option>`\n )}\n </select>\n </label>\n <p quiet>${i18next.t('figure.text.scene-reference-explained')}</p>\n\n <label field>\n <span>${i18next.t('figure.label.ceiling-height')}</span>\n <input\n type=\"number\"\n min=\"0\"\n step=\"100\"\n .value=${String(view.ceilingHeight)}\n @change=${(e: Event) => this.put({ ceilingHeight: Number((e.target as HTMLInputElement).value) || 0 })}\n />\n </label>\n <p quiet>${i18next.t('figure.text.ceiling-height-explained')}</p>\n </section>\n\n <section>\n <h3>${i18next.t('figure.label.guides')}</h3>\n\n ${this.toggle('grid', view.grid, i18next.t('figure.label.coordinate-ground'), i18next.t('figure.text.coordinate-ground-explained'))}\n ${this.toggle('gridLabels', view.gridLabels, i18next.t('figure.label.axis-labels'))}\n ${this.toggle('floor', view.floor, i18next.t('figure.label.scene-floor'), i18next.t('figure.text.floor-explained'))}\n </section>\n\n <section>\n <h3>${i18next.t('figure.label.environment')}</h3>\n\n <label field>\n <span>${i18next.t('figure.label.preset')}</span>\n <select\n .value=${view.environment}\n @change=${(e: Event) => this.put({ environment: (e.target as HTMLSelectElement).value as EnvironmentName })}\n >\n ${ENVIRONMENTS.map(\n name => html`<option value=${name} ?selected=${view.environment === name}>\n ${i18next.t(`figure.label.environment-${name}`)}\n </option>`\n )}\n </select>\n </label>\n <p quiet>${i18next.t('figure.text.environment-explained')}</p>\n\n <label field>\n <span>${i18next.t('figure.label.sky-color')}</span>\n <input\n type=\"color\"\n .value=${view.skyColor}\n @change=${(e: Event) => this.put({ skyColor: (e.target as HTMLInputElement).value })}\n />\n </label>\n </section>\n\n <section>\n <h3>${i18next.t('figure.label.key-light')}</h3>\n\n ${this.slider('dirLightIntensity', view.dirLightIntensity, i18next.t('figure.label.intensity'), 0, 5, 0.1)}\n ${this.toggle(\n 'dirLightFollowCamera',\n view.dirLightFollowCamera,\n i18next.t('figure.label.follow-camera'),\n i18next.t('figure.text.follow-camera-explained')\n )}\n ${this.toggle('dirShadowEnabled', view.dirShadowEnabled, i18next.t('figure.label.cast-shadow'))}\n ${view.dirLightIntensity === 0 && view.hemiIntensity === 0\n ? html`<p quiet>${i18next.t('figure.text.all-lights-off')}</p>`\n : ''}\n </section>\n\n <section>\n <h3>${i18next.t('figure.label.hemisphere-light')}</h3>\n\n ${this.slider('hemiIntensity', view.hemiIntensity, i18next.t('figure.label.intensity'), 0, 8, 0.1)}\n <p quiet>${i18next.t('figure.text.hemisphere-light-explained')}</p>\n </section>\n\n <section>\n <button reset @click=${() => this.reset()}>${i18next.t('figure.button.reset-view')}</button>\n </section>\n `\n }\n\n private toggle(key: keyof ViewSettings, on: boolean, label: string, hint?: string) {\n return html`\n <label row>\n <span>\n ${label}${hint ? html`<em>${hint}</em>` : ''}\n </span>\n <input\n type=\"checkbox\"\n .checked=${on}\n @change=${(e: Event) => this.put({ [key]: (e.target as HTMLInputElement).checked } as Partial<ViewSettings>)}\n />\n </label>\n `\n }\n\n private slider(key: keyof ViewSettings, value: number, label: string, min: number, max: number, step: number) {\n return html`\n <label field>\n <span>${label}</span>\n <div slider>\n <input\n type=\"range\"\n min=${min}\n max=${max}\n step=${step}\n .value=${String(value)}\n @input=${(e: Event) =>\n this.put({ [key]: Number((e.target as HTMLInputElement).value) } as Partial<ViewSettings>)}\n />\n <output>${value.toFixed(1)}</output>\n </div>\n </label>\n `\n }\n\n /** 처음 값으로 되돌린다. 만지다 길을 잃었을 때 돌아올 자리가 있어야 한다. */\n private reset() {\n this.tell({ ...DEFAULT_VIEW })\n }\n\n private put(patch: Partial<ViewSettings>) {\n this.tell({ ...(this.view ?? DEFAULT_VIEW), ...patch })\n }\n\n /**\n * 바뀐 것을 알린다.\n *\n * **알리기 전에 내 것도 바꿔 둔다.** Lit 은 속성을 다음 렌더에 넣으므로, 같은 프레임에\n * 두 번 고치면 두 번째가 `this.view` 의 옛 값을 읽어 첫 번째를 덮는다. 실제로 그랬다 —\n * 축 가이드를 끄고 바닥판을 켰더니 축 가이드가 도로 켜져 있었고, 화면의 체크 상자와\n * 씬의 상태가 서로 다른 말을 했다.\n *\n * 정본은 여전히 모델러 페이지가 갖는다. 여기 값은 다음 렌더에 같은 것으로 덮인다.\n */\n private tell(view: ViewSettings) {\n this.view = view\n this.dispatchEvent(new CustomEvent('update-view', { detail: { view }, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
@@ -5,7 +5,8 @@ declare const FigureSizeEditor_base: (new (...args: any[]) => LitElement) & type
|
|
|
5
5
|
* A part's measures and what each follows, one row an axis (ADR-0159 3). Made to follow, a measure takes what the part
|
|
6
6
|
* hangs from, along the axis its own axis lies on as it stands -- the author turns it on, nothing more. Another source
|
|
7
7
|
* is there when asked for, or when there is no such axis (the part lies at an angle) or the measure already follows
|
|
8
|
-
* something else; each way of following says what it will do, in millimetres.
|
|
8
|
+
* something else; each way of following says what it will do, in millimetres. A measure of the part's own is a value in
|
|
9
|
+
* hand as on any field (user 2026-09-24): drawn while it is typed or its label is dragged, written once on the release.
|
|
9
10
|
*/
|
|
10
11
|
export declare class FigureSizeEditor extends FigureSizeEditor_base {
|
|
11
12
|
revision?: FigureRevision;
|
|
@@ -15,6 +16,7 @@ export declare class FigureSizeEditor extends FigureSizeEditor_base {
|
|
|
15
16
|
private choosing;
|
|
16
17
|
private equivalentModes;
|
|
17
18
|
static styles: import("lit").CSSResult[];
|
|
19
|
+
private tell;
|
|
18
20
|
private apply;
|
|
19
21
|
private configure;
|
|
20
22
|
private choose;
|
|
@@ -5,12 +5,14 @@ import { live } from 'lit/directives/live.js';
|
|
|
5
5
|
import { i18next, localize } from '@operato/i18n';
|
|
6
6
|
import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js';
|
|
7
7
|
import { AXES, followOf, followableAxes, measureNow } from './links.js';
|
|
8
|
+
import { scrubLabel } from './live.js';
|
|
8
9
|
import { measureFactor, sameSizeSource, sizeInputOf, sizeRelationOf, sizeRelationSteps, sourceMeasureOf, suggestedSizeSource } from './size-response.js';
|
|
9
10
|
/**
|
|
10
11
|
* A part's measures and what each follows, one row an axis (ADR-0159 3). Made to follow, a measure takes what the part
|
|
11
12
|
* hangs from, along the axis its own axis lies on as it stands -- the author turns it on, nothing more. Another source
|
|
12
13
|
* is there when asked for, or when there is no such axis (the part lies at an angle) or the measure already follows
|
|
13
|
-
* something else; each way of following says what it will do, in millimetres.
|
|
14
|
+
* something else; each way of following says what it will do, in millimetres. A measure of the part's own is a value in
|
|
15
|
+
* hand as on any field (user 2026-09-24): drawn while it is typed or its label is dragged, written once on the release.
|
|
14
16
|
*/
|
|
15
17
|
let FigureSizeEditor = class FigureSizeEditor extends localize(i18next)(LitElement) {
|
|
16
18
|
constructor() {
|
|
@@ -39,6 +41,9 @@ let FigureSizeEditor = class FigureSizeEditor extends localize(i18next)(LitEleme
|
|
|
39
41
|
.result { margin: 0 0 6px 30px; }
|
|
40
42
|
[role=alert] { color: var(--md-sys-color-error); }
|
|
41
43
|
`]; }
|
|
44
|
+
tell(name, detail) {
|
|
45
|
+
this.dispatchEvent(new CustomEvent(name, { detail, bubbles: true, composed: true }));
|
|
46
|
+
}
|
|
42
47
|
apply(steps) {
|
|
43
48
|
if (this.locked)
|
|
44
49
|
return;
|
|
@@ -115,6 +120,42 @@ let FigureSizeEditor = class FigureSizeEditor extends localize(i18next)(LitEleme
|
|
|
115
120
|
const choosing = relation.variable && (this.choosing.has(key) || !sameSizeSource(source, suggested));
|
|
116
121
|
const selectedSource = source ? (source.of === 'instance' ? '@figure' : source.part) : '@custom';
|
|
117
122
|
const sourceAxes = source?.of === 'part' ? followableAxes(asset, source.part) : AXES;
|
|
123
|
+
const factor = measureFactor(asset, this.partId, axis);
|
|
124
|
+
/* Its own measure, no rule over it: in hand while typed or scrubbed, as the input it is (a diameter, its radius). */
|
|
125
|
+
const own = !relation.variable && !!input && !this.locked;
|
|
126
|
+
const typingSize = (e) => {
|
|
127
|
+
const value = e.target.valueAsNumber;
|
|
128
|
+
if (own && Number.isFinite(value) && value > 0)
|
|
129
|
+
this.tell('size-typing', { input, value: value / factor });
|
|
130
|
+
};
|
|
131
|
+
const scrubSize = (down) => {
|
|
132
|
+
if (!own || mm === undefined)
|
|
133
|
+
return;
|
|
134
|
+
const field = down.currentTarget.closest('.fields')?.querySelector('input[type=number]');
|
|
135
|
+
if (!field)
|
|
136
|
+
return;
|
|
137
|
+
scrubLabel(down, { value: mm, unit: 'mm' }, {
|
|
138
|
+
move: value => {
|
|
139
|
+
field.value = String(value);
|
|
140
|
+
if (value > 0)
|
|
141
|
+
this.tell('size-typing', { input, value: value / factor });
|
|
142
|
+
},
|
|
143
|
+
release: value => {
|
|
144
|
+
if (!(value > 0)) {
|
|
145
|
+
field.value = String(mm);
|
|
146
|
+
this.tell('size-let-go');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
this.error = '';
|
|
150
|
+
this.tell('size-input', { input, value: value / factor, part: this.partId });
|
|
151
|
+
this.requestUpdate();
|
|
152
|
+
},
|
|
153
|
+
cancel: () => {
|
|
154
|
+
field.value = String(mm);
|
|
155
|
+
this.tell('size-let-go');
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
};
|
|
118
159
|
const changeSize = (e) => {
|
|
119
160
|
const value = e.target.valueAsNumber;
|
|
120
161
|
if (!(Number.isFinite(value) && value > 0)) {
|
|
@@ -126,7 +167,7 @@ let FigureSizeEditor = class FigureSizeEditor extends localize(i18next)(LitEleme
|
|
|
126
167
|
this.configure(axis, source, mode, value);
|
|
127
168
|
else if (!relation.variable && input) {
|
|
128
169
|
this.error = '';
|
|
129
|
-
this.
|
|
170
|
+
this.tell('size-input', { input, value: value / factor, part: this.partId });
|
|
130
171
|
this.requestUpdate();
|
|
131
172
|
}
|
|
132
173
|
};
|
|
@@ -147,9 +188,9 @@ let FigureSizeEditor = class FigureSizeEditor extends localize(i18next)(LitEleme
|
|
|
147
188
|
};
|
|
148
189
|
return html `<div class="dimension" data-axis=${axis}>
|
|
149
190
|
<div class="fields">
|
|
150
|
-
<span>${label}</span>
|
|
191
|
+
<span ?scrub=${own} @pointerdown=${scrubSize}>${label}</span>
|
|
151
192
|
<input type="number" step="any" min="0" aria-label=${`${this.partId} ${label} ${i18next.t('figure.label.size-measure')}`} .value=${live(mm === undefined ? '' : String(Number(mm.toFixed(6))))}
|
|
152
|
-
?disabled=${this.locked} ?readonly=${relation.variable ? mode === 'custom' || uniform : !input} @change=${changeSize}>
|
|
193
|
+
?disabled=${this.locked} ?readonly=${relation.variable ? mode === 'custom' || uniform : !input} @input=${typingSize} @change=${changeSize}>
|
|
153
194
|
<label class="variable"><input type="checkbox" aria-label=${`${this.partId} ${label} ${i18next.t('figure.label.size-follows')}`} .checked=${live(relation.variable || this.choosing.has(key))} ?disabled=${this.locked || uniform}
|
|
154
195
|
@change=${follows}></label>
|
|
155
196
|
${choosing || (this.choosing.has(key) && !relation.variable)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-size-editor.js","sourceRoot":"","sources":["../../client/modeller/figure-size-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\nimport { i18next, localize } from '@operato/i18n'\nimport type { FigureAuthoringAction } from '@hatiolab/figure-model'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport type { FigureRevision } from './revision.js'\nimport { AXES, followOf, followableAxes, measureNow, type Axis } from './links.js'\nimport {\n measureFactor,\n sameSizeSource,\n sizeInputOf,\n sizeRelationOf,\n sizeRelationSteps,\n sourceMeasureOf,\n suggestedSizeSource,\n type SizeMode,\n type SizeSource\n} from './size-response.js'\n\n/**\n * A part's measures and what each follows, one row an axis (ADR-0159 3). Made to follow, a measure takes what the part\n * hangs from, along the axis its own axis lies on as it stands -- the author turns it on, nothing more. Another source\n * is there when asked for, or when there is no such axis (the part lies at an angle) or the measure already follows\n * something else; each way of following says what it will do, in millimetres.\n */\n@customElement('figure-size-editor')\nexport class FigureSizeEditor extends localize(i18next)(LitElement) {\n @property({ attribute: false }) revision?: FigureRevision\n @property() partId = ''\n @property({ type: Boolean }) locked = false\n @state() private error = ''\n /* Rows whose source the author asked to choose: `<part>:<axis>`. */\n @state() private choosing = new Set<string>()\n private equivalentModes = new Map<string, 'ratio' | 'difference'>()\n static styles = [SidePanelStyles, css`\n :host { display: block; min-width: 0; }\n .heading, .fields {\n display: grid;\n grid-template-columns: 24px minmax(55px, .85fr) 32px minmax(65px, 1fr) 42px;\n gap: 6px;\n align-items: center;\n }\n .heading { color: var(--md-sys-color-on-surface-variant); padding-bottom: 6px; }\n .dimension { padding: 3px 0; }\n .variable { display: flex; align-items: center; justify-content: center; min-height: var(--figure-control-height); }\n .source { grid-column: 4 / -1; display: flex; align-items: center; gap: 6px; min-width: 0; }\n .source span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .modes { margin: 4px 0 2px 30px; }\n .result { margin: 0 0 6px 30px; }\n [role=alert] { color: var(--md-sys-color-error); }\n `]\n private apply(steps: FigureAuthoringAction[]) {\n if (this.locked) return\n this.error = ''\n this.dispatchEvent(new CustomEvent('size-recipe', { detail: { steps }, bubbles: true, composed: true }))\n this.requestUpdate()\n }\n private configure(axis: Axis, source: SizeSource, mode: 'ratio' | 'difference', mm?: number) {\n if (this.locked || this.revision?.asset.sizing === 'uniform') return\n try {\n this.apply(sizeRelationSteps(this.revision!, this.partId, axis, source, mode, mm))\n this.equivalentModes.set(`${this.partId}:${axis}`, mode)\n } catch (e) {\n this.error = i18next.t((e as Error).message === 'SIZE_VALUE' ? 'figure.text.size-invalid' : 'figure.text.size-unavailable-source')\n this.requestUpdate()\n }\n }\n private choose(key: string, on: boolean) {\n const next = new Set(this.choosing)\n if (on) next.add(key)\n else next.delete(key)\n this.choosing = next\n }\n /** What a source is called on the panel: the figure, or the part, with the axis it is measured along. */\n private sourceWords(source: SizeSource) {\n return `${source.of === 'instance' ? i18next.t('figure.label.size-figure') : source.part} ${source.axis.toUpperCase()}`\n }\n /** What following this way does, in millimetres: the share it is of its source, or the difference it keeps. */\n private resultWords(revision: FigureRevision, source: SizeSource, mode: 'ratio' | 'difference', mm: number | undefined) {\n const theirs = sourceMeasureOf(revision, source)\n if (mm === undefined || theirs === undefined || !(theirs > 0)) return nothing\n const words = { source: this.sourceWords(source), size: Number(theirs.toFixed(1)) }\n if (mode === 'ratio') return i18next.t('figure.text.size-ratio-result', { ...words, pct: Number(((mm / theirs) * 100).toFixed(1)) })\n const gap = Number((theirs - mm).toFixed(1))\n if (Math.abs(gap) < 0.05) return i18next.t('figure.text.size-difference-same', words)\n return i18next.t(gap > 0 ? 'figure.text.size-difference-less' : 'figure.text.size-difference-more', { ...words, gap: Math.abs(gap) })\n }\n render() {\n const revision = this.revision\n if (!revision) return nothing\n const asset = revision.asset\n const axes = followableAxes(asset, this.partId)\n const targets = asset.appearance.map(a => a.target).filter(p => p !== this.partId && followableAxes(asset, p).length)\n const uniform = asset.sizing === 'uniform'\n return html`\n <div class=\"heading\" aria-hidden=\"true\">\n <span>${i18next.t('figure.label.size-axis')}</span><span>${i18next.t('figure.label.size-measure')}</span><span>${i18next.t('figure.label.size-follows')}</span><span>${i18next.t('figure.label.size-source')}</span><span></span>\n </div>\n ${axes.map(axis => {\n const key = `${this.partId}:${axis}`\n const mm = measureNow(revision, this.partId, axis)\n const relation = sizeRelationOf(revision, this.partId, axis)\n const f = followOf(asset, this.partId, axis)\n const source = relation.source\n const suggested = suggestedSizeSource(asset, this.partId, axis)\n let mode: SizeMode = relation.mode\n if (source && (f.of === 'instance' || f.of === 'part') && !f.plus) {\n const same = (source.of === 'part' ? measureFactor(asset, source.part, source.axis) : 1) / measureFactor(asset, this.partId, axis)\n if (Math.abs((f.times ?? 1) - same) < 1e-6) mode = this.equivalentModes.get(key) ?? mode\n }\n const currentMode = mode === 'custom' ? 'ratio' : mode\n const input = sizeInputOf(asset, this.partId, axis)\n const label = `${axis.toUpperCase()}${measureFactor(asset, this.partId, axis) === 2 ? ' · ' + i18next.t('figure.label.size-diameter') : ''}`\n /* The selects show when asked for, or when what it follows is not what its fastening gives -- or nothing is. */\n const choosing = relation.variable && (this.choosing.has(key) || !sameSizeSource(source, suggested))\n const selectedSource = source ? (source.of === 'instance' ? '@figure' : source.part) : '@custom'\n const sourceAxes = source?.of === 'part' ? followableAxes(asset, source.part) : AXES\n const changeSize = (e: Event) => {\n const value = (e.target as HTMLInputElement).valueAsNumber\n if (!(Number.isFinite(value) && value > 0)) {\n this.error = i18next.t('figure.text.size-invalid')\n this.requestUpdate()\n return\n }\n if (relation.variable && source && mode !== 'custom') this.configure(axis, source, mode, value)\n else if (!relation.variable && input) {\n this.error = ''\n this.dispatchEvent(new CustomEvent('size-input', { detail: { input, value: value / measureFactor(asset, this.partId, axis), part: this.partId }, bubbles: true, composed: true }))\n this.requestUpdate()\n }\n }\n const follows = (e: Event) => {\n if ((e.target as HTMLInputElement).checked) {\n if (suggested) this.configure(axis, suggested, 'ratio')\n else {\n /* At an angle to what it hangs from: which of its measures it follows is the author's to pick. */\n this.choose(key, true)\n this.error = i18next.t('figure.text.size-unpaired')\n }\n } else if (mm !== undefined) {\n this.choose(key, false)\n this.apply([{ kind: 'unlink-dimension', part: this.partId, axis, mm: mm / measureFactor(asset, this.partId, axis) }])\n }\n }\n return html`<div class=\"dimension\" data-axis=${axis}>\n <div class=\"fields\">\n <span>${label}</span>\n <input type=\"number\" step=\"any\" min=\"0\" aria-label=${`${this.partId} ${label} ${i18next.t('figure.label.size-measure')}`} .value=${live(mm === undefined ? '' : String(Number(mm.toFixed(6))))}\n ?disabled=${this.locked} ?readonly=${relation.variable ? mode === 'custom' || uniform : !input} @change=${changeSize}>\n <label class=\"variable\"><input type=\"checkbox\" aria-label=${`${this.partId} ${label} ${i18next.t('figure.label.size-follows')}`} .checked=${live(relation.variable || this.choosing.has(key))} ?disabled=${this.locked || uniform}\n @change=${follows}></label>\n ${choosing || (this.choosing.has(key) && !relation.variable)\n ? html`\n <select aria-label=${`${this.partId} ${label} ${i18next.t('figure.label.size-source')}`} .value=${live(selectedSource)} ?disabled=${this.locked || uniform}\n @change=${(e: Event) => {\n const target = (e.target as HTMLSelectElement).value\n const possible = target === '@figure' ? AXES : followableAxes(asset, target)\n const targetAxis = possible.includes(source?.axis ?? axis) ? (source?.axis ?? axis) : possible[0]!\n this.configure(axis, target === '@figure' ? { of: 'instance', axis: targetAxis } : { of: 'part', part: target, axis: targetAxis }, currentMode)\n }}>\n ${!source ? html`<option value=\"@custom\" disabled>${i18next.t(relation.variable ? 'figure.label.size-existing-rule' : 'figure.label.size-pick-source')}</option>` : nothing}\n <option value=\"@figure\" ?selected=${selectedSource === '@figure'}>${i18next.t('figure.label.size-figure')}</option>\n ${targets.map(p => html`<option value=${p} ?selected=${selectedSource === p}>${p}</option>`)}\n </select>\n <select aria-label=${`${this.partId} ${label} ${i18next.t('figure.label.size-source-axis')}`} .value=${live(source?.axis ?? axis)} ?disabled=${this.locked || uniform || !source}\n @change=${(e: Event) => source && this.configure(axis, { ...source, axis: (e.target as HTMLSelectElement).value as Axis }, currentMode)}>\n ${sourceAxes.map(a => html`<option value=${a} ?selected=${a === (source?.axis ?? axis)}>${a.toUpperCase()}</option>`)}\n </select>`\n : relation.variable && source\n ? html`<div class=\"source\">\n <span>${this.sourceWords(source)}</span>\n <button quiet ?disabled=${this.locked || uniform} @click=${() => this.choose(key, true)}>${i18next.t('figure.button.size-other-source')}</button>\n </div>`\n : html`<span></span><span></span>`}\n </div>\n ${relation.variable\n ? html`<div class=\"modes\" choice-row>\n ${(['ratio', 'difference'] as const).map(\n m => html`<label toggle><input type=\"radio\" name=${`mode-${this.partId}-${axis}`} .checked=${live(mode === m)} ?disabled=${this.locked || uniform || !source}\n @change=${() => source && this.configure(axis, source, m)}>${i18next.t(`figure.label.size-${m}`)}</label>`\n )}\n </div>\n ${mode === 'custom'\n ? html`<p hint>${i18next.t('figure.text.size-custom-rule')}</p>`\n : source\n ? html`<p hint class=\"result\">${this.resultWords(revision, source, currentMode, mm)}</p>`\n : nothing}`\n : nothing}\n </div>`\n })}\n ${uniform ? html`<p hint>${i18next.t('figure.text.size-uniform')}</p>` : nothing}\n ${this.error ? html`<p hint role=\"alert\">${this.error}</p>` : nothing}\n `\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-size-editor.js","sourceRoot":"","sources":["../../client/modeller/figure-size-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\nimport { i18next, localize } from '@operato/i18n'\nimport type { FigureAuthoringAction } from '@hatiolab/figure-model'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport type { FigureRevision } from './revision.js'\nimport { AXES, followOf, followableAxes, measureNow, type Axis } from './links.js'\nimport { scrubLabel } from './live.js'\nimport {\n measureFactor,\n sameSizeSource,\n sizeInputOf,\n sizeRelationOf,\n sizeRelationSteps,\n sourceMeasureOf,\n suggestedSizeSource,\n type SizeMode,\n type SizeSource\n} from './size-response.js'\n\n/**\n * A part's measures and what each follows, one row an axis (ADR-0159 3). Made to follow, a measure takes what the part\n * hangs from, along the axis its own axis lies on as it stands -- the author turns it on, nothing more. Another source\n * is there when asked for, or when there is no such axis (the part lies at an angle) or the measure already follows\n * something else; each way of following says what it will do, in millimetres. A measure of the part's own is a value in\n * hand as on any field (user 2026-09-24): drawn while it is typed or its label is dragged, written once on the release.\n */\n@customElement('figure-size-editor')\nexport class FigureSizeEditor extends localize(i18next)(LitElement) {\n @property({ attribute: false }) revision?: FigureRevision\n @property() partId = ''\n @property({ type: Boolean }) locked = false\n @state() private error = ''\n /* Rows whose source the author asked to choose: `<part>:<axis>`. */\n @state() private choosing = new Set<string>()\n private equivalentModes = new Map<string, 'ratio' | 'difference'>()\n static styles = [SidePanelStyles, css`\n :host { display: block; min-width: 0; }\n .heading, .fields {\n display: grid;\n grid-template-columns: 24px minmax(55px, .85fr) 32px minmax(65px, 1fr) 42px;\n gap: 6px;\n align-items: center;\n }\n .heading { color: var(--md-sys-color-on-surface-variant); padding-bottom: 6px; }\n .dimension { padding: 3px 0; }\n .variable { display: flex; align-items: center; justify-content: center; min-height: var(--figure-control-height); }\n .source { grid-column: 4 / -1; display: flex; align-items: center; gap: 6px; min-width: 0; }\n .source span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .modes { margin: 4px 0 2px 30px; }\n .result { margin: 0 0 6px 30px; }\n [role=alert] { color: var(--md-sys-color-error); }\n `]\n private tell(name: 'size-input' | 'size-typing' | 'size-let-go', detail?: object) {\n this.dispatchEvent(new CustomEvent(name, { detail, bubbles: true, composed: true }))\n }\n private apply(steps: FigureAuthoringAction[]) {\n if (this.locked) return\n this.error = ''\n this.dispatchEvent(new CustomEvent('size-recipe', { detail: { steps }, bubbles: true, composed: true }))\n this.requestUpdate()\n }\n private configure(axis: Axis, source: SizeSource, mode: 'ratio' | 'difference', mm?: number) {\n if (this.locked || this.revision?.asset.sizing === 'uniform') return\n try {\n this.apply(sizeRelationSteps(this.revision!, this.partId, axis, source, mode, mm))\n this.equivalentModes.set(`${this.partId}:${axis}`, mode)\n } catch (e) {\n this.error = i18next.t((e as Error).message === 'SIZE_VALUE' ? 'figure.text.size-invalid' : 'figure.text.size-unavailable-source')\n this.requestUpdate()\n }\n }\n private choose(key: string, on: boolean) {\n const next = new Set(this.choosing)\n if (on) next.add(key)\n else next.delete(key)\n this.choosing = next\n }\n /** What a source is called on the panel: the figure, or the part, with the axis it is measured along. */\n private sourceWords(source: SizeSource) {\n return `${source.of === 'instance' ? i18next.t('figure.label.size-figure') : source.part} ${source.axis.toUpperCase()}`\n }\n /** What following this way does, in millimetres: the share it is of its source, or the difference it keeps. */\n private resultWords(revision: FigureRevision, source: SizeSource, mode: 'ratio' | 'difference', mm: number | undefined) {\n const theirs = sourceMeasureOf(revision, source)\n if (mm === undefined || theirs === undefined || !(theirs > 0)) return nothing\n const words = { source: this.sourceWords(source), size: Number(theirs.toFixed(1)) }\n if (mode === 'ratio') return i18next.t('figure.text.size-ratio-result', { ...words, pct: Number(((mm / theirs) * 100).toFixed(1)) })\n const gap = Number((theirs - mm).toFixed(1))\n if (Math.abs(gap) < 0.05) return i18next.t('figure.text.size-difference-same', words)\n return i18next.t(gap > 0 ? 'figure.text.size-difference-less' : 'figure.text.size-difference-more', { ...words, gap: Math.abs(gap) })\n }\n render() {\n const revision = this.revision\n if (!revision) return nothing\n const asset = revision.asset\n const axes = followableAxes(asset, this.partId)\n const targets = asset.appearance.map(a => a.target).filter(p => p !== this.partId && followableAxes(asset, p).length)\n const uniform = asset.sizing === 'uniform'\n return html`\n <div class=\"heading\" aria-hidden=\"true\">\n <span>${i18next.t('figure.label.size-axis')}</span><span>${i18next.t('figure.label.size-measure')}</span><span>${i18next.t('figure.label.size-follows')}</span><span>${i18next.t('figure.label.size-source')}</span><span></span>\n </div>\n ${axes.map(axis => {\n const key = `${this.partId}:${axis}`\n const mm = measureNow(revision, this.partId, axis)\n const relation = sizeRelationOf(revision, this.partId, axis)\n const f = followOf(asset, this.partId, axis)\n const source = relation.source\n const suggested = suggestedSizeSource(asset, this.partId, axis)\n let mode: SizeMode = relation.mode\n if (source && (f.of === 'instance' || f.of === 'part') && !f.plus) {\n const same = (source.of === 'part' ? measureFactor(asset, source.part, source.axis) : 1) / measureFactor(asset, this.partId, axis)\n if (Math.abs((f.times ?? 1) - same) < 1e-6) mode = this.equivalentModes.get(key) ?? mode\n }\n const currentMode = mode === 'custom' ? 'ratio' : mode\n const input = sizeInputOf(asset, this.partId, axis)\n const label = `${axis.toUpperCase()}${measureFactor(asset, this.partId, axis) === 2 ? ' · ' + i18next.t('figure.label.size-diameter') : ''}`\n /* The selects show when asked for, or when what it follows is not what its fastening gives -- or nothing is. */\n const choosing = relation.variable && (this.choosing.has(key) || !sameSizeSource(source, suggested))\n const selectedSource = source ? (source.of === 'instance' ? '@figure' : source.part) : '@custom'\n const sourceAxes = source?.of === 'part' ? followableAxes(asset, source.part) : AXES\n const factor = measureFactor(asset, this.partId, axis)\n /* Its own measure, no rule over it: in hand while typed or scrubbed, as the input it is (a diameter, its radius). */\n const own = !relation.variable && !!input && !this.locked\n const typingSize = (e: Event) => {\n const value = (e.target as HTMLInputElement).valueAsNumber\n if (own && Number.isFinite(value) && value > 0) this.tell('size-typing', { input, value: value / factor })\n }\n const scrubSize = (down: PointerEvent) => {\n if (!own || mm === undefined) return\n const field = (down.currentTarget as HTMLElement).closest('.fields')?.querySelector<HTMLInputElement>('input[type=number]')\n if (!field) return\n scrubLabel(down, { value: mm, unit: 'mm' }, {\n move: value => {\n field.value = String(value)\n if (value > 0) this.tell('size-typing', { input, value: value / factor })\n },\n release: value => {\n if (!(value > 0)) {\n field.value = String(mm)\n this.tell('size-let-go')\n return\n }\n this.error = ''\n this.tell('size-input', { input, value: value / factor, part: this.partId })\n this.requestUpdate()\n },\n cancel: () => {\n field.value = String(mm)\n this.tell('size-let-go')\n }\n })\n }\n const changeSize = (e: Event) => {\n const value = (e.target as HTMLInputElement).valueAsNumber\n if (!(Number.isFinite(value) && value > 0)) {\n this.error = i18next.t('figure.text.size-invalid')\n this.requestUpdate()\n return\n }\n if (relation.variable && source && mode !== 'custom') this.configure(axis, source, mode, value)\n else if (!relation.variable && input) {\n this.error = ''\n this.tell('size-input', { input, value: value / factor, part: this.partId })\n this.requestUpdate()\n }\n }\n const follows = (e: Event) => {\n if ((e.target as HTMLInputElement).checked) {\n if (suggested) this.configure(axis, suggested, 'ratio')\n else {\n /* At an angle to what it hangs from: which of its measures it follows is the author's to pick. */\n this.choose(key, true)\n this.error = i18next.t('figure.text.size-unpaired')\n }\n } else if (mm !== undefined) {\n this.choose(key, false)\n this.apply([{ kind: 'unlink-dimension', part: this.partId, axis, mm: mm / measureFactor(asset, this.partId, axis) }])\n }\n }\n return html`<div class=\"dimension\" data-axis=${axis}>\n <div class=\"fields\">\n <span ?scrub=${own} @pointerdown=${scrubSize}>${label}</span>\n <input type=\"number\" step=\"any\" min=\"0\" aria-label=${`${this.partId} ${label} ${i18next.t('figure.label.size-measure')}`} .value=${live(mm === undefined ? '' : String(Number(mm.toFixed(6))))}\n ?disabled=${this.locked} ?readonly=${relation.variable ? mode === 'custom' || uniform : !input} @input=${typingSize} @change=${changeSize}>\n <label class=\"variable\"><input type=\"checkbox\" aria-label=${`${this.partId} ${label} ${i18next.t('figure.label.size-follows')}`} .checked=${live(relation.variable || this.choosing.has(key))} ?disabled=${this.locked || uniform}\n @change=${follows}></label>\n ${choosing || (this.choosing.has(key) && !relation.variable)\n ? html`\n <select aria-label=${`${this.partId} ${label} ${i18next.t('figure.label.size-source')}`} .value=${live(selectedSource)} ?disabled=${this.locked || uniform}\n @change=${(e: Event) => {\n const target = (e.target as HTMLSelectElement).value\n const possible = target === '@figure' ? AXES : followableAxes(asset, target)\n const targetAxis = possible.includes(source?.axis ?? axis) ? (source?.axis ?? axis) : possible[0]!\n this.configure(axis, target === '@figure' ? { of: 'instance', axis: targetAxis } : { of: 'part', part: target, axis: targetAxis }, currentMode)\n }}>\n ${!source ? html`<option value=\"@custom\" disabled>${i18next.t(relation.variable ? 'figure.label.size-existing-rule' : 'figure.label.size-pick-source')}</option>` : nothing}\n <option value=\"@figure\" ?selected=${selectedSource === '@figure'}>${i18next.t('figure.label.size-figure')}</option>\n ${targets.map(p => html`<option value=${p} ?selected=${selectedSource === p}>${p}</option>`)}\n </select>\n <select aria-label=${`${this.partId} ${label} ${i18next.t('figure.label.size-source-axis')}`} .value=${live(source?.axis ?? axis)} ?disabled=${this.locked || uniform || !source}\n @change=${(e: Event) => source && this.configure(axis, { ...source, axis: (e.target as HTMLSelectElement).value as Axis }, currentMode)}>\n ${sourceAxes.map(a => html`<option value=${a} ?selected=${a === (source?.axis ?? axis)}>${a.toUpperCase()}</option>`)}\n </select>`\n : relation.variable && source\n ? html`<div class=\"source\">\n <span>${this.sourceWords(source)}</span>\n <button quiet ?disabled=${this.locked || uniform} @click=${() => this.choose(key, true)}>${i18next.t('figure.button.size-other-source')}</button>\n </div>`\n : html`<span></span><span></span>`}\n </div>\n ${relation.variable\n ? html`<div class=\"modes\" choice-row>\n ${(['ratio', 'difference'] as const).map(\n m => html`<label toggle><input type=\"radio\" name=${`mode-${this.partId}-${axis}`} .checked=${live(mode === m)} ?disabled=${this.locked || uniform || !source}\n @change=${() => source && this.configure(axis, source, m)}>${i18next.t(`figure.label.size-${m}`)}</label>`\n )}\n </div>\n ${mode === 'custom'\n ? html`<p hint>${i18next.t('figure.text.size-custom-rule')}</p>`\n : source\n ? html`<p hint class=\"result\">${this.resultWords(revision, source, currentMode, mm)}</p>`\n : nothing}`\n : nothing}\n </div>`\n })}\n ${uniform ? html`<p hint>${i18next.t('figure.text.size-uniform')}</p>` : nothing}\n ${this.error ? html`<p hint role=\"alert\">${this.error}</p>` : nothing}\n `\n }\n}\n"]}
|
|
@@ -278,7 +278,7 @@ export interface Motion {
|
|
|
278
278
|
plus?: number;
|
|
279
279
|
};
|
|
280
280
|
}
|
|
281
|
-
export declare function motionOf(asset: FigureAsset, part: string): Motion | undefined;
|
|
281
|
+
export declare function motionOf(asset: FigureAsset, part: string, k?: number): Motion | undefined;
|
|
282
282
|
/** What the motion form holds: how the part moves, and either its own control or the joint it moves with. */
|
|
283
283
|
export interface MotionForm {
|
|
284
284
|
kind: 'slide' | 'turn' | 'continuous';
|
|
@@ -315,14 +315,15 @@ export interface MotionForm {
|
|
|
315
315
|
* The motion form filled from a joint as it is, so a motion can be changed where it is -- its range, the length it
|
|
316
316
|
* travels by, what it follows -- rather than taken away and made again. Taking it away is refused while another joint
|
|
317
317
|
* follows it, which left a leader's stroke fixed for good (the telescopic conveyor, 2026-09-25). The form is the
|
|
318
|
-
* joint's
|
|
318
|
+
* joint's axis `k` (ADR-0159), the first unless said; the other axes are kept as they are when it is written
|
|
319
|
+
* (`motionJoint`). An axis past the last is a new one: a turn about the first of X, Y, Z the joint's axes do not use.
|
|
319
320
|
*/
|
|
320
|
-
export declare function motionFormOf(joint: FigureJoint): MotionForm;
|
|
321
|
+
export declare function motionFormOf(joint: FigureJoint, k?: number): MotionForm;
|
|
321
322
|
/**
|
|
322
323
|
* The axes a part's joint can move with (URDF's mimic): one of another part's that moves the same way — a slide follows
|
|
323
324
|
* a slide, a turn a turn — and has a control of its own, since a follower follows the axis that is driven (ADR-0159).
|
|
324
325
|
*/
|
|
325
|
-
export declare function leadersFor(asset: FigureAsset, part: string, kind: MotionForm['kind']): Array<FigureNamedMotion & {
|
|
326
|
+
export declare function leadersFor(asset: FigureAsset, part: string, kind: MotionForm['kind'], self?: string): Array<FigureNamedMotion & {
|
|
326
327
|
part: string;
|
|
327
328
|
}>;
|
|
328
329
|
/**
|
|
@@ -330,7 +331,15 @@ export declare function leadersFor(asset: FigureAsset, part: string, kind: Motio
|
|
|
330
331
|
* a turn without end, as in USD) and a control; a follower gets the leader, the multiplier and the offset, and no
|
|
331
332
|
* control or limits of its own — its range is the leader's times the multiplier.
|
|
332
333
|
*/
|
|
333
|
-
export declare function motionJoint(joint: FigureJoint, m: MotionForm, part: string): FigureJoint;
|
|
334
|
+
export declare function motionJoint(joint: FigureJoint, m: MotionForm, part: string, k?: number): FigureJoint;
|
|
335
|
+
/** The control an axis gets when the author names none: `<part>-<kind>`, and `<part>-<kind>-<n>` for the n-th axis. */
|
|
336
|
+
export declare function controlIdFor(part: string, kind: MotionForm['kind'], k: number): string;
|
|
337
|
+
/**
|
|
338
|
+
* The joint without its axis `k`. The axes after it keep the names they went by: one named by its place
|
|
339
|
+
* (`<joint>.<k>`, figure-model `motionIdOf`) is given that name before it moves up, so its control is not renamed under
|
|
340
|
+
* a board that writes to it.
|
|
341
|
+
*/
|
|
342
|
+
export declare function withoutAxis(joint: FigureJoint, k: number): FigureJoint;
|
|
334
343
|
/**
|
|
335
344
|
* Why the motion form cannot be saved as it stands, as the kernel would refuse it: a follower's multiplier that is not
|
|
336
345
|
* a number or is 0, or a range whose most is not above its least. A range need not hold 0 -- the control starts at the
|
|
@@ -339,7 +348,7 @@ export declare function motionJoint(joint: FigureJoint, m: MotionForm, part: str
|
|
|
339
348
|
export declare function motionFormRefusalOf(m: MotionForm, follow: string): 'multiplier' | 'range' | undefined;
|
|
340
349
|
/** The select's value for what a dimension follows now. */
|
|
341
350
|
/**
|
|
342
|
-
* What a measure that is not its own follows, in the words of the choice that set it --
|
|
351
|
+
* What a measure that is not its own follows, in the words of the choice that set it -- 「피규어 X 크기에 비례」, 「bed의 X」 --
|
|
343
352
|
* where the row once said only 「다른 규칙에 연결됨」 (user 2026-10-16: which rule?).
|
|
344
353
|
*/
|
|
345
354
|
export declare function followWordsOf(follow: Follow, say: (key: string, params?: Record<string, string>) => string): string;
|