@syscore/ui-library 1.27.3 → 2.0.0-beta-publish-workflow-beta.2

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 (169) hide show
  1. package/client/App.tsx +0 -2
  2. package/client/assets/alert/icon-clear.svg +4 -0
  3. package/client/assets/alert/icon-done.svg +3 -0
  4. package/client/assets/avatar-identity/photo.png +0 -0
  5. package/client/assets/avatar-identity/placeholder-icon.svg +8 -0
  6. package/client/assets/breadcrumb/icon-ellipsis.svg +5 -0
  7. package/client/assets/breadcrumb/icon-home.svg +3 -0
  8. package/client/assets/breadcrumb/icon-separator.svg +3 -0
  9. package/client/assets/button-v01/icon-back.svg +4 -0
  10. package/client/assets/button-v01/icon-check.svg +3 -0
  11. package/client/assets/button-v01/icon-close.svg +4 -0
  12. package/client/assets/button-v01/icon-delete.svg +3 -0
  13. package/client/assets/button-v01/icon-device.svg +3 -0
  14. package/client/assets/dropdown/icon-carrot-contract.svg +3 -0
  15. package/client/assets/dropdown/icon-carrot-expand.svg +3 -0
  16. package/client/assets/dropdown/icon-clear.svg +4 -0
  17. package/client/assets/dropdown/icon-enter.svg +3 -0
  18. package/client/components/icons/UtilityChangeType.tsx +21 -0
  19. package/client/components/ui/alert-dialog-panel.tsx +246 -0
  20. package/client/components/ui/alert-v02.tsx +214 -0
  21. package/client/components/ui/app-bar.tsx +299 -0
  22. package/client/components/ui/avatar-identity.tsx +122 -0
  23. package/client/components/ui/banner.tsx +108 -0
  24. package/client/components/ui/bottom-navigation.tsx +223 -0
  25. package/client/components/ui/breadcrumb-trail.tsx +170 -0
  26. package/client/components/ui/button-v01.tsx +238 -0
  27. package/client/components/ui/button.tsx +2 -0
  28. package/client/components/ui/card.tsx +108 -26
  29. package/client/components/ui/code-badge.tsx +62 -0
  30. package/client/components/ui/date-picker.tsx +188 -0
  31. package/client/components/ui/dropdown.tsx +448 -0
  32. package/client/components/ui/empty-state.tsx +197 -0
  33. package/client/components/ui/file-upload.tsx +214 -0
  34. package/client/components/ui/footer.tsx +179 -0
  35. package/client/components/ui/layout.tsx +1182 -0
  36. package/client/components/ui/pagination-v01.tsx +157 -0
  37. package/client/components/ui/password-field-v01.tsx +67 -0
  38. package/client/components/ui/search-field-v01.tsx +192 -0
  39. package/client/components/ui/section-heading.tsx +49 -0
  40. package/client/components/ui/sidebar.tsx +2 -3
  41. package/client/components/ui/standard-navigation.tsx +8 -2
  42. package/client/components/ui/stepper.tsx +148 -0
  43. package/client/components/ui/switch-v01.tsx +71 -0
  44. package/client/components/ui/system-bar.tsx +119 -0
  45. package/client/components/ui/table-v01.tsx +230 -0
  46. package/client/components/ui/tabs-v01.tsx +99 -0
  47. package/client/components/ui/tag-v02.tsx +113 -0
  48. package/client/components/ui/text-area-v01.tsx +33 -0
  49. package/client/components/ui/text-field-v01.tsx +108 -0
  50. package/client/components/ui/timeline.tsx +181 -0
  51. package/client/components/ui/toast-v01.tsx +206 -0
  52. package/client/components/ui/tooltip.tsx +264 -71
  53. package/client/global.css +9565 -4378
  54. package/client/storybook.css +125 -0
  55. package/client/ui/Accordion.stories.tsx +1 -1
  56. package/client/ui/AlertDialogPanel/AlertDialogPanel.stories.tsx +150 -0
  57. package/client/ui/AlertV02/AlertV02.stories.tsx +188 -0
  58. package/client/ui/AppBar/app-bar.stories.tsx +280 -0
  59. package/client/ui/AspectRatio.stories.tsx +1 -1
  60. package/client/ui/AvatarIdentity/AvatarIdentity.stories.tsx +77 -0
  61. package/client/ui/Banner/banner.stories.tsx +238 -0
  62. package/client/ui/BottomNavigation/bottom-navigation.stories.tsx +285 -0
  63. package/client/ui/BreadcrumbTrail/BreadcrumbTrail.stories.tsx +232 -0
  64. package/client/ui/Button.stories.tsx +1 -1
  65. package/client/ui/ButtonV01/ButtonV01.stories.tsx +417 -0
  66. package/client/ui/Calendar/Calendar.stories.tsx +1 -1
  67. package/client/ui/Card.stories.tsx +285 -168
  68. package/client/ui/Carousel/Carousel.stories.tsx +1 -1
  69. package/client/ui/Chart/Chart.stories.tsx +1 -1
  70. package/client/ui/Checkbox.stories.tsx +1 -1
  71. package/client/ui/Collapsible/Collapsible.stories.tsx +1 -1
  72. package/client/ui/Colors.stories.tsx +1 -1
  73. package/client/ui/Command/Command.stories.tsx +1 -1
  74. package/client/ui/ContextMenu/ContextMenu.stories.tsx +1 -1
  75. package/client/ui/DatePicker/DatePicker.stories.tsx +293 -0
  76. package/client/ui/Dialog.stories.tsx +1 -1
  77. package/client/ui/Drawer/Drawer.stories.tsx +1 -1
  78. package/client/ui/Dropdown/Dropdown.stories.tsx +205 -0
  79. package/client/ui/EmptyState/empty-state.stories.tsx +251 -0
  80. package/client/ui/FileUpload/FileUpload.stories.tsx +218 -0
  81. package/client/ui/Footer/footer.stories.tsx +194 -0
  82. package/client/ui/Form/Form.stories.tsx +1 -1
  83. package/client/ui/Hero.stories.tsx +1 -1
  84. package/client/ui/HoverCard/HoverCard.stories.tsx +1 -1
  85. package/client/ui/Icons.stories.tsx +1 -1
  86. package/client/ui/Input.stories.tsx +1 -1
  87. package/client/ui/InputOTP/InputOTP.stories.tsx +1 -1
  88. package/client/ui/Label.stories.tsx +1 -1
  89. package/client/ui/Layout/Center.stories.tsx +100 -0
  90. package/client/ui/Layout/Columns.stories.tsx +136 -0
  91. package/client/ui/Layout/Container.stories.tsx +104 -0
  92. package/client/ui/Layout/FormLayout.stories.tsx +144 -0
  93. package/client/ui/Layout/Grid.stories.tsx +158 -0
  94. package/client/ui/Layout/GridSpan.stories.tsx +75 -0
  95. package/client/ui/Layout/HStack.stories.tsx +128 -0
  96. package/client/ui/Layout/Layout.stories.tsx +287 -0
  97. package/client/ui/Layout/LayoutContent.stories.tsx +91 -0
  98. package/client/ui/Layout/LayoutFooter.stories.tsx +77 -0
  99. package/client/ui/Layout/LayoutHeader.stories.tsx +104 -0
  100. package/client/ui/Layout/LayoutPanel.stories.tsx +143 -0
  101. package/client/ui/Layout/Positioned.stories.tsx +113 -0
  102. package/client/ui/Layout/Section.stories.tsx +84 -0
  103. package/client/ui/Layout/ShowHide.stories.tsx +99 -0
  104. package/client/ui/Layout/Spacer.stories.tsx +149 -0
  105. package/client/ui/Layout/Stack.stories.tsx +69 -0
  106. package/client/ui/Layout/StackItem.stories.tsx +124 -0
  107. package/client/ui/Layout/VStack.stories.tsx +101 -0
  108. package/client/ui/Layout/controls.ts +33 -0
  109. package/client/ui/Layout/demo.tsx +37 -0
  110. package/client/ui/Menubar/Menubar.stories.tsx +1 -1
  111. package/client/ui/MobileNav.stories.tsx +1 -1
  112. package/client/ui/Navigation.stories.tsx +1 -1
  113. package/client/ui/NavigationMenu/NavigationMenu.stories.tsx +1 -1
  114. package/client/ui/PageHeader.stories.tsx +13 -13
  115. package/client/ui/Pagination/Pagination.stories.tsx +178 -98
  116. package/client/ui/Pagination/PaginationLegacy.stories.tsx +121 -0
  117. package/client/ui/Panel.stories.tsx +1 -1
  118. package/client/ui/Popover/Popover.stories.tsx +1 -1
  119. package/client/ui/Progress/Progress.stories.tsx +1 -1
  120. package/client/ui/RadioGroup/RadioGroup.stories.tsx +1 -1
  121. package/client/ui/Resizable/Resizable.stories.tsx +1 -1
  122. package/client/ui/ScrollArea/ScrollArea.stories.tsx +1 -1
  123. package/client/ui/SearchField/SearchField.stories.tsx +153 -0
  124. package/client/ui/{SearchField.stories.tsx → SearchField/SearchFieldLegacy.stories.tsx} +2 -2
  125. package/client/ui/SectionBadge.stories.tsx +1 -1
  126. package/client/ui/Select.stories.tsx +1 -1
  127. package/client/ui/Separator/Separator.stories.tsx +1 -1
  128. package/client/ui/Sheet/Sheet.stories.tsx +1 -1
  129. package/client/ui/Sidebar/Sidebar.stories.tsx +57 -8
  130. package/client/ui/Skeleton/Skeleton.stories.tsx +1 -1
  131. package/client/ui/Slider/Slider.stories.tsx +1 -1
  132. package/client/ui/StandardNavigation.stories.tsx +1 -1
  133. package/client/ui/Stepper/Stepper.stories.tsx +344 -0
  134. package/client/ui/Switch.stories.tsx +1 -1
  135. package/client/ui/SwitchV01/SwitchV01.stories.tsx +152 -0
  136. package/client/ui/SystemBar/system-bar.stories.tsx +179 -0
  137. package/client/ui/Table/TableV01.stories.tsx +256 -0
  138. package/client/ui/Tabs.stories.tsx +1 -1
  139. package/client/ui/TabsV01/TabsV01.stories.tsx +144 -0
  140. package/client/ui/Tag.stories.tsx +1 -1
  141. package/client/ui/TagV02/TagStatusV02.stories.tsx +132 -0
  142. package/client/ui/TagV02/TagV02.stories.tsx +142 -0
  143. package/client/ui/TextAreaV01/TextAreaV01.stories.tsx +146 -0
  144. package/client/ui/TextFieldV01/PasswordFieldV01.stories.tsx +161 -0
  145. package/client/ui/TextFieldV01/TextFieldV01.stories.tsx +160 -0
  146. package/client/ui/Textarea.stories.tsx +1 -1
  147. package/client/ui/Timeline/timeline.stories.tsx +404 -0
  148. package/client/ui/Toast/Toast.stories.tsx +1 -1
  149. package/client/ui/ToastV01/ToastV01.stories.tsx +201 -0
  150. package/client/ui/Toaster/Toaster.stories.tsx +1 -1
  151. package/client/ui/Toggle.stories.tsx +1 -1
  152. package/client/ui/Tooltip.stories.tsx +287 -114
  153. package/client/ui/Typography.stories.tsx +1 -1
  154. package/dist/index.cjs.js +1 -1
  155. package/dist/index.d.ts +649 -13
  156. package/dist/index.es.js +4405 -653
  157. package/package.json +1 -1
  158. package/client/components/ui/badge.tsx +0 -33
  159. package/client/components/ui/sonner.tsx +0 -26
  160. package/client/components/ui/toggle-group.tsx +0 -76
  161. package/client/ui/Alert/Alert.stories.tsx +0 -82
  162. package/client/ui/AlertDialog/AlertDialog.stories.tsx +0 -106
  163. package/client/ui/Avatar/Avatar.stories.tsx +0 -94
  164. package/client/ui/Badge/Badge.stories.tsx +0 -60
  165. package/client/ui/Breadcrumb/Breadcrumb.stories.tsx +0 -97
  166. package/client/ui/DropdownMenu/DropdownMenu.stories.tsx +0 -139
  167. package/client/ui/Sonner/Sonner.stories.tsx +0 -48
  168. package/client/ui/Table/Table.stories.tsx +0 -135
  169. package/client/ui/ToggleGroup/ToggleGroup.stories.tsx +0 -88
