@things-factory/figure-ui 10.1.169 → 10.1.171
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/modeller/affected-parts.ts +11 -0
- package/client/modeller/canvas.ts +15 -1
- package/client/modeller/editor-styles.ts +98 -6
- package/client/modeller/editor.ts +212 -53
- package/client/modeller/fasten-geometry.ts +19 -0
- package/client/modeller/figure-fasten-drawing.ts +4 -3
- package/client/modeller/figure-links.ts +80 -37
- package/client/modeller/figure-material-panel.ts +20 -1
- package/client/modeller/figure-preview.ts +121 -8
- package/client/modeller/figure-properties.ts +1 -2
- package/client/modeller/figure-section-panel.ts +5 -0
- package/client/modeller/figure-verdict.ts +9 -2
- package/client/modeller/gate-findings.ts +12 -4
- package/client/modeller/group-menu.ts +57 -0
- package/client/modeller/links.ts +22 -1
- package/client/modeller/modeller-keys.ts +6 -0
- package/client/modeller/preview-size.ts +32 -0
- package/client/modeller/stage-model.ts +11 -0
- package/client/pages/figure-modeller-page.ts +8 -2
- package/dist-client/modeller/affected-parts.d.ts +6 -0
- package/dist-client/modeller/affected-parts.js +12 -0
- package/dist-client/modeller/affected-parts.js.map +1 -0
- package/dist-client/modeller/canvas.d.ts +3 -0
- package/dist-client/modeller/canvas.js +12 -1
- package/dist-client/modeller/canvas.js.map +1 -1
- package/dist-client/modeller/clips.d.ts +1 -1
- package/dist-client/modeller/editor-styles.js +98 -6
- package/dist-client/modeller/editor-styles.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +42 -1
- package/dist-client/modeller/editor.js +220 -51
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/fasten-geometry.d.ts +27 -0
- package/dist-client/modeller/fasten-geometry.js +14 -0
- package/dist-client/modeller/fasten-geometry.js.map +1 -1
- package/dist-client/modeller/figure-fasten-drawing.js +4 -3
- package/dist-client/modeller/figure-fasten-drawing.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +2 -0
- package/dist-client/modeller/figure-links.js +84 -38
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/figure-material-panel.d.ts +7 -0
- package/dist-client/modeller/figure-material-panel.js +24 -1
- package/dist-client/modeller/figure-material-panel.js.map +1 -1
- package/dist-client/modeller/figure-preview.d.ts +12 -0
- package/dist-client/modeller/figure-preview.js +120 -5
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-properties.js +1 -2
- package/dist-client/modeller/figure-properties.js.map +1 -1
- package/dist-client/modeller/figure-section-panel.js +5 -0
- package/dist-client/modeller/figure-section-panel.js.map +1 -1
- package/dist-client/modeller/figure-verdict.d.ts +1 -0
- package/dist-client/modeller/figure-verdict.js +8 -2
- package/dist-client/modeller/figure-verdict.js.map +1 -1
- package/dist-client/modeller/gate-findings.d.ts +3 -1
- package/dist-client/modeller/gate-findings.js +8 -4
- package/dist-client/modeller/gate-findings.js.map +1 -1
- package/dist-client/modeller/group-menu.d.ts +18 -0
- package/dist-client/modeller/group-menu.js +52 -0
- package/dist-client/modeller/group-menu.js.map +1 -0
- package/dist-client/modeller/links.d.ts +5 -0
- package/dist-client/modeller/links.js +21 -1
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/modeller-keys.js +7 -0
- package/dist-client/modeller/modeller-keys.js.map +1 -1
- package/dist-client/modeller/preview-size.d.ts +23 -0
- package/dist-client/modeller/preview-size.js +32 -0
- package/dist-client/modeller/preview-size.js.map +1 -0
- package/dist-client/modeller/stage-model.d.ts +11 -0
- package/dist-client/modeller/stage-model.js +11 -0
- package/dist-client/modeller/stage-model.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.d.ts +3 -0
- package/dist-client/pages/figure-modeller-page.js +11 -2
- 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/package.json +8 -8
- package/test/browser/editing-page.js +3 -1
- package/test/browser/editing.check.mjs +2 -1
- package/test/browser/links-page.js +1 -0
- package/test/browser/links.check.mjs +20 -5
- package/test/browser/modeller.check.mjs +9 -1
- package/test/browser/more-open.js +11 -0
- package/test/browser/parts.check.mjs +11 -1
- package/test/browser/places-mesh.check.mjs +9 -3
- package/test/browser/product-page.check.mjs +9 -4
- package/test/browser/props.check.mjs +224 -0
- package/test/browser/screen-page.js +18 -0
- package/test/browser/screen.check.mjs +172 -29
- package/test/browser/section-page.js +1 -0
- package/test/browser/section.check.mjs +6 -0
- package/test/command-preview.test.ts +2 -2
- package/test/fasten-geometry.test.ts +15 -0
- package/test/fields.test.ts +4 -2
- package/test/first-minute.test.ts +15 -2
- package/test/layout.test.ts +1 -1
- package/test/preview-size.test.ts +33 -0
- package/test/refusals.test.ts +1 -1
- package/test/resize-with-placement.test.ts +1 -1
- package/test/stage-model.test.ts +11 -1
- package/test/verdict.test.ts +7 -0
- package/translations/en.json +37 -27
- package/translations/es.json +18 -8
- package/translations/ja.json +19 -9
- package/translations/ko.json +50 -40
- package/translations/ms.json +19 -9
- package/translations/zh.json +19 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-styles.js","sourceRoot":"","sources":["../../client/modeller/editor-styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB,gHAAgH;AAChH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+S9B,CAAA","sourcesContent":["import { css } from 'lit'\n\n/** The modeller editor's own styles: the bar's tools, the panes, the start card, the side's tabs and panels. */\nexport const EditorStyles = css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n height: 100%;\n /* The editor folds by the width it is given, not the window's (UX ruling, 2026-09-24). */\n container-type: inline-size;\n font: 13px sans-serif;\n color: var(--md-sys-color-on-surface);\n }\n /* The bar over the work is ox-canvas-bar (ADR-0060 decision 8): the folds at its edges, undo, redo and\n fit in the suite's places. What the editor puts in it - the mode switch, the status, save - is styled here. */\n ox-canvas-bar button[mode] {\n height: 28px;\n padding: 0 10px;\n border-radius: 999em;\n border-color: transparent;\n background: none;\n }\n ox-canvas-bar button[mode][aria-pressed='true'] {\n border-color: var(--md-sys-color-primary);\n }\n /* The gizmo's tools, drawn as the bar's own icon buttons (undo, redo, fit). */\n ox-canvas-bar .gizmo-tools {\n display: inline-flex;\n gap: 2px;\n padding-left: 4px;\n border-left: 1px solid var(--md-sys-color-outline-variant);\n }\n ox-canvas-bar button[tool] {\n display: inline-grid;\n place-items: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n border-radius: var(--md-sys-shape-corner-small, 8px);\n background: transparent;\n color: var(--md-sys-color-on-surface-variant);\n cursor: pointer;\n }\n ox-canvas-bar button[tool]:hover:not(:disabled) {\n background: var(--md-sys-color-surface-container-high);\n color: var(--md-sys-color-on-surface);\n }\n ox-canvas-bar button[tool][aria-pressed='true'] {\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n ox-canvas-bar button[tool]:disabled {\n opacity: 0.38;\n cursor: default;\n }\n /*\n Slotted into the bar from here, the tools do not get the bar's own icon size (20px, set inside its shadow): they\n showed at md-icon's 24px, heavier than undo, redo and fit beside them. The same size, and the bar's focus ring.\n */\n ox-canvas-bar button[tool] md-icon {\n --md-icon-size: 20px;\n }\n ox-canvas-bar button[tool]:focus-visible {\n outline: 2px solid var(--md-sys-color-primary);\n outline-offset: 1px;\n }\n figure-preview {\n min-width: 0;\n min-height: 0;\n }\n /* The edit canvas stays standing while the preview is in front (a 3D scene costs a third of a second to make), out of sight. */\n div[middle][hidden] {\n display: none;\n }\n /* The preview, once made, stays standing out of sight too: its 3D scene is not made again each time it is asked for. */\n figure-preview[hidden] {\n display: none;\n }\n ox-canvas-bar .status {\n padding: 0 8px;\n color: var(--md-sys-color-on-surface-variant);\n }\n ox-canvas-bar .status[dirty] {\n color: var(--md-sys-color-primary);\n font-weight: 600;\n }\n ox-canvas-bar button[save] {\n height: 32px;\n padding: 0 14px;\n border: none;\n border-radius: 999em;\n color: var(--md-sys-color-on-primary);\n background: var(--md-sys-color-primary);\n }\n /* The three panes are ox-three-pane's (ADR-0060 decision 8): widths 200 | 1fr | 340, 160 | 300 under\n 860px and one column with the middle first under 560px are the frame's, as are the dividers. */\n ox-three-pane {\n flex: 1;\n min-height: 0;\n }\n figure-parts {\n min-height: 0;\n }\n figure-canvas {\n flex: 1;\n min-width: 0;\n min-height: 0;\n }\n div[middle] {\n position: relative;\n display: flex;\n min-width: 0;\n min-height: 0;\n }\n /* A new figure's first question, over the empty canvas. */\n div[start] {\n position: absolute;\n inset: 50% auto auto 50%;\n z-index: 10;\n color: var(--md-sys-color-on-surface);\n transform: translate(-50%, -50%);\n width: min(440px, calc(100% - 32px));\n box-sizing: border-box;\n padding: 20px;\n border-radius: 12px;\n background: var(--md-sys-color-surface, #fff);\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);\n }\n div[start] button[start-button] {\n width: auto;\n margin: 0;\n font-size: var(--ui-t-body);\n height: 36px;\n padding: 0 16px;\n border: 1px solid var(--md-sys-color-outline);\n border-radius: 999em;\n color: var(--md-sys-color-primary);\n background: var(--md-sys-color-surface, #fff);\n cursor: pointer;\n }\n div[start] button[start-button]:hover:not(:disabled) {\n background: var(--md-sys-color-primary-container);\n }\n div[start] button[start-button][pressed] {\n color: var(--md-sys-color-on-primary);\n background: var(--md-sys-color-primary);\n border-color: var(--md-sys-color-primary);\n }\n div[start] button[start-button]:disabled {\n opacity: 0.5;\n cursor: default;\n }\n div[start] h2 {\n margin: 0 0 12px;\n font-size: var(--ui-t-title);\n }\n div[start-paths] {\n display: grid;\n gap: 14px;\n }\n div[start-paths] h3 {\n margin: 0 0 6px;\n font-size: var(--ui-t-body);\n }\n div[start-shapes] {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n }\n div[start] small {\n display: block;\n margin-top: 4px;\n color: var(--md-sys-color-on-surface-variant);\n }\n /* The side: tabs over one panel at a time, each using the whole height. */\n aside {\n display: flex;\n flex-direction: column;\n min-height: 0;\n background: var(--md-sys-color-surface-container-lowest);\n }\n div[tabs] {\n display: flex;\n flex: none;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n button[tab] {\n flex: 1;\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 1px;\n min-width: 0;\n height: 48px;\n padding: 0;\n border: none;\n border-radius: 0;\n border-bottom: 2px solid transparent;\n background: none;\n color: var(--md-sys-color-on-surface-variant);\n }\n button[tab]:hover:not([on]) {\n background: var(--md-sys-color-surface-container);\n }\n button[tab][on] {\n color: var(--md-sys-color-primary);\n border-bottom-color: var(--md-sys-color-primary);\n }\n button[tab] md-icon {\n font-size: 20px;\n width: 20px;\n height: 20px;\n }\n button[tab] span[tab-label] {\n max-width: 100%;\n overflow: hidden;\n font-size: 0.66rem;\n line-height: 1.2;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n span[badge] {\n position: absolute;\n top: 3px;\n right: 2px;\n padding: 0 5px;\n font-size: 0.62rem;\n font-weight: 700;\n line-height: 1.5;\n color: var(--md-sys-color-on-primary-container);\n background: var(--md-sys-color-primary-container);\n border-radius: 999em;\n pointer-events: none;\n }\n /* The sections inside carry the margins (side-panel-styles); the panel only scrolls. */\n div[panel] {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 0;\n }\n div[panel][flush] {\n padding: 0;\n }\n /* Hidden, not removed: a panel keeps what it holds (the verdict its last answer) while another tab is open. */\n [off] {\n display: none !important;\n }\n /* Which part the panel speaks of. */\n div[subject] {\n position: sticky;\n top: 0;\n z-index: 1;\n display: grid;\n gap: 4px;\n padding: 10px 12px;\n background: var(--md-sys-color-surface-container-lowest);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n /* The panel's three sizes (side-panel-styles): the part's kind at the title's, its two lines at the hint's. */\n div[subject-summary] {\n display: grid;\n gap: 2px;\n }\n div[subject-summary] b {\n font-size: var(--ui-t-body, 13px);\n font-weight: 600;\n }\n div[subject-summary] b span {\n font-weight: 400;\n color: var(--md-sys-color-on-surface-variant);\n }\n div[subject-summary] small {\n color: var(--md-sys-color-on-surface-variant);\n }\n button {\n font: inherit;\n box-sizing: border-box;\n height: 32px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n background: var(--md-sys-color-surface);\n color: inherit;\n padding: 0 8px;\n min-width: 0;\n }\n button {\n cursor: pointer;\n }\n button:disabled {\n opacity: 0.45;\n cursor: default;\n }\n button[aria-pressed='true'] {\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n border-color: var(--md-sys-color-primary);\n }\n .hint {\n color: var(--md-sys-color-on-surface-variant);\n line-height: 1.5;\n }\n`\n"]}
|
|
1
|
+
{"version":3,"file":"editor-styles.js","sourceRoot":"","sources":["../../client/modeller/editor-styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB,gHAAgH;AAChH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Y9B,CAAA","sourcesContent":["import { css } from 'lit'\n\n/** The modeller editor's own styles: the bar's tools, the panes, the start card, the side's tabs and panels. */\nexport const EditorStyles = css`\n :host {\n position: relative;\n display: flex;\n flex-direction: column;\n min-height: 0;\n height: 100%;\n /* The editor folds by the width it is given, not the window's (UX ruling, 2026-09-24). */\n container-type: inline-size;\n font: 13px sans-serif;\n color: var(--md-sys-color-on-surface);\n }\n /* The bar over the work is ox-canvas-bar (ADR-0060 decision 8): the folds at its edges, undo, redo and\n fit in the suite's places. What the editor puts in it - the mode switch, the status, save - is styled here. */\n ox-canvas-bar button[mode] {\n height: 28px;\n border: 1px solid transparent;\n padding: 0 10px;\n border-radius: 999em;\n border-color: transparent;\n background: none;\n }\n ox-canvas-bar button[mode][aria-pressed='true'] {\n border-color: var(--md-sys-color-primary);\n }\n /* The gizmo's tools, drawn as the bar's own icon buttons (undo, redo, fit). */\n ox-canvas-bar .gizmo-tools {\n display: inline-flex;\n gap: 2px;\n padding-left: 4px;\n border-left: 1px solid var(--md-sys-color-outline-variant);\n }\n ox-canvas-bar button[tool] {\n display: inline-grid;\n place-items: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: none;\n border-radius: var(--md-sys-shape-corner-small, 8px);\n background: transparent;\n color: var(--md-sys-color-on-surface-variant);\n cursor: pointer;\n }\n ox-canvas-bar button[tool]:hover:not(:disabled) {\n background: var(--md-sys-color-surface-container-high);\n color: var(--md-sys-color-on-surface);\n }\n ox-canvas-bar button[tool][aria-pressed='true'] {\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n ox-canvas-bar button[tool]:disabled {\n opacity: 0.38;\n cursor: default;\n }\n /*\n Slotted into the bar from here, the tools do not get the bar's own icon size (20px, set inside its shadow): they\n showed at md-icon's 24px, heavier than undo, redo and fit beside them. The same size, and the bar's focus ring.\n */\n ox-canvas-bar button[tool] md-icon {\n --md-icon-size: 20px;\n }\n ox-canvas-bar button[tool]:focus-visible {\n outline: 2px solid var(--md-sys-color-primary);\n outline-offset: 1px;\n }\n figure-preview {\n min-width: 0;\n min-height: 0;\n }\n /* The edit canvas stays standing while the preview is in front (a 3D scene costs a third of a second to make), out of sight. */\n div[middle][hidden] {\n display: none;\n }\n /* The preview, once made, stays standing out of sight too: its 3D scene is not made again each time it is asked for. */\n figure-preview[hidden] {\n display: none;\n }\n ox-canvas-bar .status {\n padding: 0 8px;\n color: var(--md-sys-color-on-surface-variant);\n }\n ox-canvas-bar .status[dirty] {\n color: var(--md-sys-color-primary);\n font-weight: 600;\n }\n ox-canvas-bar button[save] {\n height: 32px;\n padding: 0 14px;\n border: none;\n border-radius: 999em;\n color: var(--md-sys-color-on-primary);\n background: var(--md-sys-color-primary);\n }\n /* The three panes are ox-three-pane's (ADR-0060 decision 8): widths 200 | 1fr | 340, 160 | 300 under\n 860px and one column with the middle first under 560px are the frame's, as are the dividers. */\n ox-three-pane {\n flex: 1;\n min-height: 0;\n }\n figure-parts {\n min-height: 0;\n }\n figure-canvas {\n flex: 1;\n min-width: 0;\n min-height: 0;\n }\n div[middle] {\n position: relative;\n display: flex;\n min-width: 0;\n min-height: 0;\n }\n /* A new figure's first question, over the empty canvas. */\n div[start] {\n position: absolute;\n inset: 50% auto auto 50%;\n z-index: 10;\n color: var(--md-sys-color-on-surface);\n transform: translate(-50%, -50%);\n width: min(440px, calc(100% - 32px));\n box-sizing: border-box;\n padding: 20px;\n border-radius: 12px;\n background: var(--md-sys-color-surface, #fff);\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);\n }\n div[start] button[start-button] {\n width: auto;\n margin: 0;\n font-size: var(--ui-t-body);\n height: 36px;\n padding: 0 16px;\n border: 1px solid var(--md-sys-color-outline);\n border-radius: 999em;\n color: var(--md-sys-color-primary);\n background: var(--md-sys-color-surface, #fff);\n cursor: pointer;\n }\n div[start] button[start-button]:hover:not(:disabled) {\n background: var(--md-sys-color-primary-container);\n }\n div[start] button[start-button][pressed] {\n color: var(--md-sys-color-on-primary);\n background: var(--md-sys-color-primary);\n border-color: var(--md-sys-color-primary);\n }\n div[start] button[start-button]:disabled {\n opacity: 0.5;\n cursor: default;\n }\n div[start] h2 {\n margin: 0 0 12px;\n font-size: var(--ui-t-title);\n }\n div[start-paths] {\n display: grid;\n gap: 14px;\n }\n div[start-paths] h3 {\n margin: 0 0 6px;\n font-size: var(--ui-t-body);\n }\n div[start-shapes] {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n }\n div[start] small {\n display: block;\n margin-top: 4px;\n color: var(--md-sys-color-on-surface-variant);\n }\n /* The side: tabs over one panel at a time, each using the whole height. */\n aside {\n display: flex;\n flex-direction: column;\n min-height: 0;\n background: var(--md-sys-color-surface-container-lowest);\n }\n div[tabs] {\n display: flex;\n flex: none;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n button[tab] {\n flex: 1;\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 1px;\n min-width: 0;\n height: 48px;\n padding: 0;\n border: none;\n border-radius: 0;\n border-bottom: 2px solid transparent;\n background: none;\n color: var(--md-sys-color-on-surface-variant);\n }\n button[tab]:hover:not([on]) {\n background: var(--md-sys-color-surface-container);\n }\n button[tab][on] {\n color: var(--md-sys-color-primary);\n border-bottom-color: var(--md-sys-color-primary);\n }\n button[tab] md-icon {\n font-size: 20px;\n width: 20px;\n height: 20px;\n }\n button[tab] span[tab-label] {\n max-width: 100%;\n overflow: hidden;\n font-size: 0.66rem;\n line-height: 1.2;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n span[badge] {\n position: absolute;\n top: 3px;\n right: 2px;\n padding: 0 5px;\n font-size: 0.62rem;\n font-weight: 700;\n line-height: 1.5;\n color: var(--md-sys-color-on-primary-container);\n background: var(--md-sys-color-primary-container);\n border-radius: 999em;\n pointer-events: none;\n }\n /* The sections inside carry the margins (side-panel-styles); the panel only scrolls. */\n div[panel] {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 0;\n }\n div[panel][flush] {\n padding: 0;\n }\n /* Hidden, not removed: a panel keeps what it holds (the verdict its last answer) while another tab is open. */\n [off] {\n display: none !important;\n }\n /* The part's own numbers inside a group the links draw (size, place): one column, the panel's gap. */\n div[group-fields] {\n display: grid;\n gap: 8px;\n }\n /* A folded group (capability, 「더 보기」): its title is the fold's handle, at the title's size. */\n section[more] > details > summary,\n section[capability] > details > summary {\n padding: 0;\n }\n section[more] > details > summary > h3,\n section[capability] > details > summary > h3 {\n margin: 0;\n }\n div[more-body] {\n display: grid;\n gap: 16px;\n margin-top: 12px;\n }\n /*\n The view settings and the release history, opened from the bar over the right of the work: neither is about the\n part chosen, so neither takes a tab beside the part's (chief architect 2026-10-16).\n */\n :host {\n position: relative;\n }\n div[bar-overlay-panel] {\n position: absolute;\n top: var(--figure-bar-height, 44px);\n right: 8px;\n z-index: 5;\n display: flex;\n flex-direction: column;\n width: min(360px, calc(100% - 16px));\n max-height: calc(100% - var(--figure-bar-height, 44px) - 16px);\n background: var(--md-sys-color-surface-container-lowest);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px;\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.16);\n }\n div[overlay-head] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 8px 8px 12px;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n div[overlay-head] h3 {\n margin: 0;\n }\n div[overlay-head] button[quiet] {\n margin-left: 0;\n }\n div[overlay-body] {\n min-height: 0;\n overflow: auto;\n }\n /* Which part the panel speaks of. */\n div[subject] {\n position: sticky;\n top: 0;\n z-index: 1;\n display: grid;\n gap: 4px;\n padding: 10px 12px;\n background: var(--md-sys-color-surface-container-lowest);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n /* The panel's three sizes (side-panel-styles): the part's kind at the title's, its two lines at the hint's. */\n div[subject-summary] {\n display: grid;\n gap: 2px;\n }\n div[subject-summary] b {\n font-size: var(--ui-t-body, 13px);\n font-weight: 600;\n }\n div[subject-summary] b span {\n font-weight: 400;\n color: var(--md-sys-color-on-surface-variant);\n }\n div[subject-summary] small {\n color: var(--md-sys-color-on-surface-variant);\n }\n /*\n No rule here draws every button as a box: the side's buttons take the shared panel rules (SidePanelStyles), one\n height with the fields beside them, and only the bar's publish keeps an outline (user 2026-10-16: 「버튼 박스도\n 과하게 사용되어서」 -- a bare 「button」 rule had put a 32px box round every button the editor drew).\n */\n button {\n font: inherit;\n box-sizing: border-box;\n color: inherit;\n min-width: 0;\n cursor: pointer;\n }\n /* What blocks release, beside 「발행」: one red word button, and its list under the bar. */\n ox-canvas-bar button[release-blocked] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 32px;\n padding: 0 10px;\n border: none;\n border-radius: 6px;\n color: var(--md-sys-color-on-error-container);\n background: var(--md-sys-color-error-container);\n }\n ox-canvas-bar button[release-blocked] md-icon {\n --md-icon-size: 18px;\n }\n div[release-blockers] {\n position: absolute;\n top: 46px;\n right: 8px;\n z-index: 6;\n width: min(340px, calc(100% - 16px));\n padding: 8px 10px 10px;\n box-sizing: border-box;\n background: var(--md-sys-color-surface);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px;\n box-shadow: var(--md-sys-elevation-2, 0 2px 8px #0003);\n }\n ox-canvas-bar button[publish] {\n height: 32px;\n padding: 0 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n background: var(--md-sys-color-surface);\n }\n button:disabled {\n opacity: 0.45;\n cursor: default;\n }\n button[aria-pressed='true'] {\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n border-color: var(--md-sys-color-primary);\n }\n .hint {\n color: var(--md-sys-color-on-surface-variant);\n line-height: 1.5;\n }\n`\n"]}
|
|
@@ -16,6 +16,7 @@ import './figure-preview.js';
|
|
|
16
16
|
import './figure-settings.js';
|
|
17
17
|
import './figure-capability-panel.js';
|
|
18
18
|
import './figure-mesh-choice.js';
|
|
19
|
+
import type { FigureGateFinding } from '../types.js';
|
|
19
20
|
import type { FigureBudgetLine } from './maturity.js';
|
|
20
21
|
import type { FirstSave } from './first-save.js';
|
|
21
22
|
export declare class FigureEditor extends LitElement {
|
|
@@ -26,6 +27,12 @@ export declare class FigureEditor extends LitElement {
|
|
|
26
27
|
state?: 'draft' | 'released';
|
|
27
28
|
version: number;
|
|
28
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* What blocks release now, as the page's verdict heard it: said beside 「발행」 with the way out at hand, so an author
|
|
32
|
+
* does not find it at the foot of the verdict tab (first 15 minutes, 2026-10-16; chief architect, Q1 B).
|
|
33
|
+
*/
|
|
34
|
+
releaseBlockers: FigureGateFinding[];
|
|
35
|
+
private blockersOpen;
|
|
29
36
|
/** The recipe templates (ADR-0095), read by the page from the server. */
|
|
30
37
|
templates: RecipeTemplate[];
|
|
31
38
|
/** Reads a template's guide; given by the page. */
|
|
@@ -52,6 +59,14 @@ export declare class FigureEditor extends LitElement {
|
|
|
52
59
|
/** The same link offered again with the size range narrowed, after a link the declared range could not hold. */
|
|
53
60
|
private retry?;
|
|
54
61
|
private tab;
|
|
62
|
+
/** The view settings or the release history, open over the work from the bar. */
|
|
63
|
+
private overlay?;
|
|
64
|
+
/** The capability group open: the canvas marks the places only while their group is in sight. */
|
|
65
|
+
private capabilityOpen;
|
|
66
|
+
/** 「더 보기」 open, as this person left it last (chief architect 2026-10-16: kept per person). */
|
|
67
|
+
private moreOpen;
|
|
68
|
+
private static storedMoreOpen;
|
|
69
|
+
private setMoreOpen;
|
|
55
70
|
/** The frame the bar folds - found after the first render, since the bar is drawn before it. */
|
|
56
71
|
private panes?;
|
|
57
72
|
/** What the middle shows: the parts being edited, or the figure placed on a board at eight sizes. */
|
|
@@ -187,6 +202,30 @@ export declare class FigureEditor extends LitElement {
|
|
|
187
202
|
private renamePart;
|
|
188
203
|
/** Size response, fastening and motion for the selected part, as authoring commands. */
|
|
189
204
|
private renderLinks;
|
|
205
|
+
/**
|
|
206
|
+
* A part's groups in one order whatever its state (chief architect 2026-10-16): its size, its place, its row. The links
|
|
207
|
+
* draw the three groups and their rules; the part's own numbers go into them by slot. A fastened part's place and turn
|
|
208
|
+
* are its fastening's: the place group says it in one line and the locked cells are not drawn (user 2026-10-16).
|
|
209
|
+
*/
|
|
210
|
+
private renderPartGroups;
|
|
211
|
+
/**
|
|
212
|
+
* What the figure does -- its places (ADR-0118) -- as a group of the properties, folded: a declaration made once,
|
|
213
|
+
* whose marks on the canvas show while it is open. A verdict that finds it empty still says where it is.
|
|
214
|
+
*/
|
|
215
|
+
private renderCapability;
|
|
216
|
+
/**
|
|
217
|
+
* 「더 보기」: what few parts need, folded by default and left as this person last left it (chief architect
|
|
218
|
+
* 2026-10-16) -- the section, its corners and inside; transparency, glow and segments; the mirrored copy and the
|
|
219
|
+
* alignment tools.
|
|
220
|
+
*/
|
|
221
|
+
private renderMore;
|
|
222
|
+
/** A bar button that opens the view settings or the release history over the work; pressed while it is open. */
|
|
223
|
+
private renderOverlayButton;
|
|
224
|
+
/**
|
|
225
|
+
* The view settings or the release history, over the work under the bar. Both stay drawn, hidden when closed: the
|
|
226
|
+
* history keeps what it read, as the tabs kept it. Esc closes it.
|
|
227
|
+
*/
|
|
228
|
+
private renderOverlay;
|
|
190
229
|
/**
|
|
191
230
|
* The face a size drag keeps for the selected part, figure-model's rule (`figureScaleAnchorOf`): the gizmo shows it
|
|
192
231
|
* while dragging and the commit keeps it, so nothing jumps on release. A part whose fastening is turned has none the
|
|
@@ -248,7 +287,9 @@ export declare class FigureEditor extends LitElement {
|
|
|
248
287
|
private setPitch;
|
|
249
288
|
/** Choose a part, from the list, the canvas or a place row. A figure-level tab gives way to the part's properties. */
|
|
250
289
|
private releaseWords;
|
|
251
|
-
/**
|
|
290
|
+
/** The findings that block release, under the bar beside 「발행」, each with the way out the verdict tab offers for it. */
|
|
291
|
+
private renderReleaseBlockers;
|
|
292
|
+
/** To the release that exists: the history's release section, opened from the bar, not a second one here. */
|
|
252
293
|
private goRelease;
|
|
253
294
|
private overhangOf;
|
|
254
295
|
/** The selected part's motion at both ends of its range, made once per version and part. */
|
|
@@ -46,7 +46,8 @@ const NO_MARKS = [];
|
|
|
46
46
|
import { apexOver, drawnOf } from './section-drawing.js';
|
|
47
47
|
import { END_FACE } from './section-controls.js';
|
|
48
48
|
import { nudgeOf, placementOf } from './stage-model.js';
|
|
49
|
-
import { roomRefitRowsOf } from './occupancy.js';
|
|
49
|
+
import { occupancyFromParts, roomRefitRowsOf } from './occupancy.js';
|
|
50
|
+
import { gateFindingStyles, renderGateFinding } from './gate-findings.js';
|
|
50
51
|
import { editRefusalOf, inDeclaredRoom, narrowingRetryOf, partNameRefusalOf, partRefusalOf, placedRefusalOf, recipeRefusalOf, removalNoticeOf } from './refusals.js';
|
|
51
52
|
import { endPlaceKeyOf, fieldWordsOf, followOf, measureNow, partSummaryOf, instanceRangeOf, instanceRangeToDeclare, proportionToFollow, rangeDiffers, rangeWith, turnsAboutAJoint, valueNow } from './links.js';
|
|
52
53
|
import { jointFanOf } from './joint-fan.js';
|
|
@@ -54,11 +55,20 @@ import { derivedOf } from './revision.js';
|
|
|
54
55
|
import { jointDragOf } from './joint-drag.js';
|
|
55
56
|
import { liveOverSession, NOTHING_LIVE, scrubbed, scrubStep } from './live.js';
|
|
56
57
|
import { startingShapeKindOfBody } from './starting-shape.js';
|
|
58
|
+
import { groupMenu, GroupMenuStyles } from './group-menu.js';
|
|
59
|
+
/** The person's own fold of the properties' 「더 보기」, kept in their browser. */
|
|
60
|
+
const MORE_OPEN_KEY = 'figure-properties-more-open';
|
|
57
61
|
/** Product editor surface. The injected session is shared by page persistence and AI commands. */
|
|
58
62
|
const NO_OVERHANG = { words: NO_WORDS, note: NO_WORDS };
|
|
59
63
|
let FigureEditor = class FigureEditor extends LitElement {
|
|
60
64
|
constructor() {
|
|
61
65
|
super(...arguments);
|
|
66
|
+
/**
|
|
67
|
+
* What blocks release now, as the page's verdict heard it: said beside 「발행」 with the way out at hand, so an author
|
|
68
|
+
* does not find it at the foot of the verdict tab (first 15 minutes, 2026-10-16; chief architect, Q1 B).
|
|
69
|
+
*/
|
|
70
|
+
this.releaseBlockers = [];
|
|
71
|
+
this.blockersOpen = false;
|
|
62
72
|
/** The recipe templates (ADR-0095), read by the page from the server. */
|
|
63
73
|
this.templates = [];
|
|
64
74
|
this.catalogOpen = false;
|
|
@@ -68,6 +78,10 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
68
78
|
this.selected = '';
|
|
69
79
|
this.error = '';
|
|
70
80
|
this.tab = 'properties';
|
|
81
|
+
/** The capability group open: the canvas marks the places only while their group is in sight. */
|
|
82
|
+
this.capabilityOpen = false;
|
|
83
|
+
/** 「더 보기」 open, as this person left it last (chief architect 2026-10-16: kept per person). */
|
|
84
|
+
this.moreOpen = FigureEditor_1.storedMoreOpen();
|
|
71
85
|
/** What the middle shows: the parts being edited, or the figure placed on a board at eight sizes. */
|
|
72
86
|
this.middle = 'edit';
|
|
73
87
|
/** A line saying what a command did besides what was asked; gone at the next command. */
|
|
@@ -124,16 +138,35 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
124
138
|
this.lastAnchors = {};
|
|
125
139
|
/** Data tried in the data tab, given to the preview's figures as their `data`; null when none is (ADR-0051 §8). */
|
|
126
140
|
this.dataSample = null;
|
|
127
|
-
/** To the release that exists: the history
|
|
141
|
+
/** To the release that exists: the history's release section, opened from the bar, not a second one here. */
|
|
128
142
|
this.goRelease = async () => {
|
|
129
|
-
this.
|
|
143
|
+
this.overlay = 'history';
|
|
130
144
|
await this.updateComplete;
|
|
131
145
|
await this.querySelector('figure-history-panel')?.showRelease?.();
|
|
132
146
|
};
|
|
133
147
|
}
|
|
134
148
|
static { FigureEditor_1 = this; }
|
|
135
149
|
/* The operato scrollbar, as every scrolling panel of the app has it -- the side panel scrolled with the browser's own. */
|
|
136
|
-
static { this.styles = [ScrollbarStyles, SidePanelStyles, EditorStyles]; }
|
|
150
|
+
static { this.styles = [ScrollbarStyles, SidePanelStyles, gateFindingStyles, GroupMenuStyles, EditorStyles]; }
|
|
151
|
+
static storedMoreOpen() {
|
|
152
|
+
try {
|
|
153
|
+
return localStorage.getItem(MORE_OPEN_KEY) === '1';
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
setMoreOpen(open) {
|
|
160
|
+
if (open === this.moreOpen)
|
|
161
|
+
return;
|
|
162
|
+
this.moreOpen = open;
|
|
163
|
+
try {
|
|
164
|
+
localStorage.setItem(MORE_OPEN_KEY, open ? '1' : '0');
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
/* A browser that keeps nothing folds it again next time. */
|
|
168
|
+
}
|
|
169
|
+
}
|
|
137
170
|
static storedView() {
|
|
138
171
|
try {
|
|
139
172
|
const stored = JSON.parse(localStorage.getItem('figure-view') ?? 'null');
|
|
@@ -720,7 +753,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
720
753
|
}
|
|
721
754
|
}
|
|
722
755
|
/** Size response, fastening and motion for the selected part, as authoring commands. */
|
|
723
|
-
renderLinks(unavailable, section) {
|
|
756
|
+
renderLinks(unavailable, section, slotted = nothing) {
|
|
724
757
|
const shown = this.shown();
|
|
725
758
|
if (!shown)
|
|
726
759
|
return null;
|
|
@@ -738,7 +771,122 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
738
771
|
@go-fasten=${() => this.goFasten()}
|
|
739
772
|
@preview-command=${(e) => this.commandPreview.ask(e.detail)}
|
|
740
773
|
@part-edit=${(e) => this.run(() => this.session.edit(e.detail.edit))}
|
|
741
|
-
|
|
774
|
+
>${slotted}</figure-links>`;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* A part's groups in one order whatever its state (chief architect 2026-10-16): its size, its place, its row. The links
|
|
778
|
+
* draw the three groups and their rules; the part's own numbers go into them by slot. A fastened part's place and turn
|
|
779
|
+
* are its fastening's: the place group says it in one line and the locked cells are not drawn (user 2026-10-16).
|
|
780
|
+
*/
|
|
781
|
+
renderPartGroups(shown, geometry, fields, unavailable, held) {
|
|
782
|
+
const groups = this.withSizeRow(groupFields(fields, this.selected), held);
|
|
783
|
+
const size = groups.vectors.filter(g => g.kind === 'vector' && g.name === 'size');
|
|
784
|
+
const place = groups.vectors.filter(g => g.kind === 'vector' && g.name !== 'size');
|
|
785
|
+
const fastened = !!this.asset()?.joints?.some(j => j.body1.part === ownerOf(this.selected));
|
|
786
|
+
const placeLocked = fastened && place.every(g => g.kind === 'vector' && ['x', 'y', 'z'].every(axis => !g.cells[axis]));
|
|
787
|
+
return this.renderLinks(unavailable, 'shape', html `${size.length || groups.singles.length
|
|
788
|
+
? html `<div slot="size" group-fields>
|
|
789
|
+
${size.map(g => this.renderVector(g, unavailable, held))}
|
|
790
|
+
${groups.singles.length
|
|
791
|
+
? html `<div form>${groups.singles.map(g => (g.kind === 'single' ? this.renderSingle(g.name, g.field, unavailable) : nothing))}</div>`
|
|
792
|
+
: nothing}
|
|
793
|
+
</div>`
|
|
794
|
+
: nothing}
|
|
795
|
+
${place.length && !placeLocked
|
|
796
|
+
? html `<div slot="place" group-fields>${place.map(g => this.renderVector(g, unavailable, held))}${this.renderHeldAxes(place)}</div>`
|
|
797
|
+
: nothing}
|
|
798
|
+
${this.renderRepeat(shown, geometry, unavailable)}`);
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* What the figure does -- its places (ADR-0118) -- as a group of the properties, folded: a declaration made once,
|
|
802
|
+
* whose marks on the canvas show while it is open. A verdict that finds it empty still says where it is.
|
|
803
|
+
*/
|
|
804
|
+
renderCapability(asset, unavailable) {
|
|
805
|
+
return html `<section capability>
|
|
806
|
+
<details capability-fold ?open=${this.capabilityOpen} @toggle=${(e) => (this.capabilityOpen = e.target.open)}>
|
|
807
|
+
<summary><h3>${i18next.t('figure.label.tab-capability')}</h3></summary>
|
|
808
|
+
${this.selected ? this.renderLinks(unavailable, 'places') : nothing}
|
|
809
|
+
<figure-capability-panel
|
|
810
|
+
.asset=${asset}
|
|
811
|
+
.selected=${this.selected}
|
|
812
|
+
?locked=${unavailable}
|
|
813
|
+
@select-part=${(e) => this.choose(e.detail.id)}
|
|
814
|
+
@part-edit=${(e) => this.run(() => this.session.edit(e.detail.edit))}
|
|
815
|
+
></figure-capability-panel>
|
|
816
|
+
</details>
|
|
817
|
+
</section>`;
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* 「더 보기」: what few parts need, folded by default and left as this person last left it (chief architect
|
|
821
|
+
* 2026-10-16) -- the section, its corners and inside; transparency, glow and segments; the mirrored copy and the
|
|
822
|
+
* alignment tools.
|
|
823
|
+
*/
|
|
824
|
+
renderMore(part, palette, unavailable) {
|
|
825
|
+
const tools = this.renderTools(unavailable);
|
|
826
|
+
return html `<section more>
|
|
827
|
+
<details more-fold ?open=${this.moreOpen} @toggle=${(e) => this.setMoreOpen(e.target.open)}>
|
|
828
|
+
<summary><h3>${i18next.t('figure.label.group-more')}</h3></summary>
|
|
829
|
+
<div more-body>
|
|
830
|
+
${tools ? html `<div group-fields>${tools}</div>` : nothing}
|
|
831
|
+
<figure-section-panel
|
|
832
|
+
embedded
|
|
833
|
+
.body=${{ ...part, id: this.selected }}
|
|
834
|
+
?locked=${unavailable}
|
|
835
|
+
.faceMapping=${this.faceMapping?.from === 'panel' ? this.faceMapping.need : undefined}
|
|
836
|
+
@face-mapped=${(e) => this.mapFaces(e.detail.remap)}
|
|
837
|
+
@face-mapping-cancel=${() => (this.faceMapping = undefined)}
|
|
838
|
+
@command=${(e) => this.linkCommand(e.detail.action)}
|
|
839
|
+
@command-live=${(e) => this.holdAction(e.detail.action)}
|
|
840
|
+
@section-editor-open=${() => (this.sectionEditing = this.selected)}
|
|
841
|
+
></figure-section-panel>
|
|
842
|
+
<figure-material-panel
|
|
843
|
+
show="more"
|
|
844
|
+
.body=${{ ...part, id: this.selected }}
|
|
845
|
+
.palette=${palette}
|
|
846
|
+
?locked=${unavailable}
|
|
847
|
+
@part-edit=${(e) => this.run(() => this.session.edit(e.detail.edit))}
|
|
848
|
+
@part-live=${(e) => this.hold({}, e.detail.edit)}
|
|
849
|
+
></figure-material-panel>
|
|
850
|
+
</div>
|
|
851
|
+
</details>
|
|
852
|
+
</section>`;
|
|
853
|
+
}
|
|
854
|
+
/** A bar button that opens the view settings or the release history over the work; pressed while it is open. */
|
|
855
|
+
renderOverlayButton(which, icon, label, slot) {
|
|
856
|
+
const open = this.overlay === which;
|
|
857
|
+
return html `<button
|
|
858
|
+
slot=${slot ?? nothing}
|
|
859
|
+
tool
|
|
860
|
+
bar-overlay=${which}
|
|
861
|
+
aria-pressed=${String(open)}
|
|
862
|
+
aria-label=${i18next.t(label)}
|
|
863
|
+
title=${i18next.t(label)}
|
|
864
|
+
@click=${() => (this.overlay = open ? undefined : which)}
|
|
865
|
+
>
|
|
866
|
+
<md-icon>${icon}</md-icon>
|
|
867
|
+
</button>`;
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* The view settings or the release history, over the work under the bar. Both stay drawn, hidden when closed: the
|
|
871
|
+
* history keeps what it read, as the tabs kept it. Esc closes it.
|
|
872
|
+
*/
|
|
873
|
+
renderOverlay() {
|
|
874
|
+
const close = () => (this.overlay = undefined);
|
|
875
|
+
const panel = (which, label, body) => html `<div
|
|
876
|
+
bar-overlay-panel=${which}
|
|
877
|
+
role="dialog"
|
|
878
|
+
aria-label=${i18next.t(label)}
|
|
879
|
+
?off=${this.overlay !== which}
|
|
880
|
+
@keydown=${(e) => e.key === 'Escape' && (e.stopPropagation(), close())}
|
|
881
|
+
>
|
|
882
|
+
<div overlay-head>
|
|
883
|
+
<h3>${i18next.t(label)}</h3>
|
|
884
|
+
<button quiet aria-label=${i18next.t('figure.button.close')} title=${i18next.t('figure.button.close')} @click=${close}><md-icon>close</md-icon></button>
|
|
885
|
+
</div>
|
|
886
|
+
<div overlay-body>${body}</div>
|
|
887
|
+
</div>`;
|
|
888
|
+
return html `${panel('view', 'figure.label.tab-environment', html `<figure-settings .view=${this.view} @update-view=${(e) => this.setView(e.detail.view)}></figure-settings>`)}
|
|
889
|
+
${panel('history', 'figure.label.history', html `<slot name="history"></slot>`)}`;
|
|
742
890
|
}
|
|
743
891
|
/**
|
|
744
892
|
* The face a size drag keeps for the selected part, figure-model's rule (`figureScaleAnchorOf`): the gizmo shows it
|
|
@@ -800,6 +948,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
800
948
|
this.retry = undefined;
|
|
801
949
|
this.notice = '';
|
|
802
950
|
const hadSize = this.hasSize();
|
|
951
|
+
const hadSpace = !!this.shown()?.asset.occupancy;
|
|
803
952
|
try {
|
|
804
953
|
this.session.command(action);
|
|
805
954
|
this.error = '';
|
|
@@ -807,7 +956,9 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
807
956
|
/* What the command did besides what was asked, in one line: the figure's size declared to follow (ADR ruling Q1). */
|
|
808
957
|
if (action.kind === 'follow-size' && !hadSize) {
|
|
809
958
|
const size = this.designValues();
|
|
810
|
-
|
|
959
|
+
/* The same step may have fitted the space the figure takes to its parts (figure-model, ruling 2026-10-16 Q1 A): one line says both. */
|
|
960
|
+
const spaceToo = !hadSpace && !!this.shown()?.asset.occupancy;
|
|
961
|
+
this.notice = i18next.t(spaceToo ? 'figure.text.size-and-space-declared-to-follow' : 'figure.text.size-declared-to-follow', {
|
|
811
962
|
x: Math.round(size['size.x'] ?? 0).toLocaleString(),
|
|
812
963
|
y: Math.round(size['size.y'] ?? 0).toLocaleString(),
|
|
813
964
|
z: Math.round(size['size.z'] ?? 0).toLocaleString()
|
|
@@ -1057,8 +1208,12 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1057
1208
|
const longest = model.inputs.find(i => i.id === lengthRef)?.max;
|
|
1058
1209
|
const limit = model.constants.find(c => c.id === layout?.args[6])?.value;
|
|
1059
1210
|
const field = { id: own, unit: 'mm', role: 'design', value: pitch ?? 0 };
|
|
1060
|
-
|
|
1061
|
-
|
|
1211
|
+
const removable = !!asset.joints?.some(j => j.body1.part === this.selected && j.repeat);
|
|
1212
|
+
return html `<section slot="row" row>
|
|
1213
|
+
<h3>
|
|
1214
|
+
${i18next.t('figure.label.repeat')}
|
|
1215
|
+
${groupMenu([{ label: i18next.t('figure.button.remove-repeat'), icon: 'close', disabled: unavailable || !removable, run: () => this.run(() => this.session.command({ kind: 'remove-repeat', part: this.selected })) }])}
|
|
1216
|
+
</h3>
|
|
1062
1217
|
<div inline-field><label>${i18next.t('figure.label.repeat-axis')}</label><span value>${axis.toUpperCase()}</span></div>
|
|
1063
1218
|
<div inline-field><label>${i18next.t('figure.label.repeat-count')}</label><span value>${repeat.count}</span></div>
|
|
1064
1219
|
<div inline-field>
|
|
@@ -1084,11 +1239,6 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1084
1239
|
: i18next.t(fits ? 'figure.text.repeat-fits-length' : 'figure.text.repeat-fixed-count')}
|
|
1085
1240
|
</p>
|
|
1086
1241
|
${this.renderPublicPitch(asset, pitch ?? 0, unavailable)}
|
|
1087
|
-
${asset.joints?.some(j => j.body1.part === this.selected && j.repeat)
|
|
1088
|
-
? html `<button act ?disabled=${unavailable} @click=${() => this.run(() => this.session.command({ kind: 'remove-repeat', part: this.selected }))}>
|
|
1089
|
-
<md-icon>close</md-icon>${i18next.t('figure.button.remove-repeat')}
|
|
1090
|
-
</button>`
|
|
1091
|
-
: nothing}
|
|
1092
1242
|
</section>`;
|
|
1093
1243
|
}
|
|
1094
1244
|
/** The selected row as it is drawn now, read by figure-model: nothing when it cannot be read. */
|
|
@@ -1218,6 +1368,21 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1218
1368
|
return i18next.t('figure.text.release-state-released', { version: String(version) });
|
|
1219
1369
|
return version > 0 ? i18next.t('figure.text.release-state-draft-over', { version: String(version) }) : i18next.t('figure.text.release-state-draft-new');
|
|
1220
1370
|
}
|
|
1371
|
+
/** The findings that block release, under the bar beside 「발행」, each with the way out the verdict tab offers for it. */
|
|
1372
|
+
renderReleaseBlockers(asset, unavailable) {
|
|
1373
|
+
const parts = (asset?.appearance ?? []).map(look => look.target);
|
|
1374
|
+
const way = (code) => (code === 'occupancy-undeclared' || code === 'part-outside-occupancy') && asset && parts.length
|
|
1375
|
+
? html `<button act ?disabled=${unavailable} @click=${() => this.linkCommand(occupancyFromParts(asset))}>
|
|
1376
|
+
<md-icon>fit_screen</md-icon>${i18next.t('figure.button.fit-base-to-parts')}
|
|
1377
|
+
</button>`
|
|
1378
|
+
: nothing;
|
|
1379
|
+
return html `<div release-blockers role="dialog" aria-label=${i18next.t('figure.text.must-fix-to-release')} @keydown=${(e) => e.key === 'Escape' && (this.blockersOpen = false)}>
|
|
1380
|
+
<ul gate>
|
|
1381
|
+
<li head>${i18next.t('figure.text.must-fix-to-release')}</li>
|
|
1382
|
+
${this.releaseBlockers.map(finding => renderGateFinding(finding, true, way(finding.code), parts))}
|
|
1383
|
+
</ul>
|
|
1384
|
+
</div>`;
|
|
1385
|
+
}
|
|
1221
1386
|
/*
|
|
1222
1387
|
Past the edge of the face a part is fastened to (ADR-0097 §5.5, Q3): the selected part's own, and the parts fastened
|
|
1223
1388
|
to it -- said apart from the room, nothing moved. Read once per version, part and language. The note says it is wider
|
|
@@ -1313,7 +1478,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1313
1478
|
/* A copy on the canvas selects its repeat: the part the author made. */
|
|
1314
1479
|
this.selected = id ? ownerOf(id) : id;
|
|
1315
1480
|
this.faceMapping = undefined;
|
|
1316
|
-
if (id &&
|
|
1481
|
+
if (id && this.tab === 'verdict')
|
|
1317
1482
|
this.tab = 'properties';
|
|
1318
1483
|
}
|
|
1319
1484
|
asset() {
|
|
@@ -1329,6 +1494,9 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1329
1494
|
}
|
|
1330
1495
|
updated(changed) {
|
|
1331
1496
|
super.updated?.(changed);
|
|
1497
|
+
/* Nothing blocks release any more: the list under the bar closes, and opens fresh when something does again. */
|
|
1498
|
+
if (changed.has('releaseBlockers') && !this.releaseBlockers.length && this.blockersOpen)
|
|
1499
|
+
this.blockersOpen = false;
|
|
1332
1500
|
this.refusals.tell(changed);
|
|
1333
1501
|
this.panelMemory.restore(() => this.selected);
|
|
1334
1502
|
const panes = this.renderRoot.querySelector('ox-three-pane') ?? undefined;
|
|
@@ -1408,7 +1576,6 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1408
1576
|
${i18next.t(`figure.label.resize-place-${one}`)}
|
|
1409
1577
|
</button>`)}
|
|
1410
1578
|
</div>
|
|
1411
|
-
<small>${i18next.t('figure.text.placement-is-intent')}</small>
|
|
1412
1579
|
</section>
|
|
1413
1580
|
<section>
|
|
1414
1581
|
<h3>${i18next.t('figure.label.start-shape')}</h3>
|
|
@@ -1527,14 +1694,22 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1527
1694
|
@canvas-fit=${() => this.renderRoot.querySelector('figure-canvas')?.fit()}
|
|
1528
1695
|
>
|
|
1529
1696
|
${this.renderGizmoTools(!unavailable && this.middle === 'edit')}
|
|
1697
|
+
${this.renderOverlayButton('view', 'wb_sunny', 'figure.label.tab-environment')}
|
|
1530
1698
|
${['edit', 'preview'].map(mode => html `<button slot="mode" mode aria-pressed=${String(this.middle === mode)} title=${i18next.t('figure.text.mode-' + mode + '-explained')} @click=${() => (this.middle = mode)}>
|
|
1531
1699
|
${i18next.t('figure.label.mode-' + mode)}
|
|
1532
1700
|
</button>`)}
|
|
1533
1701
|
<span slot="status" class="status" role="status" ?dirty=${status === 'figure.text.unsaved-changes'}>${i18next.t(status)}</span>
|
|
1534
1702
|
<span slot="status" release-state>${this.releaseWords(view)}</span>
|
|
1703
|
+
${this.renderOverlayButton('history', 'history', 'figure.label.history', 'commit')}
|
|
1704
|
+
${this.releaseBlockers.length
|
|
1705
|
+
? html `<button slot="commit" release-blocked aria-expanded=${String(this.blockersOpen)} @click=${() => (this.blockersOpen = !this.blockersOpen)}>
|
|
1706
|
+
<md-icon>error</md-icon>${i18next.t('figure.button.release-blocked', { count: this.releaseBlockers.length })}
|
|
1707
|
+
</button>`
|
|
1708
|
+
: nothing}
|
|
1535
1709
|
<button slot="commit" publish ?disabled=${!view.id} title=${view.id ? '' : i18next.t('figure.text.save-the-figure-before-releasing')} @click=${this.goRelease}>${i18next.t('figure.button.release')}</button>
|
|
1536
1710
|
<button slot="commit" save ?disabled=${unavailable || (!view.dirty && !!view.id)} @click=${this.save}>${i18next.t('figure.button.save')}</button>
|
|
1537
1711
|
</ox-canvas-bar>
|
|
1712
|
+
${this.blockersOpen && this.releaseBlockers.length ? this.renderReleaseBlockers(asset, unavailable) : nothing}
|
|
1538
1713
|
${this.catalogOpen
|
|
1539
1714
|
? html `<figure-recipe-catalog
|
|
1540
1715
|
.templates=${this.templates}
|
|
@@ -1600,7 +1775,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1600
1775
|
.fan=${this.fanOf(shown, live)}
|
|
1601
1776
|
.ghost=${this.previewShown().ghost}
|
|
1602
1777
|
.highlight=${this.previewShown().highlight}
|
|
1603
|
-
.marks=${this.tab === '
|
|
1778
|
+
.marks=${this.tab === 'properties' && this.capabilityOpen ? this.slotMarks(view, asset) : NO_MARKS}
|
|
1604
1779
|
.palette=${view.palette ?? {}}
|
|
1605
1780
|
.context=${view.context ?? ''}
|
|
1606
1781
|
.selected=${this.selected}
|
|
@@ -1614,12 +1789,9 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1614
1789
|
<aside slot="end">
|
|
1615
1790
|
<div tabs>
|
|
1616
1791
|
${this.renderTab('properties', 'tune', i18next.t('figure.label.properties'))}
|
|
1617
|
-
${this.renderTab('capability', 'conveyor_belt', i18next.t('figure.label.tab-capability'))}
|
|
1618
1792
|
${this.renderTab('motion', 'animation', i18next.t('figure.label.motion'))}
|
|
1619
1793
|
${this.renderTab('data', 'sensors', i18next.t('figure.label.tab-data'))}
|
|
1620
1794
|
${this.renderTab('verdict', 'insights', i18next.t('figure.label.maturity'), this.instances)}
|
|
1621
|
-
${this.renderTab('view', 'wb_sunny', i18next.t('figure.label.tab-environment'))}
|
|
1622
|
-
${this.renderTab('history', 'history', i18next.t('figure.label.history'))}
|
|
1623
1795
|
</div>
|
|
1624
1796
|
<slot name="notice"></slot>
|
|
1625
1797
|
<div panel ?off=${tab !== 'properties'}>
|
|
@@ -1639,27 +1811,17 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1639
1811
|
</div>
|
|
1640
1812
|
${this.renderRepeatNote(view.geometry)}
|
|
1641
1813
|
</section>
|
|
1642
|
-
${this.
|
|
1643
|
-
${this.renderGroups(this.withSizeRow(groupFields(partFields, this.selected), held), 'figure.label.group-placement-size', 'figure.label.group-shape', unavailable, this.renderTools(unavailable), held)}
|
|
1814
|
+
${this.renderPartGroups(shown, view.geometry, partFields, unavailable, held)}
|
|
1644
1815
|
${roomFields.length ? this.renderRoomOnly(roomFields, unavailable) : nothing}
|
|
1645
|
-
${this.renderLinks(unavailable, 'shape')}
|
|
1646
|
-
<figure-section-panel
|
|
1647
|
-
.body=${{ ...part, id: this.selected }}
|
|
1648
|
-
?locked=${unavailable}
|
|
1649
|
-
.faceMapping=${this.faceMapping?.from === 'panel' ? this.faceMapping.need : undefined}
|
|
1650
|
-
@face-mapped=${(e) => this.mapFaces(e.detail.remap)}
|
|
1651
|
-
@face-mapping-cancel=${() => (this.faceMapping = undefined)}
|
|
1652
|
-
@command=${(e) => this.linkCommand(e.detail.action)}
|
|
1653
|
-
@command-live=${(e) => this.holdAction(e.detail.action)}
|
|
1654
|
-
@section-editor-open=${() => (this.sectionEditing = this.selected)}
|
|
1655
|
-
></figure-section-panel>
|
|
1656
1816
|
<figure-material-panel
|
|
1657
1817
|
.body=${{ ...part, id: this.selected }}
|
|
1658
1818
|
.palette=${view.palette ?? {}}
|
|
1659
1819
|
?locked=${unavailable}
|
|
1660
1820
|
@part-edit=${(e) => this.run(() => this.session.edit(e.detail.edit))}
|
|
1661
1821
|
@part-live=${(e) => this.hold({}, e.detail.edit)}
|
|
1662
|
-
></figure-material-panel
|
|
1822
|
+
></figure-material-panel>
|
|
1823
|
+
${this.renderCapability(asset, unavailable)}
|
|
1824
|
+
${this.renderMore(part, view.palette ?? {}, unavailable)}`
|
|
1663
1825
|
: view.geometry.length === 0
|
|
1664
1826
|
? html `${this.renderSubject()}<section empty-figure>
|
|
1665
1827
|
<p>${i18next.t('figure.text.empty-figure-next')}</p>
|
|
@@ -1670,18 +1832,8 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1670
1832
|
</section>`
|
|
1671
1833
|
: html `${this.renderSubject()}<slot name="figure"></slot>
|
|
1672
1834
|
${this.renderGroups(groupFields(common), 'figure.label.group-figure-size', 'figure.label.design-inputs', unavailable)}
|
|
1673
|
-
${this.renderInstanceRange(shown, unavailable)}
|
|
1674
|
-
|
|
1675
|
-
<div panel ?off=${tab !== 'capability'}>
|
|
1676
|
-
${this.renderSubject()}
|
|
1677
|
-
${this.selected && part ? this.renderLinks(unavailable, 'places') : null}
|
|
1678
|
-
<figure-capability-panel
|
|
1679
|
-
.asset=${asset}
|
|
1680
|
-
.selected=${this.selected}
|
|
1681
|
-
?locked=${unavailable}
|
|
1682
|
-
@select-part=${(e) => this.choose(e.detail.id)}
|
|
1683
|
-
@part-edit=${(e) => this.run(() => this.session.edit(e.detail.edit))}
|
|
1684
|
-
></figure-capability-panel>
|
|
1835
|
+
${this.renderInstanceRange(shown, unavailable)}
|
|
1836
|
+
${this.renderCapability(asset, unavailable)}`}
|
|
1685
1837
|
</div>
|
|
1686
1838
|
<div panel ?off=${tab !== 'motion'}>
|
|
1687
1839
|
${this.renderSubject()}
|
|
@@ -1699,12 +1851,9 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1699
1851
|
></figure-data-panel>
|
|
1700
1852
|
</div>
|
|
1701
1853
|
<div panel flush ?off=${tab !== 'verdict'}><slot name="verdict"></slot></div>
|
|
1702
|
-
<div panel flush ?off=${tab !== 'view'}>
|
|
1703
|
-
<figure-settings .view=${this.view} @update-view=${(e) => this.setView(e.detail.view)}></figure-settings>
|
|
1704
|
-
</div>
|
|
1705
|
-
<div panel flush ?off=${tab !== 'history'}><slot name="history"></slot></div>
|
|
1706
1854
|
</aside>
|
|
1707
|
-
</ox-three-pane
|
|
1855
|
+
</ox-three-pane>
|
|
1856
|
+
${this.renderOverlay()}`;
|
|
1708
1857
|
}
|
|
1709
1858
|
/** Position, rotation and size as rows of three cells; the shape's own measures one to a line, under their title. */
|
|
1710
1859
|
renderGroups(groups, vectorTitle, singleTitle, unavailable, tools = null, held) {
|
|
@@ -1859,6 +2008,14 @@ __decorate([
|
|
|
1859
2008
|
property({ attribute: false }),
|
|
1860
2009
|
__metadata("design:type", Object)
|
|
1861
2010
|
], FigureEditor.prototype, "releaseState", void 0);
|
|
2011
|
+
__decorate([
|
|
2012
|
+
property({ attribute: false }),
|
|
2013
|
+
__metadata("design:type", Array)
|
|
2014
|
+
], FigureEditor.prototype, "releaseBlockers", void 0);
|
|
2015
|
+
__decorate([
|
|
2016
|
+
state(),
|
|
2017
|
+
__metadata("design:type", Object)
|
|
2018
|
+
], FigureEditor.prototype, "blockersOpen", void 0);
|
|
1862
2019
|
__decorate([
|
|
1863
2020
|
property({ attribute: false }),
|
|
1864
2021
|
__metadata("design:type", Array)
|
|
@@ -1919,6 +2076,18 @@ __decorate([
|
|
|
1919
2076
|
state(),
|
|
1920
2077
|
__metadata("design:type", String)
|
|
1921
2078
|
], FigureEditor.prototype, "tab", void 0);
|
|
2079
|
+
__decorate([
|
|
2080
|
+
state(),
|
|
2081
|
+
__metadata("design:type", String)
|
|
2082
|
+
], FigureEditor.prototype, "overlay", void 0);
|
|
2083
|
+
__decorate([
|
|
2084
|
+
state(),
|
|
2085
|
+
__metadata("design:type", Object)
|
|
2086
|
+
], FigureEditor.prototype, "capabilityOpen", void 0);
|
|
2087
|
+
__decorate([
|
|
2088
|
+
state(),
|
|
2089
|
+
__metadata("design:type", Object)
|
|
2090
|
+
], FigureEditor.prototype, "moreOpen", void 0);
|
|
1922
2091
|
__decorate([
|
|
1923
2092
|
state(),
|
|
1924
2093
|
__metadata("design:type", Function)
|