ui-svelte 0.1.0 → 0.2.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/LICENSE +1 -1
- package/README.md +6 -6
- package/dist/control/Audio.svelte +2 -2
- package/dist/control/Audio.svelte.d.ts +1 -1
- package/dist/control/Record.svelte +7 -11
- package/dist/css/base.css +1 -1
- package/dist/display/Item.svelte +7 -1
- package/dist/display/Item.svelte.d.ts +2 -0
- package/dist/display/Section.svelte +10 -2
- package/dist/display/css/card.css +1 -1
- package/dist/display/css/item.css +12 -0
- package/dist/form/TextField.svelte +24 -6
- package/dist/form/TextField.svelte.d.ts +5 -3
- package/dist/index.css +2 -2
- package/dist/layout/AppBar.svelte +12 -3
- package/dist/layout/AppBar.svelte.d.ts +2 -0
- package/dist/layout/Footer.svelte +3 -1
- package/dist/layout/Footer.svelte.d.ts +1 -0
- package/dist/layout/Scaffold.svelte +10 -4
- package/dist/layout/Scaffold.svelte.d.ts +1 -0
- package/dist/layout/css/app-bar.css +9 -6
- package/dist/layout/css/scaffold.css +9 -3
- package/dist/layout/css/sidebar.css +4 -4
- package/dist/navigation/SideNav.svelte +18 -8
- package/dist/navigation/css/nav-menu.css +2 -2
- package/dist/navigation/css/side-nav.css +6 -8
- package/dist/overlay/Dropdown.svelte +3 -0
- package/dist/types.d.ts +2 -59
- package/package.json +3 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**A modern, accessible UI component library built for Svelte 5**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Ui Svelte is a comprehensive UI component library designed to leverage Svelte 5's latest features. Build beautiful, accessible interfaces with minimal configuration and maximum developer experience.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -62,7 +62,7 @@ Optimized bundle size with tree-shaking support. Only import what you need for b
|
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
64
|
# or
|
|
65
|
-
bun add
|
|
65
|
+
bun add ui-svelte
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
---
|
|
@@ -71,13 +71,13 @@ bun add sappsui
|
|
|
71
71
|
|
|
72
72
|
```svelte
|
|
73
73
|
<script lang="ts">
|
|
74
|
-
import { Button, Card, TextField } from '
|
|
74
|
+
import { Button, Card, TextField } from 'ui-svelte';
|
|
75
75
|
|
|
76
76
|
let name = $state('');
|
|
77
77
|
</script>
|
|
78
78
|
|
|
79
79
|
<Card>
|
|
80
|
-
<h2>Welcome to
|
|
80
|
+
<h2>Welcome to Ui Svelte</h2>
|
|
81
81
|
|
|
82
82
|
<TextField name="username" label="Your Name" placeholder="Enter your name..." bind:value={name} />
|
|
83
83
|
|
|
@@ -109,9 +109,9 @@ SappsUI includes a comprehensive set of components for building modern web appli
|
|
|
109
109
|
|
|
110
110
|
## 🌟 Support
|
|
111
111
|
|
|
112
|
-
If you find
|
|
112
|
+
If you find UiSvelte helpful, please consider giving it a star on GitHub! Your support helps us continue improving the library.
|
|
113
113
|
|
|
114
|
-
For questions, issues, or feature requests, please visit our [GitHub Issues](https://github.com/sappsdev/
|
|
114
|
+
For questions, issues, or feature requests, please visit our [GitHub Issues](https://github.com/sappsdev/ui-svelte/issues) page.
|
|
115
115
|
|
|
116
116
|
---
|
|
117
117
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
variant?:
|
|
10
10
|
| 'primary'
|
|
11
11
|
| 'secondary'
|
|
12
|
-
| '
|
|
12
|
+
| 'muted'
|
|
13
13
|
| 'outlined'
|
|
14
14
|
| 'ghost'
|
|
15
15
|
| 'success'
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
<div class={baseClasses}>
|
|
177
177
|
<audio bind:this={audio} {src}></audio>
|
|
178
178
|
|
|
179
|
-
<Button onclick={togglePlay} size="md" variant
|
|
179
|
+
<Button onclick={togglePlay} size="md" {variant}>
|
|
180
180
|
{#if isPlaying}
|
|
181
181
|
<Icon icon={Pause24RegularIcon} />
|
|
182
182
|
{:else}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
type Props = {
|
|
2
2
|
class?: string;
|
|
3
3
|
src: string;
|
|
4
|
-
variant?: 'primary' | 'secondary' | '
|
|
4
|
+
variant?: 'primary' | 'secondary' | 'muted' | 'outlined' | 'ghost' | 'success' | 'info' | 'danger' | 'warning';
|
|
5
5
|
};
|
|
6
6
|
declare const Audio: import("svelte").Component<Props, {}, "">;
|
|
7
7
|
type Audio = ReturnType<typeof Audio>;
|
|
@@ -110,7 +110,6 @@
|
|
|
110
110
|
visualize();
|
|
111
111
|
} catch (error) {
|
|
112
112
|
console.error('Error accessing microphone:', error);
|
|
113
|
-
alert('No se pudo acceder al micrófono');
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
115
|
|
|
@@ -135,11 +134,8 @@
|
|
|
135
134
|
if (!response.ok) {
|
|
136
135
|
throw new Error(`Upload failed: ${response.statusText}`);
|
|
137
136
|
}
|
|
138
|
-
|
|
139
|
-
console.log('Audio uploaded successfully');
|
|
140
137
|
} catch (error) {
|
|
141
138
|
console.error('Error uploading audio:', error);
|
|
142
|
-
alert('Error al subir el audio');
|
|
143
139
|
} finally {
|
|
144
140
|
isUploading = false;
|
|
145
141
|
}
|
|
@@ -354,7 +350,7 @@
|
|
|
354
350
|
|
|
355
351
|
<div class={baseClasses}>
|
|
356
352
|
{#if isReviewing}
|
|
357
|
-
<Button onclick={togglePlayback} size="md" variant
|
|
353
|
+
<Button onclick={togglePlayback} size="md" {variant}>
|
|
358
354
|
{#if isPlaying}
|
|
359
355
|
<Icon icon={Pause24RegularIcon} />
|
|
360
356
|
{:else}
|
|
@@ -376,18 +372,18 @@
|
|
|
376
372
|
<span class="media-time">{formatTime(recordingTime)}</span>
|
|
377
373
|
|
|
378
374
|
<div class="flex gap-2">
|
|
379
|
-
<Button onclick={discardRecording} size="md" variant
|
|
375
|
+
<Button onclick={discardRecording} size="md" {variant}>
|
|
380
376
|
<Icon icon={Delete24RegularIcon} />
|
|
381
377
|
</Button>
|
|
382
|
-
<Button onclick={continueRecording} size="md" variant
|
|
378
|
+
<Button onclick={continueRecording} size="md" {variant}>
|
|
383
379
|
<Icon icon={Record24RegularIcon} />
|
|
384
380
|
</Button>
|
|
385
|
-
<Button onclick={confirmRecording} size="md" variant
|
|
381
|
+
<Button onclick={confirmRecording} size="md" {variant}>
|
|
386
382
|
<Icon icon={Checkmark24RegularIcon} />
|
|
387
383
|
</Button>
|
|
388
384
|
</div>
|
|
389
385
|
{:else if !isRecording}
|
|
390
|
-
<Button onclick={startRecording} size="md" variant
|
|
386
|
+
<Button onclick={startRecording} size="md" {variant}>
|
|
391
387
|
<Icon icon={Record24RegularIcon} />
|
|
392
388
|
</Button>
|
|
393
389
|
|
|
@@ -401,7 +397,7 @@
|
|
|
401
397
|
|
|
402
398
|
<span class="media-time">{formatTime(recordingTime)}</span>
|
|
403
399
|
{:else}
|
|
404
|
-
<Button onclick={handleToggleRecording} size="md" variant
|
|
400
|
+
<Button onclick={handleToggleRecording} size="md" {variant}>
|
|
405
401
|
{#if isPaused}
|
|
406
402
|
<Icon icon={Play24RegularIcon} />
|
|
407
403
|
{:else}
|
|
@@ -423,7 +419,7 @@
|
|
|
423
419
|
|
|
424
420
|
<span class="media-time">{formatTime(recordingTime)}</span>
|
|
425
421
|
|
|
426
|
-
<Button onclick={stopRecording} size="md" variant
|
|
422
|
+
<Button onclick={stopRecording} size="md" {variant} isLoading={isUploading}>
|
|
427
423
|
<Icon icon={RecordStop24RegularIcon} />
|
|
428
424
|
</Button>
|
|
429
425
|
{/if}
|
package/dist/css/base.css
CHANGED
package/dist/display/Item.svelte
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { Avatar } from '../index.js';
|
|
2
|
+
import { Avatar, Icon } from '../index.js';
|
|
3
3
|
import { cn } from '../utils/class-names.js';
|
|
4
4
|
import type { Snippet } from 'svelte';
|
|
5
|
+
import type { IconData } from './Icon.svelte';
|
|
5
6
|
|
|
6
7
|
type Props = {
|
|
7
8
|
id?: string | number;
|
|
8
9
|
label?: string;
|
|
9
10
|
description?: string;
|
|
11
|
+
icon?: IconData;
|
|
10
12
|
src?: string;
|
|
11
13
|
variant?: 'ghost' | 'outlined' | 'surface' | 'primary' | 'secondary' | 'muted';
|
|
12
14
|
size?: 'sm' | 'md' | 'lg';
|
|
@@ -29,6 +31,7 @@
|
|
|
29
31
|
label,
|
|
30
32
|
description,
|
|
31
33
|
src,
|
|
34
|
+
icon,
|
|
32
35
|
variant = 'ghost',
|
|
33
36
|
size = 'md',
|
|
34
37
|
status,
|
|
@@ -88,6 +91,9 @@
|
|
|
88
91
|
</script>
|
|
89
92
|
|
|
90
93
|
{#snippet itemContent()}
|
|
94
|
+
{#if icon}
|
|
95
|
+
<Icon {icon} />
|
|
96
|
+
{/if}
|
|
91
97
|
{#if src}
|
|
92
98
|
<Avatar {src} {status} size={avatarSizes[size]} variant="transparent" />
|
|
93
99
|
{/if}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { IconData } from './Icon.svelte';
|
|
2
3
|
type Props = {
|
|
3
4
|
id?: string | number;
|
|
4
5
|
label?: string;
|
|
5
6
|
description?: string;
|
|
7
|
+
icon?: IconData;
|
|
6
8
|
src?: string;
|
|
7
9
|
variant?: 'ghost' | 'outlined' | 'surface' | 'primary' | 'secondary' | 'muted';
|
|
8
10
|
size?: 'sm' | 'md' | 'lg';
|
|
@@ -50,14 +50,22 @@
|
|
|
50
50
|
};
|
|
51
51
|
</script>
|
|
52
52
|
|
|
53
|
-
<div
|
|
53
|
+
<div
|
|
54
|
+
class={cn(
|
|
55
|
+
'section',
|
|
56
|
+
variantClasses[variant],
|
|
57
|
+
isSolid && 'is-solid',
|
|
58
|
+
isBoxed && 'boxed',
|
|
59
|
+
className
|
|
60
|
+
)}
|
|
61
|
+
>
|
|
54
62
|
{#if cover}
|
|
55
63
|
<img src={cover} alt="cover" class={cn('section-cover', coverClass)} />
|
|
56
64
|
{/if}
|
|
57
65
|
{#if hasOverlay}
|
|
58
66
|
<div class={cn('section-overlay', overlayClass)}></div>
|
|
59
67
|
{/if}
|
|
60
|
-
<div class={cn('section-body',
|
|
68
|
+
<div class={cn('section-body', bodyClass)}>
|
|
61
69
|
{@render children()}
|
|
62
70
|
</div>
|
|
63
71
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
.card {
|
|
3
3
|
@apply relative flex flex-col rounded-ui overflow-hidden;
|
|
4
|
-
@apply transition-
|
|
4
|
+
@apply transition-all duration-300 ease-in-out;
|
|
5
5
|
|
|
6
6
|
&:has(> .card-cover) {
|
|
7
7
|
@apply bg-transparent! text-white! text-shadow-sm! z-0;
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
.item.is-sm {
|
|
18
18
|
@apply p-2 gap-2;
|
|
19
19
|
|
|
20
|
+
.icon {
|
|
21
|
+
@apply w-4 h-4;
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
.item-label {
|
|
21
25
|
@apply text-sm;
|
|
22
26
|
}
|
|
@@ -29,6 +33,10 @@
|
|
|
29
33
|
.item.is-md {
|
|
30
34
|
@apply p-3 gap-3;
|
|
31
35
|
|
|
36
|
+
.icon {
|
|
37
|
+
@apply w-5 h-5;
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
.item-label {
|
|
33
41
|
@apply text-base;
|
|
34
42
|
}
|
|
@@ -41,6 +49,10 @@
|
|
|
41
49
|
.item.is-lg {
|
|
42
50
|
@apply p-4 gap-4;
|
|
43
51
|
|
|
52
|
+
.icon {
|
|
53
|
+
@apply w-6 h-6;
|
|
54
|
+
}
|
|
55
|
+
|
|
44
56
|
.item-label {
|
|
45
57
|
@apply text-lg;
|
|
46
58
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { Icon } from '../index.js';
|
|
3
|
+
import type { IconData } from '../types.js';
|
|
2
4
|
import { cn } from '../utils/class-names.js';
|
|
3
5
|
import type { Snippet } from 'svelte';
|
|
4
6
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
@@ -11,8 +13,10 @@
|
|
|
11
13
|
type?: 'text' | 'password' | 'email' | 'number' | 'tel' | 'url';
|
|
12
14
|
class?: string;
|
|
13
15
|
controlClass?: string;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
startIcon?: IconData;
|
|
17
|
+
endIcon?: IconData;
|
|
18
|
+
startText?: string;
|
|
19
|
+
endText?: string;
|
|
16
20
|
onchange?: (value: unknown) => void;
|
|
17
21
|
oninput?: (value: unknown) => void;
|
|
18
22
|
variant?: 'primary' | 'secondary' | 'muted' | 'outlined' | 'line';
|
|
@@ -39,8 +43,10 @@
|
|
|
39
43
|
type = 'text',
|
|
40
44
|
class: className,
|
|
41
45
|
controlClass,
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
startIcon,
|
|
47
|
+
endIcon,
|
|
48
|
+
startText,
|
|
49
|
+
endText,
|
|
44
50
|
onchange,
|
|
45
51
|
oninput,
|
|
46
52
|
variant = 'outlined',
|
|
@@ -119,7 +125,13 @@
|
|
|
119
125
|
</span>
|
|
120
126
|
{/if}
|
|
121
127
|
|
|
122
|
-
{
|
|
128
|
+
{#if startIcon}
|
|
129
|
+
<Icon icon={startIcon} class={iconClasses} />
|
|
130
|
+
{/if}
|
|
131
|
+
|
|
132
|
+
{#if startText}
|
|
133
|
+
<span class={textClasses}>{startText}</span>
|
|
134
|
+
{/if}
|
|
123
135
|
|
|
124
136
|
<input
|
|
125
137
|
{type}
|
|
@@ -143,7 +155,13 @@
|
|
|
143
155
|
onfocusout={() => (isFocused = false)}
|
|
144
156
|
/>
|
|
145
157
|
|
|
146
|
-
{
|
|
158
|
+
{#if endText}
|
|
159
|
+
<span class={textClasses}>{endText}</span>
|
|
160
|
+
{/if}
|
|
161
|
+
|
|
162
|
+
{#if endIcon}
|
|
163
|
+
<Icon icon={endIcon} class={iconClasses} />
|
|
164
|
+
{/if}
|
|
147
165
|
</label>
|
|
148
166
|
|
|
149
167
|
{#if errorText || helpText}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IconData } from '../types.js';
|
|
2
2
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
3
|
type Props = {
|
|
4
4
|
el?: HTMLInputElement;
|
|
@@ -8,8 +8,10 @@ type Props = {
|
|
|
8
8
|
type?: 'text' | 'password' | 'email' | 'number' | 'tel' | 'url';
|
|
9
9
|
class?: string;
|
|
10
10
|
controlClass?: string;
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
startIcon?: IconData;
|
|
12
|
+
endIcon?: IconData;
|
|
13
|
+
startText?: string;
|
|
14
|
+
endText?: string;
|
|
13
15
|
onchange?: (value: unknown) => void;
|
|
14
16
|
oninput?: (value: unknown) => void;
|
|
15
17
|
variant?: 'primary' | 'secondary' | 'muted' | 'outlined' | 'line';
|
package/dist/index.css
CHANGED
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
--color-primary: var(--primary, oklch(54.6% 0.245 262.881)); /* blue-600 */
|
|
72
72
|
--color-on-primary: var(--on-primary, oklch(93.2% 0.032 255.585)); /* blue-100 */
|
|
73
73
|
|
|
74
|
-
--color-secondary: var(--secondary, oklch(
|
|
75
|
-
--color-on-secondary: var(--on-secondary, oklch(
|
|
74
|
+
--color-secondary: var(--secondary, oklch(0.592 0.249 0.584)); /* pink-600 */
|
|
75
|
+
--color-on-secondary: var(--on-secondary, oklch(0.948 0.028 342.258)); /* pink-100 */
|
|
76
76
|
|
|
77
77
|
--color-muted: var(--muted, oklch(87.2% 0.01 258.338)); /* gray-300 */
|
|
78
78
|
--color-on-muted: var(--on-muted, oklch(27.8% 0.033 256.848)); /* gray-700 */
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
isBlurred?: boolean;
|
|
16
16
|
isBordered?: boolean;
|
|
17
17
|
hideOnScroll?: boolean;
|
|
18
|
+
isSticky?: boolean;
|
|
19
|
+
isBoxed?: boolean;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
const {
|
|
@@ -28,6 +30,8 @@
|
|
|
28
30
|
endClass,
|
|
29
31
|
isBordered,
|
|
30
32
|
isBlurred,
|
|
33
|
+
isSticky,
|
|
34
|
+
isBoxed,
|
|
31
35
|
hideOnScroll
|
|
32
36
|
}: Props = $props();
|
|
33
37
|
|
|
@@ -48,14 +52,18 @@
|
|
|
48
52
|
});
|
|
49
53
|
|
|
50
54
|
$effect(() => {
|
|
51
|
-
if (hideOnScroll
|
|
55
|
+
if (!hideOnScroll) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (scroll.scrollY > headerHeight) {
|
|
52
60
|
if (scroll.scrollY > lastScrollY) {
|
|
53
61
|
isHidden = true;
|
|
54
62
|
} else if (scroll.scrollY < lastScrollY) {
|
|
55
63
|
isHidden = false;
|
|
56
64
|
}
|
|
57
65
|
lastScrollY = scroll.scrollY;
|
|
58
|
-
} else
|
|
66
|
+
} else {
|
|
59
67
|
isHidden = false;
|
|
60
68
|
lastScrollY = scroll.scrollY;
|
|
61
69
|
}
|
|
@@ -71,10 +79,11 @@
|
|
|
71
79
|
isBordered && 'is-bordered',
|
|
72
80
|
shouldBlur && 'is-blurred',
|
|
73
81
|
isHidden && 'is-hidden',
|
|
82
|
+
isSticky && 'is-sticky',
|
|
74
83
|
className
|
|
75
84
|
)}
|
|
76
85
|
>
|
|
77
|
-
<div class={cn('appbar-content', contentClass)}>
|
|
86
|
+
<div class={cn('appbar-content', isBoxed && 'boxed', contentClass)}>
|
|
78
87
|
{#if start}
|
|
79
88
|
<div class={cn('appbar-start', startClass)}>
|
|
80
89
|
{@render start()}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
endClass?: string;
|
|
15
15
|
isBlurred?: boolean;
|
|
16
16
|
isBordered?: boolean;
|
|
17
|
+
isBoxed?: boolean;
|
|
17
18
|
hideOnScroll?: boolean;
|
|
18
19
|
};
|
|
19
20
|
|
|
@@ -28,6 +29,7 @@
|
|
|
28
29
|
endClass,
|
|
29
30
|
isBordered,
|
|
30
31
|
isBlurred,
|
|
32
|
+
isBoxed,
|
|
31
33
|
hideOnScroll
|
|
32
34
|
}: Props = $props();
|
|
33
35
|
|
|
@@ -74,7 +76,7 @@
|
|
|
74
76
|
className
|
|
75
77
|
)}
|
|
76
78
|
>
|
|
77
|
-
<div class={cn('footer-content', contentClass)}>
|
|
79
|
+
<div class={cn('footer-content', isBoxed && 'boxed', contentClass)}>
|
|
78
80
|
{#if start}
|
|
79
81
|
<div class={cn('footer-start', startClass)}>
|
|
80
82
|
{@render start()}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
mainClass?: string;
|
|
13
13
|
startClass?: string;
|
|
14
14
|
endClass?: string;
|
|
15
|
+
isBoxed?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
const {
|
|
@@ -23,15 +24,18 @@
|
|
|
23
24
|
bodyClass,
|
|
24
25
|
mainClass,
|
|
25
26
|
startClass,
|
|
26
|
-
endClass
|
|
27
|
+
endClass,
|
|
28
|
+
isBoxed
|
|
27
29
|
}: Props = $props();
|
|
28
30
|
</script>
|
|
29
31
|
|
|
30
32
|
{@render appBar?.()}
|
|
31
|
-
<div class={cn('scaffold-body', bodyClass)}>
|
|
33
|
+
<div class={cn('scaffold-body', isBoxed && 'boxed', bodyClass)}>
|
|
32
34
|
{#if start}
|
|
33
35
|
<aside class={cn('scaffold-start', startClass)}>
|
|
34
|
-
{
|
|
36
|
+
<div class={cn('scaffold-content')}>
|
|
37
|
+
{@render start()}
|
|
38
|
+
</div>
|
|
35
39
|
</aside>
|
|
36
40
|
{/if}
|
|
37
41
|
<div class={cn('scaffold-main', mainClass)}>
|
|
@@ -39,7 +43,9 @@
|
|
|
39
43
|
</div>
|
|
40
44
|
{#if end}
|
|
41
45
|
<aside class={cn('scaffold-end', endClass)}>
|
|
42
|
-
{
|
|
46
|
+
<div class={cn('scaffold-content')}>
|
|
47
|
+
{@render end()}
|
|
48
|
+
</div>
|
|
43
49
|
</aside>
|
|
44
50
|
{/if}
|
|
45
51
|
</div>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
.appbar {
|
|
3
|
-
@apply w-full
|
|
4
|
-
|
|
3
|
+
@apply w-full z-30;
|
|
4
|
+
|
|
5
|
+
&.is-sticky {
|
|
6
|
+
@apply fixed top-0;
|
|
7
|
+
}
|
|
5
8
|
|
|
6
9
|
&.is-blurred {
|
|
7
|
-
@apply backdrop-blur-lg
|
|
10
|
+
@apply backdrop-blur-lg;
|
|
8
11
|
}
|
|
9
12
|
|
|
10
13
|
&.is-bordered {
|
|
@@ -20,15 +23,15 @@
|
|
|
20
23
|
@apply w-full px-2 h-full min-h-12;
|
|
21
24
|
|
|
22
25
|
.appbar-start {
|
|
23
|
-
@apply flex flex-nowrap justify-start items-center p-
|
|
26
|
+
@apply flex flex-nowrap justify-start items-center p-3 gap-3 relative;
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
.appbar-center {
|
|
27
|
-
@apply flex flex-1 flex-nowrap justify-center items-center p-
|
|
30
|
+
@apply flex flex-1 flex-nowrap justify-center items-center p-3 gap-3 relative;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
.appbar-end {
|
|
31
|
-
@apply flex flex-nowrap justify-end items-center p-
|
|
34
|
+
@apply flex flex-nowrap justify-end items-center p-3 gap-3 relative;
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
.scaffold-body {
|
|
3
3
|
@apply flex h-full w-full relative;
|
|
4
|
-
@apply bg-background text-on-background;
|
|
5
4
|
.scaffold-main {
|
|
6
5
|
@apply relative flex-1 flex flex-col min-w-0;
|
|
7
6
|
}
|
|
8
7
|
.scaffold-start {
|
|
9
|
-
@apply
|
|
8
|
+
@apply relative;
|
|
10
9
|
}
|
|
11
10
|
.scaffold-end {
|
|
12
|
-
@apply
|
|
11
|
+
@apply relative;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.scaffold-start,
|
|
15
|
+
.scaffold-end {
|
|
16
|
+
.scaffold-content {
|
|
17
|
+
@apply fixed w-fit h-full;
|
|
18
|
+
}
|
|
13
19
|
}
|
|
14
20
|
}
|
|
15
21
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
.sidebar {
|
|
3
|
-
@apply flex h-full flex-col
|
|
3
|
+
@apply flex w-fit h-full flex-col;
|
|
4
4
|
|
|
5
5
|
.sidebar-header {
|
|
6
|
-
@apply flex flex-col gap-3 p-3;
|
|
6
|
+
@apply relative flex flex-col gap-3 p-3;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
.sidebar-footer {
|
|
10
|
-
@apply flex flex-col gap-3 p-3;
|
|
10
|
+
@apply relative flex flex-col gap-3 p-3;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
.sidebar-body {
|
|
14
|
-
@apply flex min-h-0
|
|
14
|
+
@apply relative flex min-h-0 w-full flex-col gap-3 p-3 overflow-hidden hover:overflow-y-auto;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -43,13 +43,15 @@
|
|
|
43
43
|
class: className,
|
|
44
44
|
variant = 'primary',
|
|
45
45
|
size = 'md',
|
|
46
|
-
isWide
|
|
47
|
-
isCompact
|
|
48
|
-
isCollapsible
|
|
46
|
+
isWide,
|
|
47
|
+
isCompact,
|
|
48
|
+
isCollapsible
|
|
49
49
|
}: Props = $props();
|
|
50
50
|
|
|
51
|
-
let openSubmenus = $state<Record<number, boolean>>(
|
|
52
|
-
|
|
51
|
+
let openSubmenus = $state<Record<number, boolean>>({});
|
|
52
|
+
|
|
53
|
+
$effect(() => {
|
|
54
|
+
const initialState = items.reduce(
|
|
53
55
|
(acc, item, index) => {
|
|
54
56
|
if (item.type === 'submenu' && item.open) {
|
|
55
57
|
acc[index] = true;
|
|
@@ -57,10 +59,15 @@
|
|
|
57
59
|
return acc;
|
|
58
60
|
},
|
|
59
61
|
{} as Record<number, boolean>
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
+
);
|
|
63
|
+
openSubmenus = initialState;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
let isExpanded = $state(true);
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
$effect(() => {
|
|
69
|
+
isExpanded = !isCollapsible;
|
|
70
|
+
});
|
|
64
71
|
|
|
65
72
|
const variantClasses = {
|
|
66
73
|
primary: 'sidenav-primary',
|
|
@@ -184,6 +191,9 @@
|
|
|
184
191
|
class="sidenav-header sidenav-submenu-trigger"
|
|
185
192
|
onclick={() => toggleSubmenu(index)}
|
|
186
193
|
>
|
|
194
|
+
{#if item.icon}
|
|
195
|
+
<Icon icon={item.icon} />
|
|
196
|
+
{/if}
|
|
187
197
|
{#if isExpanded || !isCollapsible}
|
|
188
198
|
<div class="sidenav-header-content">
|
|
189
199
|
<div class="sidenav-header-label">{item.label}</div>
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
|
|
80
80
|
&.navmenu-primary {
|
|
81
81
|
.navmenu-item.is-active {
|
|
82
|
-
@apply bg-primary
|
|
82
|
+
@apply bg-on-primary text-primary;
|
|
83
83
|
|
|
84
84
|
.navmenu-icon {
|
|
85
85
|
@apply text-primary;
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
|
|
90
90
|
&.navmenu-secondary {
|
|
91
91
|
.navmenu-item.is-active {
|
|
92
|
-
@apply bg-secondary
|
|
92
|
+
@apply bg-on-secondary text-secondary;
|
|
93
93
|
|
|
94
94
|
.navmenu-icon {
|
|
95
95
|
@apply text-secondary;
|
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
|
|
30
30
|
&.sidenav-header-link {
|
|
31
31
|
@apply cursor-pointer rounded-ui outline-none;
|
|
32
|
-
@apply transition-all duration-200;
|
|
33
32
|
@apply hover:bg-muted/50;
|
|
34
33
|
|
|
35
34
|
&.is-active {
|
|
@@ -51,7 +50,7 @@
|
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
.sidenav-item {
|
|
54
|
-
@apply relative flex w-fit items-center gap-2 rounded-ui
|
|
53
|
+
@apply relative flex w-fit items-center gap-2 rounded-ui px-3 py-2;
|
|
55
54
|
@apply cursor-pointer select-none outline-none;
|
|
56
55
|
@apply hover:bg-muted;
|
|
57
56
|
|
|
@@ -102,7 +101,7 @@
|
|
|
102
101
|
|
|
103
102
|
&.is-sm {
|
|
104
103
|
.sidenav-item {
|
|
105
|
-
@apply gap-1.5
|
|
104
|
+
@apply gap-1.5 px-2 py-1.5 text-xs;
|
|
106
105
|
|
|
107
106
|
.sidenav-icon-wrapper .sidenav-icon {
|
|
108
107
|
@apply h-4 w-4;
|
|
@@ -120,7 +119,7 @@
|
|
|
120
119
|
|
|
121
120
|
&.is-md {
|
|
122
121
|
.sidenav-item {
|
|
123
|
-
@apply gap-2
|
|
122
|
+
@apply gap-2 px-3 py-2 text-sm;
|
|
124
123
|
|
|
125
124
|
.sidenav-icon-wrapper .sidenav-icon {
|
|
126
125
|
@apply h-5 w-5;
|
|
@@ -138,7 +137,7 @@
|
|
|
138
137
|
|
|
139
138
|
&.is-lg {
|
|
140
139
|
.sidenav-item {
|
|
141
|
-
@apply gap-3
|
|
140
|
+
@apply gap-3 px-4 py-3 text-base;
|
|
142
141
|
|
|
143
142
|
.sidenav-icon-wrapper .sidenav-icon {
|
|
144
143
|
@apply h-6 w-6;
|
|
@@ -227,16 +226,15 @@
|
|
|
227
226
|
|
|
228
227
|
.sidenav-submenu-trigger {
|
|
229
228
|
@apply w-full cursor-pointer rounded-ui outline-none;
|
|
230
|
-
@apply transition-all duration-200;
|
|
231
229
|
@apply hover:bg-muted/50;
|
|
232
230
|
@apply justify-start;
|
|
233
231
|
}
|
|
234
232
|
|
|
235
233
|
.sidenav-submenu-content {
|
|
236
|
-
@apply ml-
|
|
234
|
+
@apply ml-5 flex flex-col gap-0.5 border-l border-muted pl-2;
|
|
237
235
|
|
|
238
236
|
.sidenav-subitem {
|
|
239
|
-
@apply text-sm
|
|
237
|
+
@apply text-sm;
|
|
240
238
|
}
|
|
241
239
|
}
|
|
242
240
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Item } from '../index.js';
|
|
3
|
+
import type { IconData } from '../types.js';
|
|
3
4
|
import { onMount, type Snippet } from 'svelte';
|
|
4
5
|
|
|
5
6
|
type Option = {
|
|
@@ -7,6 +8,7 @@
|
|
|
7
8
|
label: string;
|
|
8
9
|
description?: string;
|
|
9
10
|
src?: string;
|
|
11
|
+
icon?: IconData;
|
|
10
12
|
href?: string;
|
|
11
13
|
onclick?: (option: Option) => void;
|
|
12
14
|
};
|
|
@@ -125,6 +127,7 @@
|
|
|
125
127
|
<Item
|
|
126
128
|
label={item.label}
|
|
127
129
|
src={item.src}
|
|
130
|
+
icon={item.icon}
|
|
128
131
|
description={item.description}
|
|
129
132
|
id={item.id}
|
|
130
133
|
href={item.href}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { IconData } from './display/Icon.svelte';
|
|
1
2
|
export interface DatePosition {
|
|
2
3
|
top: number;
|
|
3
4
|
left: number;
|
|
@@ -14,62 +15,4 @@ export type BandScale = ((value: string) => number) & {
|
|
|
14
15
|
bandwidth: () => number;
|
|
15
16
|
step: () => number;
|
|
16
17
|
};
|
|
17
|
-
export
|
|
18
|
-
[key: string]: {
|
|
19
|
-
label: string;
|
|
20
|
-
color: string;
|
|
21
|
-
icon?: string;
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
export interface ChartDataPoint {
|
|
25
|
-
[key: string]: string | number;
|
|
26
|
-
}
|
|
27
|
-
export interface ChartMargin {
|
|
28
|
-
top: number;
|
|
29
|
-
right: number;
|
|
30
|
-
bottom: number;
|
|
31
|
-
left: number;
|
|
32
|
-
}
|
|
33
|
-
export type ChartData = ChartDataPoint[];
|
|
34
|
-
export interface ChartProps {
|
|
35
|
-
data: ChartData;
|
|
36
|
-
config: ChartConfig;
|
|
37
|
-
className?: string;
|
|
38
|
-
width?: number;
|
|
39
|
-
height?: number;
|
|
40
|
-
}
|
|
41
|
-
export interface BarChartProps extends ChartProps {
|
|
42
|
-
xKey: string;
|
|
43
|
-
yKeys: string[];
|
|
44
|
-
showGrid?: boolean;
|
|
45
|
-
showAxis?: boolean;
|
|
46
|
-
barSpacing?: number;
|
|
47
|
-
}
|
|
48
|
-
export interface LineChartProps extends ChartProps {
|
|
49
|
-
xKey: string;
|
|
50
|
-
yKeys: string[];
|
|
51
|
-
showGrid?: boolean;
|
|
52
|
-
showAxis?: boolean;
|
|
53
|
-
smooth?: boolean;
|
|
54
|
-
showDots?: boolean;
|
|
55
|
-
}
|
|
56
|
-
export interface PieChartProps extends ChartProps {
|
|
57
|
-
valueKey: string;
|
|
58
|
-
labelKey: string;
|
|
59
|
-
showLabels?: boolean;
|
|
60
|
-
innerRadius?: number;
|
|
61
|
-
}
|
|
62
|
-
export interface AreaChartProps extends ChartProps {
|
|
63
|
-
xKey: string;
|
|
64
|
-
yKeys: string[];
|
|
65
|
-
showGrid?: boolean;
|
|
66
|
-
showAxis?: boolean;
|
|
67
|
-
smooth?: boolean;
|
|
68
|
-
stacked?: boolean;
|
|
69
|
-
}
|
|
70
|
-
export interface DoughnutChartProps extends ChartProps {
|
|
71
|
-
valueKey: string;
|
|
72
|
-
labelKey: string;
|
|
73
|
-
showLabels?: boolean;
|
|
74
|
-
innerRadius?: number;
|
|
75
|
-
}
|
|
18
|
+
export type { IconData };
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ui-svelte",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "SappsDev",
|
|
6
6
|
"email": "info@sappsdev.com"
|
|
7
7
|
},
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/sappsdev/
|
|
10
|
+
"url": "https://github.com/sappsdev/ui-svelte.git"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"@sveltejs/adapter-auto": "^6.1.0",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"!dist/**/*.test.*",
|
|
44
44
|
"!dist/**/*.spec.*"
|
|
45
45
|
],
|
|
46
|
-
"homepage": "https://svelte.sappsdev.com",
|
|
46
|
+
"homepage": "https://ui-svelte.sappsdev.com",
|
|
47
47
|
"keywords": [
|
|
48
48
|
"svelte"
|
|
49
49
|
],
|