@things-factory/figure-ui 10.1.5 → 10.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/graphql/index.ts +35 -3
- package/client/modeller/figure-ask.ts +5 -5
- package/client/modeller/figure-canvas.ts +1 -1
- package/client/modeller/figure-capabilities.ts +372 -0
- package/client/modeller/figure-history-panel.ts +171 -18
- package/client/modeller/figure-inspector.ts +392 -76
- package/client/modeller/figure-parts.ts +15 -15
- package/client/modeller/figure-preview.ts +2 -2
- package/client/modeller/figure-report.ts +102 -37
- package/client/modeller/figure-settings.ts +20 -20
- package/client/modeller/figure-side.ts +37 -9
- package/client/modeller/figure-source.test.ts +15 -1
- package/client/modeller/figure-source.ts +31 -15
- package/client/modeller/figure-thumbnail.ts +49 -4
- package/client/modeller/maturity.ts +10 -10
- package/client/pages/figure-list-page.ts +152 -66
- package/client/pages/figure-modeller-page.ts +260 -43
- package/client/types.ts +25 -0
- package/client/viewparts/figure-thumb.ts +172 -0
- package/dist-client/graphql/index.d.ts +8 -1
- package/dist-client/graphql/index.js +32 -3
- package/dist-client/graphql/index.js.map +1 -1
- package/dist-client/modeller/figure-ask.js +5 -5
- package/dist-client/modeller/figure-ask.js.map +1 -1
- package/dist-client/modeller/figure-canvas.js +1 -1
- package/dist-client/modeller/figure-canvas.js.map +1 -1
- package/dist-client/modeller/figure-capabilities.d.ts +42 -0
- package/dist-client/modeller/figure-capabilities.js +344 -0
- package/dist-client/modeller/figure-capabilities.js.map +1 -0
- package/dist-client/modeller/figure-history-panel.d.ts +15 -1
- package/dist-client/modeller/figure-history-panel.js +165 -18
- package/dist-client/modeller/figure-history-panel.js.map +1 -1
- package/dist-client/modeller/figure-inspector.d.ts +84 -0
- package/dist-client/modeller/figure-inspector.js +379 -75
- package/dist-client/modeller/figure-inspector.js.map +1 -1
- package/dist-client/modeller/figure-parts.js +15 -15
- package/dist-client/modeller/figure-parts.js.map +1 -1
- package/dist-client/modeller/figure-preview.js +2 -2
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-report.d.ts +18 -1
- package/dist-client/modeller/figure-report.js +105 -37
- package/dist-client/modeller/figure-report.js.map +1 -1
- package/dist-client/modeller/figure-settings.js +19 -19
- package/dist-client/modeller/figure-settings.js.map +1 -1
- package/dist-client/modeller/figure-side.d.ts +1 -0
- package/dist-client/modeller/figure-side.js +36 -8
- package/dist-client/modeller/figure-side.js.map +1 -1
- package/dist-client/modeller/figure-source.d.ts +15 -8
- package/dist-client/modeller/figure-source.js +16 -7
- package/dist-client/modeller/figure-source.js.map +1 -1
- package/dist-client/modeller/figure-thumbnail.js +40 -4
- package/dist-client/modeller/figure-thumbnail.js.map +1 -1
- package/dist-client/modeller/maturity.js +10 -10
- package/dist-client/modeller/maturity.js.map +1 -1
- package/dist-client/pages/figure-list-page.d.ts +1 -4
- package/dist-client/pages/figure-list-page.js +150 -63
- package/dist-client/pages/figure-list-page.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.d.ts +45 -0
- package/dist-client/pages/figure-modeller-page.js +259 -43
- package/dist-client/pages/figure-modeller-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/types.d.ts +23 -0
- package/dist-client/types.js.map +1 -1
- package/dist-client/viewparts/figure-thumb.d.ts +29 -0
- package/dist-client/viewparts/figure-thumb.js +168 -0
- package/dist-client/viewparts/figure-thumb.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -5
- package/test/i18n-prefix-guard.test.ts +129 -0
- package/test/korean-register-guard.test.ts +83 -0
- package/translations/en.json +307 -264
- package/translations/ja.json +275 -264
- package/translations/ko.json +307 -264
- package/translations/ms.json +275 -264
- package/translations/zh.json +275 -264
|
@@ -324,49 +324,49 @@ export class FigureParts extends localize(i18next)(LitElement) {
|
|
|
324
324
|
|
|
325
325
|
return html`
|
|
326
326
|
<section>
|
|
327
|
-
<h3>${i18next.t('label.shapes')}</h3>
|
|
327
|
+
<h3>${i18next.t('figure.label.shapes')}</h3>
|
|
328
328
|
<div palette>
|
|
329
329
|
${PRIMITIVE_KINDS.map(
|
|
330
330
|
kind => html`
|
|
331
331
|
<button
|
|
332
332
|
shape
|
|
333
333
|
?disabled=${full}
|
|
334
|
-
title=${full ? i18next.t('text.part-limit-reached') : i18next.t('text.add-a-shape')}
|
|
334
|
+
title=${full ? i18next.t('figure.text.part-limit-reached') : i18next.t('figure.text.add-a-shape')}
|
|
335
335
|
@click=${() => this.ask('add-part', { primitive: kind })}
|
|
336
336
|
>
|
|
337
337
|
<md-icon>${SHAPE_ICON[kind]}</md-icon>
|
|
338
|
-
${i18next.t('label.primitive-' + kind)}
|
|
338
|
+
${i18next.t('figure.label.primitive-' + kind)}
|
|
339
339
|
</button>
|
|
340
340
|
`
|
|
341
341
|
)}
|
|
342
342
|
</div>
|
|
343
343
|
${full
|
|
344
|
-
? html`<p full>${i18next.t('text.part-limit-reached-short', { level, limit })}</p>`
|
|
344
|
+
? html`<p full>${i18next.t('figure.text.part-limit-reached-short', { level, limit })}</p>`
|
|
345
345
|
: ''}
|
|
346
346
|
</section>
|
|
347
347
|
|
|
348
348
|
<section list>
|
|
349
349
|
<h3>
|
|
350
|
-
${i18next.t('label.parts')}
|
|
351
|
-
<span room ?full=${full} title=${i18next.t('text.limit-comes-from-level')}>
|
|
352
|
-
${i18next.t('text.n-of-limit', { used: parts.length, limit })}
|
|
350
|
+
${i18next.t('figure.label.parts')}
|
|
351
|
+
<span room ?full=${full} title=${i18next.t('figure.text.limit-comes-from-level')}>
|
|
352
|
+
${i18next.t('figure.text.n-of-limit', { used: parts.length, limit })}
|
|
353
353
|
</span>
|
|
354
354
|
${this.renderShowAll(parts)}
|
|
355
355
|
</h3>
|
|
356
356
|
|
|
357
357
|
<div level>
|
|
358
|
-
<label for="detail-level">${i18next.t('label.detail-level')}</label>
|
|
358
|
+
<label for="detail-level">${i18next.t('figure.label.detail-level')}</label>
|
|
359
359
|
<select
|
|
360
360
|
id="detail-level"
|
|
361
|
-
title=${i18next.t('text.detail-level-explained')}
|
|
361
|
+
title=${i18next.t('figure.text.detail-level-explained')}
|
|
362
362
|
@change=${(e: Event) =>
|
|
363
363
|
this.ask('change-detail-level', { level: (e.target as HTMLSelectElement).value })}
|
|
364
364
|
>
|
|
365
365
|
${DETAIL_LEVELS.map(
|
|
366
366
|
one => html`
|
|
367
367
|
<option value=${one} ?selected=${one === level}>
|
|
368
|
-
${one} ${i18next.t('label.detail-' + one)} ·
|
|
369
|
-
${i18next.t('text.n-parts-at-most', { limit: PART_LIMIT[one] })}
|
|
368
|
+
${one} ${i18next.t('figure.label.detail-' + one)} ·
|
|
369
|
+
${i18next.t('figure.text.n-parts-at-most', { limit: PART_LIMIT[one] })}
|
|
370
370
|
</option>
|
|
371
371
|
`
|
|
372
372
|
)}
|
|
@@ -374,7 +374,7 @@ export class FigureParts extends localize(i18next)(LitElement) {
|
|
|
374
374
|
</div>
|
|
375
375
|
|
|
376
376
|
${parts.length === 0
|
|
377
|
-
? html`<p quiet>${i18next.t('text.pick-a-shape-above-to-start')}</p>`
|
|
377
|
+
? html`<p quiet>${i18next.t('figure.text.pick-a-shape-above-to-start')}</p>`
|
|
378
378
|
: html`
|
|
379
379
|
<ol>
|
|
380
380
|
${parts.map((part, index) => this.renderRow(part, index, parts.length))}
|
|
@@ -403,7 +403,7 @@ export class FigureParts extends localize(i18next)(LitElement) {
|
|
|
403
403
|
eye
|
|
404
404
|
all
|
|
405
405
|
?off=${!anyHidden}
|
|
406
|
-
title=${i18next.t(anyHidden ? 'text.show-all-parts' : 'text.hide-all-parts')}
|
|
406
|
+
title=${i18next.t(anyHidden ? 'figure.text.show-all-parts' : 'figure.text.hide-all-parts')}
|
|
407
407
|
@click=${(e: Event) => {
|
|
408
408
|
e.stopPropagation()
|
|
409
409
|
this.ask('set-all-parts-hidden', { hidden: !anyHidden })
|
|
@@ -423,7 +423,7 @@ export class FigureParts extends localize(i18next)(LitElement) {
|
|
|
423
423
|
<button
|
|
424
424
|
eye
|
|
425
425
|
?off=${off}
|
|
426
|
-
title=${i18next.t(off ? 'text.show-this-part' : 'text.hide-this-part')}
|
|
426
|
+
title=${i18next.t(off ? 'figure.text.show-this-part' : 'figure.text.hide-this-part')}
|
|
427
427
|
@click=${(e: Event) => {
|
|
428
428
|
// 눌렀을 때 줄 고르기가 함께 일어나지 않게 막는다 — 가리려던 것이지 고르려던 것이 아니다
|
|
429
429
|
e.stopPropagation()
|
|
@@ -453,7 +453,7 @@ export class FigureParts extends localize(i18next)(LitElement) {
|
|
|
453
453
|
<button
|
|
454
454
|
op=${name}
|
|
455
455
|
?disabled=${!enabled}
|
|
456
|
-
title=${i18next.t('button.' + name)}
|
|
456
|
+
title=${i18next.t('figure.button.' + name)}
|
|
457
457
|
@click=${(e: Event) => {
|
|
458
458
|
e.stopPropagation()
|
|
459
459
|
if (enabled) this.ask(name, detail)
|
|
@@ -263,7 +263,7 @@ export class FigurePreview extends localize(i18next)(LitElement) {
|
|
|
263
263
|
private standUp() {
|
|
264
264
|
const source = this.source
|
|
265
265
|
if (!source || source.parts.length === 0) {
|
|
266
|
-
this.cannot = i18next.t('text.preview-needs-a-part')
|
|
266
|
+
this.cannot = i18next.t('figure.text.preview-needs-a-part')
|
|
267
267
|
this.teardown()
|
|
268
268
|
return
|
|
269
269
|
}
|
|
@@ -273,7 +273,7 @@ export class FigurePreview extends localize(i18next)(LitElement) {
|
|
|
273
273
|
|
|
274
274
|
const { errors } = validate(source)
|
|
275
275
|
if (errors.length > 0) {
|
|
276
|
-
this.cannot = i18next.t('text.preview-blocked-by-errors')
|
|
276
|
+
this.cannot = i18next.t('figure.text.preview-blocked-by-errors')
|
|
277
277
|
this.teardown()
|
|
278
278
|
return
|
|
279
279
|
}
|
|
@@ -6,7 +6,7 @@ import { unsafeSVG } from 'lit/directives/unsafe-svg.js'
|
|
|
6
6
|
|
|
7
7
|
import { i18next, localize } from '@operato/i18n'
|
|
8
8
|
import { ScrollbarStyles } from '@operato/styles'
|
|
9
|
-
import { compile, costCurveSvg, costOf, scoreOf, validate } from '@hatiolab/figure-model'
|
|
9
|
+
import { compile, costCurveSvg, costOf, scoreOf, sizingReport, validate } from '@hatiolab/figure-model'
|
|
10
10
|
import type { FigureCost, FigureScore, FigureSource } from '@hatiolab/figure-model'
|
|
11
11
|
|
|
12
12
|
import { capacityOf } from './scene-budget.js'
|
|
@@ -440,6 +440,23 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
440
440
|
@state() private expanded = false
|
|
441
441
|
@state() private errors: { code: string; message: string; at?: string }[] = []
|
|
442
442
|
@state() private violations: { code: string; message: string }[] = []
|
|
443
|
+
/**
|
|
444
|
+
* 크기를 바꿔 봤을 때 갈라지는가 — **발행을 막는 것**이다.
|
|
445
|
+
*
|
|
446
|
+
* 이력 탭이 같은 판정을 서버에서 받아 발행 문을 잠그지만, 그것은 **저장된 정본**에 대한
|
|
447
|
+
* 것이라 저장하기 전에는 답하지 못한다. 여기서는 저작 중인 정본을 그대로 재므로, 부품을
|
|
448
|
+
* 옮기는 그 자리에서 갈라짐이 생겼는지 사라졌는지 보인다 — 저장하고 탭을 옮겨 확인하게
|
|
449
|
+
* 두면 고칠 때가 이미 지나 있다.
|
|
450
|
+
*/
|
|
451
|
+
@state() private sizing: { code: string; message: string; at?: string; blocking: boolean }[] = []
|
|
452
|
+
/**
|
|
453
|
+
* 아직 부품이 하나도 없나 — **저작 전이지 형식을 어긴 것이 아니다.**
|
|
454
|
+
*
|
|
455
|
+
* 형식은 부품 0개를 오류로 본다(`missing-parts`). 발행 관점에서는 맞다. 그런데 새로 만들기를
|
|
456
|
+
* 누른 직후가 바로 그 상태이므로, 그것을 그대로 오류로 그리면 **아무것도 하지 않았는데 붉은
|
|
457
|
+
* 화면**을 보게 된다. 그래서 이 자리에서 둘을 가른다.
|
|
458
|
+
*/
|
|
459
|
+
@state() private bare = false
|
|
443
460
|
|
|
444
461
|
willUpdate(changed: Map<string, unknown>) {
|
|
445
462
|
if (changed.has('source')) {
|
|
@@ -448,10 +465,17 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
448
465
|
}
|
|
449
466
|
|
|
450
467
|
render() {
|
|
451
|
-
|
|
468
|
+
/*
|
|
469
|
+
부품이 없으면 이 자리는 **판정이 아니라 안내**다. 이미 있던 「부품을 추가하면 나옵니다」가
|
|
470
|
+
정확히 그 말이므로 그것을 쓴다 — 같은 상태에 문장을 둘 두지 않는다.
|
|
471
|
+
|
|
472
|
+
아래 셈들(머리·축·한도·추이)은 부품이 있어야 뜻이 있고, 재지 않은 값을 들고 그리면 0 으로
|
|
473
|
+
보인다. 0 은 「나쁘다」로 읽히므로 그 자리에 두지 않는다.
|
|
474
|
+
*/
|
|
475
|
+
if (!this.source || this.bare) {
|
|
452
476
|
return html`
|
|
453
477
|
<section>
|
|
454
|
-
<p quiet>${i18next.t('text.report-appears-when-you-add-a-part')}</p>
|
|
478
|
+
<p quiet>${i18next.t('figure.text.report-appears-when-you-add-a-part')}</p>
|
|
455
479
|
</section>
|
|
456
480
|
`
|
|
457
481
|
}
|
|
@@ -484,34 +508,34 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
484
508
|
|
|
485
509
|
return html`
|
|
486
510
|
<section>
|
|
487
|
-
<h3>${i18next.t('label.maturity')}</h3>
|
|
488
|
-
<p lead>${i18next.t('label.axis-scale')} — ${i18next.t('text.how-many-fit')}</p>
|
|
511
|
+
<h3>${i18next.t('figure.label.maturity')}</h3>
|
|
512
|
+
<p lead>${i18next.t('figure.label.axis-scale')} — ${i18next.t('figure.text.how-many-fit')}</p>
|
|
489
513
|
<div verdict>
|
|
490
514
|
<span capacity>${capacity.instances.toLocaleString()}</span>
|
|
491
|
-
<span unit>${i18next.t('text.instances-unit')}</span>
|
|
515
|
+
<span unit>${i18next.t('figure.text.instances-unit')}</span>
|
|
492
516
|
<span
|
|
493
517
|
grade
|
|
494
518
|
?tight=${score.grade === 'C'}
|
|
495
519
|
?over=${score.grade === 'D'}
|
|
496
|
-
title=${i18next.t('text.grade-explained')}
|
|
520
|
+
title=${i18next.t('figure.text.grade-explained')}
|
|
497
521
|
>
|
|
498
522
|
${score.grade}
|
|
499
|
-
<small>${i18next.t('text.headroom-percent', { percent: Math.round(score.score) })}</small>
|
|
523
|
+
<small>${i18next.t('figure.text.headroom-percent', { percent: Math.round(score.score) })}</small>
|
|
500
524
|
</span>
|
|
501
525
|
</div>
|
|
502
526
|
<p because>
|
|
503
|
-
${i18next.t('text.grade-decided-by')}
|
|
504
|
-
<strong>${i18next.t('label.budget-' + score.tightest.key)}</strong>
|
|
527
|
+
${i18next.t('figure.text.grade-decided-by')}
|
|
528
|
+
<strong>${i18next.t('figure.label.budget-' + score.tightest.key)}</strong>
|
|
505
529
|
— ${score.tightest.used} / ${score.tightest.limit}
|
|
506
530
|
(${Math.round((score.tightest.used / score.tightest.limit) * 100)}%)
|
|
507
531
|
</p>
|
|
508
532
|
${this.renderGradeScale(score.grade)}
|
|
509
533
|
<p basis>
|
|
510
|
-
${i18next.t('text.bound-by-' + capacity.bound, {
|
|
534
|
+
${i18next.t('figure.text.bound-by-' + capacity.bound, {
|
|
511
535
|
per: capacity.per.toLocaleString(),
|
|
512
536
|
budget: capacity.budget.toLocaleString()
|
|
513
537
|
})}
|
|
514
|
-
<em>${i18next.t('text.budget-not-measured-yet')}</em>
|
|
538
|
+
<em>${i18next.t('figure.text.budget-not-measured-yet')}</em>
|
|
515
539
|
</p>
|
|
516
540
|
</section>
|
|
517
541
|
`
|
|
@@ -536,7 +560,7 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
536
560
|
|
|
537
561
|
return html`
|
|
538
562
|
<p scale>
|
|
539
|
-
<span>${i18next.t('text.grade-scale-lead')}</span>
|
|
563
|
+
<span>${i18next.t('figure.text.grade-scale-lead')}</span>
|
|
540
564
|
${bounds.map(
|
|
541
565
|
([grade, bound]) => html`<span ?now=${grade === now}><b>${grade}</b> ${bound}</span>`
|
|
542
566
|
)}
|
|
@@ -568,7 +592,7 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
568
592
|
|
|
569
593
|
return html`
|
|
570
594
|
<section>
|
|
571
|
-
<h3>${i18next.t('label.by-axis')}</h3>
|
|
595
|
+
<h3>${i18next.t('figure.label.by-axis')}</h3>
|
|
572
596
|
<div radar>${this.renderRadar(all.filter(axis => axis.ratio !== undefined))}</div>
|
|
573
597
|
${this.renderUnmeasured(all.filter(axis => axis.ratio === undefined))}
|
|
574
598
|
<ul axes>
|
|
@@ -624,7 +648,7 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
624
648
|
const anchor = x < cx - 3 ? 'end' : x > cx + 3 ? 'start' : 'middle'
|
|
625
649
|
return svg`
|
|
626
650
|
<text x=${x.toFixed(1)} y=${(y + 1.8).toFixed(1)} text-anchor=${anchor}>
|
|
627
|
-
${i18next.t('label.axis-' + axis.key + '-short')}
|
|
651
|
+
${i18next.t('figure.label.axis-' + axis.key + '-short')}
|
|
628
652
|
</text>
|
|
629
653
|
`
|
|
630
654
|
})}
|
|
@@ -644,21 +668,21 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
644
668
|
|
|
645
669
|
return html`
|
|
646
670
|
<p unmeasured>
|
|
647
|
-
${i18next.t('text.axes-not-measurable-yet', {
|
|
648
|
-
axes: axes.map(axis => i18next.t('label.axis-' + axis.key)).join(' · ')
|
|
671
|
+
${i18next.t('figure.text.axes-not-measurable-yet', {
|
|
672
|
+
axes: axes.map(axis => i18next.t('figure.label.axis-' + axis.key)).join(' · ')
|
|
649
673
|
})}
|
|
650
674
|
</p>
|
|
651
675
|
`
|
|
652
676
|
}
|
|
653
677
|
|
|
654
678
|
private renderAxis(axis: MaturityAxis) {
|
|
655
|
-
const name = i18next.t('label.axis-' + axis.key)
|
|
679
|
+
const name = i18next.t('figure.label.axis-' + axis.key)
|
|
656
680
|
|
|
657
681
|
if (axis.blocked) {
|
|
658
682
|
return html`
|
|
659
683
|
<li blocked>
|
|
660
684
|
<span>${name}</span>
|
|
661
|
-
<span reading>${i18next.t('text.not-measurable-yet')}</span>
|
|
685
|
+
<span reading>${i18next.t('figure.text.not-measurable-yet')}</span>
|
|
662
686
|
<em>${i18next.t(axis.blocked)}</em>
|
|
663
687
|
</li>
|
|
664
688
|
`
|
|
@@ -688,7 +712,7 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
688
712
|
* 그것을 그대로 실으면 다른 언어 사용자에게 한국어가 나온다.
|
|
689
713
|
*
|
|
690
714
|
* `budgets` 는 **배열**이다. `Object.entries` 로 돌면 키가 인덱스(0·1·2…)가 되어
|
|
691
|
-
* `label.budget-0` 같은 없는 키를 찾는다 — 화면을 띄워 보고서야 드러났다.
|
|
715
|
+
* `figure.label.budget-0` 같은 없는 키를 찾는다 — 화면을 띄워 보고서야 드러났다.
|
|
692
716
|
* 배열을 그대로 돌고 `use.key` 를 쓴다.
|
|
693
717
|
*
|
|
694
718
|
* 그래서 **안정된 `key`** 로 이 화면의 i18n 을 찾는다. `key` 는 열거형이라 형식의
|
|
@@ -701,14 +725,14 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
701
725
|
|
|
702
726
|
return html`
|
|
703
727
|
<section>
|
|
704
|
-
<h3>${i18next.t('label.budgets')}</h3>
|
|
728
|
+
<h3>${i18next.t('figure.label.budgets')}</h3>
|
|
705
729
|
<ul budgets>
|
|
706
730
|
${score.budgets.map(use => {
|
|
707
731
|
const ratio = Math.min(1, use.ratio)
|
|
708
732
|
const tight = use.key === score.tightest.key
|
|
709
733
|
return html`
|
|
710
734
|
<li>
|
|
711
|
-
<span>${i18next.t('label.budget-' + use.key)}</span>
|
|
735
|
+
<span>${i18next.t('figure.label.budget-' + use.key)}</span>
|
|
712
736
|
<span>${use.used} / ${use.limit}</span>
|
|
713
737
|
<div bar><i ?tight=${tight} style="width:${Math.round(ratio * 100)}%"></i></div>
|
|
714
738
|
</li>
|
|
@@ -725,21 +749,21 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
725
749
|
|
|
726
750
|
return html`
|
|
727
751
|
<section>
|
|
728
|
-
<h3>${i18next.t('label.weight')}</h3>
|
|
752
|
+
<h3>${i18next.t('figure.label.weight')}</h3>
|
|
729
753
|
<dl metrics>
|
|
730
|
-
<dt>${i18next.t('label.triangles')}</dt>
|
|
754
|
+
<dt>${i18next.t('figure.label.triangles')}</dt>
|
|
731
755
|
<dd>${cost.triangles.toLocaleString()}</dd>
|
|
732
756
|
|
|
733
|
-
<dt>${i18next.t('label.triangles-at-100')}</dt>
|
|
757
|
+
<dt>${i18next.t('figure.label.triangles-at-100')}</dt>
|
|
734
758
|
<dd>${cost.at.triangles.toLocaleString()}</dd>
|
|
735
759
|
|
|
736
|
-
<dt>${i18next.t('label.draw-calls-at-100')}</dt>
|
|
760
|
+
<dt>${i18next.t('figure.label.draw-calls-at-100')}</dt>
|
|
737
761
|
<dd>${cost.at.drawCalls.toLocaleString()}</dd>
|
|
738
762
|
|
|
739
|
-
<dt>${i18next.t('label.distinct-shapes')}</dt>
|
|
763
|
+
<dt>${i18next.t('figure.label.distinct-shapes')}</dt>
|
|
740
764
|
<dd>${cost.distinctShapes}</dd>
|
|
741
765
|
|
|
742
|
-
<dt>${i18next.t('label.distinct-materials')}</dt>
|
|
766
|
+
<dt>${i18next.t('figure.label.distinct-materials')}</dt>
|
|
743
767
|
<dd>${cost.distinctMaterials}</dd>
|
|
744
768
|
</dl>
|
|
745
769
|
</section>
|
|
@@ -762,14 +786,14 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
762
786
|
|
|
763
787
|
return html`
|
|
764
788
|
<section>
|
|
765
|
-
<h3>${i18next.t('label.reuse-trend')}</h3>
|
|
789
|
+
<h3>${i18next.t('figure.label.reuse-trend')}</h3>
|
|
766
790
|
${many
|
|
767
791
|
? html`
|
|
768
792
|
<dl metrics>
|
|
769
|
-
<dt>${i18next.t('label.triangles-at-10k')}</dt>
|
|
793
|
+
<dt>${i18next.t('figure.label.triangles-at-10k')}</dt>
|
|
770
794
|
<dd>${many.at.triangles.toLocaleString()}</dd>
|
|
771
795
|
|
|
772
|
-
<dt>${i18next.t('label.draw-calls-at-10k')}</dt>
|
|
796
|
+
<dt>${i18next.t('figure.label.draw-calls-at-10k')}</dt>
|
|
773
797
|
<dd>${many.at.drawCalls.toLocaleString()}</dd>
|
|
774
798
|
</dl>
|
|
775
799
|
`
|
|
@@ -777,7 +801,7 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
777
801
|
${this.curve
|
|
778
802
|
? html`
|
|
779
803
|
<button expand @click=${() => (this.expanded = true)}>
|
|
780
|
-
${i18next.t('button.see-the-trend-chart')}
|
|
804
|
+
${i18next.t('figure.button.see-the-trend-chart')}
|
|
781
805
|
</button>
|
|
782
806
|
`
|
|
783
807
|
: nothing}
|
|
@@ -794,7 +818,7 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
794
818
|
<figure @click=${(e: Event) => e.stopPropagation()}>
|
|
795
819
|
${unsafeSVG(this.curve)}
|
|
796
820
|
<figcaption>
|
|
797
|
-
<button close @click=${() => (this.expanded = false)}>${i18next.t('button.close')}</button>
|
|
821
|
+
<button close @click=${() => (this.expanded = false)}>${i18next.t('figure.button.close')}</button>
|
|
798
822
|
</figcaption>
|
|
799
823
|
</figure>
|
|
800
824
|
</div>
|
|
@@ -809,19 +833,27 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
809
833
|
* 검사가 돌았는지 알 수 없다.
|
|
810
834
|
*/
|
|
811
835
|
private renderFindings() {
|
|
812
|
-
if (this.errors.length === 0 && this.violations.length === 0) {
|
|
836
|
+
if (this.errors.length === 0 && this.violations.length === 0 && this.sizing.length === 0) {
|
|
813
837
|
return html`
|
|
814
838
|
<section>
|
|
815
|
-
<h3>${i18next.t('label.findings')}</h3>
|
|
816
|
-
<p quiet>${i18next.t('text.no-findings')}</p>
|
|
839
|
+
<h3>${i18next.t('figure.label.findings')}</h3>
|
|
840
|
+
<p quiet>${i18next.t('figure.text.no-findings')}</p>
|
|
817
841
|
</section>
|
|
818
842
|
`
|
|
819
843
|
}
|
|
820
844
|
|
|
821
845
|
return html`
|
|
822
846
|
<section>
|
|
823
|
-
<h3>${i18next.t('label.findings')}</h3>
|
|
847
|
+
<h3>${i18next.t('figure.label.findings')}</h3>
|
|
824
848
|
<ul findings>
|
|
849
|
+
${this.sizing.map(
|
|
850
|
+
finding => html`
|
|
851
|
+
<li ?violation=${!finding.blocking}>
|
|
852
|
+
<md-icon>call_split</md-icon>
|
|
853
|
+
<span>${finding.message} ${finding.at ? html`<code at>${finding.at}</code>` : ''}</span>
|
|
854
|
+
</li>
|
|
855
|
+
`
|
|
856
|
+
)}
|
|
825
857
|
${this.errors.map(
|
|
826
858
|
e => html`
|
|
827
859
|
<li>
|
|
@@ -854,6 +886,24 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
854
886
|
this.curve = ''
|
|
855
887
|
this.errors = []
|
|
856
888
|
this.violations = []
|
|
889
|
+
this.sizing = []
|
|
890
|
+
return
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/*
|
|
894
|
+
부품이 없으면 판정을 아예 하지 않는다 — 잴 것이 없다. 「무엇을 고쳐야 하나」가 아니라
|
|
895
|
+
「무엇부터 놓나」인 상태이고, 그 안내는 부품 목록이 이미 하고 있다.
|
|
896
|
+
*/
|
|
897
|
+
this.bare = !source.parts?.length
|
|
898
|
+
if (this.bare) {
|
|
899
|
+
this.cost = undefined
|
|
900
|
+
this.score = undefined
|
|
901
|
+
this.many = undefined
|
|
902
|
+
this.capacity = undefined
|
|
903
|
+
this.curve = ''
|
|
904
|
+
this.errors = []
|
|
905
|
+
this.violations = []
|
|
906
|
+
this.sizing = []
|
|
857
907
|
return
|
|
858
908
|
}
|
|
859
909
|
|
|
@@ -868,6 +918,7 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
868
918
|
this.many = undefined
|
|
869
919
|
this.capacity = undefined
|
|
870
920
|
this.curve = ''
|
|
921
|
+
this.sizing = []
|
|
871
922
|
this.dispatchEvent(
|
|
872
923
|
new CustomEvent('verdict-changed', { detail: {}, bubbles: true, composed: true })
|
|
873
924
|
)
|
|
@@ -875,6 +926,20 @@ export class FigureReport extends localize(i18next)(LitElement) {
|
|
|
875
926
|
}
|
|
876
927
|
|
|
877
928
|
const blueprint = compile(source)
|
|
929
|
+
|
|
930
|
+
/*
|
|
931
|
+
크기를 바꿔 보는 일곱 조합. 판정 규칙은 `figure-model` 의 `gate.ts` 가 정한 것을 그대로
|
|
932
|
+
쓴다 — 무엇이 막는 것인지 화면이 다시 정하면 서버와 다른 말을 하게 된다.
|
|
933
|
+
*/
|
|
934
|
+
const report = sizingReport(blueprint)
|
|
935
|
+
this.sizing = report.findings.map(finding => ({
|
|
936
|
+
code: finding.code,
|
|
937
|
+
message: finding.message,
|
|
938
|
+
/* 숫자가 아니라 자리를 말한다 — 갈라져 나온 부품 이름이 고칠 자리다. */
|
|
939
|
+
at: finding.clumps.map(clump => [...clump].sort().join('+')).join(' | ') || undefined,
|
|
940
|
+
blocking: finding.code === 'sizing-splits'
|
|
941
|
+
}))
|
|
942
|
+
|
|
878
943
|
this.cost = costOf(blueprint, 100)
|
|
879
944
|
// 1만 개는 figure-model 에 다시 묻는다 — 화면이 곱셈으로 짐작하지 않는다.
|
|
880
945
|
this.many = costOf(blueprint, 10000)
|
|
@@ -159,34 +159,34 @@ export class FigureSettings extends localize(i18next)(LitElement) {
|
|
|
159
159
|
|
|
160
160
|
return html`
|
|
161
161
|
<section>
|
|
162
|
-
<h3>${i18next.t('label.guides')}</h3>
|
|
163
|
-
<p quiet>${i18next.t('text.view-settings-are-not-saved')}</p>
|
|
162
|
+
<h3>${i18next.t('figure.label.guides')}</h3>
|
|
163
|
+
<p quiet>${i18next.t('figure.text.view-settings-are-not-saved')}</p>
|
|
164
164
|
|
|
165
|
-
${this.toggle('grid', view.grid, i18next.t('label.coordinate-ground'), i18next.t('text.coordinate-ground-explained'))}
|
|
166
|
-
${this.toggle('gridLabels', view.gridLabels, i18next.t('label.axis-labels'))}
|
|
167
|
-
${this.toggle('floor', view.floor, i18next.t('label.floor'), i18next.t('text.floor-explained'))}
|
|
165
|
+
${this.toggle('grid', view.grid, i18next.t('figure.label.coordinate-ground'), i18next.t('figure.text.coordinate-ground-explained'))}
|
|
166
|
+
${this.toggle('gridLabels', view.gridLabels, i18next.t('figure.label.axis-labels'))}
|
|
167
|
+
${this.toggle('floor', view.floor, i18next.t('figure.label.scene-floor'), i18next.t('figure.text.floor-explained'))}
|
|
168
168
|
</section>
|
|
169
169
|
|
|
170
170
|
<section>
|
|
171
|
-
<h3>${i18next.t('label.environment')}</h3>
|
|
171
|
+
<h3>${i18next.t('figure.label.environment')}</h3>
|
|
172
172
|
|
|
173
173
|
<label field>
|
|
174
|
-
<span>${i18next.t('label.preset')}</span>
|
|
174
|
+
<span>${i18next.t('figure.label.preset')}</span>
|
|
175
175
|
<select
|
|
176
176
|
.value=${view.environment}
|
|
177
177
|
@change=${(e: Event) => this.put({ environment: (e.target as HTMLSelectElement).value as EnvironmentName })}
|
|
178
178
|
>
|
|
179
179
|
${ENVIRONMENTS.map(
|
|
180
180
|
name => html`<option value=${name} ?selected=${view.environment === name}>
|
|
181
|
-
${i18next.t(`label.environment-${name}`)}
|
|
181
|
+
${i18next.t(`figure.label.environment-${name}`)}
|
|
182
182
|
</option>`
|
|
183
183
|
)}
|
|
184
184
|
</select>
|
|
185
185
|
</label>
|
|
186
|
-
<p quiet>${i18next.t('text.environment-explained')}</p>
|
|
186
|
+
<p quiet>${i18next.t('figure.text.environment-explained')}</p>
|
|
187
187
|
|
|
188
188
|
<label field>
|
|
189
|
-
<span>${i18next.t('label.sky-color')}</span>
|
|
189
|
+
<span>${i18next.t('figure.label.sky-color')}</span>
|
|
190
190
|
<input
|
|
191
191
|
type="color"
|
|
192
192
|
.value=${view.skyColor}
|
|
@@ -196,30 +196,30 @@ export class FigureSettings extends localize(i18next)(LitElement) {
|
|
|
196
196
|
</section>
|
|
197
197
|
|
|
198
198
|
<section>
|
|
199
|
-
<h3>${i18next.t('label.key-light')}</h3>
|
|
199
|
+
<h3>${i18next.t('figure.label.key-light')}</h3>
|
|
200
200
|
|
|
201
|
-
${this.slider('dirLightIntensity', view.dirLightIntensity, i18next.t('label.intensity'), 0, 5, 0.1)}
|
|
201
|
+
${this.slider('dirLightIntensity', view.dirLightIntensity, i18next.t('figure.label.intensity'), 0, 5, 0.1)}
|
|
202
202
|
${this.toggle(
|
|
203
203
|
'dirLightFollowCamera',
|
|
204
204
|
view.dirLightFollowCamera,
|
|
205
|
-
i18next.t('label.follow-camera'),
|
|
206
|
-
i18next.t('text.follow-camera-explained')
|
|
205
|
+
i18next.t('figure.label.follow-camera'),
|
|
206
|
+
i18next.t('figure.text.follow-camera-explained')
|
|
207
207
|
)}
|
|
208
|
-
${this.toggle('dirShadowEnabled', view.dirShadowEnabled, i18next.t('label.cast-shadow'))}
|
|
208
|
+
${this.toggle('dirShadowEnabled', view.dirShadowEnabled, i18next.t('figure.label.cast-shadow'))}
|
|
209
209
|
${view.dirLightIntensity === 0 && view.hemiIntensity === 0
|
|
210
|
-
? html`<p quiet>${i18next.t('text.all-lights-off')}</p>`
|
|
210
|
+
? html`<p quiet>${i18next.t('figure.text.all-lights-off')}</p>`
|
|
211
211
|
: ''}
|
|
212
212
|
</section>
|
|
213
213
|
|
|
214
214
|
<section>
|
|
215
|
-
<h3>${i18next.t('label.hemisphere-light')}</h3>
|
|
215
|
+
<h3>${i18next.t('figure.label.hemisphere-light')}</h3>
|
|
216
216
|
|
|
217
|
-
${this.slider('hemiIntensity', view.hemiIntensity, i18next.t('label.intensity'), 0, 8, 0.1)}
|
|
218
|
-
<p quiet>${i18next.t('text.hemisphere-light-explained')}</p>
|
|
217
|
+
${this.slider('hemiIntensity', view.hemiIntensity, i18next.t('figure.label.intensity'), 0, 8, 0.1)}
|
|
218
|
+
<p quiet>${i18next.t('figure.text.hemisphere-light-explained')}</p>
|
|
219
219
|
</section>
|
|
220
220
|
|
|
221
221
|
<section>
|
|
222
|
-
<button reset @click=${() => this.reset()}>${i18next.t('button.reset-view')}</button>
|
|
222
|
+
<button reset @click=${() => this.reset()}>${i18next.t('figure.button.reset-view')}</button>
|
|
223
223
|
</section>
|
|
224
224
|
`
|
|
225
225
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import './figure-inspector.js'
|
|
2
|
+
import './figure-capabilities.js'
|
|
2
3
|
import './figure-report.js'
|
|
3
4
|
import './figure-settings.js'
|
|
4
5
|
import './figure-history-panel.js'
|
|
@@ -13,7 +14,7 @@ import type { BoardModel, PartModel } from './figure-source.js'
|
|
|
13
14
|
import { DEFAULT_VIEW } from './figure-view.js'
|
|
14
15
|
import type { ViewSettings } from './figure-view.js'
|
|
15
16
|
|
|
16
|
-
type Tab = 'properties' | 'verdict' | 'view' | 'history'
|
|
17
|
+
type Tab = 'properties' | 'capability' | 'verdict' | 'view' | 'history'
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* 저작면 오른쪽 칸 — 속성과 판정을 탭으로 겹쳐 둔다.
|
|
@@ -65,10 +66,19 @@ export class FigureSide extends localize(i18next)(LitElement) {
|
|
|
65
66
|
}
|
|
66
67
|
button[tab] {
|
|
67
68
|
flex: 1;
|
|
69
|
+
/*
|
|
70
|
+
**탭 이름은 한 줄이다.** 배지를 이름 옆에 나란히 두었더니 넷이 좁은 칸을 나눠 쓰면서
|
|
71
|
+
이름이 접혀 「성숙 / 도」가 되었다. 이름이 접히면 그 줄이 두 줄이 되고 네 탭의 높이가
|
|
72
|
+
서로 달라진다.
|
|
73
|
+
|
|
74
|
+
그래서 배지는 자리를 차지하지 않고 **이름 위에 겹친다**(아래 span[badge]). 개수는
|
|
75
|
+
곁들이는 것이고 이름이 먼저다.
|
|
76
|
+
*/
|
|
77
|
+
position: relative;
|
|
68
78
|
display: flex;
|
|
69
79
|
align-items: center;
|
|
70
80
|
justify-content: center;
|
|
71
|
-
|
|
81
|
+
white-space: nowrap;
|
|
72
82
|
padding: 8px 6px;
|
|
73
83
|
font: var(--label-font, inherit);
|
|
74
84
|
font-size: 0.76rem;
|
|
@@ -88,14 +98,25 @@ export class FigureSide extends localize(i18next)(LitElement) {
|
|
|
88
98
|
border-bottom-color: var(--md-sys-color-primary);
|
|
89
99
|
}
|
|
90
100
|
|
|
91
|
-
/*
|
|
101
|
+
/*
|
|
102
|
+
판정을 덮어 두어도 개수는 여기 남는다.
|
|
103
|
+
|
|
104
|
+
자리를 먹지 않게 오른쪽 위에 겹쳐 둔다 — 탭 이름을 밀지 않으므로 이름이 접히지 않는다.
|
|
105
|
+
숫자가 커져도(1,200 같은 것) 이름 위로 넘칠 뿐 줄을 바꾸지 않는다.
|
|
106
|
+
*/
|
|
92
107
|
span[badge] {
|
|
93
|
-
|
|
94
|
-
|
|
108
|
+
position: absolute;
|
|
109
|
+
/* 이름 위에 겹치되 위로 붙지 않게 — 탭 가운데 글자와 눈높이를 조금 맞춘다 */
|
|
110
|
+
top: 5px;
|
|
111
|
+
right: 2px;
|
|
112
|
+
padding: 0 5px;
|
|
113
|
+
font-size: 0.62rem;
|
|
95
114
|
font-weight: 700;
|
|
115
|
+
line-height: 1.5;
|
|
96
116
|
color: var(--md-sys-color-on-primary-container);
|
|
97
117
|
background-color: var(--md-sys-color-primary-container);
|
|
98
118
|
border-radius: 999em;
|
|
119
|
+
pointer-events: none;
|
|
99
120
|
}
|
|
100
121
|
|
|
101
122
|
figure-inspector,
|
|
@@ -138,10 +159,11 @@ export class FigureSide extends localize(i18next)(LitElement) {
|
|
|
138
159
|
render() {
|
|
139
160
|
return html`
|
|
140
161
|
<div tabs>
|
|
141
|
-
${this.renderTab('properties', i18next.t('label.properties'))}
|
|
142
|
-
${this.renderTab('
|
|
143
|
-
${this.renderTab('
|
|
144
|
-
${this.renderTab('
|
|
162
|
+
${this.renderTab('properties', i18next.t('figure.label.properties'))}
|
|
163
|
+
${this.renderTab('capability', i18next.t('figure.label.tab-capability'))}
|
|
164
|
+
${this.renderTab('verdict', i18next.t('figure.label.maturity'), this.instances)}
|
|
165
|
+
${this.renderTab('view', i18next.t('figure.label.tab-environment'))}
|
|
166
|
+
${this.renderTab('history', i18next.t('figure.label.history'))}
|
|
145
167
|
</div>
|
|
146
168
|
|
|
147
169
|
<figure-inspector
|
|
@@ -152,6 +174,12 @@ export class FigureSide extends localize(i18next)(LitElement) {
|
|
|
152
174
|
.selected=${this.selected}
|
|
153
175
|
></figure-inspector>
|
|
154
176
|
|
|
177
|
+
<figure-capabilities
|
|
178
|
+
?off=${this.tab !== 'capability'}
|
|
179
|
+
.board=${this.board}
|
|
180
|
+
.parts=${this.parts}
|
|
181
|
+
></figure-capabilities>
|
|
182
|
+
|
|
155
183
|
<figure-report
|
|
156
184
|
?off=${this.tab !== 'verdict'}
|
|
157
185
|
.source=${this.source}
|
|
@@ -149,7 +149,6 @@ const FULL: FigureSource = {
|
|
|
149
149
|
base: { x: 3000, y: 800, z: 2000 },
|
|
150
150
|
detailLevel: 'L',
|
|
151
151
|
styleKit: 'factory',
|
|
152
|
-
anchor: { x: 0, y: -400, z: 0 },
|
|
153
152
|
parts: [
|
|
154
153
|
{
|
|
155
154
|
name: 'deck',
|
|
@@ -200,8 +199,23 @@ const FULL: FigureSource = {
|
|
|
200
199
|
material: { token: 'palette.neutral' },
|
|
201
200
|
sizing: 'repeat',
|
|
202
201
|
repeat: { axis: 'x', pitch: 200 }
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
/*
|
|
205
|
+
물건을 놓는 자리이면서 드나드는 문이다 — AGV 의 상판이 그렇다. **그려지지 않으므로**
|
|
206
|
+
재질이 없다.
|
|
207
|
+
|
|
208
|
+
그리지 않는 것이라 화면으로는 왕복에서 누락됐는지 알 수 없다. 자리를 잃어버린 도형은
|
|
209
|
+
멀쩡해 보이면서 아무것도 받지 못한다.
|
|
210
|
+
*/
|
|
211
|
+
name: 'seat',
|
|
212
|
+
primitive: 'cube',
|
|
213
|
+
transform: { position: { x: 0, y: 420, z: 0 }, size: { x: 700, y: 500, z: 500 } },
|
|
214
|
+
capability: { roles: ['slot', 'port-in', 'port-out'], accepts: ['PALLET'], capacity: 2 }
|
|
203
215
|
}
|
|
204
216
|
],
|
|
217
|
+
/* 이 도형이 지는 능력. 부품이 아니라 도형 전체의 것이다. */
|
|
218
|
+
capabilities: ['FlowNode'],
|
|
205
219
|
/*
|
|
206
220
|
움직임. 편집면이 아직 안 만지는 자리이며, **바로 그래서 여기 있다.**
|
|
207
221
|
|