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,314 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import {useState, type CSSProperties} from 'react';
|
|
4
|
+
import {VStack, HStack} from '@astryxdesign/core/Layout';
|
|
5
|
+
import {Center} from '@astryxdesign/core/Center';
|
|
6
|
+
import {Section} from '@astryxdesign/core/Section';
|
|
7
|
+
import {Grid} from '@astryxdesign/core/Grid';
|
|
8
|
+
import {AspectRatio} from '@astryxdesign/core/AspectRatio';
|
|
9
|
+
import {Button} from '@astryxdesign/core/Button';
|
|
10
|
+
import {Text, Heading} from '@astryxdesign/core/Text';
|
|
11
|
+
import {TextInput} from '@astryxdesign/core/TextInput';
|
|
12
|
+
import {Token} from '@astryxdesign/core/Token';
|
|
13
|
+
import {TextArea} from '@astryxdesign/core/TextArea';
|
|
14
|
+
import {Link} from '@astryxdesign/core/Link';
|
|
15
|
+
import {Divider} from '@astryxdesign/core/Divider';
|
|
16
|
+
import {Card} from '@astryxdesign/core/Card';
|
|
17
|
+
import {Selector} from '@astryxdesign/core/Selector';
|
|
18
|
+
|
|
19
|
+
function CastleIllustration() {
|
|
20
|
+
return (
|
|
21
|
+
<svg
|
|
22
|
+
style={illustrationImg}
|
|
23
|
+
viewBox="0 0 400 300"
|
|
24
|
+
role="img"
|
|
25
|
+
aria-label="Moonlit castle where the night crew works">
|
|
26
|
+
<title>Castle office after dark</title>
|
|
27
|
+
<rect width="400" height="300" fill="var(--dracula-bg-dark)" />
|
|
28
|
+
<g fill="var(--dracula-purple)">
|
|
29
|
+
<circle cx="40" cy="40" r="2.5" />
|
|
30
|
+
<circle cx="120" cy="70" r="2" />
|
|
31
|
+
<circle cx="210" cy="36" r="2.5" />
|
|
32
|
+
<circle cx="330" cy="60" r="2" />
|
|
33
|
+
</g>
|
|
34
|
+
<g fill="var(--dracula-cyan)">
|
|
35
|
+
<circle cx="80" cy="55" r="2" />
|
|
36
|
+
<circle cx="170" cy="60" r="2" />
|
|
37
|
+
<circle cx="290" cy="36" r="2.5" />
|
|
38
|
+
</g>
|
|
39
|
+
<circle cx="315" cy="70" r="34" fill="var(--dracula-yellow)" />
|
|
40
|
+
<circle
|
|
41
|
+
cx="304"
|
|
42
|
+
cy="61"
|
|
43
|
+
r="6"
|
|
44
|
+
fill="var(--dracula-orange)"
|
|
45
|
+
opacity={0.5}
|
|
46
|
+
/>
|
|
47
|
+
<g
|
|
48
|
+
fill="none"
|
|
49
|
+
stroke="var(--dracula-purple)"
|
|
50
|
+
strokeWidth={3}
|
|
51
|
+
strokeLinecap="round">
|
|
52
|
+
<path d="M90 100 q9 -9 18 0 q9 -9 18 0" />
|
|
53
|
+
<path d="M180 84 q9 -9 18 0 q9 -9 18 0" />
|
|
54
|
+
</g>
|
|
55
|
+
<path
|
|
56
|
+
d="M0 220 Q140 180 260 210 T400 200 V300 H0 Z"
|
|
57
|
+
fill="var(--dracula-selection)"
|
|
58
|
+
/>
|
|
59
|
+
<path
|
|
60
|
+
d="M0 255 Q160 225 320 250 T400 245 V300 H0 Z"
|
|
61
|
+
fill="var(--dracula-bg-light)"
|
|
62
|
+
/>
|
|
63
|
+
<g>
|
|
64
|
+
<rect
|
|
65
|
+
x="140"
|
|
66
|
+
y="150"
|
|
67
|
+
width="120"
|
|
68
|
+
height="100"
|
|
69
|
+
rx={4}
|
|
70
|
+
fill="var(--dracula-bg-lighter)"
|
|
71
|
+
/>
|
|
72
|
+
<rect
|
|
73
|
+
x="122"
|
|
74
|
+
y="122"
|
|
75
|
+
width="38"
|
|
76
|
+
height="128"
|
|
77
|
+
rx={4}
|
|
78
|
+
fill="var(--dracula-bg-lighter)"
|
|
79
|
+
/>
|
|
80
|
+
<rect
|
|
81
|
+
x="240"
|
|
82
|
+
y="122"
|
|
83
|
+
width="38"
|
|
84
|
+
height="128"
|
|
85
|
+
rx={4}
|
|
86
|
+
fill="var(--dracula-bg-lighter)"
|
|
87
|
+
/>
|
|
88
|
+
<g fill="var(--dracula-yellow)">
|
|
89
|
+
<rect x="156" y="172" width="12" height="18" rx={2} />
|
|
90
|
+
<rect x="186" y="172" width="12" height="18" rx={2} />
|
|
91
|
+
<rect x="216" y="172" width="12" height="18" rx={2} />
|
|
92
|
+
<rect x="132" y="146" width="9" height="12" rx={2} />
|
|
93
|
+
<rect x="251" y="146" width="9" height="12" rx={2} />
|
|
94
|
+
</g>
|
|
95
|
+
<path
|
|
96
|
+
d="M185 250 v-24 a15 15 0 0 1 30 0 v24 Z"
|
|
97
|
+
fill="var(--dracula-bg-dark)"
|
|
98
|
+
/>
|
|
99
|
+
</g>
|
|
100
|
+
</svg>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const INQUIRY_REASONS = [
|
|
105
|
+
'New business',
|
|
106
|
+
'General inquiry',
|
|
107
|
+
'Press & media',
|
|
108
|
+
'Partnerships',
|
|
109
|
+
'Product feedback',
|
|
110
|
+
'Technical support',
|
|
111
|
+
'Other',
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const BUDGET_OPTIONS = [
|
|
115
|
+
'Under $10k',
|
|
116
|
+
'$10k – $50k',
|
|
117
|
+
'$50k – $100k',
|
|
118
|
+
'$100k – $500k',
|
|
119
|
+
'$500k+',
|
|
120
|
+
'Not sure yet',
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
const CONTACT_COLUMNS = [
|
|
124
|
+
{label: 'General inquiries', email: 'hello@castle.dracula'},
|
|
125
|
+
{label: 'New business', email: 'newbiz@castle.dracula'},
|
|
126
|
+
{label: 'Press & partnerships', email: 'press@castle.dracula'},
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
// AspectRatio has no radius prop and there's no Image primitive (#2582), so
|
|
130
|
+
// the illustration carries its own corner radius directly.
|
|
131
|
+
const pageStyle: CSSProperties = {
|
|
132
|
+
minHeight: '100%',
|
|
133
|
+
};
|
|
134
|
+
const illustrationImg: CSSProperties = {
|
|
135
|
+
width: '100%',
|
|
136
|
+
height: '100%',
|
|
137
|
+
display: 'block',
|
|
138
|
+
borderRadius: 'var(--radius-container)',
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Form (Two-column) — marketing contact form template.
|
|
143
|
+
*
|
|
144
|
+
* Layout:
|
|
145
|
+
* Top: two-column — left has headline + description + illustration,
|
|
146
|
+
* right has the contact form on a card.
|
|
147
|
+
* Bottom: three-column contact info strip.
|
|
148
|
+
* Mobile (<768px): single column stack.
|
|
149
|
+
*/
|
|
150
|
+
export default function TwoColumnForm() {
|
|
151
|
+
const [fullName, setFullName] = useState('');
|
|
152
|
+
const [email, setEmail] = useState('');
|
|
153
|
+
const [company, setCompany] = useState('');
|
|
154
|
+
const [jobTitle, setJobTitle] = useState('');
|
|
155
|
+
const [phone, setPhone] = useState('');
|
|
156
|
+
const [inquiryReason, setInquiryReason] = useState('');
|
|
157
|
+
const [budget, setBudget] = useState('');
|
|
158
|
+
const [details, setDetails] = useState('');
|
|
159
|
+
const [submitted, setSubmitted] = useState(false);
|
|
160
|
+
|
|
161
|
+
const errors = submitted
|
|
162
|
+
? {
|
|
163
|
+
fullName: !fullName.trim() ? 'Required' : undefined,
|
|
164
|
+
email: !email.trim() ? 'Required' : undefined,
|
|
165
|
+
details: !details.trim() ? 'Required' : undefined,
|
|
166
|
+
}
|
|
167
|
+
: {};
|
|
168
|
+
|
|
169
|
+
const handleSubmit = () => setSubmitted(true);
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<Center style={pageStyle}>
|
|
173
|
+
<Section maxWidth={1100} width="100%" padding={10} variant="transparent">
|
|
174
|
+
<VStack gap={10}>
|
|
175
|
+
{/* Two-column; stacks to one column below ~520px. */}
|
|
176
|
+
<Grid columns={{minWidth: 320}} align="center" gap={10}>
|
|
177
|
+
<VStack gap={6}>
|
|
178
|
+
<VStack gap={3}>
|
|
179
|
+
<Heading level={1} type="display-1">
|
|
180
|
+
Let's conjure together
|
|
181
|
+
</Heading>
|
|
182
|
+
<Text type="body" color="secondary">
|
|
183
|
+
Tell us what you're brewing and we'll help you find
|
|
184
|
+
the best path through the night.
|
|
185
|
+
</Text>
|
|
186
|
+
</VStack>
|
|
187
|
+
<AspectRatio ratio={4 / 3}>
|
|
188
|
+
<CastleIllustration />
|
|
189
|
+
</AspectRatio>
|
|
190
|
+
</VStack>
|
|
191
|
+
|
|
192
|
+
<Card padding={8}>
|
|
193
|
+
<VStack gap={4}>
|
|
194
|
+
<Text type="label">Your details</Text>
|
|
195
|
+
<TextInput
|
|
196
|
+
label="Full name"
|
|
197
|
+
isLabelHidden
|
|
198
|
+
placeholder="Full name*"
|
|
199
|
+
value={fullName}
|
|
200
|
+
onChange={setFullName}
|
|
201
|
+
status={
|
|
202
|
+
errors.fullName
|
|
203
|
+
? {type: 'error', message: errors.fullName}
|
|
204
|
+
: undefined
|
|
205
|
+
}
|
|
206
|
+
/>
|
|
207
|
+
<Grid columns={{minWidth: 180}} gap={3}>
|
|
208
|
+
<TextInput
|
|
209
|
+
label="Email"
|
|
210
|
+
isLabelHidden
|
|
211
|
+
placeholder="Email*"
|
|
212
|
+
value={email}
|
|
213
|
+
onChange={setEmail}
|
|
214
|
+
status={
|
|
215
|
+
errors.email
|
|
216
|
+
? {type: 'error', message: errors.email}
|
|
217
|
+
: undefined
|
|
218
|
+
}
|
|
219
|
+
/>
|
|
220
|
+
<TextInput
|
|
221
|
+
label="Company name"
|
|
222
|
+
isLabelHidden
|
|
223
|
+
placeholder="Company name"
|
|
224
|
+
value={company}
|
|
225
|
+
onChange={setCompany}
|
|
226
|
+
/>
|
|
227
|
+
</Grid>
|
|
228
|
+
<Grid columns={{minWidth: 180}} gap={3}>
|
|
229
|
+
<TextInput
|
|
230
|
+
label="Job title"
|
|
231
|
+
isLabelHidden
|
|
232
|
+
placeholder="Job title"
|
|
233
|
+
value={jobTitle}
|
|
234
|
+
onChange={setJobTitle}
|
|
235
|
+
/>
|
|
236
|
+
<TextInput
|
|
237
|
+
label="Phone number"
|
|
238
|
+
isLabelHidden
|
|
239
|
+
placeholder="Phone number"
|
|
240
|
+
value={phone}
|
|
241
|
+
onChange={setPhone}
|
|
242
|
+
/>
|
|
243
|
+
</Grid>
|
|
244
|
+
|
|
245
|
+
<VStack gap={2}>
|
|
246
|
+
<Text type="label">What are you reaching out about?</Text>
|
|
247
|
+
<HStack gap={2} wrap="wrap">
|
|
248
|
+
{INQUIRY_REASONS.map(reason => (
|
|
249
|
+
<Token
|
|
250
|
+
key={reason}
|
|
251
|
+
label={reason}
|
|
252
|
+
color={inquiryReason === reason ? 'blue' : 'default'}
|
|
253
|
+
onClick={() =>
|
|
254
|
+
setInquiryReason(prev =>
|
|
255
|
+
prev === reason ? '' : reason,
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
/>
|
|
259
|
+
))}
|
|
260
|
+
</HStack>
|
|
261
|
+
</VStack>
|
|
262
|
+
<Selector
|
|
263
|
+
label="Budget range"
|
|
264
|
+
options={BUDGET_OPTIONS}
|
|
265
|
+
value={budget}
|
|
266
|
+
onChange={setBudget}
|
|
267
|
+
placeholder="Select a budget range..."
|
|
268
|
+
/>
|
|
269
|
+
<TextArea
|
|
270
|
+
label="Project details"
|
|
271
|
+
isLabelHidden
|
|
272
|
+
placeholder="Project details*"
|
|
273
|
+
value={details}
|
|
274
|
+
onChange={setDetails}
|
|
275
|
+
status={
|
|
276
|
+
errors.details
|
|
277
|
+
? {type: 'error', message: errors.details}
|
|
278
|
+
: undefined
|
|
279
|
+
}
|
|
280
|
+
/>
|
|
281
|
+
{/* hAlign="stretch" = full-width button workaround; Button
|
|
282
|
+
has no full-width prop (#2600). */}
|
|
283
|
+
<VStack hAlign="stretch">
|
|
284
|
+
<Button
|
|
285
|
+
label="Send it into the night"
|
|
286
|
+
variant="primary"
|
|
287
|
+
onClick={handleSubmit}
|
|
288
|
+
/>
|
|
289
|
+
</VStack>
|
|
290
|
+
</VStack>
|
|
291
|
+
</Card>
|
|
292
|
+
</Grid>
|
|
293
|
+
|
|
294
|
+
{/* Contact strip; stacks below ~440px. */}
|
|
295
|
+
<VStack gap={6}>
|
|
296
|
+
<Divider />
|
|
297
|
+
<Grid columns={{minWidth: 200}} gap={6}>
|
|
298
|
+
{CONTACT_COLUMNS.map(col => (
|
|
299
|
+
<VStack key={col.label} gap={1} hAlign="center">
|
|
300
|
+
<Text type="supporting" color="secondary">
|
|
301
|
+
{col.label}
|
|
302
|
+
</Text>
|
|
303
|
+
<Link href={`mailto:${col.email}`} type="body" size="sm">
|
|
304
|
+
{col.email}
|
|
305
|
+
</Link>
|
|
306
|
+
</VStack>
|
|
307
|
+
))}
|
|
308
|
+
</Grid>
|
|
309
|
+
</VStack>
|
|
310
|
+
</VStack>
|
|
311
|
+
</Section>
|
|
312
|
+
</Center>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
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 {Grid} from '@astryxdesign/core/Grid';
|
|
9
|
+
import {AspectRatio} from '@astryxdesign/core/AspectRatio';
|
|
10
|
+
import {ArrowRight} from 'lucide-react';
|
|
11
|
+
|
|
12
|
+
// NOTE: The only custom styling here is gallery fill + corner radius. It
|
|
13
|
+
// exists because Astryx has no image primitive — AspectRatio exposes no
|
|
14
|
+
// objectFit or radius props and there's no Image. Tracked in issue #2582;
|
|
15
|
+
// replace these with component props once it lands.
|
|
16
|
+
// Fills the AspectRatio box. No objectFit prop on AspectRatio (#2582).
|
|
17
|
+
const galleryImage: CSSProperties = {
|
|
18
|
+
width: '100%',
|
|
19
|
+
height: '100%',
|
|
20
|
+
display: 'block',
|
|
21
|
+
};
|
|
22
|
+
// Rounds the gallery corners. No radius prop on AspectRatio (#2582);
|
|
23
|
+
// overflow clip masks the SVG scene to the rounded corners.
|
|
24
|
+
const galleryImageClip: CSSProperties = {
|
|
25
|
+
borderRadius: 'var(--radius-container)',
|
|
26
|
+
overflow: 'clip',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function NightCastleScene() {
|
|
30
|
+
return (
|
|
31
|
+
<svg
|
|
32
|
+
style={galleryImage}
|
|
33
|
+
viewBox="0 0 400 500"
|
|
34
|
+
role="img"
|
|
35
|
+
aria-label="Moonlit castle on midnight hills">
|
|
36
|
+
<title>Castle under a harvest moon</title>
|
|
37
|
+
<rect width="400" height="500" fill="var(--dracula-bg-dark)" />
|
|
38
|
+
<g fill="var(--dracula-purple)">
|
|
39
|
+
<circle cx="50" cy="60" r="2.5" />
|
|
40
|
+
<circle cx="140" cy="130" r="2" />
|
|
41
|
+
<circle cx="240" cy="50" r="2.5" />
|
|
42
|
+
<circle cx="330" cy="110" r="2" />
|
|
43
|
+
<circle cx="300" cy="200" r="2.5" />
|
|
44
|
+
</g>
|
|
45
|
+
<g fill="var(--dracula-cyan)">
|
|
46
|
+
<circle cx="95" cy="90" r="2" />
|
|
47
|
+
<circle cx="200" cy="100" r="2.5" />
|
|
48
|
+
<circle cx="360" cy="60" r="2" />
|
|
49
|
+
</g>
|
|
50
|
+
<circle cx="290" cy="120" r="52" fill="var(--dracula-yellow)" />
|
|
51
|
+
<circle
|
|
52
|
+
cx="272"
|
|
53
|
+
cy="106"
|
|
54
|
+
r="9"
|
|
55
|
+
fill="var(--dracula-orange)"
|
|
56
|
+
opacity={0.5}
|
|
57
|
+
/>
|
|
58
|
+
<g
|
|
59
|
+
fill="none"
|
|
60
|
+
stroke="var(--dracula-purple)"
|
|
61
|
+
strokeWidth={4}
|
|
62
|
+
strokeLinecap="round">
|
|
63
|
+
<path d="M70 170 q12 -12 24 0 q12 -12 24 0" />
|
|
64
|
+
<path d="M150 130 q9 -9 18 0 q9 -9 18 0" />
|
|
65
|
+
</g>
|
|
66
|
+
<path
|
|
67
|
+
d="M0 360 Q140 300 260 350 T400 335 V500 H0 Z"
|
|
68
|
+
fill="var(--dracula-selection)"
|
|
69
|
+
/>
|
|
70
|
+
<path
|
|
71
|
+
d="M0 420 Q160 365 300 410 T400 400 V500 H0 Z"
|
|
72
|
+
fill="var(--dracula-bg-light)"
|
|
73
|
+
/>
|
|
74
|
+
<g>
|
|
75
|
+
<rect
|
|
76
|
+
x="140"
|
|
77
|
+
y="270"
|
|
78
|
+
width="120"
|
|
79
|
+
height="110"
|
|
80
|
+
rx={4}
|
|
81
|
+
fill="var(--dracula-bg-lighter)"
|
|
82
|
+
/>
|
|
83
|
+
<rect
|
|
84
|
+
x="118"
|
|
85
|
+
y="235"
|
|
86
|
+
width="44"
|
|
87
|
+
height="145"
|
|
88
|
+
rx={4}
|
|
89
|
+
fill="var(--dracula-bg-lighter)"
|
|
90
|
+
/>
|
|
91
|
+
<rect
|
|
92
|
+
x="238"
|
|
93
|
+
y="235"
|
|
94
|
+
width="44"
|
|
95
|
+
height="145"
|
|
96
|
+
rx={4}
|
|
97
|
+
fill="var(--dracula-bg-lighter)"
|
|
98
|
+
/>
|
|
99
|
+
<g fill="var(--dracula-yellow)">
|
|
100
|
+
<rect x="160" y="300" width="14" height="20" rx={2} />
|
|
101
|
+
<rect x="196" y="300" width="14" height="20" rx={2} />
|
|
102
|
+
<rect x="232" y="300" width="14" height="20" rx={2} />
|
|
103
|
+
<rect x="131" y="262" width="10" height="14" rx={2} />
|
|
104
|
+
<rect x="253" y="262" width="10" height="14" rx={2} />
|
|
105
|
+
</g>
|
|
106
|
+
<path
|
|
107
|
+
d="M185 380 v-28 a15 15 0 0 1 30 0 v28 Z"
|
|
108
|
+
fill="var(--dracula-bg-dark)"
|
|
109
|
+
/>
|
|
110
|
+
</g>
|
|
111
|
+
</svg>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function HarvestMoonScene() {
|
|
116
|
+
return (
|
|
117
|
+
<svg
|
|
118
|
+
style={galleryImage}
|
|
119
|
+
viewBox="0 0 400 500"
|
|
120
|
+
role="img"
|
|
121
|
+
aria-label="Harvest moon over midnight pines">
|
|
122
|
+
<title>Harvest moon over the pines</title>
|
|
123
|
+
<rect width="400" height="500" fill="var(--dracula-bg-dark)" />
|
|
124
|
+
<g fill="var(--dracula-pink)">
|
|
125
|
+
<circle cx="60" cy="80" r="2" />
|
|
126
|
+
<circle cx="160" cy="50" r="2.5" />
|
|
127
|
+
<circle cx="320" cy="70" r="2" />
|
|
128
|
+
<circle cx="90" cy="190" r="2.5" />
|
|
129
|
+
<circle cx="250" cy="160" r="2" />
|
|
130
|
+
</g>
|
|
131
|
+
<g fill="var(--dracula-cyan)">
|
|
132
|
+
<circle cx="110" cy="120" r="2" />
|
|
133
|
+
<circle cx="220" cy="90" r="2" />
|
|
134
|
+
<circle cx="350" cy="150" r="2.5" />
|
|
135
|
+
</g>
|
|
136
|
+
<circle cx="200" cy="190" r="72" fill="var(--dracula-yellow)" />
|
|
137
|
+
<circle
|
|
138
|
+
cx="176"
|
|
139
|
+
cy="170"
|
|
140
|
+
r="12"
|
|
141
|
+
fill="var(--dracula-orange)"
|
|
142
|
+
opacity={0.5}
|
|
143
|
+
/>
|
|
144
|
+
<circle
|
|
145
|
+
cx="222"
|
|
146
|
+
cy="210"
|
|
147
|
+
r="8"
|
|
148
|
+
fill="var(--dracula-orange)"
|
|
149
|
+
opacity={0.5}
|
|
150
|
+
/>
|
|
151
|
+
<g
|
|
152
|
+
fill="none"
|
|
153
|
+
stroke="var(--dracula-purple)"
|
|
154
|
+
strokeWidth={4}
|
|
155
|
+
strokeLinecap="round">
|
|
156
|
+
<path d="M90 260 q12 -12 24 0 q12 -12 24 0" />
|
|
157
|
+
<path d="M260 250 q9 -9 18 0 q9 -9 18 0" />
|
|
158
|
+
</g>
|
|
159
|
+
<path
|
|
160
|
+
d="M0 380 Q200 320 400 370 V500 H0 Z"
|
|
161
|
+
fill="var(--dracula-selection)"
|
|
162
|
+
/>
|
|
163
|
+
<g fill="var(--dracula-bg-light)">
|
|
164
|
+
<path d="M70 500 V400 l28 -44 28 44 v100 Z" />
|
|
165
|
+
<path d="M170 500 V420 l28 -44 28 44 v80 Z" />
|
|
166
|
+
<path d="M270 500 V410 l28 -44 28 44 v90 Z" />
|
|
167
|
+
</g>
|
|
168
|
+
<g fill="var(--dracula-yellow)">
|
|
169
|
+
<rect x="81" y="442" width="8" height="12" rx={2} />
|
|
170
|
+
<rect x="181" y="458" width="8" height="12" rx={2} />
|
|
171
|
+
<rect x="281" y="450" width="8" height="12" rx={2} />
|
|
172
|
+
</g>
|
|
173
|
+
</svg>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function BatFlightScene() {
|
|
178
|
+
return (
|
|
179
|
+
<svg
|
|
180
|
+
style={galleryImage}
|
|
181
|
+
viewBox="0 0 400 500"
|
|
182
|
+
role="img"
|
|
183
|
+
aria-label="Bats crossing a violet night sky">
|
|
184
|
+
<title>Bats over violet hills</title>
|
|
185
|
+
<rect width="400" height="500" fill="var(--dracula-bg-dark)" />
|
|
186
|
+
<circle cx="200" cy="140" r="60" fill="var(--dracula-purple)" />
|
|
187
|
+
<circle
|
|
188
|
+
cx="200"
|
|
189
|
+
cy="140"
|
|
190
|
+
r="60"
|
|
191
|
+
fill="none"
|
|
192
|
+
stroke="var(--dracula-pink)"
|
|
193
|
+
strokeWidth={3}
|
|
194
|
+
opacity={0.6}
|
|
195
|
+
/>
|
|
196
|
+
<g fill="var(--dracula-cyan)">
|
|
197
|
+
<circle cx="60" cy="70" r="2" />
|
|
198
|
+
<circle cx="150" cy="40" r="2.5" />
|
|
199
|
+
<circle cx="260" cy="60" r="2" />
|
|
200
|
+
<circle cx="340" cy="110" r="2.5" />
|
|
201
|
+
<circle cx="100" cy="160" r="2" />
|
|
202
|
+
</g>
|
|
203
|
+
<g
|
|
204
|
+
fill="none"
|
|
205
|
+
stroke="var(--dracula-fg)"
|
|
206
|
+
strokeWidth={4}
|
|
207
|
+
strokeLinecap="round">
|
|
208
|
+
<path d="M110 220 q12 -12 24 0 q12 -12 24 0" />
|
|
209
|
+
<path d="M200 180 q12 -12 24 0 q12 -12 24 0" />
|
|
210
|
+
<path d="M250 260 q9 -9 18 0 q9 -9 18 0" />
|
|
211
|
+
<path d="M140 300 q9 -9 18 0 q9 -9 18 0" />
|
|
212
|
+
<path d="M290 320 q9 -9 18 0 q9 -9 18 0" />
|
|
213
|
+
</g>
|
|
214
|
+
<path
|
|
215
|
+
d="M0 370 Q140 310 270 355 T400 345 V500 H0 Z"
|
|
216
|
+
fill="var(--dracula-bg-lighter)"
|
|
217
|
+
/>
|
|
218
|
+
<path
|
|
219
|
+
d="M0 430 Q180 375 400 415 V500 H0 Z"
|
|
220
|
+
fill="var(--dracula-selection)"
|
|
221
|
+
/>
|
|
222
|
+
<g fill="var(--dracula-green)">
|
|
223
|
+
<circle cx="80" cy="440" r="6" />
|
|
224
|
+
<circle cx="200" cy="455" r="6" />
|
|
225
|
+
<circle cx="320" cy="445" r="6" />
|
|
226
|
+
</g>
|
|
227
|
+
</svg>
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const SCENES = [
|
|
232
|
+
{alt: 'Moonlit castle on midnight hills', scene: <NightCastleScene />},
|
|
233
|
+
{alt: 'Harvest moon over midnight pines', scene: <HarvestMoonScene />},
|
|
234
|
+
{alt: 'Bats crossing a violet night sky', scene: <BatFlightScene />},
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
export default function GalleryHero() {
|
|
238
|
+
return (
|
|
239
|
+
<Layout
|
|
240
|
+
content={
|
|
241
|
+
<LayoutContent padding={6}>
|
|
242
|
+
<VStack gap={10}>
|
|
243
|
+
<VStack gap={6} hAlign="center">
|
|
244
|
+
<VStack gap={3} hAlign="center">
|
|
245
|
+
<Heading
|
|
246
|
+
level={1}
|
|
247
|
+
type="display-2"
|
|
248
|
+
justify="center"
|
|
249
|
+
textWrap="balance">
|
|
250
|
+
Little haunts, everywhere you roam
|
|
251
|
+
</Heading>
|
|
252
|
+
<Text
|
|
253
|
+
type="body"
|
|
254
|
+
color="secondary"
|
|
255
|
+
justify="center"
|
|
256
|
+
textWrap="balance">
|
|
257
|
+
Sometimes all it takes is one small shadow to turn the whole
|
|
258
|
+
night around.
|
|
259
|
+
</Text>
|
|
260
|
+
</VStack>
|
|
261
|
+
<HStack gap={3} wrap="wrap" justify="center">
|
|
262
|
+
<Button
|
|
263
|
+
label="Enter the gallery"
|
|
264
|
+
variant="primary"
|
|
265
|
+
endContent={
|
|
266
|
+
<Icon icon={ArrowRight} size="sm" color="inherit" />
|
|
267
|
+
}
|
|
268
|
+
/>
|
|
269
|
+
<Button label="Read the lore" variant="secondary" />
|
|
270
|
+
</HStack>
|
|
271
|
+
</VStack>
|
|
272
|
+
<Grid columns={{minWidth: 200, repeat: 'fit'}} gap={4}>
|
|
273
|
+
{SCENES.map(item => (
|
|
274
|
+
<AspectRatio
|
|
275
|
+
key={item.alt}
|
|
276
|
+
ratio={4 / 5}
|
|
277
|
+
style={galleryImageClip}>
|
|
278
|
+
{item.scene}
|
|
279
|
+
</AspectRatio>
|
|
280
|
+
))}
|
|
281
|
+
</Grid>
|
|
282
|
+
</VStack>
|
|
283
|
+
</LayoutContent>
|
|
284
|
+
}
|
|
285
|
+
/>
|
|
286
|
+
);
|
|
287
|
+
}
|