anentrypoint-design 0.0.413 → 0.0.415

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.
Files changed (103) hide show
  1. package/dist/247420.js +63 -13
  2. package/dist/app-shell.css +40 -594
  3. package/dist/colors_and_type.css +607 -47
  4. package/dist/index.html +227 -277
  5. package/dist/preview/buttons.html +39 -28
  6. package/dist/preview/colors-core.html +18 -8
  7. package/dist/preview/colors-lore.html +26 -17
  8. package/dist/preview/colors-semantic.html +24 -18
  9. package/dist/preview/dateline.html +6 -5
  10. package/dist/preview/dropzone.html +4 -3
  11. package/dist/preview/file-grid.html +10 -9
  12. package/dist/preview/file-row.html +14 -13
  13. package/dist/preview/file-toolbar.html +4 -3
  14. package/dist/preview/file-viewer.html +4 -3
  15. package/dist/preview/header.html +26 -24
  16. package/dist/preview/icons-unicode.html +8 -5
  17. package/dist/preview/index-row.html +17 -9
  18. package/dist/preview/inputs.html +4 -3
  19. package/dist/preview/manifesto.html +34 -17
  20. package/dist/preview/motion-default.js +77 -57
  21. package/dist/preview/rules.html +4 -3
  22. package/dist/preview/spacing.html +13 -12
  23. package/dist/preview/stamps-lore.html +5 -4
  24. package/dist/preview/stamps.html +4 -3
  25. package/dist/preview/theme-ink.html +7 -6
  26. package/dist/preview/type-display.html +14 -5
  27. package/dist/preview/type-mono.html +6 -5
  28. package/dist/preview/type-prose.html +12 -10
  29. package/dist/preview/type-scale.html +4 -3
  30. package/dist/preview/wordmarks.html +10 -7
  31. package/dist/site/content/globals/site.yaml +5 -3
  32. package/dist/site/content/pages/freddie.yaml +2 -2
  33. package/dist/site/content/pages/home.yaml +55 -55
  34. package/dist/site/theme.mjs +96 -348
  35. package/dist/slides/index.html +13 -13
  36. package/dist/src/bootstrap.js +10 -1
  37. package/dist/src/components/chat.js +43 -195
  38. package/dist/src/components/community.js +18 -166
  39. package/dist/src/components/content.js +30 -210
  40. package/dist/src/components/files-modals.js +14 -106
  41. package/dist/src/components/files.js +15 -116
  42. package/dist/src/components/freddie/helpers.js +53 -8
  43. package/dist/src/components/freddie.js +35 -25
  44. package/dist/src/components/shell.js +16 -114
  45. package/dist/src/components/theme-toggle.js +69 -25
  46. package/dist/src/components.js +92 -13
  47. package/dist/src/deck-stage.js +6 -4
  48. package/dist/src/highlight.js +51 -7
  49. package/dist/src/index.js +58 -12
  50. package/dist/src/kits/os/about-app.js +2 -3
  51. package/dist/src/kits/os/app-panes.css +46 -70
  52. package/dist/src/kits/os/browser-app.js +28 -1
  53. package/dist/src/kits/os/files-app.js +7 -0
  54. package/dist/src/kits/os/freddie/pages-chat.js +90 -75
  55. package/dist/src/kits/os/freddie/pages-core.js +9 -9
  56. package/dist/src/kits/os/freddie/pages-os.js +8 -8
  57. package/dist/src/kits/os/freddie/pages-tools.js +14 -14
  58. package/dist/src/kits/os/freddie/routes.js +21 -19
  59. package/dist/src/kits/os/freddie-dashboard.css +42 -21
  60. package/dist/src/kits/os/freddie-dashboard.js +6 -6
  61. package/dist/src/kits/os/icons.js +38 -16
  62. package/dist/src/kits/os/index.js +11 -0
  63. package/dist/src/kits/os/launcher.css +26 -10
  64. package/dist/src/kits/os/launcher.js +3 -0
  65. package/dist/src/kits/os/shell.js +72 -108
  66. package/dist/src/kits/os/terminal-app.js +1 -1
  67. package/dist/src/kits/os/theme.css +1330 -150
  68. package/dist/src/kits/os/wm.css +68 -15
  69. package/dist/src/kits/os/wm.js +93 -17
  70. package/dist/src/markdown.js +121 -12
  71. package/dist/src/motion.js +18 -2
  72. package/dist/src/page-html.js +62 -134
  73. package/dist/src/theme.js +106 -13
  74. package/dist/src/web-components/ds-chat.js +80 -9
  75. package/dist/ui_kits/aicat/app.js +54 -6
  76. package/dist/ui_kits/aicat/index.html +2 -0
  77. package/dist/ui_kits/blog/index.html +33 -17
  78. package/dist/ui_kits/chat/app.js +90 -22
  79. package/dist/ui_kits/chat/index.html +2 -0
  80. package/dist/ui_kits/community/app.js +86 -24
  81. package/dist/ui_kits/community/index.html +1 -0
  82. package/dist/ui_kits/dashboard/app.js +123 -34
  83. package/dist/ui_kits/dashboard/index.html +1 -0
  84. package/dist/ui_kits/docs/index.html +43 -33
  85. package/dist/ui_kits/error_404/app.js +78 -23
  86. package/dist/ui_kits/file_browser/README.md +1 -1
  87. package/dist/ui_kits/file_browser/app.js +45 -10
  88. package/dist/ui_kits/file_browser/index.html +1 -0
  89. package/dist/ui_kits/gallery/app.js +130 -51
  90. package/dist/ui_kits/homepage/app.js +156 -138
  91. package/dist/ui_kits/project_page/app.js +142 -125
  92. package/dist/ui_kits/project_page/index.html +2 -1
  93. package/dist/ui_kits/search/app.js +52 -15
  94. package/dist/ui_kits/settings/app.js +166 -39
  95. package/dist/ui_kits/signin/app.js +175 -49
  96. package/dist/ui_kits/signin/index.html +1 -0
  97. package/dist/ui_kits/slide_deck/app.js +83 -49
  98. package/dist/ui_kits/system_primer/app.js +57 -40
  99. package/dist/ui_kits/terminal/app.js +160 -43
  100. package/package.json +1 -1
  101. package/src/page-html/client-script.js +40 -11
  102. package/src/page-html/page-styles.js +22 -1
  103. package/src/page-html.js +10 -0
