astryx-dracula 0.1.3 → 0.2.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 +1 -1
- package/README.md +2 -0
- package/USAGE.md +13 -0
- package/astryx-dracula.js +4 -4
- package/astryx.integration.mjs +3 -0
- package/package.json +4 -2
- package/templates/ai-chat-landing.template.mjs +6 -0
- package/templates/ai-chat-landing.tsx +476 -0
- package/templates/ai-chat.template.mjs +6 -0
- package/templates/ai-chat.tsx +762 -0
- package/templates/blank.template.mjs +6 -0
- package/templates/blank.tsx +16 -0
- package/templates/centered-hero.template.mjs +6 -0
- package/templates/centered-hero.tsx +188 -0
- package/templates/classic-gallery.template.mjs +6 -0
- package/templates/classic-gallery.tsx +181 -0
- package/templates/contact-form.template.mjs +6 -0
- package/templates/contact-form.tsx +292 -0
- package/templates/dashboard-portfolio.template.mjs +6 -0
- package/templates/dashboard-portfolio.tsx +800 -0
- package/templates/dashboard.template.mjs +6 -0
- package/templates/dashboard.tsx +774 -0
- package/templates/detail-page.template.mjs +6 -0
- package/templates/detail-page.tsx +695 -0
- package/templates/documentation-design.template.mjs +6 -0
- package/templates/documentation-design.tsx +751 -0
- package/templates/documentation-technical.template.mjs +6 -0
- package/templates/documentation-technical.tsx +292 -0
- package/templates/documentation.template.mjs +6 -0
- package/templates/documentation.tsx +347 -0
- package/templates/editor.template.mjs +6 -0
- package/templates/editor.tsx +959 -0
- package/templates/file-explorer.template.mjs +6 -0
- package/templates/file-explorer.tsx +577 -0
- package/templates/form-two-column.template.mjs +6 -0
- package/templates/form-two-column.tsx +314 -0
- package/templates/gallery-hero.template.mjs +6 -0
- package/templates/gallery-hero.tsx +287 -0
- package/templates/ide.template.mjs +6 -0
- package/templates/ide.tsx +533 -0
- package/templates/incident-console.template.mjs +6 -0
- package/templates/incident-console.tsx +584 -0
- package/templates/kanban-board.template.mjs +6 -0
- package/templates/kanban-board.tsx +746 -0
- package/templates/library.template.mjs +6 -0
- package/templates/library.tsx +489 -0
- package/templates/login-card.template.mjs +6 -0
- package/templates/login-card.tsx +200 -0
- package/templates/login-split.template.mjs +6 -0
- package/templates/login-split.tsx +318 -0
- package/templates/login-sso.template.mjs +6 -0
- package/templates/login-sso.tsx +277 -0
- package/templates/login.template.mjs +6 -0
- package/templates/login.tsx +98 -0
- package/templates/messaging-shell.template.mjs +6 -0
- package/templates/messaging-shell.tsx +675 -0
- package/templates/mixed-gallery.template.mjs +6 -0
- package/templates/mixed-gallery.tsx +190 -0
- package/templates/payment-form.template.mjs +6 -0
- package/templates/payment-form.tsx +990 -0
- package/templates/product-detail.template.mjs +6 -0
- package/templates/product-detail.tsx +366 -0
- package/templates/product-gallery.template.mjs +6 -0
- package/templates/product-gallery.tsx +173 -0
- package/templates/settings-dialog.template.mjs +6 -0
- package/templates/settings-dialog.tsx +920 -0
- package/templates/settings-sidebar.template.mjs +6 -0
- package/templates/settings-sidebar.tsx +952 -0
- package/templates/settings.template.mjs +6 -0
- package/templates/settings.tsx +235 -0
- package/templates/shell-nav.template.mjs +6 -0
- package/templates/shell-nav.tsx +306 -0
- package/templates/shell-side-nav.template.mjs +6 -0
- package/templates/shell-side-nav.tsx +238 -0
- package/templates/shell-top-nav.template.mjs +6 -0
- package/templates/shell-top-nav.tsx +243 -0
- package/templates/side-gallery.template.mjs +6 -0
- package/templates/side-gallery.tsx +179 -0
- package/templates/table-grouped.template.mjs +6 -0
- package/templates/table-grouped.tsx +1174 -0
- package/templates/table-page-chart.template.mjs +6 -0
- package/templates/table-page-chart.tsx +693 -0
- package/templates/table-page-heatmap-status.template.mjs +6 -0
- package/templates/table-page-heatmap-status.tsx +547 -0
- package/templates/table-page-shoe-store-heatmap.template.mjs +6 -0
- package/templates/table-page-shoe-store-heatmap.tsx +1038 -0
- package/templates/table-page.template.mjs +6 -0
- package/templates/table-page.tsx +445 -0
- package/templates/table.template.mjs +6 -0
- package/templates/table.tsx +84 -0
- package/templates/theme-showcase.template.mjs +6 -0
- package/templates/theme-showcase.tsx +1282 -0
- package/theme.css +4 -4
- package/tokens.css +4 -4
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
|
|
4
|
+
import {Text} from '@astryxdesign/core/Text';
|
|
5
|
+
|
|
6
|
+
export default function BlankPage() {
|
|
7
|
+
return (
|
|
8
|
+
<Layout
|
|
9
|
+
content={
|
|
10
|
+
<LayoutContent>
|
|
11
|
+
<Text type="large">A blank crypt awaits its story</Text>
|
|
12
|
+
</LayoutContent>
|
|
13
|
+
}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import type {CSSProperties} from 'react';
|
|
4
|
+
import {VStack, HStack, Layout, LayoutContent} from '@astryxdesign/core/Layout';
|
|
5
|
+
import {Text, Heading} from '@astryxdesign/core/Text';
|
|
6
|
+
import {Button} from '@astryxdesign/core/Button';
|
|
7
|
+
import {Icon} from '@astryxdesign/core/Icon';
|
|
8
|
+
import {AspectRatio} from '@astryxdesign/core/AspectRatio';
|
|
9
|
+
import {Section} from '@astryxdesign/core/Section';
|
|
10
|
+
import {ArrowRight} from 'lucide-react';
|
|
11
|
+
|
|
12
|
+
const heroImage: CSSProperties = {
|
|
13
|
+
width: '100%',
|
|
14
|
+
height: '100%',
|
|
15
|
+
display: 'block',
|
|
16
|
+
};
|
|
17
|
+
const heroFrame: CSSProperties = {
|
|
18
|
+
maxWidth: 1200,
|
|
19
|
+
marginInline: 'auto',
|
|
20
|
+
borderRadius: 'var(--radius-page)',
|
|
21
|
+
border: 'var(--border-width) solid var(--color-separator)',
|
|
22
|
+
overflow: 'clip',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function NightCastleScene() {
|
|
26
|
+
return (
|
|
27
|
+
<svg
|
|
28
|
+
style={heroImage}
|
|
29
|
+
viewBox="0 0 800 450"
|
|
30
|
+
role="img"
|
|
31
|
+
aria-label="Moonlit castle on a hill in Dracula theme colors">
|
|
32
|
+
<title>Castle under a harvest moon</title>
|
|
33
|
+
<rect width="800" height="450" fill="var(--dracula-bg-dark)" />
|
|
34
|
+
{/* Stars */}
|
|
35
|
+
<g fill="var(--dracula-purple)">
|
|
36
|
+
<circle cx="60" cy="60" r="2.5" />
|
|
37
|
+
<circle cx="180" cy="120" r="2" />
|
|
38
|
+
<circle cx="330" cy="50" r="2.5" />
|
|
39
|
+
<circle cx="470" cy="90" r="2" />
|
|
40
|
+
<circle cx="700" cy="200" r="2.5" />
|
|
41
|
+
<circle cx="750" cy="80" r="2" />
|
|
42
|
+
</g>
|
|
43
|
+
<g fill="var(--dracula-cyan)">
|
|
44
|
+
<circle cx="120" cy="90" r="2" />
|
|
45
|
+
<circle cx="270" cy="70" r="2.5" />
|
|
46
|
+
<circle cx="540" cy="50" r="2" />
|
|
47
|
+
<circle cx="660" cy="160" r="2" />
|
|
48
|
+
</g>
|
|
49
|
+
<g fill="var(--dracula-pink)">
|
|
50
|
+
<circle cx="90" cy="170" r="2" />
|
|
51
|
+
<circle cx="400" cy="130" r="2.5" />
|
|
52
|
+
<circle cx="590" cy="200" r="2" />
|
|
53
|
+
<circle cx="730" cy="260" r="2" />
|
|
54
|
+
</g>
|
|
55
|
+
{/* Harvest moon */}
|
|
56
|
+
<circle cx="620" cy="110" r="56" fill="var(--dracula-yellow)" />
|
|
57
|
+
<circle
|
|
58
|
+
cx="600"
|
|
59
|
+
cy="95"
|
|
60
|
+
r="10"
|
|
61
|
+
fill="var(--dracula-orange)"
|
|
62
|
+
opacity={0.5}
|
|
63
|
+
/>
|
|
64
|
+
<circle
|
|
65
|
+
cx="638"
|
|
66
|
+
cy="125"
|
|
67
|
+
r="7"
|
|
68
|
+
fill="var(--dracula-orange)"
|
|
69
|
+
opacity={0.5}
|
|
70
|
+
/>
|
|
71
|
+
{/* Bats */}
|
|
72
|
+
<g
|
|
73
|
+
fill="none"
|
|
74
|
+
stroke="var(--dracula-purple)"
|
|
75
|
+
strokeWidth={4}
|
|
76
|
+
strokeLinecap="round">
|
|
77
|
+
<path d="M120 130 q12 -12 24 0 q12 -12 24 0" />
|
|
78
|
+
<path d="M210 90 q9 -9 18 0 q9 -9 18 0" />
|
|
79
|
+
<path d="M470 160 q9 -9 18 0 q9 -9 18 0" />
|
|
80
|
+
</g>
|
|
81
|
+
{/* Hills */}
|
|
82
|
+
<path
|
|
83
|
+
d="M0 330 Q200 260 400 320 T800 300 V450 H0 Z"
|
|
84
|
+
fill="var(--dracula-selection)"
|
|
85
|
+
/>
|
|
86
|
+
<path
|
|
87
|
+
d="M0 385 Q240 320 480 375 T800 360 V450 H0 Z"
|
|
88
|
+
fill="var(--dracula-bg-light)"
|
|
89
|
+
/>
|
|
90
|
+
{/* Castle */}
|
|
91
|
+
<g>
|
|
92
|
+
<rect
|
|
93
|
+
x="150"
|
|
94
|
+
y="225"
|
|
95
|
+
width="120"
|
|
96
|
+
height="120"
|
|
97
|
+
rx={4}
|
|
98
|
+
fill="var(--dracula-bg-lighter)"
|
|
99
|
+
/>
|
|
100
|
+
<rect
|
|
101
|
+
x="130"
|
|
102
|
+
y="185"
|
|
103
|
+
width="44"
|
|
104
|
+
height="160"
|
|
105
|
+
rx={4}
|
|
106
|
+
fill="var(--dracula-bg-lighter)"
|
|
107
|
+
/>
|
|
108
|
+
<rect
|
|
109
|
+
x="246"
|
|
110
|
+
y="185"
|
|
111
|
+
width="44"
|
|
112
|
+
height="160"
|
|
113
|
+
rx={4}
|
|
114
|
+
fill="var(--dracula-bg-lighter)"
|
|
115
|
+
/>
|
|
116
|
+
<g fill="var(--dracula-bg-lighter)">
|
|
117
|
+
<rect x="130" y="175" width="12" height="14" rx={2} />
|
|
118
|
+
<rect x="149" y="175" width="12" height="14" rx={2} />
|
|
119
|
+
<rect x="246" y="175" width="12" height="14" rx={2} />
|
|
120
|
+
<rect x="265" y="175" width="12" height="14" rx={2} />
|
|
121
|
+
<rect x="150" y="215" width="14" height="16" rx={2} />
|
|
122
|
+
<rect x="173" y="215" width="14" height="16" rx={2} />
|
|
123
|
+
<rect x="196" y="215" width="14" height="16" rx={2} />
|
|
124
|
+
<rect x="219" y="215" width="14" height="16" rx={2} />
|
|
125
|
+
<rect x="242" y="215" width="14" height="16" rx={2} />
|
|
126
|
+
</g>
|
|
127
|
+
<g fill="var(--dracula-yellow)">
|
|
128
|
+
<rect x="168" y="255" width="14" height="20" rx={2} />
|
|
129
|
+
<rect x="203" y="255" width="14" height="20" rx={2} />
|
|
130
|
+
<rect x="238" y="255" width="14" height="20" rx={2} />
|
|
131
|
+
<rect x="143" y="215" width="10" height="14" rx={2} />
|
|
132
|
+
<rect x="259" y="215" width="10" height="14" rx={2} />
|
|
133
|
+
</g>
|
|
134
|
+
<path
|
|
135
|
+
d="M195 345 v-30 a15 15 0 0 1 30 0 v30 Z"
|
|
136
|
+
fill="var(--dracula-bg-dark)"
|
|
137
|
+
/>
|
|
138
|
+
</g>
|
|
139
|
+
</svg>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export default function CenteredHero() {
|
|
144
|
+
return (
|
|
145
|
+
<Layout
|
|
146
|
+
content={
|
|
147
|
+
<LayoutContent padding={6}>
|
|
148
|
+
<VStack gap={10}>
|
|
149
|
+
<VStack gap={6} hAlign="center">
|
|
150
|
+
<VStack gap={3} hAlign="center">
|
|
151
|
+
<Heading
|
|
152
|
+
level={1}
|
|
153
|
+
type="display-2"
|
|
154
|
+
justify="center"
|
|
155
|
+
textWrap="balance">
|
|
156
|
+
Small joys for creatures of the night
|
|
157
|
+
</Heading>
|
|
158
|
+
<Text
|
|
159
|
+
type="body"
|
|
160
|
+
color="secondary"
|
|
161
|
+
justify="center"
|
|
162
|
+
textWrap="balance">
|
|
163
|
+
Sometimes all it takes is one small ritual to turn the whole
|
|
164
|
+
night around.
|
|
165
|
+
</Text>
|
|
166
|
+
</VStack>
|
|
167
|
+
<HStack gap={3} wrap="wrap" justify="center">
|
|
168
|
+
<Button
|
|
169
|
+
label="Embrace the night"
|
|
170
|
+
variant="primary"
|
|
171
|
+
endContent={
|
|
172
|
+
<Icon icon={ArrowRight} size="sm" color="inherit" />
|
|
173
|
+
}
|
|
174
|
+
/>
|
|
175
|
+
<Button label="Read the lore" variant="secondary" />
|
|
176
|
+
</HStack>
|
|
177
|
+
</VStack>
|
|
178
|
+
<Section variant="transparent" padding={0}>
|
|
179
|
+
<AspectRatio ratio={16 / 9} style={heroFrame}>
|
|
180
|
+
<NightCastleScene />
|
|
181
|
+
</AspectRatio>
|
|
182
|
+
</Section>
|
|
183
|
+
</VStack>
|
|
184
|
+
</LayoutContent>
|
|
185
|
+
}
|
|
186
|
+
/>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import {useState, type CSSProperties} from 'react';
|
|
4
|
+
import {VStack, Layout, LayoutContent} from '@astryxdesign/core/Layout';
|
|
5
|
+
import {Center} from '@astryxdesign/core/Center';
|
|
6
|
+
import {Card} from '@astryxdesign/core/Card';
|
|
7
|
+
import {AspectRatio} from '@astryxdesign/core/AspectRatio';
|
|
8
|
+
import {Text, Heading} from '@astryxdesign/core/Text';
|
|
9
|
+
import {Grid} from '@astryxdesign/core/Grid';
|
|
10
|
+
import {Section} from '@astryxdesign/core/Section';
|
|
11
|
+
import {TabList, Tab} from '@astryxdesign/core/TabList';
|
|
12
|
+
|
|
13
|
+
// ─── Styles ─────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
const outer: CSSProperties = {
|
|
16
|
+
maxWidth: 1200,
|
|
17
|
+
width: '100%',
|
|
18
|
+
paddingInline: 'var(--space-viewport)',
|
|
19
|
+
paddingBlock: 'var(--space-viewport)',
|
|
20
|
+
};
|
|
21
|
+
const frameClip: CSSProperties = {
|
|
22
|
+
overflow: 'clip',
|
|
23
|
+
};
|
|
24
|
+
const artImage: CSSProperties = {
|
|
25
|
+
width: '100%',
|
|
26
|
+
height: '100%',
|
|
27
|
+
display: 'block',
|
|
28
|
+
};
|
|
29
|
+
const textCenter: CSSProperties = {
|
|
30
|
+
textAlign: 'center',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// ─── Gallery Data ───────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
type Category = 'all' | 'lifestyle' | 'scene' | 'home';
|
|
36
|
+
|
|
37
|
+
interface GalleryImage {
|
|
38
|
+
alt: string;
|
|
39
|
+
category: Exclude<Category, 'all'>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Dracula accent per gallery shelf.
|
|
43
|
+
const CATEGORY_HUES: Record<Exclude<Category, 'all'>, string> = {
|
|
44
|
+
scene: 'var(--dracula-cyan)',
|
|
45
|
+
lifestyle: 'var(--dracula-pink)',
|
|
46
|
+
home: 'var(--dracula-yellow)',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const GALLERY_IMAGES: GalleryImage[] = [
|
|
50
|
+
{alt: 'Moonlit ridge trail under a harvest moon', category: 'scene'},
|
|
51
|
+
{alt: 'Late portrait in violet lamplight', category: 'lifestyle'},
|
|
52
|
+
{alt: 'Lamplit reading nook after midnight', category: 'home'},
|
|
53
|
+
{alt: 'Fog rolling over the night pines', category: 'scene'},
|
|
54
|
+
{alt: 'Dancer caught mid-step in stage pink', category: 'lifestyle'},
|
|
55
|
+
{alt: 'Kitchen table set for a midnight feast', category: 'lifestyle'},
|
|
56
|
+
{alt: 'Castle silhouette over sleeping hills', category: 'scene'},
|
|
57
|
+
{alt: 'Attic window glowing amber at 2am', category: 'home'},
|
|
58
|
+
{alt: 'Cellar shelves lined with bottled dusk', category: 'home'},
|
|
59
|
+
{alt: 'Bats crossing a violet harvest moon', category: 'scene'},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
// ─── Gallery Art ────────────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
function GalleryArt({image, index}: {image: GalleryImage; index: number}) {
|
|
65
|
+
const hue = CATEGORY_HUES[image.category];
|
|
66
|
+
const moonX = 90 + ((index * 53) % 220);
|
|
67
|
+
const moonY = 62 + ((index * 29) % 60);
|
|
68
|
+
const hillA = 190 + ((index * 13) % 40);
|
|
69
|
+
const hillB = 215 + ((index * 17) % 40);
|
|
70
|
+
return (
|
|
71
|
+
<svg
|
|
72
|
+
viewBox="0 0 400 300"
|
|
73
|
+
preserveAspectRatio="xMidYMid slice"
|
|
74
|
+
style={artImage}
|
|
75
|
+
role="img"
|
|
76
|
+
aria-label={image.alt}>
|
|
77
|
+
<rect width="400" height="300" fill="var(--dracula-bg-light)" />
|
|
78
|
+
<g fill="var(--dracula-purple)" opacity={0.55}>
|
|
79
|
+
<circle cx={40 + ((index * 37) % 320)} cy={30} r={2} />
|
|
80
|
+
<circle cx={120 + ((index * 23) % 200)} cy={52} r={1.6} />
|
|
81
|
+
<circle cx={260 + ((index * 11) % 110)} cy={26} r={2.2} />
|
|
82
|
+
<circle cx={330} cy={70 + ((index * 7) % 30)} r={1.6} />
|
|
83
|
+
</g>
|
|
84
|
+
<circle cx={moonX} cy={moonY} r={34} fill={hue} opacity={0.9} />
|
|
85
|
+
<circle
|
|
86
|
+
cx={moonX - 12}
|
|
87
|
+
cy={moonY - 8}
|
|
88
|
+
r={28}
|
|
89
|
+
fill="var(--dracula-bg-light)"
|
|
90
|
+
opacity={0.55}
|
|
91
|
+
/>
|
|
92
|
+
<path
|
|
93
|
+
d={`M0 ${hillA} Q100 ${hillA - 50} 200 ${hillA - 10} T400 ${hillA - 30} V300 H0 Z`}
|
|
94
|
+
fill="var(--dracula-current-line)"
|
|
95
|
+
/>
|
|
96
|
+
<path
|
|
97
|
+
d={`M0 ${hillB} Q120 ${hillB - 40} 240 ${hillB} T400 ${hillB - 20} V300 H0 Z`}
|
|
98
|
+
fill="var(--dracula-bg)"
|
|
99
|
+
/>
|
|
100
|
+
<g
|
|
101
|
+
transform={`translate(${60 + ((index * 41) % 280)} ${hillB - 34})`}
|
|
102
|
+
fill="none"
|
|
103
|
+
stroke={hue}
|
|
104
|
+
strokeWidth="4"
|
|
105
|
+
strokeLinecap="round"
|
|
106
|
+
strokeLinejoin="round">
|
|
107
|
+
<rect x="-22" y="-22" width="44" height="44" rx="5" />
|
|
108
|
+
<circle cx="9" cy="-9" r="2" fill={hue} stroke="none" />
|
|
109
|
+
<path d="M-17 15 L-4 0 L5 9 L10 4 L17 12" />
|
|
110
|
+
</g>
|
|
111
|
+
</svg>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ─── Main Page ──────────────────────────────────────────────────────────────
|
|
116
|
+
|
|
117
|
+
export default function ClassicGallery() {
|
|
118
|
+
const [filter, setFilter] = useState<Category>('all');
|
|
119
|
+
|
|
120
|
+
const filteredImages =
|
|
121
|
+
filter === 'all'
|
|
122
|
+
? GALLERY_IMAGES
|
|
123
|
+
: GALLERY_IMAGES.filter(img => img.category === filter);
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<Layout
|
|
127
|
+
height="fill"
|
|
128
|
+
content={
|
|
129
|
+
<LayoutContent padding={0}>
|
|
130
|
+
<Center axis="horizontal">
|
|
131
|
+
<VStack gap={8} style={outer}>
|
|
132
|
+
{/* Header */}
|
|
133
|
+
<Center axis="horizontal">
|
|
134
|
+
<Section variant="transparent" maxWidth={680} padding={0}>
|
|
135
|
+
<VStack gap={4} hAlign="center" style={textCenter}>
|
|
136
|
+
<VStack gap={2} hAlign="center">
|
|
137
|
+
<Heading level={1}>Hung after dark</Heading>
|
|
138
|
+
<Text type="body" color="secondary">
|
|
139
|
+
A coven-curated wall of moonlit ridges, late portraits,
|
|
140
|
+
and lamplit rooms. Filter by haunt and stay a while —
|
|
141
|
+
the gallery never sleeps.
|
|
142
|
+
</Text>
|
|
143
|
+
</VStack>
|
|
144
|
+
|
|
145
|
+
<TabList
|
|
146
|
+
value={filter}
|
|
147
|
+
onChange={v => setFilter(v as Category)}>
|
|
148
|
+
<Tab value="all" label="All" />
|
|
149
|
+
<Tab value="lifestyle" label="Lifestyle" />
|
|
150
|
+
<Tab value="scene" label="Scenery" />
|
|
151
|
+
<Tab value="home" label="Home" />
|
|
152
|
+
</TabList>
|
|
153
|
+
<Text
|
|
154
|
+
type="supporting"
|
|
155
|
+
color="secondary"
|
|
156
|
+
hasTabularNumbers>
|
|
157
|
+
{filteredImages.length}{' '}
|
|
158
|
+
{filteredImages.length === 1 ? 'piece' : 'pieces'} on the
|
|
159
|
+
wall
|
|
160
|
+
</Text>
|
|
161
|
+
</VStack>
|
|
162
|
+
</Section>
|
|
163
|
+
</Center>
|
|
164
|
+
|
|
165
|
+
{/* Gallery Grid */}
|
|
166
|
+
<Grid columns={{minWidth: 260, repeat: 'fit'}} gap={4}>
|
|
167
|
+
{filteredImages.map((image, i) => (
|
|
168
|
+
<Card key={image.alt} padding={0} style={frameClip}>
|
|
169
|
+
<AspectRatio ratio={3 / 2}>
|
|
170
|
+
<GalleryArt image={image} index={i} />
|
|
171
|
+
</AspectRatio>
|
|
172
|
+
</Card>
|
|
173
|
+
))}
|
|
174
|
+
</Grid>
|
|
175
|
+
</VStack>
|
|
176
|
+
</Center>
|
|
177
|
+
</LayoutContent>
|
|
178
|
+
}
|
|
179
|
+
/>
|
|
180
|
+
);
|
|
181
|
+
}
|