@marianmeres/stuic 2.66.0 → 3.0.1

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 (208) hide show
  1. package/README.md +292 -4
  2. package/dist/README.md +41 -18
  3. package/dist/actions/index.d.ts +1 -0
  4. package/dist/actions/index.js +1 -0
  5. package/dist/actions/popover/README.md +19 -0
  6. package/dist/actions/popover/index.css +6 -9
  7. package/dist/actions/popover/popover.svelte.js +2 -2
  8. package/dist/actions/tooltip/README.md +18 -0
  9. package/dist/actions/tooltip/index.css +5 -8
  10. package/dist/actions/tooltip/tooltip.svelte.js +1 -1
  11. package/dist/actions/typeahead.svelte.d.ts +53 -0
  12. package/dist/actions/typeahead.svelte.js +328 -0
  13. package/dist/base.css +17 -0
  14. package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte +10 -10
  15. package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte.d.ts +4 -3
  16. package/dist/components/AlertConfirmPrompt/Current.svelte +15 -18
  17. package/dist/components/AlertConfirmPrompt/Current.svelte.d.ts +4 -3
  18. package/dist/components/AlertConfirmPrompt/acp-icons.js +5 -4
  19. package/dist/components/AlertConfirmPrompt/index.css +66 -0
  20. package/dist/components/AssetsPreview/AssetsPreview.svelte +91 -73
  21. package/dist/components/AssetsPreview/index.css +61 -0
  22. package/dist/components/Avatar/Avatar.svelte +31 -18
  23. package/dist/components/Avatar/README.md +166 -0
  24. package/dist/components/Avatar/index.css +130 -0
  25. package/dist/components/Backdrop/Backdrop.svelte +7 -2
  26. package/dist/components/Backdrop/README.md +71 -6
  27. package/dist/components/Backdrop/index.css +31 -0
  28. package/dist/components/Button/Button.svelte +116 -124
  29. package/dist/components/Button/Button.svelte.d.ts +35 -24
  30. package/dist/components/Button/README.md +87 -21
  31. package/dist/components/Button/index.css +475 -9
  32. package/dist/components/Button/index.d.ts +1 -1
  33. package/dist/components/Button/index.js +1 -1
  34. package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte +7 -39
  35. package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte.d.ts +0 -1
  36. package/dist/components/ButtonGroupRadio/README.md +82 -4
  37. package/dist/components/ButtonGroupRadio/index.css +158 -14
  38. package/dist/components/Collapsible/Collapsible.svelte +7 -7
  39. package/dist/components/Collapsible/Collapsible.svelte.d.ts +2 -2
  40. package/dist/components/Collapsible/README.md +34 -2
  41. package/dist/components/Collapsible/index.css +40 -0
  42. package/dist/components/CommandMenu/CommandMenu.svelte +18 -26
  43. package/dist/components/CommandMenu/CommandMenu.svelte.d.ts +0 -1
  44. package/dist/components/CommandMenu/README.md +39 -0
  45. package/dist/components/CommandMenu/index.css +47 -2
  46. package/dist/components/DismissibleMessage/DismissibleMessage.svelte +53 -51
  47. package/dist/components/DismissibleMessage/DismissibleMessage.svelte.d.ts +6 -6
  48. package/dist/components/DismissibleMessage/README.md +93 -11
  49. package/dist/components/DismissibleMessage/index.css +128 -8
  50. package/dist/components/DismissibleMessage/index.d.ts +1 -1
  51. package/dist/components/DropdownMenu/DropdownMenu.svelte +14 -51
  52. package/dist/components/DropdownMenu/DropdownMenu.svelte.d.ts +6 -7
  53. package/dist/components/DropdownMenu/README.md +132 -0
  54. package/dist/components/DropdownMenu/index.css +258 -52
  55. package/dist/components/Input/FieldAssets.svelte +8 -5
  56. package/dist/components/Input/FieldCheckbox.svelte +7 -44
  57. package/dist/components/Input/FieldFile.svelte +1 -6
  58. package/dist/components/Input/FieldInput.svelte +9 -1
  59. package/dist/components/Input/FieldInput.svelte.d.ts +2 -0
  60. package/dist/components/Input/FieldOptions.svelte +42 -39
  61. package/dist/components/Input/FieldRadios.svelte +7 -16
  62. package/dist/components/Input/FieldSelect.svelte +1 -1
  63. package/dist/components/Input/FieldSwitch.svelte +1 -5
  64. package/dist/components/Input/FieldTextarea.svelte +1 -1
  65. package/dist/components/Input/README.md +194 -0
  66. package/dist/components/Input/_internal/FieldRadioInternal.svelte +2 -40
  67. package/dist/components/Input/_internal/InputWrap.svelte +8 -48
  68. package/dist/components/Input/index.css +524 -116
  69. package/dist/components/KbdShortcut/KbdShortcut.svelte +4 -12
  70. package/dist/components/KbdShortcut/README.md +34 -0
  71. package/dist/components/KbdShortcut/index.css +55 -0
  72. package/dist/components/ListItemButton/ListItemButton.svelte +37 -74
  73. package/dist/components/ListItemButton/ListItemButton.svelte.d.ts +1 -10
  74. package/dist/components/ListItemButton/README.md +100 -45
  75. package/dist/components/ListItemButton/index.css +173 -52
  76. package/dist/components/ListItemButton/index.d.ts +1 -1
  77. package/dist/components/ListItemButton/index.js +1 -1
  78. package/dist/components/Modal/Modal.svelte +1 -8
  79. package/dist/components/Modal/README.md +29 -0
  80. package/dist/components/Modal/index.css +38 -0
  81. package/dist/components/ModalDialog/ModalDialog.svelte +2 -21
  82. package/dist/components/ModalDialog/README.md +35 -0
  83. package/dist/components/ModalDialog/index.css +59 -0
  84. package/dist/components/Nav/Nav.svelte +732 -0
  85. package/dist/components/Nav/Nav.svelte.d.ts +110 -0
  86. package/dist/components/Nav/README.md +334 -0
  87. package/dist/components/Nav/index.css +318 -0
  88. package/dist/components/Nav/index.d.ts +1 -0
  89. package/dist/components/Nav/index.js +1 -0
  90. package/dist/components/Notifications/Notifications.svelte +44 -129
  91. package/dist/components/Notifications/Notifications.svelte.d.ts +9 -18
  92. package/dist/components/Notifications/README.md +186 -70
  93. package/dist/components/Notifications/index.css +212 -15
  94. package/dist/components/Notifications/notifications-stack.svelte.d.ts +4 -0
  95. package/dist/components/Notifications/notifications-stack.svelte.js +8 -0
  96. package/dist/components/Progress/Progress.svelte +4 -2
  97. package/dist/components/Progress/Progress.svelte.d.ts +1 -0
  98. package/dist/components/Progress/README.md +97 -11
  99. package/dist/components/Progress/_internal/Bar.svelte +4 -15
  100. package/dist/components/Progress/_internal/Bar.svelte.d.ts +1 -1
  101. package/dist/components/Progress/_internal/Circle.svelte +30 -2
  102. package/dist/components/Progress/_internal/Circle.svelte.d.ts +1 -0
  103. package/dist/components/Progress/index.css +50 -4
  104. package/dist/components/Skeleton/README.md +152 -0
  105. package/dist/components/Skeleton/Skeleton.svelte +9 -9
  106. package/dist/components/Skeleton/Skeleton.svelte.d.ts +0 -1
  107. package/dist/components/Skeleton/index.css +72 -45
  108. package/dist/components/Spinner/README.md +149 -37
  109. package/dist/components/Spinner/Spinner.svelte +14 -38
  110. package/dist/components/Spinner/Spinner.svelte.d.ts +2 -1
  111. package/dist/components/Spinner/SpinnerCircle.svelte +6 -34
  112. package/dist/components/Spinner/SpinnerCircle.svelte.d.ts +1 -0
  113. package/dist/components/Spinner/SpinnerCircleOscillate.svelte +10 -5
  114. package/dist/components/Spinner/SpinnerUnicode.svelte +3 -1
  115. package/dist/components/Spinner/SpinnerUnicode.svelte.d.ts +1 -0
  116. package/dist/components/Spinner/index.css +104 -0
  117. package/dist/components/Switch/README.md +45 -14
  118. package/dist/components/Switch/Switch.svelte +23 -48
  119. package/dist/components/Switch/Switch.svelte.d.ts +4 -2
  120. package/dist/components/Switch/index.css +121 -4
  121. package/dist/components/Switch/index.d.ts +1 -2
  122. package/dist/components/Switch/index.js +1 -2
  123. package/dist/components/TabbedMenu/README.md +37 -21
  124. package/dist/components/TabbedMenu/TabbedMenu.svelte +5 -46
  125. package/dist/components/TabbedMenu/TabbedMenu.svelte.d.ts +0 -1
  126. package/dist/components/TabbedMenu/index.css +84 -17
  127. package/dist/components/ThemePreview/README.md +289 -0
  128. package/dist/components/ThemePreview/ThemePreview.svelte +394 -0
  129. package/dist/components/ThemePreview/ThemePreview.svelte.d.ts +35 -0
  130. package/dist/components/ThemePreview/index.css +509 -0
  131. package/dist/components/ThemePreview/index.d.ts +1 -0
  132. package/dist/components/ThemePreview/index.js +1 -0
  133. package/dist/components/TwCheck/README.md +32 -13
  134. package/dist/components/TwCheck/TwCheck.svelte +11 -9
  135. package/dist/components/TwCheck/TwCheck.svelte.d.ts +0 -1
  136. package/dist/components/TwCheck/index.css +17 -2
  137. package/dist/components/TypeaheadInput/TypeaheadInput.svelte +20 -188
  138. package/dist/components/TypeaheadInput/TypeaheadInput.svelte.d.ts +4 -2
  139. package/dist/components/X/X.svelte +12 -5
  140. package/dist/components/X/X.svelte.d.ts +1 -0
  141. package/dist/icons/index.d.ts +1 -0
  142. package/dist/icons/index.js +1 -0
  143. package/dist/index.css +46 -26
  144. package/dist/index.d.ts +2 -0
  145. package/dist/index.js +2 -0
  146. package/dist/themes/blue-orange.css +217 -0
  147. package/dist/themes/blue-orange.d.ts +6 -0
  148. package/dist/themes/blue-orange.js +175 -0
  149. package/dist/themes/cyan-red.css +217 -0
  150. package/dist/themes/cyan-red.d.ts +6 -0
  151. package/dist/themes/cyan-red.js +175 -0
  152. package/dist/themes/cyan-slate.css +217 -0
  153. package/dist/themes/cyan-slate.d.ts +6 -0
  154. package/dist/themes/cyan-slate.js +175 -0
  155. package/dist/themes/emerald-pink.css +217 -0
  156. package/dist/themes/emerald-pink.d.ts +6 -0
  157. package/dist/themes/emerald-pink.js +175 -0
  158. package/dist/themes/fuchsia-emerald.css +217 -0
  159. package/dist/themes/fuchsia-emerald.d.ts +6 -0
  160. package/dist/themes/fuchsia-emerald.js +175 -0
  161. package/dist/themes/gray.css +217 -0
  162. package/dist/themes/gray.d.ts +6 -0
  163. package/dist/themes/gray.js +175 -0
  164. package/dist/themes/indigo-amber.css +217 -0
  165. package/dist/themes/indigo-amber.d.ts +6 -0
  166. package/dist/themes/indigo-amber.js +175 -0
  167. package/dist/themes/neutral.css +217 -0
  168. package/dist/themes/neutral.d.ts +6 -0
  169. package/dist/themes/neutral.js +175 -0
  170. package/dist/themes/pink-emerald.css +217 -0
  171. package/dist/themes/pink-emerald.d.ts +6 -0
  172. package/dist/themes/pink-emerald.js +175 -0
  173. package/dist/themes/purple-yellow.css +217 -0
  174. package/dist/themes/purple-yellow.d.ts +6 -0
  175. package/dist/themes/purple-yellow.js +175 -0
  176. package/dist/themes/rainbow.css +217 -0
  177. package/dist/themes/rainbow.d.ts +6 -0
  178. package/dist/themes/rainbow.js +180 -0
  179. package/dist/themes/red-blue.css +217 -0
  180. package/dist/themes/red-blue.d.ts +6 -0
  181. package/dist/themes/red-blue.js +175 -0
  182. package/dist/themes/red-cyan.css +217 -0
  183. package/dist/themes/red-cyan.d.ts +6 -0
  184. package/dist/themes/red-cyan.js +175 -0
  185. package/dist/themes/rose-teal.css +217 -0
  186. package/dist/themes/rose-teal.d.ts +6 -0
  187. package/dist/themes/rose-teal.js +175 -0
  188. package/dist/themes/sky-amber.css +217 -0
  189. package/dist/themes/sky-amber.d.ts +6 -0
  190. package/dist/themes/sky-amber.js +175 -0
  191. package/dist/themes/slate-cyan.css +217 -0
  192. package/dist/themes/slate-cyan.d.ts +6 -0
  193. package/dist/themes/slate-cyan.js +175 -0
  194. package/dist/themes/tailwind-color-pairs.md +31 -0
  195. package/dist/themes/teal-rose.css +217 -0
  196. package/dist/themes/teal-rose.d.ts +6 -0
  197. package/dist/themes/teal-rose.js +175 -0
  198. package/dist/themes/violet-lime.css +217 -0
  199. package/dist/themes/violet-lime.d.ts +6 -0
  200. package/dist/themes/violet-lime.js +175 -0
  201. package/dist/utils/design-tokens.d.ts +43 -0
  202. package/dist/utils/design-tokens.js +127 -0
  203. package/dist/utils/index.d.ts +1 -0
  204. package/dist/utils/index.js +1 -0
  205. package/dist/utils/storage-abstraction.js +1 -1
  206. package/package.json +14 -11
  207. package/dist/components/Switch/SwitchButton.svelte +0 -135
  208. package/dist/components/Switch/SwitchButton.svelte.d.ts +0 -21
