@things-factory/figure-ui 10.1.44 → 10.1.46
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/figure-v3-links.ts +394 -0
- package/client/modeller/modeller-route.ts +6 -21
- package/client/modeller/v3-editor.ts +47 -5
- package/client/modeller/v3-gizmo.ts +13 -2
- package/client/modeller/v3-links.ts +170 -0
- package/client/pages/figure-v3-modeller-page.ts +2 -5
- package/client/route.ts +2 -6
- package/dist-client/modeller/figure-v3-links.d.ts +47 -0
- package/dist-client/modeller/figure-v3-links.js +379 -0
- package/dist-client/modeller/figure-v3-links.js.map +1 -0
- package/dist-client/modeller/modeller-route.d.ts +4 -11
- package/dist-client/modeller/modeller-route.js +5 -22
- package/dist-client/modeller/modeller-route.js.map +1 -1
- package/dist-client/modeller/v3-editor.d.ts +5 -0
- package/dist-client/modeller/v3-editor.js +49 -4
- package/dist-client/modeller/v3-editor.js.map +1 -1
- package/dist-client/modeller/v3-gizmo.js +11 -1
- package/dist-client/modeller/v3-gizmo.js.map +1 -1
- package/dist-client/modeller/v3-links.d.ts +67 -0
- package/dist-client/modeller/v3-links.js +141 -0
- package/dist-client/modeller/v3-links.js.map +1 -0
- package/dist-client/pages/figure-v3-modeller-page.d.ts +2 -5
- package/dist-client/pages/figure-v3-modeller-page.js +2 -5
- package/dist-client/pages/figure-v3-modeller-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +2 -5
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.scratch-fm.tsbuildinfo +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/test/ai-proposal-contract.test.ts +0 -88
- package/test/figure-source.test.ts +0 -102
- package/test/i18n-prefix-guard.test.ts +0 -24
- package/test/modeller-route.test.ts +14 -25
- package/test/part-edits.test.ts +0 -7
- package/test/scene-budget.test.ts +0 -7
- package/test/v3-gizmo.test.ts +10 -0
- package/test/v3-links.test.ts +163 -0
- package/things-factory.config.js +2 -5
- package/translations/en.json +21 -1
- package/translations/ja.json +21 -1
- package/translations/ko.json +21 -1
- package/translations/ms.json +21 -1
- package/translations/zh.json +21 -1
- package/client/modeller/angle-dial.ts +0 -70
- package/client/modeller/base-box.ts +0 -175
- package/client/modeller/figure-animations.ts +0 -1249
- package/client/modeller/figure-canvas.ts +0 -567
- package/client/modeller/figure-capabilities.ts +0 -379
- package/client/modeller/figure-inspector.ts +0 -2208
- package/client/modeller/figure-parts.ts +0 -479
- package/client/modeller/figure-preview.ts +0 -598
- package/client/modeller/figure-report.ts +0 -966
- package/client/modeller/figure-settings.ts +0 -328
- package/client/modeller/figure-side.ts +0 -272
- package/client/modeller/figure-thumbnail.ts +0 -123
- package/client/modeller/figure-view.ts +0 -152
- package/client/modeller/joint-edits.ts +0 -262
- package/client/modeller/joint-gizmo.ts +0 -180
- package/client/modeller/maturity.ts +0 -288
- package/client/modeller/new-figure-entry.ts +0 -4
- package/client/modeller/pose-defaults.ts +0 -67
- package/client/pages/figure-modeller-page.ts +0 -2082
- package/dist-client/modeller/angle-dial.d.ts +0 -32
- package/dist-client/modeller/angle-dial.js +0 -41
- package/dist-client/modeller/angle-dial.js.map +0 -1
- package/dist-client/modeller/base-box.d.ts +0 -71
- package/dist-client/modeller/base-box.js +0 -110
- package/dist-client/modeller/base-box.js.map +0 -1
- package/dist-client/modeller/figure-animations.d.ts +0 -159
- package/dist-client/modeller/figure-animations.js +0 -1132
- package/dist-client/modeller/figure-animations.js.map +0 -1
- package/dist-client/modeller/figure-canvas.d.ts +0 -150
- package/dist-client/modeller/figure-canvas.js +0 -506
- package/dist-client/modeller/figure-canvas.js.map +0 -1
- package/dist-client/modeller/figure-capabilities.d.ts +0 -42
- package/dist-client/modeller/figure-capabilities.js +0 -349
- package/dist-client/modeller/figure-capabilities.js.map +0 -1
- package/dist-client/modeller/figure-inspector.d.ts +0 -329
- package/dist-client/modeller/figure-inspector.js +0 -2095
- package/dist-client/modeller/figure-inspector.js.map +0 -1
- package/dist-client/modeller/figure-parts.d.ts +0 -64
- package/dist-client/modeller/figure-parts.js +0 -478
- package/dist-client/modeller/figure-parts.js.map +0 -1
- package/dist-client/modeller/figure-preview.d.ts +0 -138
- package/dist-client/modeller/figure-preview.js +0 -549
- package/dist-client/modeller/figure-preview.js.map +0 -1
- package/dist-client/modeller/figure-report.d.ts +0 -165
- package/dist-client/modeller/figure-report.js +0 -952
- package/dist-client/modeller/figure-report.js.map +0 -1
- package/dist-client/modeller/figure-settings.d.ts +0 -39
- package/dist-client/modeller/figure-settings.js +0 -317
- package/dist-client/modeller/figure-settings.js.map +0 -1
- package/dist-client/modeller/figure-side.d.ts +0 -78
- package/dist-client/modeller/figure-side.js +0 -317
- package/dist-client/modeller/figure-side.js.map +0 -1
- package/dist-client/modeller/figure-thumbnail.d.ts +0 -3
- package/dist-client/modeller/figure-thumbnail.js +0 -95
- package/dist-client/modeller/figure-thumbnail.js.map +0 -1
- package/dist-client/modeller/figure-view.d.ts +0 -118
- package/dist-client/modeller/figure-view.js +0 -78
- package/dist-client/modeller/figure-view.js.map +0 -1
- package/dist-client/modeller/joint-edits.d.ts +0 -49
- package/dist-client/modeller/joint-edits.js +0 -223
- package/dist-client/modeller/joint-edits.js.map +0 -1
- package/dist-client/modeller/joint-gizmo.d.ts +0 -34
- package/dist-client/modeller/joint-gizmo.js +0 -158
- package/dist-client/modeller/joint-gizmo.js.map +0 -1
- package/dist-client/modeller/maturity.d.ts +0 -55
- package/dist-client/modeller/maturity.js +0 -212
- package/dist-client/modeller/maturity.js.map +0 -1
- package/dist-client/modeller/new-figure-entry.d.ts +0 -2
- package/dist-client/modeller/new-figure-entry.js +0 -5
- package/dist-client/modeller/new-figure-entry.js.map +0 -1
- package/dist-client/modeller/pose-defaults.d.ts +0 -9
- package/dist-client/modeller/pose-defaults.js +0 -35
- package/dist-client/modeller/pose-defaults.js.map +0 -1
- package/dist-client/pages/figure-modeller-page.d.ts +0 -419
- package/dist-client/pages/figure-modeller-page.js +0 -2060
- package/dist-client/pages/figure-modeller-page.js.map +0 -1
- package/test/angle-dial.test.ts +0 -78
- package/test/base-box.test.ts +0 -235
- package/test/joint-edits.test.ts +0 -165
- package/test/joint-gizmo.test.ts +0 -174
- package/test/joint-needle.test.ts +0 -162
- package/test/modeller-undo-redo.test.ts +0 -33
- package/test/new-figure-entry.test.ts +0 -15
- package/test/pose-defaults.test.ts +0 -71
- package/test/preview-board-depth.test.ts +0 -27
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
import { css, html, LitElement } from 'lit'
|
|
2
|
-
import { customElement, property } from 'lit/decorators.js'
|
|
3
|
-
|
|
4
|
-
import { i18next, localize } from '@operato/i18n'
|
|
5
|
-
import { ScrollbarStyles } from '@operato/styles'
|
|
6
|
-
|
|
7
|
-
import { DEFAULT_VIEW, ENVIRONMENTS, SCENE_REFERENCES } from './figure-view.js'
|
|
8
|
-
import type { EnvironmentName, ViewSettings } from './figure-view.js'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 저작 화면의 **보기 설정**.
|
|
12
|
-
*
|
|
13
|
-
* ## 자산이 아니라 작업대다
|
|
14
|
-
*
|
|
15
|
-
* 여기서 고치는 것은 저장되지 않는다. 조명을 밝게 하고 바닥을 켠 것은 지금 보기 편한
|
|
16
|
-
* 상태일 뿐이다. 그래서 「저장 안 됨」을 화면에 적어 둔다 — 안 적으면 저작자가 조명을
|
|
17
|
-
* 맞춰 두고 그것이 자산에 딸려 간다고 여긴다.
|
|
18
|
-
*
|
|
19
|
-
* ## 값을 들고 있지 않는다
|
|
20
|
-
*
|
|
21
|
-
* 이 패널은 받은 것을 그리고 바뀐 것을 알린다. 정본은 모델러 페이지가 갖는다 — 속성
|
|
22
|
-
* 패널과 같은 방식이다. 여기서 들고 있으면 페이지가 다시 그릴 때 두 벌이 갈린다.
|
|
23
|
-
*/
|
|
24
|
-
@customElement('figure-settings')
|
|
25
|
-
export class FigureSettings extends localize(i18next)(LitElement) {
|
|
26
|
-
static styles = [
|
|
27
|
-
ScrollbarStyles,
|
|
28
|
-
css`
|
|
29
|
-
:host {
|
|
30
|
-
display: flex;
|
|
31
|
-
flex-direction: column;
|
|
32
|
-
min-height: 0;
|
|
33
|
-
overflow-y: auto;
|
|
34
|
-
background-color: var(--md-sys-color-surface-container-lowest);
|
|
35
|
-
color: var(--md-sys-color-on-surface);
|
|
36
|
-
font: var(--label-font, inherit);
|
|
37
|
-
font-size: 0.76rem;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
section {
|
|
41
|
-
display: flex;
|
|
42
|
-
flex-direction: column;
|
|
43
|
-
gap: var(--spacing-medium, 8px);
|
|
44
|
-
padding: var(--spacing-large, 12px);
|
|
45
|
-
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/* 속성 패널의 묶음 제목과 같은 규격이다 — 두 탭이 다른 눈금을 쓰면 따로 논다 */
|
|
49
|
-
h3 {
|
|
50
|
-
margin: 0 0 2px 0;
|
|
51
|
-
font-size: var(--ui-t-micro, 11px);
|
|
52
|
-
font-weight: 700;
|
|
53
|
-
letter-spacing: 0.04em;
|
|
54
|
-
text-transform: uppercase;
|
|
55
|
-
color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/* 저장되지 않는다는 것을 한 번 말해 둔다 */
|
|
59
|
-
p[quiet] {
|
|
60
|
-
margin: 0;
|
|
61
|
-
font-size: 0.72rem;
|
|
62
|
-
line-height: 1.5;
|
|
63
|
-
color: var(--md-sys-color-on-surface-variant);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
label[row] {
|
|
67
|
-
display: flex;
|
|
68
|
-
align-items: center;
|
|
69
|
-
justify-content: space-between;
|
|
70
|
-
gap: var(--spacing-medium, 8px);
|
|
71
|
-
cursor: pointer;
|
|
72
|
-
}
|
|
73
|
-
label[row] span {
|
|
74
|
-
display: flex;
|
|
75
|
-
flex-direction: column;
|
|
76
|
-
}
|
|
77
|
-
label[row] em {
|
|
78
|
-
font-style: normal;
|
|
79
|
-
font-size: 0.7rem;
|
|
80
|
-
color: var(--md-sys-color-on-surface-variant);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
input[type='checkbox'] {
|
|
84
|
-
flex: none;
|
|
85
|
-
width: 16px;
|
|
86
|
-
height: 16px;
|
|
87
|
-
margin: 0;
|
|
88
|
-
accent-color: var(--md-sys-color-primary);
|
|
89
|
-
cursor: pointer;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
label[field] {
|
|
93
|
-
display: flex;
|
|
94
|
-
flex-direction: column;
|
|
95
|
-
gap: 4px;
|
|
96
|
-
}
|
|
97
|
-
label[field] > span {
|
|
98
|
-
color: var(--md-sys-color-on-surface-variant);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
select,
|
|
102
|
-
input[type='number'],
|
|
103
|
-
input[type='color'] {
|
|
104
|
-
width: 100%;
|
|
105
|
-
padding: 5px 6px;
|
|
106
|
-
font: var(--input-field-font, inherit);
|
|
107
|
-
font-size: 0.76rem;
|
|
108
|
-
color: var(--md-sys-color-on-surface);
|
|
109
|
-
background-color: var(--md-sys-color-surface);
|
|
110
|
-
border: 1px solid var(--md-sys-color-outline-variant);
|
|
111
|
-
border-radius: 4px;
|
|
112
|
-
}
|
|
113
|
-
input[type='color'] {
|
|
114
|
-
height: 30px;
|
|
115
|
-
padding: 2px;
|
|
116
|
-
cursor: pointer;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/* 값이 옆에 붙어야 끌면서 얼마인지 안다 */
|
|
120
|
-
div[slider] {
|
|
121
|
-
display: flex;
|
|
122
|
-
align-items: center;
|
|
123
|
-
gap: var(--spacing-medium, 8px);
|
|
124
|
-
}
|
|
125
|
-
input[type='range'] {
|
|
126
|
-
flex: 1;
|
|
127
|
-
accent-color: var(--md-sys-color-primary);
|
|
128
|
-
cursor: pointer;
|
|
129
|
-
}
|
|
130
|
-
div[slider] output {
|
|
131
|
-
flex: none;
|
|
132
|
-
width: 2.4em;
|
|
133
|
-
text-align: right;
|
|
134
|
-
font: var(--mono-font, ui-monospace, monospace);
|
|
135
|
-
font-size: 0.72rem;
|
|
136
|
-
color: var(--md-sys-color-on-surface-variant);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
button[reset] {
|
|
140
|
-
align-self: flex-start;
|
|
141
|
-
padding: 5px 12px;
|
|
142
|
-
font: var(--label-font, inherit);
|
|
143
|
-
font-size: 0.74rem;
|
|
144
|
-
color: var(--md-sys-color-on-surface-variant);
|
|
145
|
-
background: none;
|
|
146
|
-
border: 1px solid var(--md-sys-color-outline-variant);
|
|
147
|
-
border-radius: 4px;
|
|
148
|
-
cursor: pointer;
|
|
149
|
-
}
|
|
150
|
-
button[reset]:hover {
|
|
151
|
-
background-color: var(--md-sys-color-surface-container);
|
|
152
|
-
}
|
|
153
|
-
`
|
|
154
|
-
]
|
|
155
|
-
|
|
156
|
-
@property({ type: Object }) view: ViewSettings = DEFAULT_VIEW
|
|
157
|
-
|
|
158
|
-
render() {
|
|
159
|
-
const view = this.view ?? DEFAULT_VIEW
|
|
160
|
-
|
|
161
|
-
return html`
|
|
162
|
-
<!--
|
|
163
|
-
놓이는 도면.
|
|
164
|
-
|
|
165
|
-
이 묶음이 맨 위인 것은, 나머지가 「어떻게 보이나」인데 이것은 「무엇으로 보고
|
|
166
|
-
있나」이기 때문이다. 미리보기가 도면에 놓인 모습을 말하는 자리이므로, 어떤 도면을
|
|
167
|
-
가정하는지가 먼저 정해져야 그 다음이 뜻을 갖는다.
|
|
168
|
-
|
|
169
|
-
도형 탭의 「배치 기준」과 짝이지 같은 것이 아니다. 저쪽은 이 도형이 어느 면에
|
|
170
|
-
붙는가(저장된다), 이쪽은 그 면을 가진 도면이 어느 쪽을 기준으로 재는가(저장 안 된다).
|
|
171
|
-
-->
|
|
172
|
-
<section>
|
|
173
|
-
<h3>${i18next.t('figure.label.assumed-drawing')}</h3>
|
|
174
|
-
<p quiet>${i18next.t('figure.text.view-settings-are-not-saved')}</p>
|
|
175
|
-
|
|
176
|
-
<label field>
|
|
177
|
-
<span>${i18next.t('figure.label.scene-reference')}</span>
|
|
178
|
-
<select
|
|
179
|
-
.value=${view.placement}
|
|
180
|
-
@change=${(e: Event) =>
|
|
181
|
-
this.put({ placement: (e.target as HTMLSelectElement).value as ViewSettings['placement'] })}
|
|
182
|
-
>
|
|
183
|
-
${SCENE_REFERENCES.map(
|
|
184
|
-
name => html`<option value=${name} ?selected=${view.placement === name}>
|
|
185
|
-
${i18next.t(`figure.label.scene-reference-${name}`)}
|
|
186
|
-
</option>`
|
|
187
|
-
)}
|
|
188
|
-
</select>
|
|
189
|
-
</label>
|
|
190
|
-
<p quiet>${i18next.t('figure.text.scene-reference-explained')}</p>
|
|
191
|
-
|
|
192
|
-
<label field>
|
|
193
|
-
<span>${i18next.t('figure.label.ceiling-height')}</span>
|
|
194
|
-
<input
|
|
195
|
-
type="number"
|
|
196
|
-
min="0"
|
|
197
|
-
step="100"
|
|
198
|
-
.value=${String(view.ceilingHeight)}
|
|
199
|
-
@change=${(e: Event) => this.put({ ceilingHeight: Number((e.target as HTMLInputElement).value) || 0 })}
|
|
200
|
-
/>
|
|
201
|
-
</label>
|
|
202
|
-
<p quiet>${i18next.t('figure.text.ceiling-height-explained')}</p>
|
|
203
|
-
</section>
|
|
204
|
-
|
|
205
|
-
<section>
|
|
206
|
-
<h3>${i18next.t('figure.label.guides')}</h3>
|
|
207
|
-
|
|
208
|
-
${this.toggle('grid', view.grid, i18next.t('figure.label.coordinate-ground'), i18next.t('figure.text.coordinate-ground-explained'))}
|
|
209
|
-
${this.toggle('gridLabels', view.gridLabels, i18next.t('figure.label.axis-labels'))}
|
|
210
|
-
${this.toggle('floor', view.floor, i18next.t('figure.label.scene-floor'), i18next.t('figure.text.floor-explained'))}
|
|
211
|
-
</section>
|
|
212
|
-
|
|
213
|
-
<section>
|
|
214
|
-
<h3>${i18next.t('figure.label.environment')}</h3>
|
|
215
|
-
|
|
216
|
-
<label field>
|
|
217
|
-
<span>${i18next.t('figure.label.preset')}</span>
|
|
218
|
-
<select
|
|
219
|
-
.value=${view.environment}
|
|
220
|
-
@change=${(e: Event) => this.put({ environment: (e.target as HTMLSelectElement).value as EnvironmentName })}
|
|
221
|
-
>
|
|
222
|
-
${ENVIRONMENTS.map(
|
|
223
|
-
name => html`<option value=${name} ?selected=${view.environment === name}>
|
|
224
|
-
${i18next.t(`figure.label.environment-${name}`)}
|
|
225
|
-
</option>`
|
|
226
|
-
)}
|
|
227
|
-
</select>
|
|
228
|
-
</label>
|
|
229
|
-
<p quiet>${i18next.t('figure.text.environment-explained')}</p>
|
|
230
|
-
|
|
231
|
-
<label field>
|
|
232
|
-
<span>${i18next.t('figure.label.sky-color')}</span>
|
|
233
|
-
<input
|
|
234
|
-
type="color"
|
|
235
|
-
.value=${view.skyColor}
|
|
236
|
-
@change=${(e: Event) => this.put({ skyColor: (e.target as HTMLInputElement).value })}
|
|
237
|
-
/>
|
|
238
|
-
</label>
|
|
239
|
-
</section>
|
|
240
|
-
|
|
241
|
-
<section>
|
|
242
|
-
<h3>${i18next.t('figure.label.key-light')}</h3>
|
|
243
|
-
|
|
244
|
-
${this.slider('dirLightIntensity', view.dirLightIntensity, i18next.t('figure.label.intensity'), 0, 5, 0.1)}
|
|
245
|
-
${this.toggle(
|
|
246
|
-
'dirLightFollowCamera',
|
|
247
|
-
view.dirLightFollowCamera,
|
|
248
|
-
i18next.t('figure.label.follow-camera'),
|
|
249
|
-
i18next.t('figure.text.follow-camera-explained')
|
|
250
|
-
)}
|
|
251
|
-
${this.toggle('dirShadowEnabled', view.dirShadowEnabled, i18next.t('figure.label.cast-shadow'))}
|
|
252
|
-
${view.dirLightIntensity === 0 && view.hemiIntensity === 0
|
|
253
|
-
? html`<p quiet>${i18next.t('figure.text.all-lights-off')}</p>`
|
|
254
|
-
: ''}
|
|
255
|
-
</section>
|
|
256
|
-
|
|
257
|
-
<section>
|
|
258
|
-
<h3>${i18next.t('figure.label.hemisphere-light')}</h3>
|
|
259
|
-
|
|
260
|
-
${this.slider('hemiIntensity', view.hemiIntensity, i18next.t('figure.label.intensity'), 0, 8, 0.1)}
|
|
261
|
-
<p quiet>${i18next.t('figure.text.hemisphere-light-explained')}</p>
|
|
262
|
-
</section>
|
|
263
|
-
|
|
264
|
-
<section>
|
|
265
|
-
<button reset @click=${() => this.reset()}>${i18next.t('figure.button.reset-view')}</button>
|
|
266
|
-
</section>
|
|
267
|
-
`
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
private toggle(key: keyof ViewSettings, on: boolean, label: string, hint?: string) {
|
|
271
|
-
return html`
|
|
272
|
-
<label row>
|
|
273
|
-
<span>
|
|
274
|
-
${label}${hint ? html`<em>${hint}</em>` : ''}
|
|
275
|
-
</span>
|
|
276
|
-
<input
|
|
277
|
-
type="checkbox"
|
|
278
|
-
.checked=${on}
|
|
279
|
-
@change=${(e: Event) => this.put({ [key]: (e.target as HTMLInputElement).checked } as Partial<ViewSettings>)}
|
|
280
|
-
/>
|
|
281
|
-
</label>
|
|
282
|
-
`
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
private slider(key: keyof ViewSettings, value: number, label: string, min: number, max: number, step: number) {
|
|
286
|
-
return html`
|
|
287
|
-
<label field>
|
|
288
|
-
<span>${label}</span>
|
|
289
|
-
<div slider>
|
|
290
|
-
<input
|
|
291
|
-
type="range"
|
|
292
|
-
min=${min}
|
|
293
|
-
max=${max}
|
|
294
|
-
step=${step}
|
|
295
|
-
.value=${String(value)}
|
|
296
|
-
@input=${(e: Event) =>
|
|
297
|
-
this.put({ [key]: Number((e.target as HTMLInputElement).value) } as Partial<ViewSettings>)}
|
|
298
|
-
/>
|
|
299
|
-
<output>${value.toFixed(1)}</output>
|
|
300
|
-
</div>
|
|
301
|
-
</label>
|
|
302
|
-
`
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/** 처음 값으로 되돌린다. 만지다 길을 잃었을 때 돌아올 자리가 있어야 한다. */
|
|
306
|
-
private reset() {
|
|
307
|
-
this.tell({ ...DEFAULT_VIEW })
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
private put(patch: Partial<ViewSettings>) {
|
|
311
|
-
this.tell({ ...(this.view ?? DEFAULT_VIEW), ...patch })
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* 바뀐 것을 알린다.
|
|
316
|
-
*
|
|
317
|
-
* **알리기 전에 내 것도 바꿔 둔다.** Lit 은 속성을 다음 렌더에 넣으므로, 같은 프레임에
|
|
318
|
-
* 두 번 고치면 두 번째가 `this.view` 의 옛 값을 읽어 첫 번째를 덮는다. 실제로 그랬다 —
|
|
319
|
-
* 축 가이드를 끄고 바닥판을 켰더니 축 가이드가 도로 켜져 있었고, 화면의 체크 상자와
|
|
320
|
-
* 씬의 상태가 서로 다른 말을 했다.
|
|
321
|
-
*
|
|
322
|
-
* 정본은 여전히 모델러 페이지가 갖는다. 여기 값은 다음 렌더에 같은 것으로 덮인다.
|
|
323
|
-
*/
|
|
324
|
-
private tell(view: ViewSettings) {
|
|
325
|
-
this.view = view
|
|
326
|
-
this.dispatchEvent(new CustomEvent('update-view', { detail: { view }, bubbles: true, composed: true }))
|
|
327
|
-
}
|
|
328
|
-
}
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
import '@material/web/icon/icon.js'
|
|
2
|
-
import './figure-inspector.js'
|
|
3
|
-
import './figure-capabilities.js'
|
|
4
|
-
import './figure-animations.js'
|
|
5
|
-
import './figure-report.js'
|
|
6
|
-
import './figure-settings.js'
|
|
7
|
-
import './figure-history-panel.js'
|
|
8
|
-
|
|
9
|
-
import { css, html, LitElement } from 'lit'
|
|
10
|
-
import { customElement, property, state } from 'lit/decorators.js'
|
|
11
|
-
|
|
12
|
-
import { i18next, localize } from '@operato/i18n'
|
|
13
|
-
import type { ContractChange, FigureSource } from '@hatiolab/figure-model'
|
|
14
|
-
|
|
15
|
-
import type { FigureDraft, PartModel } from './figure-source.js'
|
|
16
|
-
import { DEFAULT_VIEW } from './figure-view.js'
|
|
17
|
-
import type { ViewSettings } from './figure-view.js'
|
|
18
|
-
|
|
19
|
-
type Tab = 'properties' | 'capability' | 'animation' | 'verdict' | 'view' | 'history'
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 저작면 오른쪽 칸 — 속성과 판정을 탭으로 겹쳐 둔다.
|
|
23
|
-
*
|
|
24
|
-
* ## 왜 위아래로 나누지 않나
|
|
25
|
-
*
|
|
26
|
-
* 둘 다 세로로 긴 화면이다. 위아래로 나누면 양쪽 다 잘려서, 속성은 재질까지 못
|
|
27
|
-
* 내려가고 판정은 무게까지 못 내려간다. 탭으로 겹치면 각자 칸 전체를 쓴다.
|
|
28
|
-
*
|
|
29
|
-
* ## 그래도 개수는 늘 보인다
|
|
30
|
-
*
|
|
31
|
-
* 성숙도의 축 하나 —「몇 개까지 편한가」— 는 부품을 고칠 때마다 움직이고, 그것이
|
|
32
|
-
* 보여야 저작자가 고칠 수 있다. 탭 뒤로 숨으면 저장하고 나서야 알게 된다. 그래서 그
|
|
33
|
-
* 숫자만 **탭 이름표에 남긴다** — 성숙도를 덮어 두고 속성을 만져도 따라 움직이는
|
|
34
|
-
* 것이 보인다.
|
|
35
|
-
*
|
|
36
|
-
* 판정은 화면에서 감춰도 **DOM 에는 남는다.** 떼었다 붙이면 다시 세느라 값이 잠깐
|
|
37
|
-
* 비고, 펼쳐 둔 추이 그림 같은 상태도 날아간다.
|
|
38
|
-
*/
|
|
39
|
-
@customElement('figure-side')
|
|
40
|
-
export class FigureSide extends localize(i18next)(LitElement) {
|
|
41
|
-
static styles = css`
|
|
42
|
-
:host {
|
|
43
|
-
display: flex;
|
|
44
|
-
flex-direction: column;
|
|
45
|
-
min-height: 0;
|
|
46
|
-
overflow: hidden;
|
|
47
|
-
background-color: var(--md-sys-color-surface-container-lowest);
|
|
48
|
-
border-left: 1px solid var(--md-sys-color-outline-variant);
|
|
49
|
-
color: var(--md-sys-color-on-surface);
|
|
50
|
-
font: var(--label-font, inherit);
|
|
51
|
-
/*
|
|
52
|
-
이 패널의 본문 크기를 여기서 한 번 정한다.
|
|
53
|
-
|
|
54
|
-
전에는 규칙마다 따로 적었다. 그러면 빠뜨린 규칙이 본문 기본 크기(1rem)를
|
|
55
|
-
물려받아 그 줄만 제목처럼 커진다. 오류가 아니라서 화면을 띄워 봐야 안다.
|
|
56
|
-
이 파일에서만 두 번 났다.
|
|
57
|
-
|
|
58
|
-
form 요소(input · select · button)는 글꼴을 물려받지 않으므로 각자 적어야 한다.
|
|
59
|
-
그것 말고는 여기 값을 따른다.
|
|
60
|
-
*/
|
|
61
|
-
font-size: 0.76rem;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
div[tabs] {
|
|
65
|
-
display: flex;
|
|
66
|
-
flex: none;
|
|
67
|
-
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
|
68
|
-
}
|
|
69
|
-
button[tab] {
|
|
70
|
-
flex: 1;
|
|
71
|
-
/*
|
|
72
|
-
**아이콘 하나가 한 칸을 쓴다.**
|
|
73
|
-
|
|
74
|
-
전에는 이름을 적었는데, 넷이 좁은 칸을 나눠 쓰면서 접혀 「성숙 / 도」가 되었다. 접히면
|
|
75
|
-
그 탭만 두 줄이 되어 높이가 서로 달라진다. 다섯이 되면서 더는 줄여 짜 넣을 수 없어
|
|
76
|
-
아이콘으로 바꿨고, 이름은 title 과 aria-label 로 남는다.
|
|
77
|
-
|
|
78
|
-
배지는 여전히 자리를 차지하지 않고 **아이콘 위에 겹친다**(아래 span[badge]). 개수는
|
|
79
|
-
곁들이는 것이다.
|
|
80
|
-
*/
|
|
81
|
-
position: relative;
|
|
82
|
-
display: flex;
|
|
83
|
-
align-items: center;
|
|
84
|
-
justify-content: center;
|
|
85
|
-
white-space: nowrap;
|
|
86
|
-
padding: 7px 6px;
|
|
87
|
-
color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
|
|
88
|
-
background: none;
|
|
89
|
-
border: none;
|
|
90
|
-
/* 고른 탭을 밑줄로 말한다 — 칸을 색으로 채우면 아래 내용과 경계가 흐려진다 */
|
|
91
|
-
border-bottom: 2px solid transparent;
|
|
92
|
-
cursor: pointer;
|
|
93
|
-
}
|
|
94
|
-
button[tab]:hover:not([on]) {
|
|
95
|
-
background-color: var(--md-sys-color-surface-container);
|
|
96
|
-
}
|
|
97
|
-
button[tab][on] {
|
|
98
|
-
font-weight: 700;
|
|
99
|
-
color: var(--md-sys-color-primary);
|
|
100
|
-
border-bottom-color: var(--md-sys-color-primary);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/*
|
|
104
|
-
판정을 덮어 두어도 개수는 여기 남는다.
|
|
105
|
-
|
|
106
|
-
자리를 먹지 않게 오른쪽 위에 겹쳐 둔다 — 탭 이름을 밀지 않으므로 이름이 접히지 않는다.
|
|
107
|
-
숫자가 커져도(1,200 같은 것) 이름 위로 넘칠 뿐 줄을 바꾸지 않는다.
|
|
108
|
-
*/
|
|
109
|
-
button[tab] md-icon {
|
|
110
|
-
font-size: 20px;
|
|
111
|
-
width: 20px;
|
|
112
|
-
height: 20px;
|
|
113
|
-
}
|
|
114
|
-
span[badge] {
|
|
115
|
-
position: absolute;
|
|
116
|
-
/* 이름 위에 겹치되 위로 붙지 않게 — 탭 가운데 글자와 눈높이를 조금 맞춘다 */
|
|
117
|
-
top: 5px;
|
|
118
|
-
right: 2px;
|
|
119
|
-
padding: 0 5px;
|
|
120
|
-
font-size: 0.62rem;
|
|
121
|
-
font-weight: 700;
|
|
122
|
-
line-height: 1.5;
|
|
123
|
-
color: var(--md-sys-color-on-primary-container);
|
|
124
|
-
background-color: var(--md-sys-color-primary-container);
|
|
125
|
-
border-radius: 999em;
|
|
126
|
-
pointer-events: none;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
figure-inspector,
|
|
130
|
-
figure-animations,
|
|
131
|
-
figure-report,
|
|
132
|
-
figure-settings {
|
|
133
|
-
flex: 1;
|
|
134
|
-
min-height: 0;
|
|
135
|
-
border-left: none;
|
|
136
|
-
}
|
|
137
|
-
/* 감추되 떼지는 않는다 */
|
|
138
|
-
[off] {
|
|
139
|
-
display: none;
|
|
140
|
-
}
|
|
141
|
-
`
|
|
142
|
-
|
|
143
|
-
/*
|
|
144
|
-
두 형태가 이 패널에서 갈린다.
|
|
145
|
-
|
|
146
|
-
속성은 **수정하는** 곳이라 편집 중인 씬 모델을 받는다. 판정은 **저장될 것을 측정하는**
|
|
147
|
-
곳이라 변환된 FigureSource 를 받는다. 변환은 모델러 페이지가 한 번만 해서 내려보낸다.
|
|
148
|
-
*/
|
|
149
|
-
@property({ type: String }) figureName = ''
|
|
150
|
-
/** 카탈로그 분류·태그. 속성 탭이 보여 주고 바꾼다. */
|
|
151
|
-
@property({ type: String }) figureCategory?: string
|
|
152
|
-
@property({ type: Array }) figureTags?: string[]
|
|
153
|
-
/** 이력 탭이 발행하고 되돌리는 데 필요한 것들. 정본은 저작면이 든다. */
|
|
154
|
-
@property({ type: String }) figureId?: string
|
|
155
|
-
@property({ type: String }) figureState?: 'draft' | 'released'
|
|
156
|
-
@property({ type: Number }) figureVersion = 0
|
|
157
|
-
@property({ type: Boolean }) dirty = false
|
|
158
|
-
|
|
159
|
-
@property({ type: Object }) draft?: FigureDraft
|
|
160
|
-
@property({ type: Array }) parts: PartModel[] = []
|
|
161
|
-
@property({ type: Object }) source?: FigureSource
|
|
162
|
-
|
|
163
|
-
/** 이 고침이 이미 놓인 인스턴스에 무엇을 하나(ADR-0063 결정 3). 발행 전 도형에는 비어 있다. */
|
|
164
|
-
@property({ type: Array }) contract: ContractChange[] = []
|
|
165
|
-
/** 직전 발행 기준 상자. 외형 변화 안내의 X·Z 복원 선택지에만 쓴다. */
|
|
166
|
-
@property({ type: Object }) releasedBase?: FigureSource['base']
|
|
167
|
-
|
|
168
|
-
/** 견주지 못한 까닭. 있으면 화면이 「확인하지 못했다」로 말한다. */
|
|
169
|
-
@property({ type: String }) contractFailure?: string
|
|
170
|
-
@property({ type: Number }) selected = -1
|
|
171
|
-
/** 저작 화면의 보기 설정. 자산이 아니라 작업대다 — 저장되지 않는다. */
|
|
172
|
-
@property({ type: Object }) view: ViewSettings = DEFAULT_VIEW
|
|
173
|
-
|
|
174
|
-
@state() private tab: Tab = 'properties'
|
|
175
|
-
/** 판정이 알려 준 개수. 탭 이름표에 붙는다. */
|
|
176
|
-
@state() private instances?: number
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* 이 도형이 든 clip 수. 탭 아이콘에 붙는다.
|
|
180
|
-
*
|
|
181
|
-
* 아이콘만으로는 「여기에 무언가 있다」를 알 수 없다. 대부분의 도형은 움직이지 않으므로
|
|
182
|
-
* 이 탭은 늘 비어 있을 것이고, 그러면 움직이는 도형을 열었을 때 그 사실이 눈에 걸려야 한다.
|
|
183
|
-
* 0 이면 아무것도 안 붙인다 — 「0」을 붙이면 없는 것이 있는 것처럼 자리를 차지한다.
|
|
184
|
-
*/
|
|
185
|
-
private get clipCount(): number | undefined {
|
|
186
|
-
const n = (this.draft?.animations?.length ?? 0) + (this.draft?.parameters?.length ?? 0)
|
|
187
|
-
return n === 0 ? undefined : n
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
render() {
|
|
191
|
-
return html`
|
|
192
|
-
<div tabs>
|
|
193
|
-
${this.renderTab('properties', 'tune', i18next.t('figure.label.properties'))}
|
|
194
|
-
${this.renderTab('capability', 'conveyor_belt', i18next.t('figure.label.tab-capability'))}
|
|
195
|
-
${this.renderTab('animation', 'animation', i18next.t('figure.label.animation'), this.clipCount)}
|
|
196
|
-
${this.renderTab('verdict', 'insights', i18next.t('figure.label.maturity'), this.instances)}
|
|
197
|
-
${this.renderTab('view', 'wb_sunny', i18next.t('figure.label.tab-environment'))}
|
|
198
|
-
${this.renderTab('history', 'history', i18next.t('figure.label.history'))}
|
|
199
|
-
</div>
|
|
200
|
-
|
|
201
|
-
<figure-inspector
|
|
202
|
-
?off=${this.tab !== 'properties'}
|
|
203
|
-
.figureId=${this.figureId}
|
|
204
|
-
.figureVersion=${this.figureVersion}
|
|
205
|
-
.figureName=${this.figureName}
|
|
206
|
-
.figureCategory=${this.figureCategory}
|
|
207
|
-
.figureTags=${this.figureTags}
|
|
208
|
-
.draft=${this.draft}
|
|
209
|
-
.parts=${this.parts}
|
|
210
|
-
.contract=${this.contract}
|
|
211
|
-
.contractFailure=${this.contractFailure}
|
|
212
|
-
.selected=${this.selected}
|
|
213
|
-
></figure-inspector>
|
|
214
|
-
|
|
215
|
-
<figure-capabilities
|
|
216
|
-
?off=${this.tab !== 'capability'}
|
|
217
|
-
.draft=${this.draft}
|
|
218
|
-
.parts=${this.parts}
|
|
219
|
-
></figure-capabilities>
|
|
220
|
-
|
|
221
|
-
<figure-animations
|
|
222
|
-
?off=${this.tab !== 'animation'}
|
|
223
|
-
.draft=${this.draft}
|
|
224
|
-
.parts=${this.parts}
|
|
225
|
-
></figure-animations>
|
|
226
|
-
|
|
227
|
-
<figure-report
|
|
228
|
-
?off=${this.tab !== 'verdict'}
|
|
229
|
-
.source=${this.source}
|
|
230
|
-
@verdict-changed=${(e: CustomEvent) => (this.instances = e.detail.instances)}
|
|
231
|
-
></figure-report>
|
|
232
|
-
|
|
233
|
-
<figure-settings ?off=${this.tab !== 'view'} .view=${this.view}></figure-settings>
|
|
234
|
-
|
|
235
|
-
<!--
|
|
236
|
-
이력은 감춰도 DOM 에 남긴다 — 다른 탭들과 같은 규칙이다. 떼었다 붙이면 판본을 다시 부른다.
|
|
237
|
-
-->
|
|
238
|
-
<figure-history-panel
|
|
239
|
-
?off=${this.tab !== 'history'}
|
|
240
|
-
.figureId=${this.figureId}
|
|
241
|
-
.figureState=${this.figureState}
|
|
242
|
-
.figureVersion=${this.figureVersion}
|
|
243
|
-
.dirty=${this.dirty}
|
|
244
|
-
.releasedBase=${this.releasedBase}
|
|
245
|
-
></figure-history-panel>
|
|
246
|
-
`
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* 탭 하나 — **아이콘이 이름을 대신한다.**
|
|
251
|
-
*
|
|
252
|
-
* 탭이 다섯이 되면서 이름이 좁은 칸을 나눠 쓰다 접혔다. 앞으로 더 늘어날 자리이므로 이름을
|
|
253
|
-
* 줄여 짜 넣는 대신 아이콘으로 바꾼다.
|
|
254
|
-
*
|
|
255
|
-
* **이름을 버리지는 않는다.** 아이콘만으로는 무엇인지 모르는 사람이 있고, 특히 「능력」처럼
|
|
256
|
-
* 이 도구에만 있는 개념이 그렇다. 그래서 이름은 `title` 로 남아 마우스를 올리면 나오고,
|
|
257
|
-
* `aria-label` 로 읽는 기계에도 그대로 간다.
|
|
258
|
-
*/
|
|
259
|
-
private renderTab(tab: Tab, icon: string, label: string, badge?: number) {
|
|
260
|
-
return html`
|
|
261
|
-
<button
|
|
262
|
-
tab
|
|
263
|
-
?on=${this.tab === tab}
|
|
264
|
-
title=${label}
|
|
265
|
-
aria-label=${label}
|
|
266
|
-
@click=${() => (this.tab = tab)}
|
|
267
|
-
>
|
|
268
|
-
<md-icon>${icon}</md-icon>${badge == null ? '' : html`<span badge>${badge.toLocaleString()}</span>`}
|
|
269
|
-
</button>
|
|
270
|
-
`
|
|
271
|
-
}
|
|
272
|
-
}
|