@devchitchat/chat 4.5.0 → 5.0.1

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 (39) hide show
  1. package/index.js +0 -9
  2. package/package.json +2 -3
  3. package/pages/_layout.html +0 -7
  4. package/pages/admin/_layout.html +0 -7
  5. package/pages/channels/[channelId].phtml +17 -42
  6. package/pages/design/_layout.html +349 -0
  7. package/pages/design/_layout.js +13 -0
  8. package/pages/design/components/index.js +3 -0
  9. package/pages/design/components/index.phtml +380 -0
  10. package/pages/design/index.js +3 -0
  11. package/pages/design/index.phtml +78 -0
  12. package/pages/design/principles/index.js +3 -0
  13. package/pages/design/principles/index.phtml +147 -0
  14. package/pages/design/tokens/index.js +3 -0
  15. package/pages/design/tokens/index.phtml +236 -0
  16. package/pages/public/client/app.js +171 -13
  17. package/pages/public/client/controllers/ChatController.js +204 -0
  18. package/pages/public/client/controllers/WebSocketController.js +191 -0
  19. package/pages/public/client/model/AppModel.js +351 -0
  20. package/pages/public/client/model/events.js +41 -0
  21. package/pages/public/client/resizable.js +74 -0
  22. package/pages/public/client/rtc-peer-manager.js +5 -2
  23. package/pages/public/client/settings-sync.js +45 -7
  24. package/pages/public/client/shared/messages.js +21 -9
  25. package/pages/public/client/theme.js +6 -4
  26. package/pages/public/client/views/CallView.js +754 -0
  27. package/pages/public/client/views/ChatHeaderView.js +67 -0
  28. package/pages/public/client/views/ComposerView.js +491 -0
  29. package/pages/public/client/views/MessageListView.js +461 -0
  30. package/pages/public/client/views/SidebarView.js +977 -0
  31. package/pages/public/client/views/ThreadPanelView.js +260 -0
  32. package/pages/public/client/views/shared/EmojiPickerSingleton.js +201 -0
  33. package/pages/public/client/views/shared/MentionPicker.js +139 -0
  34. package/pages/public/client/views/shared/MessageInteractions.js +353 -0
  35. package/pages/public/themes/base.css +29 -31
  36. package/src/ws/ChatServer.js +2 -1
  37. package/src/ws/handlers/rtcHandlers.js +7 -0
  38. package/pages/public/client/islands/call.js +0 -2282
  39. package/pages/public/client/islands/sidebar.js +0 -1198
package/index.js CHANGED
@@ -108,11 +108,6 @@ export async function setup(config = {}) {
108
108
  return new Response('WebSocket upgrade required', { status: 426 })
109
109
  }
110
110
 
111
- routes[p('/vendor/rdbl.js')] = () =>
112
- new Response(Bun.file(new URL(import.meta.resolve('@devchitchat/rdbljs/src/rdbl.js'))), {
113
- headers: { 'Content-Type': 'text/javascript' },
114
- })
115
-
116
111
  routes[p('/sw.js')] = () => new Response(
117
112
  Bun.file(CHAT_PAGES_DIR + '/public/sw.js'),
118
113
  { headers: { 'Content-Type': 'application/javascript; charset=utf-8', 'Service-Worker-Allowed': `${basePath}/`, 'Cache-Control': 'no-cache, no-store' } }
@@ -191,10 +186,6 @@ export async function start(config = {}) {
191
186
  })) return
192
187
  return new Response('WebSocket upgrade required', { status: 426 })
193
188
  },