@@ -0,0 +1,289 @@
1
+ # ThemePreview
2
+
3
+ A comprehensive theme preview component that serves two purposes:
4
+
5
+ 1. **Visual Preview** - Shows all design tokens in action as a mini webpage layout
6
+ 2. **Reference Implementation** - Demonstrates theming best practices for creating components
7
+
8
+ ## Usage
9
+
10
+ ```svelte
11
+ <script lang="ts">
12
+ import { ThemePreview } from '@marianmeres/stuic';
13
+ </script>
14
+
15
+ <ThemePreview />
16
+ ```
17
+
18
+ ### Compact Mode
19
+
20
+ ```svelte
21
+ <ThemePreview compact showLabels={false} />
22
+ ```
23
+
24
+ ### Custom Sections
25
+
26
+ ```svelte
27
+ <ThemePreview>
28
+ {#snippet header()}
29
+ <h1>My Custom Theme</h1>
30
+ {/snippet}
31
+
32
+ {#snippet sidebar()}
33
+ <nav>Custom navigation...</nav>
34
+ {/snippet}
35
+ </ThemePreview>
36
+ ```
37
+
38
+ ## Props
39
+
40
+ | Prop | Type | Default | Description |
41
+ |------|------|---------|-------------|
42
+ | `showLabels` | `boolean` | `true` | Show section labels |
43
+ | `compact` | `boolean` | `false` | Reduced spacing |
44
+ | `showAllVariants` | `boolean` | `true` | Show all button variants |
45
+ | `showInputs` | `boolean` | `true` | Show input examples |
46
+ | `class` | `string` | - | Additional CSS classes |
47
+ | `el` | `HTMLDivElement` | - | Bindable element reference |
48
+ | `header` | `Snippet` | - | Custom header content |
49
+ | `sidebar` | `Snippet` | - | Custom sidebar content |
50
+ | `footer` | `Snippet` | - | Custom footer content |
51
+
52
+ ## Component Tokens
53
+
54
+ Override to customize appearance:
55
+
56
+ ```css
57
+ :root {
58
+ --stuic-theme-preview-radius: var(--radius-lg);
59
+ --stuic-theme-preview-gap: 2rem;
60
+ --stuic-theme-preview-transition: 200ms;
61
+ --stuic-theme-preview-sidebar-width: 250px;
62
+ }
63
+ ```
64
+
65
+ ---
66
+
67
+ # Theming Best Practices
68
+
69
+ This component demonstrates the patterns used throughout stuic. Follow these when creating new components.
70
+
71
+ ## 1. Theme Token Reference
72
+
73
+ ### Intent Colors
74
+
75
+ Communicate **purpose** and **meaning**:
76
+
77
+ | Token | Purpose |
78
+ |-------|---------|
79
+ | `--stuic-color-primary` | Main actions ("do this") |
80
+ | `--stuic-color-accent` | Highlights ("notice this") |
81
+ | `--stuic-color-destructive` | Dangerous/irreversible actions |
82
+ | `--stuic-color-warning` | Caution states |
83
+ | `--stuic-color-success` | Positive outcomes |
84
+ | `--stuic-color-info` | Neutral information |
85
+
86
+ Each intent has states and foregrounds:
87
+ - `--stuic-color-{intent}` - base color
88
+ - `--stuic-color-{intent}-hover` - hover state
89
+ - `--stuic-color-{intent}-active` - active/pressed state
90
+ - `--stuic-color-{intent}-foreground` - text on base
91
+ - `--stuic-color-{intent}-foreground-hover`
92
+ - `--stuic-color-{intent}-foreground-active`
93
+
94
+ ### Role Colors
95
+
96
+ Define **position** in the visual hierarchy:
97
+
98
+ | Token | Purpose |
99
+ |-------|---------|
100
+ | `--stuic-color-background` | Page background |
101
+ | `--stuic-color-foreground` | Primary text |
102
+ | `--stuic-color-surface` | Card/panel backgrounds |
103
+ | `--stuic-color-surface-foreground` | Text on surfaces |
104
+ | `--stuic-color-muted` | Subtle backgrounds |
105
+ | `--stuic-color-muted-foreground` | Secondary text |
106
+ | `--stuic-color-border` | Border color |
107
+ | `--stuic-color-input` | Input field backgrounds |
108
+ | `--stuic-color-ring` | Focus ring color |
109
+
110
+ ## 2. Internal Variable Pattern
111
+
112
+ The core theming technique in stuic separates **what colors to use** (intent) from **how to apply them** (variant).
113
+
114
+ ### Step 1: Intent Sets the Palette
115
+
116
+ ```css
117
+ .my-component[data-intent="primary"] {
118
+ --_color: var(--stuic-color-primary);
119
+ --_color-hover: var(--stuic-color-primary-hover);
120
+ --_color-active: var(--stuic-color-primary-active);
121
+ --_fg: var(--stuic-color-primary-foreground);
122
+ --_fg-hover: var(--stuic-color-primary-foreground-hover);
123
+ --_fg-active: var(--stuic-color-primary-foreground-active);
124
+ }
125
+ ```
126
+
127
+ ### Step 2: Variant Determines Application
128
+
129
+ ```css
130
+ /* Solid: filled background */
131
+ .my-component[data-variant="solid"] {
132
+ --_bg: var(--_color);
133
+ --_text: var(--_fg);
134
+ --_border: var(--_color);
135
+ }
136
+
137
+ /* Outline: transparent, colored border */
138
+ .my-component[data-variant="outline"] {
139
+ --_bg: transparent;
140
+ --_bg-hover: color-mix(in srgb, var(--_color) 10%, transparent);
141
+ --_text: var(--_color);
142
+ --_border: var(--_color);
143
+ }
144
+ ```
145
+
146
+ ### Step 3: Base Styles Consume Variables
147
+
148
+ ```css
149
+ .my-component {
150
+ background: var(--_bg);
151
+ color: var(--_text);
152
+ border-color: var(--_border);
153
+ }
154
+
155
+ .my-component:hover {
156
+ background: var(--_bg-hover);
157
+ color: var(--_text-hover);
158
+ border-color: var(--_border-hover);
159
+ }
160
+ ```
161
+
162
+ This pattern allows any intent + variant combination to work automatically.
163
+
164
+ ## 3. Foreground Pairing Convention
165
+
166
+ When using a background color, always use its paired foreground for text:
167
+
168
+ ```css
169
+ .card {
170
+ background: var(--stuic-color-surface);
171
+ color: var(--stuic-color-surface-foreground);
172
+ }
173
+
174
+ .muted-section {
175
+ background: var(--stuic-color-muted);
176
+ color: var(--stuic-color-muted-foreground);
177
+ }
178
+ ```
179
+
180
+ ## 4. Component Tokens
181
+
182
+ Define component-level tokens in `:root` for easy customization:
183
+
184
+ ```css
185
+ :root {
186
+ --stuic-my-component-radius: var(--radius-md);
187
+ --stuic-my-component-padding: 1rem;
188
+ --stuic-my-component-transition: 150ms;
189
+ }
190
+
191
+ .my-component {
192
+ border-radius: var(--stuic-my-component-radius);
193
+ padding: var(--stuic-my-component-padding);
194
+ transition: all var(--stuic-my-component-transition);
195
+ }
196
+ ```
197
+
198
+ Users can override globally or locally:
199
+ ```css
200
+ /* Global override */
201
+ :root {
202
+ --stuic-my-component-radius: 0;
203
+ }
204
+ ```
205
+
206
+ ```svelte
207
+ <!-- Local override -->
208
+ <MyComponent style="--stuic-my-component-radius: 999px;" />
209
+ ```
210
+
211
+ ## 5. State Handling
212
+
213
+ Always define hover and active states using theme tokens:
214
+
215
+ ```css
216
+ .element {
217
+ background: var(--stuic-color-surface);
218
+ }
219
+
220
+ .element:hover {
221
+ background: var(--stuic-color-surface-hover);
222
+ }
223
+
224
+ .element:active {
225
+ background: var(--stuic-color-surface-active);
226
+ }
227
+
228
+ .element:focus-visible {
229
+ outline: 3px solid var(--stuic-color-ring);
230
+ outline-offset: 2px;
231
+ }
232
+ ```
233
+
234
+ ## 6. Dark Mode
235
+
236
+ Themes handle dark mode via `:root.dark` selector. When using theme tokens properly, components don't need explicit dark mode styles - the theme handles everything.
237
+
238
+ ```css
239
+ /* Theme defines both modes */
240
+ :root {
241
+ --stuic-color-background: var(--color-white);
242
+ --stuic-color-foreground: var(--color-neutral-900);
243
+ }
244
+
245
+ :root.dark {
246
+ --stuic-color-background: var(--color-neutral-950);
247
+ --stuic-color-foreground: var(--color-neutral-100);
248
+ }
249
+
250
+ /* Component just uses tokens - works in both modes */
251
+ .my-component {
252
+ background: var(--stuic-color-background);
253
+ color: var(--stuic-color-foreground);
254
+ }
255
+ ```
256
+
257
+ ## 7. Accessibility
258
+
259
+ - Use `--stuic-color-ring` for focus indicators
260
+ - Ensure sufficient contrast between background and foreground pairs
261
+ - Respect reduced motion preferences:
262
+
263
+ ```css
264
+ @media (prefers-reduced-motion: reduce) {
265
+ .my-component {
266
+ transition: none;
267
+ }
268
+ }
269
+ ```
270
+
271
+ ## 8. Data Attributes
272
+
273
+ Use data attributes for styling variants instead of classes:
274
+
275
+ ```svelte
276
+ <button
277
+ data-intent={intent}
278
+ data-variant={variant}
279
+ data-size={size}
280
+ >
281
+ ```
282
+
283
+ ```css
284
+ .button[data-intent="primary"] { ... }
285
+ .button[data-variant="outline"] { ... }
286
+ .button[data-size="lg"] { ... }
287
+ ```
288
+
289
+ This keeps the class attribute clean for user customization via `class` prop.
@@ -0,0 +1,394 @@
1
+ <script lang="ts" module>
2
+ import type { Snippet } from "svelte";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
6
+ /** Show section labels */
7
+ showLabels?: boolean;
8
+ /** Compact layout (reduced spacing) */
9
+ compact?: boolean;
10
+ /** Show all button variants or just solid */
11
+ showAllVariants?: boolean;
12
+ /** Show input examples */
13
+ showInputs?: boolean;
14
+ /** Additional CSS classes */
15
+ class?: string;
16
+ /** Bindable element reference */
17
+ el?: HTMLDivElement;
18
+ /** Optional header snippet */
19
+ header?: Snippet;
20
+ /** Optional sidebar snippet */
21
+ sidebar?: Snippet;
22
+ /** Optional footer snippet */
23
+ footer?: Snippet;
24
+ /** Optional AlertConfirmPromptStack*/
25
+ acp?: AlertConfirmPromptStack;
26
+ /** Optional NotificationsStack*/
27
+ notifications?: NotificationsStack;
28
+ }
29
+
30
+ /** Intent colors to demonstrate */
31
+ export const INTENT_COLORS = [
32
+ "primary",
33
+ "accent",
34
+ "destructive",
35
+ "warning",
36
+ "success",
37
+ "info",
38
+ ] as const;
39
+
40
+ /** Button variants to demonstrate */
41
+ export const BUTTON_VARIANTS = ["solid", "outline", "ghost", "soft", "link"] as const;
42
+ </script>
43
+
44
+ <script lang="ts">
45
+ import { twMerge } from "../../utils/tw-merge.js";
46
+ import Button from "../Button/Button.svelte";
47
+ import Switch from "../Switch/Switch.svelte";
48
+ import { AlertConfirmPromptStack } from "../AlertConfirmPrompt/index.js";
49
+ import {
50
+ type DismissibleMessageIntent,
51
+ DismissibleMessage,
52
+ } from "../DismissibleMessage/index.js";
53
+ import { createClog } from "@marianmeres/clog";
54
+ import Nav, { type NavGroup } from "../Nav/Nav.svelte";
55
+ import type { NotificationsStack } from "../Notifications/notifications-stack.svelte.js";
56
+ import FieldInput from "../Input/FieldInput.svelte";
57
+ import FieldCheckbox from "../Input/FieldCheckbox.svelte";
58
+
59
+ const clog = createClog("ThemePreview", { color: "auto" });
60
+
61
+ let {
62
+ showLabels = true,
63
+ compact = false,
64
+ showAllVariants = true,
65
+ showInputs = true,
66
+ class: classProp,
67
+ el = $bindable(),
68
+ header,
69
+ sidebar,
70
+ footer,
71
+ acp,
72
+ notifications,
73
+ ...rest
74
+ }: Props = $props();
75
+
76
+ let spacing = $derived(compact ? "gap-2 p-2" : "gap-4 p-4");
77
+
78
+ const alert = (intent?: string) => {
79
+ acp?.alert(intent);
80
+ notif(intent);
81
+ };
82
+
83
+ const notif = (intent?: string) => {
84
+ if (intent && notifications) {
85
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
86
+ (notifications as any)[intent]?.(intent);
87
+ }
88
+ };
89
+
90
+ // Navigation groups for sidebar
91
+ let activeNavId = $state("dashboard");
92
+ const navGroups: NavGroup[] = [
93
+ {
94
+ title: "Navigation",
95
+ id: "navigation",
96
+ items: [
97
+ { id: "dashboard", label: "Dashboard" },
98
+ { id: "settings", label: "Settings" },
99
+ { id: "profile", label: "Profile" },
100
+ { id: "archived", label: "Archived", disabled: true },
101
+ ],
102
+ },
103
+ ];
104
+
105
+ //
106
+ let dismissibleMessage = $state<string | null>();
107
+ let dismissibleIntent = $state<DismissibleMessageIntent | undefined>();
108
+ </script>
109
+
110
+ <div bind:this={el} class={twMerge("stuic-theme-preview", spacing, classProp)} {...rest}>
111
+ <!-- HEADER -->
112
+ <header class="stuic-theme-preview-header">
113
+ {#if header}
114
+ {@render header()}
115
+ {:else}
116
+ <div class="header-content">
117
+ <h1 class="header-title">Theme Preview</h1>
118
+ <p class="header-subtitle">Design tokens in action</p>
119
+ </div>
120
+ {/if}
121
+ </header>
122
+
123
+ <!-- BODY: Sidebar + Main -->
124
+ <div class="stuic-theme-preview-body">
125
+ <!-- SIDEBAR -->
126
+ <aside class="stuic-theme-preview-sidebar">
127
+ {#if sidebar}
128
+ {@render sidebar()}
129
+ {:else}
130
+ <Nav
131
+ groups={navGroups}
132
+ activeId={activeNavId}
133
+ onSelect={(item) => (activeNavId = item.id)}
134
+ />
135
+ <div class="sidebar-footer">
136
+ <span class="muted-text">v1.0.0</span>
137
+ </div>
138
+ {/if}
139
+ </aside>
140
+
141
+ <!-- MAIN CONTENT -->
142
+ <main class="stuic-theme-preview-main">
143
+ <DismissibleMessage
144
+ message={dismissibleMessage}
145
+ intent={dismissibleIntent}
146
+ onDismiss={() => {
147
+ dismissibleIntent = undefined;
148
+ dismissibleMessage = null;
149
+ }}
150
+ />
151
+ <!-- INTENT BUTTONS -->
152
+ <section class="preview-section">
153
+ {#if showLabels}
154
+ <h2 class="section-label">Intent Colors (Buttons)</h2>
155
+ {/if}
156
+
157
+ <div class="button-grid">
158
+ {#each INTENT_COLORS as intent}
159
+ <div class="button-column">
160
+ {#if showLabels}
161
+ <span class="intent-label">{intent}</span>
162
+ {/if}
163
+
164
+ {#if showAllVariants}
165
+ {#each BUTTON_VARIANTS as variant}
166
+ <Button
167
+ {intent}
168
+ {variant}
169
+ onclick={() => {
170
+ if (!["primary", "accent"].includes(intent)) {
171
+ dismissibleIntent = intent as DismissibleMessageIntent;
172
+ dismissibleMessage = intent;
173
+ notif(intent);
174
+ } else {
175
+ alert(intent);
176
+ }
177
+ }}
178
+ >
179
+ {variant}
180
+ </Button>
181
+ {/each}
182
+ {:else}
183
+ <Button {intent} onclick={() => alert(intent)}>
184
+ {intent}
185
+ </Button>
186
+ {/if}
187
+ </div>
188
+ {/each}
189
+ </div>
190
+ </section>
191
+
192
+ <section class="preview-section">
193
+ {#if showLabels}
194
+ <h2 class="section-label">Default Button (no explicit intent)</h2>
195
+ {/if}
196
+ <div class="flex gap-6 flex-wrap">
197
+ {#each BUTTON_VARIANTS as variant}
198
+ <div class="flex gap-2">
199
+ <Button {variant}>{variant}</Button>
200
+ <Button x {variant} roundedFull />
201
+ </div>
202
+ {/each}
203
+ </div>
204
+ </section>
205
+
206
+ <!-- ROLE COLORS -->
207
+ <section class="preview-section">
208
+ {#if showLabels}
209
+ <h2 class="section-label">Role Colors</h2>
210
+ {/if}
211
+
212
+ <div class="role-colors-grid">
213
+ <div class="color-swatch background">
214
+ <span class="swatch-label">background</span>
215
+ <span class="foreground-text">foreground text</span>
216
+ </div>
217
+
218
+ <div class="color-swatch surface">
219
+ <span class="swatch-label">surface</span>
220
+ <span class="surface-foreground-text">surface-foreground</span>
221
+ </div>
222
+
223
+ <div class="color-swatch surface-1">
224
+ <span class="swatch-label">surface-1</span>
225
+ <span class="surface-1-foreground-text">surface-1-foreground</span>
226
+ </div>
227
+
228
+ <div class="color-swatch surface-2">
229
+ <span class="swatch-label">surface-2</span>
230
+ <span class="surface-2-foreground-text">surface-2-foreground</span>
231
+ </div>
232
+
233
+ <div class="color-swatch muted-bg">
234
+ <span class="swatch-label">muted</span>
235
+ <span class="muted-foreground-text">muted-foreground</span>
236
+ </div>
237
+ </div>
238
+ </section>
239
+
240
+ <!-- BORDERS -->
241
+ <section class="preview-section">
242
+ {#if showLabels}
243
+ <h2 class="section-label">Borders</h2>
244
+ {/if}
245
+
246
+ <div class="border-examples">
247
+ <div class="border-box default">Default border</div>
248
+ <div class="border-box hover">Hover state (hover me)</div>
249
+ <div class="border-box active">Active state</div>
250
+ </div>
251
+ </section>
252
+
253
+ <!-- INPUTS -->
254
+ {#if showInputs}
255
+ <section class="preview-section">
256
+ {#if showLabels}
257
+ <h2 class="section-label">Inputs</h2>
258
+ {/if}
259
+
260
+ <div class="input-examples flex items-center">
261
+ <!-- <div class="input-wrapper"> -->
262
+ <!-- <input type="text" class="preview-input" placeholder="Text input..." /> -->
263
+ <FieldInput class="m-0" />
264
+ <!-- </div> -->
265
+ <!-- <div class="input-wrapper"> -->
266
+ <FieldCheckbox label="Hey ho" class="m-0" />
267
+ <!-- <input
268
+ type="text"
269
+ class="preview-input focus"
270
+ value="Focused state"
271
+ readonly
272
+ /> -->
273
+ <!-- </div> -->
274
+ </div>
275
+ </section>
276
+ {/if}
277
+
278
+ <!-- SWITCHES -->
279
+ <section class="preview-section">
280
+ {#if showLabels}
281
+ <h2 class="section-label">Switches</h2>
282
+ {/if}
283
+
284
+ <div class="flex flex-wrap items-center gap-4">
285
+ <Switch checked />
286
+ {#each INTENT_COLORS as intent}
287
+ <Switch {intent} checked />
288
+ {/each}
289
+ </div>
290
+ </section>
291
+
292
+ <!-- HIGHLIGHT BOXES -->
293
+ <section class="preview-section">
294
+ {#if showLabels}
295
+ <h2 class="section-label">Highlighted Content</h2>
296
+ {/if}
297
+
298
+ <div class="highlight-box primary">
299
+ <strong>Primary Highlight</strong>
300
+ <p>This box uses primary intent colors for important content.</p>
301
+ </div>
302
+
303
+ <div class="highlight-box accent">
304
+ <strong>Accent Highlight</strong>
305
+ <p>This box uses accent colors to draw attention.</p>
306
+ </div>
307
+ </section>
308
+
309
+ <!-- TYPOGRAPHY -->
310
+ <section class="preview-section">
311
+ {#if showLabels}
312
+ <h2 class="section-label">Typography</h2>
313
+ {/if}
314
+
315
+ <div class="typography-demo">
316
+ <p class="text-foreground">
317
+ This is <strong>foreground</strong> text - the primary text color.
318
+ </p>
319
+ <p class="text-muted">
320
+ This is <strong>muted</strong> text - used for secondary information.
321
+ </p>
322
+ <p class="text-surface-foreground">
323
+ This is <strong>surface-foreground</strong> text - used on surface backgrounds.
324
+ </p>
325
+ </div>
326
+ </section>
327
+
328
+ <!-- TAILWIND UTILITY CLASSES -->
329
+ <section class="preview-section">
330
+ {#if showLabels}
331
+ <h2 class="section-label">Tailwind Utility Classes</h2>
332
+ {/if}
333
+
334
+ <div class="flex flex-col gap-3">
335
+ <!-- Intent color boxes using inline styles with CSS variables -->
336
+ <div class="flex flex-wrap gap-2">
337
+ {#each INTENT_COLORS as intent}
338
+ <div
339
+ class="px-3 py-2 rounded text-sm"
340
+ style="background: var(--stuic-color-{intent}); color: var(--stuic-color-{intent}-foreground);"
341
+ >
342
+ {intent}
343
+ </div>
344
+ {/each}
345
+ </div>
346
+
347
+ <!-- Role color examples using Tailwind arbitrary value syntax -->
348
+ <div class="flex flex-wrap gap-2">
349
+ <div
350
+ class="px-3 py-2 rounded border border-(--stuic-color-border) bg-(--stuic-color-surface) text-(--stuic-color-surface-foreground)"
351
+ >
352
+ surface + border
353
+ </div>
354
+ <div
355
+ class="px-3 py-2 rounded bg-(--stuic-color-muted) text-(--stuic-color-muted-foreground)"
356
+ >
357
+ muted
358
+ </div>
359
+ <div
360
+ class="px-3 py-2 rounded bg-(--stuic-color-primary) text-(--stuic-color-primary-foreground)"
361
+ >
362
+ primary
363
+ </div>
364
+ <div
365
+ class="px-3 py-2 rounded bg-(--stuic-color-accent) text-(--stuic-color-accent-foreground)"
366
+ >
367
+ accent
368
+ </div>
369
+ </div>
370
+
371
+ <!-- Code hint -->
372
+ <p class="text-xs text-(--stuic-color-muted-foreground)">
373
+ Using: <code class="bg-(--stuic-color-muted) px-1 rounded"
374
+ >bg-(--stuic-color-primary)</code
375
+ > syntax
376
+ </p>
377
+ </div>
378
+ </section>
379
+ </main>
380
+ </div>
381
+
382
+ <!-- FOOTER -->
383
+ <footer class="stuic-theme-preview-footer">
384
+ {#if footer}
385
+ {@render footer()}
386
+ {:else}
387
+ <div class="footer-content">
388
+ <span class="muted-text">Theme tokens demonstration</span>
389
+ <span class="footer-divider">|</span>
390
+ <span class="foreground-text">stuic</span>
391
+ </div>
392
+ {/if}
393
+ </footer>
394
+ </div>
@@ -0,0 +1,35 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
4
+ /** Show section labels */
5
+ showLabels?: boolean;
6
+ /** Compact layout (reduced spacing) */
7
+ compact?: boolean;
8
+ /** Show all button variants or just solid */
9
+ showAllVariants?: boolean;
10
+ /** Show input examples */
11
+ showInputs?: boolean;
12
+ /** Additional CSS classes */
13
+ class?: string;
14
+ /** Bindable element reference */
15
+ el?: HTMLDivElement;
16
+ /** Optional header snippet */
17
+ header?: Snippet;
18
+ /** Optional sidebar snippet */
19
+ sidebar?: Snippet;
20
+ /** Optional footer snippet */
21
+ footer?: Snippet;
22
+ /** Optional AlertConfirmPromptStack*/
23
+ acp?: AlertConfirmPromptStack;
24
+ /** Optional NotificationsStack*/
25
+ notifications?: NotificationsStack;
26
+ }
27
+ /** Intent colors to demonstrate */
28
+ export declare const INTENT_COLORS: readonly ["primary", "accent", "destructive", "warning", "success", "info"];
29
+ /** Button variants to demonstrate */
30
+ export declare const BUTTON_VARIANTS: readonly ["solid", "outline", "ghost", "soft", "link"];
31
+ import { AlertConfirmPromptStack } from "../AlertConfirmPrompt/index.js";
32
+ import type { NotificationsStack } from "../Notifications/notifications-stack.svelte.js";
33
+ declare const ThemePreview: import("svelte").Component<Props, {}, "el">;
34
+ type ThemePreview = ReturnType<typeof ThemePreview>;
35
+ export default ThemePreview;