@d0nj/dsh-ui-custom 0.2.1 → 0.3.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/README.md CHANGED
@@ -10,7 +10,7 @@ The Harness ships one palette per mode. Restyling it otherwise means editing CSS
10
10
 
11
11
  - **15 presets**, each defined for both light and dark: Midnight, Paper, High contrast, Dracula, Nord, Catppuccin Mocha, Gruvbox, One Dark, Solarized, Rosé Pine, Tokyo Night, Ayu Dark, GitHub Dark, Monokai, Mono.
12
12
  - **14 colour tokens** — surfaces, borders, text, brand, and state colours — each overridable per mode.
13
- - **Typography** per role: interface/body, code, and the sidebar terminal, including font stacks and separate sizes.
13
+ - **Typography** per role: interface/body, code, and the sidebar terminal, including 40 font families and separate sizes. Families load from our own mirror, not Google Fonts.
14
14
  - **Geometry**: corner radius (0–24 px) and spacing density (compact, comfortable, spacious).
15
15
  - **Theme Studio** panel with live preview, so changes apply without a restart.
16
16
 
@@ -881,6 +881,11 @@ window.__ModuleLoader__.load({
881
881
  'fangsong', '-apple-system', 'blinkmacsystemfont',
882
882
  'inherit', 'initial', 'unset',
883
883
  ]);
884
+ /** Tokens the Client paints with that no preset names; each follows a documented token. */
885
+ const RUNTIME_ALIASES = [
886
+ ['--dsw-specific-input-major', '--dsw-alias-bg-layer-1'],
887
+ ['--dsw-alias-button-info-fill', '--dsw-alias-brand-primary'],
888
+ ];
884
889
  /**
885
890
  * Whether a value is a plausible CSS colour.
886
891
  *
@@ -1002,6 +1007,18 @@ window.__ModuleLoader__.load({
1002
1007
  }
1003
1008
  tokens[name] = { light, dark };
1004
1009
  }
1010
+ for (const [alias, source] of RUNTIME_ALIASES) {
1011
+ const modes = tokens[source];
1012
+ if (modes !== undefined)
1013
+ tokens[alias] = modes;
1014
+ }
1015
+ const accent = tokens['--dsw-alias-button-info-fill'];
1016
+ if (accent !== undefined) {
1017
+ tokens['--dsw-alias-button-info-hover'] = {
1018
+ light: `color-mix(in srgb, ${accent.light} 85%, black)`,
1019
+ dark: `color-mix(in srgb, ${accent.dark} 85%, white)`,
1020
+ };
1021
+ }
1005
1022
  for (const [name, modes] of Object.entries(geometryTokens(document.geometry))) {
1006
1023
  tokens[name] = modes;
1007
1024
  }
@@ -1277,10 +1294,10 @@ window.__ModuleLoader__.load({
1277
1294
  const matches = () => {
1278
1295
  const query = combo.query.trim().toLowerCase();
1279
1296
  if (query === '')
1280
- return [DEFAULT_CHOICE, ...choices.slice(0, 39)];
1297
+ return [DEFAULT_CHOICE, ...choices];
1281
1298
  const filtered = choices.filter((choice) => choice.toLowerCase().includes(query));
1282
1299
  const keepDefault = 'default (built-in)'.includes(query) || 'built-in'.includes(query);
1283
- return (keepDefault ? [DEFAULT_CHOICE, ...filtered] : filtered).slice(0, 40);
1300
+ return keepDefault ? [DEFAULT_CHOICE, ...filtered] : filtered;
1284
1301
  };
1285
1302
  const commit = (value) => {
1286
1303
  combo.open = false;
@@ -1518,10 +1535,20 @@ window.__ModuleLoader__.load({
1518
1535
  },
1519
1536
  "./client/hosted-fonts.js": (module, exports, __require) => {
1520
1537
  /**
1521
- * Families fetched from a font CDN on demand.
1538
+ * Families loaded on demand from our own font mirror.
1539
+ *
1540
+ * The mirror keeps every family out of Google's hands: the plugin loads one
1541
+ * stylesheet per pick, and the stylesheet's `unicode-range` rules make the
1542
+ * browser download only the subsets the page needs.
1522
1543
  *
1523
1544
  * @module @d0nj/dsh-ui-custom/hosted-fonts
1524
1545
  */
