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