@celestia-island/hikari 0.45.4 → 0.45.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/package.json +1 -1
- package/src/components/HkAboutModal.scss +162 -40
- package/src/components/HkAboutModal.test.tsx +105 -34
- package/src/components/HkAboutModal.tsx +133 -103
- package/src/i18n/locales/ar/platform.json +0 -4
- package/src/i18n/locales/de/platform.json +0 -4
- package/src/i18n/locales/en/platform.json +0 -4
- package/src/i18n/locales/es/platform.json +0 -4
- package/src/i18n/locales/fr/platform.json +0 -4
- package/src/i18n/locales/ja/platform.json +0 -4
- package/src/i18n/locales/ko/platform.json +0 -4
- package/src/i18n/locales/pt/platform.json +0 -4
- package/src/i18n/locales/ru/platform.json +0 -4
- package/src/i18n/locales/zh-Hans/platform.json +0 -4
- package/src/i18n/locales/zh-Hant/platform.json +0 -4
- package/src/index.ts +5 -1
package/package.json
CHANGED
|
@@ -30,17 +30,39 @@
|
|
|
30
30
|
gap: var(--space-16, 1rem);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/* ── Identity hero: haloed logo → name → version · tagline ─────────────── */
|
|
34
|
+
|
|
33
35
|
.s-about-modal-header {
|
|
34
36
|
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
35
38
|
align-items: center;
|
|
36
|
-
gap: var(--space-
|
|
39
|
+
gap: var(--space-10, 0.625rem);
|
|
40
|
+
text-align: center;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
|
-
.
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
// Framed mark. The app logo is a light-on-light illustration (a white tablet
|
|
44
|
+
// render with its own baked soft shadow), so it needs a tinted, bounded bed:
|
|
45
|
+
// floating on the modal surface it read as a stray smudge, and the same bed
|
|
46
|
+
// gives it contrast on dark themes without hard-coding a mode.
|
|
47
|
+
.s-about-modal-logo-frame {
|
|
48
|
+
display: grid;
|
|
49
|
+
place-items: center;
|
|
50
|
+
width: 5rem;
|
|
51
|
+
height: 5rem;
|
|
42
52
|
flex-shrink: 0;
|
|
43
|
-
border
|
|
53
|
+
border: 1px solid rgb(var(--color-primary) / 14%);
|
|
54
|
+
border-radius: var(--radius-xl, 16px);
|
|
55
|
+
background: linear-gradient(
|
|
56
|
+
155deg,
|
|
57
|
+
rgb(var(--color-primary) / 13%),
|
|
58
|
+
rgb(var(--color-primary) / 4%)
|
|
59
|
+
);
|
|
60
|
+
box-shadow: 0 6px 18px rgb(var(--color-primary) / 12%);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.s-about-modal-logo-img {
|
|
64
|
+
width: 3.75rem;
|
|
65
|
+
height: 3.75rem;
|
|
44
66
|
object-fit: contain;
|
|
45
67
|
user-select: none;
|
|
46
68
|
}
|
|
@@ -49,41 +71,89 @@
|
|
|
49
71
|
display: flex;
|
|
50
72
|
align-items: center;
|
|
51
73
|
justify-content: center;
|
|
52
|
-
width:
|
|
53
|
-
height:
|
|
54
|
-
flex-shrink: 0;
|
|
74
|
+
width: 3.25rem;
|
|
75
|
+
height: 3.25rem;
|
|
55
76
|
border-radius: var(--radius-lg, 12px);
|
|
56
|
-
background:
|
|
77
|
+
background: linear-gradient(
|
|
78
|
+
150deg,
|
|
79
|
+
rgb(var(--color-primary)),
|
|
80
|
+
rgb(var(--color-secondary, var(--color-primary)))
|
|
81
|
+
);
|
|
57
82
|
color: rgb(var(--color-on-solid-text, 255 255 255));
|
|
58
|
-
font-size: var(--text-
|
|
83
|
+
font-size: var(--text-xl, 1.25rem);
|
|
59
84
|
font-weight: 700;
|
|
60
85
|
}
|
|
61
86
|
|
|
87
|
+
.s-about-modal-identity {
|
|
88
|
+
display: flex;
|
|
89
|
+
flex-direction: column;
|
|
90
|
+
align-items: center;
|
|
91
|
+
gap: var(--space-2, 0.125rem);
|
|
92
|
+
}
|
|
93
|
+
|
|
62
94
|
.s-about-modal-name {
|
|
63
95
|
margin: 0;
|
|
64
|
-
font-size: var(--text-
|
|
96
|
+
font-size: var(--text-xl, 1.25rem);
|
|
65
97
|
font-weight: 700;
|
|
98
|
+
line-height: 1.3;
|
|
99
|
+
letter-spacing: 0.01em;
|
|
66
100
|
color: rgb(var(--color-text));
|
|
67
101
|
}
|
|
68
102
|
|
|
103
|
+
// Version and tagline share one compact muted line — two stacked lines of
|
|
104
|
+
// equal weight made the hero read as a form.
|
|
105
|
+
.s-about-modal-subtitle {
|
|
106
|
+
display: flex;
|
|
107
|
+
flex-wrap: wrap;
|
|
108
|
+
align-items: center;
|
|
109
|
+
justify-content: center;
|
|
110
|
+
gap: var(--space-6, 0.375rem);
|
|
111
|
+
margin: 0;
|
|
112
|
+
font-size: var(--text-xs, 0.75rem);
|
|
113
|
+
line-height: 1.5;
|
|
114
|
+
color: rgb(var(--color-muted));
|
|
115
|
+
}
|
|
116
|
+
|
|
69
117
|
.s-about-modal-version {
|
|
70
|
-
|
|
71
|
-
|
|
118
|
+
font-variant-numeric: tabular-nums;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.s-about-modal-subtitle-sep {
|
|
122
|
+
color: rgb(var(--color-border));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.s-about-modal-tagline {
|
|
72
126
|
color: rgb(var(--color-muted));
|
|
73
127
|
}
|
|
74
128
|
|
|
75
|
-
|
|
129
|
+
/* ── Credits: made-by sentence + organization blurb ────────────────────── */
|
|
130
|
+
|
|
131
|
+
.s-about-modal-credits {
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
align-items: center;
|
|
135
|
+
gap: var(--space-4, 0.25rem);
|
|
136
|
+
margin-top: calc(-1 * var(--space-4, 0.25rem));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.s-about-modal-made-by {
|
|
76
140
|
margin: 0;
|
|
77
|
-
font-size: var(--text-
|
|
78
|
-
font-weight: 600;
|
|
141
|
+
font-size: var(--text-sm, 0.8125rem);
|
|
79
142
|
text-align: center;
|
|
80
143
|
color: rgb(var(--color-text));
|
|
81
144
|
}
|
|
82
145
|
|
|
83
|
-
.s-about-modal-
|
|
84
|
-
margin:
|
|
85
|
-
|
|
86
|
-
|
|
146
|
+
.s-about-modal-made-by .s-about-modal-row-link {
|
|
147
|
+
margin: 0 0.15em;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.s-about-modal-row-link {
|
|
151
|
+
color: rgb(var(--color-primary));
|
|
152
|
+
text-decoration: none;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.s-about-modal-row-link:hover {
|
|
156
|
+
text-decoration: underline;
|
|
87
157
|
}
|
|
88
158
|
|
|
89
159
|
.s-about-modal-description {
|
|
@@ -91,45 +161,84 @@
|
|
|
91
161
|
font-size: var(--text-xs, 0.75rem);
|
|
92
162
|
line-height: 1.6;
|
|
93
163
|
text-align: center;
|
|
164
|
+
text-wrap: pretty;
|
|
94
165
|
color: rgb(var(--color-muted));
|
|
95
166
|
}
|
|
96
167
|
|
|
168
|
+
/* ── Spec card: component version rows ────────────────────────────────── */
|
|
169
|
+
|
|
97
170
|
.s-about-modal-rows {
|
|
98
171
|
display: flex;
|
|
99
172
|
flex-direction: column;
|
|
100
|
-
|
|
173
|
+
padding: var(--space-2, 0.125rem) var(--space-14, 0.875rem);
|
|
174
|
+
border: 1px solid var(--border-subtle, rgb(100 100 100 / 12%));
|
|
175
|
+
border-radius: var(--radius-lg, 12px);
|
|
176
|
+
background: rgb(var(--color-primary) / 3%);
|
|
101
177
|
}
|
|
102
178
|
|
|
103
179
|
.s-about-modal-row {
|
|
104
180
|
display: flex;
|
|
105
181
|
align-items: center;
|
|
106
182
|
justify-content: space-between;
|
|
107
|
-
gap: var(--space-
|
|
183
|
+
gap: var(--space-12, 0.75rem);
|
|
184
|
+
min-height: 2.125rem;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.s-about-modal-row + .s-about-modal-row {
|
|
188
|
+
border-top: 1px solid var(--border-faint, rgb(100 100 100 / 10%));
|
|
108
189
|
}
|
|
109
190
|
|
|
110
191
|
.s-about-modal-row-label {
|
|
111
|
-
|
|
192
|
+
flex: 0 1 auto;
|
|
193
|
+
font-size: var(--text-xs, 0.75rem);
|
|
112
194
|
color: rgb(var(--color-muted));
|
|
113
195
|
}
|
|
114
196
|
|
|
115
197
|
.s-about-modal-row-value {
|
|
116
|
-
|
|
117
|
-
|
|
198
|
+
display: inline-flex;
|
|
199
|
+
align-items: center;
|
|
200
|
+
gap: var(--space-8, 0.5rem);
|
|
201
|
+
flex: 0 0 auto;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.s-about-modal-row-number {
|
|
118
205
|
font-family: var(--font-mono, vars.$hikari-font-family-mono);
|
|
206
|
+
font-size: var(--text-xs, 0.75rem);
|
|
207
|
+
font-variant-numeric: tabular-nums;
|
|
208
|
+
letter-spacing: -0.01em;
|
|
209
|
+
color: rgb(var(--color-text));
|
|
119
210
|
}
|
|
120
211
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
212
|
+
// Environment word (生产 / 测试) lives in its own pill so it never melts
|
|
213
|
+
// into the version string.
|
|
214
|
+
.s-about-modal-row-meta {
|
|
215
|
+
padding: 0 var(--space-6, 0.375rem);
|
|
216
|
+
border: 1px solid var(--border-subtle, rgb(100 100 100 / 12%));
|
|
217
|
+
border-radius: var(--radius-full, 9999px);
|
|
218
|
+
font-size: var(--text-2xs, 0.625rem);
|
|
219
|
+
line-height: 1.6;
|
|
220
|
+
white-space: nowrap;
|
|
221
|
+
color: rgb(var(--color-muted));
|
|
124
222
|
}
|
|
125
223
|
|
|
126
|
-
.s-about-modal-row-
|
|
127
|
-
|
|
224
|
+
.s-about-modal-row-meta[data-tone="positive"] {
|
|
225
|
+
border-color: rgb(var(--color-success) / 32%);
|
|
226
|
+
background: rgb(var(--color-success) / 10%);
|
|
227
|
+
color: rgb(var(--color-success));
|
|
128
228
|
}
|
|
129
229
|
|
|
130
|
-
.s-about-modal-
|
|
230
|
+
.s-about-modal-row-meta[data-tone="caution"] {
|
|
231
|
+
border-color: rgb(var(--color-warning) / 32%);
|
|
232
|
+
background: rgb(var(--color-warning) / 10%);
|
|
233
|
+
color: rgb(var(--color-warning));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* ── Chips: licenses and external links ───────────────────────────────── */
|
|
237
|
+
|
|
238
|
+
.s-about-modal-chips {
|
|
131
239
|
display: flex;
|
|
132
240
|
flex-direction: column;
|
|
241
|
+
align-items: center;
|
|
133
242
|
gap: var(--space-8, 0.5rem);
|
|
134
243
|
}
|
|
135
244
|
|
|
@@ -137,38 +246,50 @@
|
|
|
137
246
|
display: flex;
|
|
138
247
|
flex-wrap: wrap;
|
|
139
248
|
justify-content: center;
|
|
140
|
-
gap: var(--space-
|
|
249
|
+
gap: var(--space-6, 0.375rem);
|
|
141
250
|
}
|
|
142
251
|
|
|
252
|
+
// Ghost pills: the chips are secondary navigation, so they carry a hairline
|
|
253
|
+
// instead of a filled brand block.
|
|
143
254
|
.s-about-modal-link {
|
|
144
|
-
padding: var(--space-
|
|
145
|
-
border
|
|
146
|
-
|
|
147
|
-
color: rgb(var(--color-
|
|
255
|
+
padding: var(--space-2, 0.125rem) var(--space-10, 0.625rem);
|
|
256
|
+
border: 1px solid var(--border-subtle, rgb(100 100 100 / 12%));
|
|
257
|
+
border-radius: var(--radius-full, 9999px);
|
|
258
|
+
color: rgb(var(--color-muted));
|
|
148
259
|
font-size: var(--text-xs, 0.75rem);
|
|
260
|
+
line-height: 1.7;
|
|
149
261
|
text-decoration: none;
|
|
150
|
-
transition:
|
|
262
|
+
transition:
|
|
263
|
+
color var(--duration-short, 0.15s) ease,
|
|
264
|
+
border-color var(--duration-short, 0.15s) ease,
|
|
265
|
+
background var(--duration-short, 0.15s) ease;
|
|
151
266
|
}
|
|
152
267
|
|
|
153
268
|
.s-about-modal-link:hover {
|
|
154
|
-
|
|
269
|
+
border-color: var(--c-primary-strong, rgb(var(--color-primary) / 40%));
|
|
270
|
+
background: var(--c-primary-faint, rgb(var(--color-primary) / 5%));
|
|
271
|
+
color: rgb(var(--color-primary));
|
|
155
272
|
}
|
|
156
273
|
|
|
157
274
|
.s-about-modal-link:active {
|
|
158
|
-
background: rgb(var(--color-primary) /
|
|
275
|
+
background: var(--c-primary-subtle, rgb(var(--color-primary) / 8%));
|
|
159
276
|
}
|
|
160
277
|
|
|
161
278
|
.s-about-modal-link:focus-visible {
|
|
279
|
+
outline: none;
|
|
162
280
|
box-shadow:
|
|
163
281
|
0 0 0 2px rgb(var(--color-surface)),
|
|
164
282
|
0 0 0 4px rgb(var(--color-primary));
|
|
165
283
|
}
|
|
166
284
|
|
|
285
|
+
/* ── Legal footer: filing links + copyright ───────────────────────────── */
|
|
286
|
+
|
|
167
287
|
.s-about-modal-footer-links {
|
|
168
288
|
display: flex;
|
|
169
289
|
flex-wrap: wrap;
|
|
170
290
|
justify-content: center;
|
|
171
|
-
gap: var(--space-
|
|
291
|
+
gap: var(--space-16, 1rem);
|
|
292
|
+
margin-top: calc(-1 * var(--space-4, 0.25rem));
|
|
172
293
|
}
|
|
173
294
|
|
|
174
295
|
.s-about-modal-footer-link {
|
|
@@ -185,4 +306,5 @@
|
|
|
185
306
|
.s-about-modal-footer {
|
|
186
307
|
display: flex;
|
|
187
308
|
justify-content: center;
|
|
309
|
+
margin-top: calc(-1 * var(--space-6, 0.375rem));
|
|
188
310
|
}
|
|
@@ -5,14 +5,16 @@ import { HkAboutModal } from "./HkAboutModal";
|
|
|
5
5
|
import { setLocale } from "../i18n/context";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* HkAboutModal contract tests for the branding
|
|
8
|
+
* HkAboutModal contract tests for the branding + redesign waves:
|
|
9
9
|
* - the first-letter tile is the default identity and `logoSrc` swaps it
|
|
10
|
-
* for an image
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
10
|
+
* for an image inside the identity frame
|
|
11
|
+
* - version and tagline share one subtitle line
|
|
12
|
+
* - description / made-by / license / copyright render the given strings,
|
|
13
|
+
* madeByNameHref turns the author name into an external link
|
|
14
|
+
* - component rows split the machine value from an optional meta pill
|
|
13
15
|
* - the backdrop factory renders inside the clipped backdrop layer
|
|
14
|
-
* - links render as
|
|
15
|
-
* -
|
|
16
|
+
* - licenses and links render as chips under one centered block
|
|
17
|
+
* - footer (filing) links render as external links
|
|
16
18
|
*
|
|
17
19
|
* (Repo test convention: raw createApp + document queries, no
|
|
18
20
|
* @vue/test-utils dependency.)
|
|
@@ -94,40 +96,79 @@ describe("HkAboutModal branding", () => {
|
|
|
94
96
|
expect(query<HTMLElement>(".s-about-modal-description").textContent).toBe("Save the world.");
|
|
95
97
|
});
|
|
96
98
|
|
|
97
|
-
it("renders the made-by
|
|
99
|
+
it("renders the made-by sentence with a linked author name", async () => {
|
|
98
100
|
mountAbout({
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
madeByPrefix: "由",
|
|
102
|
+
madeByName: "伊欧",
|
|
103
|
+
madeByNameHref: "https://github.com/langyo",
|
|
104
|
+
madeBySuffix: " 主创,来自 Celestia Island",
|
|
103
105
|
});
|
|
104
106
|
await flushModal();
|
|
105
|
-
const
|
|
106
|
-
expect(
|
|
107
|
+
const line = query<HTMLElement>(".s-about-modal-made-by");
|
|
108
|
+
expect(line.textContent).toBe("由伊欧 主创,来自 Celestia Island");
|
|
107
109
|
const link = query<HTMLAnchorElement>(".s-about-modal-row-link");
|
|
108
|
-
expect(link.textContent).toBe("
|
|
109
|
-
expect(link.getAttribute("href")).toBe("https://github.com/
|
|
110
|
+
expect(link.textContent).toBe("伊欧");
|
|
111
|
+
expect(link.getAttribute("href")).toBe("https://github.com/langyo");
|
|
110
112
|
expect(link.getAttribute("target")).toBe("_blank");
|
|
111
|
-
const rows = [...document.body.querySelectorAll<HTMLElement>(".s-about-modal-row")];
|
|
112
|
-
const licenseRow = rows.find((row) => row.textContent?.includes("BUSL-1.1"));
|
|
113
|
-
expect(licenseRow, "license row renders").toBeTruthy();
|
|
114
|
-
expect(licenseRow!.textContent).toContain("License");
|
|
115
113
|
});
|
|
116
114
|
|
|
117
|
-
it("renders the made-by
|
|
118
|
-
mountAbout({
|
|
115
|
+
it("renders the made-by sentence without a link when no href", async () => {
|
|
116
|
+
mountAbout({ madeByPrefix: "由", madeByName: "伊欧", madeBySuffix: " 主创" });
|
|
119
117
|
await flushModal();
|
|
120
|
-
expect(query<HTMLElement>(".s-about-modal-
|
|
118
|
+
expect(query<HTMLElement>(".s-about-modal-made-by").textContent).toBe("由伊欧 主创");
|
|
121
119
|
expect(document.body.querySelector(".s-about-modal-row-link")).toBeNull();
|
|
122
120
|
});
|
|
123
121
|
|
|
124
|
-
it("renders
|
|
122
|
+
it("renders software-component version rows with a meta pill and tone", async () => {
|
|
123
|
+
mountAbout({
|
|
124
|
+
componentVersions: [
|
|
125
|
+
{ label: "WebUI 版本", value: "0.1.138 REW2HF", meta: "生产", metaTone: "positive" },
|
|
126
|
+
{ label: "计算引擎版本", value: "0.1.0" },
|
|
127
|
+
],
|
|
128
|
+
});
|
|
129
|
+
await flushModal();
|
|
130
|
+
const rows = [...document.body.querySelectorAll<HTMLElement>(".s-about-modal-row")];
|
|
131
|
+
expect(rows.length).toBe(2);
|
|
132
|
+
expect(rows[0]!.textContent).toContain("WebUI 版本");
|
|
133
|
+
// The number and the environment word are separate nodes: the value
|
|
134
|
+
// stays machine-readable, the tag carries the typography.
|
|
135
|
+
const number = query<HTMLElement>(".s-about-modal-row-number");
|
|
136
|
+
expect(number.textContent).toBe("0.1.138 REW2HF");
|
|
137
|
+
const meta = query<HTMLElement>(".s-about-modal-row-meta");
|
|
138
|
+
expect(meta.textContent).toBe("生产");
|
|
139
|
+
expect(meta.getAttribute("data-tone")).toBe("positive");
|
|
140
|
+
// The second row has no meta, so it renders no pill.
|
|
141
|
+
expect(rows[1]!.querySelector(".s-about-modal-row-meta")).toBeNull();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("defaults the meta pill to the neutral tone", async () => {
|
|
145
|
+
mountAbout({
|
|
146
|
+
componentVersions: [{ label: "计算引擎版本", value: "0.1.0", meta: "测试" }],
|
|
147
|
+
});
|
|
148
|
+
await flushModal();
|
|
149
|
+
expect(query<HTMLElement>(".s-about-modal-row-meta").getAttribute("data-tone")).toBe(
|
|
150
|
+
"neutral",
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("renders centered license chips", async () => {
|
|
155
|
+
mountAbout({
|
|
156
|
+
licenses: [
|
|
157
|
+
{ label: "SySL-1.0", href: "https://github.com/celestia-island/hikari/blob/master/LICENSE" },
|
|
158
|
+
{ label: "BUSL-1.1", href: "https://github.com/celestia-island/shittim-chest/blob/master/LICENSE" },
|
|
159
|
+
],
|
|
160
|
+
});
|
|
161
|
+
await flushModal();
|
|
162
|
+
const chips = [...document.body.querySelectorAll<HTMLAnchorElement>(".s-about-modal-link")];
|
|
163
|
+
expect(chips.map((chip) => chip.textContent)).toEqual(["SySL-1.0", "BUSL-1.1"]);
|
|
164
|
+
for (const chip of chips) expect(chip.getAttribute("target")).toBe("_blank");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("renders centered legal footer links", async () => {
|
|
125
168
|
mountAbout({
|
|
126
|
-
slogan: "技术宅拯救世界。",
|
|
127
169
|
footerLinks: [{ label: "京ICP备2026xxxx号", href: "https://beian.miit.gov.cn/" }],
|
|
128
170
|
});
|
|
129
171
|
await flushModal();
|
|
130
|
-
expect(query<HTMLElement>(".s-about-modal-slogan").textContent).toBe("技术宅拯救世界。");
|
|
131
172
|
const links = [
|
|
132
173
|
...document.body.querySelectorAll<HTMLAnchorElement>(".s-about-modal-footer-link"),
|
|
133
174
|
];
|
|
@@ -177,19 +218,49 @@ describe("HkAboutModal branding", () => {
|
|
|
177
218
|
expect(badge.textContent).toContain(`© ${year} Test App`);
|
|
178
219
|
});
|
|
179
220
|
|
|
180
|
-
it("
|
|
181
|
-
mountAbout(
|
|
221
|
+
it("renders no branding rows when no branding props are given", async () => {
|
|
222
|
+
mountAbout();
|
|
182
223
|
await flushModal();
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
224
|
+
expect(document.body.querySelectorAll(".s-about-modal-row").length).toBe(0);
|
|
225
|
+
expect(document.body.querySelector(".s-about-modal-made-by")).toBeNull();
|
|
226
|
+
expect(document.body.querySelector(".s-about-modal-links")).toBeNull();
|
|
227
|
+
expect(document.body.querySelector(".s-about-modal-chips")).toBeNull();
|
|
228
|
+
expect(document.body.querySelector(".s-about-modal-credits")).toBeNull();
|
|
229
|
+
});
|
|
186
230
|
|
|
187
|
-
|
|
231
|
+
it("groups license and link chips under one centered chips block", async () => {
|
|
232
|
+
mountAbout({
|
|
233
|
+
licenses: [{ label: "SySL-1.0", href: "https://example.test/sysl" }],
|
|
234
|
+
links: [{ label: "celestia.world", href: "https://celestia.world" }],
|
|
235
|
+
});
|
|
188
236
|
await flushModal();
|
|
189
|
-
|
|
237
|
+
const chips = query<HTMLElement>(".s-about-modal-chips");
|
|
238
|
+
const slots = [...chips.querySelectorAll<HTMLElement>(".s-about-modal-links")].map((el) =>
|
|
239
|
+
el.getAttribute("data-slot"),
|
|
240
|
+
);
|
|
241
|
+
expect(slots).toEqual(["licenses", "links"]);
|
|
242
|
+
expect(
|
|
243
|
+
[...chips.querySelectorAll<HTMLAnchorElement>(".s-about-modal-link")].map(
|
|
244
|
+
(chip) => chip.textContent,
|
|
245
|
+
),
|
|
246
|
+
).toEqual(["SySL-1.0", "celestia.world"]);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("frames the logo image inside the identity frame", async () => {
|
|
250
|
+
mountAbout({ logoSrc: "data:image/webp;base64,AAA" });
|
|
251
|
+
await flushModal();
|
|
252
|
+
const frame = query<HTMLElement>(".s-about-modal-logo-frame");
|
|
253
|
+
expect(frame.querySelector("img.s-about-modal-logo-img")).toBeTruthy();
|
|
254
|
+
});
|
|
190
255
|
|
|
191
|
-
|
|
256
|
+
it("keeps version and tagline on one subtitle line", async () => {
|
|
257
|
+
mountAbout({ version: "9.9.9", tagline: "Chat with your agents" });
|
|
192
258
|
await flushModal();
|
|
193
|
-
|
|
259
|
+
const subtitle = query<HTMLElement>(".s-about-modal-subtitle");
|
|
260
|
+
expect(subtitle.querySelector(".s-about-modal-version")?.textContent).toContain("9.9.9");
|
|
261
|
+
expect(subtitle.querySelector(".s-about-modal-tagline")?.textContent).toBe(
|
|
262
|
+
"Chat with your agents",
|
|
263
|
+
);
|
|
264
|
+
expect(subtitle.querySelector(".s-about-modal-subtitle-sep")).toBeTruthy();
|
|
194
265
|
});
|
|
195
266
|
});
|
|
@@ -10,18 +10,34 @@ export interface HAboutLink {
|
|
|
10
10
|
href: string;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* One software-component version row.
|
|
15
|
+
*
|
|
16
|
+
* `value` is the machine-readable half (version, optionally plus a build
|
|
17
|
+
* hash) and renders in the mono/tabular face; `meta` is the optional
|
|
18
|
+
* human-facing trailing tag (e.g. the environment word 生产 / 测试),
|
|
19
|
+
* rendered as a separate muted pill so it never melts into the version
|
|
20
|
+
* string. `metaTone` tints that pill when the tag carries a status
|
|
21
|
+
* meaning (e.g. a production environment).
|
|
22
|
+
*/
|
|
23
|
+
export interface HAboutComponentVersion {
|
|
24
|
+
label: string;
|
|
25
|
+
value: string;
|
|
26
|
+
meta?: string;
|
|
27
|
+
metaTone?: "neutral" | "positive" | "caution";
|
|
28
|
+
}
|
|
29
|
+
|
|
13
30
|
/**
|
|
14
31
|
* HkAboutModal — version / about dialog.
|
|
15
32
|
* (Upstreamed from shittim-chest's plana-legacy layer.)
|
|
16
33
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* to the plain identity + version card when none are given.
|
|
34
|
+
* Layout (2026-09 redesign): a centered identity hero (haloed logo, name,
|
|
35
|
+
* then version + tagline on one compact line), an optional credits block
|
|
36
|
+
* (made-by sentence with a linked author name + organization blurb), a
|
|
37
|
+
* bordered spec card holding the software-component versions, ghost chip
|
|
38
|
+
* rows for licenses / external links, and a muted legal footer (filing
|
|
39
|
+
* links + copyright). Every branding prop is optional — the modal degrades
|
|
40
|
+
* to the plain identity card when none are given.
|
|
25
41
|
*/
|
|
26
42
|
export const HkAboutModal = defineComponent({
|
|
27
43
|
name: "HkAboutModal",
|
|
@@ -31,28 +47,27 @@ export const HkAboutModal = defineComponent({
|
|
|
31
47
|
appName: { type: String, required: true },
|
|
32
48
|
/** Application version (e.g. "0.1.4"). */
|
|
33
49
|
version: { type: String, required: true },
|
|
34
|
-
/** Optional app build hash / commit. */
|
|
35
|
-
buildHash: { type: String, default: undefined },
|
|
36
|
-
/** Optional engine version (backend), e.g. "0.2.1". */
|
|
37
|
-
engineVersion: { type: String, default: undefined },
|
|
38
|
-
/** Optional engine build hash / commit. */
|
|
39
|
-
engineBuildHash: { type: String, default: undefined },
|
|
40
50
|
/** Optional logo image URL — replaces the first-letter tile. */
|
|
41
51
|
logoSrc: { type: String, default: undefined },
|
|
42
|
-
/** Optional one-liner
|
|
52
|
+
/** Optional one-liner shown beside the version (e.g. the app tagline). */
|
|
43
53
|
tagline: { type: String, default: undefined },
|
|
44
|
-
/** Optional centered
|
|
45
|
-
slogan: { type: String, default: undefined },
|
|
46
|
-
/** Optional centered small line under the slogan (organization blurb). */
|
|
54
|
+
/** Optional centered small line under the credits (organization blurb). */
|
|
47
55
|
description: { type: String, default: undefined },
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
|
|
56
|
+
/** Made-by sentence: text before the linked author name (e.g. "由"). */
|
|
57
|
+
madeByPrefix: { type: String, default: undefined },
|
|
58
|
+
/** Made-by sentence: the linked author name (e.g. "伊欧"). */
|
|
59
|
+
madeByName: { type: String, default: undefined },
|
|
60
|
+
/** Link applied to the author name (e.g. the GitHub profile). */
|
|
61
|
+
madeByNameHref: { type: String, default: undefined },
|
|
62
|
+
/** Made-by sentence: text after the name (e.g. " 主创,来自 …"). */
|
|
63
|
+
madeBySuffix: { type: String, default: undefined },
|
|
64
|
+
/** License chips (e.g. SySL-1.0 / BUSL-1.1), rendered centered. */
|
|
65
|
+
licenses: { type: Array as PropType<HAboutLink[]>, default: () => [] },
|
|
66
|
+
/** Software-component version rows (WebUI / engines), label + value. */
|
|
67
|
+
componentVersions: {
|
|
68
|
+
type: Array as PropType<HAboutComponentVersion[]>,
|
|
69
|
+
default: () => [],
|
|
70
|
+
},
|
|
56
71
|
/** Optional copyright holder in the footer (defaults to the app name). */
|
|
57
72
|
copyright: { type: String, default: undefined },
|
|
58
73
|
/** Optional external links (e.g. GitHub, docs). */
|
|
@@ -73,21 +88,47 @@ export const HkAboutModal = defineComponent({
|
|
|
73
88
|
setup(props, { emit }) {
|
|
74
89
|
const { t } = useI18n();
|
|
75
90
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const renderOriginValue = () => {
|
|
81
|
-
if (!props.originHref) return props.origin;
|
|
82
|
-
return (
|
|
91
|
+
const renderMadeBy = () => {
|
|
92
|
+
if (!props.madeByName) return null;
|
|
93
|
+
const name = props.madeByNameHref ? (
|
|
83
94
|
<a
|
|
84
95
|
class="s-about-modal-row-link"
|
|
85
|
-
href={props.
|
|
96
|
+
href={props.madeByNameHref}
|
|
86
97
|
target="_blank"
|
|
87
98
|
rel="noopener noreferrer"
|
|
88
99
|
>
|
|
89
|
-
{props.
|
|
100
|
+
{props.madeByName}
|
|
90
101
|
</a>
|
|
102
|
+
) : (
|
|
103
|
+
<span>{props.madeByName}</span>
|
|
104
|
+
);
|
|
105
|
+
return (
|
|
106
|
+
<p class="s-about-modal-made-by">
|
|
107
|
+
{props.madeByPrefix}
|
|
108
|
+
{name}
|
|
109
|
+
{props.madeBySuffix}
|
|
110
|
+
</p>
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const renderChips = (items: HAboutLink[], slot: string) => {
|
|
115
|
+
if (items.length === 0) return null;
|
|
116
|
+
return (
|
|
117
|
+
<div class="s-about-modal-links" data-slot={slot}>
|
|
118
|
+
<div class="s-about-modal-links-list">
|
|
119
|
+
{items.map((item) => (
|
|
120
|
+
<a
|
|
121
|
+
key={item.href}
|
|
122
|
+
href={item.href}
|
|
123
|
+
target="_blank"
|
|
124
|
+
rel="noopener noreferrer"
|
|
125
|
+
class="s-about-modal-link"
|
|
126
|
+
>
|
|
127
|
+
{item.label}
|
|
128
|
+
</a>
|
|
129
|
+
))}
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
91
132
|
);
|
|
92
133
|
};
|
|
93
134
|
|
|
@@ -106,81 +147,70 @@ export const HkAboutModal = defineComponent({
|
|
|
106
147
|
)}
|
|
107
148
|
<div class="s-about-modal-body">
|
|
108
149
|
<header class="s-about-modal-header">
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
150
|
+
<div class="s-about-modal-logo-frame">
|
|
151
|
+
{props.logoSrc ? (
|
|
152
|
+
<img
|
|
153
|
+
class="s-about-modal-logo-img"
|
|
154
|
+
src={props.logoSrc}
|
|
155
|
+
alt=""
|
|
156
|
+
draggable={false}
|
|
157
|
+
/>
|
|
158
|
+
) : (
|
|
159
|
+
<div class="s-about-modal-logo">{props.appName.slice(0, 1).toUpperCase()}</div>
|
|
160
|
+
)}
|
|
161
|
+
</div>
|
|
162
|
+
<div class="s-about-modal-identity">
|
|
115
163
|
<h2 class="s-about-modal-name">{props.appName}</h2>
|
|
116
|
-
<p class="s-about-modal-
|
|
117
|
-
|
|
164
|
+
<p class="s-about-modal-subtitle">
|
|
165
|
+
<span class="s-about-modal-version">
|
|
166
|
+
{t("hikari::about.version", "Version")} {props.version}
|
|
167
|
+
</span>
|
|
168
|
+
{props.tagline && (
|
|
169
|
+
<>
|
|
170
|
+
<span class="s-about-modal-subtitle-sep" aria-hidden="true">
|
|
171
|
+
·
|
|
172
|
+
</span>
|
|
173
|
+
<span class="s-about-modal-tagline">{props.tagline}</span>
|
|
174
|
+
</>
|
|
175
|
+
)}
|
|
118
176
|
</p>
|
|
119
|
-
{props.tagline && <p class="s-about-modal-tagline">{props.tagline}</p>}
|
|
120
177
|
</div>
|
|
121
178
|
</header>
|
|
122
179
|
|
|
123
|
-
{props.
|
|
124
|
-
|
|
180
|
+
{(props.madeByName || props.description) && (
|
|
181
|
+
<div class="s-about-modal-credits">
|
|
182
|
+
{renderMadeBy()}
|
|
183
|
+
{props.description && (
|
|
184
|
+
<p class="s-about-modal-description">{props.description}</p>
|
|
185
|
+
)}
|
|
186
|
+
</div>
|
|
187
|
+
)}
|
|
125
188
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
</span>
|
|
147
|
-
</div>
|
|
148
|
-
)}
|
|
149
|
-
{props.engineVersion && (
|
|
150
|
-
<div class="s-about-modal-row">
|
|
151
|
-
<span class="s-about-modal-row-label">
|
|
152
|
-
{t("hikari::about.engineVersion", "Engine version")}
|
|
153
|
-
</span>
|
|
154
|
-
<span class="s-about-modal-row-value">{props.engineVersion}</span>
|
|
155
|
-
</div>
|
|
156
|
-
)}
|
|
157
|
-
{props.engineBuildHash && (
|
|
158
|
-
<div class="s-about-modal-row">
|
|
159
|
-
<span class="s-about-modal-row-label">
|
|
160
|
-
{t("hikari::about.engineBuildHash", "Engine build")}
|
|
161
|
-
</span>
|
|
162
|
-
<span class="s-about-modal-row-value" title={props.engineBuildHash}>
|
|
163
|
-
{shortHash(props.engineBuildHash)}
|
|
164
|
-
</span>
|
|
165
|
-
</div>
|
|
166
|
-
)}
|
|
167
|
-
</div>
|
|
189
|
+
{props.componentVersions.length > 0 && (
|
|
190
|
+
<div class="s-about-modal-rows">
|
|
191
|
+
{props.componentVersions.map((component) => (
|
|
192
|
+
<div class="s-about-modal-row" key={component.label}>
|
|
193
|
+
<span class="s-about-modal-row-label">{component.label}</span>
|
|
194
|
+
<span class="s-about-modal-row-value">
|
|
195
|
+
<span class="s-about-modal-row-number">{component.value}</span>
|
|
196
|
+
{component.meta && (
|
|
197
|
+
<span
|
|
198
|
+
class="s-about-modal-row-meta"
|
|
199
|
+
data-tone={component.metaTone ?? "neutral"}
|
|
200
|
+
>
|
|
201
|
+
{component.meta}
|
|
202
|
+
</span>
|
|
203
|
+
)}
|
|
204
|
+
</span>
|
|
205
|
+
</div>
|
|
206
|
+
))}
|
|
207
|
+
</div>
|
|
208
|
+
)}
|
|
168
209
|
|
|
169
|
-
{props.links.length > 0 && (
|
|
170
|
-
<div class="s-about-modal-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
<a
|
|
174
|
-
key={link.href}
|
|
175
|
-
href={link.href}
|
|
176
|
-
target="_blank"
|
|
177
|
-
rel="noopener noreferrer"
|
|
178
|
-
class="s-about-modal-link"
|
|
179
|
-
>
|
|
180
|
-
{link.label}
|
|
181
|
-
</a>
|
|
182
|
-
))}
|
|
183
|
-
</div>
|
|
210
|
+
{(props.licenses.length > 0 || props.links.length > 0) && (
|
|
211
|
+
<div class="s-about-modal-chips">
|
|
212
|
+
{renderChips(props.licenses, "licenses")}
|
|
213
|
+
{renderChips(props.links, "links")}
|
|
184
214
|
</div>
|
|
185
215
|
)}
|
|
186
216
|
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "فشل النسخ",
|
|
15
15
|
"hikari::about.title": "حول",
|
|
16
16
|
"hikari::about.version": "الإصدار",
|
|
17
|
-
"hikari::about.buildHash": "البناء",
|
|
18
|
-
"hikari::about.engineVersion": "إصدار المحرك",
|
|
19
|
-
"hikari::about.engineBuildHash": "بناء المحرك",
|
|
20
|
-
"hikari::about.license": "الترخيص",
|
|
21
17
|
"hikari::theme.mode": "وضع السمة",
|
|
22
18
|
"hikari::theme.modeLight": "فاتح",
|
|
23
19
|
"hikari::theme.modeDark": "داكن",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "Kopieren fehlgeschlagen",
|
|
15
15
|
"hikari::about.title": "Über",
|
|
16
16
|
"hikari::about.version": "Version",
|
|
17
|
-
"hikari::about.buildHash": "Build",
|
|
18
|
-
"hikari::about.engineVersion": "Engine-Version",
|
|
19
|
-
"hikari::about.engineBuildHash": "Engine-Build",
|
|
20
|
-
"hikari::about.license": "Lizenz",
|
|
21
17
|
"hikari::theme.mode": "Design-Modus",
|
|
22
18
|
"hikari::theme.modeLight": "Hell",
|
|
23
19
|
"hikari::theme.modeDark": "Dunkel",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "Copy failed",
|
|
15
15
|
"hikari::about.title": "About",
|
|
16
16
|
"hikari::about.version": "Version",
|
|
17
|
-
"hikari::about.buildHash": "Build",
|
|
18
|
-
"hikari::about.engineVersion": "Engine version",
|
|
19
|
-
"hikari::about.engineBuildHash": "Engine build",
|
|
20
|
-
"hikari::about.license": "License",
|
|
21
17
|
"hikari::theme.mode": "Theme mode",
|
|
22
18
|
"hikari::theme.modeLight": "Light",
|
|
23
19
|
"hikari::theme.modeDark": "Dark",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "Error al copiar",
|
|
15
15
|
"hikari::about.title": "Acerca de",
|
|
16
16
|
"hikari::about.version": "Versión",
|
|
17
|
-
"hikari::about.buildHash": "Compilación",
|
|
18
|
-
"hikari::about.engineVersion": "Versión del motor",
|
|
19
|
-
"hikari::about.engineBuildHash": "Compilación del motor",
|
|
20
|
-
"hikari::about.license": "Licencia",
|
|
21
17
|
"hikari::theme.mode": "Modo de tema",
|
|
22
18
|
"hikari::theme.modeLight": "Claro",
|
|
23
19
|
"hikari::theme.modeDark": "Oscuro",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "Échec de la copie",
|
|
15
15
|
"hikari::about.title": "À propos",
|
|
16
16
|
"hikari::about.version": "Version",
|
|
17
|
-
"hikari::about.buildHash": "Build",
|
|
18
|
-
"hikari::about.engineVersion": "Version du moteur",
|
|
19
|
-
"hikari::about.engineBuildHash": "Build du moteur",
|
|
20
|
-
"hikari::about.license": "Licence",
|
|
21
17
|
"hikari::theme.mode": "Mode du thème",
|
|
22
18
|
"hikari::theme.modeLight": "Clair",
|
|
23
19
|
"hikari::theme.modeDark": "Sombre",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "コピーに失敗しました",
|
|
15
15
|
"hikari::about.title": "このアプリについて",
|
|
16
16
|
"hikari::about.version": "バージョン",
|
|
17
|
-
"hikari::about.buildHash": "ビルド",
|
|
18
|
-
"hikari::about.engineVersion": "エンジンバージョン",
|
|
19
|
-
"hikari::about.engineBuildHash": "エンジンビルド",
|
|
20
|
-
"hikari::about.license": "ライセンス",
|
|
21
17
|
"hikari::theme.mode": "テーマモード",
|
|
22
18
|
"hikari::theme.modeLight": "ライト",
|
|
23
19
|
"hikari::theme.modeDark": "ダーク",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "복사 실패",
|
|
15
15
|
"hikari::about.title": "정보",
|
|
16
16
|
"hikari::about.version": "버전",
|
|
17
|
-
"hikari::about.buildHash": "빌드",
|
|
18
|
-
"hikari::about.engineVersion": "엔진 버전",
|
|
19
|
-
"hikari::about.engineBuildHash": "엔진 빌드",
|
|
20
|
-
"hikari::about.license": "라이선스",
|
|
21
17
|
"hikari::theme.mode": "테마 모드",
|
|
22
18
|
"hikari::theme.modeLight": "라이트",
|
|
23
19
|
"hikari::theme.modeDark": "다크",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "Falha ao copiar",
|
|
15
15
|
"hikari::about.title": "Sobre",
|
|
16
16
|
"hikari::about.version": "Versão",
|
|
17
|
-
"hikari::about.buildHash": "Build",
|
|
18
|
-
"hikari::about.engineVersion": "Versão do motor",
|
|
19
|
-
"hikari::about.engineBuildHash": "Build do motor",
|
|
20
|
-
"hikari::about.license": "Licença",
|
|
21
17
|
"hikari::theme.mode": "Modo do tema",
|
|
22
18
|
"hikari::theme.modeLight": "Claro",
|
|
23
19
|
"hikari::theme.modeDark": "Escuro",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "Не удалось скопировать",
|
|
15
15
|
"hikari::about.title": "О программе",
|
|
16
16
|
"hikari::about.version": "Версия",
|
|
17
|
-
"hikari::about.buildHash": "Сборка",
|
|
18
|
-
"hikari::about.engineVersion": "Версия движка",
|
|
19
|
-
"hikari::about.engineBuildHash": "Сборка движка",
|
|
20
|
-
"hikari::about.license": "Лицензия",
|
|
21
17
|
"hikari::theme.mode": "Режим темы",
|
|
22
18
|
"hikari::theme.modeLight": "Светлая",
|
|
23
19
|
"hikari::theme.modeDark": "Тёмная",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "复制失败",
|
|
15
15
|
"hikari::about.title": "关于",
|
|
16
16
|
"hikari::about.version": "版本",
|
|
17
|
-
"hikari::about.buildHash": "构建",
|
|
18
|
-
"hikari::about.engineVersion": "引擎版本",
|
|
19
|
-
"hikari::about.engineBuildHash": "引擎构建",
|
|
20
|
-
"hikari::about.license": "许可证",
|
|
21
17
|
"hikari::theme.mode": "主题模式",
|
|
22
18
|
"hikari::theme.modeLight": "浅色",
|
|
23
19
|
"hikari::theme.modeDark": "深色",
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"hikari::clipboard.copyFailed": "複製失敗",
|
|
15
15
|
"hikari::about.title": "關於",
|
|
16
16
|
"hikari::about.version": "版本",
|
|
17
|
-
"hikari::about.buildHash": "建置",
|
|
18
|
-
"hikari::about.engineVersion": "引擎版本",
|
|
19
|
-
"hikari::about.engineBuildHash": "引擎建置",
|
|
20
|
-
"hikari::about.license": "授權條款",
|
|
21
17
|
"hikari::theme.mode": "主題模式",
|
|
22
18
|
"hikari::theme.modeLight": "淺色",
|
|
23
19
|
"hikari::theme.modeDark": "深色",
|
package/src/index.ts
CHANGED
|
@@ -353,7 +353,11 @@ export { HkSecretRevealModal as HSecretRevealModal } from "./components/HkSecret
|
|
|
353
353
|
export { HkCaptchaWidget as HCaptchaWidget, type HkCaptchaProvider } from "./components/HkCaptchaWidget";
|
|
354
354
|
export { HkCaptchaModal as HCaptchaModal } from "./components/HkCaptchaModal";
|
|
355
355
|
export { HkProtocolModal as HProtocolModal } from "./components/HkProtocolModal";
|
|
356
|
-
export {
|
|
356
|
+
export {
|
|
357
|
+
HkAboutModal as HAboutModal,
|
|
358
|
+
type HAboutComponentVersion,
|
|
359
|
+
type HAboutLink,
|
|
360
|
+
} from "./components/HkAboutModal";
|
|
357
361
|
export { HkLogWindow as HLogWindow, type HLogTab } from "./components/HkLogWindow";
|
|
358
362
|
export { HkCookieConsent as HCookieConsent } from "./components/HkCookieConsent";
|
|
359
363
|
export {
|