@@ -0,0 +1,251 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { EmptyState, EmptyStateAction } from "../../components/ui/empty-state";
3
+
4
+ // ─── Inline SVG icons ─────────────────────────────────────────────────────────
5
+
6
+ function IconSearch() {
7
+ return (
8
+ <svg
9
+ width="64"
10
+ height="64"
11
+ viewBox="0 0 24 24"
12
+ fill="none"
13
+ stroke="currentColor"
14
+ strokeWidth="1.25"
15
+ strokeLinecap="round"
16
+ strokeLinejoin="round"
17
+ aria-hidden="true"
18
+ >
19
+ <circle cx="11" cy="11" r="8" />
20
+ <line x1="21" y1="21" x2="16.65" y2="16.65" />
21
+ </svg>
22
+ );
23
+ }
24
+
25
+ function IconCheckCircle() {
26
+ return (
27
+ <svg
28
+ width="64"
29
+ height="64"
30
+ viewBox="0 0 24 24"
31
+ fill="none"
32
+ stroke="currentColor"
33
+ strokeWidth="1.25"
34
+ strokeLinecap="round"
35
+ strokeLinejoin="round"
36
+ aria-hidden="true"
37
+ >
38
+ <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
39
+ <polyline points="22 4 12 14.01 9 11.01" />
40
+ </svg>
41
+ );
42
+ }
43
+
44
+ function IconFileText() {
45
+ return (
46
+ <svg
47
+ width="64"
48
+ height="64"
49
+ viewBox="0 0 24 24"
50
+ fill="none"
51
+ stroke="currentColor"
52
+ strokeWidth="1.25"
53
+ strokeLinecap="round"
54
+ strokeLinejoin="round"
55
+ aria-hidden="true"
56
+ >
57
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
58
+ <polyline points="14 2 14 8 20 8" />
59
+ <line x1="16" y1="13" x2="8" y2="13" />
60
+ <line x1="16" y1="17" x2="8" y2="17" />
61
+ <polyline points="10 9 9 9 8 9" />
62
+ </svg>
63
+ );
64
+ }
65
+
66
+ // ─────────────────────────────────────────────────────────────────────────────
67
+
68
+ const meta = {
69
+ title: "Draft/EmptyState",
70
+ component: EmptyState,
71
+ tags: ["autodocs"],
72
+ parameters: {
73
+ layout: "padded",
74
+ },
75
+ argTypes: {
76
+ headline: { control: "text" },
77
+ title: { control: "text" },
78
+ subtitle: { control: "text" },
79
+ text: { control: "text" },
80
+ image: { control: "text" },
81
+ actionText: { control: "text" },
82
+ },
83
+ } satisfies Meta<typeof EmptyState>;
84
+
85
+ export default meta;
86
+ type Story = StoryObj<typeof meta>;
87
+
88
+ // ─── Default ─────────────────────────────────────────────────────────────────
89
+ // Simplest form — headline + title + body text only, no media.
90
+
91
+ export const Default: Story = {
92
+ render: () => (
93
+ <EmptyState
94
+ headline="No Messages Yet"
95
+ title="Check back later."
96
+ text="You haven't received any messages yet. When you do, they'll appear here."
97
+ />
98
+ ),
99
+ };
100
+
101
+ // ─── Content ─────────────────────────────────────────────────────────────────
102
+ // Props: headline, title, subtitle, text.
103
+
104
+ export const Content: Story = {
105
+ render: () => (
106
+ <EmptyState
107
+ headline="Whoops, 404"
108
+ title="Page not found"
109
+ subtitle="The requested resource couldn't be located."
110
+ text="The page you were looking for does not exist. Please check the URL or go back to the home page."
111
+ />
112
+ ),
113
+ };
114
+
115
+ // ─── Media — Icon ─────────────────────────────────────────────────────────────
116
+ // Pass a React node to the `icon` prop to render it in the media area.
117
+
118
+ export const MediaIcon: Story = {
119
+ render: () => (
120
+ <EmptyState
121
+ icon={<IconSearch />}
122
+ title="We couldn't find a match."
123
+ text="Try adjusting your search terms or filters. Sometimes less specific terms or broader queries can help you find what you're looking for."
124
+ />
125
+ ),
126
+ };
127
+
128
+ // ─── Media — Image ────────────────────────────────────────────────────────────
129
+ // Pass a URL to the `image` prop for an illustration.
130
+
131
+ export const MediaImage: Story = {
132
+ render: () => (
133
+ <EmptyState
134
+ image="https://cdn.vuetifyjs.com/docs/images/components/v-empty-state/teamwork.png"
135
+ imageAlt="Two people working together"
136
+ title="Manage your inventory transfers"
137
+ text="Track and receive your incoming inventory from suppliers"
138
+ />
139
+ ),
140
+ };
141
+
142
+ // ─── Actions ─────────────────────────────────────────────────────────────────
143
+ // Use `actionText` + `onClickAction` for a single auto-rendered CTA button.
144
+
145
+ export const Actions: Story = {
146
+ render: () => (
147
+ <EmptyState
148
+ image="https://cdn.vuetifyjs.com/docs/images/components/v-empty-state/connection.svg"
149
+ imageAlt="Connection error illustration"
150
+ title="Something Went Wrong"
151
+ text="There might be a problem with your connection or our servers. Please check your internet connection or try again later. We appreciate your patience."
152
+ actionText="Retry Request"
153
+ onClickAction={() => alert("Retrying…")}
154
+ />
155
+ ),
156
+ };
157
+
158
+ // ─── Slot: Default ────────────────────────────────────────────────────────────
159
+ // Anything passed as children renders in the default slot below the text.
160
+
161
+ export const SlotDefault: Story = {
162
+ render: () => (
163
+ <EmptyState
164
+ headline="Welcome,"
165
+ icon={<IconFileText />}
166
+ title="What would you like to do today?"
167
+ >
168
+ <div
169
+ style={{
170
+ display: "grid",
171
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
172
+ gap: "1rem",
173
+ marginTop: "1.5rem",
174
+ width: "100%",
175
+ }}
176
+ >
177
+ {[
178
+ { title: "Learn More", description: "Start with our dedicated feature guides" },
179
+ { title: "Try the Playground", description: "Test things out interactively" },
180
+ { title: "Create a Bin", description: "Create a new bin to store your code" },
181
+ { title: "Report a Bug", description: "File a bug report for Vuetify" },
182
+ ].map((card) => (
183
+ <div key={card.title} className="empty-state-card">
184
+ <div className="empty-state-card-title">{card.title}</div>
185
+ <div className="empty-state-card-desc">{card.description}</div>
186
+ </div>
187
+ ))}
188
+ </div>
189
+ </EmptyState>
190
+ ),
191
+ };
192
+
193
+ // ─── Slot: Media ─────────────────────────────────────────────────────────────
194
+ // `mediaSlot` fully replaces the media area.
195
+
196
+ export const SlotMedia: Story = {
197
+ render: () => (
198
+ <EmptyState
199
+ mediaSlot={
200
+ <span style={{ color: "var(--color-gray-400, #9ca3af)", display: "flex" }}>
201
+ <IconCheckCircle />
202
+ </span>
203
+ }
204
+ headlineSlot={
205
+ <div style={{ fontSize: "2rem", fontWeight: 700, color: "var(--color-gray-700, #3d3f47)" }}>
206
+ All Done For Now!
207
+ </div>
208
+ }
209
+ titleSlot={
210
+ <div style={{ fontSize: "1.25rem", fontWeight: 600 }}>
211
+ You're all caught up.
212
+ </div>
213
+ }
214
+ textSlot={
215
+ <div style={{ color: "var(--color-gray-500, #71747d)", fontSize: "0.875rem" }}>
216
+ Great job on completing all your tasks! This might be a good time to
217
+ relax or consider planning your next set of goals. If you think of
218
+ something new, just hit the button below to add a new task.
219
+ </div>
220
+ }
221
+ />
222
+ ),
223
+ };
224
+
225
+ // ─── Slot: Actions ────────────────────────────────────────────────────────────
226
+ // `actionsSlot` lets you compose multiple buttons in the actions area.
227
+
228
+ export const SlotActions: Story = {
229
+ render: () => (
230
+ <EmptyState
231
+ image="https://cdn.vuetifyjs.com/docs/images/components/v-empty-state/teamwork.png"
232
+ imageAlt="Teamwork illustration"
233
+ titleSlot={
234
+ <div style={{ fontSize: "1rem", fontWeight: 600, marginTop: "2rem" }}>
235
+ Manage your inventory transfers
236
+ </div>
237
+ }
238
+ textSlot={
239
+ <div style={{ fontSize: "0.875rem", color: "var(--color-gray-500, #71747d)" }}>
240
+ Track and receive your incoming inventory from suppliers
241
+ </div>
242
+ }
243
+ actionsSlot={
244
+ <>
245
+ <EmptyStateAction variant="outline">Learn more</EmptyStateAction>
246
+ <EmptyStateAction variant="primary">Add transfer</EmptyStateAction>
247
+ </>
248
+ }
249
+ />
250
+ ),
251
+ };
@@ -0,0 +1,218 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { FileUpload } from "../../components/ui/file-upload";
3
+
4
+ const meta = {
5
+ title: "Components/FileUpload",
6
+ component: FileUpload,
7
+ tags: ["autodocs"],
8
+ parameters: {
9
+ layout: "padded",
10
+ docs: {
11
+ description: {
12
+ component: [
13
+ "A drag-and-drop file upload zone with file list, size validation, and error states.",
14
+ "",
15
+ "**Import:**",
16
+ "```tsx",
17
+ `import { FileUpload } from "@syscore/ui-library"`,
18
+ "```",
19
+ "",
20
+ "**Key props:**",
21
+ "",
22
+ "| Prop | Type | Default | Effect |",
23
+ "|------|------|---------|--------|",
24
+ "| `accept` | string | — | Allowed file types e.g. `\".pdf,.png\"` |",
25
+ "| `multiple` | boolean | `false` | Allow selecting multiple files |",
26
+ "| `maxSize` | number (bytes) | — | Reject files larger than this |",
27
+ "| `maxFiles` | number | — | Cap the number of accepted files |",
28
+ "| `variant` | `\"default\"` \\| `\"compact\"` | `\"default\"` | Full zone vs inline row |",
29
+ "| `disabled` | boolean | `false` | Disable all interaction |",
30
+ "| `onFilesChange` | `(files: File[]) => void` | — | Called whenever the file list changes |",
31
+ ].join("\n"),
32
+ },
33
+ },
34
+ },
35
+ } satisfies Meta<typeof FileUpload>;
36
+
37
+ export default meta;
38
+ type Story = StoryObj<typeof meta>;
39
+
40
+ export const Default: Story = {
41
+ parameters: {
42
+ docs: {
43
+ source: {
44
+ code: `import { FileUpload } from "@syscore/ui-library"
45
+
46
+ <FileUpload
47
+ accept=".pdf,.png,.jpg"
48
+ maxSize={5 * 1024 * 1024}
49
+ onFilesChange={(files) => console.log(files)}
50
+ />`,
51
+ },
52
+ },
53
+ },
54
+ render: () => (
55
+ <div className="max-w-lg">
56
+ <FileUpload
57
+ accept=".pdf,.png,.jpg"
58
+ maxSize={5 * 1024 * 1024}
59
+ onFilesChange={(files) => console.log("Files:", files)}
60
+ />
61
+ </div>
62
+ ),
63
+ };
64
+
65
+ export const Multiple: Story = {
66
+ parameters: {
67
+ docs: {
68
+ source: {
69
+ code: `import { FileUpload } from "@syscore/ui-library"
70
+
71
+ <FileUpload
72
+ multiple
73
+ maxFiles={5}
74
+ accept=".pdf,.docx,.xlsx"
75
+ maxSize={10 * 1024 * 1024}
76
+ onFilesChange={(files) => console.log(files)}
77
+ />`,
78
+ },
79
+ },
80
+ },
81
+ render: () => (
82
+ <div className="max-w-lg">
83
+ <FileUpload
84
+ multiple
85
+ maxFiles={5}
86
+ accept=".pdf,.docx,.xlsx"
87
+ maxSize={10 * 1024 * 1024}
88
+ onFilesChange={(files) => console.log("Files:", files)}
89
+ />
90
+ </div>
91
+ ),
92
+ };
93
+
94
+ export const Compact: Story = {
95
+ parameters: {
96
+ docs: {
97
+ source: {
98
+ code: `import { FileUpload } from "@syscore/ui-library"
99
+
100
+ {/* Inline row layout — fits inside a form field row */}
101
+ <FileUpload
102
+ variant="compact"
103
+ accept=".pdf"
104
+ maxSize={2 * 1024 * 1024}
105
+ onFilesChange={(files) => console.log(files)}
106
+ />`,
107
+ },
108
+ },
109
+ },
110
+ render: () => (
111
+ <div className="max-w-lg">
112
+ <FileUpload
113
+ variant="compact"
114
+ accept=".pdf"
115
+ maxSize={2 * 1024 * 1024}
116
+ onFilesChange={(files) => console.log("Files:", files)}
117
+ />
118
+ </div>
119
+ ),
120
+ };
121
+
122
+ export const ImagesOnly: Story = {
123
+ name: "Images only",
124
+ parameters: {
125
+ docs: {
126
+ source: {
127
+ code: `import { FileUpload } from "@syscore/ui-library"
128
+
129
+ <FileUpload
130
+ accept="image/*"
131
+ multiple
132
+ maxSize={3 * 1024 * 1024}
133
+ onFilesChange={(files) => console.log(files)}
134
+ />`,
135
+ },
136
+ },
137
+ },
138
+ render: () => (
139
+ <div className="max-w-lg">
140
+ <FileUpload
141
+ accept="image/*"
142
+ multiple
143
+ maxSize={3 * 1024 * 1024}
144
+ onFilesChange={(files) => console.log("Files:", files)}
145
+ />
146
+ </div>
147
+ ),
148
+ };
149
+
150
+ export const Disabled: Story = {
151
+ parameters: {
152
+ docs: {
153
+ source: {
154
+ code: `import { FileUpload } from "@syscore/ui-library"
155
+
156
+ <FileUpload disabled />`,
157
+ },
158
+ },
159
+ },
160
+ render: () => (
161
+ <div className="max-w-lg">
162
+ <FileUpload disabled />
163
+ </div>
164
+ ),
165
+ };
166
+
167
+ export const InForm: Story = {
168
+ name: "Inside a form",
169
+ parameters: {
170
+ docs: {
171
+ source: {
172
+ code: `import { FileUpload } from "@syscore/ui-library"
173
+ import { Stack, Text, Button } from "@syscore/ui-library"
174
+
175
+ <Stack gap="xl">
176
+ <Stack gap="xs">
177
+ <Text variant="overline-small">Project name</Text>
178
+ <Input placeholder="My WELL project" />
179
+ </Stack>
180
+
181
+ <Stack gap="xs">
182
+ <Text variant="overline-small">Supporting documents</Text>
183
+ <FileUpload
184
+ multiple
185
+ maxFiles={3}
186
+ accept=".pdf,.docx"
187
+ maxSize={10 * 1024 * 1024}
188
+ onFilesChange={(files) => setDocuments(files)}
189
+ />
190
+ </Stack>
191
+
192
+ <Button variant="primary-dark" size="large">Submit</Button>
193
+ </Stack>`,
194
+ },
195
+ },
196
+ },
197
+ render: () => (
198
+ <div className="max-w-md border border-gray-100 rounded-xl p-6">
199
+ <div className="flex flex-col gap-6">
200
+ <div className="flex flex-col gap-2">
201
+ <span className="text-xs font-semibold uppercase tracking-wider text-gray-500">Project name</span>
202
+ <input className="border border-gray-200 rounded-md px-3 py-2 text-sm w-full" placeholder="My WELL project" />
203
+ </div>
204
+ <div className="flex flex-col gap-2">
205
+ <span className="text-xs font-semibold uppercase tracking-wider text-gray-500">Supporting documents</span>
206
+ <FileUpload
207
+ multiple
208
+ maxFiles={3}
209
+ accept=".pdf,.docx"
210
+ maxSize={10 * 1024 * 1024}
211
+ onFilesChange={(files) => console.log("Files:", files)}
212
+ />
213
+ </div>
214
+ <button className="w-full bg-gray-900 text-white rounded-lg py-2.5 text-sm font-medium">Submit</button>
215
+ </div>
216
+ </div>
217
+ ),
218
+ };
@@ -0,0 +1,194 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import {
3
+ Footer,
4
+ FooterRow,
5
+ FooterLinks,
6
+ FooterLink,
7
+ FooterIconButton,
8
+ FooterDivider,
9
+ FooterCopyright,
10
+ FooterBand,
11
+ } from "../../components/ui/footer";
12
+
13
+ // ─── Social icons (inline SVGs — no extra dep needed) ─────────────────────
14
+
15
+ function IconFacebook() {
16
+ return (
17
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
18
+ <path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z" />
19
+ </svg>
20
+ );
21
+ }
22
+ function IconTwitter() {
23
+ return (
24
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
25
+ <path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z" />
26
+ </svg>
27
+ );
28
+ }
29
+ function IconLinkedIn() {
30
+ return (
31
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
32
+ <path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z" />
33
+ <rect x="2" y="9" width="4" height="12" />
34
+ <circle cx="4" cy="4" r="2" />
35
+ </svg>
36
+ );
37
+ }
38
+ function IconInstagram() {
39
+ return (
40
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
41
+ <rect x="2" y="2" width="20" height="20" rx="5" ry="5" />
42
+ <path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" />
43
+ <line x1="17.5" y1="6.5" x2="17.51" y2="6.5" />
44
+ </svg>
45
+ );
46
+ }
47
+
48
+ const SOCIAL_ICONS = [
49
+ { icon: <IconFacebook />, label: "Facebook" },
50
+ { icon: <IconTwitter />, label: "Twitter" },
51
+ { icon: <IconLinkedIn />, label: "LinkedIn" },
52
+ { icon: <IconInstagram />, label: "Instagram" },
53
+ ];
54
+
55
+ const NAV_LINKS = ["Home", "About Us", "Team", "Services", "Blog", "Contact Us"];
56
+
57
+ // ─────────────────────────────────────────────────────────────────────────────
58
+
59
+ const meta = {
60
+ title: "Draft/Footer",
61
+ component: Footer,
62
+ tags: ["autodocs"],
63
+ parameters: {
64
+ layout: "fullscreen",
65
+ },
66
+ argTypes: {
67
+ bordered: { control: "boolean" },
68
+ rounded: { control: "boolean" },
69
+ elevated: { control: "boolean" },
70
+ color: { control: "color" },
71
+ },
72
+ } satisfies Meta<typeof Footer>;
73
+
74
+ export default meta;
75
+
76
+ type Story = StoryObj<typeof meta>;
77
+
78
+ // ─── Default ─────────────────────────────────────────────────────────────────
79
+ // Simplest form — just a container with a copyright line.
80
+
81
+ export const Default: Story = {
82
+ render: () => (
83
+ <Footer>
84
+ <FooterCopyright />
85
+ </Footer>
86
+ ),
87
+ };
88
+
89
+ // ─── Bordered ────────────────────────────────────────────────────────────────
90
+ // Adds a visible top border.
91
+
92
+ export const Bordered: Story = {
93
+ render: () => (
94
+ <Footer bordered>
95
+ <FooterCopyright />
96
+ </Footer>
97
+ ),
98
+ };
99
+
100
+ // ─── Company Footer ───────────────────────────────────────────────────────────
101
+ // Nav links + copyright. Matches the Vuetify "company footer" example.
102
+
103
+ export const CompanyFooter: Story = {
104
+ render: () => (
105
+ <Footer>
106
+ <FooterLinks>
107
+ {NAV_LINKS.map((link) => (
108
+ <FooterLink key={link} href="#">
109
+ {link}
110
+ </FooterLink>
111
+ ))}
112
+ </FooterLinks>
113
+ <FooterCopyright />
114
+ </Footer>
115
+ ),
116
+ };
117
+
118
+ // ─── Indigo Footer ────────────────────────────────────────────────────────────
119
+ // Social icons + paragraph + copyright on an indigo background.
120
+ // Uses --color-indigo-300 from the global token system.
121
+
122
+ export const IndigoFooter: Story = {
123
+ render: () => (
124
+ <Footer
125
+ color="var(--color-indigo-300, #a5b4fc)"
126
+ className="footer--indigo"
127
+ >
128
+ {/* Social icon row */}
129
+ <FooterRow className="footer-row--center">
130
+ {SOCIAL_ICONS.map(({ icon, label }) => (
131
+ <FooterIconButton key={label} aria-label={label}>
132
+ {icon}
133
+ </FooterIconButton>
134
+ ))}
135
+ </FooterRow>
136
+
137
+ {/* Divider */}
138
+ <FooterDivider width="50px" className="footer-divider--thick" />
139
+
140
+ {/* Body copy */}
141
+ <p className="footer-body-text">
142
+ Phasellus feugiat arcu sapien, et iaculis ipsum elementum sit amet.
143
+ Mauris cursus commodo interdum. Praesent ut risus eget metus luctus
144
+ accumsan id ultrices nunc. Sed at orci sed massa consectetur dignissim a
145
+ sit amet dui. Duis commodo vitae velit et faucibus. Morbi vehicula
146
+ lacinia malesuada. Nulla placerat augue vel ipsum ultrices, cursus
147
+ iaculis dui sollicitudin.
148
+ </p>
149
+
150
+ {/* Full-width divider */}
151
+ <FooterDivider />
152
+
153
+ {/* Copyright */}
154
+ <FooterCopyright />
155
+ </Footer>
156
+ ),
157
+ };
158
+
159
+ // ─── Teal Footer ─────────────────────────────────────────────────────────────
160
+ // Two-section footer: top row with tagline + social icons,
161
+ // bottom band with copyright. Rounded corners.
162
+
163
+ export const TealFooter: Story = {
164
+ render: () => (
165
+ <Footer
166
+ color="var(--color-cyan-800, #0f748a)"
167
+ rounded
168
+ className="footer--teal"
169
+ >
170
+ {/* Top row */}
171
+ <FooterRow className="footer-row--space-between footer-row--padded">
172
+ <strong className="footer-tagline">
173
+ Get connected with us on social networks!
174
+ </strong>
175
+ <div className="footer-row footer-row--gap">
176
+ {SOCIAL_ICONS.map(({ icon, label }) => (
177
+ <FooterIconButton
178
+ key={label}
179
+ aria-label={label}
180
+ className="footer-icon-btn--small footer-icon-btn--plain"
181
+ >
182
+ {icon}
183
+ </FooterIconButton>
184
+ ))}
185
+ </div>
186
+ </FooterRow>
187
+
188
+ {/* Bottom band */}
189
+ <FooterBand>
190
+ <FooterCopyright />
191
+ </FooterBand>
192
+ </Footer>
193
+ ),
194
+ };
@@ -3,7 +3,7 @@ import type { Meta, StoryObj } from "@storybook/react";
3
3
  type Story = StoryObj;
4
4
 
5
5
  const meta = {
6
- title: "UI/Form",
6
+ title: "Draft/Form",
7
7
  tags: ["autodocs"],
8
8
  parameters: {
9
9
  layout: "padded",
@@ -5,7 +5,7 @@ import { HeroSection } from "../components/ui/hero-section";
5
5
  import { motion } from "motion/react";
6
6
 
7
7
  const meta = {
8
- title: "Review/Hero",
8
+ title: "Components/Hero",
9
9
  component: HeroSection,
10
10
  tags: ["autodocs"],
11
11
  parameters: {
@@ -6,7 +6,7 @@ import {
6
6
  } from "../../components/ui/hover-card";
7
7
 
8
8
  const meta = {
9
- title: "UI/HoverCard",
9
+ title: "Draft/HoverCard",
10
10
  component: HoverCard,
11
11
  tags: ["autodocs"],
12
12
  parameters: {