@classic-homes/theme-svelte 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +305 -0
- package/dist/lib/components/Alert.svelte +51 -0
- package/dist/lib/components/Alert.svelte.d.ts +9 -0
- package/dist/lib/components/AlertDescription.svelte +16 -0
- package/dist/lib/components/AlertDescription.svelte.d.ts +9 -0
- package/dist/lib/components/AlertDialog.svelte +136 -0
- package/dist/lib/components/AlertDialog.svelte.d.ts +79 -0
- package/dist/lib/components/AlertTitle.svelte +16 -0
- package/dist/lib/components/AlertTitle.svelte.d.ts +9 -0
- package/dist/lib/components/Avatar.svelte +56 -0
- package/dist/lib/components/Avatar.svelte.d.ts +26 -0
- package/dist/lib/components/AvatarFallback.svelte +31 -0
- package/dist/lib/components/AvatarFallback.svelte.d.ts +17 -0
- package/dist/lib/components/AvatarImage.svelte +29 -0
- package/dist/lib/components/AvatarImage.svelte.d.ts +12 -0
- package/dist/lib/components/Badge.svelte +73 -0
- package/dist/lib/components/Badge.svelte.d.ts +11 -0
- package/dist/lib/components/Button.svelte +130 -0
- package/dist/lib/components/Button.svelte.d.ts +17 -0
- package/dist/lib/components/Card.svelte +58 -0
- package/dist/lib/components/Card.svelte.d.ts +26 -0
- package/dist/lib/components/CardContent.svelte +16 -0
- package/dist/lib/components/CardContent.svelte.d.ts +9 -0
- package/dist/lib/components/CardDescription.svelte +16 -0
- package/dist/lib/components/CardDescription.svelte.d.ts +9 -0
- package/dist/lib/components/CardFooter.svelte +16 -0
- package/dist/lib/components/CardFooter.svelte.d.ts +9 -0
- package/dist/lib/components/CardHeader.svelte +16 -0
- package/dist/lib/components/CardHeader.svelte.d.ts +9 -0
- package/dist/lib/components/CardTitle.svelte +16 -0
- package/dist/lib/components/CardTitle.svelte.d.ts +9 -0
- package/dist/lib/components/Checkbox.svelte +65 -0
- package/dist/lib/components/Checkbox.svelte.d.ts +14 -0
- package/dist/lib/components/DataTable.svelte +334 -0
- package/dist/lib/components/DataTable.svelte.d.ts +103 -0
- package/dist/lib/components/Dialog.svelte +111 -0
- package/dist/lib/components/Dialog.svelte.d.ts +22 -0
- package/dist/lib/components/DropdownMenu.svelte +135 -0
- package/dist/lib/components/DropdownMenu.svelte.d.ts +33 -0
- package/dist/lib/components/FileUpload.svelte +448 -0
- package/dist/lib/components/FileUpload.svelte.d.ts +42 -0
- package/dist/lib/components/FormField.svelte +134 -0
- package/dist/lib/components/FormField.svelte.d.ts +37 -0
- package/dist/lib/components/Input.svelte +61 -0
- package/dist/lib/components/Input.svelte.d.ts +19 -0
- package/dist/lib/components/Label.svelte +33 -0
- package/dist/lib/components/Label.svelte.d.ts +11 -0
- package/dist/lib/components/LoadingLogo.svelte +124 -0
- package/dist/lib/components/LoadingLogo.svelte.d.ts +16 -0
- package/dist/lib/components/LogoMain.svelte +237 -0
- package/dist/lib/components/LogoMain.svelte.d.ts +20 -0
- package/dist/lib/components/PageHeader.svelte +90 -0
- package/dist/lib/components/PageHeader.svelte.d.ts +28 -0
- package/dist/lib/components/Section.svelte +44 -0
- package/dist/lib/components/Section.svelte.d.ts +28 -0
- package/dist/lib/components/Select.svelte +174 -0
- package/dist/lib/components/Select.svelte.d.ts +32 -0
- package/dist/lib/components/Separator.svelte +29 -0
- package/dist/lib/components/Separator.svelte.d.ts +9 -0
- package/dist/lib/components/Skeleton.svelte +35 -0
- package/dist/lib/components/Skeleton.svelte.d.ts +7 -0
- package/dist/lib/components/Spinner.svelte +50 -0
- package/dist/lib/components/Spinner.svelte.d.ts +8 -0
- package/dist/lib/components/Switch.svelte +56 -0
- package/dist/lib/components/Switch.svelte.d.ts +14 -0
- package/dist/lib/components/TabPanel.svelte +44 -0
- package/dist/lib/components/TabPanel.svelte.d.ts +12 -0
- package/dist/lib/components/Tabs.svelte +125 -0
- package/dist/lib/components/Tabs.svelte.d.ts +19 -0
- package/dist/lib/components/Textarea.svelte +54 -0
- package/dist/lib/components/Textarea.svelte.d.ts +16 -0
- package/dist/lib/components/Toast.svelte +116 -0
- package/dist/lib/components/Toast.svelte.d.ts +12 -0
- package/dist/lib/components/ToastContainer.svelte +56 -0
- package/dist/lib/components/ToastContainer.svelte.d.ts +8 -0
- package/dist/lib/components/Tooltip.svelte +55 -0
- package/dist/lib/components/Tooltip.svelte.d.ts +18 -0
- package/dist/lib/components/layout/AppShell.svelte +82 -0
- package/dist/lib/components/layout/AppShell.svelte.d.ts +44 -0
- package/dist/lib/components/layout/DashboardLayout.svelte +248 -0
- package/dist/lib/components/layout/DashboardLayout.svelte.d.ts +62 -0
- package/dist/lib/components/layout/Footer.svelte +130 -0
- package/dist/lib/components/layout/Footer.svelte.d.ts +32 -0
- package/dist/lib/components/layout/FormPageLayout.svelte +92 -0
- package/dist/lib/components/layout/FormPageLayout.svelte.d.ts +33 -0
- package/dist/lib/components/layout/Header.svelte +94 -0
- package/dist/lib/components/layout/Header.svelte.d.ts +30 -0
- package/dist/lib/components/layout/PublicLayout.svelte +180 -0
- package/dist/lib/components/layout/PublicLayout.svelte.d.ts +39 -0
- package/dist/lib/components/layout/QuickLinks.svelte +112 -0
- package/dist/lib/components/layout/QuickLinks.svelte.d.ts +27 -0
- package/dist/lib/components/layout/Sidebar.svelte +243 -0
- package/dist/lib/components/layout/Sidebar.svelte.d.ts +48 -0
- package/dist/lib/composables/index.d.ts +8 -0
- package/dist/lib/composables/index.js +10 -0
- package/dist/lib/composables/useAsync.svelte.d.ts +102 -0
- package/dist/lib/composables/useAsync.svelte.js +210 -0
- package/dist/lib/composables/useForm.svelte.d.ts +123 -0
- package/dist/lib/composables/useForm.svelte.js +245 -0
- package/dist/lib/index.d.ts +65 -0
- package/dist/lib/index.js +83 -0
- package/dist/lib/performance.d.ts +79 -0
- package/dist/lib/performance.js +170 -0
- package/dist/lib/schemas/auth.d.ts +410 -0
- package/dist/lib/schemas/auth.js +216 -0
- package/dist/lib/schemas/common.d.ts +267 -0
- package/dist/lib/schemas/common.js +268 -0
- package/dist/lib/schemas/index.d.ts +24 -0
- package/dist/lib/schemas/index.js +32 -0
- package/dist/lib/stores/sidebar.svelte.d.ts +25 -0
- package/dist/lib/stores/sidebar.svelte.js +38 -0
- package/dist/lib/stores/theme.svelte.d.ts +72 -0
- package/dist/lib/stores/theme.svelte.js +150 -0
- package/dist/lib/stores/toast.svelte.d.ts +62 -0
- package/dist/lib/stores/toast.svelte.js +93 -0
- package/dist/lib/types/components.d.ts +85 -0
- package/dist/lib/types/components.js +7 -0
- package/dist/lib/types/layout.d.ts +258 -0
- package/dist/lib/types/layout.js +7 -0
- package/dist/lib/utils.d.ts +6 -0
- package/dist/lib/utils.js +9 -0
- package/dist/lib/validation.d.ts +101 -0
- package/dist/lib/validation.js +170 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# @classic-homes/theme-svelte
|
|
2
|
+
|
|
3
|
+
Svelte 5 components for the Classic Theme design system. Built on [Bits UI](https://bits-ui.com) primitives and styled with Tailwind CSS.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @classic-homes/theme-svelte @classic-homes/theme-tokens
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
### 1. Configure Tailwind CSS
|
|
14
|
+
|
|
15
|
+
Add the Classic Theme preset to your `tailwind.config.js`:
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import preset from '@classic-homes/theme-tailwind-preset';
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
presets: [preset],
|
|
22
|
+
content: [
|
|
23
|
+
'./src/**/*.{html,js,svelte,ts}',
|
|
24
|
+
'./node_modules/@classic-homes/theme-svelte/**/*.{html,js,svelte,ts}',
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Import Design Tokens
|
|
30
|
+
|
|
31
|
+
Import the CSS tokens in your app's root CSS file:
|
|
32
|
+
|
|
33
|
+
```css
|
|
34
|
+
@import '@classic-homes/theme-tokens/css';
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or in your root layout:
|
|
38
|
+
|
|
39
|
+
```svelte
|
|
40
|
+
<script>
|
|
41
|
+
import '@classic-homes/theme-tokens/css';
|
|
42
|
+
</script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
```svelte
|
|
48
|
+
<script>
|
|
49
|
+
import { Button, Card, CardHeader, CardTitle, CardContent } from '@classic-homes/theme-svelte';
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<Card>
|
|
53
|
+
<CardHeader>
|
|
54
|
+
<CardTitle>Welcome</CardTitle>
|
|
55
|
+
</CardHeader>
|
|
56
|
+
<CardContent>
|
|
57
|
+
<Button variant="default">Click me</Button>
|
|
58
|
+
</CardContent>
|
|
59
|
+
</Card>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Components
|
|
63
|
+
|
|
64
|
+
### Core UI
|
|
65
|
+
|
|
66
|
+
- `Button` - Buttons with variants (default, secondary, destructive, outline, ghost, link)
|
|
67
|
+
- `Input` - Text input field
|
|
68
|
+
- `Textarea` - Multi-line text input
|
|
69
|
+
- `Label` - Form labels
|
|
70
|
+
- `Checkbox` - Checkbox input
|
|
71
|
+
- `Switch` - Toggle switch
|
|
72
|
+
- `Select` - Dropdown select
|
|
73
|
+
- `FormField` - Combined label + input + error handling
|
|
74
|
+
|
|
75
|
+
### Layout
|
|
76
|
+
|
|
77
|
+
- `AppShell` - Application wrapper with skip links and toast container
|
|
78
|
+
- `DashboardLayout` - Sidebar + header layout for dashboards
|
|
79
|
+
- `PublicLayout` - Header + footer layout for public pages
|
|
80
|
+
- `FormPageLayout` - Centered form page layout
|
|
81
|
+
- `Sidebar` - Navigation sidebar
|
|
82
|
+
- `Header` - Page header
|
|
83
|
+
- `Footer` - Page footer
|
|
84
|
+
|
|
85
|
+
### Feedback
|
|
86
|
+
|
|
87
|
+
- `Alert` - Alert messages (default, destructive, success, warning, info)
|
|
88
|
+
- `AlertDialog` - Confirmation dialogs
|
|
89
|
+
- `Dialog` - Modal dialogs
|
|
90
|
+
- `Toast` - Toast notifications
|
|
91
|
+
- `ToastContainer` - Toast notification container
|
|
92
|
+
- `Spinner` - Loading spinner
|
|
93
|
+
- `Skeleton` - Loading skeleton
|
|
94
|
+
|
|
95
|
+
### Data Display
|
|
96
|
+
|
|
97
|
+
- `Card` - Card container with header, content, footer
|
|
98
|
+
- `Badge` - Status badges
|
|
99
|
+
- `DataTable` - Sortable data table
|
|
100
|
+
- `Tabs` - Tab navigation
|
|
101
|
+
- `Tooltip` - Hover tooltips
|
|
102
|
+
- `DropdownMenu` - Dropdown menus
|
|
103
|
+
- `Avatar` - User avatars
|
|
104
|
+
|
|
105
|
+
### Branding
|
|
106
|
+
|
|
107
|
+
- `LogoMain` - Main logo component
|
|
108
|
+
- `LoadingLogo` - Animated loading logo
|
|
109
|
+
|
|
110
|
+
## Error Handling
|
|
111
|
+
|
|
112
|
+
### Overview
|
|
113
|
+
|
|
114
|
+
Components in this library do not include built-in error boundaries to give you full control over error handling. We recommend implementing error handling at your application's root level.
|
|
115
|
+
|
|
116
|
+
### Recommended: Error Boundary Component
|
|
117
|
+
|
|
118
|
+
Create an ErrorBoundary component to catch and handle errors gracefully:
|
|
119
|
+
|
|
120
|
+
```svelte
|
|
121
|
+
<!-- src/lib/ErrorBoundary.svelte -->
|
|
122
|
+
<script lang="ts">
|
|
123
|
+
import type { Snippet } from 'svelte';
|
|
124
|
+
import { Button, Alert, AlertDescription } from '@classic-homes/theme-svelte';
|
|
125
|
+
|
|
126
|
+
interface Props {
|
|
127
|
+
children: Snippet;
|
|
128
|
+
fallback?: Snippet<[Error, () => void]>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let { children, fallback }: Props = $props();
|
|
132
|
+
let error = $state<Error | null>(null);
|
|
133
|
+
|
|
134
|
+
function reset() {
|
|
135
|
+
error = null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
$effect(() => {
|
|
139
|
+
const handleError = (e: ErrorEvent) => {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
error = e.error || new Error(e.message);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const handleUnhandledRejection = (e: PromiseRejectionEvent) => {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
error = e.reason instanceof Error ? e.reason : new Error(String(e.reason));
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
window.addEventListener('error', handleError);
|
|
150
|
+
window.addEventListener('unhandledrejection', handleUnhandledRejection);
|
|
151
|
+
|
|
152
|
+
return () => {
|
|
153
|
+
window.removeEventListener('error', handleError);
|
|
154
|
+
window.removeEventListener('unhandledrejection', handleUnhandledRejection);
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
</script>
|
|
158
|
+
|
|
159
|
+
{#if error}
|
|
160
|
+
{#if fallback}
|
|
161
|
+
{@render fallback(error, reset)}
|
|
162
|
+
{:else}
|
|
163
|
+
<div class="flex min-h-screen items-center justify-center p-4">
|
|
164
|
+
<div class="w-full max-w-md space-y-4">
|
|
165
|
+
<Alert variant="destructive">
|
|
166
|
+
<AlertDescription>
|
|
167
|
+
<strong>Something went wrong</strong>
|
|
168
|
+
<p class="mt-2 text-sm">{error.message}</p>
|
|
169
|
+
</AlertDescription>
|
|
170
|
+
</Alert>
|
|
171
|
+
<Button onclick={reset} variant="outline" class="w-full">Try again</Button>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
{/if}
|
|
175
|
+
{:else}
|
|
176
|
+
{@render children()}
|
|
177
|
+
{/if}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Usage with AppShell
|
|
181
|
+
|
|
182
|
+
Wrap your `AppShell` with the ErrorBoundary:
|
|
183
|
+
|
|
184
|
+
```svelte
|
|
185
|
+
<!-- src/routes/+layout.svelte -->
|
|
186
|
+
<script>
|
|
187
|
+
import { AppShell } from '@classic-homes/theme-svelte';
|
|
188
|
+
import ErrorBoundary from '$lib/ErrorBoundary.svelte';
|
|
189
|
+
</script>
|
|
190
|
+
|
|
191
|
+
<ErrorBoundary>
|
|
192
|
+
<AppShell>
|
|
193
|
+
<slot />
|
|
194
|
+
</AppShell>
|
|
195
|
+
</ErrorBoundary>
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Custom Fallback UI
|
|
199
|
+
|
|
200
|
+
You can provide a custom fallback UI:
|
|
201
|
+
|
|
202
|
+
```svelte
|
|
203
|
+
<ErrorBoundary>
|
|
204
|
+
{#snippet fallback(error, reset)}
|
|
205
|
+
<div class="error-page">
|
|
206
|
+
<h1>Oops!</h1>
|
|
207
|
+
<p>{error.message}</p>
|
|
208
|
+
<button onclick={reset}>Reload</button>
|
|
209
|
+
</div>
|
|
210
|
+
{/snippet}
|
|
211
|
+
|
|
212
|
+
<AppShell>
|
|
213
|
+
<slot />
|
|
214
|
+
</AppShell>
|
|
215
|
+
</ErrorBoundary>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Toast Notifications
|
|
219
|
+
|
|
220
|
+
The library includes a toast store for managing notifications:
|
|
221
|
+
|
|
222
|
+
```svelte
|
|
223
|
+
<script>
|
|
224
|
+
import { toastStore, Button } from '@classic-homes/theme-svelte';
|
|
225
|
+
|
|
226
|
+
function showSuccess() {
|
|
227
|
+
toastStore.success('Operation completed successfully!');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function showError() {
|
|
231
|
+
toastStore.error('Something went wrong', { title: 'Error' });
|
|
232
|
+
}
|
|
233
|
+
</script>
|
|
234
|
+
|
|
235
|
+
<Button onclick={showSuccess}>Show Success</Button>
|
|
236
|
+
<Button onclick={showError} variant="destructive">Show Error</Button>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Toast methods:
|
|
240
|
+
|
|
241
|
+
- `toastStore.success(message, options?)` - Green success toast
|
|
242
|
+
- `toastStore.error(message, options?)` - Red error toast (persistent by default)
|
|
243
|
+
- `toastStore.warning(message, options?)` - Yellow warning toast
|
|
244
|
+
- `toastStore.info(message, options?)` - Blue info toast
|
|
245
|
+
- `toastStore.add(toast)` - Add custom toast
|
|
246
|
+
- `toastStore.remove(id)` - Remove toast by ID
|
|
247
|
+
- `toastStore.clear()` - Remove all toasts
|
|
248
|
+
|
|
249
|
+
## Sidebar State
|
|
250
|
+
|
|
251
|
+
For layouts with collapsible sidebars, use the sidebar store:
|
|
252
|
+
|
|
253
|
+
```svelte
|
|
254
|
+
<script>
|
|
255
|
+
import { sidebarStore } from '@classic-homes/theme-svelte';
|
|
256
|
+
|
|
257
|
+
function toggleSidebar() {
|
|
258
|
+
sidebarStore.toggle();
|
|
259
|
+
}
|
|
260
|
+
</script>
|
|
261
|
+
|
|
262
|
+
<button onclick={toggleSidebar}>
|
|
263
|
+
{sidebarStore.isOpen ? 'Close' : 'Open'} Sidebar
|
|
264
|
+
</button>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## TypeScript Support
|
|
268
|
+
|
|
269
|
+
All components are fully typed. Import types as needed:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
import type {
|
|
273
|
+
NavItem,
|
|
274
|
+
NavSection,
|
|
275
|
+
User,
|
|
276
|
+
Tab,
|
|
277
|
+
FileMetadata,
|
|
278
|
+
DataTableColumn,
|
|
279
|
+
SelectOption,
|
|
280
|
+
} from '@classic-homes/theme-svelte';
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Svelte 5 Runes
|
|
284
|
+
|
|
285
|
+
All components use Svelte 5 runes syntax:
|
|
286
|
+
|
|
287
|
+
- `$props()` for component props
|
|
288
|
+
- `$state()` for reactive state
|
|
289
|
+
- `$derived()` for computed values
|
|
290
|
+
- `$effect()` for side effects
|
|
291
|
+
- `$bindable()` for two-way binding
|
|
292
|
+
|
|
293
|
+
## Accessibility
|
|
294
|
+
|
|
295
|
+
Components are built with accessibility in mind:
|
|
296
|
+
|
|
297
|
+
- Proper ARIA attributes
|
|
298
|
+
- Keyboard navigation support
|
|
299
|
+
- Focus management
|
|
300
|
+
- Screen reader friendly
|
|
301
|
+
- Skip links in AppShell
|
|
302
|
+
|
|
303
|
+
## License
|
|
304
|
+
|
|
305
|
+
MIT
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
import { tv, type VariantProps } from 'tailwind-variants';
|
|
5
|
+
|
|
6
|
+
const alertVariants = tv({
|
|
7
|
+
base: 'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground',
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default:
|
|
11
|
+
'bg-gray-50 dark:bg-gray-800 border-gray-200 dark:border-gray-700 text-gray-900 dark:text-gray-100',
|
|
12
|
+
destructive:
|
|
13
|
+
'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800 text-red-700 dark:text-red-400 [&>svg]:text-red-700 dark:[&>svg]:text-red-400',
|
|
14
|
+
error:
|
|
15
|
+
'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800 text-red-700 dark:text-red-400 [&>svg]:text-red-700 dark:[&>svg]:text-red-400',
|
|
16
|
+
success:
|
|
17
|
+
'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800 text-green-700 dark:text-green-400 [&>svg]:text-green-700 dark:[&>svg]:text-green-400',
|
|
18
|
+
warning:
|
|
19
|
+
'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800 text-yellow-700 dark:text-yellow-400 [&>svg]:text-yellow-700 dark:[&>svg]:text-yellow-400',
|
|
20
|
+
info: 'bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800 text-blue-700 dark:text-blue-400 [&>svg]:text-blue-700 dark:[&>svg]:text-blue-400',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: 'default',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
type AlertVariants = VariantProps<typeof alertVariants>;
|
|
29
|
+
|
|
30
|
+
interface Props {
|
|
31
|
+
variant?: AlertVariants['variant'];
|
|
32
|
+
class?: string;
|
|
33
|
+
children: Snippet;
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let { variant = 'default', class: className, children, ...restProps }: Props = $props();
|
|
38
|
+
|
|
39
|
+
const classes = $derived(cn(alertVariants({ variant }), className));
|
|
40
|
+
|
|
41
|
+
// Use assertive for errors/warnings, polite for info/success/default
|
|
42
|
+
const ariaLive = $derived(
|
|
43
|
+
variant === 'error' || variant === 'destructive' || variant === 'warning'
|
|
44
|
+
? 'assertive'
|
|
45
|
+
: 'polite'
|
|
46
|
+
);
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<div role="alert" aria-live={ariaLive} class={classes} {...restProps}>
|
|
50
|
+
{@render children()}
|
|
51
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
declare const Alert: import("svelte").Component<{
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
variant?: "default" | "destructive" | "error" | "success" | "warning" | "info" | undefined;
|
|
5
|
+
class?: string;
|
|
6
|
+
children: Snippet;
|
|
7
|
+
}, {}, "">;
|
|
8
|
+
type Alert = ReturnType<typeof Alert>;
|
|
9
|
+
export default Alert;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
class?: string;
|
|
7
|
+
children: Snippet;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { class: className, children, ...restProps }: Props = $props();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<div class={cn('text-sm [&_p]:leading-relaxed', className)} {...restProps}>
|
|
15
|
+
{@render children()}
|
|
16
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
class?: string;
|
|
4
|
+
children: Snippet;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
declare const AlertDescription: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type AlertDescription = ReturnType<typeof AlertDescription>;
|
|
9
|
+
export default AlertDescription;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
import { tv, type VariantProps } from 'tailwind-variants';
|
|
6
|
+
|
|
7
|
+
const buttonVariants = tv({
|
|
8
|
+
base: 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
12
|
+
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
|
13
|
+
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
|
14
|
+
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
variant: 'default',
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
interface Props {
|
|
23
|
+
/** Whether the dialog is open */
|
|
24
|
+
open?: boolean;
|
|
25
|
+
/** Callback when open state changes */
|
|
26
|
+
onOpenChange?: (open: boolean) => void;
|
|
27
|
+
/** Dialog title */
|
|
28
|
+
title: string;
|
|
29
|
+
/** Dialog description */
|
|
30
|
+
description?: string;
|
|
31
|
+
/** Cancel button text */
|
|
32
|
+
cancelText?: string;
|
|
33
|
+
/** Confirm button text */
|
|
34
|
+
confirmText?: string;
|
|
35
|
+
/** Confirm button variant */
|
|
36
|
+
confirmVariant?: VariantProps<typeof buttonVariants>['variant'];
|
|
37
|
+
/** Callback when user confirms */
|
|
38
|
+
onConfirm?: () => void;
|
|
39
|
+
/** Callback when user cancels */
|
|
40
|
+
onCancel?: () => void;
|
|
41
|
+
/** Additional class for dialog content */
|
|
42
|
+
class?: string;
|
|
43
|
+
/** Optional trigger element */
|
|
44
|
+
trigger?: Snippet;
|
|
45
|
+
/** Optional custom content */
|
|
46
|
+
children?: Snippet;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let {
|
|
50
|
+
open = $bindable(false),
|
|
51
|
+
onOpenChange,
|
|
52
|
+
title,
|
|
53
|
+
description,
|
|
54
|
+
cancelText = 'Cancel',
|
|
55
|
+
confirmText = 'Continue',
|
|
56
|
+
confirmVariant = 'default',
|
|
57
|
+
onConfirm,
|
|
58
|
+
onCancel,
|
|
59
|
+
class: className,
|
|
60
|
+
trigger,
|
|
61
|
+
children,
|
|
62
|
+
}: Props = $props();
|
|
63
|
+
|
|
64
|
+
function handleOpenChange(newOpen: boolean) {
|
|
65
|
+
open = newOpen;
|
|
66
|
+
onOpenChange?.(newOpen);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function handleCancel() {
|
|
70
|
+
onCancel?.();
|
|
71
|
+
open = false;
|
|
72
|
+
onOpenChange?.(false);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function handleConfirm() {
|
|
76
|
+
onConfirm?.();
|
|
77
|
+
open = false;
|
|
78
|
+
onOpenChange?.(false);
|
|
79
|
+
}
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<AlertDialogPrimitive.Root bind:open onOpenChange={handleOpenChange}>
|
|
83
|
+
{#if trigger}
|
|
84
|
+
<AlertDialogPrimitive.Trigger asChild>
|
|
85
|
+
{#snippet child({ props })}
|
|
86
|
+
<span {...props}>
|
|
87
|
+
{@render trigger()}
|
|
88
|
+
</span>
|
|
89
|
+
{/snippet}
|
|
90
|
+
</AlertDialogPrimitive.Trigger>
|
|
91
|
+
{/if}
|
|
92
|
+
|
|
93
|
+
<AlertDialogPrimitive.Portal>
|
|
94
|
+
<AlertDialogPrimitive.Overlay
|
|
95
|
+
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
|
96
|
+
/>
|
|
97
|
+
<AlertDialogPrimitive.Content
|
|
98
|
+
class={cn(
|
|
99
|
+
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
|
100
|
+
className
|
|
101
|
+
)}
|
|
102
|
+
>
|
|
103
|
+
<div class="flex flex-col space-y-2 text-center sm:text-left">
|
|
104
|
+
<AlertDialogPrimitive.Title class="text-lg font-semibold">
|
|
105
|
+
{title}
|
|
106
|
+
</AlertDialogPrimitive.Title>
|
|
107
|
+
{#if description}
|
|
108
|
+
<AlertDialogPrimitive.Description class="text-sm text-muted-foreground">
|
|
109
|
+
{description}
|
|
110
|
+
</AlertDialogPrimitive.Description>
|
|
111
|
+
{/if}
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
{#if children}
|
|
115
|
+
<div class="py-2">
|
|
116
|
+
{@render children()}
|
|
117
|
+
</div>
|
|
118
|
+
{/if}
|
|
119
|
+
|
|
120
|
+
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
|
|
121
|
+
<AlertDialogPrimitive.Cancel
|
|
122
|
+
class={cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0 h-10 px-4 py-2')}
|
|
123
|
+
onclick={handleCancel}
|
|
124
|
+
>
|
|
125
|
+
{cancelText}
|
|
126
|
+
</AlertDialogPrimitive.Cancel>
|
|
127
|
+
<AlertDialogPrimitive.Action
|
|
128
|
+
class={cn(buttonVariants({ variant: confirmVariant }), 'h-10 px-4 py-2')}
|
|
129
|
+
onclick={handleConfirm}
|
|
130
|
+
>
|
|
131
|
+
{confirmText}
|
|
132
|
+
</AlertDialogPrimitive.Action>
|
|
133
|
+
</div>
|
|
134
|
+
</AlertDialogPrimitive.Content>
|
|
135
|
+
</AlertDialogPrimitive.Portal>
|
|
136
|
+
</AlertDialogPrimitive.Root>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
3
|
+
declare const AlertDialog: import("svelte").Component<{
|
|
4
|
+
/** Whether the dialog is open */
|
|
5
|
+
open?: boolean;
|
|
6
|
+
/** Callback when open state changes */
|
|
7
|
+
onOpenChange?: (open: boolean) => void;
|
|
8
|
+
/** Dialog title */
|
|
9
|
+
title: string;
|
|
10
|
+
/** Dialog description */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** Cancel button text */
|
|
13
|
+
cancelText?: string;
|
|
14
|
+
/** Confirm button text */
|
|
15
|
+
confirmText?: string;
|
|
16
|
+
/** Confirm button variant */
|
|
17
|
+
confirmVariant?: VariantProps<import("tailwind-variants").TVReturnType<{
|
|
18
|
+
variant: {
|
|
19
|
+
default: string;
|
|
20
|
+
destructive: string;
|
|
21
|
+
outline: string;
|
|
22
|
+
ghost: string;
|
|
23
|
+
};
|
|
24
|
+
}, undefined, "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", import("tailwind-variants/dist/config.js").TVConfig<{
|
|
25
|
+
variant: {
|
|
26
|
+
default: string;
|
|
27
|
+
destructive: string;
|
|
28
|
+
outline: string;
|
|
29
|
+
ghost: string;
|
|
30
|
+
};
|
|
31
|
+
}, {
|
|
32
|
+
variant: {
|
|
33
|
+
default: string;
|
|
34
|
+
destructive: string;
|
|
35
|
+
outline: string;
|
|
36
|
+
ghost: string;
|
|
37
|
+
};
|
|
38
|
+
}>, {
|
|
39
|
+
variant: {
|
|
40
|
+
default: string;
|
|
41
|
+
destructive: string;
|
|
42
|
+
outline: string;
|
|
43
|
+
ghost: string;
|
|
44
|
+
};
|
|
45
|
+
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
46
|
+
variant: {
|
|
47
|
+
default: string;
|
|
48
|
+
destructive: string;
|
|
49
|
+
outline: string;
|
|
50
|
+
ghost: string;
|
|
51
|
+
};
|
|
52
|
+
}, undefined, "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", import("tailwind-variants/dist/config.js").TVConfig<{
|
|
53
|
+
variant: {
|
|
54
|
+
default: string;
|
|
55
|
+
destructive: string;
|
|
56
|
+
outline: string;
|
|
57
|
+
ghost: string;
|
|
58
|
+
};
|
|
59
|
+
}, {
|
|
60
|
+
variant: {
|
|
61
|
+
default: string;
|
|
62
|
+
destructive: string;
|
|
63
|
+
outline: string;
|
|
64
|
+
ghost: string;
|
|
65
|
+
};
|
|
66
|
+
}>, unknown, unknown, undefined>>>["variant"];
|
|
67
|
+
/** Callback when user confirms */
|
|
68
|
+
onConfirm?: () => void;
|
|
69
|
+
/** Callback when user cancels */
|
|
70
|
+
onCancel?: () => void;
|
|
71
|
+
/** Additional class for dialog content */
|
|
72
|
+
class?: string;
|
|
73
|
+
/** Optional trigger element */
|
|
74
|
+
trigger?: Snippet;
|
|
75
|
+
/** Optional custom content */
|
|
76
|
+
children?: Snippet;
|
|
77
|
+
}, {}, "open">;
|
|
78
|
+
type AlertDialog = ReturnType<typeof AlertDialog>;
|
|
79
|
+
export default AlertDialog;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
class?: string;
|
|
7
|
+
children: Snippet;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { class: className, children, ...restProps }: Props = $props();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<h5 class={cn('mb-1 font-medium leading-none tracking-tight', className)} {...restProps}>
|
|
15
|
+
{@render children()}
|
|
16
|
+
</h5>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
class?: string;
|
|
4
|
+
children: Snippet;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
declare const AlertTitle: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type AlertTitle = ReturnType<typeof AlertTitle>;
|
|
9
|
+
export default AlertTitle;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Avatar - User/entity representation component
|
|
4
|
+
*
|
|
5
|
+
* Built on Bits UI Avatar primitive for accessibility and loading state handling.
|
|
6
|
+
* Displays user images with fallback placeholder support.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Multiple size variants (xs, sm, md, lg)
|
|
10
|
+
* - Automatic image loading state management
|
|
11
|
+
* - Fallback display when image fails/loading
|
|
12
|
+
* - Circular design by default
|
|
13
|
+
*/
|
|
14
|
+
import type { Snippet } from 'svelte';
|
|
15
|
+
import { Avatar as AvatarPrimitive } from 'bits-ui';
|
|
16
|
+
import { cn } from '../utils.js';
|
|
17
|
+
import { tv, type VariantProps } from 'tailwind-variants';
|
|
18
|
+
|
|
19
|
+
const avatarVariants = tv({
|
|
20
|
+
base: 'relative flex shrink-0 overflow-hidden rounded-full',
|
|
21
|
+
variants: {
|
|
22
|
+
size: {
|
|
23
|
+
xs: 'h-6 w-6',
|
|
24
|
+
sm: 'h-8 w-8',
|
|
25
|
+
md: 'h-10 w-10',
|
|
26
|
+
lg: 'h-12 w-12',
|
|
27
|
+
xl: 'h-16 w-16',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
defaultVariants: {
|
|
31
|
+
size: 'md',
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
type AvatarVariants = VariantProps<typeof avatarVariants>;
|
|
36
|
+
|
|
37
|
+
interface Props {
|
|
38
|
+
/** Size variant */
|
|
39
|
+
size?: AvatarVariants['size'];
|
|
40
|
+
/** Delay before showing fallback (ms) */
|
|
41
|
+
delayMs?: number;
|
|
42
|
+
/** Additional classes */
|
|
43
|
+
class?: string;
|
|
44
|
+
/** Avatar content (AvatarImage and/or AvatarFallback) */
|
|
45
|
+
children: Snippet;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let { size = 'md', delayMs = 0, class: className, children, ...restProps }: Props = $props();
|
|
50
|
+
|
|
51
|
+
const classes = $derived(cn(avatarVariants({ size }), className));
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<AvatarPrimitive.Root class={classes} {delayMs} {...restProps}>
|
|
55
|
+
{@render children()}
|
|
56
|
+
</AvatarPrimitive.Root>
|