194
- [p('/vendor/rdbl.js')]: () =>
195
- new Response(Bun.file(new URL(import.meta.resolve('@devchitchat/rdbljs/src/rdbl.js'))), {
196
- headers: { 'Content-Type': 'text/javascript' },
197
- }),
198
189
  [p('/sw.js')]: () => new Response(
199
190
  Bun.file(CHAT_PAGES_DIR + '/public/sw.js'),
200
191
  { headers: { 'Content-Type': 'application/javascript; charset=utf-8', 'Service-Worker-Allowed': `${basePath}/`, 'Cache-Control': 'no-cache, no-store' } }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devchitchat/chat",
3
- "version": "4.5.0",
3
+ "version": "5.0.1",
4
4
  "description": "A small chat app. p2p video and screenshare.",
5
5
  "scripts": {
6
6
  "dev": "bun --watch index.js",
@@ -29,8 +29,7 @@
29
29
  "styles.css"
30
30
  ],
31
31
  "dependencies": {
32
- "@devchitchat/index97": "^3.3.0",
33
- "@devchitchat/rdbljs": "^2.0.1"
32
+ "@devchitchat/index97": "^3.3.0"
34
33
  },
35
34
  "main": "index.js",
36
35
  "module": "index.js",
@@ -12,13 +12,6 @@
12
12
  <link rel="stylesheet" href="{{base}}/themes/base.css">
13
13
  <link rel="stylesheet" href="{{base}}/themes/dark.css" id="theme-stylesheet">
14
14
  <script>window.__BASE_PATH__ = "{{base}}"</script>
15
- <script type="importmap">
16
- {
17
- "imports": {
18
- "@devchitchat/rdbljs": "{{base}}/vendor/rdbl.js"
19
- }
20
- }
21
- </script>
22
15
  </head>
23
16
  <body>
24
17
  <main class="app-shell">
@@ -12,13 +12,6 @@
12
12
  <link rel="stylesheet" href="{{base}}/themes/base.css">
13
13
  <link rel="stylesheet" href="{{base}}/themes/dark.css" id="theme-stylesheet">
14
14
  <script>window.__BASE_PATH__ = "{{base}}"</script>
15
- <script type="importmap">
16
- {
17
- "imports": {
18
- "@devchitchat/rdbljs": "{{base}}/vendor/rdbl.js"
19
- }
20
- }
21
- </script>
22
15
  </head>
23
16
  <body>
24
17
  <header class="admin-topbar">
@@ -1,29 +1,15 @@
1
- <!-- Sidebar island: hub/channel nav + online presence -->
2
- <aside class="sidebar" id="sidebar" role="navigation" aria-label="Channels" island="{{base}}/client/islands/sidebar.js" data-currentChannel="{{currentChannelId}}" data-userid="{{user.user_id}}" data-vapid-key="{{vapidPublicKey}}">
3
- <section each="hubs" key="hub_id" class="hub-group">
1
+ <aside class="sidebar" id="sidebar" role="navigation" aria-label="Channels" data-currentChannel="{{currentChannelId}}" data-userid="{{user.user_id}}" data-vapid-key="{{vapidPublicKey}}">
2
+ <section class="hub-group">
4
3
  {{#each hubs}}
5
- <details class="hub-header" data-key="{{hub_id}}" data-visibility="{{visibility}}" data-description="{{description}}" draggable="true" open>
4
+ <details class="hub-header" data-hub-id="{{hub_id}}" data-visibility="{{visibility}}" data-description="{{description}}" draggable="true" open>
6
5
  <summary class="hub-name" data-hub-id="{{hub_id}}">
7
- <span text="name">{{name}}</span>
8
- <button class="btn-hub-gear btn-icon" title="Hub settings" aria-label="Hub settings" type="button">&#9881;</button>
6
+ <span>{{name}}</span>
9
7
  <button class="btn-hub-add btn-icon" title="Create a channel" aria-label="Create a channel" type="button">+</button>
10
8
  </summary>
11
- <ul each="channels" key="channel_id" class="channel-list">
12
- <template>
13
- <li class="channel-item" cls="className" draggable="true">
14
- <a attr="href:url; title:name" text="name" class="channel-link"
15
- data-channel-id=""
16
- data-channel-name=""
17
- data-channel-topic=""
18
- data-channel-kind=""
19
- data-channel-visibility=""></a>
20
- <span class="call-badge" aria-label="Call active"></span>
21
- <button class="btn-channel-gear btn-icon" title="Channel settings" aria-label="Channel settings" type="button">&#9881;</button>
22
- </li>
23
- </template>
9
+ <ul class="channel-list">
24
10
  {{#each channels}}
25
- <li data-key="{{channel_id}}" class="channel-item {{className}}" cls="className" draggable="true">
26
- <a attr="href:url; title:name" text="name" class="channel-link"
11
+ <li class="channel-item {{className}}" draggable="true">
12
+ <a class="channel-link"
27
13
  href="{{base}}/channels/{{channel_id}}"
28
14
  title="{{name}}"
29
15
  data-channel-id="{{channel_id}}"
@@ -32,7 +18,6 @@
32
18
  data-channel-kind="{{kind}}"
33
19
  data-channel-visibility="{{visibility}}">{{name}}</a>
34
20
  <span class="call-badge" aria-label="Call active"></span>
35
- <button class="btn-channel-gear btn-icon" title="Channel settings" aria-label="Channel settings" type="button">&#9881;</button>
36
21
  </li>
37
22
  {{/each}}
38
23
  </ul>
@@ -43,7 +28,7 @@
43
28
  <section class="dm-section">
44
29
  <h3 class="dm-section-title">Direct Messages</h3>
45
30
  <ul class="dm-list" id="dm-list">
46
- <!-- populated by sidebar.js via dm.list_result -->
31
+ <!-- populated by SidebarView via dm.list_result -->
47
32
  </ul>
48
33
  </section>
49
34
 
@@ -83,8 +68,7 @@
83
68
  <!-- Main content wrapper: slides in from right on mobile -->
84
69
  <div class="main-content">
85
70
 
86
- <!-- Chat + call island: messages, composer, and WebRTC -->
87
- <section class="chat-panel" island="{{base}}/client/islands/call.js"
71
+ <section class="chat-panel"
88
72
  data-id="{{channel.channel_id}}"
89
73
  data-name="{{channel.name}}"
90
74
  data-topic="{{channel.topic}}"
@@ -101,8 +85,8 @@
101
85
  <header class="chat-header">
102
86
  <button class="btn-back-mobile" aria-label="Back to channels" type="button">&#8592;</button>
103
87
  <hgroup>
104
- <h2 class="chat-title" text="channelName">{{channel.name}}</h2>
105
- <p class="chat-topic" text="channelTopic">{{channel.topic}}</p>
88
+ <h2 class="chat-title">{{channel.name}}</h2>
89
+ <p class="chat-topic">{{channel.topic}}</p>
106
90
  </hgroup>
107
91
  <div class="chat-header-actions">
108
92
  <button class="btn-ghost btn-start-call" id="btn-start-call" aria-label="Start call" type="button">
@@ -135,7 +119,7 @@
135
119
  <div class="messages" id="messages" aria-live="polite" aria-label="Messages" role="log">
136
120
  <div class="load-more-sentinel" id="load-more-sentinel" aria-hidden="true" hidden></div>
137
121
  {{#each seedMessages}}
138
- <article class="message" data-seq="{{seq}}" data-msg-id="{{msg_id}}" data-key="message_id" data-user-id="{{user_id}}" data-raw-text="{{raw_text}}" data-edited-at="{{edited_at}}" data-attachments="{{attachments_json}}" data-reactions="{{reactions_json}}" data-reply-count="{{reply_count}}">
122
+ <article class="message" data-seq="{{seq}}" data-msg-id="{{msg_id}}" data-user-id="{{user_id}}" data-raw-text="{{raw_text}}" data-edited-at="{{edited_at}}" data-attachments="{{attachments_json}}" data-reactions="{{reactions_json}}" data-reply-count="{{reply_count}}">
139
123
  <span class="message-handle" data-user-id="{{user_id}}">{{user_display_name}}</span>
140
124
  <time class="message-time" datetime="{{ts}}">{{ts_fmt}}{{#if edited_at}}<span class="message-edited">(edited)</span>{{/if}}</time>
141
125
  <div class="message-text">{{{text}}}</div>
@@ -143,25 +127,16 @@
143
127
  <div class="reaction-bar"></div>
144
128
  </article>
145
129
  {{/each}}
146
- <template>
147
- <article class="message">
148
- <span class="message-handle"></span>
149
- <time class="message-time" datetime=""></time>
150
- <p class="message-text" text="text"></p>
151
- </article>
152
- </template>
153
130
  </div>
154
131
 
155
132
  <footer class="composer">
156
- <button onclick="toggleUrgentMode" class="btn-urgent-toggle" type="button"
157
- cls="urgentClass"
133
+ <button class="btn-urgent-toggle" type="button"
158
134
  title="Toggle urgent mode — Enter sends as urgent (Ctrl+Enter for one-shot)" aria-label="Toggle urgent send">&#x1F514;</button>
159
- <textarea model="draft" id="message-input" placeholder="Message in {{channel.name}}" aria-label="Write a message"
160
- rows="1" onkeydown="handleComposerKey">
161
- </textarea>
162
- <button onclick="toggleComposeMode" class="btn-compose-expand btn-icon" type="button"
135
+ <textarea id="message-input" placeholder="Message in {{channel.name}}" aria-label="Write a message"
136
+ rows="1"></textarea>
137
+ <button class="btn-compose-expand btn-icon" type="button"
163
138
  title="Compose mode (Ctrl+E)" aria-label="Open compose mode">&#x26F6;</button>
164
- <button onclick="sendMessage" class="btn-send" aria-label="Send message" type="button">Send</button>
139
+ <button class="btn-send" aria-label="Send message" type="button">Send</button>
165
140
  </footer>
166
141
 
167
142
  <!-- Compose overlay — full-panel editor with Write / Preview tabs -->
@@ -0,0 +1,349 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="dark">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Design System — devchitchat</title>
7
+ <link rel="stylesheet" href="{{base}}/themes/base.css">
8
+ <link rel="stylesheet" href="{{base}}/themes/dark.css" id="theme-stylesheet">
9
+ <script>window.__BASE_PATH__ = "{{base}}"</script>
10
+ <style>
11
+ /* ── Design system shell ─────────────────────────────────────── */
12
+ *, *::before, *::after { box-sizing: border-box }
13
+
14
+ .ds-shell {
15
+ display: flex;
16
+ min-height: 100dvh;
17
+ background: var(--bg-base);
18
+ color: var(--text-primary);
19
+ font-family: var(--font-sans);
20
+ }
21
+
22
+ /* ── Left nav ────────────────────────────────────────────────── */
23
+ .ds-nav {
24
+ width: 220px;
25
+ flex-shrink: 0;
26
+ position: sticky;
27
+ top: 0;
28
+ height: 100dvh;
29
+ overflow-y: auto;
30
+ border-right: 1px solid var(--border);
31
+ background: var(--bg-sidebar);
32
+ display: flex;
33
+ flex-direction: column;
34
+ padding: 0 0 24px;
35
+ }
36
+
37
+ .ds-nav-brand {
38
+ padding: 20px 16px 8px;
39
+ font-size: 11px;
40
+ font-weight: 600;
41
+ letter-spacing: 0.08em;
42
+ text-transform: uppercase;
43
+ color: var(--text-muted);
44
+ border-bottom: 1px solid var(--border);
45
+ margin-bottom: 8px;
46
+ }
47
+
48
+ .ds-nav-brand a {
49
+ color: var(--text-muted);
50
+ text-decoration: none;
51
+ }
52
+
53
+ .ds-nav-brand a:hover { color: var(--text-secondary) }
54
+
55
+ .ds-nav-section {
56
+ padding: 16px 16px 4px;
57
+ font-size: 10px;
58
+ font-weight: 600;
59
+ letter-spacing: 0.1em;
60
+ text-transform: uppercase;
61
+ color: var(--text-muted);
62
+ }
63
+
64
+ .ds-nav-link {
65
+ display: block;
66
+ padding: 6px 16px;
67
+ font-size: 13px;
68
+ color: var(--text-secondary);
69
+ text-decoration: none;
70
+ border-radius: var(--radius-sm);
71
+ margin: 1px 6px;
72
+ transition: background var(--transition), color var(--transition);
73
+ }
74
+
75
+ .ds-nav-link:hover {
76
+ background: var(--bg-hover);
77
+ color: var(--text-primary);
78
+ }
79
+
80
+ .ds-nav-link.active {
81
+ background: var(--bg-active);
82
+ color: var(--accent);
83
+ font-weight: 500;
84
+ }
85
+
86
+ .ds-nav-footer {
87
+ margin-top: auto;
88
+ padding: 12px 16px 0;
89
+ border-top: 1px solid var(--border);
90
+ display: flex;
91
+ flex-direction: column;
92
+ gap: 8px;
93
+ }
94
+
95
+ /* ── Main content ─────────────────────────────────────────────── */
96
+ .ds-content {
97
+ flex: 1;
98
+ min-width: 0;
99
+ padding: 48px 56px;
100
+ max-width: 960px;
101
+ }
102
+
103
+ /* ── Page sections ────────────────────────────────────────────── */
104
+ .ds-page-title {
105
+ font-size: 28px;
106
+ font-weight: 600;
107
+ letter-spacing: -0.02em;
108
+ color: var(--text-primary);
109
+ margin: 0 0 6px;
110
+ }
111
+
112
+ .ds-page-subtitle {
113
+ font-size: 15px;
114
+ color: var(--text-secondary);
115
+ margin: 0 0 40px;
116
+ line-height: 1.5;
117
+ }
118
+
119
+ .ds-section {
120
+ margin-bottom: 56px;
121
+ }
122
+
123
+ .ds-section-title {
124
+ font-size: 17px;
125
+ font-weight: 600;
126
+ color: var(--text-primary);
127
+ margin: 0 0 4px;
128
+ }
129
+
130
+ .ds-section-desc {
131
+ font-size: 13px;
132
+ color: var(--text-secondary);
133
+ margin: 0 0 20px;
134
+ line-height: 1.5;
135
+ }
136
+
137
+ .ds-divider {
138
+ border: none;
139
+ border-top: 1px solid var(--border);
140
+ margin: 48px 0;
141
+ }
142
+
143
+ /* ── Canvas: live component previews ─────────────────────────── */
144
+ .ds-canvas {
145
+ background: var(--bg-elevated);
146
+ border: 1px solid var(--border);
147
+ border-radius: var(--radius-lg);
148
+ padding: 32px;
149
+ margin-bottom: 12px;
150
+ }
151
+
152
+ .ds-canvas--flush { padding: 0; overflow: hidden; }
153
+ .ds-canvas--dark { background: var(--bg-base) }
154
+ .ds-canvas--grid {
155
+ display: flex;
156
+ flex-wrap: wrap;
157
+ gap: 12px;
158
+ align-items: flex-start;
159
+ }
160
+
161
+ /* ── Code block ──────────────────────────────────────────────── */
162
+ .ds-code {
163
+ background: var(--code-background);
164
+ border-radius: var(--radius-md);
165
+ padding: 14px 16px;
166
+ font-family: var(--font-mono);
167
+ font-size: 12px;
168
+ line-height: 1.6;
169
+ color: var(--text-secondary);
170
+ overflow-x: auto;
171
+ margin-bottom: 24px;
172
+ white-space: pre;
173
+ }
174
+
175
+ /* ── Annotation: refactoring notes ──────────────────────────── */
176
+ .ds-annotation {
177
+ border-left: 3px solid var(--color-warning);
178
+ background: color-mix(in srgb, var(--color-warning) 8%, transparent);
179
+ border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
180
+ padding: 10px 14px;
181
+ font-size: 13px;
182
+ color: var(--text-secondary);
183
+ line-height: 1.5;
184
+ margin-bottom: 24px;
185
+ }
186
+
187
+ .ds-annotation strong { color: var(--color-warning); font-weight: 600 }
188
+
189
+ /* ── Token grid ──────────────────────────────────────────────── */
190
+ .token-grid {
191
+ display: grid;
192
+ grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
193
+ gap: 12px;
194
+ margin-bottom: 24px;
195
+ }
196
+
197
+ .token-swatch {
198
+ border-radius: var(--radius-md);
199
+ overflow: hidden;
200
+ border: 1px solid var(--border);
201
+ }
202
+
203
+ .token-swatch-preview {
204
+ height: 56px;
205
+ }
206
+
207
+ .token-swatch-label {
208
+ padding: 8px 10px;
209
+ background: var(--bg-elevated);
210
+ }
211
+
212
+ .token-swatch-name {
213
+ font-family: var(--font-mono);
214
+ font-size: 11px;
215
+ color: var(--text-primary);
216
+ display: block;
217
+ margin-bottom: 2px;
218
+ }
219
+
220
+ .token-swatch-value {
221
+ font-size: 11px;
222
+ color: var(--text-muted);
223
+ }
224
+
225
+ .token-row {
226
+ display: flex;
227
+ align-items: center;
228
+ gap: 12px;
229
+ padding: 10px 0;
230
+ border-bottom: 1px solid var(--border);
231
+ font-size: 13px;
232
+ }
233
+
234
+ .token-row:last-child { border-bottom: none }
235
+
236
+ .token-row-preview {
237
+ width: 36px;
238
+ height: 36px;
239
+ border-radius: var(--radius-sm);
240
+ flex-shrink: 0;
241
+ }
242
+
243
+ .token-row-name {
244
+ font-family: var(--font-mono);
245
+ font-size: 12px;
246
+ color: var(--text-primary);
247
+ flex: 1;
248
+ }
249
+
250
+ .token-row-value {
251
+ font-size: 12px;
252
+ color: var(--text-muted);
253
+ }
254
+
255
+ /* ── Inline label ─────────────────────────────────────────────── */
256
+ .ds-label {
257
+ font-size: 11px;
258
+ font-weight: 500;
259
+ text-transform: uppercase;
260
+ letter-spacing: 0.06em;
261
+ color: var(--text-muted);
262
+ display: block;
263
+ margin-bottom: 8px;
264
+ }
265
+
266
+ /* ── Principle cards ─────────────────────────────────────────── */
267
+ .principle-card {
268
+ border: 1px solid var(--border);
269
+ border-radius: var(--radius-lg);
270
+ padding: 20px 24px;
271
+ margin-bottom: 12px;
272
+ }
273
+
274
+ .principle-num {
275
+ font-size: 11px;
276
+ font-weight: 700;
277
+ color: var(--accent);
278
+ text-transform: uppercase;
279
+ letter-spacing: 0.08em;
280
+ margin-bottom: 4px;
281
+ }
282
+
283
+ .principle-title {
284
+ font-size: 15px;
285
+ font-weight: 600;
286
+ color: var(--text-primary);
287
+ margin: 0 0 8px;
288
+ }
289
+
290
+ .principle-body {
291
+ font-size: 14px;
292
+ color: var(--text-secondary);
293
+ line-height: 1.6;
294
+ margin: 0;
295
+ }
296
+
297
+ .principle-body + .principle-body {
298
+ margin-top: 8px;
299
+ }
300
+
301
+ .principle-tension {
302
+ margin-top: 12px;
303
+ padding: 10px 12px;
304
+ background: color-mix(in srgb, var(--accent) 8%, transparent);
305
+ border-radius: var(--radius-sm);
306
+ font-size: 13px;
307
+ color: var(--text-secondary);
308
+ line-height: 1.5;
309
+ }
310
+
311
+ .principle-tension strong { color: var(--accent) }
312
+ </style>
313
+ </head>
314
+ <body>
315
+ <div class="ds-shell">
316
+ <nav class="ds-nav">
317
+ <div class="ds-nav-brand">
318
+ <a href="{{base}}/">← devchitchat</a><br>
319
+ Design System
320
+ </div>
321
+
322
+ <span class="ds-nav-section">Foundation</span>
323
+ <a href="{{base}}/design" class="ds-nav-link {{#if activeOverview}}active{{/if}}">Overview</a>
324
+ <a href="{{base}}/design/principles" class="ds-nav-link {{#if activePrinciples}}active{{/if}}">Principles</a>
325
+ <a href="{{base}}/design/tokens" class="ds-nav-link {{#if activeTokens}}active{{/if}}">Tokens</a>
326
+
327
+ <span class="ds-nav-section">Components</span>
328
+ <a href="{{base}}/design/components" class="ds-nav-link {{#if activeComponents}}active{{/if}}">All Components</a>
329
+
330
+ <div class="ds-nav-footer">
331
+ <label for="theme-picker" class="sr-only">Theme</label>
332
+ <select id="theme-picker" aria-label="Choose theme" autocomplete="off">
333
+ <option value="dark">Dark</option>
334
+ <option value="light">Light</option>
335
+ <option value="ocean">Ocean</option>
336
+ <option value="forest">Forest</option>
337
+ <option value="rose">Rose</option>
338
+ </select>
339
+ </div>
340
+ </nav>
341
+
342
+ <main class="ds-content">
343
+ {{content}}
344
+ </main>
345
+ </div>
346
+
347
+ <script type="module" src="{{base}}/client/theme.js"></script>
348
+ </body>
349
+ </html>
@@ -0,0 +1,13 @@
1
+ export async function data(req) {
2
+ const base = req.basePath ?? ''
3
+ const url = new URL(req.url)
4
+ const pathname = url.pathname.replace(base, '').replace(/\/$/, '') || '/'
5
+
6
+ return {
7
+ base,
8
+ activeOverview: pathname === '/design',
9
+ activePrinciples: pathname === '/design/principles',
10
+ activeTokens: pathname === '/design/tokens',
11
+ activeComponents: pathname === '/design/components',
12
+ }
13
+ }
@@ -0,0 +1,3 @@
1
+ export function GET() {
2
+ return { activeComponents: true }
3
+ }