1546
+ /**
1547
+ * The catalog.
1548
+ *
1549
+ * A family added here is not loadable until the mirror carries it, so a new
1550
+ * family means a new mirror tag and a new version of this package.
1551
+ */
1525
1552
  const HOSTED_FONTS = [
1526
1553
  { family: 'Inter', category: 'sans' },
1527
1554
  { family: 'IBM Plex Sans', category: 'sans' },
@@ -1542,6 +1569,10 @@ window.__ModuleLoader__.load({
1542
1569
  { family: 'Sora', category: 'sans' },
1543
1570
  { family: 'Space Grotesk', category: 'sans' },
1544
1571
  { family: 'JetBrains Mono', category: 'mono' },
1572
+ { family: 'Geist Mono', category: 'mono' },
1573
+ { family: 'Victor Mono', category: 'mono' },
1574
+ { family: 'MonoLisa', category: 'mono' },
1575
+ { family: 'SF Mono', category: 'mono' },
1545
1576
  { family: 'Fira Code', category: 'mono' },
1546
1577
  { family: 'Source Code Pro', category: 'mono' },
1547
1578
  { family: 'IBM Plex Mono', category: 'mono' },
@@ -1560,17 +1591,22 @@ window.__ModuleLoader__.load({
1560
1591
  { family: 'Bricolage Grotesque', category: 'display' },
1561
1592
  { family: 'Instrument Serif', category: 'display' },
1562
1593
  ];
1563
- const CDN_BASE = 'https://fonts.googleapis.com/css2';
1594
+ const CDN_BASE = 'https://cdn.jsdelivr.net/gh/d0nj/dsh-fonts@v1.0.0/fonts';
1564
1595
  /** Stylesheets outlive any one render, and a repeat request is a wasted round-trip. */
1565
1596
  const requested = new Set();
1597
+ /**
1598
+ * @param family - the family to address.
1599
+ * @returns its directory name in the mirror.
1600
+ */
1601
+ function fontSlug(family) {
1602
+ return family.toLowerCase().replaceAll(' ', '-').replaceAll(/[^a-z0-9-]/gu, '');
1603
+ }
1566
1604
  /**
1567
1605
  * @param font - the family to request.
1568
1606
  * @returns an absolute stylesheet URL.
1569
1607
  */
1570
1608
  function hostedFontUrl(font) {
1571
- const name = font.family.trim().replace(/\s+/gu, '+');
1572
- const weights = (font.weights ?? [400]).join(';');
1573
- return `${CDN_BASE}?family=${name}:wght@${weights}&display=swap`;
1609
+ return `${CDN_BASE}/${fontSlug(font.family)}/font.css`;
1574
1610
  }
1575
1611
  /**
1576
1612
  * Load one family into the page; resolves on failure too, because a font that
@@ -1615,7 +1651,7 @@ window.__ModuleLoader__.load({
1615
1651
  return fonts.find((font) => font.family.toLowerCase() === key);
1616
1652
  }
1617
1653
  //# sourceMappingURL=hosted-fonts.js.map
1618
- Object.assign(exports, { hostedFontUrl: hostedFontUrl, loadHostedFont: loadHostedFont, hostedFamilies: hostedFamilies, findHostedFont: findHostedFont, HOSTED_FONTS: HOSTED_FONTS });
1654
+ Object.assign(exports, { fontSlug: fontSlug, hostedFontUrl: hostedFontUrl, loadHostedFont: loadHostedFont, hostedFamilies: hostedFamilies, findHostedFont: findHostedFont, HOSTED_FONTS: HOSTED_FONTS });
1619
1655
 
1620
1656
  },
1621
1657
  }
@@ -1,5 +1,9 @@
1
1
  /**
2
- * Families fetched from a font CDN on demand.
2
+ * Families loaded on demand from our own font mirror.
3
+ *
4
+ * The mirror keeps every family out of Google's hands: the plugin loads one
5
+ * stylesheet per pick, and the stylesheet's `unicode-range` rules make the
6
+ * browser download only the subsets the page needs.
3
7
  *
4
8
  * @module @d0nj/dsh-ui-custom/hosted-fonts
5
9
  */
@@ -7,14 +11,23 @@
7
11
  export type FontCategory = 'sans' | 'serif' | 'mono' | 'display';
8
12
  /** One hosted family this package can load. */
9
13
  export interface HostedFont {
10
- /** CSS family name, exactly as the stylesheet declares it. */
14
+ /** CSS family name, exactly as the mirrored stylesheet declares it. */
11
15
  readonly family: string;
12
16
  /** Grouping in the picker. */
13
17
  readonly category: FontCategory;
14
- /** Weights requested from the CDN; 400 is enough for body text. */
15
- readonly weights?: readonly number[];
16
18
  }
19
+ /**
20
+ * The catalog.
21
+ *
22
+ * A family added here is not loadable until the mirror carries it, so a new
23
+ * family means a new mirror tag and a new version of this package.
24
+ */
17
25
  export declare const HOSTED_FONTS: readonly HostedFont[];
26
+ /**
27
+ * @param family - the family to address.
28
+ * @returns its directory name in the mirror.
29
+ */
30
+ export declare function fontSlug(family: string): string;
18
31
  /**
19
32
  * @param font - the family to request.
20
33
  * @returns an absolute stylesheet URL.
@@ -1,8 +1,18 @@
1
1
  /**
2
- * Families fetched from a font CDN on demand.
2
+ * Families loaded on demand from our own font mirror.
3
+ *
4
+ * The mirror keeps every family out of Google's hands: the plugin loads one
5
+ * stylesheet per pick, and the stylesheet's `unicode-range` rules make the
6
+ * browser download only the subsets the page needs.
3
7
  *
4
8
  * @module @d0nj/dsh-ui-custom/hosted-fonts
5
9
  */
10
+ /**
11
+ * The catalog.
12
+ *
13
+ * A family added here is not loadable until the mirror carries it, so a new
14
+ * family means a new mirror tag and a new version of this package.
15
+ */
6
16
  export const HOSTED_FONTS = [
7
17
  { family: 'Inter', category: 'sans' },
8
18
  { family: 'IBM Plex Sans', category: 'sans' },
@@ -23,6 +33,10 @@ export const HOSTED_FONTS = [
23
33
  { family: 'Sora', category: 'sans' },
24
34
  { family: 'Space Grotesk', category: 'sans' },
25
35
  { family: 'JetBrains Mono', category: 'mono' },
36
+ { family: 'Geist Mono', category: 'mono' },
37
+ { family: 'Victor Mono', category: 'mono' },
38
+ { family: 'MonoLisa', category: 'mono' },
39
+ { family: 'SF Mono', category: 'mono' },
26
40
  { family: 'Fira Code', category: 'mono' },
27
41
  { family: 'Source Code Pro', category: 'mono' },
28
42
  { family: 'IBM Plex Mono', category: 'mono' },
@@ -41,17 +55,22 @@ export const HOSTED_FONTS = [
41
55
  { family: 'Bricolage Grotesque', category: 'display' },
42
56
  { family: 'Instrument Serif', category: 'display' },
43
57
  ];
44
- const CDN_BASE = 'https://fonts.googleapis.com/css2';
58
+ const CDN_BASE = 'https://cdn.jsdelivr.net/gh/d0nj/dsh-fonts@v1.0.0/fonts';
45
59
  /** Stylesheets outlive any one render, and a repeat request is a wasted round-trip. */
46
60
  const requested = new Set();
61
+ /**
62
+ * @param family - the family to address.
63
+ * @returns its directory name in the mirror.
64
+ */
65
+ export function fontSlug(family) {
66
+ return family.toLowerCase().replaceAll(' ', '-').replaceAll(/[^a-z0-9-]/gu, '');
67
+ }
47
68
  /**
48
69
  * @param font - the family to request.
49
70
  * @returns an absolute stylesheet URL.
50
71
  */
51
72
  export function hostedFontUrl(font) {
52
- const name = font.family.trim().replace(/\s+/gu, '+');
53
- const weights = (font.weights ?? [400]).join(';');
54
- return `${CDN_BASE}?family=${name}:wght@${weights}&display=swap`;
73
+ return `${CDN_BASE}/${fontSlug(font.family)}/font.css`;
55
74
  }
56
75
  /**
57
76
  * Load one family into the page; resolves on failure too, because a font that
@@ -250,10 +250,10 @@ export function ThemeStudio(React, props) {
250
250
  const matches = () => {
251
251
  const query = combo.query.trim().toLowerCase();
252
252
  if (query === '')
253
- return [DEFAULT_CHOICE, ...choices.slice(0, 39)];
253
+ return [DEFAULT_CHOICE, ...choices];
254
254
  const filtered = choices.filter((choice) => choice.toLowerCase().includes(query));
255
255
  const keepDefault = 'default (built-in)'.includes(query) || 'built-in'.includes(query);
256
- return (keepDefault ? [DEFAULT_CHOICE, ...filtered] : filtered).slice(0, 40);
256
+ return keepDefault ? [DEFAULT_CHOICE, ...filtered] : filtered;
257
257
  };
258
258
  const commit = (value) => {
259
259
  combo.open = false;
package/dist/resolve.js CHANGED
@@ -24,6 +24,11 @@ const GENERIC_FAMILIES = new Set([
24
24
  'fangsong', '-apple-system', 'blinkmacsystemfont',
25
25
  'inherit', 'initial', 'unset',
26
26
  ]);
27
+ /** Tokens the Client paints with that no preset names; each follows a documented token. */
28
+ const RUNTIME_ALIASES = [
29
+ ['--dsw-specific-input-major', '--dsw-alias-bg-layer-1'],
30
+ ['--dsw-alias-button-info-fill', '--dsw-alias-brand-primary'],
31
+ ];
27
32
  /**
28
33
  * Whether a value is a plausible CSS colour.
29
34
  *
@@ -145,6 +150,18 @@ export function resolveCustomization(document) {
145
150
  }
146
151
  tokens[name] = { light, dark };
147
152
  }
153
+ for (const [alias, source] of RUNTIME_ALIASES) {
154
+ const modes = tokens[source];
155
+ if (modes !== undefined)
156
+ tokens[alias] = modes;
157
+ }
158
+ const accent = tokens['--dsw-alias-button-info-fill'];
159
+ if (accent !== undefined) {
160
+ tokens['--dsw-alias-button-info-hover'] = {
161
+ light: `color-mix(in srgb, ${accent.light} 85%, black)`,
162
+ dark: `color-mix(in srgb, ${accent.dark} 85%, white)`,
163
+ };
164
+ }
148
165
  for (const [name, modes] of Object.entries(geometryTokens(document.geometry))) {
149
166
  tokens[name] = modes;
150
167
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d0nj/dsh-ui-custom",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Theme, colour-token, typography and geometry customisation for the DeepSeek Harness Web UI, with presets and a live editor.",
5
5
  "license": "MIT",
6
6
  "repository": {