@@ -1,27 +1,39 @@
1
1
  import * as webjsx from 'webjsx';
2
- import { Topbar, Crumb, Status, Side, AppShell, Heading, Lede, Chip, ThemeToggle } from 'ds/components.js';
2
+ import { Topbar, Crumb, Status, Side, AppShell, PageHeader, ThemeToggle } from 'ds/components.js';
3
3
  import { mountKit } from 'ds/bootstrap.js';
4
4
  const h = webjsx.createElement;
5
5
 
6
6
  const root = document.getElementById('root');
7
7
 
8
+ // No slide sets `accent`. It fed `--slide-accent`, which the stylesheet reads
9
+ // as a `color:` on .ds-slide-hero and .ds-slide-bullet-key — so passing a raw
10
+ // lore fill ('green', 'mascot') put a background tone into a text slot, the
11
+ // exact --accent vs --accent-ink split AGENTS.md warns about, and rendered the
12
+ // title slides in a muted mid-green against near-black. Unset, both rules fall
13
+ // through to their `var(--accent-ink)` default, which is the readable tone and
14
+ // inverts correctly with the theme.
15
+ //
16
+ // Eyebrows here are reserved for the two slides that are a DIFFERENT KIND of
17
+ // slide from the body of the deck: the opening masthead and the closing marker.
18
+ // The interior slides deliberately carry none. Their eyebrows were the bare
19
+ // numbers 01-04, which is a position indicator, not a category label — and the
20
+ // deck already shows position twice (the `ds-deck-count` "n / 6" readout and
21
+ // the numbered sidebar list), so a third copy named nothing new. If you add a
22
+ // slide, it gets no eyebrow unless it genuinely names a new section.
8
23
  const slides = [
9
24
  {
10
25
  kind: 'title',
11
26
  eyebrow: '247420 · mmxxvi',
12
27
  title: 'the deck',
13
- sub: 'a 16:9 slide template built from the SDK chrome.',
14
- accent: 'green'
28
+ sub: 'a 16:9 slide template built from the SDK chrome.'
15
29
  },
16
30
  {
17
31
  kind: 'lede',
18
- eyebrow: '01',
19
- title: 'one tool, one font, one rhythm.',
20
- body: 'space grotesk for prose, jetbrains mono for tokens. nothing else. the rhythm is 8pt all the way down.'
32
+ title: 'no fonts to load.',
33
+ body: 'display, narrow and body all resolve to system-ui; mono resolves to the platform ui-monospace. nothing is fetched, so nothing reflows. the rhythm is 8pt all the way down.'
21
34
  },
22
35
  {
23
36
  kind: 'bullets',
24
- eyebrow: '02',
25
37
  title: 'three modes for theme',
26
38
  items: [
27
39
  ['auto', 'follow the OS — re-renders live when you flip dark mode'],
@@ -31,13 +43,11 @@ const slides = [
31
43
  },
32
44
  {
33
45
  kind: 'quote',
34
- eyebrow: '03',
35
46
  body: '"the surface should never lie about what the program is doing."',
36
47
  cite: '— 247420 design principle'
37
48
  },
38
49
  {
39
50
  kind: 'split',
40
- eyebrow: '04',
41
51
  title: 'usable terminals are instant.',
42
52
  left: 'output appears the moment it exists. no reveal animation, no typewriter — the user is waiting on real work.',
43
53
  right: 'showcase terminals can play a loop. they are clearly labelled "demo" and pause on prefers-reduced-motion.'
@@ -46,84 +56,98 @@ const slides = [
46
56
  kind: 'title',
47
57
  eyebrow: 'fin',
48
58
  title: 'two-four-seven · four-twenty',
49
- sub: 'always open, always a little high.',
50
- accent: 'mascot'
59
+ sub: 'always open, always a little high.'
51
60
  }
52
61
  ];
53
62
 
54
63
  const state = { i: 0 };
55
64
 
56
65
  function Slide(s) {
57
- const accentVar = s.accent ? `var(--${s.accent})` : 'var(--accent)';
58
- const eyebrow = h('div', {
59
- style: 'font-family:var(--ff-mono);font-size:11px;letter-spacing:0.1em;text-transform:uppercase;color:var(--fg-3);margin-bottom:24px'
60
- }, s.eyebrow || '');
66
+ // custom-property-only inline: carries the per-slide accent tone, no layout
67
+ const accentStyle = s.accent ? `--slide-accent:var(--${s.accent})` : '';
68
+ // null, not an empty div — an empty .ds-slide-eyebrow still paints its
69
+ // margin-bottom, leaving an unexplained gap above the eyebrow-less slides.
70
+ const eyebrow = s.eyebrow ? h('div', { class: 'ds-slide-eyebrow' }, s.eyebrow) : null;
61
71
 
62
72
  if (s.kind === 'title') {
63
- return h('div', { style: 'display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:24px' },
73
+ return h('div', { class: 'ds-slide-col ds-slide-col--start', style: accentStyle },
64
74
  eyebrow,
65
- h('div', { style: `font-size:var(--fs-hero);line-height:var(--lh-tight);color:${accentVar};letter-spacing:var(--tr-tight);font-weight:600` }, s.title),
75
+ h('div', { class: 'ds-slide-hero' }, s.title),
66
76
  s.sub ? h('div', { class: 't-lede' }, s.sub) : null
67
77
  );
68
78
  }
69
79
  if (s.kind === 'lede') {
70
- return h('div', { style: 'display:flex;flex-direction:column;justify-content:center;gap:18px;max-width:38ch' },
80
+ return h('div', { class: 'ds-slide-col ds-slide-col--narrow', style: accentStyle },
71
81
  eyebrow,
72
- h('div', { style: 'font-size:var(--fs-h1);line-height:var(--lh-snug);color:var(--fg);font-weight:500' }, s.title),
82
+ h('div', { class: 'ds-slide-h1' }, s.title),
73
83
  h('div', { class: 't-lede' }, s.body)
74
84
  );
75
85
  }
76
86
  if (s.kind === 'bullets') {
77
- return h('div', { style: 'display:flex;flex-direction:column;justify-content:center;gap:18px' },
87
+ return h('div', { class: 'ds-slide-col', style: accentStyle },
78
88
  eyebrow,
79
- h('div', { style: 'font-size:var(--fs-h1);line-height:var(--lh-snug);color:var(--fg);font-weight:500;margin-bottom:12px' }, s.title),
89
+ h('div', { class: 'ds-slide-h1 ds-slide-h1--lead' }, s.title),
80
90
  ...s.items.map(([k, v]) =>
81
- h('div', { style: 'display:flex;gap:18px;align-items:baseline;border-bottom:1px solid var(--rule);padding:12px 0' },
82
- h('span', { style: `flex:0 0 100px;font-family:var(--ff-mono);font-size:var(--fs-sm);color:${accentVar}` }, k),
83
- h('span', { style: 'color:var(--fg-2);font-size:var(--fs-lg)' }, v)
91
+ h('div', { class: 'ds-slide-bullet' },
92
+ h('span', { class: 'ds-slide-bullet-key' }, k),
93
+ h('span', { class: 'ds-slide-bullet-val' }, v)
84
94
  )
85
95
  )
86
96
  );
87
97
  }
88
98
  if (s.kind === 'quote') {
89
- return h('div', { style: 'display:flex;flex-direction:column;justify-content:center;gap:18px;max-width:42ch' },
99
+ return h('div', { class: 'ds-slide-col ds-slide-col--quote', style: accentStyle },
90
100
  eyebrow,
91
- h('div', { style: 'font-size:var(--fs-h2);line-height:var(--lh-snug);color:var(--fg);font-weight:400;font-style:italic' }, s.body),
92
- h('div', { style: 'font-family:var(--ff-mono);font-size:var(--fs-sm);color:var(--fg-3)' }, s.cite)
101
+ h('div', { class: 'ds-slide-quote-body' }, s.body),
102
+ h('div', { class: 'ds-slide-cite' }, s.cite)
93
103
  );
94
104
  }
95
105
  if (s.kind === 'split') {
96
- return h('div', { style: 'display:flex;flex-direction:column;justify-content:center;gap:24px' },
106
+ return h('div', { class: 'ds-slide-col', style: accentStyle },
97
107
  eyebrow,
98
- h('div', { style: 'font-size:var(--fs-h1);line-height:var(--lh-snug);color:var(--fg);font-weight:500' }, s.title),
99
- h('div', { style: 'display:grid;grid-template-columns:1fr 1fr;gap:32px;margin-top:12px' },
100
- h('div', { style: 'padding:18px;background:var(--bg-2);border-radius:14px;color:var(--fg-2);font-size:var(--fs-lg);line-height:var(--lh-base)' }, s.left),
101
- h('div', { style: `padding:18px;background:var(--bg-2);border-radius:14px;color:var(--fg-2);font-size:var(--fs-lg);line-height:var(--lh-base);border-left:3px solid ${accentVar}` }, s.right)
108
+ h('div', { class: 'ds-slide-h1' }, s.title),
109
+ h('div', { class: 'ds-slide-split' },
110
+ h('div', { class: 'ds-slide-split-cell' }, s.left),
111
+ h('div', { class: 'ds-slide-split-cell ds-slide-split-cell--accent' }, s.right)
102
112
  )
103
113
  );
104
114
  }
105
115
  return null;
106
116
  }
107
117
 
118
+ let touchX = null;
119
+
108
120
  function Stage() {
109
121
  const s = slides[state.i];
110
122
  return h('div', {
111
123
  class: 'ds-deck-stage',
112
- style: 'aspect-ratio:16/9;width:100%;max-width:1100px;margin:24px auto;background:var(--bg-2);border-radius:18px;padding:64px;box-sizing:border-box;display:flex;'
113
- }, h('div', { style: 'flex:1;display:flex' }, Slide(s)));
124
+ ontouchstart: (e) => { touchX = e.touches[0].clientX; },
125
+ ontouchend: (e) => {
126
+ if (touchX == null) return;
127
+ const dx = e.changedTouches[0].clientX - touchX;
128
+ touchX = null;
129
+ if (dx < -40 && state.i < slides.length - 1) { state.i++; kit.render(); }
130
+ else if (dx > 40 && state.i > 0) { state.i--; kit.render(); }
131
+ }
132
+ }, h('div', { class: 'ds-deck-slide' }, Slide(s)));
114
133
  }
115
134
 
116
135
  function Controls() {
117
- return h('div', { style: 'display:flex;align-items:center;justify-content:center;gap:14px;padding:8px;font-family:var(--ff-mono);font-size:var(--fs-sm)' },
136
+ // Disabled at the ends rather than silently no-op: a button that looks
137
+ // live and does nothing when pressed reads as a broken deck, not as "you
138
+ // are on the last slide".
139
+ const atStart = state.i === 0;
140
+ const atEnd = state.i === slides.length - 1;
141
+ return h('div', { class: 'ds-deck-controls' },
118
142
  h('button', {
119
- class: 'btn',
143
+ class: 'btn', disabled: atStart, 'aria-disabled': atStart ? 'true' : null,
120
144
  onclick: () => { if (state.i > 0) { state.i--; kit.render(); } }
121
- }, ' prev'),
122
- h('span', { style: 'color:var(--fg-3)' }, (state.i + 1) + ' / ' + slides.length),
145
+ }, '<- prev'),
146
+ h('span', { class: 'ds-deck-count' }, (state.i + 1) + ' / ' + slides.length),
123
147
  h('button', {
124
- class: 'btn',
148
+ class: 'btn', disabled: atEnd, 'aria-disabled': atEnd ? 'true' : null,
125
149
  onclick: () => { if (state.i < slides.length - 1) { state.i++; kit.render(); } }
126
- }, 'next ')
150
+ }, 'next ->')
127
151
  );
128
152
  }
129
153
 
@@ -137,26 +161,36 @@ function App() {
137
161
  crumb: Crumb({ trail: ['247420', 'kits'], leaf: 'slide deck' }),
138
162
  side: Side({
139
163
  sections: [
164
+ // The slide list IS this deck's navigation — every entry jumps
165
+ // to its slide. It was previously a static readout, which left
166
+ // the only way to reach slide 5 as four presses of `next`.
140
167
  { group: 'slides', items: slides.map((s, i) => ({
141
- glyph: i === state.i ? '' : '',
168
+ glyph: i === state.i ? '*' : '-',
142
169
  label: (i + 1) + ' · ' + (s.title || s.eyebrow || s.kind),
143
- key: 's' + i
170
+ key: 's' + i,
171
+ active: i === state.i,
172
+ href: '#slide-' + (i + 1),
173
+ onClick: (e) => { e.preventDefault(); state.i = i; kit.render(); }
144
174
  })) }
145
175
  ]
146
176
  }),
147
177
  main: [
148
- h('div', { class: 'ds-section', style: 'padding:8px' },
149
- h('div', { style: 'display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap' },
150
- h('div', {}, Heading({ level: 1, children: 'slide deck' })),
151
- ThemeToggle()
152
- ),
153
- Lede({ children: '16:9 stage, keyboard arrow keys for nav, six slide kinds: title / lede / bullets / quote / split / fin.' }),
178
+ // Dense page header, not a display H1 over a lede: the stage below
179
+ // is the content, and a full-scale kit title above it made the
180
+ // page's chrome read heavier than the slide it frames.
181
+ PageHeader({
182
+ dense: true,
183
+ title: 'slide deck',
184
+ lede: '16:9 stage · arrow keys, space and home/end navigate · six slide kinds',
185
+ right: ThemeToggle({ compact: true })
186
+ }),
187
+ h('div', { class: 'ds-section ds-section-pad' },
154
188
  Stage(),
155
189
  Controls()
156
190
  )
157
191
  ],
158
192
  status: Status({
159
- left: ['slide deck', ' slide ' + (state.i + 1) + '/' + slides.length, ' ←/→ to nav'],
193
+ left: ['slide deck', '- slide ' + (state.i + 1) + '/' + slides.length, '- </> to nav'],
160
194
  right: ['247420 / mmxxvi']
161
195
  })
162
196
  });
@@ -1,5 +1,5 @@
1
1
  import * as webjsx from 'webjsx';
2
- import { Topbar, Crumb, Status, Side, AppShell, Panel, Heading, Lede, Chip, Btn, ThemeToggle } from 'ds/components.js';
2
+ import { Topbar, Crumb, Status, Side, AppShell, Panel, PageHeader, Chip, Btn, ThemeToggle } from 'ds/components.js';
3
3
  import { mountKit } from 'ds/bootstrap.js';
4
4
  const h = webjsx.createElement;
5
5
 
@@ -48,62 +48,71 @@ const TYPE_SCALE = [
48
48
  ];
49
49
 
50
50
  function Swatch(name, v, big) {
51
- return h('div', { class: 'ds-swatch', style: 'display:flex;flex-direction:column;gap:6px' },
52
- h('div', {
53
- style: 'height:' + (big ? '64px' : '48px') +
54
- ';background:' + v +
55
- ';border-radius:10px;border:1px solid var(--rule)'
56
- }),
57
- h('div', { style: 'font-family:var(--ff-mono);font-size:11px;color:var(--fg-3)' }, name)
51
+ return h('div', { class: 'ds-swatch ds-swatch-col' },
52
+ // custom-property-only inline: carries the swatch tone, no layout
53
+ h('div', { class: 'ds-swatch-chip' + (big ? ' ds-swatch-chip--big' : ''), style: '--swatch:' + v }),
54
+ h('div', { class: 'ds-swatch-name' }, name)
58
55
  );
59
56
  }
60
57
 
61
58
  function PaletteGrid() {
62
- return Panel({ title: 'lore palette', style: 'margin:8px 0', children:
63
- h('div', { style: 'display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:12px;padding:14px 18px' },
59
+ return Panel({ id: 'palette', title: 'lore palette', count: PALETTE.length, class: 'ds-panel-gap', children:
60
+ h('div', { class: 'ds-swatch-grid-sm' },
64
61
  ...PALETTE.map(p => Swatch(p.name, p.v, false))
65
62
  )
66
63
  });
67
64
  }
68
65
 
69
66
  function SemanticGrid() {
70
- return Panel({ title: 'semantic tokensinvert with theme', count: '7', style: 'margin:8px 0', children:
71
- h('div', { style: 'display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;padding:14px 18px' },
67
+ // count reads off the array it was the hardcoded string '7', which would
68
+ // have silently gone stale the first time a token was added or removed.
69
+ return Panel({ id: 'semantic', title: 'semantic tokens — invert with theme', count: SEMANTIC.length, class: 'ds-panel-gap', children:
70
+ h('div', { class: 'ds-swatch-grid-sm ds-swatch-grid-lg' },
72
71
  ...SEMANTIC.map(p => Swatch(p.name, p.v, true))
73
72
  )
74
73
  });
75
74
  }
76
75
 
77
76
  function TypeScalePanel() {
78
- return Panel({ title: 'type scale', style: 'margin:8px 0', children:
79
- h('div', { style: 'padding:14px 18px;display:flex;flex-direction:column;gap:14px' },
77
+ return Panel({ id: 'type-scale', title: 'type scale', count: TYPE_SCALE.length, class: 'ds-panel-gap', children:
78
+ h('div', { class: 'ds-type-panel' },
80
79
  ...TYPE_SCALE.map(t =>
81
- h('div', { style: 'display:flex;align-items:baseline;gap:14px;border-bottom:1px solid var(--rule);padding-bottom:8px' },
82
- h('span', { style: 'flex:0 0 64px;font-family:var(--ff-mono);font-size:11px;color:var(--fg-3)' }, t.name),
83
- h('div', { class: t.cls, style: 'font-size:' + t.size + ';line-height:var(--lh-tight);color:var(--fg)' }, 'two-four-seven four-twenty')
80
+ h('div', { class: 'ds-type-row' },
81
+ h('span', { class: 'ds-type-row-label' }, t.name),
82
+ // custom-property-only inline: picks the sampled size token
83
+ h('div', { class: (t.cls ? t.cls + ' ' : '') + 'ds-type-sample', style: '--sample-size:' + t.size }, 'two-four-seven four-twenty')
84
84
  )
85
85
  )
86
86
  )
87
87
  });
88
88
  }
89
89
 
90
+ // The three button specimens are the only controls on this reference page that
91
+ // look pressable, so pressing one has to do something. Each reports which
92
+ // variant was last pressed, which is the one fact a primer's button row can
93
+ // truthfully demonstrate — the alternative was three buttons that swallow every
94
+ // click, on the page whose whole job is showing how controls behave.
95
+ const primState = { pressed: null };
96
+
90
97
  function PrimitivesPanel() {
91
- return Panel({ title: 'primitives', style: 'margin:8px 0', children:
92
- h('div', { style: 'padding:14px 18px;display:flex;flex-direction:column;gap:18px' },
93
- h('div', { style: 'display:flex;gap:10px;flex-wrap:wrap;align-items:center' },
94
- h('span', { style: 'font-family:var(--ff-mono);font-size:11px;color:var(--fg-3);flex:0 0 64px' }, 'chips'),
98
+ return Panel({ id: 'primitives', title: 'primitives', class: 'ds-panel-gap', children:
99
+ h('div', { class: 'ds-prim-panel' },
100
+ h('div', { class: 'ds-prim-row' },
101
+ h('span', { class: 'ds-prim-label' }, 'chips'),
95
102
  Chip({ tone: 'accent', children: 'accent' }),
96
103
  Chip({ tone: 'dim', children: 'dim' }),
97
104
  Chip({ tone: '', children: 'plain' })
98
105
  ),
99
- h('div', { style: 'display:flex;gap:10px;flex-wrap:wrap;align-items:center' },
100
- h('span', { style: 'font-family:var(--ff-mono);font-size:11px;color:var(--fg-3);flex:0 0 64px' }, 'buttons'),
101
- Btn({ primary: true, children: 'primary' }),
102
- Btn({ children: 'default' }),
103
- Btn({ ghost: true, children: 'ghost' })
106
+ h('div', { class: 'ds-prim-row' },
107
+ h('span', { class: 'ds-prim-label' }, 'buttons'),
108
+ Btn({ primary: true, children: 'primary', onClick: () => { primState.pressed = 'primary'; kit.render(); } }),
109
+ Btn({ children: 'default', onClick: () => { primState.pressed = 'default'; kit.render(); } }),
110
+ Btn({ ghost: true, children: 'ghost', onClick: () => { primState.pressed = 'ghost'; kit.render(); } }),
111
+ h('span', { class: 'ds-prim-label' },
112
+ primState.pressed ? 'last pressed: ' + primState.pressed : 'none pressed yet')
104
113
  ),
105
- h('div', { style: 'display:flex;gap:10px;flex-wrap:wrap;align-items:center' },
106
- h('span', { style: 'font-family:var(--ff-mono);font-size:11px;color:var(--fg-3);flex:0 0 64px' }, 'theme'),
114
+ h('div', { class: 'ds-prim-row' },
115
+ h('span', { class: 'ds-prim-label' }, 'theme'),
107
116
  ThemeToggle(),
108
117
  ThemeToggle({ compact: true })
109
118
  )
@@ -119,23 +128,31 @@ function App() {
119
128
  items: [['index', '../../'], ['terminal', '../terminal/']]
120
129
  }),
121
130
  crumb: Crumb({ trail: ['247420', 'kits'], leaf: 'system primer' }),
131
+ // Every entry anchors to the panel it names. These were four inert
132
+ // rows styled exactly like working nav — the only sidebar on the page
133
+ // and none of it went anywhere.
122
134
  side: Side({
123
135
  sections: [
124
136
  { group: 'sections', items: [
125
- { glyph: '', label: 'palette', key: 'p' },
126
- { glyph: '', label: 'semantic', key: 's' },
127
- { glyph: '', label: 'type scale', key: 't' },
128
- { glyph: '', label: 'primitives', key: 'r' }
137
+ { glyph: '-', label: 'palette', key: 'p', href: '#palette' },
138
+ { glyph: '-', label: 'semantic', key: 's', href: '#semantic' },
139
+ { glyph: '-', label: 'type scale', key: 't', href: '#type-scale' },
140
+ { glyph: '-', label: 'primitives', key: 'r', href: '#primitives' }
129
141
  ] }
130
142
  ]
131
143
  }),
132
144
  main: [
133
- h('div', { class: 'ds-section', style: 'padding:8px' },
134
- h('div', { style: 'display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap' },
135
- h('div', {}, Heading({ level: 1, children: 'system primer' })),
136
- ThemeToggle()
137
- ),
138
- Lede({ children: 'one page showing palette, semantic tokens, type scale, and primitives. flip the theme toggle — semantic tokens invert, lore palette stays put.' }),
145
+ // Dense header: this is a reference surface people scroll to look
146
+ // something up, not a landing page. The display H1 + wrapped lede
147
+ // spent most of the first fold on an intro, and the lede's narrow
148
+ // measure sat ragged against the full-width heading above it.
149
+ PageHeader({
150
+ dense: true,
151
+ title: 'system primer',
152
+ lede: 'palette, semantic tokens, type scale, primitives — flip the theme and the semantic tokens invert while the lore palette holds',
153
+ right: ThemeToggle({ compact: true })
154
+ }),
155
+ h('div', { class: 'ds-section ds-section-pad' },
139
156
  PaletteGrid(),
140
157
  SemanticGrid(),
141
158
  TypeScalePanel(),
@@ -143,10 +160,10 @@ function App() {
143
160
  )
144
161
  ],
145
162
  status: Status({
146
- left: ['system primer', ' ' + PALETTE.length + ' lore colors', ' ' + SEMANTIC.length + ' semantic'],
163
+ left: ['system primer', '- ' + PALETTE.length + ' lore colors', '- ' + SEMANTIC.length + ' semantic'],
147
164
  right: ['247420 / mmxxvi']
148
165
  })
149
166
  });
150
167
  }
151
168
 
152
- mountKit({ root, view: App, screen: '16 System Primer' });
169
+ const kit = mountKit({ root, view: App, screen: '16 System Primer' });