@runwisp/ui 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/LICENSE +215 -0
  2. package/README.md +20 -0
  3. package/package.json +128 -0
  4. package/src/app.d.ts +8 -0
  5. package/src/app.html +12 -0
  6. package/src/astro/CTABand.astro +32 -0
  7. package/src/astro/Hero.astro +58 -0
  8. package/src/astro/SiteFooter.astro +47 -0
  9. package/src/astro/SiteHeader.astro +46 -0
  10. package/src/lib/actions/portal.ts +16 -0
  11. package/src/lib/assets/runwisp-logo.svg +16 -0
  12. package/src/lib/components/Accordion.svelte +20 -0
  13. package/src/lib/components/AccordionItem.svelte +74 -0
  14. package/src/lib/components/Alert.svelte +107 -0
  15. package/src/lib/components/AlertDialog.svelte +63 -0
  16. package/src/lib/components/Avatar.svelte +88 -0
  17. package/src/lib/components/Badge.svelte +131 -0
  18. package/src/lib/components/Breadcrumb.svelte +58 -0
  19. package/src/lib/components/Button.svelte +69 -0
  20. package/src/lib/components/Card.svelte +70 -0
  21. package/src/lib/components/Checkbox.svelte +90 -0
  22. package/src/lib/components/CodeBlock.svelte +66 -0
  23. package/src/lib/components/CronInput.svelte +130 -0
  24. package/src/lib/components/DataGrid.svelte +368 -0
  25. package/src/lib/components/Drawer.svelte +156 -0
  26. package/src/lib/components/Dropdown.svelte +195 -0
  27. package/src/lib/components/DurationInput.svelte +170 -0
  28. package/src/lib/components/EmptyState.svelte +46 -0
  29. package/src/lib/components/ErrorState.svelte +73 -0
  30. package/src/lib/components/FeatureCard.svelte +35 -0
  31. package/src/lib/components/FeatureGrid.svelte +37 -0
  32. package/src/lib/components/FormField.svelte +53 -0
  33. package/src/lib/components/Heading.svelte +46 -0
  34. package/src/lib/components/Input.svelte +114 -0
  35. package/src/lib/components/Kbd.svelte +31 -0
  36. package/src/lib/components/Link.svelte +56 -0
  37. package/src/lib/components/LinkButton.svelte +55 -0
  38. package/src/lib/components/LogConsole.svelte +424 -0
  39. package/src/lib/components/Logo.svelte +34 -0
  40. package/src/lib/components/Modal.svelte +138 -0
  41. package/src/lib/components/PageContainer.svelte +38 -0
  42. package/src/lib/components/Pagination.svelte +96 -0
  43. package/src/lib/components/Popover.svelte +130 -0
  44. package/src/lib/components/Progress.svelte +68 -0
  45. package/src/lib/components/Prose.svelte +43 -0
  46. package/src/lib/components/Radio.svelte +82 -0
  47. package/src/lib/components/RadioGroup.svelte +53 -0
  48. package/src/lib/components/Select.svelte +454 -0
  49. package/src/lib/components/Separator.svelte +30 -0
  50. package/src/lib/components/Skeleton.svelte +75 -0
  51. package/src/lib/components/Sparkline.svelte +58 -0
  52. package/src/lib/components/Spinner.svelte +44 -0
  53. package/src/lib/components/StatusIndicator.svelte +203 -0
  54. package/src/lib/components/Table.svelte +19 -0
  55. package/src/lib/components/TableBody.svelte +17 -0
  56. package/src/lib/components/TableCell.svelte +34 -0
  57. package/src/lib/components/TableHead.svelte +19 -0
  58. package/src/lib/components/TableRow.svelte +22 -0
  59. package/src/lib/components/Tabs.svelte +148 -0
  60. package/src/lib/components/Text.svelte +57 -0
  61. package/src/lib/components/Textarea.svelte +81 -0
  62. package/src/lib/components/ThemeToggle.svelte +47 -0
  63. package/src/lib/components/TimezoneSelect.svelte +127 -0
  64. package/src/lib/components/ToastContainer.svelte +84 -0
  65. package/src/lib/components/Toggle.svelte +84 -0
  66. package/src/lib/components/Tooltip.svelte +56 -0
  67. package/src/lib/components/button-styles.ts +51 -0
  68. package/src/lib/components/dashboard/RunDetailPanel.svelte +252 -0
  69. package/src/lib/components/dashboard/RunsList.svelte +331 -0
  70. package/src/lib/components/dashboard/run-helpers.ts +12 -0
  71. package/src/lib/components/dashboard/status-config.ts +141 -0
  72. package/src/lib/components/dashboard/types.ts +35 -0
  73. package/src/lib/index.ts +122 -0
  74. package/src/lib/log-console/LogCache.svelte.ts +93 -0
  75. package/src/lib/log-console/LogFetcher.svelte.ts +179 -0
  76. package/src/lib/log-console/types.ts +24 -0
  77. package/src/lib/theme-tokens.css +235 -0
  78. package/src/lib/theme.css +276 -0
  79. package/src/lib/utils/error.ts +18 -0
  80. package/src/lib/utils/format.ts +76 -0
  81. package/src/lib/utils/id.ts +6 -0
  82. package/src/lib/utils/toast.svelte.ts +87 -0
  83. package/src/lib/utils/toast.ts +60 -0
  84. package/src/routes/+layout.svelte +10 -0
  85. package/src/routes/+page.svelte +5 -0
  86. package/src/routes/layout.css +3 -0
  87. package/src/stories/Alert.stories.svelte +64 -0
  88. package/src/stories/Avatar.stories.svelte +76 -0
  89. package/src/stories/Badge.stories.svelte +76 -0
  90. package/src/stories/Breadcrumb.stories.svelte +64 -0
  91. package/src/stories/Button.stories.svelte +101 -0
  92. package/src/stories/Card.stories.svelte +106 -0
  93. package/src/stories/Checkbox.stories.svelte +77 -0
  94. package/src/stories/DataGrid.stories.svelte +130 -0
  95. package/src/stories/Dropdown.stories.svelte +81 -0
  96. package/src/stories/EmptyState.stories.svelte +74 -0
  97. package/src/stories/Input.stories.svelte +88 -0
  98. package/src/stories/Logo.stories.svelte +82 -0
  99. package/src/stories/Modal.stories.svelte +101 -0
  100. package/src/stories/Progress.stories.svelte +65 -0
  101. package/src/stories/Select.stories.svelte +158 -0
  102. package/src/stories/Tabs.stories.svelte +103 -0
  103. package/src/stories/Textarea.stories.svelte +45 -0
  104. package/src/stories/Toggle.stories.svelte +74 -0
  105. package/src/stories/Tooltip.stories.svelte +77 -0
  106. package/src/stories/Welcome.mdx +241 -0
  107. package/src/stories/assets/runwisp_c.svg +16 -0
  108. package/src/svelte-shims.d.ts +18 -0
