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.
- package/BRAND.md +30 -18
- package/README.md +17 -12
- 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 +66 -33
- package/templates/ai-chat.tsx +36 -19
- package/templates/blank.tsx +4 -3
- package/templates/centered-hero.tsx +14 -125
- package/templates/classic-gallery.tsx +20 -66
- package/templates/contact-form.tsx +59 -39
- package/templates/dashboard-portfolio.tsx +143 -226
- package/templates/dashboard.tsx +122 -122
- package/templates/detail-page.tsx +95 -91
- package/templates/documentation-design.template.mjs +1 -1
- package/templates/documentation-design.tsx +83 -96
- package/templates/documentation-technical.template.mjs +1 -1
- package/templates/documentation-technical.tsx +29 -19
- package/templates/documentation.template.mjs +1 -1
- package/templates/documentation.tsx +52 -74
- package/templates/editor.tsx +112 -84
- package/templates/file-explorer.tsx +131 -84
- package/templates/form-two-column.tsx +61 -125
- package/templates/gallery-hero.tsx +15 -171
- package/templates/ide.tsx +22 -20
- package/templates/incident-console.tsx +104 -70
- package/templates/kanban-board.tsx +99 -42
- package/templates/library.template.mjs +2 -2
- package/templates/library.tsx +37 -42
- package/templates/login-card.tsx +58 -87
- package/templates/login-split.tsx +88 -126
- package/templates/login-sso.tsx +105 -64
- package/templates/login.tsx +107 -53
- package/templates/messaging-shell.tsx +171 -144
- package/templates/mixed-gallery.tsx +29 -130
- package/templates/payment-form.tsx +368 -290
- package/templates/product-detail.tsx +39 -58
- package/templates/product-gallery.tsx +30 -41
- package/templates/product-tour.template.mjs +6 -0
- package/templates/product-tour.tsx +916 -0
- package/templates/settings-dialog.tsx +135 -282
- package/templates/settings-sidebar.tsx +178 -268
- package/templates/settings.tsx +41 -14
- package/templates/shell-nav.tsx +31 -24
- package/templates/shell-side-nav.tsx +29 -20
- package/templates/shell-top-nav.tsx +80 -44
- package/templates/side-gallery.tsx +38 -94
- package/templates/table-grouped.tsx +62 -34
- package/templates/table-page-chart.tsx +23 -302
- package/templates/table-page-heatmap-status.tsx +156 -92
- package/templates/table-page-shoe-store-heatmap.tsx +18 -293
- package/templates/table-page.tsx +23 -7
- package/templates/table.tsx +23 -8
- 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 +299 -237
- package/theme.css +76 -14
- package/tokens.css +425 -30
package/templates/editor.tsx
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
// XLE (canonical structure, validated with `bunx astryx layout check`):
|
|
3
|
-
// L > (LP[w=320] > V[g=4] > (S[p=4] > V[g=4] > Hd"Page Editor"[level=
|
|
3
|
+
// L > (LP[w=320] > V[g=4] > (S[p=4] > V[g=4] > Hd"Page Editor"[level=1] + Tbar) + (V[g=4] > (TL > Tab"Blocks"! + Tab"Properties") + D + (S[p=4] > V[g=2] > Hd"Add Block"[level=3] + UL + Hd"Layers"[level=3] + UL))) + (LC > V[g=4] > C*3)
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
useState,
|
|
7
|
+
useCallback,
|
|
8
|
+
type ComponentType,
|
|
9
|
+
type CSSProperties,
|
|
10
|
+
type KeyboardEvent,
|
|
11
|
+
type MouseEvent,
|
|
12
|
+
type SVGProps,
|
|
13
|
+
} from 'react';
|
|
6
14
|
import {useMediaQuery} from '@astryxdesign/core/hooks';
|
|
7
15
|
import {Button} from '@astryxdesign/core/Button';
|
|
8
|
-
import {
|
|
16
|
+
import {SelectableCard} from '@astryxdesign/core/SelectableCard';
|
|
9
17
|
import {Center} from '@astryxdesign/core/Center';
|
|
10
18
|
import {Dialog} from '@astryxdesign/core/Dialog';
|
|
11
19
|
import {Divider} from '@astryxdesign/core/Divider';
|
|
@@ -20,7 +28,7 @@ import {
|
|
|
20
28
|
} from '@astryxdesign/core/Layout';
|
|
21
29
|
import {Icon} from '@astryxdesign/core/Icon';
|
|
22
30
|
import {List, ListItem} from '@astryxdesign/core/List';
|
|
23
|
-
import {Table, proportional
|
|
31
|
+
import {Table, proportional} from '@astryxdesign/core/Table';
|
|
24
32
|
import type {TableColumn} from '@astryxdesign/core/Table';
|
|
25
33
|
import {Section} from '@astryxdesign/core/Section';
|
|
26
34
|
import {
|
|
@@ -56,10 +64,8 @@ import {
|
|
|
56
64
|
Banknote,
|
|
57
65
|
CarFront,
|
|
58
66
|
CirclePlay,
|
|
59
|
-
Ellipsis,
|
|
60
67
|
Lock,
|
|
61
68
|
} from 'lucide-react';
|
|
62
|
-
import {Spinner} from '@astryxdesign/core/Spinner';
|
|
63
69
|
|
|
64
70
|
type BlockType =
|
|
65
71
|
'hero' | 'text' | 'image' | 'button' | 'cards' | 'features' | 'cta';
|
|
@@ -73,7 +79,7 @@ interface Block {
|
|
|
73
79
|
|
|
74
80
|
type ViewportSize = 'desktop' | 'tablet' | 'phone';
|
|
75
81
|
type SidebarTab = 'blocks' | 'properties';
|
|
76
|
-
type IconComponent =
|
|
82
|
+
type IconComponent = ComponentType<SVGProps<SVGSVGElement>>;
|
|
77
83
|
|
|
78
84
|
const BLOCK_META: Record<BlockType, {label: string; icon: IconComponent}> = {
|
|
79
85
|
hero: {label: 'Hero', icon: LayoutGrid},
|
|
@@ -102,11 +108,14 @@ const CATEGORY_ICONS: Record<string, IconComponent> = {
|
|
|
102
108
|
Entertainment: CirclePlay,
|
|
103
109
|
};
|
|
104
110
|
|
|
111
|
+
// The minimums clear the 375px phone canvas once the preview card's 24px
|
|
112
|
+
// padding is taken out; the widest column carries the slack and every cell
|
|
113
|
+
// truncates rather than pushing the table past the card.
|
|
105
114
|
const TRANSACTION_COLUMNS: TableColumn<Transaction>[] = [
|
|
106
115
|
{
|
|
107
116
|
key: 'name',
|
|
108
117
|
header: 'Transaction',
|
|
109
|
-
width: proportional(2, {minWidth:
|
|
118
|
+
width: proportional(2, {minWidth: 104}),
|
|
110
119
|
renderCell: (item: Transaction) => (
|
|
111
120
|
<HStack gap={3} vAlign="center">
|
|
112
121
|
<Icon icon={CATEGORY_ICONS[item.category] || Sparkles} />
|
|
@@ -124,7 +133,7 @@ const TRANSACTION_COLUMNS: TableColumn<Transaction>[] = [
|
|
|
124
133
|
{
|
|
125
134
|
key: 'date',
|
|
126
135
|
header: 'Date',
|
|
127
|
-
width: proportional(1, {minWidth:
|
|
136
|
+
width: proportional(1, {minWidth: 64}),
|
|
128
137
|
renderCell: (item: Transaction) => (
|
|
129
138
|
<Text type="body" color="secondary" hasTabularNumbers>
|
|
130
139
|
{item.date}
|
|
@@ -134,27 +143,13 @@ const TRANSACTION_COLUMNS: TableColumn<Transaction>[] = [
|
|
|
134
143
|
{
|
|
135
144
|
key: 'amount',
|
|
136
145
|
header: 'Amount',
|
|
137
|
-
width: proportional(1, {minWidth:
|
|
146
|
+
width: proportional(1, {minWidth: 88}),
|
|
138
147
|
renderCell: (item: Transaction) => (
|
|
139
148
|
<Text type="body" weight="semibold" hasTabularNumbers>
|
|
140
149
|
{item.amount}
|
|
141
150
|
</Text>
|
|
142
151
|
),
|
|
143
152
|
},
|
|
144
|
-
{
|
|
145
|
-
key: 'actions',
|
|
146
|
-
header: '',
|
|
147
|
-
width: pixel(44),
|
|
148
|
-
renderCell: () => (
|
|
149
|
-
<Button
|
|
150
|
-
label="More"
|
|
151
|
-
icon={<Icon icon={Ellipsis} size="sm" />}
|
|
152
|
-
variant="ghost"
|
|
153
|
-
size="sm"
|
|
154
|
-
isIconOnly
|
|
155
|
-
/>
|
|
156
|
-
),
|
|
157
|
-
},
|
|
158
153
|
];
|
|
159
154
|
|
|
160
155
|
const VIEWPORT_MAX: Record<ViewportSize, number> = {
|
|
@@ -243,9 +238,9 @@ function defaultProps(type: BlockType): Record<string, unknown> {
|
|
|
243
238
|
switch (type) {
|
|
244
239
|
case 'hero':
|
|
245
240
|
return {
|
|
246
|
-
heading: '
|
|
247
|
-
subheading: '
|
|
248
|
-
buttonLabel: '
|
|
241
|
+
heading: 'Midnight at the Castle Gates',
|
|
242
|
+
subheading: 'Gather the coven — the night is young and the candles are lit.',
|
|
243
|
+
buttonLabel: 'Enter the night',
|
|
249
244
|
alignment: 'center',
|
|
250
245
|
};
|
|
251
246
|
case 'text':
|
|
@@ -283,10 +278,11 @@ function defaultProps(type: BlockType): Record<string, unknown> {
|
|
|
283
278
|
};
|
|
284
279
|
case 'cta':
|
|
285
280
|
return {
|
|
286
|
-
heading: '
|
|
287
|
-
description:
|
|
288
|
-
|
|
289
|
-
|
|
281
|
+
heading: 'Join the Midnight Coven',
|
|
282
|
+
description:
|
|
283
|
+
'Claim your seat at the table — letters from the crypt, once a moon.',
|
|
284
|
+
primaryLabel: 'Join the coven',
|
|
285
|
+
secondaryLabel: 'Read the lore',
|
|
290
286
|
};
|
|
291
287
|
}
|
|
292
288
|
}
|
|
@@ -310,19 +306,21 @@ const canvasStyle = (maxWidth: number): CSSProperties => ({
|
|
|
310
306
|
width: '100%',
|
|
311
307
|
marginInline: 'auto',
|
|
312
308
|
});
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
//
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
//
|
|
309
|
+
// `clickable` and `selectedCard` are gone: the eight block cards are core's
|
|
310
|
+
// `SelectableCard` now, which supplies the cursor, the hover overlay
|
|
311
|
+
// (`SelectableCard.tsx:90` reads `--color-overlay-hover`) and the selected ring
|
|
312
|
+
// from the same tokens this file was hand-rolling. Worth recording why the old
|
|
313
|
+
// pair was wrong twice over: it was reachable only as an inline `style` spread,
|
|
314
|
+
// and a spread of a lookup is not a measurement — those values were never
|
|
315
|
+
// checked against what `Card` actually renders. The 1.4.11 non-claim on the
|
|
316
|
+
// ring colour is unchanged and still stands: Comment #6272A4 cannot reach
|
|
317
|
+
// 3:1 on #343746 at any alpha, and core's own selected ring has that ceiling.
|
|
318
|
+
// The sidebar keeps its width when the canvas is wider than the window.
|
|
319
|
+
const panelShrink: CSSProperties = {flexShrink: 0};
|
|
320
|
+
// Square muted chip behind the CTA icon — Center handles the centering
|
|
323
321
|
// and sizing; only the surface (radius + fill) needs custom CSS.
|
|
324
322
|
const iconCircle: CSSProperties = {
|
|
325
|
-
borderRadius: '
|
|
323
|
+
borderRadius: 'var(--radius-element)',
|
|
326
324
|
backgroundColor: 'var(--color-selection)',
|
|
327
325
|
};
|
|
328
326
|
|
|
@@ -459,37 +457,41 @@ function BlockPreview({
|
|
|
459
457
|
onSelect: () => void;
|
|
460
458
|
}) {
|
|
461
459
|
const {type, props} = block;
|
|
462
|
-
const cardStyle: CSSProperties = {
|
|
463
|
-
...clickable,
|
|
464
|
-
...(isSelected ? selectedCard : null),
|
|
465
|
-
};
|
|
466
460
|
|
|
467
461
|
switch (type) {
|
|
468
462
|
case 'hero':
|
|
469
463
|
return (
|
|
470
|
-
<
|
|
464
|
+
<SelectableCard
|
|
465
|
+
padding={4}
|
|
466
|
+
label={block.label}
|
|
467
|
+
isSelected={isSelected}
|
|
468
|
+
onChange={onSelect}>
|
|
471
469
|
<VStack gap={4}>
|
|
472
|
-
<Heading level={
|
|
470
|
+
<Heading level={3}>
|
|
473
471
|
{(props.heading as string) || 'Hero Heading'}
|
|
474
472
|
</Heading>
|
|
475
473
|
<Text type="body" color="secondary">
|
|
476
|
-
{(props.subheading as string) || '
|
|
474
|
+
{(props.subheading as string) || 'A whisper from the crypt…'}
|
|
477
475
|
</Text>
|
|
478
476
|
{(props.buttonLabel as string) && (
|
|
479
477
|
<Button label={props.buttonLabel as string} />
|
|
480
478
|
)}
|
|
481
479
|
</VStack>
|
|
482
|
-
|
|
480
|
+
</SelectableCard>
|
|
483
481
|
);
|
|
484
482
|
|
|
485
483
|
case 'text':
|
|
486
484
|
if (props.heading) {
|
|
487
485
|
return (
|
|
488
|
-
<
|
|
486
|
+
<SelectableCard
|
|
487
|
+
padding={4}
|
|
488
|
+
label={block.label}
|
|
489
|
+
isSelected={isSelected}
|
|
490
|
+
onChange={onSelect}>
|
|
489
491
|
<EmptyState
|
|
490
492
|
title={props.heading as string}
|
|
491
493
|
description={props.description as string}
|
|
492
|
-
icon={<
|
|
494
|
+
icon={<Icon icon={FileText} color="secondary" />}
|
|
493
495
|
actions={
|
|
494
496
|
(props.buttonLabel as string) ? (
|
|
495
497
|
<Button
|
|
@@ -499,32 +501,44 @@ function BlockPreview({
|
|
|
499
501
|
) : undefined
|
|
500
502
|
}
|
|
501
503
|
/>
|
|
502
|
-
</
|
|
504
|
+
</SelectableCard>
|
|
503
505
|
);
|
|
504
506
|
}
|
|
505
507
|
return (
|
|
506
|
-
<
|
|
508
|
+
<SelectableCard
|
|
509
|
+
padding={4}
|
|
510
|
+
label={block.label}
|
|
511
|
+
isSelected={isSelected}
|
|
512
|
+
onChange={onSelect}>
|
|
507
513
|
<Text type="body">
|
|
508
|
-
{(props.content as string) || '
|
|
514
|
+
{(props.content as string) || 'Ink your midnight thoughts here…'}
|
|
509
515
|
</Text>
|
|
510
|
-
|
|
516
|
+
</SelectableCard>
|
|
511
517
|
);
|
|
512
518
|
|
|
513
519
|
case 'image':
|
|
514
520
|
return (
|
|
515
|
-
<
|
|
521
|
+
<SelectableCard
|
|
522
|
+
padding={4}
|
|
523
|
+
label={block.label}
|
|
524
|
+
isSelected={isSelected}
|
|
525
|
+
onChange={onSelect}>
|
|
516
526
|
<EmptyState
|
|
517
527
|
title="Image Block"
|
|
518
528
|
description="Drop an image or enter a URL"
|
|
519
|
-
icon={<Icon icon={Image} />}
|
|
529
|
+
icon={<Icon icon={Image} color="secondary" />}
|
|
520
530
|
isCompact
|
|
521
531
|
/>
|
|
522
|
-
|
|
532
|
+
</SelectableCard>
|
|
523
533
|
);
|
|
524
534
|
|
|
525
535
|
case 'button':
|
|
526
536
|
return (
|
|
527
|
-
<
|
|
537
|
+
<SelectableCard
|
|
538
|
+
padding={4}
|
|
539
|
+
label={block.label}
|
|
540
|
+
isSelected={isSelected}
|
|
541
|
+
onChange={onSelect}>
|
|
528
542
|
<Center>
|
|
529
543
|
<Button
|
|
530
544
|
label={(props.label as string) || 'Button'}
|
|
@@ -535,13 +549,17 @@ function BlockPreview({
|
|
|
535
549
|
size={(props.size as 'sm' | 'md' | 'lg') || 'md'}
|
|
536
550
|
/>
|
|
537
551
|
</Center>
|
|
538
|
-
|
|
552
|
+
</SelectableCard>
|
|
539
553
|
);
|
|
540
554
|
|
|
541
555
|
case 'features': {
|
|
542
556
|
const items = (props.items as Transaction[]) || [];
|
|
543
557
|
return (
|
|
544
|
-
<
|
|
558
|
+
<SelectableCard
|
|
559
|
+
padding={4}
|
|
560
|
+
label={block.label}
|
|
561
|
+
isSelected={isSelected}
|
|
562
|
+
onChange={onSelect}>
|
|
545
563
|
<VStack gap={4}>
|
|
546
564
|
<HStack gap={3} vAlign="start" hAlign="between">
|
|
547
565
|
<VStack gap={1}>
|
|
@@ -549,12 +567,12 @@ function BlockPreview({
|
|
|
549
567
|
{(props.heading as string) || 'Features'}
|
|
550
568
|
</Heading>
|
|
551
569
|
{(props.description as string) && (
|
|
552
|
-
<Text type="
|
|
570
|
+
<Text type="body" color="secondary">
|
|
553
571
|
{props.description as string}
|
|
554
572
|
</Text>
|
|
555
573
|
)}
|
|
556
574
|
</VStack>
|
|
557
|
-
<Button label="View All" variant="secondary"
|
|
575
|
+
<Button label="View All" variant="secondary" />
|
|
558
576
|
</HStack>
|
|
559
577
|
<Table
|
|
560
578
|
data={items}
|
|
@@ -564,7 +582,7 @@ function BlockPreview({
|
|
|
564
582
|
textOverflow="truncate"
|
|
565
583
|
/>
|
|
566
584
|
</VStack>
|
|
567
|
-
|
|
585
|
+
</SelectableCard>
|
|
568
586
|
);
|
|
569
587
|
}
|
|
570
588
|
|
|
@@ -572,41 +590,50 @@ function BlockPreview({
|
|
|
572
590
|
const cardItems =
|
|
573
591
|
(props.cards as Array<{title: string; description: string}>) || [];
|
|
574
592
|
return (
|
|
575
|
-
<
|
|
593
|
+
<SelectableCard
|
|
594
|
+
padding={4}
|
|
595
|
+
label={block.label}
|
|
596
|
+
isSelected={isSelected}
|
|
597
|
+
onChange={onSelect}>
|
|
576
598
|
<VStack gap={4}>
|
|
577
599
|
<Heading level={3}>Cards</Heading>
|
|
578
600
|
<Divider />
|
|
579
601
|
<List density="balanced" hasDividers={false}>
|
|
580
|
-
{cardItems.map((card
|
|
602
|
+
{cardItems.map((card) => (
|
|
581
603
|
<ListItem
|
|
582
|
-
key={
|
|
604
|
+
key={card.title}
|
|
583
605
|
label={card.title}
|
|
584
606
|
description={card.description}
|
|
585
607
|
/>
|
|
586
608
|
))}
|
|
587
609
|
</List>
|
|
588
610
|
</VStack>
|
|
589
|
-
|
|
611
|
+
</SelectableCard>
|
|
590
612
|
);
|
|
591
613
|
}
|
|
592
614
|
|
|
593
615
|
case 'cta':
|
|
594
616
|
return (
|
|
595
|
-
<
|
|
617
|
+
<SelectableCard
|
|
618
|
+
padding={4}
|
|
619
|
+
label={block.label}
|
|
620
|
+
isSelected={isSelected}
|
|
621
|
+
onChange={onSelect}>
|
|
596
622
|
<HStack gap={4} vAlign="start">
|
|
597
623
|
<Center width={40} height={40} style={iconCircle}>
|
|
598
624
|
<Icon icon={Lock} color="secondary" />
|
|
599
625
|
</Center>
|
|
600
626
|
<VStack gap={1}>
|
|
601
|
-
<Heading level={
|
|
627
|
+
<Heading level={3}>
|
|
602
628
|
{(props.heading as string) || 'Notice'}
|
|
603
629
|
</Heading>
|
|
604
630
|
<Text type="body" color="secondary">
|
|
605
|
-
{(props.description as string) ||
|
|
631
|
+
{(props.description as string) ||
|
|
632
|
+
'Words from the crypt gather here…'}
|
|
606
633
|
</Text>
|
|
607
634
|
</VStack>
|
|
608
635
|
</HStack>
|
|
609
|
-
|
|
636
|
+
</SelectableCard>
|
|
610
637
|
);
|
|
611
638
|
|
|
612
639
|
default:
|
|
@@ -703,7 +730,7 @@ export default function PageEditor() {
|
|
|
703
730
|
const blocksTabContent = (
|
|
704
731
|
<VStack gap={2}>
|
|
705
732
|
<VStack gap={1}>
|
|
706
|
-
<Heading level={
|
|
733
|
+
<Heading level={3}>Add Block</Heading>
|
|
707
734
|
<List density="balanced" hasDividers={false}>
|
|
708
735
|
{(Object.keys(BLOCK_META) as BlockType[]).map(type => (
|
|
709
736
|
<ListItem
|
|
@@ -719,7 +746,7 @@ export default function PageEditor() {
|
|
|
719
746
|
</VStack>
|
|
720
747
|
|
|
721
748
|
<VStack gap={1}>
|
|
722
|
-
<Heading level={
|
|
749
|
+
<Heading level={3}>Layers</Heading>
|
|
723
750
|
<List density="balanced" hasDividers={false}>
|
|
724
751
|
{blocks.map(block => (
|
|
725
752
|
<ListItem
|
|
@@ -737,7 +764,7 @@ export default function PageEditor() {
|
|
|
737
764
|
icon={<Icon icon={ChevronUp} size="sm" />}
|
|
738
765
|
variant="ghost"
|
|
739
766
|
size="sm"
|
|
740
|
-
onClick={(e:
|
|
767
|
+
onClick={(e: MouseEvent) => {
|
|
741
768
|
e.stopPropagation();
|
|
742
769
|
moveBlock(block.id, -1);
|
|
743
770
|
}}
|
|
@@ -748,7 +775,7 @@ export default function PageEditor() {
|
|
|
748
775
|
icon={<Icon icon={ChevronDown} size="sm" />}
|
|
749
776
|
variant="ghost"
|
|
750
777
|
size="sm"
|
|
751
|
-
onClick={(e:
|
|
778
|
+
onClick={(e: MouseEvent) => {
|
|
752
779
|
e.stopPropagation();
|
|
753
780
|
moveBlock(block.id, 1);
|
|
754
781
|
}}
|
|
@@ -759,7 +786,7 @@ export default function PageEditor() {
|
|
|
759
786
|
icon={<Icon icon={Trash2} size="sm" />}
|
|
760
787
|
variant="ghost"
|
|
761
788
|
size="sm"
|
|
762
|
-
onClick={(e:
|
|
789
|
+
onClick={(e: MouseEvent) => {
|
|
763
790
|
e.stopPropagation();
|
|
764
791
|
deleteBlock(block.id);
|
|
765
792
|
}}
|
|
@@ -811,15 +838,16 @@ export default function PageEditor() {
|
|
|
811
838
|
<LayoutPanel
|
|
812
839
|
hasDivider={!isMobile}
|
|
813
840
|
padding={0}
|
|
814
|
-
|
|
841
|
+
width={isMobile ? '100%' : 320}
|
|
842
|
+
style={panelShrink}>
|
|
815
843
|
<VStack gap={4}>
|
|
816
|
-
{/* Panel Header */}
|
|
844
|
+
{/* Panel Header — mobile/desktop branches are exclusive: exactly one h1. */}
|
|
817
845
|
<Section variant="transparent" padding={4}>
|
|
818
846
|
{isMobile ? (
|
|
819
847
|
// Mobile: the title, an Edit button that opens the customizations
|
|
820
848
|
// dialog, and the primary action.
|
|
821
849
|
<HStack gap={3} vAlign="center" hAlign="between">
|
|
822
|
-
<Heading level={2
|
|
850
|
+
<Heading level={1} type="display-2">{pageTitle}</Heading>
|
|
823
851
|
<HStack gap={2} vAlign="center">
|
|
824
852
|
<Button
|
|
825
853
|
label="Edit"
|
|
@@ -839,7 +867,7 @@ export default function PageEditor() {
|
|
|
839
867
|
isLabelHidden
|
|
840
868
|
value={pageTitle}
|
|
841
869
|
onChange={setPageTitle}
|
|
842
|
-
onKeyDown={(e:
|
|
870
|
+
onKeyDown={(e: KeyboardEvent) => {
|
|
843
871
|
if (e.key === 'Enter') {
|
|
844
872
|
setIsEditingTitle(false);
|
|
845
873
|
}
|
|
@@ -848,7 +876,7 @@ export default function PageEditor() {
|
|
|
848
876
|
onBlur={() => setIsEditingTitle(false)}
|
|
849
877
|
/>
|
|
850
878
|
) : (
|
|
851
|
-
<Heading level={2
|
|
879
|
+
<Heading level={1} type="display-2">{pageTitle}</Heading>
|
|
852
880
|
)}
|
|
853
881
|
|
|
854
882
|
<Toolbar
|
|
@@ -922,7 +950,7 @@ export default function PageEditor() {
|
|
|
922
950
|
<EmptyState
|
|
923
951
|
title="No blocks yet"
|
|
924
952
|
description="Add blocks from the sidebar to start building your page"
|
|
925
|
-
icon={<Icon icon={CirclePlus} />}
|
|
953
|
+
icon={<Icon icon={CirclePlus} color="secondary" />}
|
|
926
954
|
/>
|
|
927
955
|
)}
|
|
928
956
|
</VStack>
|