astryx-dracula 0.2.0 → 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/BRAND.md +30 -18
- package/README.md +22 -11
- package/USAGE.md +29 -10
- package/astryx-dracula.js +19 -13
- package/astryx-dracula.variants.d.ts +15 -0
- package/package.json +59 -17
- package/shared/auth-chrome-config.ts +18 -0
- package/shared/auth-chrome.tsx +25 -0
- package/shared/auth-copy.ts +22 -0
- package/shared/chaptered-doc-config.ts +92 -0
- package/shared/chaptered-doc.tsx +332 -0
- package/shared/chart-hues.ts +27 -0
- package/shared/chart-labels.tsx +44 -0
- package/shared/chart-legend.tsx +100 -0
- package/shared/chart-panel-style.ts +13 -0
- package/shared/data-bar.tsx +160 -0
- package/shared/gallery-image.ts +20 -0
- package/shared/login-demo.ts +7 -0
- package/shared/metric-delta.tsx +36 -0
- package/shared/order-desk.tsx +273 -0
- package/shared/revenue-chart.tsx +174 -0
- package/shared/scene-castle.tsx +322 -0
- package/shared/scene-frame.tsx +88 -0
- package/shared/scene-hues.ts +49 -0
- package/shared/scene-tile.tsx +128 -0
- package/shared/settings-data.ts +125 -0
- package/shared/settings-rows.tsx +179 -0
- package/shared/sparkline.tsx +94 -0
- package/shared/sso-icons.tsx +30 -0
- package/templates/ai-chat-landing.tsx +67 -32
- package/templates/ai-chat.tsx +41 -20
- package/templates/blank.tsx +5 -2
- package/templates/centered-hero.tsx +15 -124
- package/templates/classic-gallery.tsx +21 -65
- package/templates/contact-form.tsx +62 -40
- package/templates/dashboard-portfolio.tsx +146 -227
- package/templates/dashboard.tsx +123 -121
- package/templates/detail-page.tsx +101 -95
- package/templates/documentation-design.template.mjs +1 -1
- package/templates/documentation-design.tsx +85 -96
- package/templates/documentation-technical.template.mjs +1 -1
- package/templates/documentation-technical.tsx +33 -21
- package/templates/documentation.template.mjs +1 -1
- package/templates/documentation.tsx +54 -74
- package/templates/editor.tsx +119 -89
- package/templates/file-explorer.tsx +133 -84
- package/templates/form-two-column.tsx +62 -124
- package/templates/gallery-hero.tsx +17 -171
- package/templates/ide.tsx +27 -21
- package/templates/incident-console.tsx +105 -69
- package/templates/kanban-board.tsx +100 -41
- package/templates/library.template.mjs +2 -2
- package/templates/library.tsx +38 -41
- package/templates/login-card.tsx +59 -86
- package/templates/login-split.tsx +88 -128
- package/templates/login-sso.tsx +107 -68
- package/templates/login.tsx +108 -52
- package/templates/messaging-shell.tsx +172 -143
- package/templates/mixed-gallery.tsx +31 -130
- package/templates/payment-form.tsx +369 -289
- package/templates/product-detail.tsx +40 -57
- package/templates/product-gallery.tsx +31 -40
- package/templates/product-tour.template.mjs +6 -0
- package/templates/product-tour.tsx +916 -0
- package/templates/settings-dialog.tsx +145 -286
- package/templates/settings-sidebar.tsx +179 -267
- package/templates/settings.tsx +42 -13
- package/templates/shell-nav.tsx +32 -23
- package/templates/shell-side-nav.tsx +30 -19
- package/templates/shell-top-nav.tsx +81 -43
- package/templates/side-gallery.tsx +39 -93
- package/templates/table-grouped.tsx +63 -33
- package/templates/table-page-chart.tsx +24 -297
- package/templates/table-page-heatmap-status.tsx +157 -91
- package/templates/table-page-shoe-store-heatmap.tsx +19 -288
- package/templates/table-page.tsx +24 -6
- package/templates/table.tsx +24 -7
- package/templates/tech-report.template.mjs +6 -0
- package/templates/tech-report.tsx +1486 -0
- package/templates/theme-showcase.template.mjs +1 -1
- package/templates/theme-showcase.tsx +313 -249
- package/theme.css +76 -14
- package/tokens.css +425 -30
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
// XLE (canonical structure, validated with `bunx astryx layout check`):
|
|
3
|
+
// L > (LP[w=68] > V > Av + (V > IB*4) + IB) + (LP[w=260] > V > (H > Hd"Messages"[level=1] + IB) + TI"Jump to…" + (V > Tx"Channels"[t=label] + (List > (ListItem)*4)) + (V > Tx"Direct messages"[t=label] + (List > (ListItem)*3))) + (LC[p=0] > V > (H > Hd"design-systems"[level=2] + SD + IB) + (ChL > ChML > (ChM > ChB)*6 + ChC)) + (LP[w=340] > V > (H > Tx"Thread"[weight=semibold] + IB) + (ChL > ChML > (ChM > ChB)*3 + ChC))
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
|
-
* Messaging Shell — Slack-style column frame for team messaging tools.
|
|
5
|
-
*
|
|
6
|
-
* Frame (desktop, left to right):
|
|
7
|
-
* workspace rail 68px | channel sidebar 260px | message stream (fill) | thread panel 340px
|
|
8
|
-
*
|
|
9
|
-
* Container policy: dense rows, zero Cards. Channels and DMs are List/ListItem
|
|
10
|
-
* rows, presence is AvatarStatusDot/StatusDot, unread counts are the only
|
|
11
|
-
* Badge usage. The stream and thread are built on the Chat component family.
|
|
12
|
-
*
|
|
13
|
-
* Responsive contract:
|
|
14
|
-
* >1024px — full four-column frame (rail | sidebar | stream | thread)
|
|
15
|
-
* <=1024px — thread panel hidden; stream takes the reclaimed width
|
|
16
|
-
* <=768px — sidebar also hidden; rail + stream keep full width
|
|
17
|
-
*
|
|
18
|
-
* Fixtures are deterministic: fixed ISO timestamps rendered via <Timestamp>,
|
|
19
|
-
* no Date.now()/Math.random() anywhere.
|
|
6
|
+
* Messaging Shell — Slack-style column frame for team messaging tools. Frame (desktop, left to right): (Frame/responsive/container: see XLE header above.)
|
|
20
7
|
*/
|
|
21
8
|
|
|
22
9
|
import {useState, type CSSProperties} from 'react';
|
|
@@ -86,9 +73,6 @@ const styles: Record<string, CSSProperties> = {
|
|
|
86
73
|
paddingTop: 'var(--spacing-3)',
|
|
87
74
|
paddingBottom: 'var(--spacing-3)',
|
|
88
75
|
},
|
|
89
|
-
railSpacer: {
|
|
90
|
-
flex: 1,
|
|
91
|
-
},
|
|
92
76
|
sidebar: {
|
|
93
77
|
height: '100%',
|
|
94
78
|
minHeight: 0,
|
|
@@ -102,15 +86,22 @@ const styles: Record<string, CSSProperties> = {
|
|
|
102
86
|
paddingInline: 'var(--spacing-3)',
|
|
103
87
|
paddingBottom: 'var(--spacing-2)',
|
|
104
88
|
},
|
|
89
|
+
// Block-start only: the inline (8px) and bottom (12px) edges already clear
|
|
90
|
+
// Two different jobs on one object, so the two different values are not
|
|
91
|
+
// redundant. INLINE is a content gutter: it must equal sidebarHeader and
|
|
92
|
+
// sidebarSearch above it (both var(--spacing-3) = 12px) because the channel
|
|
93
|
+
// list sits directly under the search field in the same 260px start panel --
|
|
94
|
+
// at 8px the body sat 4px inside the field above it. BLOCK-START is a ring
|
|
95
|
+
// budget, not a gutter: 4px = ring offset 2 + thickness 2, so the focus ring
|
|
96
|
+
// lands inside this clip instead of on its edge. The bottom edge stays 12px
|
|
97
|
+
// because the list scrolls into it, not into a ring.
|
|
105
98
|
sidebarScroll: {
|
|
106
99
|
minHeight: 0,
|
|
107
100
|
overflowY: 'auto',
|
|
108
|
-
paddingInline: 'var(--spacing-
|
|
101
|
+
paddingInline: 'var(--spacing-3)',
|
|
102
|
+
paddingBlockStart: 'var(--spacing-1)',
|
|
109
103
|
paddingBottom: 'var(--spacing-3)',
|
|
110
104
|
},
|
|
111
|
-
sectionGap: {
|
|
112
|
-
marginTop: 'var(--spacing-4)',
|
|
113
|
-
},
|
|
114
105
|
streamColumn: {
|
|
115
106
|
height: '100%',
|
|
116
107
|
minHeight: 0,
|
|
@@ -139,7 +130,7 @@ const styles: Record<string, CSSProperties> = {
|
|
|
139
130
|
threadHeader: {
|
|
140
131
|
alignItems: 'center',
|
|
141
132
|
paddingInline: 'var(--spacing-3)',
|
|
142
|
-
paddingBlock: 'var(--spacing-
|
|
133
|
+
paddingBlock: 'var(--spacing-3)',
|
|
143
134
|
},
|
|
144
135
|
threadScroll: {
|
|
145
136
|
minHeight: 0,
|
|
@@ -211,7 +202,7 @@ const DIRECT_MESSAGES: DirectMessage[] = [
|
|
|
211
202
|
{id: 'dm-sasha', userId: 'sasha', presence: 'offline', unread: 0},
|
|
212
203
|
];
|
|
213
204
|
|
|
214
|
-
// AvatarStatusDot supports success | neutral | error (no warning).
|
|
205
|
+
// AvatarStatusDot supports success | neutral | error (no warning): busy stays error (do-not-disturb), never warning.
|
|
215
206
|
const PRESENCE_VARIANT: Record<Presence, 'success' | 'error' | 'neutral'> = {
|
|
216
207
|
online: 'success',
|
|
217
208
|
busy: 'error',
|
|
@@ -224,12 +215,18 @@ const PRESENCE_LABEL: Record<Presence, string> = {
|
|
|
224
215
|
offline: 'Offline',
|
|
225
216
|
};
|
|
226
217
|
|
|
218
|
+
/** One bubble's copy. Ids key the bubble; its position only sets the grouping. */
|
|
219
|
+
interface StreamBubble {
|
|
220
|
+
id: string;
|
|
221
|
+
text: string;
|
|
222
|
+
}
|
|
223
|
+
|
|
227
224
|
/** One message group: consecutive bubbles from the same sender. */
|
|
228
225
|
interface StreamMessage {
|
|
229
226
|
id: string;
|
|
230
227
|
userId: string;
|
|
231
228
|
time: string;
|
|
232
|
-
bubbles:
|
|
229
|
+
bubbles: StreamBubble[];
|
|
233
230
|
}
|
|
234
231
|
|
|
235
232
|
const MESSAGES_BY_CHANNEL: Record<string, StreamMessage[]> = {
|
|
@@ -239,23 +236,40 @@ const MESSAGES_BY_CHANNEL: Record<string, StreamMessage[]> = {
|
|
|
239
236
|
userId: 'mira',
|
|
240
237
|
time: '2026-06-30T09:12:00',
|
|
241
238
|
bubbles: [
|
|
242
|
-
|
|
243
|
-
|
|
239
|
+
{
|
|
240
|
+
id: 'm1-1',
|
|
241
|
+
text: 'Morning! The Timestamp component now supports a `system_date` format, worth switching the audit log over.',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: 'm1-2',
|
|
245
|
+
text: 'I put the migration notes in the wiki under Decisions.',
|
|
246
|
+
},
|
|
244
247
|
],
|
|
245
248
|
},
|
|
246
249
|
{
|
|
247
250
|
id: 'm2',
|
|
248
251
|
userId: 'devon',
|
|
249
252
|
time: '2026-06-30T09:15:00',
|
|
250
|
-
bubbles: [
|
|
253
|
+
bubbles: [
|
|
254
|
+
{
|
|
255
|
+
id: 'm2-1',
|
|
256
|
+
text: 'Nice. Does that unblock the incident console timeline work?',
|
|
257
|
+
},
|
|
258
|
+
],
|
|
251
259
|
},
|
|
252
260
|
{
|
|
253
261
|
id: 'm3',
|
|
254
262
|
userId: 'you',
|
|
255
263
|
time: '2026-06-30T09:17:00',
|
|
256
264
|
bubbles: [
|
|
257
|
-
|
|
258
|
-
|
|
265
|
+
{
|
|
266
|
+
id: 'm3-1',
|
|
267
|
+
text: 'It does. I will pick that up after the template review.',
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
id: 'm3-2',
|
|
271
|
+
text: 'One question on the List density defaults, will start a thread.',
|
|
272
|
+
},
|
|
259
273
|
],
|
|
260
274
|
},
|
|
261
275
|
{
|
|
@@ -263,14 +277,17 @@ const MESSAGES_BY_CHANNEL: Record<string, StreamMessage[]> = {
|
|
|
263
277
|
userId: 'sasha',
|
|
264
278
|
time: '2026-06-30T09:24:00',
|
|
265
279
|
bubbles: [
|
|
266
|
-
|
|
280
|
+
{
|
|
281
|
+
id: 'm4-1',
|
|
282
|
+
text: 'Heads up: the token sync job ran clean overnight, no drift between core and the theme packages.',
|
|
283
|
+
},
|
|
267
284
|
],
|
|
268
285
|
},
|
|
269
286
|
{
|
|
270
287
|
id: 'm5',
|
|
271
288
|
userId: 'mira',
|
|
272
289
|
time: '2026-06-30T09:26:00',
|
|
273
|
-
bubbles: ['Great
|
|
290
|
+
bubbles: [{id: 'm5-1', text: 'Great, closing out the drift task then.'}],
|
|
274
291
|
},
|
|
275
292
|
],
|
|
276
293
|
'frontend-guild': [
|
|
@@ -279,14 +296,17 @@ const MESSAGES_BY_CHANNEL: Record<string, StreamMessage[]> = {
|
|
|
279
296
|
userId: 'devon',
|
|
280
297
|
time: '2026-06-30T08:40:00',
|
|
281
298
|
bubbles: [
|
|
282
|
-
|
|
299
|
+
{
|
|
300
|
+
id: 'g1-1',
|
|
301
|
+
text: 'Guild sync moved to Thursday this week to avoid the release freeze.',
|
|
302
|
+
},
|
|
283
303
|
],
|
|
284
304
|
},
|
|
285
305
|
{
|
|
286
306
|
id: 'g2',
|
|
287
307
|
userId: 'you',
|
|
288
308
|
time: '2026-06-30T08:44:00',
|
|
289
|
-
bubbles: ['Works for me
|
|
309
|
+
bubbles: [{id: 'g2-1', text: 'Works for me, agenda doc is updated.'}],
|
|
290
310
|
},
|
|
291
311
|
],
|
|
292
312
|
};
|
|
@@ -302,7 +322,7 @@ const THREAD_ROOT: ThreadReply = {
|
|
|
302
322
|
id: 't0',
|
|
303
323
|
userId: 'you',
|
|
304
324
|
time: '2026-06-30T09:17:30',
|
|
305
|
-
text: 'One question on the List density defaults
|
|
325
|
+
text: 'One question on the List density defaults: should channel sidebars use compact or balanced? The spec shows both.',
|
|
306
326
|
};
|
|
307
327
|
|
|
308
328
|
const THREAD_REPLIES: ThreadReply[] = [
|
|
@@ -316,7 +336,7 @@ const THREAD_REPLIES: ThreadReply[] = [
|
|
|
316
336
|
id: 't2',
|
|
317
337
|
userId: 'devon',
|
|
318
338
|
time: '2026-06-30T09:21:00',
|
|
319
|
-
text: 'Agreed
|
|
339
|
+
text: 'Agreed, the sidebar rows here are a good reference implementation.',
|
|
320
340
|
},
|
|
321
341
|
];
|
|
322
342
|
|
|
@@ -341,9 +361,9 @@ function StreamMessageGroup({message}: {message: StreamMessage}) {
|
|
|
341
361
|
<ChatMessage
|
|
342
362
|
sender={isSelf ? 'user' : 'assistant'}
|
|
343
363
|
avatar={isSelf ? undefined : <Avatar name={user.name} size="md" />}>
|
|
344
|
-
{message.bubbles.map((
|
|
364
|
+
{message.bubbles.map((bubble, index) => (
|
|
345
365
|
<ChatMessageBubble
|
|
346
|
-
key={
|
|
366
|
+
key={bubble.id}
|
|
347
367
|
group={
|
|
348
368
|
message.bubbles.length === 1
|
|
349
369
|
? undefined
|
|
@@ -361,7 +381,7 @@ function StreamMessageGroup({message}: {message: StreamMessage}) {
|
|
|
361
381
|
/>
|
|
362
382
|
) : undefined
|
|
363
383
|
}>
|
|
364
|
-
{text}
|
|
384
|
+
{bubble.text}
|
|
365
385
|
</ChatMessageBubble>
|
|
366
386
|
))}
|
|
367
387
|
</ChatMessage>
|
|
@@ -398,7 +418,7 @@ export default function MessagingShell() {
|
|
|
398
418
|
|
|
399
419
|
const workspaceRail = (
|
|
400
420
|
<VStack gap={2} style={styles.rail}>
|
|
401
|
-
<Avatar name="Night
|
|
421
|
+
<Avatar name="Night watch" size="md" />
|
|
402
422
|
{RAIL_ITEMS.map(item => (
|
|
403
423
|
<IconButton
|
|
404
424
|
key={item.id}
|
|
@@ -409,7 +429,7 @@ export default function MessagingShell() {
|
|
|
409
429
|
onClick={() => {}}
|
|
410
430
|
/>
|
|
411
431
|
))}
|
|
412
|
-
<
|
|
432
|
+
<StackItem size="fill" />
|
|
413
433
|
<IconButton
|
|
414
434
|
label="Settings"
|
|
415
435
|
tooltip="Settings"
|
|
@@ -429,7 +449,7 @@ export default function MessagingShell() {
|
|
|
429
449
|
<Stack direction="vertical" style={styles.sidebar}>
|
|
430
450
|
<HStack gap={2} style={styles.sidebarHeader}>
|
|
431
451
|
<StackItem size="fill">
|
|
432
|
-
<Heading level={
|
|
452
|
+
<Heading level={1}>Messages</Heading>
|
|
433
453
|
</StackItem>
|
|
434
454
|
<IconButton
|
|
435
455
|
label="New message"
|
|
@@ -440,18 +460,23 @@ export default function MessagingShell() {
|
|
|
440
460
|
onClick={() => {}}
|
|
441
461
|
/>
|
|
442
462
|
</HStack>
|
|
443
|
-
<
|
|
463
|
+
<VStack gap={0} style={styles.sidebarSearch}>
|
|
444
464
|
<TextInput
|
|
445
465
|
label="Jump to"
|
|
446
466
|
isLabelHidden
|
|
447
467
|
size="sm"
|
|
448
|
-
placeholder="Jump to
|
|
468
|
+
placeholder="Jump to…"
|
|
449
469
|
startIcon={Search}
|
|
450
470
|
value={searchQuery}
|
|
451
471
|
onChange={setSearchQuery}
|
|
452
472
|
/>
|
|
453
|
-
</
|
|
454
|
-
<StackItem
|
|
473
|
+
</VStack>
|
|
474
|
+
<StackItem
|
|
475
|
+
size="fill"
|
|
476
|
+
style={styles.sidebarScroll}
|
|
477
|
+
role="region"
|
|
478
|
+
aria-label="Channels and direct messages"
|
|
479
|
+
tabIndex={0}>
|
|
455
480
|
<List
|
|
456
481
|
density="compact"
|
|
457
482
|
hasDividers={false}
|
|
@@ -480,42 +505,43 @@ export default function MessagingShell() {
|
|
|
480
505
|
/>
|
|
481
506
|
))}
|
|
482
507
|
</List>
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
508
|
+
{/* The section gap rides on this List's own margin: List is the row
|
|
509
|
+
container, so no wrapper element is needed. */}
|
|
510
|
+
<List
|
|
511
|
+
density="compact"
|
|
512
|
+
hasDividers={false}
|
|
513
|
+
style={styles.sectionGap}
|
|
514
|
+
header={
|
|
515
|
+
<Text type="label" size="sm" color="secondary">
|
|
516
|
+
Direct messages
|
|
517
|
+
</Text>
|
|
518
|
+
}>
|
|
519
|
+
{visibleDms.map(dm => (
|
|
520
|
+
<ListItem
|
|
521
|
+
key={dm.id}
|
|
522
|
+
label={USERS[dm.userId].name}
|
|
523
|
+
isSelected={selectedDmId === dm.id}
|
|
524
|
+
onClick={() => setSelectedDmId(dm.id)}
|
|
525
|
+
startContent={
|
|
526
|
+
<Avatar
|
|
527
|
+
name={USERS[dm.userId].name}
|
|
528
|
+
size="sm"
|
|
529
|
+
status={
|
|
530
|
+
<AvatarStatusDot
|
|
531
|
+
variant={PRESENCE_VARIANT[dm.presence]}
|
|
532
|
+
label={PRESENCE_LABEL[dm.presence]}
|
|
533
|
+
/>
|
|
534
|
+
}
|
|
535
|
+
/>
|
|
536
|
+
}
|
|
537
|
+
endContent={
|
|
538
|
+
dm.unread > 0 ? (
|
|
539
|
+
<Badge label={String(dm.unread)} variant="neutral" />
|
|
540
|
+
) : undefined
|
|
541
|
+
}
|
|
542
|
+
/>
|
|
543
|
+
))}
|
|
544
|
+
</List>
|
|
519
545
|
</StackItem>
|
|
520
546
|
</Stack>
|
|
521
547
|
);
|
|
@@ -524,9 +550,9 @@ export default function MessagingShell() {
|
|
|
524
550
|
<Stack direction="vertical" style={styles.streamColumn}>
|
|
525
551
|
<HStack gap={3} style={styles.streamHeader}>
|
|
526
552
|
<Icon icon={Hash} size="sm" color="secondary" />
|
|
527
|
-
<Heading level={
|
|
553
|
+
<Heading level={2}>{selectedChannel.name}</Heading>
|
|
528
554
|
<StackItem size="fill" style={styles.streamTopic}>
|
|
529
|
-
<Text type="
|
|
555
|
+
<Text type="body" color="secondary" maxLines={1}>
|
|
530
556
|
{selectedChannel.topic}
|
|
531
557
|
</Text>
|
|
532
558
|
</StackItem>
|
|
@@ -542,36 +568,35 @@ export default function MessagingShell() {
|
|
|
542
568
|
</HStack>
|
|
543
569
|
<Divider />
|
|
544
570
|
<StackItem size="fill" style={styles.chatArea}>
|
|
545
|
-
<
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
</div>
|
|
571
|
+
<ChatLayout
|
|
572
|
+
style={styles.chatFill}
|
|
573
|
+
composer={
|
|
574
|
+
<ChatComposer
|
|
575
|
+
placeholder={`Message #${selectedChannel.name}`}
|
|
576
|
+
onSubmit={() => {}}
|
|
577
|
+
/>
|
|
578
|
+
}
|
|
579
|
+
emptyState={
|
|
580
|
+
<EmptyState
|
|
581
|
+
icon={<Icon icon={Inbox} size="lg" color="secondary" />}
|
|
582
|
+
title="No messages yet"
|
|
583
|
+
description="Start the conversation. Messages posted here are visible to the whole channel."
|
|
584
|
+
/>
|
|
585
|
+
}>
|
|
586
|
+
{messages.length > 0 ? (
|
|
587
|
+
<ChatMessageList density="balanced">
|
|
588
|
+
<ChatSystemMessage variant="divider">
|
|
589
|
+
Tuesday, June 30
|
|
590
|
+
</ChatSystemMessage>
|
|
591
|
+
<ChatSystemMessage>
|
|
592
|
+
Sasha Ortiz joined #{selectedChannel.name}
|
|
593
|
+
</ChatSystemMessage>
|
|
594
|
+
{messages.map(message => (
|
|
595
|
+
<StreamMessageGroup key={message.id} message={message} />
|
|
596
|
+
))}
|
|
597
|
+
</ChatMessageList>
|
|
598
|
+
) : null}
|
|
599
|
+
</ChatLayout>
|
|
575
600
|
</StackItem>
|
|
576
601
|
</Stack>
|
|
577
602
|
);
|
|
@@ -597,7 +622,12 @@ export default function MessagingShell() {
|
|
|
597
622
|
/>
|
|
598
623
|
</HStack>
|
|
599
624
|
<Divider />
|
|
600
|
-
<StackItem
|
|
625
|
+
<StackItem
|
|
626
|
+
size="fill"
|
|
627
|
+
style={styles.threadScroll}
|
|
628
|
+
role="region"
|
|
629
|
+
aria-label="Thread messages"
|
|
630
|
+
tabIndex={0}>
|
|
601
631
|
<ChatMessageList density="compact">
|
|
602
632
|
<ChatMessage
|
|
603
633
|
sender="assistant"
|
|
@@ -635,41 +665,40 @@ export default function MessagingShell() {
|
|
|
635
665
|
))}
|
|
636
666
|
</ChatMessageList>
|
|
637
667
|
</StackItem>
|
|
638
|
-
<
|
|
668
|
+
<VStack gap={0} style={styles.threadComposer}>
|
|
639
669
|
<ChatComposer
|
|
640
670
|
density="compact"
|
|
641
|
-
placeholder="Reply in thread
|
|
671
|
+
placeholder="Reply in thread…"
|
|
642
672
|
onSubmit={() => {}}
|
|
643
673
|
/>
|
|
644
|
-
</
|
|
674
|
+
</VStack>
|
|
645
675
|
</Stack>
|
|
646
676
|
);
|
|
647
677
|
|
|
648
678
|
return (
|
|
649
|
-
<
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
679
|
+
<Layout
|
|
680
|
+
height="fill"
|
|
681
|
+
style={styles.root}
|
|
682
|
+
start={
|
|
683
|
+
<>
|
|
684
|
+
<LayoutPanel width={68} padding={0}>
|
|
685
|
+
{workspaceRail}
|
|
686
|
+
</LayoutPanel>
|
|
687
|
+
{!isSidebarHidden && (
|
|
688
|
+
<LayoutPanel width={260} padding={0}>
|
|
689
|
+
{channelSidebar}
|
|
656
690
|
</LayoutPanel>
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
) : undefined
|
|
670
|
-
}
|
|
671
|
-
content={<LayoutContent padding={0}>{messageStream}</LayoutContent>}
|
|
672
|
-
/>
|
|
673
|
-
</div>
|
|
691
|
+
)}
|
|
692
|
+
</>
|
|
693
|
+
}
|
|
694
|
+
end={
|
|
695
|
+
showThreadPanel ? (
|
|
696
|
+
<LayoutPanel width={340} padding={0}>
|
|
697
|
+
{threadPanel}
|
|
698
|
+
</LayoutPanel>
|
|
699
|
+
) : undefined
|
|
700
|
+
}
|
|
701
|
+
content={<LayoutContent padding={0}>{messageStream}</LayoutContent>}
|
|
702
|
+
/>
|
|
674
703
|
);
|
|
675
704
|
}
|