@@ -0,0 +1,74 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import EmptyState from "$lib/components/EmptyState.svelte";
7
+ import Button from "$lib/components/Button.svelte";
8
+ import { Calendar, Search, TriangleAlert, Plus, RefreshCw } from "@lucide/svelte";
9
+
10
+ const { Story } = defineMeta({
11
+ title: "Core/EmptyState",
12
+ component: EmptyState,
13
+ tags: ["autodocs"],
14
+ });
15
+ </script>
16
+
17
+ <Story name="Default" args={{ title: "No data", description: "There's nothing here yet." }} />
18
+
19
+ <Story name="No Tasks" asChild>
20
+ <EmptyState
21
+ icon={Calendar}
22
+ title="No scheduled tasks"
23
+ description="Create your first scheduled task to start automating tasks."
24
+ >
25
+ {#snippet actions()}
26
+ <Button variant="primary">
27
+ {#snippet icon()}<Plus size={16} />{/snippet}
28
+ Create Task
29
+ </Button>
30
+ {/snippet}
31
+ </EmptyState>
32
+ </Story>
33
+
34
+ <Story name="No Search Results" asChild>
35
+ <EmptyState
36
+ icon={Search}
37
+ title="No results found"
38
+ description="Try adjusting your search terms or filters to find what you're looking for."
39
+ >
40
+ {#snippet actions()}
41
+ <Button variant="secondary">Clear Filters</Button>
42
+ {/snippet}
43
+ </EmptyState>
44
+ </Story>
45
+
46
+ <Story name="Error State" asChild>
47
+ <EmptyState
48
+ icon={TriangleAlert}
49
+ title="Something went wrong"
50
+ description="We couldn't load the data. Please try again or contact support if the problem persists."
51
+ >
52
+ {#snippet actions()}
53
+ <Button variant="primary">
54
+ {#snippet icon()}<RefreshCw size={16} />{/snippet}
55
+ Try Again
56
+ </Button>
57
+ <Button variant="ghost">Contact Support</Button>
58
+ {/snippet}
59
+ </EmptyState>
60
+ </Story>
61
+
62
+ <Story name="In Card Context" asChild>
63
+ <div class="max-w-lg rounded-xl border border-mist-200 bg-white p-6">
64
+ <EmptyState
65
+ icon={Calendar}
66
+ title="No upcoming executions"
67
+ description="All scheduled tasks are either paused or have completed."
68
+ >
69
+ {#snippet actions()}
70
+ <Button variant="secondary" size="sm">View All Tasks</Button>
71
+ {/snippet}
72
+ </EmptyState>
73
+ </div>
74
+ </Story>
@@ -0,0 +1,88 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Input from "$lib/components/Input.svelte";
7
+ import { Search, Mail, Lock, User, Calendar, Clock } from "@lucide/svelte";
8
+
9
+ const { Story } = defineMeta({
10
+ title: "Forms/Input",
11
+ component: Input,
12
+ tags: ["autodocs"],
13
+ argTypes: {
14
+ size: {
15
+ control: "select",
16
+ options: ["sm", "md", "lg"],
17
+ },
18
+ },
19
+ });
20
+ </script>
21
+
22
+ <Story name="Default" args={{ placeholder: "Enter text..." }} />
23
+
24
+ <Story name="With Label" args={{ label: "Task Name", placeholder: "my-scheduled-task" }} />
25
+
26
+ <Story
27
+ name="With Hint"
28
+ args={{
29
+ label: "Cron Expression",
30
+ placeholder: "*/5 * * * *",
31
+ hint: "Use standard cron syntax. Minimum interval is 1 minute.",
32
+ }}
33
+ />
34
+
35
+ <Story
36
+ name="With Error"
37
+ args={{
38
+ label: "Email Address",
39
+ placeholder: "user@example.com",
40
+ value: "invalid-email",
41
+ error: "Please enter a valid email address",
42
+ }}
43
+ />
44
+
45
+ <Story name="With Icons" asChild>
46
+ <div class="max-w-sm space-y-4">
47
+ <Input placeholder="Search tasks...">
48
+ {#snippet leadingIcon()}<Search size={18} />{/snippet}
49
+ </Input>
50
+ <Input label="Email" type="email" placeholder="you@example.com">
51
+ {#snippet leadingIcon()}<Mail size={18} />{/snippet}
52
+ </Input>
53
+ <Input label="Password" type="password" placeholder="Enter password">
54
+ {#snippet leadingIcon()}<Lock size={18} />{/snippet}
55
+ </Input>
56
+ <Input label="Username" placeholder="Enter username">
57
+ {#snippet leadingIcon()}<User size={18} />{/snippet}
58
+ </Input>
59
+ </div>
60
+ </Story>
61
+
62
+ <Story name="Sizes" asChild>
63
+ <div class="max-w-sm space-y-4">
64
+ <Input size="sm" label="Small" placeholder="Small input" />
65
+ <Input size="md" label="Medium" placeholder="Medium input (default)" />
66
+ <Input size="lg" label="Large" placeholder="Large input" />
67
+ </div>
68
+ </Story>
69
+
70
+ <Story
71
+ name="Disabled"
72
+ args={{ label: "Disabled Input", value: "Cannot edit this", disabled: true }}
73
+ />
74
+
75
+ <Story name="Input Types" asChild>
76
+ <div class="max-w-sm space-y-4">
77
+ <Input label="Text" type="text" placeholder="Regular text" />
78
+ <Input label="Email" type="email" placeholder="user@example.com" />
79
+ <Input label="Password" type="password" placeholder="••••••••" />
80
+ <Input label="Number" type="number" placeholder="0" />
81
+ <Input label="Date" type="date">
82
+ {#snippet leadingIcon()}<Calendar size={18} />{/snippet}
83
+ </Input>
84
+ <Input label="Time" type="time">
85
+ {#snippet leadingIcon()}<Clock size={18} />{/snippet}
86
+ </Input>
87
+ </div>
88
+ </Story>
@@ -0,0 +1,82 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Logo from "$lib/components/Logo.svelte";
7
+
8
+ const { Story } = defineMeta({
9
+ title: "Brand/Logo",
10
+ component: Logo,
11
+ tags: ["autodocs"],
12
+ argTypes: {
13
+ size: {
14
+ control: "select",
15
+ options: ["xs", "sm", "md", "lg", "xl"],
16
+ },
17
+ },
18
+ });
19
+ </script>
20
+
21
+ <Story name="Default" args={{}} />
22
+
23
+ <Story name="Sizes" asChild>
24
+ <div class="flex items-center gap-8 rounded-lg bg-mist-50 p-8">
25
+ <div class="flex flex-col items-center gap-2">
26
+ <Logo size="xs" />
27
+ <span class="text-xs text-mist-600">XS</span>
28
+ </div>
29
+ <div class="flex flex-col items-center gap-2">
30
+ <Logo size="sm" />
31
+ <span class="text-xs text-mist-600">SM</span>
32
+ </div>
33
+ <div class="flex flex-col items-center gap-2">
34
+ <Logo size="md" />
35
+ <span class="text-xs text-mist-600">MD</span>
36
+ </div>
37
+ <div class="flex flex-col items-center gap-2">
38
+ <Logo size="lg" />
39
+ <span class="text-xs text-mist-600">LG</span>
40
+ </div>
41
+ <div class="flex flex-col items-center gap-2">
42
+ <Logo size="xl" />
43
+ <span class="text-xs text-mist-600">XL</span>
44
+ </div>
45
+ </div>
46
+ </Story>
47
+
48
+ <Story name="On Gradient Background" asChild>
49
+ <div
50
+ class="flex items-center gap-4 rounded-lg bg-gradient-to-br from-wisp-500 to-aurora-500 p-8 text-white"
51
+ >
52
+ <Logo size="lg" />
53
+ <span class="text-2xl font-bold">RunWisp</span>
54
+ </div>
55
+ </Story>
56
+
57
+ <Story name="Dark Background" asChild>
58
+ <div class="flex items-center gap-4 rounded-lg bg-mist-900 p-8 text-white">
59
+ <Logo size="lg" />
60
+ <span class="text-2xl font-bold">RunWisp</span>
61
+ </div>
62
+ </Story>
63
+
64
+ <Story name="With Custom Class" asChild>
65
+ <div class="flex items-center gap-4 rounded-lg bg-mist-50 p-8">
66
+ <Logo size="lg" class="text-wisp-600" />
67
+ <span class="text-lg font-semibold text-mist-900">Custom Color</span>
68
+ </div>
69
+ </Story>
70
+
71
+ <Story name="In Header Style" asChild>
72
+ <div
73
+ class="flex items-center gap-4 rounded-lg bg-gradient-to-br from-wisp-500 to-aurora-500 p-4 text-white"
74
+ >
75
+ <div
76
+ class="flex h-8 w-8 items-center justify-center rounded-lg bg-white/20 backdrop-blur-sm"
77
+ >
78
+ <Logo size="sm" />
79
+ </div>
80
+ <span class="text-lg font-semibold">RunWisp</span>
81
+ </div>
82
+ </Story>
@@ -0,0 +1,101 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Modal from "$lib/components/Modal.svelte";
7
+ import Button from "$lib/components/Button.svelte";
8
+ import Input from "$lib/components/Input.svelte";
9
+ import Select from "$lib/components/Select.svelte";
10
+
11
+ const { Story } = defineMeta({
12
+ title: "Core/Modal",
13
+ component: Modal,
14
+ tags: ["autodocs"],
15
+ argTypes: {
16
+ size: {
17
+ control: "select",
18
+ options: ["sm", "md", "lg", "xl", "full"],
19
+ },
20
+ },
21
+ });
22
+
23
+ let basicOpen = $state(false);
24
+ let formOpen = $state(false);
25
+ let confirmOpen = $state(false);
26
+ let largeOpen = $state(false);
27
+
28
+ const scheduleTypes = [
29
+ { value: "cron", label: "Cron Expression" },
30
+ { value: "interval", label: "Fixed Interval" },
31
+ ];
32
+ </script>
33
+
34
+ <Story name="Basic" asChild>
35
+ <Button onclick={() => (basicOpen = true)}>Open Modal</Button>
36
+ <Modal
37
+ bind:open={basicOpen}
38
+ title="Modal Title"
39
+ description="This is a description of the modal."
40
+ >
41
+ <p class="text-mist-600">This is the modal content. You can put any content here.</p>
42
+ </Modal>
43
+ </Story>
44
+
45
+ <Story name="With Form" asChild>
46
+ <Button onclick={() => (formOpen = true)}>Create New Task</Button>
47
+ <Modal bind:open={formOpen} title="Create New Task" size="lg">
48
+ <div class="space-y-4">
49
+ <Input label="Task Name" placeholder="my-scheduled-task" />
50
+ <Select label="Schedule Type" options={scheduleTypes} placeholder="Select type..." />
51
+ <Input label="Cron Expression" placeholder="*/5 * * * *" hint="Standard cron syntax" />
52
+ </div>
53
+ {#snippet footer()}
54
+ <div class="flex justify-end gap-3">
55
+ <Button variant="ghost" onclick={() => (formOpen = false)}>Cancel</Button>
56
+ <Button variant="primary">Create Task</Button>
57
+ </div>
58
+ {/snippet}
59
+ </Modal>
60
+ </Story>
61
+
62
+ <Story name="Confirmation Dialog" asChild>
63
+ <Button variant="danger" onclick={() => (confirmOpen = true)}>Delete Task</Button>
64
+ <Modal bind:open={confirmOpen} title="Delete Task?" size="sm">
65
+ <p class="text-mist-600">
66
+ Are you sure you want to delete <strong>backup-database</strong>? This action cannot be
67
+ undone.
68
+ </p>
69
+ {#snippet footer()}
70
+ <div class="flex justify-end gap-3">
71
+ <Button variant="ghost" onclick={() => (confirmOpen = false)}>Cancel</Button>
72
+ <Button variant="danger" onclick={() => (confirmOpen = false)}>Delete</Button>
73
+ </div>
74
+ {/snippet}
75
+ </Modal>
76
+ </Story>
77
+
78
+ <Story name="Large Modal" asChild>
79
+ <Button onclick={() => (largeOpen = true)}>View Task Logs</Button>
80
+ <Modal bind:open={largeOpen} title="Task Execution Logs" size="full">
81
+ <div
82
+ class="max-h-96 overflow-auto rounded-lg bg-mist-900 p-4 font-mono text-sm text-mist-100"
83
+ >
84
+ <p class="text-aurora-400">Starting task execution...</p>
85
+ <p class="text-mist-300">Connecting to database...</p>
86
+ <p class="text-mist-300">Connection established</p>
87
+ <p class="text-mist-300">Running backup query...</p>
88
+ <p class="text-mist-300">Processing 1,234 records...</p>
89
+ <p class="text-mist-300">Compressing backup file...</p>
90
+ <p class="text-mist-300">Uploading to storage...</p>
91
+ <p class="text-success-400">Task completed successfully</p>
92
+ <p class="text-mist-500">Total execution time: 90s</p>
93
+ </div>
94
+ {#snippet footer()}
95
+ <div class="flex justify-between">
96
+ <Button variant="ghost">Download Logs</Button>
97
+ <Button variant="primary" onclick={() => (largeOpen = false)}>Close</Button>
98
+ </div>
99
+ {/snippet}
100
+ </Modal>
101
+ </Story>
@@ -0,0 +1,65 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Progress from "$lib/components/Progress.svelte";
7
+
8
+ const { Story } = defineMeta({
9
+ title: "Core/Progress",
10
+ component: Progress,
11
+ tags: ["autodocs"],
12
+ argTypes: {
13
+ variant: {
14
+ control: "select",
15
+ options: ["default", "success", "warning", "danger"],
16
+ },
17
+ size: {
18
+ control: "select",
19
+ options: ["sm", "md", "lg"],
20
+ },
21
+ },
22
+ });
23
+ </script>
24
+
25
+ <Story name="Default" args={{ value: 65 }} />
26
+
27
+ <Story name="With Label" args={{ value: 75, showLabel: true, label: "Upload progress" }} />
28
+
29
+ <Story name="Variants" asChild>
30
+ <div class="max-w-md space-y-4">
31
+ <Progress value={80} label="Default" showLabel />
32
+ <Progress value={80} variant="success" label="Success" showLabel />
33
+ <Progress value={80} variant="warning" label="Warning" showLabel />
34
+ <Progress value={80} variant="danger" label="Danger" showLabel />
35
+ </div>
36
+ </Story>
37
+
38
+ <Story name="Sizes" asChild>
39
+ <div class="max-w-md space-y-4">
40
+ <Progress value={60} size="sm" label="Small" showLabel />
41
+ <Progress value={60} size="md" label="Medium" showLabel />
42
+ <Progress value={60} size="lg" label="Large" showLabel />
43
+ </div>
44
+ </Story>
45
+
46
+ <Story name="Usage Example" asChild>
47
+ <div class="max-w-md space-y-4 rounded-xl border border-mist-200 bg-white p-4">
48
+ <h3 class="font-semibold text-mist-900">Resource Usage</h3>
49
+ <Progress value={45} label="CPU Usage" showLabel />
50
+ <Progress value={72} label="Memory" showLabel variant="warning" />
51
+ <Progress value={23} label="Storage" showLabel variant="success" />
52
+ <Progress value={89} label="API Requests" showLabel variant="danger" />
53
+ </div>
54
+ </Story>
55
+
56
+ <Story name="Task Execution Progress" asChild>
57
+ <div class="max-w-md space-y-4 rounded-xl border border-mist-200 bg-white p-4">
58
+ <div class="flex items-center justify-between">
59
+ <h3 class="font-semibold text-mist-900">backup-database</h3>
60
+ <span class="text-sm text-mist-500">Running...</span>
61
+ </div>
62
+ <Progress value={67} showLabel />
63
+ <p class="text-sm text-mist-500">Processing 847 of 1,234 records</p>
64
+ </div>
65
+ </Story>
@@ -0,0 +1,158 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Select from "$lib/components/Select.svelte";
7
+ import { Globe, Clock, Zap, Cloud, Cpu, Database } from "@lucide/svelte";
8
+
9
+ const { Story } = defineMeta({
10
+ title: "Forms/Select",
11
+ component: Select,
12
+ tags: ["autodocs"],
13
+ argTypes: {
14
+ size: {
15
+ control: "select",
16
+ options: ["sm", "md", "lg"],
17
+ },
18
+ searchable: {
19
+ control: "boolean",
20
+ },
21
+ disabled: {
22
+ control: "boolean",
23
+ },
24
+ },
25
+ });
26
+
27
+ const simpleOptions = [
28
+ { value: "option1", label: "Option 1" },
29
+ { value: "option2", label: "Option 2" },
30
+ { value: "option3", label: "Option 3" },
31
+ ];
32
+
33
+ const richOptions = [
34
+ {
35
+ value: "load-balanced",
36
+ label: "Load Balanced",
37
+ description: "Distribute tasks evenly across available runners based on load.",
38
+ icon: Zap,
39
+ },
40
+ {
41
+ value: "round-robin",
42
+ label: "Round Robin",
43
+ description: "Cycle through runners sequentially.",
44
+ icon: Clock,
45
+ },
46
+ {
47
+ value: "geodistributed",
48
+ label: "Geo-Distributed",
49
+ description: "Route to the nearest available daemon.",
50
+ icon: Globe,
51
+ },
52
+ {
53
+ value: "fan-out",
54
+ label: "Fan Out",
55
+ description: "Execute on all connected runners simultaneously.",
56
+ icon: Database,
57
+ disabled: true,
58
+ },
59
+ ];
60
+
61
+ const groupedOptions = [
62
+ { value: "us-east-1", label: "US East (N. Virginia)", group: "Americas", icon: Cloud },
63
+ { value: "us-west-1", label: "US West (N. California)", group: "Americas", icon: Cloud },
64
+ { value: "eu-west-1", label: "EU (Ireland)", group: "Europe", icon: Globe },
65
+ { value: "eu-central-1", label: "EU (Frankfurt)", group: "Europe", icon: Globe },
66
+ {
67
+ value: "ap-southeast-1",
68
+ label: "Asia Pacific (Singapore)",
69
+ group: "Asia Pacific",
70
+ icon: Globe,
71
+ },
72
+ {
73
+ value: "ap-northeast-1",
74
+ label: "Asia Pacific (Tokyo)",
75
+ group: "Asia Pacific",
76
+ icon: Globe,
77
+ },
78
+ { value: "local", label: "Local Machine", group: "Development", icon: Cpu },
79
+ ];
80
+ </script>
81
+
82
+ <Story
83
+ name="Default"
84
+ args={{
85
+ options: simpleOptions,
86
+ placeholder: "Select an option...",
87
+ }}
88
+ />
89
+
90
+ <Story
91
+ name="With Label & Hint"
92
+ args={{
93
+ label: "Deployment Strategy",
94
+ options: richOptions,
95
+ placeholder: "Choose strategy...",
96
+ hint: "Select how tasks are distributed to runners.",
97
+ }}
98
+ />
99
+
100
+ <Story
101
+ name="Searchable"
102
+ args={{
103
+ label: "Region",
104
+ options: groupedOptions,
105
+ searchable: true,
106
+ placeholder: "Search regions...",
107
+ description: "Filter by region name.",
108
+ }}
109
+ />
110
+
111
+ <Story
112
+ name="With Error"
113
+ args={{
114
+ label: "Required Field",
115
+ options: simpleOptions,
116
+ error: "This field is required.",
117
+ placeholder: "Select...",
118
+ }}
119
+ />
120
+
121
+ <Story name="Sizes" asChild>
122
+ <div class="max-w-sm space-y-6">
123
+ <Select size="sm" label="Small Size" options={simpleOptions} placeholder="Small" />
124
+ <Select
125
+ size="md"
126
+ label="Medium Size"
127
+ options={richOptions}
128
+ placeholder="Medium with Icons"
129
+ />
130
+ <Select
131
+ size="lg"
132
+ label="Large Size"
133
+ options={groupedOptions}
134
+ placeholder="Large with Groups"
135
+ searchable={true}
136
+ />
137
+ </div>
138
+ </Story>
139
+
140
+ <Story
141
+ name="Rich Content"
142
+ args={{
143
+ label: "Complex Selection",
144
+ options: richOptions,
145
+ placeholder: "Select with icons & descriptions...",
146
+ class: "max-w-md",
147
+ }}
148
+ />
149
+
150
+ <Story
151
+ name="Disabled"
152
+ args={{
153
+ label: "Disabled Input",
154
+ options: simpleOptions,
155
+ value: "option1",
156
+ disabled: true,
157
+ }}
158
+ />
@@ -0,0 +1,103 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Tabs from "$lib/components/Tabs.svelte";
7
+ import { Calendar, ListTodo, Activity, Settings } from "@lucide/svelte";
8
+
9
+ const { Story } = defineMeta({
10
+ title: "Core/Tabs",
11
+ component: Tabs,
12
+ tags: ["autodocs"],
13
+ argTypes: {
14
+ variant: {
15
+ control: "select",
16
+ options: ["underline", "pills", "enclosed"],
17
+ },
18
+ },
19
+ });
20
+
21
+ const basicTabs = [
22
+ { id: "overview", label: "Overview" },
23
+ { id: "details", label: "Details" },
24
+ { id: "logs", label: "Logs" },
25
+ { id: "settings", label: "Settings" },
26
+ ];
27
+
28
+ const iconTabs = [
29
+ { id: "schedules", label: "Schedules", icon: Calendar },
30
+ { id: "tasks", label: "Tasks", icon: ListTodo, badge: 3 },
31
+ { id: "monitoring", label: "Monitoring", icon: Activity },
32
+ { id: "settings", label: "Settings", icon: Settings },
33
+ ];
34
+
35
+ const disabledTabs = [
36
+ { id: "active", label: "Active" },
37
+ { id: "completed", label: "Completed" },
38
+ { id: "failed", label: "Failed" },
39
+ { id: "archived", label: "Archived", disabled: true },
40
+ ];
41
+ </script>
42
+
43
+ <Story name="Underline (Default)" asChild>
44
+ <Tabs tabs={basicTabs} variant="underline">
45
+ {#snippet children(activeTab)}
46
+ <div class="rounded-lg border border-mist-200 bg-white p-4">
47
+ <p class="text-mist-600">Content for <strong>{activeTab}</strong> tab</p>
48
+ </div>
49
+ {/snippet}
50
+ </Tabs>
51
+ </Story>
52
+
53
+ <Story name="Pills" asChild>
54
+ <Tabs tabs={basicTabs} variant="pills">
55
+ {#snippet children(activeTab)}
56
+ <div class="rounded-lg border border-mist-200 bg-white p-4">
57
+ <p class="text-mist-600">Content for <strong>{activeTab}</strong> tab</p>
58
+ </div>
59
+ {/snippet}
60
+ </Tabs>
61
+ </Story>
62
+
63
+ <Story name="Enclosed" asChild>
64
+ <Tabs tabs={basicTabs} variant="enclosed">
65
+ {#snippet children(activeTab)}
66
+ <div class="rounded-lg border border-mist-200 bg-white p-4">
67
+ <p class="text-mist-600">Content for <strong>{activeTab}</strong> tab</p>
68
+ </div>
69
+ {/snippet}
70
+ </Tabs>
71
+ </Story>
72
+
73
+ <Story name="With Icons and Badges" asChild>
74
+ <Tabs tabs={iconTabs} variant="underline">
75
+ {#snippet children(activeTab)}
76
+ <div class="rounded-lg border border-mist-200 bg-white p-4">
77
+ <p class="text-mist-600">You're viewing the <strong>{activeTab}</strong> section</p>
78
+ </div>
79
+ {/snippet}
80
+ </Tabs>
81
+ </Story>
82
+
83
+ <Story name="Full Width" asChild>
84
+ <div class="max-w-md">
85
+ <Tabs tabs={basicTabs} variant="pills" fullWidth>
86
+ {#snippet children(activeTab)}
87
+ <div class="rounded-lg border border-mist-200 bg-white p-4">
88
+ <p class="text-mist-600">Content for <strong>{activeTab}</strong> tab</p>
89
+ </div>
90
+ {/snippet}
91
+ </Tabs>
92
+ </div>
93
+ </Story>
94
+
95
+ <Story name="With Disabled Tab" asChild>
96
+ <Tabs tabs={disabledTabs} variant="underline">
97
+ {#snippet children(activeTab)}
98
+ <div class="rounded-lg border border-mist-200 bg-white p-4">
99
+ <p class="text-mist-600">Showing <strong>{activeTab}</strong> tasks</p>
100
+ </div>
101
+ {/snippet}
102
+ </Tabs>
103
+ </Story>