@celestia-island/hikari 0.51.3 → 0.52.0
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
CHANGED
|
@@ -295,6 +295,28 @@
|
|
|
295
295
|
vertical-align: baseline;
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
+
// Accent face: bare text like `plain`, but tinted in the primary colour so
|
|
299
|
+
// the link visibly stands out of the run it sits in — the "this is
|
|
300
|
+
// clickable" cue (user direction 2026-09-15; the pure `plain` face melted
|
|
301
|
+
// the credits names into the sentence too well). No frame, no pill padding,
|
|
302
|
+
// and no underline at rest; the hover deepens the tint and adds one.
|
|
303
|
+
//
|
|
304
|
+
// Same specificity story as the `plain` block above: this rule (0,2,0) beats
|
|
305
|
+
// the chip base (0,1,0), and the `[data-face="accent"]:hover` / `:active`
|
|
306
|
+
// rules below (0,3,0) keep the chip's tinted hover box off the bare text.
|
|
307
|
+
.s-about-modal-link[data-face="accent"] {
|
|
308
|
+
display: inline;
|
|
309
|
+
margin: 0;
|
|
310
|
+
padding: 0;
|
|
311
|
+
border: 0;
|
|
312
|
+
border-radius: 0;
|
|
313
|
+
background: none;
|
|
314
|
+
color: rgb(var(--color-primary));
|
|
315
|
+
font-size: inherit;
|
|
316
|
+
line-height: inherit;
|
|
317
|
+
vertical-align: baseline;
|
|
318
|
+
}
|
|
319
|
+
|
|
298
320
|
// A link carrying an icon is one aligned unit (the mark, then the optional
|
|
299
321
|
// label) — icon-only links are how the GitHub mark rides beside the domains.
|
|
300
322
|
// Same specificity as the `plain` block above, so source order decides: this
|
|
@@ -339,6 +361,15 @@
|
|
|
339
361
|
color: rgb(var(--color-primary));
|
|
340
362
|
}
|
|
341
363
|
|
|
364
|
+
// The accent face already rests in the primary colour, so the hover cue is
|
|
365
|
+
// the deepened tint plus an underline — the glyph colour alone cannot move.
|
|
366
|
+
.s-about-modal-link[data-face="accent"]:hover {
|
|
367
|
+
background: none;
|
|
368
|
+
color: var(--c-primary-strong, rgb(var(--color-primary) / 80%));
|
|
369
|
+
text-decoration: underline;
|
|
370
|
+
text-underline-offset: 0.15em;
|
|
371
|
+
}
|
|
372
|
+
|
|
342
373
|
.s-about-modal-link:active {
|
|
343
374
|
background: var(--c-primary-subtle, rgb(var(--color-primary) / 8%));
|
|
344
375
|
}
|
|
@@ -348,6 +379,11 @@
|
|
|
348
379
|
color: var(--c-primary-strong, rgb(var(--color-primary) / 40%));
|
|
349
380
|
}
|
|
350
381
|
|
|
382
|
+
.s-about-modal-link[data-face="accent"]:active {
|
|
383
|
+
background: none;
|
|
384
|
+
color: rgb(var(--color-muted));
|
|
385
|
+
}
|
|
386
|
+
|
|
351
387
|
.s-about-modal-link:focus-visible {
|
|
352
388
|
outline: none;
|
|
353
389
|
box-shadow:
|
|
@@ -136,6 +136,44 @@ describe("HkAboutModal stylesheet contract", () => {
|
|
|
136
136
|
expect(declaration(ruleBody(css, `${PLAIN}:active`), "background")).toBe("none");
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
+
const ACCENT = ".s-about-modal-link[data-face=accent]";
|
|
140
|
+
|
|
141
|
+
it("keeps the accent face a bare text link tinted in the primary colour", () => {
|
|
142
|
+
const accent = ruleBody(css, ACCENT);
|
|
143
|
+
expect(accent, "the accent-face rule must survive compilation").not.toBe("");
|
|
144
|
+
expect({
|
|
145
|
+
padding: declaration(accent, "padding"),
|
|
146
|
+
border: declaration(accent, "border"),
|
|
147
|
+
radius: declaration(accent, "border-radius"),
|
|
148
|
+
background: declaration(accent, "background"),
|
|
149
|
+
// The tint IS the face: bare geometry like `plain`, but the colour
|
|
150
|
+
// comes from the theme's primary token rather than `inherit`.
|
|
151
|
+
color: declaration(accent, "color"),
|
|
152
|
+
fontSize: declaration(accent, "font-size"),
|
|
153
|
+
lineHeight: declaration(accent, "line-height"),
|
|
154
|
+
}).toEqual({
|
|
155
|
+
padding: "0",
|
|
156
|
+
border: "0",
|
|
157
|
+
radius: "0",
|
|
158
|
+
background: "none",
|
|
159
|
+
color: "rgb(var(--color-primary))",
|
|
160
|
+
fontSize: "inherit",
|
|
161
|
+
lineHeight: "inherit",
|
|
162
|
+
});
|
|
163
|
+
// No underline at rest — the tint is the cue; the hover adds one.
|
|
164
|
+
expect(declaration(accent, "text-decoration")).not.toContain("underline");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("gives the accent hover an added cue beyond the resting tint", () => {
|
|
168
|
+
// The accent face already rests in the primary colour, so a hover that
|
|
169
|
+
// only re-set the same colour would be invisible — the deepened tint
|
|
170
|
+
// plus the underline is the contract.
|
|
171
|
+
const hover = ruleBody(css, `${ACCENT}:hover`);
|
|
172
|
+
expect(declaration(hover, "background")).toBe("none");
|
|
173
|
+
expect(declaration(hover, "text-decoration")).toContain("underline");
|
|
174
|
+
expect(declaration(ruleBody(css, `${ACCENT}:active`), "background")).toBe("none");
|
|
175
|
+
});
|
|
176
|
+
|
|
139
177
|
it("keeps an icon link one aligned unit with a visible mark", () => {
|
|
140
178
|
const iconLink = ruleBody(css, ".s-about-modal-link.s-about-modal-link-has-icon");
|
|
141
179
|
expect(declaration(iconLink, "display")).toBe("inline-flex");
|
|
@@ -16,7 +16,8 @@ import { setLocale } from "../i18n/context";
|
|
|
16
16
|
* - the backdrop factory renders inside the clipped backdrop layer
|
|
17
17
|
* - licenses and links render as chips under one centered block
|
|
18
18
|
* - footer (filing) links render as external links
|
|
19
|
-
* - `face: "plain"`
|
|
19
|
+
* - `face: "plain"` / `face: "accent"` turn any of them into a bare text
|
|
20
|
+
* link (still a link,
|
|
20
21
|
* still a new tab), and an entry carrying an `icon` renders the mark, with
|
|
21
22
|
* an accessible name when it has no label to be named by
|
|
22
23
|
*
|
|
@@ -156,6 +157,31 @@ describe("HkAboutModal branding", () => {
|
|
|
156
157
|
}
|
|
157
158
|
});
|
|
158
159
|
|
|
160
|
+
it("renders a credit name as a tinted accent link when the entry asks for it", async () => {
|
|
161
|
+
mountAbout({
|
|
162
|
+
credits: [
|
|
163
|
+
{ text: "来自 " },
|
|
164
|
+
{ name: "Celestia Island", href: "https://github.com/celestia-island", face: "accent" },
|
|
165
|
+
{ text: ",由 " },
|
|
166
|
+
{ name: "伊欧", href: "https://github.com/langyo", face: "accent" },
|
|
167
|
+
{ text: " 主创" },
|
|
168
|
+
],
|
|
169
|
+
});
|
|
170
|
+
await flushModal();
|
|
171
|
+
const links = [
|
|
172
|
+
...document.body.querySelectorAll<HTMLAnchorElement>(".s-about-modal-credit-link"),
|
|
173
|
+
];
|
|
174
|
+
// Same bare-text shape as `plain` (no chip geometry), but the entry's
|
|
175
|
+
// face reaches the stylesheet as `accent`.
|
|
176
|
+
expect(links.map((link) => link.textContent)).toEqual(["Celestia Island", "伊欧"]);
|
|
177
|
+
for (const link of links) {
|
|
178
|
+
expect(link.getAttribute("data-face")).toBe("accent");
|
|
179
|
+
expect(link.classList.contains("s-about-modal-link")).toBe(true);
|
|
180
|
+
expect(link.getAttribute("target")).toBe("_blank");
|
|
181
|
+
expect(link.getAttribute("aria-label")).toBeNull();
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
159
185
|
it("renders plain faces across the link rows and the legal filings", async () => {
|
|
160
186
|
mountAbout({
|
|
161
187
|
links: [
|
|
@@ -11,11 +11,13 @@ import "./HkAboutModal.scss";
|
|
|
11
11
|
*
|
|
12
12
|
* `chip` is the dialog's original face — a ghost tag. `plain` is bare text:
|
|
13
13
|
* no frame, no underline, so the hover colour shift is the whole
|
|
14
|
-
* affordance.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* affordance. `accent` is also bare text, but tinted in the primary colour
|
|
15
|
+
* so the link visibly stands out of the sentence it sits in — the "this is
|
|
16
|
+
* clickable" cue (user direction 2026-09-15). Chosen per link, because one
|
|
17
|
+
* dialog can want both (the credits names / URLs / filings read as sentence
|
|
18
|
+
* text, the licenses stay tags).
|
|
17
19
|
*/
|
|
18
|
-
export type HAboutLinkFace = "chip" | "plain";
|
|
20
|
+
export type HAboutLinkFace = "chip" | "plain" | "accent";
|
|
19
21
|
|
|
20
22
|
/** Leading icon a link can carry; an icon-only link shows it alone. */
|
|
21
23
|
export type HAboutLinkIcon = "github";
|
|
@@ -90,8 +92,8 @@ export interface HAboutComponentVersion {
|
|
|
90
92
|
* bordered spec card holding the software-component versions, and the
|
|
91
93
|
* link rows — licenses, external links and legal filings. Every link opens
|
|
92
94
|
* in a new tab and renders in the face its entry asks for: the ghost chip,
|
|
93
|
-
* or bare text (`plain`) for names / URLs / filings that
|
|
94
|
-
* ordinary sentence text. Every branding prop is optional — the modal
|
|
95
|
+
* or bare text (`plain` / tinted `accent`) for names / URLs / filings that
|
|
96
|
+
* should read as ordinary sentence text. Every branding prop is optional — the modal
|
|
95
97
|
* degrades to the plain identity card when none are given.
|
|
96
98
|
*/
|
|
97
99
|
export const HkAboutModal = defineComponent({
|
|
@@ -111,7 +113,8 @@ export const HkAboutModal = defineComponent({
|
|
|
111
113
|
/**
|
|
112
114
|
* Credits sentence, assembled from text runs and linked names
|
|
113
115
|
* (e.g. 来自 <Celestia Island>,由 <伊欧> 主创). Each name renders in the
|
|
114
|
-
* face its entry asks for — `chip`,
|
|
116
|
+
* face its entry asks for — `chip`, bare text with `plain`, or bare
|
|
117
|
+
* text tinted in the primary colour with `accent`.
|
|
115
118
|
*/
|
|
116
119
|
credits: { type: Array as PropType<HAboutCredit[]>, default: () => [] },
|
|
117
120
|
/** License links (e.g. SySL-1.0 / BUSL-1.1), rendered centered. */
|