@things-factory/figure-ui 10.1.4 → 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 +122 -15
- 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 +477 -0
- 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 +54 -8
- 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 +450 -227
- package/client/pages/figure-modeller-page.ts +282 -43
- package/client/types.ts +42 -0
- package/client/viewparts/figure-thumb.ts +172 -0
- package/dist-client/graphql/index.d.ts +31 -4
- package/dist-client/graphql/index.js +102 -12
- 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 +56 -0
- package/dist-client/modeller/figure-history-panel.js +490 -0
- package/dist-client/modeller/figure-history-panel.js.map +1 -0
- 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 +7 -0
- package/dist-client/modeller/figure-side.js +66 -7
- 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 +45 -25
- package/dist-client/pages/figure-list-page.js +439 -247
- package/dist-client/pages/figure-list-page.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.d.ts +54 -0
- package/dist-client/pages/figure-modeller-page.js +279 -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 +42 -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 +9 -5
- package/test/i18n-prefix-guard.test.ts +129 -0
- package/test/korean-register-guard.test.ts +83 -0
- package/translations/en.json +307 -249
- package/translations/ja.json +275 -249
- package/translations/ko.json +307 -249
- package/translations/ms.json +275 -249
- package/translations/zh.json +275 -249
- package/client/viewparts/figure-card.ts +0 -226
- package/dist-client/viewparts/figure-card.d.ts +0 -24
- package/dist-client/viewparts/figure-card.js +0 -221
- package/dist-client/viewparts/figure-card.js.map +0 -1
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import '@material/web/icon/icon.js'
|
|
2
|
-
|
|
3
|
-
import { css, html, LitElement } from 'lit'
|
|
4
|
-
import { customElement, property } from 'lit/decorators.js'
|
|
5
|
-
|
|
6
|
-
import { i18next, localize } from '@operato/i18n'
|
|
7
|
-
|
|
8
|
-
import { capacityFrom } from '../modeller/scene-budget.js'
|
|
9
|
-
import type { Figure } from '../types.js'
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* 이 값 아래면 카드에서 색으로 눈에 띄게 한다.
|
|
13
|
-
*
|
|
14
|
-
* **등급 경계가 아니다.** 등급(A~D)은 `figure-model` 의 `scoreOf` 가 정하고 화면은
|
|
15
|
-
* 그것을 베끼지 않는다. 이것은 「눈에 걸리게 할 선」이고, 화면의 판단이다.
|
|
16
|
-
*/
|
|
17
|
-
const ATTENTION_BELOW = 50
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Figure 한 장.
|
|
21
|
-
*
|
|
22
|
-
* 카드에 무엇을 실을지가 이 화면의 값이다. 이름과 썸네일만 실으면 저작자는 **무게를
|
|
23
|
-
* 모른 채** 고르게 된다. 삼각형 수와 점수를 함께 실어, 「이걸 100개 놓아도 되나」를
|
|
24
|
-
* 목록에서 판단할 수 있게 한다.
|
|
25
|
-
*/
|
|
26
|
-
@customElement('figure-card')
|
|
27
|
-
export class FigureCard extends localize(i18next)(LitElement) {
|
|
28
|
-
static styles = css`
|
|
29
|
-
:host {
|
|
30
|
-
display: flex;
|
|
31
|
-
flex-direction: column;
|
|
32
|
-
overflow: hidden;
|
|
33
|
-
background-color: var(--md-sys-color-surface-container-lowest);
|
|
34
|
-
border: 1px solid var(--md-sys-color-outline-variant);
|
|
35
|
-
border-radius: 6px;
|
|
36
|
-
cursor: pointer;
|
|
37
|
-
}
|
|
38
|
-
:host(:hover) {
|
|
39
|
-
border-color: var(--md-sys-color-primary);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
div[thumbnail] {
|
|
43
|
-
position: relative;
|
|
44
|
-
aspect-ratio: 4 / 3;
|
|
45
|
-
display: flex;
|
|
46
|
-
align-items: center;
|
|
47
|
-
justify-content: center;
|
|
48
|
-
background-color: var(--md-sys-color-surface-container);
|
|
49
|
-
overflow: hidden;
|
|
50
|
-
}
|
|
51
|
-
div[thumbnail] img {
|
|
52
|
-
width: 100%;
|
|
53
|
-
height: 100%;
|
|
54
|
-
object-fit: contain;
|
|
55
|
-
}
|
|
56
|
-
/* 썸네일이 아직 없는 것을 빈 사각형으로 두지 않는다 — 왜 없는지 말한다 */
|
|
57
|
-
div[thumbnail] span[nothumb] {
|
|
58
|
-
display: flex;
|
|
59
|
-
flex-direction: column;
|
|
60
|
-
align-items: center;
|
|
61
|
-
gap: 4px;
|
|
62
|
-
font: var(--label-font, inherit);
|
|
63
|
-
color: var(--md-sys-color-outline-variant);
|
|
64
|
-
}
|
|
65
|
-
div[thumbnail] span[nothumb] md-icon {
|
|
66
|
-
--md-icon-size: 28px;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
span[state] {
|
|
70
|
-
position: absolute;
|
|
71
|
-
top: 6px;
|
|
72
|
-
left: 6px;
|
|
73
|
-
padding: 1px 7px;
|
|
74
|
-
font: var(--label-font, inherit);
|
|
75
|
-
font-size: 0.7rem;
|
|
76
|
-
color: var(--md-sys-color-on-secondary-container);
|
|
77
|
-
background-color: var(--md-sys-color-secondary-container);
|
|
78
|
-
border-radius: 6px;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
button[remove] {
|
|
82
|
-
position: absolute;
|
|
83
|
-
top: 4px;
|
|
84
|
-
right: 4px;
|
|
85
|
-
display: none;
|
|
86
|
-
padding: 3px;
|
|
87
|
-
color: var(--md-sys-color-on-surface);
|
|
88
|
-
background-color: var(--md-sys-color-surface);
|
|
89
|
-
border: 1px solid var(--md-sys-color-outline-variant);
|
|
90
|
-
border-radius: 6px;
|
|
91
|
-
cursor: pointer;
|
|
92
|
-
}
|
|
93
|
-
button[remove] md-icon {
|
|
94
|
-
--md-icon-size: 16px;
|
|
95
|
-
}
|
|
96
|
-
:host(:hover) button[remove] {
|
|
97
|
-
display: block;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
div[body] {
|
|
101
|
-
display: flex;
|
|
102
|
-
flex-direction: column;
|
|
103
|
-
gap: 2px;
|
|
104
|
-
padding: 8px 10px 10px 10px;
|
|
105
|
-
}
|
|
106
|
-
span[name] {
|
|
107
|
-
font: var(--theme-font, inherit);
|
|
108
|
-
font-size: 0.92rem;
|
|
109
|
-
color: var(--md-sys-color-on-surface);
|
|
110
|
-
overflow: hidden;
|
|
111
|
-
text-overflow: ellipsis;
|
|
112
|
-
white-space: nowrap;
|
|
113
|
-
}
|
|
114
|
-
/* 타입 이름은 저장되는 식별자다 — 표시 이름과 다르게 보이게 둔다 */
|
|
115
|
-
code[type] {
|
|
116
|
-
font-family: var(--mono-font, monospace);
|
|
117
|
-
font-size: 0.72rem;
|
|
118
|
-
color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
div[metrics] {
|
|
122
|
-
display: flex;
|
|
123
|
-
align-items: center;
|
|
124
|
-
gap: 10px;
|
|
125
|
-
margin-top: 6px;
|
|
126
|
-
font: var(--label-font, inherit);
|
|
127
|
-
font-size: 0.72rem;
|
|
128
|
-
color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
|
|
129
|
-
}
|
|
130
|
-
/* 「몇 개까지」가 카드의 머리다 — 저작면 머리와 같은 말이라야 한다 */
|
|
131
|
-
span[fits] {
|
|
132
|
-
margin-right: auto;
|
|
133
|
-
font-size: 0.82rem;
|
|
134
|
-
font-weight: 700;
|
|
135
|
-
color: var(--md-sys-color-primary);
|
|
136
|
-
}
|
|
137
|
-
span[grade] {
|
|
138
|
-
padding: 0 6px;
|
|
139
|
-
font-weight: 700;
|
|
140
|
-
color: var(--md-sys-color-on-primary-container);
|
|
141
|
-
background-color: var(--md-sys-color-primary-container);
|
|
142
|
-
border-radius: 6px;
|
|
143
|
-
}
|
|
144
|
-
/* 점수가 낮으면 색으로도 말한다 — 숫자만으로는 눈에 안 들어온다 */
|
|
145
|
-
span[grade][low] {
|
|
146
|
-
color: var(--md-sys-color-on-error, #fff);
|
|
147
|
-
background-color: var(--md-sys-color-error);
|
|
148
|
-
}
|
|
149
|
-
span[unmeasured] {
|
|
150
|
-
font-style: italic;
|
|
151
|
-
color: var(--md-sys-color-outline-variant);
|
|
152
|
-
}
|
|
153
|
-
`
|
|
154
|
-
|
|
155
|
-
@property({ type: Object }) figure!: Figure
|
|
156
|
-
|
|
157
|
-
render() {
|
|
158
|
-
const figure = this.figure
|
|
159
|
-
if (!figure) {
|
|
160
|
-
return html``
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return html`
|
|
164
|
-
<div thumbnail @click=${() => this.dispatchEvent(new CustomEvent('open'))}>
|
|
165
|
-
${figure.thumbnail
|
|
166
|
-
? html`<img src=${figure.thumbnail} alt=${figure.name} />`
|
|
167
|
-
: html`
|
|
168
|
-
<span nothumb>
|
|
169
|
-
<md-icon>deployed_code</md-icon>
|
|
170
|
-
${i18next.t('text.thumbnail-not-made-yet')}
|
|
171
|
-
</span>
|
|
172
|
-
`}
|
|
173
|
-
${figure.state === 'draft' ? html`<span state>${i18next.t('label.draft')}</span>` : ''}
|
|
174
|
-
<button
|
|
175
|
-
remove
|
|
176
|
-
title=${i18next.t('button.delete')}
|
|
177
|
-
@click=${(e: Event) => {
|
|
178
|
-
e.stopPropagation()
|
|
179
|
-
this.dispatchEvent(new CustomEvent('remove'))
|
|
180
|
-
}}
|
|
181
|
-
>
|
|
182
|
-
<md-icon>delete</md-icon>
|
|
183
|
-
</button>
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
<div body @click=${() => this.dispatchEvent(new CustomEvent('open'))}>
|
|
187
|
-
<span name title=${figure.name}>${figure.name}</span>
|
|
188
|
-
<code type>${figure.type}</code>
|
|
189
|
-
|
|
190
|
-
<div metrics>${this.renderMetrics()}</div>
|
|
191
|
-
</div>
|
|
192
|
-
`
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* 무게와 점수.
|
|
197
|
-
*
|
|
198
|
-
* 아직 재지 않은 것(정본을 저장한 적이 없는 것)을 **0 으로 보여 주지 않는다.**
|
|
199
|
-
* 0 은 「가볍다」는 뜻이 되어 버린다. 재지 않았다고 말한다.
|
|
200
|
-
*/
|
|
201
|
-
private renderMetrics() {
|
|
202
|
-
const { score, triangles, groups } = this.figure
|
|
203
|
-
|
|
204
|
-
if (score == null || triangles == null) {
|
|
205
|
-
return html`<span unmeasured>${i18next.t('text.not-measured-yet')}</span>`
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// 목록이 저작면과 **같은 말**을 하게 한다. 저작면 머리가 「몇 개까지」이면 카드도
|
|
209
|
-
// 그것이어야 한다 — 같은 형상을 두 화면이 다른 잣대로 말하면 무엇을 고칠지 모른다.
|
|
210
|
-
const capacity = capacityFrom(groups ?? 0, triangles)
|
|
211
|
-
|
|
212
|
-
// 등급 문자(A~D)를 여기서 만들지 않는다. 경계는 `figure-model` 의 `scoreOf` 가
|
|
213
|
-
// 정하고, 그것을 화면이 베끼면 두 벌이 되어 목록과 저작면이 다른 등급을 보여 준다.
|
|
214
|
-
// 목록에는 점수 숫자만 싣는다. 등급이 필요해지면 `figure-model` 이
|
|
215
|
-
// `gradeOf(score)` 를 내보내야 한다 — 그때 그것을 쓴다.
|
|
216
|
-
return html`
|
|
217
|
-
${capacity
|
|
218
|
-
? html`<span fits title=${i18next.t('text.reuse-score-explained')}>
|
|
219
|
-
${i18next.t('text.fits-n-instances', { n: capacity.instances.toLocaleString() })}
|
|
220
|
-
</span>`
|
|
221
|
-
: ''}
|
|
222
|
-
<span grade ?low=${score < ATTENTION_BELOW}>${Math.round(score)}</span>
|
|
223
|
-
<span>${i18next.t('text.triangle-count', { count: triangles })}</span>
|
|
224
|
-
`
|
|
225
|
-
}
|
|
226
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import '@material/web/icon/icon.js';
|
|
2
|
-
import { LitElement } from 'lit';
|
|
3
|
-
import type { Figure } from '../types.js';
|
|
4
|
-
declare const FigureCard_base: (new (...args: any[]) => LitElement) & typeof LitElement;
|
|
5
|
-
/**
|
|
6
|
-
* Figure 한 장.
|
|
7
|
-
*
|
|
8
|
-
* 카드에 무엇을 실을지가 이 화면의 값이다. 이름과 썸네일만 실으면 저작자는 **무게를
|
|
9
|
-
* 모른 채** 고르게 된다. 삼각형 수와 점수를 함께 실어, 「이걸 100개 놓아도 되나」를
|
|
10
|
-
* 목록에서 판단할 수 있게 한다.
|
|
11
|
-
*/
|
|
12
|
-
export declare class FigureCard extends FigureCard_base {
|
|
13
|
-
static styles: import("lit").CSSResult;
|
|
14
|
-
figure: Figure;
|
|
15
|
-
render(): import("lit-html").TemplateResult<1>;
|
|
16
|
-
/**
|
|
17
|
-
* 무게와 점수.
|
|
18
|
-
*
|
|
19
|
-
* 아직 재지 않은 것(정본을 저장한 적이 없는 것)을 **0 으로 보여 주지 않는다.**
|
|
20
|
-
* 0 은 「가볍다」는 뜻이 되어 버린다. 재지 않았다고 말한다.
|
|
21
|
-
*/
|
|
22
|
-
private renderMetrics;
|
|
23
|
-
}
|
|
24
|
-
export {};
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import '@material/web/icon/icon.js';
|
|
3
|
-
import { css, html, LitElement } from 'lit';
|
|
4
|
-
import { customElement, property } from 'lit/decorators.js';
|
|
5
|
-
import { i18next, localize } from '@operato/i18n';
|
|
6
|
-
import { capacityFrom } from '../modeller/scene-budget.js';
|
|
7
|
-
/**
|
|
8
|
-
* 이 값 아래면 카드에서 색으로 눈에 띄게 한다.
|
|
9
|
-
*
|
|
10
|
-
* **등급 경계가 아니다.** 등급(A~D)은 `figure-model` 의 `scoreOf` 가 정하고 화면은
|
|
11
|
-
* 그것을 베끼지 않는다. 이것은 「눈에 걸리게 할 선」이고, 화면의 판단이다.
|
|
12
|
-
*/
|
|
13
|
-
const ATTENTION_BELOW = 50;
|
|
14
|
-
/**
|
|
15
|
-
* Figure 한 장.
|
|
16
|
-
*
|
|
17
|
-
* 카드에 무엇을 실을지가 이 화면의 값이다. 이름과 썸네일만 실으면 저작자는 **무게를
|
|
18
|
-
* 모른 채** 고르게 된다. 삼각형 수와 점수를 함께 실어, 「이걸 100개 놓아도 되나」를
|
|
19
|
-
* 목록에서 판단할 수 있게 한다.
|
|
20
|
-
*/
|
|
21
|
-
let FigureCard = class FigureCard extends localize(i18next)(LitElement) {
|
|
22
|
-
static { this.styles = css `
|
|
23
|
-
:host {
|
|
24
|
-
display: flex;
|
|
25
|
-
flex-direction: column;
|
|
26
|
-
overflow: hidden;
|
|
27
|
-
background-color: var(--md-sys-color-surface-container-lowest);
|
|
28
|
-
border: 1px solid var(--md-sys-color-outline-variant);
|
|
29
|
-
border-radius: 6px;
|
|
30
|
-
cursor: pointer;
|
|
31
|
-
}
|
|
32
|
-
:host(:hover) {
|
|
33
|
-
border-color: var(--md-sys-color-primary);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
div[thumbnail] {
|
|
37
|
-
position: relative;
|
|
38
|
-
aspect-ratio: 4 / 3;
|
|
39
|
-
display: flex;
|
|
40
|
-
align-items: center;
|
|
41
|
-
justify-content: center;
|
|
42
|
-
background-color: var(--md-sys-color-surface-container);
|
|
43
|
-
overflow: hidden;
|
|
44
|
-
}
|
|
45
|
-
div[thumbnail] img {
|
|
46
|
-
width: 100%;
|
|
47
|
-
height: 100%;
|
|
48
|
-
object-fit: contain;
|
|
49
|
-
}
|
|
50
|
-
/* 썸네일이 아직 없는 것을 빈 사각형으로 두지 않는다 — 왜 없는지 말한다 */
|
|
51
|
-
div[thumbnail] span[nothumb] {
|
|
52
|
-
display: flex;
|
|
53
|
-
flex-direction: column;
|
|
54
|
-
align-items: center;
|
|
55
|
-
gap: 4px;
|
|
56
|
-
font: var(--label-font, inherit);
|
|
57
|
-
color: var(--md-sys-color-outline-variant);
|
|
58
|
-
}
|
|
59
|
-
div[thumbnail] span[nothumb] md-icon {
|
|
60
|
-
--md-icon-size: 28px;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
span[state] {
|
|
64
|
-
position: absolute;
|
|
65
|
-
top: 6px;
|
|
66
|
-
left: 6px;
|
|
67
|
-
padding: 1px 7px;
|
|
68
|
-
font: var(--label-font, inherit);
|
|
69
|
-
font-size: 0.7rem;
|
|
70
|
-
color: var(--md-sys-color-on-secondary-container);
|
|
71
|
-
background-color: var(--md-sys-color-secondary-container);
|
|
72
|
-
border-radius: 6px;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
button[remove] {
|
|
76
|
-
position: absolute;
|
|
77
|
-
top: 4px;
|
|
78
|
-
right: 4px;
|
|
79
|
-
display: none;
|
|
80
|
-
padding: 3px;
|
|
81
|
-
color: var(--md-sys-color-on-surface);
|
|
82
|
-
background-color: var(--md-sys-color-surface);
|
|
83
|
-
border: 1px solid var(--md-sys-color-outline-variant);
|
|
84
|
-
border-radius: 6px;
|
|
85
|
-
cursor: pointer;
|
|
86
|
-
}
|
|
87
|
-
button[remove] md-icon {
|
|
88
|
-
--md-icon-size: 16px;
|
|
89
|
-
}
|
|
90
|
-
:host(:hover) button[remove] {
|
|
91
|
-
display: block;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
div[body] {
|
|
95
|
-
display: flex;
|
|
96
|
-
flex-direction: column;
|
|
97
|
-
gap: 2px;
|
|
98
|
-
padding: 8px 10px 10px 10px;
|
|
99
|
-
}
|
|
100
|
-
span[name] {
|
|
101
|
-
font: var(--theme-font, inherit);
|
|
102
|
-
font-size: 0.92rem;
|
|
103
|
-
color: var(--md-sys-color-on-surface);
|
|
104
|
-
overflow: hidden;
|
|
105
|
-
text-overflow: ellipsis;
|
|
106
|
-
white-space: nowrap;
|
|
107
|
-
}
|
|
108
|
-
/* 타입 이름은 저장되는 식별자다 — 표시 이름과 다르게 보이게 둔다 */
|
|
109
|
-
code[type] {
|
|
110
|
-
font-family: var(--mono-font, monospace);
|
|
111
|
-
font-size: 0.72rem;
|
|
112
|
-
color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
div[metrics] {
|
|
116
|
-
display: flex;
|
|
117
|
-
align-items: center;
|
|
118
|
-
gap: 10px;
|
|
119
|
-
margin-top: 6px;
|
|
120
|
-
font: var(--label-font, inherit);
|
|
121
|
-
font-size: 0.72rem;
|
|
122
|
-
color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
|
|
123
|
-
}
|
|
124
|
-
/* 「몇 개까지」가 카드의 머리다 — 저작면 머리와 같은 말이라야 한다 */
|
|
125
|
-
span[fits] {
|
|
126
|
-
margin-right: auto;
|
|
127
|
-
font-size: 0.82rem;
|
|
128
|
-
font-weight: 700;
|
|
129
|
-
color: var(--md-sys-color-primary);
|
|
130
|
-
}
|
|
131
|
-
span[grade] {
|
|
132
|
-
padding: 0 6px;
|
|
133
|
-
font-weight: 700;
|
|
134
|
-
color: var(--md-sys-color-on-primary-container);
|
|
135
|
-
background-color: var(--md-sys-color-primary-container);
|
|
136
|
-
border-radius: 6px;
|
|
137
|
-
}
|
|
138
|
-
/* 점수가 낮으면 색으로도 말한다 — 숫자만으로는 눈에 안 들어온다 */
|
|
139
|
-
span[grade][low] {
|
|
140
|
-
color: var(--md-sys-color-on-error, #fff);
|
|
141
|
-
background-color: var(--md-sys-color-error);
|
|
142
|
-
}
|
|
143
|
-
span[unmeasured] {
|
|
144
|
-
font-style: italic;
|
|
145
|
-
color: var(--md-sys-color-outline-variant);
|
|
146
|
-
}
|
|
147
|
-
`; }
|
|
148
|
-
render() {
|
|
149
|
-
const figure = this.figure;
|
|
150
|
-
if (!figure) {
|
|
151
|
-
return html ``;
|
|
152
|
-
}
|
|
153
|
-
return html `
|
|
154
|
-
<div thumbnail @click=${() => this.dispatchEvent(new CustomEvent('open'))}>
|
|
155
|
-
${figure.thumbnail
|
|
156
|
-
? html `<img src=${figure.thumbnail} alt=${figure.name} />`
|
|
157
|
-
: html `
|
|
158
|
-
<span nothumb>
|
|
159
|
-
<md-icon>deployed_code</md-icon>
|
|
160
|
-
${i18next.t('text.thumbnail-not-made-yet')}
|
|
161
|
-
</span>
|
|
162
|
-
`}
|
|
163
|
-
${figure.state === 'draft' ? html `<span state>${i18next.t('label.draft')}</span>` : ''}
|
|
164
|
-
<button
|
|
165
|
-
remove
|
|
166
|
-
title=${i18next.t('button.delete')}
|
|
167
|
-
@click=${(e) => {
|
|
168
|
-
e.stopPropagation();
|
|
169
|
-
this.dispatchEvent(new CustomEvent('remove'));
|
|
170
|
-
}}
|
|
171
|
-
>
|
|
172
|
-
<md-icon>delete</md-icon>
|
|
173
|
-
</button>
|
|
174
|
-
</div>
|
|
175
|
-
|
|
176
|
-
<div body @click=${() => this.dispatchEvent(new CustomEvent('open'))}>
|
|
177
|
-
<span name title=${figure.name}>${figure.name}</span>
|
|
178
|
-
<code type>${figure.type}</code>
|
|
179
|
-
|
|
180
|
-
<div metrics>${this.renderMetrics()}</div>
|
|
181
|
-
</div>
|
|
182
|
-
`;
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* 무게와 점수.
|
|
186
|
-
*
|
|
187
|
-
* 아직 재지 않은 것(정본을 저장한 적이 없는 것)을 **0 으로 보여 주지 않는다.**
|
|
188
|
-
* 0 은 「가볍다」는 뜻이 되어 버린다. 재지 않았다고 말한다.
|
|
189
|
-
*/
|
|
190
|
-
renderMetrics() {
|
|
191
|
-
const { score, triangles, groups } = this.figure;
|
|
192
|
-
if (score == null || triangles == null) {
|
|
193
|
-
return html `<span unmeasured>${i18next.t('text.not-measured-yet')}</span>`;
|
|
194
|
-
}
|
|
195
|
-
// 목록이 저작면과 **같은 말**을 하게 한다. 저작면 머리가 「몇 개까지」이면 카드도
|
|
196
|
-
// 그것이어야 한다 — 같은 형상을 두 화면이 다른 잣대로 말하면 무엇을 고칠지 모른다.
|
|
197
|
-
const capacity = capacityFrom(groups ?? 0, triangles);
|
|
198
|
-
// 등급 문자(A~D)를 여기서 만들지 않는다. 경계는 `figure-model` 의 `scoreOf` 가
|
|
199
|
-
// 정하고, 그것을 화면이 베끼면 두 벌이 되어 목록과 저작면이 다른 등급을 보여 준다.
|
|
200
|
-
// 목록에는 점수 숫자만 싣는다. 등급이 필요해지면 `figure-model` 이
|
|
201
|
-
// `gradeOf(score)` 를 내보내야 한다 — 그때 그것을 쓴다.
|
|
202
|
-
return html `
|
|
203
|
-
${capacity
|
|
204
|
-
? html `<span fits title=${i18next.t('text.reuse-score-explained')}>
|
|
205
|
-
${i18next.t('text.fits-n-instances', { n: capacity.instances.toLocaleString() })}
|
|
206
|
-
</span>`
|
|
207
|
-
: ''}
|
|
208
|
-
<span grade ?low=${score < ATTENTION_BELOW}>${Math.round(score)}</span>
|
|
209
|
-
<span>${i18next.t('text.triangle-count', { count: triangles })}</span>
|
|
210
|
-
`;
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
__decorate([
|
|
214
|
-
property({ type: Object }),
|
|
215
|
-
__metadata("design:type", Object)
|
|
216
|
-
], FigureCard.prototype, "figure", void 0);
|
|
217
|
-
FigureCard = __decorate([
|
|
218
|
-
customElement('figure-card')
|
|
219
|
-
], FigureCard);
|
|
220
|
-
export { FigureCard };
|
|
221
|
-
//# sourceMappingURL=figure-card.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"figure-card.js","sourceRoot":"","sources":["../../client/viewparts/figure-card.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\n\nimport { capacityFrom } from '../modeller/scene-budget.js'\nimport type { Figure } from '../types.js'\n\n/**\n * 이 값 아래면 카드에서 색으로 눈에 띄게 한다.\n *\n * **등급 경계가 아니다.** 등급(A~D)은 `figure-model` 의 `scoreOf` 가 정하고 화면은\n * 그것을 베끼지 않는다. 이것은 「눈에 걸리게 할 선」이고, 화면의 판단이다.\n */\nconst ATTENTION_BELOW = 50\n\n/**\n * Figure 한 장.\n *\n * 카드에 무엇을 실을지가 이 화면의 값이다. 이름과 썸네일만 실으면 저작자는 **무게를\n * 모른 채** 고르게 된다. 삼각형 수와 점수를 함께 실어, 「이걸 100개 놓아도 되나」를\n * 목록에서 판단할 수 있게 한다.\n */\n@customElement('figure-card')\nexport class FigureCard extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background-color: var(--md-sys-color-surface-container-lowest);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n :host(:hover) {\n border-color: var(--md-sys-color-primary);\n }\n\n div[thumbnail] {\n position: relative;\n aspect-ratio: 4 / 3;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--md-sys-color-surface-container);\n overflow: hidden;\n }\n div[thumbnail] img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n /* 썸네일이 아직 없는 것을 빈 사각형으로 두지 않는다 — 왜 없는지 말한다 */\n div[thumbnail] span[nothumb] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n font: var(--label-font, inherit);\n color: var(--md-sys-color-outline-variant);\n }\n div[thumbnail] span[nothumb] md-icon {\n --md-icon-size: 28px;\n }\n\n span[state] {\n position: absolute;\n top: 6px;\n left: 6px;\n padding: 1px 7px;\n font: var(--label-font, inherit);\n font-size: 0.7rem;\n color: var(--md-sys-color-on-secondary-container);\n background-color: var(--md-sys-color-secondary-container);\n border-radius: 6px;\n }\n\n button[remove] {\n position: absolute;\n top: 4px;\n right: 4px;\n display: none;\n padding: 3px;\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n button[remove] md-icon {\n --md-icon-size: 16px;\n }\n :host(:hover) button[remove] {\n display: block;\n }\n\n div[body] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 10px 10px 10px;\n }\n span[name] {\n font: var(--theme-font, inherit);\n font-size: 0.92rem;\n color: var(--md-sys-color-on-surface);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n /* 타입 이름은 저장되는 식별자다 — 표시 이름과 다르게 보이게 둔다 */\n code[type] {\n font-family: var(--mono-font, monospace);\n font-size: 0.72rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n div[metrics] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-top: 6px;\n font: var(--label-font, inherit);\n font-size: 0.72rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n /* 「몇 개까지」가 카드의 머리다 — 저작면 머리와 같은 말이라야 한다 */\n span[fits] {\n margin-right: auto;\n font-size: 0.82rem;\n font-weight: 700;\n color: var(--md-sys-color-primary);\n }\n span[grade] {\n padding: 0 6px;\n font-weight: 700;\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-radius: 6px;\n }\n /* 점수가 낮으면 색으로도 말한다 — 숫자만으로는 눈에 안 들어온다 */\n span[grade][low] {\n color: var(--md-sys-color-on-error, #fff);\n background-color: var(--md-sys-color-error);\n }\n span[unmeasured] {\n font-style: italic;\n color: var(--md-sys-color-outline-variant);\n }\n `\n\n @property({ type: Object }) figure!: Figure\n\n render() {\n const figure = this.figure\n if (!figure) {\n return html``\n }\n\n return html`\n <div thumbnail @click=${() => this.dispatchEvent(new CustomEvent('open'))}>\n ${figure.thumbnail\n ? html`<img src=${figure.thumbnail} alt=${figure.name} />`\n : html`\n <span nothumb>\n <md-icon>deployed_code</md-icon>\n ${i18next.t('text.thumbnail-not-made-yet')}\n </span>\n `}\n ${figure.state === 'draft' ? html`<span state>${i18next.t('label.draft')}</span>` : ''}\n <button\n remove\n title=${i18next.t('button.delete')}\n @click=${(e: Event) => {\n e.stopPropagation()\n this.dispatchEvent(new CustomEvent('remove'))\n }}\n >\n <md-icon>delete</md-icon>\n </button>\n </div>\n\n <div body @click=${() => this.dispatchEvent(new CustomEvent('open'))}>\n <span name title=${figure.name}>${figure.name}</span>\n <code type>${figure.type}</code>\n\n <div metrics>${this.renderMetrics()}</div>\n </div>\n `\n }\n\n /**\n * 무게와 점수.\n *\n * 아직 재지 않은 것(정본을 저장한 적이 없는 것)을 **0 으로 보여 주지 않는다.**\n * 0 은 「가볍다」는 뜻이 되어 버린다. 재지 않았다고 말한다.\n */\n private renderMetrics() {\n const { score, triangles, groups } = this.figure\n\n if (score == null || triangles == null) {\n return html`<span unmeasured>${i18next.t('text.not-measured-yet')}</span>`\n }\n\n // 목록이 저작면과 **같은 말**을 하게 한다. 저작면 머리가 「몇 개까지」이면 카드도\n // 그것이어야 한다 — 같은 형상을 두 화면이 다른 잣대로 말하면 무엇을 고칠지 모른다.\n const capacity = capacityFrom(groups ?? 0, triangles)\n\n // 등급 문자(A~D)를 여기서 만들지 않는다. 경계는 `figure-model` 의 `scoreOf` 가\n // 정하고, 그것을 화면이 베끼면 두 벌이 되어 목록과 저작면이 다른 등급을 보여 준다.\n // 목록에는 점수 숫자만 싣는다. 등급이 필요해지면 `figure-model` 이\n // `gradeOf(score)` 를 내보내야 한다 — 그때 그것을 쓴다.\n return html`\n ${capacity\n ? html`<span fits title=${i18next.t('text.reuse-score-explained')}>\n ${i18next.t('text.fits-n-instances', { n: capacity.instances.toLocaleString() })}\n </span>`\n : ''}\n <span grade ?low=${score < ATTENTION_BELOW}>${Math.round(score)}</span>\n <span>${i18next.t('text.triangle-count', { count: triangles })}</span>\n `\n }\n}\n"]}
|