@things-factory/figure-ui 10.1.74 → 10.1.76
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/figure-assistant.ts +3 -3
- package/client/graphql/{v3-store.ts → store.ts} +6 -6
- package/client/modeller/{v3-ai-proposal.ts → ai-proposal.ts} +8 -8
- package/client/modeller/{v3-align.ts → align.ts} +14 -14
- package/client/modeller/{v3-canvas.ts → canvas.ts} +13 -13
- package/client/modeller/{v3-clips.ts → clips.ts} +5 -5
- package/client/modeller/{v3-controls.ts → controls.ts} +2 -2
- package/client/modeller/{v3-editor.ts → editor.ts} +137 -126
- package/client/modeller/{figure-v3-capability.ts → figure-capability-panel.ts} +7 -7
- package/client/modeller/{figure-v3-clips.ts → figure-clips.ts} +10 -10
- package/client/modeller/{figure-v3-controls.ts → figure-controls.ts} +9 -9
- package/client/modeller/{v3-figure-facts.ts → figure-facts.ts} +11 -11
- package/client/modeller/{figure-v3-first-save.ts → figure-first-save.ts} +3 -3
- package/client/modeller/figure-history-panel.ts +1 -1
- package/client/modeller/{figure-v3-links.ts → figure-links.ts} +35 -35
- package/client/modeller/{figure-v3-material.ts → figure-material-panel.ts} +20 -20
- package/client/modeller/{figure-v3-parts.ts → figure-parts.ts} +15 -15
- package/client/modeller/{figure-v3-preview.ts → figure-preview.ts} +14 -14
- package/client/modeller/{figure-v3-properties.ts → figure-properties.ts} +25 -25
- package/client/modeller/{figure-v3-recipe-catalog.ts → figure-recipe-catalog.ts} +10 -10
- package/client/modeller/{figure-v3-verdict.ts → figure-verdict.ts} +24 -24
- package/client/modeller/gate-findings.ts +2 -2
- package/client/modeller/{v3-gizmo.ts → gizmo.ts} +11 -11
- package/client/modeller/{v3-joint-drag.ts → joint-drag.ts} +11 -11
- package/client/modeller/{v3-joint-fan.ts → joint-fan.ts} +13 -13
- package/client/modeller/{v3-links.ts → links.ts} +59 -59
- package/client/modeller/{v3-live.ts → live.ts} +9 -9
- package/client/modeller/{v3-maturity.ts → maturity.ts} +65 -65
- package/client/modeller/modeller-route.ts +1 -1
- package/client/modeller/{v3-occupancy.ts → occupancy.ts} +6 -6
- package/client/modeller/{v3-palette.ts → palette.ts} +3 -3
- package/client/modeller/{v3-preview-model.ts → preview-model.ts} +8 -8
- package/client/modeller/{v3-product-session.ts → product-session.ts} +25 -25
- package/client/modeller/{v3-recipe-source.ts → recipe-source.ts} +2 -2
- package/client/modeller/{v3-recipes.ts → recipes.ts} +9 -9
- package/client/modeller/{v3-refusals.ts → refusals.ts} +62 -13
- package/client/modeller/{v3-renderer.ts → renderer.ts} +16 -16
- package/client/modeller/{v3-stage-model.ts → stage-model.ts} +15 -15
- package/client/modeller/{v3-thumbnail.ts → thumbnail.ts} +8 -8
- package/client/pages/figure-list-page.ts +4 -4
- package/client/pages/{figure-v3-modeller-page.ts → figure-modeller-page.ts} +37 -37
- package/client/route.ts +1 -5
- package/dist-client/figure-assistant.js +3 -3
- package/dist-client/figure-assistant.js.map +1 -1
- package/dist-client/graphql/store.d.ts +3 -0
- package/dist-client/graphql/store.js +39 -0
- package/dist-client/graphql/store.js.map +1 -0
- package/dist-client/modeller/ai-proposal.d.ts +51 -0
- package/dist-client/modeller/ai-proposal.js +64 -0
- package/dist-client/modeller/ai-proposal.js.map +1 -0
- package/dist-client/modeller/align.d.ts +30 -0
- package/dist-client/modeller/align.js +75 -0
- package/dist-client/modeller/align.js.map +1 -0
- package/dist-client/modeller/canvas.d.ts +72 -0
- package/dist-client/modeller/canvas.js +379 -0
- package/dist-client/modeller/canvas.js.map +1 -0
- package/dist-client/modeller/clips.d.ts +39 -0
- package/dist-client/modeller/clips.js +58 -0
- package/dist-client/modeller/clips.js.map +1 -0
- package/dist-client/modeller/controls.d.ts +28 -0
- package/dist-client/modeller/controls.js +28 -0
- package/dist-client/modeller/controls.js.map +1 -0
- package/dist-client/modeller/editor.d.ts +203 -0
- package/dist-client/modeller/editor.js +1526 -0
- package/dist-client/modeller/editor.js.map +1 -0
- package/dist-client/modeller/fields.d.ts +45 -0
- package/dist-client/modeller/fields.js +83 -0
- package/dist-client/modeller/fields.js.map +1 -0
- package/dist-client/modeller/figure-capability-panel.d.ts +22 -0
- package/dist-client/modeller/figure-capability-panel.js +141 -0
- package/dist-client/modeller/figure-capability-panel.js.map +1 -0
- package/dist-client/modeller/figure-clips.d.ts +31 -0
- package/dist-client/modeller/figure-clips.js +268 -0
- package/dist-client/modeller/figure-clips.js.map +1 -0
- package/dist-client/modeller/figure-controls.d.ts +36 -0
- package/dist-client/modeller/figure-controls.js +226 -0
- package/dist-client/modeller/figure-controls.js.map +1 -0
- package/dist-client/modeller/figure-facts.d.ts +35 -0
- package/dist-client/modeller/figure-facts.js +55 -0
- package/dist-client/modeller/figure-facts.js.map +1 -0
- package/dist-client/modeller/figure-first-save.d.ts +20 -0
- package/dist-client/modeller/figure-first-save.js +118 -0
- package/dist-client/modeller/figure-first-save.js.map +1 -0
- 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 +77 -0
- package/dist-client/modeller/figure-links.js +649 -0
- package/dist-client/modeller/figure-links.js.map +1 -0
- package/dist-client/modeller/figure-material-panel.d.ts +39 -0
- package/dist-client/modeller/figure-material-panel.js +323 -0
- package/dist-client/modeller/figure-material-panel.js.map +1 -0
- package/dist-client/modeller/figure-parts.d.ts +69 -0
- package/dist-client/modeller/figure-parts.js +559 -0
- package/dist-client/modeller/figure-parts.js.map +1 -0
- package/dist-client/modeller/figure-preview.d.ts +34 -0
- package/dist-client/modeller/figure-preview.js +346 -0
- package/dist-client/modeller/figure-preview.js.map +1 -0
- package/dist-client/modeller/figure-properties.d.ts +45 -0
- package/dist-client/modeller/figure-properties.js +239 -0
- package/dist-client/modeller/figure-properties.js.map +1 -0
- package/dist-client/modeller/figure-recipe-catalog.d.ts +38 -0
- package/dist-client/modeller/figure-recipe-catalog.js +399 -0
- package/dist-client/modeller/figure-recipe-catalog.js.map +1 -0
- package/dist-client/modeller/figure-verdict.d.ts +64 -0
- package/dist-client/modeller/figure-verdict.js +787 -0
- package/dist-client/modeller/figure-verdict.js.map +1 -0
- package/dist-client/modeller/first-save.d.ts +17 -0
- package/dist-client/modeller/first-save.js +26 -0
- package/dist-client/modeller/first-save.js.map +1 -0
- package/dist-client/modeller/gate-findings.d.ts +2 -2
- package/dist-client/modeller/gate-findings.js +2 -2
- package/dist-client/modeller/gate-findings.js.map +1 -1
- package/dist-client/modeller/gizmo.d.ts +72 -0
- package/dist-client/modeller/gizmo.js +111 -0
- package/dist-client/modeller/gizmo.js.map +1 -0
- package/dist-client/modeller/help.d.ts +18 -0
- package/dist-client/modeller/help.js +37 -0
- package/dist-client/modeller/help.js.map +1 -0
- package/dist-client/modeller/joint-drag.d.ts +19 -0
- package/dist-client/modeller/joint-drag.js +97 -0
- package/dist-client/modeller/joint-drag.js.map +1 -0
- package/dist-client/modeller/joint-fan.d.ts +9 -0
- package/dist-client/modeller/joint-fan.js +276 -0
- package/dist-client/modeller/joint-fan.js.map +1 -0
- package/dist-client/modeller/keys.d.ts +22 -0
- package/dist-client/modeller/keys.js +26 -0
- package/dist-client/modeller/keys.js.map +1 -0
- package/dist-client/modeller/links.d.ts +267 -0
- package/dist-client/modeller/links.js +480 -0
- package/dist-client/modeller/links.js.map +1 -0
- package/dist-client/modeller/live.d.ts +37 -0
- package/dist-client/modeller/live.js +68 -0
- package/dist-client/modeller/live.js.map +1 -0
- package/dist-client/modeller/maturity.d.ts +120 -0
- package/dist-client/modeller/maturity.js +313 -0
- package/dist-client/modeller/maturity.js.map +1 -0
- package/dist-client/modeller/modeller-route.d.ts +1 -1
- package/dist-client/modeller/modeller-route.js +1 -1
- package/dist-client/modeller/modeller-route.js.map +1 -1
- package/dist-client/modeller/occupancy.d.ts +18 -0
- package/dist-client/modeller/occupancy.js +24 -0
- package/dist-client/modeller/occupancy.js.map +1 -0
- package/dist-client/modeller/palette.d.ts +7 -0
- package/dist-client/modeller/palette.js +46 -0
- package/dist-client/modeller/palette.js.map +1 -0
- package/dist-client/modeller/preview-model.d.ts +47 -0
- package/dist-client/modeller/preview-model.js +68 -0
- package/dist-client/modeller/preview-model.js.map +1 -0
- package/dist-client/modeller/product-session.d.ts +510 -0
- package/dist-client/modeller/product-session.js +157 -0
- package/dist-client/modeller/product-session.js.map +1 -0
- package/dist-client/modeller/recipe-source.d.ts +8 -0
- package/dist-client/modeller/recipe-source.js +14 -0
- package/dist-client/modeller/recipe-source.js.map +1 -0
- package/dist-client/modeller/recipes.d.ts +37 -0
- package/dist-client/modeller/recipes.js +103 -0
- package/dist-client/modeller/recipes.js.map +1 -0
- package/dist-client/modeller/refusals.d.ts +68 -0
- package/dist-client/modeller/refusals.js +142 -0
- package/dist-client/modeller/refusals.js.map +1 -0
- package/dist-client/modeller/renderer.d.ts +40 -0
- package/dist-client/modeller/renderer.js +73 -0
- package/dist-client/modeller/renderer.js.map +1 -0
- package/dist-client/modeller/stage-model.d.ts +39 -0
- package/dist-client/modeller/stage-model.js +147 -0
- package/dist-client/modeller/stage-model.js.map +1 -0
- package/dist-client/modeller/thumbnail.d.ts +3 -0
- package/dist-client/modeller/thumbnail.js +75 -0
- package/dist-client/modeller/thumbnail.js.map +1 -0
- package/dist-client/modeller/v3-clips.d.ts +1 -1
- package/dist-client/modeller/v3-editor.d.ts +5 -0
- package/dist-client/modeller/v3-editor.js +21 -10
- package/dist-client/modeller/v3-editor.js.map +1 -1
- package/dist-client/modeller/v3-product-session.d.ts +31 -0
- package/dist-client/modeller/v3-refusals.d.ts +37 -5
- package/dist-client/modeller/v3-refusals.js +59 -16
- package/dist-client/modeller/v3-refusals.js.map +1 -1
- package/dist-client/pages/figure-list-page.d.ts +1 -1
- package/dist-client/pages/figure-list-page.js +4 -4
- package/dist-client/pages/figure-list-page.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.d.ts +102 -0
- package/dist-client/pages/figure-modeller-page.js +548 -0
- package/dist-client/pages/figure-modeller-page.js.map +1 -0
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +1 -5
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/docs/product-cutover.md +25 -0
- package/package.json +5 -5
- package/test/{v3-ai-proposal.test.ts → ai-proposal.test.ts} +6 -6
- package/test/{v3-align.test.ts → align.test.ts} +8 -8
- package/test/browser/modeller-page.js +30 -30
- package/test/browser/modeller.check.mjs +17 -16
- package/test/browser/serve.mjs +1 -1
- package/test/browser/thumbnail-page.js +6 -6
- package/test/{v3-clips.test.ts → clips.test.ts} +18 -18
- package/test/{v3-controls.test.ts → controls.test.ts} +15 -15
- package/test/{v3-fields.test.ts → fields.test.ts} +13 -13
- package/test/figure-assistant-surface.test.ts +3 -3
- package/test/{v3-first-save.test.ts → first-save.test.ts} +10 -10
- package/test/fixtures/joint-column.json +2 -2
- package/test/fixtures/joint-roller.json +2 -2
- package/test/fixtures/robot-arm-6dof.json +2 -2
- package/test/{v3-gizmo.test.ts → gizmo.test.ts} +33 -33
- package/test/{v3-joint-drag.test.ts → joint-drag.test.ts} +17 -17
- package/test/{v3-joint-fan.test.ts → joint-fan.test.ts} +18 -18
- package/test/joints.ts +6 -6
- package/test/{v3-keys.test.ts → keys.test.ts} +2 -2
- package/test/{v3-layout.test.ts → layout.test.ts} +8 -8
- package/test/{v3-links.test.ts → links.test.ts} +201 -201
- package/test/{v3-live.test.ts → live.test.ts} +18 -18
- package/test/{v3-material.test.ts → material.test.ts} +12 -12
- package/test/{v3-maturity.test.ts → maturity.test.ts} +74 -74
- package/test/modeller-route.test.ts +5 -6
- package/test/{v3-palette-icons.test.ts → palette-icons.test.ts} +1 -1
- package/test/{v3-parts-wiring.test.ts → parts-wiring.test.ts} +11 -7
- package/test/{v3-preview.test.ts → preview.test.ts} +12 -12
- package/test/{v3-product-session.test.ts → product-session.test.ts} +17 -17
- package/test/{v3-product-write.test.ts → product-write.test.ts} +20 -20
- package/test/{v3-properties.test.ts → properties.test.ts} +24 -24
- package/test/{v3-recipes.test.ts → recipes.test.ts} +10 -10
- package/test/refusals.test.ts +166 -0
- package/test/{v3-release-panel.test.ts → release-panel.test.ts} +21 -21
- package/test/renderer.test.ts +24 -0
- package/test/resolve-ts-siblings.mjs +1 -1
- package/test/{v3-scene-canvas.test.ts → scene-canvas.test.ts} +6 -6
- package/test/{v3-stage-model.test.ts → stage-model.test.ts} +5 -5
- package/test/{v3-theme.test.ts → theme.test.ts} +4 -4
- package/test/{v3-thumbnail.test.ts → thumbnail.test.ts} +4 -4
- package/test/{v3-verdict.test.ts → verdict.test.ts} +17 -17
- package/test/{v3-view.test.ts → view.test.ts} +2 -2
- package/things-factory.config.js +2 -3
- package/translations/en.json +15 -7
- package/translations/ja.json +15 -7
- package/translations/ko.json +15 -7
- package/translations/ms.json +15 -7
- package/translations/zh.json +15 -7
- package/docs/v3-product-cutover.md +0 -25
- package/test/v3-refusals.test.ts +0 -136
- package/test/v3-renderer.test.ts +0 -24
- /package/client/modeller/{v3-fields.ts → fields.ts} +0 -0
- /package/client/modeller/{v3-first-save.ts → first-save.ts} +0 -0
- /package/client/modeller/{v3-help.ts → help.ts} +0 -0
- /package/client/modeller/{v3-keys.ts → keys.ts} +0 -0
|
@@ -4,23 +4,23 @@ import { customElement, property } from 'lit/decorators.js'
|
|
|
4
4
|
import { i18next, localize } from '@operato/i18n'
|
|
5
5
|
import { ScrollbarStyles } from '@operato/styles'
|
|
6
6
|
import { PART_LIMIT } from '@hatiolab/figure-model'
|
|
7
|
-
import type {
|
|
8
|
-
import type {
|
|
9
|
-
import { partLabelOf } from './
|
|
7
|
+
import type { FigurePrimitiveCreation } from '@hatiolab/figure-model'
|
|
8
|
+
import type { FigureBudgetLine } from './maturity.js'
|
|
9
|
+
import { partLabelOf } from './fields.js'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* 도형 팔레트와 부품 목록 —
|
|
12
|
+
* 도형 팔레트와 부품 목록 — 자산의 것.
|
|
13
13
|
*
|
|
14
14
|
* 팔레트는 목록 위에, 눈 단추는 늘 자리를 차지하고, 조작은 고른 줄에서만 보인다.
|
|
15
15
|
*
|
|
16
|
-
* 부품의 도형은
|
|
16
|
+
* 부품의 도형은 평가가 준 `provider` 로 읽는다. 「숨김」은 여기서도 **작업대의 것**이다 — 저장되지 않고, 자산의 `visibility`(상태에 따라
|
|
17
17
|
* 보이고 안 보이는 것)와는 다른 것이다. 그것은 속성 패널의 몫이다.
|
|
18
18
|
*
|
|
19
19
|
* 이 컴포넌트는 정본을 만지지 않는다. 무엇을 하겠다는 것만 알린다.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
/** 한 줄 —
|
|
23
|
-
export interface
|
|
22
|
+
/** 한 줄 — 평가에서 이 패널이 읽는 것만. */
|
|
23
|
+
export interface FigurePartRow {
|
|
24
24
|
id: string
|
|
25
25
|
provider: string
|
|
26
26
|
/** 작업대에서 잠깐 가린 것. 저장되지 않는다. */
|
|
@@ -50,8 +50,8 @@ const PROVIDER_ICON: Record<string, string> = {
|
|
|
50
50
|
/*
|
|
51
51
|
The palette. A plate and a wall are boxes of a shape a person reaches for, so they are starting sizes, not kinds of their own.
|
|
52
52
|
*/
|
|
53
|
-
export type
|
|
54
|
-
const RECIPES: Array<{ kind:
|
|
53
|
+
export type FigurePaletteKind = FigurePrimitiveCreation['kind'] | 'plate' | 'wall'
|
|
54
|
+
const RECIPES: Array<{ kind: FigurePaletteKind; icon: string; label: string }> = [
|
|
55
55
|
{ kind: 'box', icon: 'deployed_code', label: 'figure.label.primitive-cube' },
|
|
56
56
|
{ kind: 'cylinder', icon: 'database', label: 'figure.label.primitive-cylinder' },
|
|
57
57
|
{ kind: 'rounded-box', icon: 'crop_square', label: 'figure.label.primitive-rounded-box' },
|
|
@@ -64,8 +64,8 @@ const RECIPES: Array<{ kind: V3PaletteKind; icon: string; label: string }> = [
|
|
|
64
64
|
{ kind: 'hollow-box', icon: 'inventory_2', label: 'figure.label.primitive-hollow-box' }
|
|
65
65
|
]
|
|
66
66
|
|
|
67
|
-
@customElement('figure-
|
|
68
|
-
export class
|
|
67
|
+
@customElement('figure-parts')
|
|
68
|
+
export class FigureParts extends localize(i18next)(LitElement) {
|
|
69
69
|
static styles = [
|
|
70
70
|
ScrollbarStyles,
|
|
71
71
|
css`
|
|
@@ -363,8 +363,8 @@ export class FigureV3Parts extends localize(i18next)(LitElement) {
|
|
|
363
363
|
`
|
|
364
364
|
]
|
|
365
365
|
|
|
366
|
-
@property({ type: Array }) parts:
|
|
367
|
-
/** 고른 부품의 id. 자리(index)가 아니다 —
|
|
366
|
+
@property({ type: Array }) parts: FigurePartRow[] = []
|
|
367
|
+
/** 고른 부품의 id. 자리(index)가 아니다 — 부품은 id 로 안정하게 가리킨다. */
|
|
368
368
|
@property({ type: String }) selected = ''
|
|
369
369
|
/** 편집할 수 없을 때(불러오는 중 · 저장 중) 팔레트와 조작을 잠근다. */
|
|
370
370
|
@property({ type: Boolean }) locked = false
|
|
@@ -372,7 +372,7 @@ export class FigureV3Parts extends localize(i18next)(LitElement) {
|
|
|
372
372
|
* 이 도형이 치르는 값 — 삼각형 · 묶음 · 한 화면에 몇 대 · 등급. 부품을 더하는 바로 그 자리에서 보여야 로우폴리의
|
|
373
373
|
* 기준이 저작을 이끈다. 등급이 D 면 무엇이 넘쳤는지를 적는다. 누르면 성숙도 탭이 열린다.
|
|
374
374
|
*/
|
|
375
|
-
@property({ attribute: false }) budget?:
|
|
375
|
+
@property({ attribute: false }) budget?: FigureBudgetLine
|
|
376
376
|
/**
|
|
377
377
|
* 디테일 등급(S/M/L)의 부품 한도(사용자 2026-09-24). 부품을 넣기 **전에** 몇 개 남았는지 보이고, 다 차면 팔레트가
|
|
378
378
|
* 잠긴다. 되풀이는 한 부품으로 센다. 등급을 안 정했으면 한도는 없다.
|
|
@@ -502,7 +502,7 @@ export class FigureV3Parts extends localize(i18next)(LitElement) {
|
|
|
502
502
|
`
|
|
503
503
|
}
|
|
504
504
|
|
|
505
|
-
private renderRow(part:
|
|
505
|
+
private renderRow(part: FigurePartRow, index: number) {
|
|
506
506
|
const selected = part.id === this.selected
|
|
507
507
|
const off = !!part.hidden
|
|
508
508
|
return html`
|
|
@@ -2,13 +2,13 @@ import { css, html, LitElement, nothing, unsafeCSS } from 'lit'
|
|
|
2
2
|
import { customElement, property, query, state } from 'lit/decorators.js'
|
|
3
3
|
|
|
4
4
|
import { i18next, localize } from '@operato/i18n'
|
|
5
|
-
import {
|
|
6
|
-
import type {
|
|
7
|
-
import { create,
|
|
5
|
+
import { compileFigureAsset } from '@hatiolab/figure-model'
|
|
6
|
+
import type { FigureAsset } from '@hatiolab/figure-model'
|
|
7
|
+
import { create, registerFigure, unregisterFigure } from '@hatiolab/things-scene'
|
|
8
8
|
|
|
9
9
|
import { DEFAULT_VIEW, previewBoardDepth, sceneLook, WORKBENCH, type ViewSettings } from './figure-view.js'
|
|
10
10
|
import { dialShape } from './angle-dial.js'
|
|
11
|
-
import { authoredSizeOf, PREVIEW_FACTOR, PREVIEW_WAYS, previewClampsOf, previewInstances } from './
|
|
11
|
+
import { authoredSizeOf, PREVIEW_FACTOR, PREVIEW_WAYS, previewClampsOf, previewInstances } from './preview-model.js'
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* The figure placed on a board.
|
|
@@ -17,7 +17,7 @@ import { authoredSizeOf, PREVIEW_FACTOR, PREVIEW_WAYS, previewClampsOf, previewI
|
|
|
17
17
|
* different size, so here the figure being authored is registered as a board registers it and placed as
|
|
18
18
|
* `FigureInstance`s: the size it was made, and each of the seven ways of growing one, two or three axes twice as
|
|
19
19
|
* large, side by side at one scale, four to a row. The board draws them as it will on a real board --
|
|
20
|
-
* placement, lights, environment, the same
|
|
20
|
+
* placement, lights, environment, the same renderer.
|
|
21
21
|
*
|
|
22
22
|
* The controls: each value that poses the figure with a slider (and a dial for an angle), each clip's
|
|
23
23
|
* speed, and 「이 자세를 기본으로」 to keep the pose as the one it stands in. Nothing here is edited; the canvas edits.
|
|
@@ -34,8 +34,8 @@ interface SceneHandle {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
@customElement('figure-
|
|
38
|
-
export class
|
|
37
|
+
@customElement('figure-preview')
|
|
38
|
+
export class FigurePreview extends localize(i18next)(LitElement) {
|
|
39
39
|
static styles = css`
|
|
40
40
|
:host {
|
|
41
41
|
position: relative;
|
|
@@ -149,7 +149,7 @@ export class FigureV3Preview extends localize(i18next)(LitElement) {
|
|
|
149
149
|
`
|
|
150
150
|
|
|
151
151
|
/** The figure being authored, as the editor holds it now. */
|
|
152
|
-
@property({ attribute: false }) asset?:
|
|
152
|
+
@property({ attribute: false }) asset?: FigureAsset
|
|
153
153
|
/** Which figure: the type it is registered under here is this one's own, never a real type a board uses. */
|
|
154
154
|
@property() context = ''
|
|
155
155
|
@property({ attribute: false }) view: ViewSettings = DEFAULT_VIEW
|
|
@@ -192,7 +192,7 @@ export class FigureV3Preview extends localize(i18next)(LitElement) {
|
|
|
192
192
|
${controls.length + clips.length ? this.renderDrivers(asset!, controls, clips) : nothing}`}`
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
private renderDrivers(asset:
|
|
195
|
+
private renderDrivers(asset: FigureAsset, controls: FigureAsset['document']['model']['inputs'], clips: string[]) {
|
|
196
196
|
const changed = controls.filter(c => this.giving[c.id] !== undefined && this.giving[c.id] !== asset.stateDefaults[c.id])
|
|
197
197
|
return html`<div clips>
|
|
198
198
|
${changed.length
|
|
@@ -252,7 +252,7 @@ export class FigureV3Preview extends localize(i18next)(LitElement) {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
private poseAsDefault() {
|
|
255
|
-
this.dispatchEvent(new CustomEvent('
|
|
255
|
+
this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-state-defaults', values: { ...this.giving } } }, bubbles: true, composed: true }))
|
|
256
256
|
this.giving = {}
|
|
257
257
|
}
|
|
258
258
|
|
|
@@ -297,7 +297,7 @@ export class FigureV3Preview extends localize(i18next)(LitElement) {
|
|
|
297
297
|
const signature = JSON.stringify([asset, view.placement, view.ceilingHeight])
|
|
298
298
|
if (this.scene && this.standing === signature) return
|
|
299
299
|
try {
|
|
300
|
-
|
|
300
|
+
compileFigureAsset(asset)
|
|
301
301
|
} catch {
|
|
302
302
|
this.cannot = i18next.t('figure.text.preview-blocked-by-errors')
|
|
303
303
|
this.teardown()
|
|
@@ -307,8 +307,8 @@ export class FigureV3Preview extends localize(i18next)(LitElement) {
|
|
|
307
307
|
this.driving = {}
|
|
308
308
|
try {
|
|
309
309
|
/* Registered as a board registers it, under a type of this preview's own: a real type's drawings stay as they are. */
|
|
310
|
-
const type = `figure-
|
|
311
|
-
|
|
310
|
+
const type = `figure-preview-${this.context || 'new'}`
|
|
311
|
+
registerFigure(type, asset)
|
|
312
312
|
this.registered = type
|
|
313
313
|
const size = authoredSizeOf(asset)
|
|
314
314
|
const { components, board } = previewInstances(type, size)
|
|
@@ -343,7 +343,7 @@ export class FigureV3Preview extends localize(i18next)(LitElement) {
|
|
|
343
343
|
this.scene?.dispose?.()
|
|
344
344
|
this.scene = undefined
|
|
345
345
|
this.standing = undefined
|
|
346
|
-
if (this.registered)
|
|
346
|
+
if (this.registered) unregisterFigure(this.registered)
|
|
347
347
|
this.registered = undefined
|
|
348
348
|
}
|
|
349
349
|
}
|
|
@@ -5,16 +5,16 @@ import { customElement, property, state } from 'lit/decorators.js'
|
|
|
5
5
|
import { live } from 'lit/directives/live.js'
|
|
6
6
|
|
|
7
7
|
import { i18next, localize } from '@operato/i18n'
|
|
8
|
-
import {
|
|
9
|
-
import type {
|
|
8
|
+
import { FIGURE_FACES } from '@hatiolab/figure-model'
|
|
9
|
+
import type { FigureAuthoringAction, FigureFace } from '@hatiolab/figure-model'
|
|
10
10
|
|
|
11
|
-
import { occupancyFromParts } from './
|
|
12
|
-
import { tagsOf,
|
|
11
|
+
import { occupancyFromParts } from './occupancy.js'
|
|
12
|
+
import { tagsOf, figureFigureFacts, type Placement, type FigureFigureFacts } from './figure-facts.js'
|
|
13
13
|
import { SidePanelStyles } from './side-panel-styles.js'
|
|
14
14
|
import { ScrollbarStyles } from '@operato/styles'
|
|
15
15
|
|
|
16
16
|
const PLACEMENTS: Placement[] = ['floor', 'ceiling', 'center', 'wall']
|
|
17
|
-
const FACES = Object.keys(
|
|
17
|
+
const FACES = Object.keys(FIGURE_FACES) as FigureFace[]
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* 속성 — the modeller's figure properties.
|
|
@@ -23,16 +23,16 @@ const FACES = Object.keys(V3_FACES) as V3Face[]
|
|
|
23
23
|
* catalogue files it.
|
|
24
24
|
*
|
|
25
25
|
* Two kinds of change leave this tab, and it does neither itself:
|
|
26
|
-
* - `
|
|
26
|
+
* - `command` carries an authoring command (rename, declare the room, the mounting face). The page runs it
|
|
27
27
|
* through the session, so it is one step of the same undo history as every other edit, and is saved with it.
|
|
28
|
-
* - `
|
|
28
|
+
* - `catalog` carries a change to the row (category, tags). Those are not in the asset; the page writes them
|
|
29
29
|
* to the saved row at once, so they need a saved figure.
|
|
30
30
|
*
|
|
31
|
-
* Not here yet, because
|
|
32
|
-
* parts, as graph expressions), and the detail level. Both wait on a
|
|
31
|
+
* Not here yet, because has no place for them: editing the declared room by hand (declares it from the
|
|
32
|
+
* parts, as graph expressions), and the detail level. Both wait on a ruling.
|
|
33
33
|
*/
|
|
34
|
-
@customElement('figure-
|
|
35
|
-
export class
|
|
34
|
+
@customElement('figure-properties')
|
|
35
|
+
export class FigureProperties extends localize(i18next)(LitElement) {
|
|
36
36
|
static styles = [ScrollbarStyles, SidePanelStyles, css`
|
|
37
37
|
:host {
|
|
38
38
|
display: block;
|
|
@@ -66,11 +66,11 @@ export class FigureV3Properties extends localize(i18next)(LitElement) {
|
|
|
66
66
|
@property({ type: Array }) figureTags?: string[]
|
|
67
67
|
/** The part and face picked for the mounting face, before 「이 면으로」 is pressed. */
|
|
68
68
|
@state() private pickedPart?: string
|
|
69
|
-
@state() private pickedFace?:
|
|
69
|
+
@state() private pickedFace?: FigureFace
|
|
70
70
|
|
|
71
|
-
private facts():
|
|
71
|
+
private facts(): FigureFigureFacts | undefined {
|
|
72
72
|
try {
|
|
73
|
-
return this.source ?
|
|
73
|
+
return this.source ? figureFigureFacts(this.source) : undefined
|
|
74
74
|
} catch {
|
|
75
75
|
/* A source the format refuses has no facts to show; the verdict tab says why. */
|
|
76
76
|
return undefined
|
|
@@ -96,7 +96,7 @@ export class FigureV3Properties extends localize(i18next)(LitElement) {
|
|
|
96
96
|
</section>`
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
private renderName(facts:
|
|
99
|
+
private renderName(facts: FigureFigureFacts) {
|
|
100
100
|
return html`
|
|
101
101
|
<div field>
|
|
102
102
|
<label>${i18next.t('figure.label.name')}</label>
|
|
@@ -118,10 +118,10 @@ export class FigureV3Properties extends localize(i18next)(LitElement) {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
|
-
* The face the figure is placed by. In
|
|
122
|
-
* again from the parts — the only way
|
|
121
|
+
* The face the figure is placed by. In it is part of the room declaration, so choosing one declares the room
|
|
122
|
+
* again from the parts — the only way declares it — with the new face. The hint says so.
|
|
123
123
|
*/
|
|
124
|
-
private renderPlacement(facts:
|
|
124
|
+
private renderPlacement(facts: FigureFigureFacts) {
|
|
125
125
|
const current = facts.placement ?? 'floor'
|
|
126
126
|
return html`
|
|
127
127
|
<div field>
|
|
@@ -145,7 +145,7 @@ export class FigureV3Properties extends localize(i18next)(LitElement) {
|
|
|
145
145
|
`
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
private renderSpace(facts:
|
|
148
|
+
private renderSpace(facts: FigureFigureFacts) {
|
|
149
149
|
return html`
|
|
150
150
|
<div field>
|
|
151
151
|
<label>${i18next.t('figure.label.declared-space')}</label>
|
|
@@ -159,11 +159,11 @@ export class FigureV3Properties extends localize(i18next)(LitElement) {
|
|
|
159
159
|
`
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
private renderMounting(facts:
|
|
162
|
+
private renderMounting(facts: FigureFigureFacts) {
|
|
163
163
|
const mounting = facts.mounting
|
|
164
164
|
/* Chosen, or what is set, or where the figure meets its plane -- not the first part listed (walk 1). */
|
|
165
165
|
const part = [this.pickedPart, mounting?.part, facts.suggested?.part, facts.parts[0]].find(one => one && facts.parts.includes(one))
|
|
166
|
-
const face:
|
|
166
|
+
const face: FigureFace = this.pickedFace ?? mounting?.face ?? facts.suggested?.face ?? 'bottom'
|
|
167
167
|
return html`
|
|
168
168
|
<div field>
|
|
169
169
|
<label>${i18next.t('figure.label.mounting-face')}</label>
|
|
@@ -171,7 +171,7 @@ export class FigureV3Properties extends localize(i18next)(LitElement) {
|
|
|
171
171
|
<select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedPart = (e.target as HTMLSelectElement).value)}>
|
|
172
172
|
${facts.parts.map(one => html`<option value=${one} ?selected=${one === part}>${one}</option>`)}
|
|
173
173
|
</select>
|
|
174
|
-
<select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedFace = (e.target as HTMLSelectElement).value as
|
|
174
|
+
<select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedFace = (e.target as HTMLSelectElement).value as FigureFace)}>
|
|
175
175
|
${FACES.map(one => html`<option value=${one} ?selected=${one === face}>${i18next.t('figure.label.face-' + one)}</option>`)}
|
|
176
176
|
</select>
|
|
177
177
|
</div>
|
|
@@ -224,11 +224,11 @@ export class FigureV3Properties extends localize(i18next)(LitElement) {
|
|
|
224
224
|
this.command(occupancyFromParts(this.source, placement))
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
private command(action:
|
|
228
|
-
this.dispatchEvent(new CustomEvent('
|
|
227
|
+
private command(action: FigureAuthoringAction) {
|
|
228
|
+
this.dispatchEvent(new CustomEvent('command', { detail: { action }, bubbles: true, composed: true }))
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
private catalog(patch: { category?: string; tags?: string[] }) {
|
|
232
|
-
this.dispatchEvent(new CustomEvent('
|
|
232
|
+
this.dispatchEvent(new CustomEvent('catalog', { detail: patch, bubbles: true, composed: true }))
|
|
233
233
|
}
|
|
234
234
|
}
|
|
@@ -6,19 +6,19 @@ import { customElement, property, state } from 'lit/decorators.js'
|
|
|
6
6
|
|
|
7
7
|
import { i18next, localize } from '@operato/i18n'
|
|
8
8
|
import { ScrollbarStyles } from '@operato/styles'
|
|
9
|
-
import {
|
|
10
|
-
import type {
|
|
9
|
+
import { describeFigureRecipe } from '@hatiolab/figure-model'
|
|
10
|
+
import type { FigureRecipe, FigureRecipeValue } from '@hatiolab/figure-model'
|
|
11
11
|
|
|
12
|
-
import { recipeFieldOf, recipeReady, recipeValueOf, recipeWord, recipeWorkings, recipesMatching, type RecipeTemplate } from './
|
|
12
|
+
import { recipeFieldOf, recipeReady, recipeValueOf, recipeWord, recipeWorkings, recipesMatching, type RecipeTemplate } from './recipes.js'
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* The recipe catalog (ADR-0095): the templates the product ships, by category, found by words, each told in full --
|
|
16
16
|
* what it puts in, how many parts, how they move, what each value does, and how to use it -- and put onto the chosen
|
|
17
|
-
* part in one step. The numbers and the ways of moving are worked out from the recipe (`
|
|
17
|
+
* part in one step. The numbers and the ways of moving are worked out from the recipe (`describeFigureRecipe`), so they say
|
|
18
18
|
* what it does; only the descriptions and the guide are written.
|
|
19
19
|
*/
|
|
20
|
-
@customElement('figure-
|
|
21
|
-
export class
|
|
20
|
+
@customElement('figure-recipe-catalog')
|
|
21
|
+
export class FigureRecipeCatalog extends localize(i18next)(LitElement) {
|
|
22
22
|
static styles = [
|
|
23
23
|
ScrollbarStyles,
|
|
24
24
|
css`
|
|
@@ -238,7 +238,7 @@ export class FigureV3RecipeCatalog extends localize(i18next)(LitElement) {
|
|
|
238
238
|
@state() private category = ''
|
|
239
239
|
@state() private query = ''
|
|
240
240
|
@state() private chosen = ''
|
|
241
|
-
@state() private values: Record<string,
|
|
241
|
+
@state() private values: Record<string, FigureRecipeValue> = {}
|
|
242
242
|
/*
|
|
243
243
|
The guide as a page \`ox-markdown\` can read: it renders what its src points to, not text, and given the text it
|
|
244
244
|
fetched it as a path and drew the app's own page in its place (seen on :3300, 2026-09-26). A blob of type
|
|
@@ -314,7 +314,7 @@ export class FigureV3RecipeCatalog extends localize(i18next)(LitElement) {
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
private renderDetail(t: RecipeTemplate, language: string) {
|
|
317
|
-
const d =
|
|
317
|
+
const d = describeFigureRecipe(t.recipe)
|
|
318
318
|
const count = d.parts.min === d.parts.max ? String(d.parts.min) : `${d.parts.min}–${d.parts.max}`
|
|
319
319
|
const ready = recipeReady(t.recipe, this.selected)
|
|
320
320
|
return html`
|
|
@@ -339,8 +339,8 @@ export class FigureV3RecipeCatalog extends localize(i18next)(LitElement) {
|
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
/** Each value: its name, what it does, and the field to set it -- a share typed as a percentage. */
|
|
342
|
-
private renderForm(recipe:
|
|
343
|
-
const set = (name: string, value:
|
|
342
|
+
private renderForm(recipe: FigureRecipe, language: string) {
|
|
343
|
+
const set = (name: string, value: FigureRecipeValue) => (this.values = { ...this.values, [name]: value })
|
|
344
344
|
return html`<div form>
|
|
345
345
|
<h3>${i18next.t('figure.label.recipe-values')}</h3>
|
|
346
346
|
${recipe.params.map(param => {
|
|
@@ -5,15 +5,15 @@ import { customElement, property, state } from 'lit/decorators.js'
|
|
|
5
5
|
|
|
6
6
|
import { i18next, localize } from '@operato/i18n'
|
|
7
7
|
import { ScrollbarStyles } from '@operato/styles'
|
|
8
|
-
import { LIMITS,
|
|
8
|
+
import { LIMITS, parseFigureAsset, FIGURE_PER_INSTANCE, figureCostOf } from '@hatiolab/figure-model'
|
|
9
9
|
|
|
10
10
|
import { inspectFigureDraft } from '../graphql/index.js'
|
|
11
11
|
import type { FigureInspection } from '../types.js'
|
|
12
12
|
import { gateFindingStyles, renderGateFinding } from './gate-findings.js'
|
|
13
13
|
import { MEASURED } from './scene-budget.js'
|
|
14
14
|
import { SidePanelStyles } from './side-panel-styles.js'
|
|
15
|
-
import { budgetOf, CURVE_SIZE, curveLayout, GRADE_SCALE, shortNumber,
|
|
16
|
-
import type {
|
|
15
|
+
import { budgetOf, CURVE_SIZE, curveLayout, GRADE_SCALE, shortNumber, figureReportOf } from './maturity.js'
|
|
16
|
+
import type { FigureBudgetUse, FigureMaturityAxis, FigureReport } from './maturity.js'
|
|
17
17
|
|
|
18
18
|
/** How long an edit settles before the server is asked again. One question per pause, not one per keystroke. */
|
|
19
19
|
export const VERDICT_SETTLE_MS = 400
|
|
@@ -28,7 +28,7 @@ export const VERDICT_SETTLE_MS = 400
|
|
|
28
28
|
*
|
|
29
29
|
* ## What is computed where
|
|
30
30
|
*
|
|
31
|
-
* The numbers come from `
|
|
31
|
+
* The numbers come from `maturity.ts`, which reads the evaluated asset the way the renderer draws it — the
|
|
32
32
|
* screen calls and shows, it does not count. The count uses the same `capacityFrom` the catalogue cards use, so the
|
|
33
33
|
* tab and the card cannot disagree.
|
|
34
34
|
*
|
|
@@ -38,16 +38,16 @@ export const VERDICT_SETTLE_MS = 400
|
|
|
38
38
|
*
|
|
39
39
|
* ## The grade
|
|
40
40
|
*
|
|
41
|
-
* figure-model's `
|
|
41
|
+
* figure-model's `figureScoreOf`, which the catalogue uses too: headroom against placing `LIMITS.screenInstances` of the
|
|
42
42
|
* figure on one screen (chief architect, 2026-09-24) -- the screen's measured groups and its triangle target shared
|
|
43
43
|
* per instance -- and the rule limits for independently moved parts and transparent materials, decided by the
|
|
44
|
-
* tightest. The two budgets
|
|
44
|
+
* tightest. The two budgets has no field for are left out and the tab says so.
|
|
45
45
|
*/
|
|
46
46
|
/** A per-instance share of the screen is not a whole number; what an instance may draw is the whole part of it. */
|
|
47
|
-
const limitOf = (use:
|
|
47
|
+
const limitOf = (use: FigureBudgetUse) => Math.floor(use.limit).toLocaleString()
|
|
48
48
|
|
|
49
|
-
@customElement('figure-
|
|
50
|
-
export class
|
|
49
|
+
@customElement('figure-verdict')
|
|
50
|
+
export class FigureVerdict extends localize(i18next)(LitElement) {
|
|
51
51
|
static styles = [
|
|
52
52
|
ScrollbarStyles,
|
|
53
53
|
SidePanelStyles,
|
|
@@ -384,7 +384,7 @@ export class FigureV3Verdict extends localize(i18next)(LitElement) {
|
|
|
384
384
|
@property({ type: String }) figureType?: string
|
|
385
385
|
|
|
386
386
|
/** The report over the source being edited. Absent when nothing is drawn, or the format refuses the source. */
|
|
387
|
-
@state() private report?:
|
|
387
|
+
@state() private report?: FigureReport
|
|
388
388
|
/** Bodies in the asset, drawn or hidden. With none there is nothing to fit the space to, so the button is not offered. */
|
|
389
389
|
@state() private bodies = 0
|
|
390
390
|
/** Whether the trend chart is open at its own size. */
|
|
@@ -408,13 +408,13 @@ export class FigureV3Verdict extends localize(i18next)(LitElement) {
|
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
private measure() {
|
|
411
|
-
let report:
|
|
411
|
+
let report: FigureReport | undefined
|
|
412
412
|
let bodies = 0
|
|
413
413
|
try {
|
|
414
|
-
const asset = this.source ?
|
|
415
|
-
const cost = asset ?
|
|
414
|
+
const asset = this.source ? parseFigureAsset(this.source) : undefined
|
|
415
|
+
const cost = asset ? figureCostOf(asset) : undefined
|
|
416
416
|
bodies = cost ? cost.groups + cost.hidden : 0
|
|
417
|
-
report = asset ?
|
|
417
|
+
report = asset ? figureReportOf(asset) : undefined
|
|
418
418
|
} catch {
|
|
419
419
|
/* A source the format refuses has no report; the server's finding below says why. */
|
|
420
420
|
report = undefined
|
|
@@ -481,7 +481,7 @@ export class FigureV3Verdict extends localize(i18next)(LitElement) {
|
|
|
481
481
|
* The count's denominator is measured (2026-09-18, Apple M5) and says so with the machine and the date; the
|
|
482
482
|
* triangle side is still the design document's target and says that.
|
|
483
483
|
*/
|
|
484
|
-
private renderVerdict(report:
|
|
484
|
+
private renderVerdict(report: FigureReport) {
|
|
485
485
|
const { capacity, score } = report
|
|
486
486
|
return html`
|
|
487
487
|
<section>
|
|
@@ -508,8 +508,8 @@ export class FigureV3Verdict extends localize(i18next)(LitElement) {
|
|
|
508
508
|
<p basis>
|
|
509
509
|
${i18next.t('figure.text.grade-target', {
|
|
510
510
|
target: LIMITS.screenInstances,
|
|
511
|
-
groups: Math.floor(
|
|
512
|
-
triangles: Math.floor(
|
|
511
|
+
groups: Math.floor(FIGURE_PER_INSTANCE.groups),
|
|
512
|
+
triangles: Math.floor(FIGURE_PER_INSTANCE.triangles).toLocaleString()
|
|
513
513
|
})}
|
|
514
514
|
</p>
|
|
515
515
|
${this.renderGradeScale(score.grade)}
|
|
@@ -544,7 +544,7 @@ export class FigureV3Verdict extends localize(i18next)(LitElement) {
|
|
|
544
544
|
*
|
|
545
545
|
* Scale is left out of the list: it leads the tab, and the same number twice reads as two different things.
|
|
546
546
|
*/
|
|
547
|
-
private renderAxes(report:
|
|
547
|
+
private renderAxes(report: FigureReport) {
|
|
548
548
|
const measured = report.axes.filter(axis => axis.ratio !== undefined)
|
|
549
549
|
const unmeasured = report.axes.filter(axis => axis.ratio === undefined)
|
|
550
550
|
return html`
|
|
@@ -566,7 +566,7 @@ export class FigureV3Verdict extends localize(i18next)(LitElement) {
|
|
|
566
566
|
}
|
|
567
567
|
|
|
568
568
|
/** The radar: rings at a third, two thirds and full, short names so the left edge is not cut. */
|
|
569
|
-
private renderRadar(axes:
|
|
569
|
+
private renderRadar(axes: FigureMaturityAxis[]) {
|
|
570
570
|
const cx = 60
|
|
571
571
|
const cy = 46
|
|
572
572
|
const r = 28
|
|
@@ -600,7 +600,7 @@ export class FigureV3Verdict extends localize(i18next)(LitElement) {
|
|
|
600
600
|
`
|
|
601
601
|
}
|
|
602
602
|
|
|
603
|
-
private renderAxis(axis:
|
|
603
|
+
private renderAxis(axis: FigureMaturityAxis) {
|
|
604
604
|
const name = i18next.t('figure.label.axis-' + axis.key)
|
|
605
605
|
if (axis.blocked) {
|
|
606
606
|
return html`
|
|
@@ -623,7 +623,7 @@ export class FigureV3Verdict extends localize(i18next)(LitElement) {
|
|
|
623
623
|
}
|
|
624
624
|
|
|
625
625
|
/** The budget bars. The one closest to its limit is coloured — it decided the grade. */
|
|
626
|
-
private renderBudgets(report:
|
|
626
|
+
private renderBudgets(report: FigureReport) {
|
|
627
627
|
const { score } = report
|
|
628
628
|
return html`
|
|
629
629
|
<section>
|
|
@@ -639,12 +639,12 @@ export class FigureV3Verdict extends localize(i18next)(LitElement) {
|
|
|
639
639
|
`
|
|
640
640
|
)}
|
|
641
641
|
</ul>
|
|
642
|
-
<p quiet>${i18next.t('figure.text.budgets-not-in
|
|
642
|
+
<p quiet>${i18next.t('figure.text.budgets-not-in')}</p>
|
|
643
643
|
</section>
|
|
644
644
|
`
|
|
645
645
|
}
|
|
646
646
|
|
|
647
|
-
private renderMetrics(report:
|
|
647
|
+
private renderMetrics(report: FigureReport) {
|
|
648
648
|
return html`
|
|
649
649
|
<section>
|
|
650
650
|
<h3>${i18next.t('figure.label.weight')}</h3>
|
|
@@ -673,7 +673,7 @@ export class FigureV3Verdict extends localize(i18next)(LitElement) {
|
|
|
673
673
|
* The trend at its own size: both axes logarithmic, the growing lines against the flat ones, and a
|
|
674
674
|
* legend with each line's value at the last count.
|
|
675
675
|
*/
|
|
676
|
-
private renderSheet(report:
|
|
676
|
+
private renderSheet(report: FigureReport) {
|
|
677
677
|
if (!this.expanded) return nothing
|
|
678
678
|
const layout = curveLayout(report.curve)
|
|
679
679
|
if (!layout) return nothing
|
|
@@ -6,8 +6,8 @@ import type { FigureGateFinding } from '../types.js'
|
|
|
6
6
|
/**
|
|
7
7
|
* One release-gate finding as a line on screen — the measured fact, where, why it matters, and what to change.
|
|
8
8
|
*
|
|
9
|
-
* Two places draw these: the release panel (`figure-history-panel`) and the
|
|
10
|
-
* (`figure-
|
|
9
|
+
* Two places draw these: the release panel (`figure-history-panel`) and the modeller's verdict while editing
|
|
10
|
+
* (`figure-verdict`). They show the same findings from the same server door, so they draw them one way; a copy
|
|
11
11
|
* in each would drift the first time one of them is touched. The caller passes its own action buttons, because
|
|
12
12
|
* what can be done about a finding depends on the screen it is shown on.
|
|
13
13
|
*/
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
1
|
+
import { figureAttachmentsOf } from '@hatiolab/figure-model'
|
|
2
|
+
import type { FigureAsset, FigureInputChange } from '@hatiolab/figure-model'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* What the gizmo may write for a part: move · turn · size, on a
|
|
5
|
+
* What the gizmo may write for a part: move · turn · size, on a asset.
|
|
6
6
|
*
|
|
7
7
|
* A drag can only be written back where the part is placed by its own numbers. A part the create commands made is:
|
|
8
8
|
* its pose is `rigid@1` into the asset frame from `<part>.position.*` and `<part>.rotation.*`, and a box's shape
|
|
9
9
|
* (`box-shape@1` or `rounded-box@1`) takes its width, height and depth from inputs of its own — `<part>.size.*` from
|
|
10
|
-
* `
|
|
10
|
+
* `addFigureBox`, `<part>.dimension.*` from the editor's shape palette. A part fastened to another, following an instance size or placed by
|
|
11
11
|
* expressions has no such numbers; the gizmo does not offer what it could not write back, rather
|
|
12
12
|
* than move something the next evaluation would put back.
|
|
13
13
|
*/
|
|
@@ -61,7 +61,7 @@ export function gizmoReachOf(asset: AssetLike, part: string): GizmoReach {
|
|
|
61
61
|
!!pose &&
|
|
62
62
|
pose.op === 'rigid@1' &&
|
|
63
63
|
!nodes.some(node => node.id === `${part}.motion`) &&
|
|
64
|
-
|
|
64
|
+
figureAttachmentsOf(asset as unknown as FigureAsset)[part] === null
|
|
65
65
|
const posed = direct || reseated
|
|
66
66
|
const shape = nodes.find(node => node.id === `${part}.shape`)
|
|
67
67
|
const mine = (ids: string[]) => ids.every(id => id.startsWith(`${part}.`) && design.has(id))
|
|
@@ -111,10 +111,10 @@ export interface GizmoResult {
|
|
|
111
111
|
* The input changes a drag makes — one list, applied as one step. Millimetres to the millimetre and degrees to a
|
|
112
112
|
* tenth (a drag otherwise stores 722.4180046035418 mm). A size never goes below 1 mm.
|
|
113
113
|
*/
|
|
114
|
-
export function gizmoChanges(part: string, reach: GizmoReach, result: GizmoResult, sizes: Record<string, number>):
|
|
115
|
-
const changes:
|
|
116
|
-
const put = (input: string, unit:
|
|
117
|
-
changes.push({ kind: 'set-design', input, unit, value } as
|
|
114
|
+
export function gizmoChanges(part: string, reach: GizmoReach, result: GizmoResult, sizes: Record<string, number>): FigureInputChange[] {
|
|
115
|
+
const changes: FigureInputChange[] = []
|
|
116
|
+
const put = (input: string, unit: FigureInputChange['unit'], value: number) =>
|
|
117
|
+
changes.push({ kind: 'set-design', input, unit, value } as FigureInputChange)
|
|
118
118
|
if (result.position && reach.translate)
|
|
119
119
|
AXES.forEach((axis, i) => put(`${part}.position.${axis}`, 'mm', Math.round(result.position![i]!)))
|
|
120
120
|
if (result.rotation && reach.rotate)
|
|
@@ -144,7 +144,7 @@ export function gizmoChanges(part: string, reach: GizmoReach, result: GizmoResul
|
|
|
144
144
|
* face): the part's own Y position moves by half the change. A post typed 2200 tall sank 933 mm under the floor
|
|
145
145
|
* (2026-09-26). Only for a part placed by its own numbers and standing unturned; otherwise its height is not up and down.
|
|
146
146
|
*/
|
|
147
|
-
export function keepBottomChanges(part: string, reach: GizmoReach, input: string, value: number, values: Record<string, number>):
|
|
147
|
+
export function keepBottomChanges(part: string, reach: GizmoReach, input: string, value: number, values: Record<string, number>): FigureInputChange[] {
|
|
148
148
|
if (!reach.translate) return []
|
|
149
149
|
const height = reach.sizes?.[1] ?? reach.ownSizes?.[1] ?? reach.round?.along[0]
|
|
150
150
|
if (!height || height !== input) return []
|
|
@@ -152,5 +152,5 @@ export function keepBottomChanges(part: string, reach: GizmoReach, input: string
|
|
|
152
152
|
const before = values[input],
|
|
153
153
|
y = values[`${part}.position.y`]
|
|
154
154
|
if (before === undefined || y === undefined || !Number.isFinite(value)) return []
|
|
155
|
-
return [{ kind: 'set-design', input: `${part}.position.y`, unit: 'mm', value: Math.round((y + (value - before) / 2) * 10) / 10 } as
|
|
155
|
+
return [{ kind: 'set-design', input: `${part}.position.y`, unit: 'mm', value: Math.round((y + (value - before) / 2) * 10) / 10 } as FigureInputChange]
|
|
156
156
|
}
|