svelte-comp 1.3.5 → 1.3.6
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/LICENSE.md +21 -21
- package/README.md +101 -101
- package/dist/App.svelte +1046 -1046
- package/dist/Container.svelte +59 -59
- package/dist/app.css +234 -234
- package/dist/app.d.ts +10 -10
- package/dist/lib/Accordion.svelte +155 -155
- package/dist/lib/Badge.svelte +44 -44
- package/dist/lib/Button.svelte +185 -185
- package/dist/lib/Calendar.svelte +384 -384
- package/dist/lib/Card.svelte +103 -103
- package/dist/lib/Carousel.svelte +293 -293
- package/dist/lib/CheckBox.svelte +210 -210
- package/dist/lib/CodeView.svelte +308 -308
- package/dist/lib/ColorPicker.svelte +159 -159
- package/dist/lib/ContextMenu.svelte +328 -328
- package/dist/lib/DatePicker.svelte +246 -246
- package/dist/lib/Dialog.svelte +233 -233
- package/dist/lib/Field.svelte +299 -299
- package/dist/lib/FilePicker.svelte +295 -295
- package/dist/lib/Form.svelte +438 -438
- package/dist/lib/Hamburger.svelte +217 -217
- package/dist/lib/InstallPWA.svelte +94 -94
- package/dist/lib/Menu.svelte +623 -623
- package/dist/lib/NoticeBase.svelte +140 -140
- package/dist/lib/PaginatedCard.svelte +73 -73
- package/dist/lib/Pagination.svelte +119 -119
- package/dist/lib/PrimaryColorSelect.svelte +111 -111
- package/dist/lib/ProgressBar.svelte +141 -141
- package/dist/lib/ProgressCircle.svelte +190 -190
- package/dist/lib/Radio.svelte +189 -189
- package/dist/lib/SearchInput.svelte +104 -104
- package/dist/lib/Select.svelte +524 -524
- package/dist/lib/Slider.svelte +253 -253
- package/dist/lib/Splitter.svelte +159 -159
- package/dist/lib/Switch.svelte +168 -168
- package/dist/lib/Table.svelte +299 -299
- package/dist/lib/Tabs.svelte +213 -213
- package/dist/lib/ThemeToggle.svelte +128 -128
- package/dist/lib/TimePicker.svelte +312 -312
- package/dist/lib/TimePickerNew.svelte +634 -634
- package/dist/lib/Toast.svelte +123 -123
- package/dist/lib/Tooltip.svelte +110 -110
- package/dist/lib/Topbar.svelte +112 -112
- package/dist/styles.css +234 -234
- package/package.json +52 -52
package/dist/App.svelte
CHANGED
|
@@ -1,1046 +1,1046 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import Accordion from "./lib/Accordion.svelte";
|
|
3
|
-
import Badge from "./lib/Badge.svelte";
|
|
4
|
-
import Button from "./lib/Button.svelte";
|
|
5
|
-
import Calendar from "./lib/Calendar.svelte";
|
|
6
|
-
import Card from "./lib/Card.svelte";
|
|
7
|
-
import Carousel from "./lib/Carousel.svelte";
|
|
8
|
-
import CheckBox from "./lib/CheckBox.svelte";
|
|
9
|
-
import CodeView from "./lib/CodeView.svelte";
|
|
10
|
-
import ColorPicker from "./lib/ColorPicker.svelte";
|
|
11
|
-
import ContextMenu from "./lib/ContextMenu.svelte";
|
|
12
|
-
import DatePicker from "./lib/DatePicker.svelte";
|
|
13
|
-
import Dialog from "./lib/Dialog.svelte";
|
|
14
|
-
import Field from "./lib/Field.svelte";
|
|
15
|
-
import FilePicker from "./lib/FilePicker.svelte";
|
|
16
|
-
import Form from "./lib/Form.svelte";
|
|
17
|
-
import InstallPWA from "./lib/InstallPWA.svelte";
|
|
18
|
-
import Menu from "./lib/Menu.svelte";
|
|
19
|
-
import NoticeBase from "./lib/NoticeBase.svelte";
|
|
20
|
-
import PaginatedCard from "./lib/PaginatedCard.svelte";
|
|
21
|
-
import Pagination from "./lib/Pagination.svelte";
|
|
22
|
-
import PrimaryColorSelect from "./lib/PrimaryColorSelect.svelte";
|
|
23
|
-
import ProgressBar from "./lib/ProgressBar.svelte";
|
|
24
|
-
import ProgressCircle from "./lib/ProgressCircle.svelte";
|
|
25
|
-
import Radio from "./lib/Radio.svelte";
|
|
26
|
-
import SearchInput from "./lib/SearchInput.svelte";
|
|
27
|
-
import Select from "./lib/Select.svelte";
|
|
28
|
-
import Slider from "./lib/Slider.svelte";
|
|
29
|
-
import Splitter from "./lib/Splitter.svelte";
|
|
30
|
-
import Switch from "./lib/Switch.svelte";
|
|
31
|
-
import Table from "./lib/Table.svelte";
|
|
32
|
-
import Tabs from "./lib/Tabs.svelte";
|
|
33
|
-
import ThemeToggle from "./lib/ThemeToggle.svelte";
|
|
34
|
-
import TimePicker from "./lib/TimePicker.svelte";
|
|
35
|
-
import Toast from "./lib/Toast.svelte";
|
|
36
|
-
import Tooltip from "./lib/Tooltip.svelte";
|
|
37
|
-
import Topbar from "./lib/Topbar.svelte";
|
|
38
|
-
import type { FieldSchema, MenuAction, MenuItem, SizeKey, ToastVariant } from "./lib/types";
|
|
39
|
-
import Container from "./Container.svelte";
|
|
40
|
-
|
|
41
|
-
const tabs = [
|
|
42
|
-
{ id: "overview", label: "Overview" },
|
|
43
|
-
{ id: "team", label: "Team" },
|
|
44
|
-
{ id: "table", label: "Data" },
|
|
45
|
-
];
|
|
46
|
-
let activeTab = $state(tabs[0].id);
|
|
47
|
-
|
|
48
|
-
let sliderValue = $state(68);
|
|
49
|
-
let autoplay = $state(true);
|
|
50
|
-
|
|
51
|
-
const planOptions = [
|
|
52
|
-
{ label: "Starter", value: "starter" },
|
|
53
|
-
{ label: "Pro", value: "pro" },
|
|
54
|
-
{ label: "Enterprise", value: "enterprise" },
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
let selectedPlan = $state(planOptions[1].value);
|
|
58
|
-
let featureName = $state("Dashboard 2.0");
|
|
59
|
-
let contactEmail = $state("team@studio.dev");
|
|
60
|
-
let dateValue = $state<string | null>(null);
|
|
61
|
-
let timeValue = $state<string | null>(null);
|
|
62
|
-
let accentColor = $state<string | null>("#7c3aed");
|
|
63
|
-
|
|
64
|
-
const accordionItems = [
|
|
65
|
-
{
|
|
66
|
-
title: "Composition",
|
|
67
|
-
content:
|
|
68
|
-
"Card, Tabs, Table and Carousel let you assemble complex screens without extra layout work.",
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
title: "Forms",
|
|
72
|
-
content:
|
|
73
|
-
"Field, Select, DatePicker, TimePicker and ColorPicker share spacing, tokens and state handling.",
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
title: "Feedback",
|
|
77
|
-
content:
|
|
78
|
-
"ProgressBar, ProgressCircle, Toast and Dialog keep users informed without noise.",
|
|
79
|
-
},
|
|
80
|
-
];
|
|
81
|
-
|
|
82
|
-
const carouselItems = [
|
|
83
|
-
{
|
|
84
|
-
title: "Smooth forms",
|
|
85
|
-
content:
|
|
86
|
-
"Clean fields, tight spacing and built-in hints help ship surveys in minutes.",
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
title: "Smart navigation",
|
|
90
|
-
content:
|
|
91
|
-
"Tabs and Accordion keep content nearby while Carousel saves horizontal space.",
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
title: "Status signals",
|
|
95
|
-
content:
|
|
96
|
-
"Toast and progress indicators deliver context quickly without blocking flows.",
|
|
97
|
-
},
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
const tableColumns = [
|
|
101
|
-
{ key: "name", label: "Feature", width: "42%" },
|
|
102
|
-
{ key: "owner", label: "Owner" },
|
|
103
|
-
{ key: "status", label: "Status" },
|
|
104
|
-
{ key: "eta", label: "ETA", align: "end" },
|
|
105
|
-
] as const;
|
|
106
|
-
|
|
107
|
-
const tableRows = [
|
|
108
|
-
{ id: 1, name: "Onboarding", owner: "Anna", status: "Ready", eta: "Today" },
|
|
109
|
-
{ id: 2, name: "Theming", owner: "Mark", status: "In progress", eta: "Fri" },
|
|
110
|
-
{ id: 3, name: "Notifications", owner: "Oleg", status: "Testing", eta: "Thu" },
|
|
111
|
-
{ id: 4, name: "Data tables", owner: "Ira", status: "In progress", eta: "Next week" },
|
|
112
|
-
{ id: 5, name: "Carousel", owner: "Anton", status: "Design", eta: "In two weeks" },
|
|
113
|
-
{ id: 6, name: "Accessibility", owner: "Sasha", status: "Review", eta: "Today" },
|
|
114
|
-
];
|
|
115
|
-
|
|
116
|
-
const pageSize = 4;
|
|
117
|
-
let tablePage = $state(1);
|
|
118
|
-
const totalPages = $derived(
|
|
119
|
-
Math.max(1, Math.ceil(tableRows.length / pageSize))
|
|
120
|
-
);
|
|
121
|
-
const pagedRows = $derived(
|
|
122
|
-
tableRows.slice((tablePage - 1) * pageSize, tablePage * pageSize)
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
$effect(() => {
|
|
126
|
-
if (tablePage > totalPages) tablePage = totalPages;
|
|
127
|
-
if (tablePage < 1) tablePage = 1;
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
const quality = [
|
|
131
|
-
{ label: "UI polish", value: 86 },
|
|
132
|
-
{ label: "Accessibility", value: 72 },
|
|
133
|
-
{ label: "Performance", value: 64 },
|
|
134
|
-
];
|
|
135
|
-
|
|
136
|
-
const team = [
|
|
137
|
-
{ name: "Anna", role: "Product", focus: "UX flows" },
|
|
138
|
-
{ name: "Mark", role: "Frontend", focus: "Components" },
|
|
139
|
-
{ name: "Oleg", role: "QA", focus: "Automation" },
|
|
140
|
-
];
|
|
141
|
-
|
|
142
|
-
const navItems = [
|
|
143
|
-
{ id: "overview", label: "Overview" },
|
|
144
|
-
{ id: "inputs", label: "Inputs" },
|
|
145
|
-
{ id: "layout", label: "Layout" },
|
|
146
|
-
{ id: "data", label: "Data" },
|
|
147
|
-
];
|
|
148
|
-
let activeNav = $state(navItems[0].id);
|
|
149
|
-
|
|
150
|
-
let searchQuery = $state("");
|
|
151
|
-
let calendarValue = $state<string | null>(null);
|
|
152
|
-
let fileList = $state<FileList | null>(null);
|
|
153
|
-
let dialogOpen = $state(false);
|
|
154
|
-
let radioGroup = $state("daily");
|
|
155
|
-
let newsletterChecked = $state(false);
|
|
156
|
-
let mixedChecked = $state(false);
|
|
157
|
-
let mixedState = $state(true);
|
|
158
|
-
let menuSelection = $state("Pick an action from the menu bar");
|
|
159
|
-
let menuSize = $state<SizeKey>("sm");
|
|
160
|
-
let standalonePage = $state(1);
|
|
161
|
-
const standaloneTotal = 5;
|
|
162
|
-
let codeEditable = $state(false);
|
|
163
|
-
let codeSample = $state(
|
|
164
|
-
"const tokens = ['spacing', 'radius', 'colors'];\n\nexport function tokensReady() {\n return tokens.length > 0;\n}\n"
|
|
165
|
-
);
|
|
166
|
-
let contextMenuStatus = $state("Right-click the panel to open the menu");
|
|
167
|
-
let contextMenuRef = $state<{
|
|
168
|
-
openAt: (event: MouseEvent) => void;
|
|
169
|
-
close: () => void;
|
|
170
|
-
} | null>(null);
|
|
171
|
-
|
|
172
|
-
const menuData: MenuItem[] = [
|
|
173
|
-
{
|
|
174
|
-
name: "File",
|
|
175
|
-
actions: [
|
|
176
|
-
{ id: "new", label: "New", shortcut: "Ctrl+N" },
|
|
177
|
-
{ id: "open", label: "Open", shortcut: "Ctrl+O" },
|
|
178
|
-
{ type: "separator" },
|
|
179
|
-
{ id: "export", label: "Export", shortcut: "Ctrl+E" },
|
|
180
|
-
],
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
name: "View",
|
|
184
|
-
actions: [
|
|
185
|
-
{ id: "xs", label: "XS" },
|
|
186
|
-
{ id: "sm", label: "SM" },
|
|
187
|
-
{ id: "md", label: "MD" },
|
|
188
|
-
{ id: "lg", label: "LG" },
|
|
189
|
-
{ id: "xl", label: "XL" },
|
|
190
|
-
],
|
|
191
|
-
},
|
|
192
|
-
];
|
|
193
|
-
|
|
194
|
-
const miniFormSchema: FieldSchema[] = [
|
|
195
|
-
{ name: "project", type: "text", label: "Project", required: true },
|
|
196
|
-
{ name: "owner", type: "email", label: "Owner email", required: true },
|
|
197
|
-
{
|
|
198
|
-
name: "priority",
|
|
199
|
-
type: "select",
|
|
200
|
-
label: "Priority",
|
|
201
|
-
options: [
|
|
202
|
-
{ label: "Low", value: "low" },
|
|
203
|
-
{ label: "Medium", value: "medium" },
|
|
204
|
-
{ label: "High", value: "high" },
|
|
205
|
-
],
|
|
206
|
-
},
|
|
207
|
-
{ name: "subscribe", type: "checkbox", label: "Send updates" },
|
|
208
|
-
];
|
|
209
|
-
let formResult = $state("Not submitted yet");
|
|
210
|
-
|
|
211
|
-
type ToastItem = { id: number; title?: string; message: string; variant: ToastVariant };
|
|
212
|
-
let toasts = $state<ToastItem[]>([]);
|
|
213
|
-
let toastId = 0;
|
|
214
|
-
|
|
215
|
-
function pushToast(variant: ToastVariant) {
|
|
216
|
-
const messageMap: Record<ToastVariant, string> = {
|
|
217
|
-
success: "Changes saved and ready to roll out.",
|
|
218
|
-
info: "Components share tokens, typography, and behavior.",
|
|
219
|
-
warning: "Double-check disabled, focus, and hover states.",
|
|
220
|
-
danger: "Tests caught a blocking issue. Investigate.",
|
|
221
|
-
};
|
|
222
|
-
const titleMap: Record<ToastVariant, string> = {
|
|
223
|
-
success: "Success",
|
|
224
|
-
info: "Heads up",
|
|
225
|
-
warning: "Warning",
|
|
226
|
-
danger: "Error",
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
const id = ++toastId;
|
|
230
|
-
toasts = [
|
|
231
|
-
...toasts,
|
|
232
|
-
{ id, variant, title: titleMap[variant], message: messageMap[variant] },
|
|
233
|
-
];
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function removeToast(id: number) {
|
|
237
|
-
toasts = toasts.filter((t) => t.id !== id);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function handleMenuSelect(menu: string, action: MenuAction) {
|
|
241
|
-
const label =
|
|
242
|
-
typeof action === "string"
|
|
243
|
-
? action
|
|
244
|
-
: action.label || action.id || "Action";
|
|
245
|
-
const id = typeof action === "string" ? action : action.id;
|
|
246
|
-
if (id && ["xs", "sm", "md", "lg", "xl"].includes(id)) {
|
|
247
|
-
menuSize = id as SizeKey;
|
|
248
|
-
}
|
|
249
|
-
menuSelection = `${menu}: ${label}`;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function handleMiniSubmit(values: Record<string, unknown>) {
|
|
253
|
-
formResult = JSON.stringify(values, null, 2);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function handleContextAction(label: string, variant: ToastVariant) {
|
|
257
|
-
contextMenuStatus = `Last action: ${label}`;
|
|
258
|
-
pushToast(variant);
|
|
259
|
-
}
|
|
260
|
-
</script>
|
|
261
|
-
|
|
262
|
-
<Topbar
|
|
263
|
-
title="svelte-comp"
|
|
264
|
-
showHamburger={true}
|
|
265
|
-
menuItems={navItems}
|
|
266
|
-
onMenuSelect={(id) => (activeNav = id)}
|
|
267
|
-
/>
|
|
268
|
-
|
|
269
|
-
<Container>
|
|
270
|
-
<div class="relative mx-auto max-w-6xl space-y-8 px-6 pb-10 pt-24">
|
|
271
|
-
<section
|
|
272
|
-
class="relative rounded-[28px] border border-[var(--border-color-default)] bg-gradient-to-br from-[var(--color-bg-surface)] via-white/70 to-[var(--color-bg-muted)] shadow-[0_20px_60px_-25px_var(--shadow-color)] dark:from-[var(--color-bg-surface)] dark:via-slate-900/70 dark:to-slate-900/50"
|
|
273
|
-
>
|
|
274
|
-
<div
|
|
275
|
-
class="absolute inset-0 bg-[radial-gradient(circle_at_20%_20%,rgba(99,102,241,0.18),transparent_35%),radial-gradient(circle_at_80%_0%,rgba(16,185,129,0.14),transparent_25%)]"
|
|
276
|
-
></div>
|
|
277
|
-
|
|
278
|
-
<div class="relative grid gap-8 p-8 md:p-10 lg:grid-cols-[1.1fr_0.9fr]">
|
|
279
|
-
<div class="space-y-4">
|
|
280
|
-
<p class="text-xs uppercase tracking-[0.25em] text-[var(--color-text-muted)]">
|
|
281
|
-
svelte-comp
|
|
282
|
-
</p>
|
|
283
|
-
<h1 class="text-3xl font-bold leading-tight md:text-4xl">
|
|
284
|
-
Component showcase
|
|
285
|
-
</h1>
|
|
286
|
-
<p class="text-[var(--color-text-muted)] md:w-3/4">
|
|
287
|
-
Toggle theme, tweak the primary color, and try the main lib components in a cohesive layout.
|
|
288
|
-
</p>
|
|
289
|
-
|
|
290
|
-
<div class="flex flex-wrap gap-3">
|
|
291
|
-
<Button variant="primary" onClick={() => pushToast("info")} sz="lg">
|
|
292
|
-
Launch interactive
|
|
293
|
-
</Button>
|
|
294
|
-
<Button variant="ghost" onClick={() => pushToast("warning")} sz="lg">
|
|
295
|
-
Remind to review
|
|
296
|
-
</Button>
|
|
297
|
-
</div>
|
|
298
|
-
|
|
299
|
-
<div class="flex flex-wrap gap-3 text-sm text-[var(--color-text-muted)]">
|
|
300
|
-
<span
|
|
301
|
-
class="inline-flex items-center gap-2 rounded-full border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] px-3 py-2"
|
|
302
|
-
>
|
|
303
|
-
<span class="h-2 w-2 animate-pulse rounded-full bg-[var(--color-bg-primary)]"></span>
|
|
304
|
-
Live preview is on
|
|
305
|
-
</span>
|
|
306
|
-
<span
|
|
307
|
-
class="inline-flex items-center gap-2 rounded-full border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] px-3 py-2"
|
|
308
|
-
>
|
|
309
|
-
<span class="h-2 w-2 rounded-full bg-[var(--color-bg-secondary)]"></span>
|
|
310
|
-
{tabs.length} sections below
|
|
311
|
-
</span>
|
|
312
|
-
</div>
|
|
313
|
-
</div>
|
|
314
|
-
|
|
315
|
-
<div
|
|
316
|
-
class="space-y-4 rounded-2xl border border-[var(--border-color-default)] bg-white/70 p-5 shadow-lg dark:bg-slate-900/60"
|
|
317
|
-
>
|
|
318
|
-
<div class="flex items-start justify-between gap-3">
|
|
319
|
-
<div>
|
|
320
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
321
|
-
Theme
|
|
322
|
-
</p>
|
|
323
|
-
<p class="text-lg font-semibold">Mode and accent</p>
|
|
324
|
-
</div>
|
|
325
|
-
|
|
326
|
-
<Tooltip text="Toggles document-level theme" position="bottom">
|
|
327
|
-
<ThemeToggle class="relative shadow-sm" sz="sm" />
|
|
328
|
-
</Tooltip>
|
|
329
|
-
</div>
|
|
330
|
-
|
|
331
|
-
<PrimaryColorSelect class="w-full" />
|
|
332
|
-
|
|
333
|
-
<div
|
|
334
|
-
class="flex items-center justify-between rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-muted)]/70 px-4 py-3"
|
|
335
|
-
>
|
|
336
|
-
<div>
|
|
337
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
338
|
-
Autoplay
|
|
339
|
-
</p>
|
|
340
|
-
<p class="text-sm font-medium">Carousel</p>
|
|
341
|
-
</div>
|
|
342
|
-
<Switch
|
|
343
|
-
checked={autoplay}
|
|
344
|
-
onChange={(v) => (autoplay = v)}
|
|
345
|
-
sz="sm"
|
|
346
|
-
rightLabel={autoplay ? "On" : "Off"}
|
|
347
|
-
/>
|
|
348
|
-
</div>
|
|
349
|
-
|
|
350
|
-
<div class="grid gap-3 md:grid-cols-2">
|
|
351
|
-
<ProgressCircle value={sliderValue} label="Readiness" />
|
|
352
|
-
<ProgressBar value={sliderValue} label="Sprint focus" />
|
|
353
|
-
</div>
|
|
354
|
-
</div>
|
|
355
|
-
</div>
|
|
356
|
-
</section>
|
|
357
|
-
|
|
358
|
-
{#snippet controlsHeader()}
|
|
359
|
-
<div class="flex items-center justify-between gap-2">
|
|
360
|
-
<div>
|
|
361
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
362
|
-
Actions
|
|
363
|
-
</p>
|
|
364
|
-
<h2 class="text-lg font-semibold leading-tight">Quick triggers</h2>
|
|
365
|
-
</div>
|
|
366
|
-
<Tooltip text="Buttons use the full variant set" position="left">
|
|
367
|
-
<span
|
|
368
|
-
class="inline-flex h-9 w-9 items-center justify-center rounded-full bg-[var(--color-bg-muted)] text-sm font-semibold text-[var(--color-text-default)]"
|
|
369
|
-
>
|
|
370
|
-
?
|
|
371
|
-
</span>
|
|
372
|
-
</Tooltip>
|
|
373
|
-
</div>
|
|
374
|
-
{/snippet}
|
|
375
|
-
|
|
376
|
-
{#snippet formHeader()}
|
|
377
|
-
<div class="flex items-center justify-between">
|
|
378
|
-
<div>
|
|
379
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
380
|
-
Form
|
|
381
|
-
</p>
|
|
382
|
-
<h2 class="text-lg font-semibold leading-tight">Mini brief</h2>
|
|
383
|
-
</div>
|
|
384
|
-
<Tooltip text="Field, Select, DatePicker, TimePicker and ColorPicker" position="left">
|
|
385
|
-
<span
|
|
386
|
-
class="inline-flex h-8 w-8 items-center justify-center rounded-full bg-[var(--color-bg-muted)] text-sm font-semibold text-[var(--color-text-default)]"
|
|
387
|
-
>
|
|
388
|
-
i
|
|
389
|
-
</span>
|
|
390
|
-
</Tooltip>
|
|
391
|
-
</div>
|
|
392
|
-
{/snippet}
|
|
393
|
-
|
|
394
|
-
<div class="grid gap-6 lg:grid-cols-2">
|
|
395
|
-
<Card header={controlsHeader}>
|
|
396
|
-
<div class="space-y-4">
|
|
397
|
-
<div class="flex flex-wrap gap-2">
|
|
398
|
-
<Button variant="primary" onClick={() => pushToast("success")}>Primary</Button>
|
|
399
|
-
<Button variant="secondary">Secondary</Button>
|
|
400
|
-
<Button variant="ghost">Ghost</Button>
|
|
401
|
-
<Button variant="pill">Pill</Button>
|
|
402
|
-
<Button variant="danger" onClick={() => pushToast("danger")}>Danger</Button>
|
|
403
|
-
</div>
|
|
404
|
-
|
|
405
|
-
<div
|
|
406
|
-
class="flex items-center justify-between gap-3 rounded-xl border border-[var(--border-color-default)] px-4 py-3"
|
|
407
|
-
>
|
|
408
|
-
<div class="space-y-1">
|
|
409
|
-
<p class="text-sm font-medium">Live mode</p>
|
|
410
|
-
<p class="text-xs text-[var(--color-text-muted)]">
|
|
411
|
-
Keep autoplay and progress linked across the page
|
|
412
|
-
</p>
|
|
413
|
-
</div>
|
|
414
|
-
<Switch checked={autoplay} onChange={(v) => (autoplay = v)} sz="sm" />
|
|
415
|
-
</div>
|
|
416
|
-
|
|
417
|
-
<div class="space-y-2">
|
|
418
|
-
<div class="flex items-center justify-between text-sm">
|
|
419
|
-
<span class="text-[var(--color-text-muted)]">Drag to refresh progress</span>
|
|
420
|
-
<span class="font-mono text-[var(--color-text-default)]">{sliderValue}%</span>
|
|
421
|
-
</div>
|
|
422
|
-
<Slider
|
|
423
|
-
value={sliderValue}
|
|
424
|
-
min={0}
|
|
425
|
-
max={100}
|
|
426
|
-
onInput={(v) => (sliderValue = v)}
|
|
427
|
-
showValue={false}
|
|
428
|
-
/>
|
|
429
|
-
</div>
|
|
430
|
-
|
|
431
|
-
<div class="grid gap-3 md:grid-cols-2">
|
|
432
|
-
<ProgressBar value={sliderValue} label="Iteration" />
|
|
433
|
-
<ProgressCircle value={sliderValue} label="Readiness" />
|
|
434
|
-
</div>
|
|
435
|
-
|
|
436
|
-
<div class="flex flex-wrap gap-2">
|
|
437
|
-
<Button variant="success" onClick={() => pushToast("success")} sz="sm">
|
|
438
|
-
Success toast
|
|
439
|
-
</Button>
|
|
440
|
-
<Button variant="warning" onClick={() => pushToast("warning")} sz="sm">
|
|
441
|
-
Warning toast
|
|
442
|
-
</Button>
|
|
443
|
-
<Button variant="info" onClick={() => pushToast("info")} sz="sm">
|
|
444
|
-
Info toast
|
|
445
|
-
</Button>
|
|
446
|
-
</div>
|
|
447
|
-
</div>
|
|
448
|
-
</Card>
|
|
449
|
-
|
|
450
|
-
<Card header={formHeader}>
|
|
451
|
-
<div class="space-y-4">
|
|
452
|
-
<div class="grid gap-3 md:grid-cols-2">
|
|
453
|
-
<Field
|
|
454
|
-
label="Name"
|
|
455
|
-
value={featureName}
|
|
456
|
-
onChange={(v) => (featureName = String(v))}
|
|
457
|
-
/>
|
|
458
|
-
<Field
|
|
459
|
-
label="Contact email"
|
|
460
|
-
type="email"
|
|
461
|
-
value={contactEmail}
|
|
462
|
-
onChange={(v) => (contactEmail = String(v))}
|
|
463
|
-
/>
|
|
464
|
-
</div>
|
|
465
|
-
|
|
466
|
-
<Select
|
|
467
|
-
label="Plan"
|
|
468
|
-
options={planOptions}
|
|
469
|
-
value={selectedPlan}
|
|
470
|
-
placeholder="Choose a plan"
|
|
471
|
-
onChange={(v) => (selectedPlan = v)}
|
|
472
|
-
/>
|
|
473
|
-
|
|
474
|
-
<div class="grid gap-3 md:grid-cols-3">
|
|
475
|
-
<DatePicker
|
|
476
|
-
label="Launch date"
|
|
477
|
-
value={dateValue}
|
|
478
|
-
onChange={(v) => (dateValue = v)}
|
|
479
|
-
/>
|
|
480
|
-
<TimePicker
|
|
481
|
-
label="Release time"
|
|
482
|
-
value={timeValue}
|
|
483
|
-
onChange={(v) => (timeValue = v)}
|
|
484
|
-
/>
|
|
485
|
-
<ColorPicker
|
|
486
|
-
label="Accent"
|
|
487
|
-
value={accentColor}
|
|
488
|
-
onChange={(v) => (accentColor = v)}
|
|
489
|
-
/>
|
|
490
|
-
</div>
|
|
491
|
-
|
|
492
|
-
<div class="flex justify-end gap-3">
|
|
493
|
-
<Button
|
|
494
|
-
variant="ghost"
|
|
495
|
-
onClick={() => {
|
|
496
|
-
featureName = "Dashboard 2.0";
|
|
497
|
-
selectedPlan = planOptions[1].value;
|
|
498
|
-
contactEmail = "team@studio.dev";
|
|
499
|
-
dateValue = null;
|
|
500
|
-
timeValue = null;
|
|
501
|
-
accentColor = "#7c3aed";
|
|
502
|
-
}}
|
|
503
|
-
>
|
|
504
|
-
Reset
|
|
505
|
-
</Button>
|
|
506
|
-
<Button variant="primary" onClick={() => pushToast("success")}>
|
|
507
|
-
Save
|
|
508
|
-
</Button>
|
|
509
|
-
</div>
|
|
510
|
-
</div>
|
|
511
|
-
</Card>
|
|
512
|
-
</div>
|
|
513
|
-
|
|
514
|
-
{#snippet dataHeader()}
|
|
515
|
-
<div class="flex items-center justify-between gap-3">
|
|
516
|
-
<div>
|
|
517
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
518
|
-
Data
|
|
519
|
-
</p>
|
|
520
|
-
<h2 class="text-lg font-semibold leading-tight">Sprint snapshot</h2>
|
|
521
|
-
</div>
|
|
522
|
-
<Button variant="secondary" sz="sm" onClick={() => pushToast("info")}>
|
|
523
|
-
Refresh
|
|
524
|
-
</Button>
|
|
525
|
-
</div>
|
|
526
|
-
{/snippet}
|
|
527
|
-
|
|
528
|
-
{#snippet accordionHeader()}
|
|
529
|
-
<div class="flex items-center justify-between gap-3">
|
|
530
|
-
<div>
|
|
531
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
532
|
-
Details
|
|
533
|
-
</p>
|
|
534
|
-
<h3 class="text-lg font-semibold leading-tight">Sections</h3>
|
|
535
|
-
</div>
|
|
536
|
-
</div>
|
|
537
|
-
{/snippet}
|
|
538
|
-
|
|
539
|
-
{#snippet carouselHeader()}
|
|
540
|
-
<div class="flex items-center justify-between gap-3">
|
|
541
|
-
<div>
|
|
542
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
543
|
-
Carousel
|
|
544
|
-
</p>
|
|
545
|
-
<h3 class="text-lg font-semibold leading-tight">Stories</h3>
|
|
546
|
-
</div>
|
|
547
|
-
<span class="text-xs text-[var(--color-text-muted)]">
|
|
548
|
-
Autoplay {autoplay ? "on" : "off"}
|
|
549
|
-
</span>
|
|
550
|
-
</div>
|
|
551
|
-
{/snippet}
|
|
552
|
-
|
|
553
|
-
<div class="grid gap-6 lg:grid-cols-[1.2fr_0.8fr]">
|
|
554
|
-
<Card header={dataHeader} class="h-full">
|
|
555
|
-
<Tabs
|
|
556
|
-
tabs={tabs}
|
|
557
|
-
activeTab={activeTab}
|
|
558
|
-
onChange={(id) => (activeTab = id)}
|
|
559
|
-
variant="underline"
|
|
560
|
-
fitted={true}
|
|
561
|
-
>
|
|
562
|
-
{#if activeTab === "overview"}
|
|
563
|
-
<div class="grid gap-4 md:grid-cols-3">
|
|
564
|
-
<div
|
|
565
|
-
class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4"
|
|
566
|
-
>
|
|
567
|
-
<p class="text-xs uppercase tracking-[0.1em] text-[var(--color-text-muted)]">
|
|
568
|
-
Readiness
|
|
569
|
-
</p>
|
|
570
|
-
<p class="text-2xl font-bold">{sliderValue}%</p>
|
|
571
|
-
<p class="text-sm text-[var(--color-text-muted)]">
|
|
572
|
-
Synced with the slider above
|
|
573
|
-
</p>
|
|
574
|
-
</div>
|
|
575
|
-
|
|
576
|
-
<div
|
|
577
|
-
class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4"
|
|
578
|
-
>
|
|
579
|
-
<p class="text-xs uppercase tracking-[0.1em] text-[var(--color-text-muted)]">
|
|
580
|
-
Plan
|
|
581
|
-
</p>
|
|
582
|
-
<p class="text-lg font-semibold">{selectedPlan}</p>
|
|
583
|
-
<p class="text-sm text-[var(--color-text-muted)]">
|
|
584
|
-
Contact: {contactEmail}
|
|
585
|
-
</p>
|
|
586
|
-
</div>
|
|
587
|
-
|
|
588
|
-
<div
|
|
589
|
-
class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4"
|
|
590
|
-
>
|
|
591
|
-
<p class="text-xs uppercase tracking-[0.1em] text-[var(--color-text-muted)]">
|
|
592
|
-
Release window
|
|
593
|
-
</p>
|
|
594
|
-
<p class="text-lg font-semibold">
|
|
595
|
-
{dateValue ?? "Not selected yet"}
|
|
596
|
-
</p>
|
|
597
|
-
<p class="text-sm text-[var(--color-text-muted)]">
|
|
598
|
-
{timeValue ?? "Time is being planned"}
|
|
599
|
-
</p>
|
|
600
|
-
</div>
|
|
601
|
-
</div>
|
|
602
|
-
|
|
603
|
-
<div class="mt-4 grid gap-3 md:grid-cols-3">
|
|
604
|
-
{#each quality as metric (metric.label)}
|
|
605
|
-
<ProgressBar value={metric.value} label={metric.label} sz="sm" />
|
|
606
|
-
{/each}
|
|
607
|
-
</div>
|
|
608
|
-
{:else if activeTab === "team"}
|
|
609
|
-
<div class="space-y-3">
|
|
610
|
-
{#each team as person (person.name)}
|
|
611
|
-
<div
|
|
612
|
-
class="flex items-center justify-between rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] px-4 py-3"
|
|
613
|
-
>
|
|
614
|
-
<div>
|
|
615
|
-
<p class="font-semibold">{person.name}</p>
|
|
616
|
-
<p class="text-sm text-[var(--color-text-muted)]">{person.role}</p>
|
|
617
|
-
</div>
|
|
618
|
-
<span
|
|
619
|
-
class="rounded-full bg-[var(--color-bg-muted)] px-3 py-1 text-xs text-[var(--color-text-default)]"
|
|
620
|
-
>
|
|
621
|
-
{person.focus}
|
|
622
|
-
</span>
|
|
623
|
-
</div>
|
|
624
|
-
{/each}
|
|
625
|
-
</div>
|
|
626
|
-
{:else}
|
|
627
|
-
<Table
|
|
628
|
-
columns={tableColumns}
|
|
629
|
-
rows={pagedRows}
|
|
630
|
-
variant="zebra"
|
|
631
|
-
pagination={{ currentPage: tablePage, totalPages, onPageChange: (p) => (tablePage = p) }}
|
|
632
|
-
/>
|
|
633
|
-
{/if}
|
|
634
|
-
</Tabs>
|
|
635
|
-
</Card>
|
|
636
|
-
|
|
637
|
-
<div class="grid gap-6">
|
|
638
|
-
<Card header={accordionHeader}>
|
|
639
|
-
<Accordion items={accordionItems} multiple={true} defaultOpen={[0]} />
|
|
640
|
-
</Card>
|
|
641
|
-
|
|
642
|
-
<Card header={carouselHeader}>
|
|
643
|
-
<Carousel
|
|
644
|
-
items={carouselItems}
|
|
645
|
-
autoplay={autoplay}
|
|
646
|
-
interval={4200}
|
|
647
|
-
showDots={true}
|
|
648
|
-
showArrows={true}
|
|
649
|
-
sz="sm"
|
|
650
|
-
/>
|
|
651
|
-
</Card>
|
|
652
|
-
</div>
|
|
653
|
-
</div>
|
|
654
|
-
|
|
655
|
-
{#snippet statusHeader()}
|
|
656
|
-
<div class="flex items-center justify-between gap-2">
|
|
657
|
-
<div>
|
|
658
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
659
|
-
Status
|
|
660
|
-
</p>
|
|
661
|
-
<h2 class="text-lg font-semibold leading-tight">Search and signals</h2>
|
|
662
|
-
</div>
|
|
663
|
-
</div>
|
|
664
|
-
{/snippet}
|
|
665
|
-
|
|
666
|
-
{#snippet optionsHeader()}
|
|
667
|
-
<div class="flex items-center justify-between gap-2">
|
|
668
|
-
<div>
|
|
669
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
670
|
-
Options
|
|
671
|
-
</p>
|
|
672
|
-
<h2 class="text-lg font-semibold leading-tight">Toggles and calendar</h2>
|
|
673
|
-
</div>
|
|
674
|
-
</div>
|
|
675
|
-
{/snippet}
|
|
676
|
-
|
|
677
|
-
<div class="grid gap-6 lg:grid-cols-2">
|
|
678
|
-
<Card header={statusHeader}>
|
|
679
|
-
<div class="space-y-4">
|
|
680
|
-
<SearchInput
|
|
681
|
-
label="Search components"
|
|
682
|
-
placeholder="Filter by name"
|
|
683
|
-
bind:value={searchQuery}
|
|
684
|
-
/>
|
|
685
|
-
|
|
686
|
-
<div class="flex flex-wrap gap-2">
|
|
687
|
-
<Badge message="Live" variant="success" showIcon />
|
|
688
|
-
<Badge message="Needs review" variant="warning" showIcon />
|
|
689
|
-
<Badge message="Queued" variant="info" />
|
|
690
|
-
</div>
|
|
691
|
-
|
|
692
|
-
{#snippet noticeEnd()}
|
|
693
|
-
<Button variant="ghost" sz="xs">Undo</Button>
|
|
694
|
-
{/snippet}
|
|
695
|
-
|
|
696
|
-
<NoticeBase
|
|
697
|
-
title="Release note"
|
|
698
|
-
message="New components landed in the demo."
|
|
699
|
-
variant="info"
|
|
700
|
-
size="md"
|
|
701
|
-
end={noticeEnd}
|
|
702
|
-
/>
|
|
703
|
-
</div>
|
|
704
|
-
</Card>
|
|
705
|
-
|
|
706
|
-
<Card header={optionsHeader}>
|
|
707
|
-
<div class="space-y-4">
|
|
708
|
-
<div class="space-y-2">
|
|
709
|
-
<Radio
|
|
710
|
-
label="Daily updates"
|
|
711
|
-
value="daily"
|
|
712
|
-
bind:group={radioGroup}
|
|
713
|
-
/>
|
|
714
|
-
<Radio
|
|
715
|
-
label="Weekly updates"
|
|
716
|
-
value="weekly"
|
|
717
|
-
bind:group={radioGroup}
|
|
718
|
-
/>
|
|
719
|
-
<Radio
|
|
720
|
-
label="Monthly updates"
|
|
721
|
-
value="monthly"
|
|
722
|
-
bind:group={radioGroup}
|
|
723
|
-
/>
|
|
724
|
-
</div>
|
|
725
|
-
|
|
726
|
-
<div class="flex flex-wrap gap-3">
|
|
727
|
-
<CheckBox
|
|
728
|
-
label="Send digest emails"
|
|
729
|
-
bind:checked={newsletterChecked}
|
|
730
|
-
/>
|
|
731
|
-
<CheckBox
|
|
732
|
-
label="Mixed state"
|
|
733
|
-
indeterminate={mixedState}
|
|
734
|
-
checked={mixedChecked}
|
|
735
|
-
onChange={(v) => {
|
|
736
|
-
mixedChecked = v;
|
|
737
|
-
mixedState = false;
|
|
738
|
-
}}
|
|
739
|
-
/>
|
|
740
|
-
</div>
|
|
741
|
-
|
|
742
|
-
<div class="grid gap-3 md:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]">
|
|
743
|
-
<div class="min-w-0">
|
|
744
|
-
<Calendar
|
|
745
|
-
value={calendarValue}
|
|
746
|
-
onChange={(v) => (calendarValue = v)}
|
|
747
|
-
showOutsideDays={true}
|
|
748
|
-
class="w-full"
|
|
749
|
-
/>
|
|
750
|
-
</div>
|
|
751
|
-
<div class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4">
|
|
752
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
753
|
-
Selected date
|
|
754
|
-
</p>
|
|
755
|
-
<p class="text-lg font-semibold">
|
|
756
|
-
{calendarValue ?? "No date yet"}
|
|
757
|
-
</p>
|
|
758
|
-
<p class="text-sm text-[var(--color-text-muted)] mt-2">
|
|
759
|
-
Plan: {radioGroup}
|
|
760
|
-
</p>
|
|
761
|
-
</div>
|
|
762
|
-
</div>
|
|
763
|
-
</div>
|
|
764
|
-
</Card>
|
|
765
|
-
</div>
|
|
766
|
-
|
|
767
|
-
{#snippet filesHeader()}
|
|
768
|
-
<div class="flex items-center justify-between gap-2">
|
|
769
|
-
<div>
|
|
770
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
771
|
-
Files
|
|
772
|
-
</p>
|
|
773
|
-
<h2 class="text-lg font-semibold leading-tight">Uploads and dialogs</h2>
|
|
774
|
-
</div>
|
|
775
|
-
<InstallPWA inline={true} alwaysShow={true} />
|
|
776
|
-
</div>
|
|
777
|
-
{/snippet}
|
|
778
|
-
|
|
779
|
-
{#snippet formGeneratorHeader()}
|
|
780
|
-
<div class="flex items-center justify-between gap-2">
|
|
781
|
-
<div>
|
|
782
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
783
|
-
Form
|
|
784
|
-
</p>
|
|
785
|
-
<h2 class="text-lg font-semibold leading-tight">Schema-driven form</h2>
|
|
786
|
-
</div>
|
|
787
|
-
</div>
|
|
788
|
-
{/snippet}
|
|
789
|
-
|
|
790
|
-
<div class="grid gap-6 lg:grid-cols-2">
|
|
791
|
-
<Card header={filesHeader}>
|
|
792
|
-
<div class="space-y-4">
|
|
793
|
-
<FilePicker
|
|
794
|
-
value={fileList}
|
|
795
|
-
onFilesSelected={(files) => (fileList = files)}
|
|
796
|
-
accept="image/*,.pdf"
|
|
797
|
-
/>
|
|
798
|
-
|
|
799
|
-
<div class="flex items-center justify-between rounded-xl border border-[var(--border-color-default)] px-4 py-3">
|
|
800
|
-
<div>
|
|
801
|
-
<p class="text-sm font-medium">Confirm release</p>
|
|
802
|
-
<p class="text-xs text-[var(--color-text-muted)]">
|
|
803
|
-
Last file: {fileList?.[0]?.name ?? "none"}
|
|
804
|
-
</p>
|
|
805
|
-
</div>
|
|
806
|
-
<Button variant="primary" onClick={() => (dialogOpen = true)} sz="sm">
|
|
807
|
-
Open dialog
|
|
808
|
-
</Button>
|
|
809
|
-
</div>
|
|
810
|
-
</div>
|
|
811
|
-
</Card>
|
|
812
|
-
|
|
813
|
-
<Card header={formGeneratorHeader}>
|
|
814
|
-
<div class="space-y-4">
|
|
815
|
-
<Form
|
|
816
|
-
schema={miniFormSchema}
|
|
817
|
-
onSubmit={handleMiniSubmit}
|
|
818
|
-
validateOn="submit"
|
|
819
|
-
/>
|
|
820
|
-
<div class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-3">
|
|
821
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
822
|
-
Last submit
|
|
823
|
-
</p>
|
|
824
|
-
<pre class="text-xs whitespace-pre-wrap text-[var(--color-text-default)]">
|
|
825
|
-
{formResult}
|
|
826
|
-
</pre>
|
|
827
|
-
</div>
|
|
828
|
-
</div>
|
|
829
|
-
</Card>
|
|
830
|
-
</div>
|
|
831
|
-
|
|
832
|
-
{#snippet menuHeader()}
|
|
833
|
-
<div class="flex items-center justify-between gap-2">
|
|
834
|
-
<div>
|
|
835
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
836
|
-
Menu
|
|
837
|
-
</p>
|
|
838
|
-
<h2 class="text-lg font-semibold leading-tight">Navigation controls</h2>
|
|
839
|
-
</div>
|
|
840
|
-
</div>
|
|
841
|
-
{/snippet}
|
|
842
|
-
|
|
843
|
-
{#snippet layoutHeader()}
|
|
844
|
-
<div class="flex items-center justify-between gap-2">
|
|
845
|
-
<div>
|
|
846
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
847
|
-
Layout
|
|
848
|
-
</p>
|
|
849
|
-
<h2 class="text-lg font-semibold leading-tight">Splitter + context menu</h2>
|
|
850
|
-
</div>
|
|
851
|
-
</div>
|
|
852
|
-
{/snippet}
|
|
853
|
-
|
|
854
|
-
{#snippet firstPane()}
|
|
855
|
-
<div class="h-full grid place-items-center text-sm font-medium">
|
|
856
|
-
First panel
|
|
857
|
-
</div>
|
|
858
|
-
{/snippet}
|
|
859
|
-
|
|
860
|
-
{#snippet secondPane()}
|
|
861
|
-
<div class="h-full grid place-items-center text-sm font-medium">
|
|
862
|
-
Second panel
|
|
863
|
-
</div>
|
|
864
|
-
{/snippet}
|
|
865
|
-
|
|
866
|
-
<div class="grid gap-6 lg:grid-cols-2">
|
|
867
|
-
<Card header={menuHeader}>
|
|
868
|
-
<div class="space-y-4">
|
|
869
|
-
<Menu menus={menuData} sz={menuSize} onSelect={handleMenuSelect} />
|
|
870
|
-
|
|
871
|
-
<div class="text-sm text-[var(--color-text-muted)]">
|
|
872
|
-
{menuSelection}
|
|
873
|
-
</div>
|
|
874
|
-
|
|
875
|
-
<div class="rounded-xl border border-[var(--border-color-default)] p-4">
|
|
876
|
-
<Pagination
|
|
877
|
-
currentPage={standalonePage}
|
|
878
|
-
totalPages={standaloneTotal}
|
|
879
|
-
onPageChange={(p) => (standalonePage = p)}
|
|
880
|
-
/>
|
|
881
|
-
</div>
|
|
882
|
-
|
|
883
|
-
{#snippet pageOne()}
|
|
884
|
-
<div class="p-4 rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)]">
|
|
885
|
-
<p class="text-sm font-medium">Release notes</p>
|
|
886
|
-
<p class="text-xs text-[var(--color-text-muted)]">
|
|
887
|
-
Snapshot of changes across components.
|
|
888
|
-
</p>
|
|
889
|
-
</div>
|
|
890
|
-
{/snippet}
|
|
891
|
-
{#snippet pageTwo()}
|
|
892
|
-
<div class="p-4 rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)]">
|
|
893
|
-
<p class="text-sm font-medium">Design tasks</p>
|
|
894
|
-
<p class="text-xs text-[var(--color-text-muted)]">
|
|
895
|
-
Review tokens and spacing.
|
|
896
|
-
</p>
|
|
897
|
-
</div>
|
|
898
|
-
{/snippet}
|
|
899
|
-
{#snippet pageThree()}
|
|
900
|
-
<div class="p-4 rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)]">
|
|
901
|
-
<p class="text-sm font-medium">QA checklist</p>
|
|
902
|
-
<p class="text-xs text-[var(--color-text-muted)]">
|
|
903
|
-
Validate keyboard and focus behavior.
|
|
904
|
-
</p>
|
|
905
|
-
</div>
|
|
906
|
-
{/snippet}
|
|
907
|
-
|
|
908
|
-
<PaginatedCard
|
|
909
|
-
items={[pageOne, pageTwo, pageThree]}
|
|
910
|
-
itemsPerPage={1}
|
|
911
|
-
/>
|
|
912
|
-
</div>
|
|
913
|
-
</Card>
|
|
914
|
-
|
|
915
|
-
<Card header={layoutHeader}>
|
|
916
|
-
<div class="space-y-4">
|
|
917
|
-
<div class="h-56 rounded-xl border border-[var(--border-color-default)] overflow-hidden">
|
|
918
|
-
<Splitter
|
|
919
|
-
direction="horizontal"
|
|
920
|
-
initialSize={45}
|
|
921
|
-
dividerSize={6}
|
|
922
|
-
minSize={20}
|
|
923
|
-
maxSize={80}
|
|
924
|
-
first={firstPane}
|
|
925
|
-
second={secondPane}
|
|
926
|
-
/>
|
|
927
|
-
</div>
|
|
928
|
-
|
|
929
|
-
<div
|
|
930
|
-
class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4 text-sm text-[var(--color-text-muted)]"
|
|
931
|
-
oncontextmenu={(e) => contextMenuRef?.openAt(e)}
|
|
932
|
-
role="button"
|
|
933
|
-
tabindex="0"
|
|
934
|
-
>
|
|
935
|
-
{contextMenuStatus}
|
|
936
|
-
</div>
|
|
937
|
-
|
|
938
|
-
<ContextMenu
|
|
939
|
-
bind:this={contextMenuRef}
|
|
940
|
-
onUndo={() => handleContextAction("Undo", "info")}
|
|
941
|
-
onRedo={() => handleContextAction("Redo", "info")}
|
|
942
|
-
onCopy={() => handleContextAction("Copy", "success")}
|
|
943
|
-
onCut={() => handleContextAction("Cut", "warning")}
|
|
944
|
-
onPaste={() => handleContextAction("Paste", "success")}
|
|
945
|
-
onDelete={() => handleContextAction("Delete", "danger")}
|
|
946
|
-
/>
|
|
947
|
-
</div>
|
|
948
|
-
</Card>
|
|
949
|
-
</div>
|
|
950
|
-
|
|
951
|
-
{#snippet codeHeader()}
|
|
952
|
-
<div class="flex items-center justify-between gap-2">
|
|
953
|
-
<div>
|
|
954
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
955
|
-
Code
|
|
956
|
-
</p>
|
|
957
|
-
<h2 class="text-lg font-semibold leading-tight">CodeView editor</h2>
|
|
958
|
-
</div>
|
|
959
|
-
<Switch
|
|
960
|
-
checked={codeEditable}
|
|
961
|
-
onChange={(v) => (codeEditable = v)}
|
|
962
|
-
rightLabel={codeEditable ? "Editable" : "Read only"}
|
|
963
|
-
sz="sm"
|
|
964
|
-
/>
|
|
965
|
-
</div>
|
|
966
|
-
{/snippet}
|
|
967
|
-
|
|
968
|
-
{#snippet quickHeader()}
|
|
969
|
-
<div class="flex items-center justify-between gap-2">
|
|
970
|
-
<div>
|
|
971
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
972
|
-
Actions
|
|
973
|
-
</p>
|
|
974
|
-
<h2 class="text-lg font-semibold leading-tight">Quick actions</h2>
|
|
975
|
-
</div>
|
|
976
|
-
</div>
|
|
977
|
-
{/snippet}
|
|
978
|
-
|
|
979
|
-
<div class="grid gap-6 lg:grid-cols-2">
|
|
980
|
-
<Card header={codeHeader} class="min-h-[360px]">
|
|
981
|
-
<CodeView
|
|
982
|
-
bind:code={codeSample}
|
|
983
|
-
language="js"
|
|
984
|
-
title="tokens.js"
|
|
985
|
-
showCopyButton={true}
|
|
986
|
-
showLineNumbers={true}
|
|
987
|
-
editable={codeEditable}
|
|
988
|
-
activeLine={true}
|
|
989
|
-
class="h-[320px]"
|
|
990
|
-
/>
|
|
991
|
-
</Card>
|
|
992
|
-
|
|
993
|
-
<Card header={quickHeader}>
|
|
994
|
-
<div class="space-y-4">
|
|
995
|
-
<div class="flex flex-wrap gap-2">
|
|
996
|
-
<Button variant="secondary" onClick={() => pushToast("info")}>
|
|
997
|
-
Notify
|
|
998
|
-
</Button>
|
|
999
|
-
<Button variant="success" onClick={() => pushToast("success")}>
|
|
1000
|
-
Success
|
|
1001
|
-
</Button>
|
|
1002
|
-
<Button variant="danger" onClick={() => pushToast("danger")}>
|
|
1003
|
-
Error
|
|
1004
|
-
</Button>
|
|
1005
|
-
</div>
|
|
1006
|
-
|
|
1007
|
-
<div class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4">
|
|
1008
|
-
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
1009
|
-
Active nav
|
|
1010
|
-
</p>
|
|
1011
|
-
<p class="text-lg font-semibold">{activeNav}</p>
|
|
1012
|
-
<p class="text-sm text-[var(--color-text-muted)]">
|
|
1013
|
-
Search: {searchQuery || "empty"}
|
|
1014
|
-
</p>
|
|
1015
|
-
</div>
|
|
1016
|
-
</div>
|
|
1017
|
-
</Card>
|
|
1018
|
-
</div>
|
|
1019
|
-
|
|
1020
|
-
<Dialog
|
|
1021
|
-
open={dialogOpen}
|
|
1022
|
-
title="Confirm release"
|
|
1023
|
-
message="Ready to ship the selected files?"
|
|
1024
|
-
onConfirm={() => {
|
|
1025
|
-
dialogOpen = false;
|
|
1026
|
-
pushToast("success");
|
|
1027
|
-
}}
|
|
1028
|
-
onCancel={() => {
|
|
1029
|
-
dialogOpen = false;
|
|
1030
|
-
}}
|
|
1031
|
-
onClose={() => {
|
|
1032
|
-
dialogOpen = false;
|
|
1033
|
-
}}
|
|
1034
|
-
/>
|
|
1035
|
-
</div>
|
|
1036
|
-
|
|
1037
|
-
{#each toasts as toast (toast.id)}
|
|
1038
|
-
<Toast
|
|
1039
|
-
title={toast.title}
|
|
1040
|
-
message={toast.message}
|
|
1041
|
-
variant={toast.variant}
|
|
1042
|
-
onClose={() => removeToast(toast.id)}
|
|
1043
|
-
timeout={3500}
|
|
1044
|
-
/>
|
|
1045
|
-
{/each}
|
|
1046
|
-
</Container>
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Accordion from "./lib/Accordion.svelte";
|
|
3
|
+
import Badge from "./lib/Badge.svelte";
|
|
4
|
+
import Button from "./lib/Button.svelte";
|
|
5
|
+
import Calendar from "./lib/Calendar.svelte";
|
|
6
|
+
import Card from "./lib/Card.svelte";
|
|
7
|
+
import Carousel from "./lib/Carousel.svelte";
|
|
8
|
+
import CheckBox from "./lib/CheckBox.svelte";
|
|
9
|
+
import CodeView from "./lib/CodeView.svelte";
|
|
10
|
+
import ColorPicker from "./lib/ColorPicker.svelte";
|
|
11
|
+
import ContextMenu from "./lib/ContextMenu.svelte";
|
|
12
|
+
import DatePicker from "./lib/DatePicker.svelte";
|
|
13
|
+
import Dialog from "./lib/Dialog.svelte";
|
|
14
|
+
import Field from "./lib/Field.svelte";
|
|
15
|
+
import FilePicker from "./lib/FilePicker.svelte";
|
|
16
|
+
import Form from "./lib/Form.svelte";
|
|
17
|
+
import InstallPWA from "./lib/InstallPWA.svelte";
|
|
18
|
+
import Menu from "./lib/Menu.svelte";
|
|
19
|
+
import NoticeBase from "./lib/NoticeBase.svelte";
|
|
20
|
+
import PaginatedCard from "./lib/PaginatedCard.svelte";
|
|
21
|
+
import Pagination from "./lib/Pagination.svelte";
|
|
22
|
+
import PrimaryColorSelect from "./lib/PrimaryColorSelect.svelte";
|
|
23
|
+
import ProgressBar from "./lib/ProgressBar.svelte";
|
|
24
|
+
import ProgressCircle from "./lib/ProgressCircle.svelte";
|
|
25
|
+
import Radio from "./lib/Radio.svelte";
|
|
26
|
+
import SearchInput from "./lib/SearchInput.svelte";
|
|
27
|
+
import Select from "./lib/Select.svelte";
|
|
28
|
+
import Slider from "./lib/Slider.svelte";
|
|
29
|
+
import Splitter from "./lib/Splitter.svelte";
|
|
30
|
+
import Switch from "./lib/Switch.svelte";
|
|
31
|
+
import Table from "./lib/Table.svelte";
|
|
32
|
+
import Tabs from "./lib/Tabs.svelte";
|
|
33
|
+
import ThemeToggle from "./lib/ThemeToggle.svelte";
|
|
34
|
+
import TimePicker from "./lib/TimePicker.svelte";
|
|
35
|
+
import Toast from "./lib/Toast.svelte";
|
|
36
|
+
import Tooltip from "./lib/Tooltip.svelte";
|
|
37
|
+
import Topbar from "./lib/Topbar.svelte";
|
|
38
|
+
import type { FieldSchema, MenuAction, MenuItem, SizeKey, ToastVariant } from "./lib/types";
|
|
39
|
+
import Container from "./Container.svelte";
|
|
40
|
+
|
|
41
|
+
const tabs = [
|
|
42
|
+
{ id: "overview", label: "Overview" },
|
|
43
|
+
{ id: "team", label: "Team" },
|
|
44
|
+
{ id: "table", label: "Data" },
|
|
45
|
+
];
|
|
46
|
+
let activeTab = $state(tabs[0].id);
|
|
47
|
+
|
|
48
|
+
let sliderValue = $state(68);
|
|
49
|
+
let autoplay = $state(true);
|
|
50
|
+
|
|
51
|
+
const planOptions = [
|
|
52
|
+
{ label: "Starter", value: "starter" },
|
|
53
|
+
{ label: "Pro", value: "pro" },
|
|
54
|
+
{ label: "Enterprise", value: "enterprise" },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
let selectedPlan = $state(planOptions[1].value);
|
|
58
|
+
let featureName = $state("Dashboard 2.0");
|
|
59
|
+
let contactEmail = $state("team@studio.dev");
|
|
60
|
+
let dateValue = $state<string | null>(null);
|
|
61
|
+
let timeValue = $state<string | null>(null);
|
|
62
|
+
let accentColor = $state<string | null>("#7c3aed");
|
|
63
|
+
|
|
64
|
+
const accordionItems = [
|
|
65
|
+
{
|
|
66
|
+
title: "Composition",
|
|
67
|
+
content:
|
|
68
|
+
"Card, Tabs, Table and Carousel let you assemble complex screens without extra layout work.",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
title: "Forms",
|
|
72
|
+
content:
|
|
73
|
+
"Field, Select, DatePicker, TimePicker and ColorPicker share spacing, tokens and state handling.",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
title: "Feedback",
|
|
77
|
+
content:
|
|
78
|
+
"ProgressBar, ProgressCircle, Toast and Dialog keep users informed without noise.",
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const carouselItems = [
|
|
83
|
+
{
|
|
84
|
+
title: "Smooth forms",
|
|
85
|
+
content:
|
|
86
|
+
"Clean fields, tight spacing and built-in hints help ship surveys in minutes.",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
title: "Smart navigation",
|
|
90
|
+
content:
|
|
91
|
+
"Tabs and Accordion keep content nearby while Carousel saves horizontal space.",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
title: "Status signals",
|
|
95
|
+
content:
|
|
96
|
+
"Toast and progress indicators deliver context quickly without blocking flows.",
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const tableColumns = [
|
|
101
|
+
{ key: "name", label: "Feature", width: "42%" },
|
|
102
|
+
{ key: "owner", label: "Owner" },
|
|
103
|
+
{ key: "status", label: "Status" },
|
|
104
|
+
{ key: "eta", label: "ETA", align: "end" },
|
|
105
|
+
] as const;
|
|
106
|
+
|
|
107
|
+
const tableRows = [
|
|
108
|
+
{ id: 1, name: "Onboarding", owner: "Anna", status: "Ready", eta: "Today" },
|
|
109
|
+
{ id: 2, name: "Theming", owner: "Mark", status: "In progress", eta: "Fri" },
|
|
110
|
+
{ id: 3, name: "Notifications", owner: "Oleg", status: "Testing", eta: "Thu" },
|
|
111
|
+
{ id: 4, name: "Data tables", owner: "Ira", status: "In progress", eta: "Next week" },
|
|
112
|
+
{ id: 5, name: "Carousel", owner: "Anton", status: "Design", eta: "In two weeks" },
|
|
113
|
+
{ id: 6, name: "Accessibility", owner: "Sasha", status: "Review", eta: "Today" },
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
const pageSize = 4;
|
|
117
|
+
let tablePage = $state(1);
|
|
118
|
+
const totalPages = $derived(
|
|
119
|
+
Math.max(1, Math.ceil(tableRows.length / pageSize))
|
|
120
|
+
);
|
|
121
|
+
const pagedRows = $derived(
|
|
122
|
+
tableRows.slice((tablePage - 1) * pageSize, tablePage * pageSize)
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
$effect(() => {
|
|
126
|
+
if (tablePage > totalPages) tablePage = totalPages;
|
|
127
|
+
if (tablePage < 1) tablePage = 1;
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const quality = [
|
|
131
|
+
{ label: "UI polish", value: 86 },
|
|
132
|
+
{ label: "Accessibility", value: 72 },
|
|
133
|
+
{ label: "Performance", value: 64 },
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
const team = [
|
|
137
|
+
{ name: "Anna", role: "Product", focus: "UX flows" },
|
|
138
|
+
{ name: "Mark", role: "Frontend", focus: "Components" },
|
|
139
|
+
{ name: "Oleg", role: "QA", focus: "Automation" },
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
const navItems = [
|
|
143
|
+
{ id: "overview", label: "Overview" },
|
|
144
|
+
{ id: "inputs", label: "Inputs" },
|
|
145
|
+
{ id: "layout", label: "Layout" },
|
|
146
|
+
{ id: "data", label: "Data" },
|
|
147
|
+
];
|
|
148
|
+
let activeNav = $state(navItems[0].id);
|
|
149
|
+
|
|
150
|
+
let searchQuery = $state("");
|
|
151
|
+
let calendarValue = $state<string | null>(null);
|
|
152
|
+
let fileList = $state<FileList | null>(null);
|
|
153
|
+
let dialogOpen = $state(false);
|
|
154
|
+
let radioGroup = $state("daily");
|
|
155
|
+
let newsletterChecked = $state(false);
|
|
156
|
+
let mixedChecked = $state(false);
|
|
157
|
+
let mixedState = $state(true);
|
|
158
|
+
let menuSelection = $state("Pick an action from the menu bar");
|
|
159
|
+
let menuSize = $state<SizeKey>("sm");
|
|
160
|
+
let standalonePage = $state(1);
|
|
161
|
+
const standaloneTotal = 5;
|
|
162
|
+
let codeEditable = $state(false);
|
|
163
|
+
let codeSample = $state(
|
|
164
|
+
"const tokens = ['spacing', 'radius', 'colors'];\n\nexport function tokensReady() {\n return tokens.length > 0;\n}\n"
|
|
165
|
+
);
|
|
166
|
+
let contextMenuStatus = $state("Right-click the panel to open the menu");
|
|
167
|
+
let contextMenuRef = $state<{
|
|
168
|
+
openAt: (event: MouseEvent) => void;
|
|
169
|
+
close: () => void;
|
|
170
|
+
} | null>(null);
|
|
171
|
+
|
|
172
|
+
const menuData: MenuItem[] = [
|
|
173
|
+
{
|
|
174
|
+
name: "File",
|
|
175
|
+
actions: [
|
|
176
|
+
{ id: "new", label: "New", shortcut: "Ctrl+N" },
|
|
177
|
+
{ id: "open", label: "Open", shortcut: "Ctrl+O" },
|
|
178
|
+
{ type: "separator" },
|
|
179
|
+
{ id: "export", label: "Export", shortcut: "Ctrl+E" },
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: "View",
|
|
184
|
+
actions: [
|
|
185
|
+
{ id: "xs", label: "XS" },
|
|
186
|
+
{ id: "sm", label: "SM" },
|
|
187
|
+
{ id: "md", label: "MD" },
|
|
188
|
+
{ id: "lg", label: "LG" },
|
|
189
|
+
{ id: "xl", label: "XL" },
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
const miniFormSchema: FieldSchema[] = [
|
|
195
|
+
{ name: "project", type: "text", label: "Project", required: true },
|
|
196
|
+
{ name: "owner", type: "email", label: "Owner email", required: true },
|
|
197
|
+
{
|
|
198
|
+
name: "priority",
|
|
199
|
+
type: "select",
|
|
200
|
+
label: "Priority",
|
|
201
|
+
options: [
|
|
202
|
+
{ label: "Low", value: "low" },
|
|
203
|
+
{ label: "Medium", value: "medium" },
|
|
204
|
+
{ label: "High", value: "high" },
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
{ name: "subscribe", type: "checkbox", label: "Send updates" },
|
|
208
|
+
];
|
|
209
|
+
let formResult = $state("Not submitted yet");
|
|
210
|
+
|
|
211
|
+
type ToastItem = { id: number; title?: string; message: string; variant: ToastVariant };
|
|
212
|
+
let toasts = $state<ToastItem[]>([]);
|
|
213
|
+
let toastId = 0;
|
|
214
|
+
|
|
215
|
+
function pushToast(variant: ToastVariant) {
|
|
216
|
+
const messageMap: Record<ToastVariant, string> = {
|
|
217
|
+
success: "Changes saved and ready to roll out.",
|
|
218
|
+
info: "Components share tokens, typography, and behavior.",
|
|
219
|
+
warning: "Double-check disabled, focus, and hover states.",
|
|
220
|
+
danger: "Tests caught a blocking issue. Investigate.",
|
|
221
|
+
};
|
|
222
|
+
const titleMap: Record<ToastVariant, string> = {
|
|
223
|
+
success: "Success",
|
|
224
|
+
info: "Heads up",
|
|
225
|
+
warning: "Warning",
|
|
226
|
+
danger: "Error",
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const id = ++toastId;
|
|
230
|
+
toasts = [
|
|
231
|
+
...toasts,
|
|
232
|
+
{ id, variant, title: titleMap[variant], message: messageMap[variant] },
|
|
233
|
+
];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function removeToast(id: number) {
|
|
237
|
+
toasts = toasts.filter((t) => t.id !== id);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function handleMenuSelect(menu: string, action: MenuAction) {
|
|
241
|
+
const label =
|
|
242
|
+
typeof action === "string"
|
|
243
|
+
? action
|
|
244
|
+
: action.label || action.id || "Action";
|
|
245
|
+
const id = typeof action === "string" ? action : action.id;
|
|
246
|
+
if (id && ["xs", "sm", "md", "lg", "xl"].includes(id)) {
|
|
247
|
+
menuSize = id as SizeKey;
|
|
248
|
+
}
|
|
249
|
+
menuSelection = `${menu}: ${label}`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function handleMiniSubmit(values: Record<string, unknown>) {
|
|
253
|
+
formResult = JSON.stringify(values, null, 2);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function handleContextAction(label: string, variant: ToastVariant) {
|
|
257
|
+
contextMenuStatus = `Last action: ${label}`;
|
|
258
|
+
pushToast(variant);
|
|
259
|
+
}
|
|
260
|
+
</script>
|
|
261
|
+
|
|
262
|
+
<Topbar
|
|
263
|
+
title="svelte-comp"
|
|
264
|
+
showHamburger={true}
|
|
265
|
+
menuItems={navItems}
|
|
266
|
+
onMenuSelect={(id) => (activeNav = id)}
|
|
267
|
+
/>
|
|
268
|
+
|
|
269
|
+
<Container>
|
|
270
|
+
<div class="relative mx-auto max-w-6xl space-y-8 px-6 pb-10 pt-24">
|
|
271
|
+
<section
|
|
272
|
+
class="relative rounded-[28px] border border-[var(--border-color-default)] bg-gradient-to-br from-[var(--color-bg-surface)] via-white/70 to-[var(--color-bg-muted)] shadow-[0_20px_60px_-25px_var(--shadow-color)] dark:from-[var(--color-bg-surface)] dark:via-slate-900/70 dark:to-slate-900/50"
|
|
273
|
+
>
|
|
274
|
+
<div
|
|
275
|
+
class="absolute inset-0 bg-[radial-gradient(circle_at_20%_20%,rgba(99,102,241,0.18),transparent_35%),radial-gradient(circle_at_80%_0%,rgba(16,185,129,0.14),transparent_25%)]"
|
|
276
|
+
></div>
|
|
277
|
+
|
|
278
|
+
<div class="relative grid gap-8 p-8 md:p-10 lg:grid-cols-[1.1fr_0.9fr]">
|
|
279
|
+
<div class="space-y-4">
|
|
280
|
+
<p class="text-xs uppercase tracking-[0.25em] text-[var(--color-text-muted)]">
|
|
281
|
+
svelte-comp
|
|
282
|
+
</p>
|
|
283
|
+
<h1 class="text-3xl font-bold leading-tight md:text-4xl">
|
|
284
|
+
Component showcase
|
|
285
|
+
</h1>
|
|
286
|
+
<p class="text-[var(--color-text-muted)] md:w-3/4">
|
|
287
|
+
Toggle theme, tweak the primary color, and try the main lib components in a cohesive layout.
|
|
288
|
+
</p>
|
|
289
|
+
|
|
290
|
+
<div class="flex flex-wrap gap-3">
|
|
291
|
+
<Button variant="primary" onClick={() => pushToast("info")} sz="lg">
|
|
292
|
+
Launch interactive
|
|
293
|
+
</Button>
|
|
294
|
+
<Button variant="ghost" onClick={() => pushToast("warning")} sz="lg">
|
|
295
|
+
Remind to review
|
|
296
|
+
</Button>
|
|
297
|
+
</div>
|
|
298
|
+
|
|
299
|
+
<div class="flex flex-wrap gap-3 text-sm text-[var(--color-text-muted)]">
|
|
300
|
+
<span
|
|
301
|
+
class="inline-flex items-center gap-2 rounded-full border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] px-3 py-2"
|
|
302
|
+
>
|
|
303
|
+
<span class="h-2 w-2 animate-pulse rounded-full bg-[var(--color-bg-primary)]"></span>
|
|
304
|
+
Live preview is on
|
|
305
|
+
</span>
|
|
306
|
+
<span
|
|
307
|
+
class="inline-flex items-center gap-2 rounded-full border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] px-3 py-2"
|
|
308
|
+
>
|
|
309
|
+
<span class="h-2 w-2 rounded-full bg-[var(--color-bg-secondary)]"></span>
|
|
310
|
+
{tabs.length} sections below
|
|
311
|
+
</span>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
<div
|
|
316
|
+
class="space-y-4 rounded-2xl border border-[var(--border-color-default)] bg-white/70 p-5 shadow-lg dark:bg-slate-900/60"
|
|
317
|
+
>
|
|
318
|
+
<div class="flex items-start justify-between gap-3">
|
|
319
|
+
<div>
|
|
320
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
321
|
+
Theme
|
|
322
|
+
</p>
|
|
323
|
+
<p class="text-lg font-semibold">Mode and accent</p>
|
|
324
|
+
</div>
|
|
325
|
+
|
|
326
|
+
<Tooltip text="Toggles document-level theme" position="bottom">
|
|
327
|
+
<ThemeToggle class="relative shadow-sm" sz="sm" />
|
|
328
|
+
</Tooltip>
|
|
329
|
+
</div>
|
|
330
|
+
|
|
331
|
+
<PrimaryColorSelect class="w-full" />
|
|
332
|
+
|
|
333
|
+
<div
|
|
334
|
+
class="flex items-center justify-between rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-muted)]/70 px-4 py-3"
|
|
335
|
+
>
|
|
336
|
+
<div>
|
|
337
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
338
|
+
Autoplay
|
|
339
|
+
</p>
|
|
340
|
+
<p class="text-sm font-medium">Carousel</p>
|
|
341
|
+
</div>
|
|
342
|
+
<Switch
|
|
343
|
+
checked={autoplay}
|
|
344
|
+
onChange={(v) => (autoplay = v)}
|
|
345
|
+
sz="sm"
|
|
346
|
+
rightLabel={autoplay ? "On" : "Off"}
|
|
347
|
+
/>
|
|
348
|
+
</div>
|
|
349
|
+
|
|
350
|
+
<div class="grid gap-3 md:grid-cols-2">
|
|
351
|
+
<ProgressCircle value={sliderValue} label="Readiness" />
|
|
352
|
+
<ProgressBar value={sliderValue} label="Sprint focus" />
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
355
|
+
</div>
|
|
356
|
+
</section>
|
|
357
|
+
|
|
358
|
+
{#snippet controlsHeader()}
|
|
359
|
+
<div class="flex items-center justify-between gap-2">
|
|
360
|
+
<div>
|
|
361
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
362
|
+
Actions
|
|
363
|
+
</p>
|
|
364
|
+
<h2 class="text-lg font-semibold leading-tight">Quick triggers</h2>
|
|
365
|
+
</div>
|
|
366
|
+
<Tooltip text="Buttons use the full variant set" position="left">
|
|
367
|
+
<span
|
|
368
|
+
class="inline-flex h-9 w-9 items-center justify-center rounded-full bg-[var(--color-bg-muted)] text-sm font-semibold text-[var(--color-text-default)]"
|
|
369
|
+
>
|
|
370
|
+
?
|
|
371
|
+
</span>
|
|
372
|
+
</Tooltip>
|
|
373
|
+
</div>
|
|
374
|
+
{/snippet}
|
|
375
|
+
|
|
376
|
+
{#snippet formHeader()}
|
|
377
|
+
<div class="flex items-center justify-between">
|
|
378
|
+
<div>
|
|
379
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
380
|
+
Form
|
|
381
|
+
</p>
|
|
382
|
+
<h2 class="text-lg font-semibold leading-tight">Mini brief</h2>
|
|
383
|
+
</div>
|
|
384
|
+
<Tooltip text="Field, Select, DatePicker, TimePicker and ColorPicker" position="left">
|
|
385
|
+
<span
|
|
386
|
+
class="inline-flex h-8 w-8 items-center justify-center rounded-full bg-[var(--color-bg-muted)] text-sm font-semibold text-[var(--color-text-default)]"
|
|
387
|
+
>
|
|
388
|
+
i
|
|
389
|
+
</span>
|
|
390
|
+
</Tooltip>
|
|
391
|
+
</div>
|
|
392
|
+
{/snippet}
|
|
393
|
+
|
|
394
|
+
<div class="grid gap-6 lg:grid-cols-2">
|
|
395
|
+
<Card header={controlsHeader}>
|
|
396
|
+
<div class="space-y-4">
|
|
397
|
+
<div class="flex flex-wrap gap-2">
|
|
398
|
+
<Button variant="primary" onClick={() => pushToast("success")}>Primary</Button>
|
|
399
|
+
<Button variant="secondary">Secondary</Button>
|
|
400
|
+
<Button variant="ghost">Ghost</Button>
|
|
401
|
+
<Button variant="pill">Pill</Button>
|
|
402
|
+
<Button variant="danger" onClick={() => pushToast("danger")}>Danger</Button>
|
|
403
|
+
</div>
|
|
404
|
+
|
|
405
|
+
<div
|
|
406
|
+
class="flex items-center justify-between gap-3 rounded-xl border border-[var(--border-color-default)] px-4 py-3"
|
|
407
|
+
>
|
|
408
|
+
<div class="space-y-1">
|
|
409
|
+
<p class="text-sm font-medium">Live mode</p>
|
|
410
|
+
<p class="text-xs text-[var(--color-text-muted)]">
|
|
411
|
+
Keep autoplay and progress linked across the page
|
|
412
|
+
</p>
|
|
413
|
+
</div>
|
|
414
|
+
<Switch checked={autoplay} onChange={(v) => (autoplay = v)} sz="sm" />
|
|
415
|
+
</div>
|
|
416
|
+
|
|
417
|
+
<div class="space-y-2">
|
|
418
|
+
<div class="flex items-center justify-between text-sm">
|
|
419
|
+
<span class="text-[var(--color-text-muted)]">Drag to refresh progress</span>
|
|
420
|
+
<span class="font-mono text-[var(--color-text-default)]">{sliderValue}%</span>
|
|
421
|
+
</div>
|
|
422
|
+
<Slider
|
|
423
|
+
value={sliderValue}
|
|
424
|
+
min={0}
|
|
425
|
+
max={100}
|
|
426
|
+
onInput={(v) => (sliderValue = v)}
|
|
427
|
+
showValue={false}
|
|
428
|
+
/>
|
|
429
|
+
</div>
|
|
430
|
+
|
|
431
|
+
<div class="grid gap-3 md:grid-cols-2">
|
|
432
|
+
<ProgressBar value={sliderValue} label="Iteration" />
|
|
433
|
+
<ProgressCircle value={sliderValue} label="Readiness" />
|
|
434
|
+
</div>
|
|
435
|
+
|
|
436
|
+
<div class="flex flex-wrap gap-2">
|
|
437
|
+
<Button variant="success" onClick={() => pushToast("success")} sz="sm">
|
|
438
|
+
Success toast
|
|
439
|
+
</Button>
|
|
440
|
+
<Button variant="warning" onClick={() => pushToast("warning")} sz="sm">
|
|
441
|
+
Warning toast
|
|
442
|
+
</Button>
|
|
443
|
+
<Button variant="info" onClick={() => pushToast("info")} sz="sm">
|
|
444
|
+
Info toast
|
|
445
|
+
</Button>
|
|
446
|
+
</div>
|
|
447
|
+
</div>
|
|
448
|
+
</Card>
|
|
449
|
+
|
|
450
|
+
<Card header={formHeader}>
|
|
451
|
+
<div class="space-y-4">
|
|
452
|
+
<div class="grid gap-3 md:grid-cols-2">
|
|
453
|
+
<Field
|
|
454
|
+
label="Name"
|
|
455
|
+
value={featureName}
|
|
456
|
+
onChange={(v) => (featureName = String(v))}
|
|
457
|
+
/>
|
|
458
|
+
<Field
|
|
459
|
+
label="Contact email"
|
|
460
|
+
type="email"
|
|
461
|
+
value={contactEmail}
|
|
462
|
+
onChange={(v) => (contactEmail = String(v))}
|
|
463
|
+
/>
|
|
464
|
+
</div>
|
|
465
|
+
|
|
466
|
+
<Select
|
|
467
|
+
label="Plan"
|
|
468
|
+
options={planOptions}
|
|
469
|
+
value={selectedPlan}
|
|
470
|
+
placeholder="Choose a plan"
|
|
471
|
+
onChange={(v) => (selectedPlan = v)}
|
|
472
|
+
/>
|
|
473
|
+
|
|
474
|
+
<div class="grid gap-3 md:grid-cols-3">
|
|
475
|
+
<DatePicker
|
|
476
|
+
label="Launch date"
|
|
477
|
+
value={dateValue}
|
|
478
|
+
onChange={(v) => (dateValue = v)}
|
|
479
|
+
/>
|
|
480
|
+
<TimePicker
|
|
481
|
+
label="Release time"
|
|
482
|
+
value={timeValue}
|
|
483
|
+
onChange={(v) => (timeValue = v)}
|
|
484
|
+
/>
|
|
485
|
+
<ColorPicker
|
|
486
|
+
label="Accent"
|
|
487
|
+
value={accentColor}
|
|
488
|
+
onChange={(v) => (accentColor = v)}
|
|
489
|
+
/>
|
|
490
|
+
</div>
|
|
491
|
+
|
|
492
|
+
<div class="flex justify-end gap-3">
|
|
493
|
+
<Button
|
|
494
|
+
variant="ghost"
|
|
495
|
+
onClick={() => {
|
|
496
|
+
featureName = "Dashboard 2.0";
|
|
497
|
+
selectedPlan = planOptions[1].value;
|
|
498
|
+
contactEmail = "team@studio.dev";
|
|
499
|
+
dateValue = null;
|
|
500
|
+
timeValue = null;
|
|
501
|
+
accentColor = "#7c3aed";
|
|
502
|
+
}}
|
|
503
|
+
>
|
|
504
|
+
Reset
|
|
505
|
+
</Button>
|
|
506
|
+
<Button variant="primary" onClick={() => pushToast("success")}>
|
|
507
|
+
Save
|
|
508
|
+
</Button>
|
|
509
|
+
</div>
|
|
510
|
+
</div>
|
|
511
|
+
</Card>
|
|
512
|
+
</div>
|
|
513
|
+
|
|
514
|
+
{#snippet dataHeader()}
|
|
515
|
+
<div class="flex items-center justify-between gap-3">
|
|
516
|
+
<div>
|
|
517
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
518
|
+
Data
|
|
519
|
+
</p>
|
|
520
|
+
<h2 class="text-lg font-semibold leading-tight">Sprint snapshot</h2>
|
|
521
|
+
</div>
|
|
522
|
+
<Button variant="secondary" sz="sm" onClick={() => pushToast("info")}>
|
|
523
|
+
Refresh
|
|
524
|
+
</Button>
|
|
525
|
+
</div>
|
|
526
|
+
{/snippet}
|
|
527
|
+
|
|
528
|
+
{#snippet accordionHeader()}
|
|
529
|
+
<div class="flex items-center justify-between gap-3">
|
|
530
|
+
<div>
|
|
531
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
532
|
+
Details
|
|
533
|
+
</p>
|
|
534
|
+
<h3 class="text-lg font-semibold leading-tight">Sections</h3>
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
{/snippet}
|
|
538
|
+
|
|
539
|
+
{#snippet carouselHeader()}
|
|
540
|
+
<div class="flex items-center justify-between gap-3">
|
|
541
|
+
<div>
|
|
542
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
543
|
+
Carousel
|
|
544
|
+
</p>
|
|
545
|
+
<h3 class="text-lg font-semibold leading-tight">Stories</h3>
|
|
546
|
+
</div>
|
|
547
|
+
<span class="text-xs text-[var(--color-text-muted)]">
|
|
548
|
+
Autoplay {autoplay ? "on" : "off"}
|
|
549
|
+
</span>
|
|
550
|
+
</div>
|
|
551
|
+
{/snippet}
|
|
552
|
+
|
|
553
|
+
<div class="grid gap-6 lg:grid-cols-[1.2fr_0.8fr]">
|
|
554
|
+
<Card header={dataHeader} class="h-full">
|
|
555
|
+
<Tabs
|
|
556
|
+
tabs={tabs}
|
|
557
|
+
activeTab={activeTab}
|
|
558
|
+
onChange={(id) => (activeTab = id)}
|
|
559
|
+
variant="underline"
|
|
560
|
+
fitted={true}
|
|
561
|
+
>
|
|
562
|
+
{#if activeTab === "overview"}
|
|
563
|
+
<div class="grid gap-4 md:grid-cols-3">
|
|
564
|
+
<div
|
|
565
|
+
class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4"
|
|
566
|
+
>
|
|
567
|
+
<p class="text-xs uppercase tracking-[0.1em] text-[var(--color-text-muted)]">
|
|
568
|
+
Readiness
|
|
569
|
+
</p>
|
|
570
|
+
<p class="text-2xl font-bold">{sliderValue}%</p>
|
|
571
|
+
<p class="text-sm text-[var(--color-text-muted)]">
|
|
572
|
+
Synced with the slider above
|
|
573
|
+
</p>
|
|
574
|
+
</div>
|
|
575
|
+
|
|
576
|
+
<div
|
|
577
|
+
class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4"
|
|
578
|
+
>
|
|
579
|
+
<p class="text-xs uppercase tracking-[0.1em] text-[var(--color-text-muted)]">
|
|
580
|
+
Plan
|
|
581
|
+
</p>
|
|
582
|
+
<p class="text-lg font-semibold">{selectedPlan}</p>
|
|
583
|
+
<p class="text-sm text-[var(--color-text-muted)]">
|
|
584
|
+
Contact: {contactEmail}
|
|
585
|
+
</p>
|
|
586
|
+
</div>
|
|
587
|
+
|
|
588
|
+
<div
|
|
589
|
+
class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4"
|
|
590
|
+
>
|
|
591
|
+
<p class="text-xs uppercase tracking-[0.1em] text-[var(--color-text-muted)]">
|
|
592
|
+
Release window
|
|
593
|
+
</p>
|
|
594
|
+
<p class="text-lg font-semibold">
|
|
595
|
+
{dateValue ?? "Not selected yet"}
|
|
596
|
+
</p>
|
|
597
|
+
<p class="text-sm text-[var(--color-text-muted)]">
|
|
598
|
+
{timeValue ?? "Time is being planned"}
|
|
599
|
+
</p>
|
|
600
|
+
</div>
|
|
601
|
+
</div>
|
|
602
|
+
|
|
603
|
+
<div class="mt-4 grid gap-3 md:grid-cols-3">
|
|
604
|
+
{#each quality as metric (metric.label)}
|
|
605
|
+
<ProgressBar value={metric.value} label={metric.label} sz="sm" />
|
|
606
|
+
{/each}
|
|
607
|
+
</div>
|
|
608
|
+
{:else if activeTab === "team"}
|
|
609
|
+
<div class="space-y-3">
|
|
610
|
+
{#each team as person (person.name)}
|
|
611
|
+
<div
|
|
612
|
+
class="flex items-center justify-between rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] px-4 py-3"
|
|
613
|
+
>
|
|
614
|
+
<div>
|
|
615
|
+
<p class="font-semibold">{person.name}</p>
|
|
616
|
+
<p class="text-sm text-[var(--color-text-muted)]">{person.role}</p>
|
|
617
|
+
</div>
|
|
618
|
+
<span
|
|
619
|
+
class="rounded-full bg-[var(--color-bg-muted)] px-3 py-1 text-xs text-[var(--color-text-default)]"
|
|
620
|
+
>
|
|
621
|
+
{person.focus}
|
|
622
|
+
</span>
|
|
623
|
+
</div>
|
|
624
|
+
{/each}
|
|
625
|
+
</div>
|
|
626
|
+
{:else}
|
|
627
|
+
<Table
|
|
628
|
+
columns={tableColumns}
|
|
629
|
+
rows={pagedRows}
|
|
630
|
+
variant="zebra"
|
|
631
|
+
pagination={{ currentPage: tablePage, totalPages, onPageChange: (p) => (tablePage = p) }}
|
|
632
|
+
/>
|
|
633
|
+
{/if}
|
|
634
|
+
</Tabs>
|
|
635
|
+
</Card>
|
|
636
|
+
|
|
637
|
+
<div class="grid gap-6">
|
|
638
|
+
<Card header={accordionHeader}>
|
|
639
|
+
<Accordion items={accordionItems} multiple={true} defaultOpen={[0]} />
|
|
640
|
+
</Card>
|
|
641
|
+
|
|
642
|
+
<Card header={carouselHeader}>
|
|
643
|
+
<Carousel
|
|
644
|
+
items={carouselItems}
|
|
645
|
+
autoplay={autoplay}
|
|
646
|
+
interval={4200}
|
|
647
|
+
showDots={true}
|
|
648
|
+
showArrows={true}
|
|
649
|
+
sz="sm"
|
|
650
|
+
/>
|
|
651
|
+
</Card>
|
|
652
|
+
</div>
|
|
653
|
+
</div>
|
|
654
|
+
|
|
655
|
+
{#snippet statusHeader()}
|
|
656
|
+
<div class="flex items-center justify-between gap-2">
|
|
657
|
+
<div>
|
|
658
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
659
|
+
Status
|
|
660
|
+
</p>
|
|
661
|
+
<h2 class="text-lg font-semibold leading-tight">Search and signals</h2>
|
|
662
|
+
</div>
|
|
663
|
+
</div>
|
|
664
|
+
{/snippet}
|
|
665
|
+
|
|
666
|
+
{#snippet optionsHeader()}
|
|
667
|
+
<div class="flex items-center justify-between gap-2">
|
|
668
|
+
<div>
|
|
669
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
670
|
+
Options
|
|
671
|
+
</p>
|
|
672
|
+
<h2 class="text-lg font-semibold leading-tight">Toggles and calendar</h2>
|
|
673
|
+
</div>
|
|
674
|
+
</div>
|
|
675
|
+
{/snippet}
|
|
676
|
+
|
|
677
|
+
<div class="grid gap-6 lg:grid-cols-2">
|
|
678
|
+
<Card header={statusHeader}>
|
|
679
|
+
<div class="space-y-4">
|
|
680
|
+
<SearchInput
|
|
681
|
+
label="Search components"
|
|
682
|
+
placeholder="Filter by name"
|
|
683
|
+
bind:value={searchQuery}
|
|
684
|
+
/>
|
|
685
|
+
|
|
686
|
+
<div class="flex flex-wrap gap-2">
|
|
687
|
+
<Badge message="Live" variant="success" showIcon />
|
|
688
|
+
<Badge message="Needs review" variant="warning" showIcon />
|
|
689
|
+
<Badge message="Queued" variant="info" />
|
|
690
|
+
</div>
|
|
691
|
+
|
|
692
|
+
{#snippet noticeEnd()}
|
|
693
|
+
<Button variant="ghost" sz="xs">Undo</Button>
|
|
694
|
+
{/snippet}
|
|
695
|
+
|
|
696
|
+
<NoticeBase
|
|
697
|
+
title="Release note"
|
|
698
|
+
message="New components landed in the demo."
|
|
699
|
+
variant="info"
|
|
700
|
+
size="md"
|
|
701
|
+
end={noticeEnd}
|
|
702
|
+
/>
|
|
703
|
+
</div>
|
|
704
|
+
</Card>
|
|
705
|
+
|
|
706
|
+
<Card header={optionsHeader}>
|
|
707
|
+
<div class="space-y-4">
|
|
708
|
+
<div class="space-y-2">
|
|
709
|
+
<Radio
|
|
710
|
+
label="Daily updates"
|
|
711
|
+
value="daily"
|
|
712
|
+
bind:group={radioGroup}
|
|
713
|
+
/>
|
|
714
|
+
<Radio
|
|
715
|
+
label="Weekly updates"
|
|
716
|
+
value="weekly"
|
|
717
|
+
bind:group={radioGroup}
|
|
718
|
+
/>
|
|
719
|
+
<Radio
|
|
720
|
+
label="Monthly updates"
|
|
721
|
+
value="monthly"
|
|
722
|
+
bind:group={radioGroup}
|
|
723
|
+
/>
|
|
724
|
+
</div>
|
|
725
|
+
|
|
726
|
+
<div class="flex flex-wrap gap-3">
|
|
727
|
+
<CheckBox
|
|
728
|
+
label="Send digest emails"
|
|
729
|
+
bind:checked={newsletterChecked}
|
|
730
|
+
/>
|
|
731
|
+
<CheckBox
|
|
732
|
+
label="Mixed state"
|
|
733
|
+
indeterminate={mixedState}
|
|
734
|
+
checked={mixedChecked}
|
|
735
|
+
onChange={(v) => {
|
|
736
|
+
mixedChecked = v;
|
|
737
|
+
mixedState = false;
|
|
738
|
+
}}
|
|
739
|
+
/>
|
|
740
|
+
</div>
|
|
741
|
+
|
|
742
|
+
<div class="grid gap-3 md:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]">
|
|
743
|
+
<div class="min-w-0">
|
|
744
|
+
<Calendar
|
|
745
|
+
value={calendarValue}
|
|
746
|
+
onChange={(v) => (calendarValue = v)}
|
|
747
|
+
showOutsideDays={true}
|
|
748
|
+
class="w-full"
|
|
749
|
+
/>
|
|
750
|
+
</div>
|
|
751
|
+
<div class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4">
|
|
752
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
753
|
+
Selected date
|
|
754
|
+
</p>
|
|
755
|
+
<p class="text-lg font-semibold">
|
|
756
|
+
{calendarValue ?? "No date yet"}
|
|
757
|
+
</p>
|
|
758
|
+
<p class="text-sm text-[var(--color-text-muted)] mt-2">
|
|
759
|
+
Plan: {radioGroup}
|
|
760
|
+
</p>
|
|
761
|
+
</div>
|
|
762
|
+
</div>
|
|
763
|
+
</div>
|
|
764
|
+
</Card>
|
|
765
|
+
</div>
|
|
766
|
+
|
|
767
|
+
{#snippet filesHeader()}
|
|
768
|
+
<div class="flex items-center justify-between gap-2">
|
|
769
|
+
<div>
|
|
770
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
771
|
+
Files
|
|
772
|
+
</p>
|
|
773
|
+
<h2 class="text-lg font-semibold leading-tight">Uploads and dialogs</h2>
|
|
774
|
+
</div>
|
|
775
|
+
<InstallPWA inline={true} alwaysShow={true} />
|
|
776
|
+
</div>
|
|
777
|
+
{/snippet}
|
|
778
|
+
|
|
779
|
+
{#snippet formGeneratorHeader()}
|
|
780
|
+
<div class="flex items-center justify-between gap-2">
|
|
781
|
+
<div>
|
|
782
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
783
|
+
Form
|
|
784
|
+
</p>
|
|
785
|
+
<h2 class="text-lg font-semibold leading-tight">Schema-driven form</h2>
|
|
786
|
+
</div>
|
|
787
|
+
</div>
|
|
788
|
+
{/snippet}
|
|
789
|
+
|
|
790
|
+
<div class="grid gap-6 lg:grid-cols-2">
|
|
791
|
+
<Card header={filesHeader}>
|
|
792
|
+
<div class="space-y-4">
|
|
793
|
+
<FilePicker
|
|
794
|
+
value={fileList}
|
|
795
|
+
onFilesSelected={(files) => (fileList = files)}
|
|
796
|
+
accept="image/*,.pdf"
|
|
797
|
+
/>
|
|
798
|
+
|
|
799
|
+
<div class="flex items-center justify-between rounded-xl border border-[var(--border-color-default)] px-4 py-3">
|
|
800
|
+
<div>
|
|
801
|
+
<p class="text-sm font-medium">Confirm release</p>
|
|
802
|
+
<p class="text-xs text-[var(--color-text-muted)]">
|
|
803
|
+
Last file: {fileList?.[0]?.name ?? "none"}
|
|
804
|
+
</p>
|
|
805
|
+
</div>
|
|
806
|
+
<Button variant="primary" onClick={() => (dialogOpen = true)} sz="sm">
|
|
807
|
+
Open dialog
|
|
808
|
+
</Button>
|
|
809
|
+
</div>
|
|
810
|
+
</div>
|
|
811
|
+
</Card>
|
|
812
|
+
|
|
813
|
+
<Card header={formGeneratorHeader}>
|
|
814
|
+
<div class="space-y-4">
|
|
815
|
+
<Form
|
|
816
|
+
schema={miniFormSchema}
|
|
817
|
+
onSubmit={handleMiniSubmit}
|
|
818
|
+
validateOn="submit"
|
|
819
|
+
/>
|
|
820
|
+
<div class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-3">
|
|
821
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
822
|
+
Last submit
|
|
823
|
+
</p>
|
|
824
|
+
<pre class="text-xs whitespace-pre-wrap text-[var(--color-text-default)]">
|
|
825
|
+
{formResult}
|
|
826
|
+
</pre>
|
|
827
|
+
</div>
|
|
828
|
+
</div>
|
|
829
|
+
</Card>
|
|
830
|
+
</div>
|
|
831
|
+
|
|
832
|
+
{#snippet menuHeader()}
|
|
833
|
+
<div class="flex items-center justify-between gap-2">
|
|
834
|
+
<div>
|
|
835
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
836
|
+
Menu
|
|
837
|
+
</p>
|
|
838
|
+
<h2 class="text-lg font-semibold leading-tight">Navigation controls</h2>
|
|
839
|
+
</div>
|
|
840
|
+
</div>
|
|
841
|
+
{/snippet}
|
|
842
|
+
|
|
843
|
+
{#snippet layoutHeader()}
|
|
844
|
+
<div class="flex items-center justify-between gap-2">
|
|
845
|
+
<div>
|
|
846
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
847
|
+
Layout
|
|
848
|
+
</p>
|
|
849
|
+
<h2 class="text-lg font-semibold leading-tight">Splitter + context menu</h2>
|
|
850
|
+
</div>
|
|
851
|
+
</div>
|
|
852
|
+
{/snippet}
|
|
853
|
+
|
|
854
|
+
{#snippet firstPane()}
|
|
855
|
+
<div class="h-full grid place-items-center text-sm font-medium">
|
|
856
|
+
First panel
|
|
857
|
+
</div>
|
|
858
|
+
{/snippet}
|
|
859
|
+
|
|
860
|
+
{#snippet secondPane()}
|
|
861
|
+
<div class="h-full grid place-items-center text-sm font-medium">
|
|
862
|
+
Second panel
|
|
863
|
+
</div>
|
|
864
|
+
{/snippet}
|
|
865
|
+
|
|
866
|
+
<div class="grid gap-6 lg:grid-cols-2">
|
|
867
|
+
<Card header={menuHeader}>
|
|
868
|
+
<div class="space-y-4">
|
|
869
|
+
<Menu menus={menuData} sz={menuSize} onSelect={handleMenuSelect} />
|
|
870
|
+
|
|
871
|
+
<div class="text-sm text-[var(--color-text-muted)]">
|
|
872
|
+
{menuSelection}
|
|
873
|
+
</div>
|
|
874
|
+
|
|
875
|
+
<div class="rounded-xl border border-[var(--border-color-default)] p-4">
|
|
876
|
+
<Pagination
|
|
877
|
+
currentPage={standalonePage}
|
|
878
|
+
totalPages={standaloneTotal}
|
|
879
|
+
onPageChange={(p) => (standalonePage = p)}
|
|
880
|
+
/>
|
|
881
|
+
</div>
|
|
882
|
+
|
|
883
|
+
{#snippet pageOne()}
|
|
884
|
+
<div class="p-4 rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)]">
|
|
885
|
+
<p class="text-sm font-medium">Release notes</p>
|
|
886
|
+
<p class="text-xs text-[var(--color-text-muted)]">
|
|
887
|
+
Snapshot of changes across components.
|
|
888
|
+
</p>
|
|
889
|
+
</div>
|
|
890
|
+
{/snippet}
|
|
891
|
+
{#snippet pageTwo()}
|
|
892
|
+
<div class="p-4 rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)]">
|
|
893
|
+
<p class="text-sm font-medium">Design tasks</p>
|
|
894
|
+
<p class="text-xs text-[var(--color-text-muted)]">
|
|
895
|
+
Review tokens and spacing.
|
|
896
|
+
</p>
|
|
897
|
+
</div>
|
|
898
|
+
{/snippet}
|
|
899
|
+
{#snippet pageThree()}
|
|
900
|
+
<div class="p-4 rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)]">
|
|
901
|
+
<p class="text-sm font-medium">QA checklist</p>
|
|
902
|
+
<p class="text-xs text-[var(--color-text-muted)]">
|
|
903
|
+
Validate keyboard and focus behavior.
|
|
904
|
+
</p>
|
|
905
|
+
</div>
|
|
906
|
+
{/snippet}
|
|
907
|
+
|
|
908
|
+
<PaginatedCard
|
|
909
|
+
items={[pageOne, pageTwo, pageThree]}
|
|
910
|
+
itemsPerPage={1}
|
|
911
|
+
/>
|
|
912
|
+
</div>
|
|
913
|
+
</Card>
|
|
914
|
+
|
|
915
|
+
<Card header={layoutHeader}>
|
|
916
|
+
<div class="space-y-4">
|
|
917
|
+
<div class="h-56 rounded-xl border border-[var(--border-color-default)] overflow-hidden">
|
|
918
|
+
<Splitter
|
|
919
|
+
direction="horizontal"
|
|
920
|
+
initialSize={45}
|
|
921
|
+
dividerSize={6}
|
|
922
|
+
minSize={20}
|
|
923
|
+
maxSize={80}
|
|
924
|
+
first={firstPane}
|
|
925
|
+
second={secondPane}
|
|
926
|
+
/>
|
|
927
|
+
</div>
|
|
928
|
+
|
|
929
|
+
<div
|
|
930
|
+
class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4 text-sm text-[var(--color-text-muted)]"
|
|
931
|
+
oncontextmenu={(e) => contextMenuRef?.openAt(e)}
|
|
932
|
+
role="button"
|
|
933
|
+
tabindex="0"
|
|
934
|
+
>
|
|
935
|
+
{contextMenuStatus}
|
|
936
|
+
</div>
|
|
937
|
+
|
|
938
|
+
<ContextMenu
|
|
939
|
+
bind:this={contextMenuRef}
|
|
940
|
+
onUndo={() => handleContextAction("Undo", "info")}
|
|
941
|
+
onRedo={() => handleContextAction("Redo", "info")}
|
|
942
|
+
onCopy={() => handleContextAction("Copy", "success")}
|
|
943
|
+
onCut={() => handleContextAction("Cut", "warning")}
|
|
944
|
+
onPaste={() => handleContextAction("Paste", "success")}
|
|
945
|
+
onDelete={() => handleContextAction("Delete", "danger")}
|
|
946
|
+
/>
|
|
947
|
+
</div>
|
|
948
|
+
</Card>
|
|
949
|
+
</div>
|
|
950
|
+
|
|
951
|
+
{#snippet codeHeader()}
|
|
952
|
+
<div class="flex items-center justify-between gap-2">
|
|
953
|
+
<div>
|
|
954
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
955
|
+
Code
|
|
956
|
+
</p>
|
|
957
|
+
<h2 class="text-lg font-semibold leading-tight">CodeView editor</h2>
|
|
958
|
+
</div>
|
|
959
|
+
<Switch
|
|
960
|
+
checked={codeEditable}
|
|
961
|
+
onChange={(v) => (codeEditable = v)}
|
|
962
|
+
rightLabel={codeEditable ? "Editable" : "Read only"}
|
|
963
|
+
sz="sm"
|
|
964
|
+
/>
|
|
965
|
+
</div>
|
|
966
|
+
{/snippet}
|
|
967
|
+
|
|
968
|
+
{#snippet quickHeader()}
|
|
969
|
+
<div class="flex items-center justify-between gap-2">
|
|
970
|
+
<div>
|
|
971
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
972
|
+
Actions
|
|
973
|
+
</p>
|
|
974
|
+
<h2 class="text-lg font-semibold leading-tight">Quick actions</h2>
|
|
975
|
+
</div>
|
|
976
|
+
</div>
|
|
977
|
+
{/snippet}
|
|
978
|
+
|
|
979
|
+
<div class="grid gap-6 lg:grid-cols-2">
|
|
980
|
+
<Card header={codeHeader} class="min-h-[360px]">
|
|
981
|
+
<CodeView
|
|
982
|
+
bind:code={codeSample}
|
|
983
|
+
language="js"
|
|
984
|
+
title="tokens.js"
|
|
985
|
+
showCopyButton={true}
|
|
986
|
+
showLineNumbers={true}
|
|
987
|
+
editable={codeEditable}
|
|
988
|
+
activeLine={true}
|
|
989
|
+
class="h-[320px]"
|
|
990
|
+
/>
|
|
991
|
+
</Card>
|
|
992
|
+
|
|
993
|
+
<Card header={quickHeader}>
|
|
994
|
+
<div class="space-y-4">
|
|
995
|
+
<div class="flex flex-wrap gap-2">
|
|
996
|
+
<Button variant="secondary" onClick={() => pushToast("info")}>
|
|
997
|
+
Notify
|
|
998
|
+
</Button>
|
|
999
|
+
<Button variant="success" onClick={() => pushToast("success")}>
|
|
1000
|
+
Success
|
|
1001
|
+
</Button>
|
|
1002
|
+
<Button variant="danger" onClick={() => pushToast("danger")}>
|
|
1003
|
+
Error
|
|
1004
|
+
</Button>
|
|
1005
|
+
</div>
|
|
1006
|
+
|
|
1007
|
+
<div class="rounded-xl border border-[var(--border-color-default)] bg-[var(--color-bg-surface)] p-4">
|
|
1008
|
+
<p class="text-xs uppercase tracking-[0.15em] text-[var(--color-text-muted)]">
|
|
1009
|
+
Active nav
|
|
1010
|
+
</p>
|
|
1011
|
+
<p class="text-lg font-semibold">{activeNav}</p>
|
|
1012
|
+
<p class="text-sm text-[var(--color-text-muted)]">
|
|
1013
|
+
Search: {searchQuery || "empty"}
|
|
1014
|
+
</p>
|
|
1015
|
+
</div>
|
|
1016
|
+
</div>
|
|
1017
|
+
</Card>
|
|
1018
|
+
</div>
|
|
1019
|
+
|
|
1020
|
+
<Dialog
|
|
1021
|
+
open={dialogOpen}
|
|
1022
|
+
title="Confirm release"
|
|
1023
|
+
message="Ready to ship the selected files?"
|
|
1024
|
+
onConfirm={() => {
|
|
1025
|
+
dialogOpen = false;
|
|
1026
|
+
pushToast("success");
|
|
1027
|
+
}}
|
|
1028
|
+
onCancel={() => {
|
|
1029
|
+
dialogOpen = false;
|
|
1030
|
+
}}
|
|
1031
|
+
onClose={() => {
|
|
1032
|
+
dialogOpen = false;
|
|
1033
|
+
}}
|
|
1034
|
+
/>
|
|
1035
|
+
</div>
|
|
1036
|
+
|
|
1037
|
+
{#each toasts as toast (toast.id)}
|
|
1038
|
+
<Toast
|
|
1039
|
+
title={toast.title}
|
|
1040
|
+
message={toast.message}
|
|
1041
|
+
variant={toast.variant}
|
|
1042
|
+
onClose={() => removeToast(toast.id)}
|
|
1043
|
+
timeout={3500}
|
|
1044
|
+
/>
|
|
1045
|
+
{/each}
|
|
1046
|
+
</Container>
|