@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.
- package/README.md +292 -4
- package/dist/README.md +41 -18
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/actions/popover/README.md +19 -0
- package/dist/actions/popover/index.css +6 -9
- package/dist/actions/popover/popover.svelte.js +2 -2
- package/dist/actions/tooltip/README.md +18 -0
- package/dist/actions/tooltip/index.css +5 -8
- package/dist/actions/tooltip/tooltip.svelte.js +1 -1
- package/dist/actions/typeahead.svelte.d.ts +53 -0
- package/dist/actions/typeahead.svelte.js +328 -0
- package/dist/base.css +17 -0
- package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte +10 -10
- package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte.d.ts +4 -3
- package/dist/components/AlertConfirmPrompt/Current.svelte +15 -18
- package/dist/components/AlertConfirmPrompt/Current.svelte.d.ts +4 -3
- package/dist/components/AlertConfirmPrompt/acp-icons.js +5 -4
- package/dist/components/AlertConfirmPrompt/index.css +66 -0
- package/dist/components/AssetsPreview/AssetsPreview.svelte +91 -73
- package/dist/components/AssetsPreview/index.css +61 -0
- package/dist/components/Avatar/Avatar.svelte +31 -18
- package/dist/components/Avatar/README.md +166 -0
- package/dist/components/Avatar/index.css +130 -0
- package/dist/components/Backdrop/Backdrop.svelte +7 -2
- package/dist/components/Backdrop/README.md +71 -6
- package/dist/components/Backdrop/index.css +31 -0
- package/dist/components/Button/Button.svelte +116 -124
- package/dist/components/Button/Button.svelte.d.ts +35 -24
- package/dist/components/Button/README.md +87 -21
- package/dist/components/Button/index.css +475 -9
- package/dist/components/Button/index.d.ts +1 -1
- package/dist/components/Button/index.js +1 -1
- package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte +7 -39
- package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte.d.ts +0 -1
- package/dist/components/ButtonGroupRadio/README.md +82 -4
- package/dist/components/ButtonGroupRadio/index.css +158 -14
- package/dist/components/Collapsible/Collapsible.svelte +7 -7
- package/dist/components/Collapsible/Collapsible.svelte.d.ts +2 -2
- package/dist/components/Collapsible/README.md +34 -2
- package/dist/components/Collapsible/index.css +40 -0
- package/dist/components/CommandMenu/CommandMenu.svelte +18 -26
- package/dist/components/CommandMenu/CommandMenu.svelte.d.ts +0 -1
- package/dist/components/CommandMenu/README.md +39 -0
- package/dist/components/CommandMenu/index.css +47 -2
- package/dist/components/DismissibleMessage/DismissibleMessage.svelte +53 -51
- package/dist/components/DismissibleMessage/DismissibleMessage.svelte.d.ts +6 -6
- package/dist/components/DismissibleMessage/README.md +93 -11
- package/dist/components/DismissibleMessage/index.css +128 -8
- package/dist/components/DismissibleMessage/index.d.ts +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.svelte +14 -51
- package/dist/components/DropdownMenu/DropdownMenu.svelte.d.ts +6 -7
- package/dist/components/DropdownMenu/README.md +132 -0
- package/dist/components/DropdownMenu/index.css +258 -52
- package/dist/components/Input/FieldAssets.svelte +8 -5
- package/dist/components/Input/FieldCheckbox.svelte +7 -44
- package/dist/components/Input/FieldFile.svelte +1 -6
- package/dist/components/Input/FieldInput.svelte +9 -1
- package/dist/components/Input/FieldInput.svelte.d.ts +2 -0
- package/dist/components/Input/FieldOptions.svelte +42 -39
- package/dist/components/Input/FieldRadios.svelte +7 -16
- package/dist/components/Input/FieldSelect.svelte +1 -1
- package/dist/components/Input/FieldSwitch.svelte +1 -5
- package/dist/components/Input/FieldTextarea.svelte +1 -1
- package/dist/components/Input/README.md +194 -0
- package/dist/components/Input/_internal/FieldRadioInternal.svelte +2 -40
- package/dist/components/Input/_internal/InputWrap.svelte +8 -48
- package/dist/components/Input/index.css +524 -116
- package/dist/components/KbdShortcut/KbdShortcut.svelte +4 -12
- package/dist/components/KbdShortcut/README.md +34 -0
- package/dist/components/KbdShortcut/index.css +55 -0
- package/dist/components/ListItemButton/ListItemButton.svelte +37 -74
- package/dist/components/ListItemButton/ListItemButton.svelte.d.ts +1 -10
- package/dist/components/ListItemButton/README.md +100 -45
- package/dist/components/ListItemButton/index.css +173 -52
- package/dist/components/ListItemButton/index.d.ts +1 -1
- package/dist/components/ListItemButton/index.js +1 -1
- package/dist/components/Modal/Modal.svelte +1 -8
- package/dist/components/Modal/README.md +29 -0
- package/dist/components/Modal/index.css +38 -0
- package/dist/components/ModalDialog/ModalDialog.svelte +2 -21
- package/dist/components/ModalDialog/README.md +35 -0
- package/dist/components/ModalDialog/index.css +59 -0
- package/dist/components/Nav/Nav.svelte +732 -0
- package/dist/components/Nav/Nav.svelte.d.ts +110 -0
- package/dist/components/Nav/README.md +334 -0
- package/dist/components/Nav/index.css +318 -0
- package/dist/components/Nav/index.d.ts +1 -0
- package/dist/components/Nav/index.js +1 -0
- package/dist/components/Notifications/Notifications.svelte +44 -129
- package/dist/components/Notifications/Notifications.svelte.d.ts +9 -18
- package/dist/components/Notifications/README.md +186 -70
- package/dist/components/Notifications/index.css +212 -15
- package/dist/components/Notifications/notifications-stack.svelte.d.ts +4 -0
- package/dist/components/Notifications/notifications-stack.svelte.js +8 -0
- package/dist/components/Progress/Progress.svelte +4 -2
- package/dist/components/Progress/Progress.svelte.d.ts +1 -0
- package/dist/components/Progress/README.md +97 -11
- package/dist/components/Progress/_internal/Bar.svelte +4 -15
- package/dist/components/Progress/_internal/Bar.svelte.d.ts +1 -1
- package/dist/components/Progress/_internal/Circle.svelte +30 -2
- package/dist/components/Progress/_internal/Circle.svelte.d.ts +1 -0
- package/dist/components/Progress/index.css +50 -4
- package/dist/components/Skeleton/README.md +152 -0
- package/dist/components/Skeleton/Skeleton.svelte +9 -9
- package/dist/components/Skeleton/Skeleton.svelte.d.ts +0 -1
- package/dist/components/Skeleton/index.css +72 -45
- package/dist/components/Spinner/README.md +149 -37
- package/dist/components/Spinner/Spinner.svelte +14 -38
- package/dist/components/Spinner/Spinner.svelte.d.ts +2 -1
- package/dist/components/Spinner/SpinnerCircle.svelte +6 -34
- package/dist/components/Spinner/SpinnerCircle.svelte.d.ts +1 -0
- package/dist/components/Spinner/SpinnerCircleOscillate.svelte +10 -5
- package/dist/components/Spinner/SpinnerUnicode.svelte +3 -1
- package/dist/components/Spinner/SpinnerUnicode.svelte.d.ts +1 -0
- package/dist/components/Spinner/index.css +104 -0
- package/dist/components/Switch/README.md +45 -14
- package/dist/components/Switch/Switch.svelte +23 -48
- package/dist/components/Switch/Switch.svelte.d.ts +4 -2
- package/dist/components/Switch/index.css +121 -4
- package/dist/components/Switch/index.d.ts +1 -2
- package/dist/components/Switch/index.js +1 -2
- package/dist/components/TabbedMenu/README.md +37 -21
- package/dist/components/TabbedMenu/TabbedMenu.svelte +5 -46
- package/dist/components/TabbedMenu/TabbedMenu.svelte.d.ts +0 -1
- package/dist/components/TabbedMenu/index.css +84 -17
- package/dist/components/ThemePreview/README.md +289 -0
- package/dist/components/ThemePreview/ThemePreview.svelte +394 -0
- package/dist/components/ThemePreview/ThemePreview.svelte.d.ts +35 -0
- package/dist/components/ThemePreview/index.css +509 -0
- package/dist/components/ThemePreview/index.d.ts +1 -0
- package/dist/components/ThemePreview/index.js +1 -0
- package/dist/components/TwCheck/README.md +32 -13
- package/dist/components/TwCheck/TwCheck.svelte +11 -9
- package/dist/components/TwCheck/TwCheck.svelte.d.ts +0 -1
- package/dist/components/TwCheck/index.css +17 -2
- package/dist/components/TypeaheadInput/TypeaheadInput.svelte +20 -188
- package/dist/components/TypeaheadInput/TypeaheadInput.svelte.d.ts +4 -2
- package/dist/components/X/X.svelte +12 -5
- package/dist/components/X/X.svelte.d.ts +1 -0
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.css +46 -26
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/themes/blue-orange.css +217 -0
- package/dist/themes/blue-orange.d.ts +6 -0
- package/dist/themes/blue-orange.js +175 -0
- package/dist/themes/cyan-red.css +217 -0
- package/dist/themes/cyan-red.d.ts +6 -0
- package/dist/themes/cyan-red.js +175 -0
- package/dist/themes/cyan-slate.css +217 -0
- package/dist/themes/cyan-slate.d.ts +6 -0
- package/dist/themes/cyan-slate.js +175 -0
- package/dist/themes/emerald-pink.css +217 -0
- package/dist/themes/emerald-pink.d.ts +6 -0
- package/dist/themes/emerald-pink.js +175 -0
- package/dist/themes/fuchsia-emerald.css +217 -0
- package/dist/themes/fuchsia-emerald.d.ts +6 -0
- package/dist/themes/fuchsia-emerald.js +175 -0
- package/dist/themes/gray.css +217 -0
- package/dist/themes/gray.d.ts +6 -0
- package/dist/themes/gray.js +175 -0
- package/dist/themes/indigo-amber.css +217 -0
- package/dist/themes/indigo-amber.d.ts +6 -0
- package/dist/themes/indigo-amber.js +175 -0
- package/dist/themes/neutral.css +217 -0
- package/dist/themes/neutral.d.ts +6 -0
- package/dist/themes/neutral.js +175 -0
- package/dist/themes/pink-emerald.css +217 -0
- package/dist/themes/pink-emerald.d.ts +6 -0
- package/dist/themes/pink-emerald.js +175 -0
- package/dist/themes/purple-yellow.css +217 -0
- package/dist/themes/purple-yellow.d.ts +6 -0
- package/dist/themes/purple-yellow.js +175 -0
- package/dist/themes/rainbow.css +217 -0
- package/dist/themes/rainbow.d.ts +6 -0
- package/dist/themes/rainbow.js +180 -0
- package/dist/themes/red-blue.css +217 -0
- package/dist/themes/red-blue.d.ts +6 -0
- package/dist/themes/red-blue.js +175 -0
- package/dist/themes/red-cyan.css +217 -0
- package/dist/themes/red-cyan.d.ts +6 -0
- package/dist/themes/red-cyan.js +175 -0
- package/dist/themes/rose-teal.css +217 -0
- package/dist/themes/rose-teal.d.ts +6 -0
- package/dist/themes/rose-teal.js +175 -0
- package/dist/themes/sky-amber.css +217 -0
- package/dist/themes/sky-amber.d.ts +6 -0
- package/dist/themes/sky-amber.js +175 -0
- package/dist/themes/slate-cyan.css +217 -0
- package/dist/themes/slate-cyan.d.ts +6 -0
- package/dist/themes/slate-cyan.js +175 -0
- package/dist/themes/tailwind-color-pairs.md +31 -0
- package/dist/themes/teal-rose.css +217 -0
- package/dist/themes/teal-rose.d.ts +6 -0
- package/dist/themes/teal-rose.js +175 -0
- package/dist/themes/violet-lime.css +217 -0
- package/dist/themes/violet-lime.d.ts +6 -0
- package/dist/themes/violet-lime.js +175 -0
- package/dist/utils/design-tokens.d.ts +43 -0
- package/dist/utils/design-tokens.js +127 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/storage-abstraction.js +1 -1
- package/package.json +14 -11
- package/dist/components/Switch/SwitchButton.svelte +0 -135
- 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;
|