@delightstack/components 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/LICENSE +21 -0
- package/README.md +136 -0
- package/SKILL.md +149 -0
- package/bin/agents.js +63 -0
- package/dist/actions/Alert.svelte +202 -0
- package/dist/actions/Alert.svelte.d.ts +36 -0
- package/dist/actions/Alert.svelte.d.ts.map +1 -0
- package/dist/actions/Button.svelte +1450 -0
- package/dist/actions/Button.svelte.d.ts +56 -0
- package/dist/actions/Button.svelte.d.ts.map +1 -0
- package/dist/actions/ButtonGroup.svelte +111 -0
- package/dist/actions/ButtonGroup.svelte.d.ts +41 -0
- package/dist/actions/ButtonGroup.svelte.d.ts.map +1 -0
- package/dist/actions/CommandPalette.svelte +939 -0
- package/dist/actions/CommandPalette.svelte.d.ts +37 -0
- package/dist/actions/CommandPalette.svelte.d.ts.map +1 -0
- package/dist/actions/ContextMenu.svelte +138 -0
- package/dist/actions/ContextMenu.svelte.d.ts +54 -0
- package/dist/actions/ContextMenu.svelte.d.ts.map +1 -0
- package/dist/actions/Modal.svelte +474 -0
- package/dist/actions/Modal.svelte.d.ts +28 -0
- package/dist/actions/Modal.svelte.d.ts.map +1 -0
- package/dist/actions/Popover.svelte +1214 -0
- package/dist/actions/Popover.svelte.d.ts +31 -0
- package/dist/actions/Popover.svelte.d.ts.map +1 -0
- package/dist/actions/Portal.svelte +80 -0
- package/dist/actions/Portal.svelte.d.ts +17 -0
- package/dist/actions/Portal.svelte.d.ts.map +1 -0
- package/dist/actions/ThemeToggle.svelte +345 -0
- package/dist/actions/ThemeToggle.svelte.d.ts +15 -0
- package/dist/actions/ThemeToggle.svelte.d.ts.map +1 -0
- package/dist/actions/index.d.ts +13 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +10 -0
- package/dist/actions/scrollbar.d.ts +48 -0
- package/dist/actions/scrollbar.d.ts.map +1 -0
- package/dist/actions/scrollbar.js +404 -0
- package/dist/display/Accordion.svelte +586 -0
- package/dist/display/Accordion.svelte.d.ts +41 -0
- package/dist/display/Accordion.svelte.d.ts.map +1 -0
- package/dist/display/Avatar.svelte +527 -0
- package/dist/display/Avatar.svelte.d.ts +22 -0
- package/dist/display/Avatar.svelte.d.ts.map +1 -0
- package/dist/display/AvatarGroup.svelte +298 -0
- package/dist/display/AvatarGroup.svelte.d.ts +31 -0
- package/dist/display/AvatarGroup.svelte.d.ts.map +1 -0
- package/dist/display/Calendar.svelte +1366 -0
- package/dist/display/Calendar.svelte.d.ts +58 -0
- package/dist/display/Calendar.svelte.d.ts.map +1 -0
- package/dist/display/Chart.svelte +1426 -0
- package/dist/display/Chart.svelte.d.ts +35 -0
- package/dist/display/Chart.svelte.d.ts.map +1 -0
- package/dist/display/Code.svelte +780 -0
- package/dist/display/Code.svelte.d.ts +19 -0
- package/dist/display/Code.svelte.d.ts.map +1 -0
- package/dist/display/Comparison.svelte +686 -0
- package/dist/display/Comparison.svelte.d.ts +22 -0
- package/dist/display/Comparison.svelte.d.ts.map +1 -0
- package/dist/display/Counter.svelte +285 -0
- package/dist/display/Counter.svelte.d.ts +21 -0
- package/dist/display/Counter.svelte.d.ts.map +1 -0
- package/dist/display/Expand.svelte +48 -0
- package/dist/display/Expand.svelte.d.ts +9 -0
- package/dist/display/Expand.svelte.d.ts.map +1 -0
- package/dist/display/List.svelte +294 -0
- package/dist/display/List.svelte.d.ts +40 -0
- package/dist/display/List.svelte.d.ts.map +1 -0
- package/dist/display/ListContextReset.svelte +19 -0
- package/dist/display/ListContextReset.svelte.d.ts +7 -0
- package/dist/display/ListContextReset.svelte.d.ts.map +1 -0
- package/dist/display/ListItem.svelte +834 -0
- package/dist/display/ListItem.svelte.d.ts +22 -0
- package/dist/display/ListItem.svelte.d.ts.map +1 -0
- package/dist/display/QR.svelte +1193 -0
- package/dist/display/QR.svelte.d.ts +23 -0
- package/dist/display/QR.svelte.d.ts.map +1 -0
- package/dist/display/SplitPane.svelte +744 -0
- package/dist/display/SplitPane.svelte.d.ts +25 -0
- package/dist/display/SplitPane.svelte.d.ts.map +1 -0
- package/dist/display/Stat.svelte +439 -0
- package/dist/display/Stat.svelte.d.ts +24 -0
- package/dist/display/Stat.svelte.d.ts.map +1 -0
- package/dist/display/Table.svelte +4654 -0
- package/dist/display/Table.svelte.d.ts +249 -0
- package/dist/display/Table.svelte.d.ts.map +1 -0
- package/dist/display/TableCellEditor.svelte +935 -0
- package/dist/display/TableCellEditor.svelte.d.ts +58 -0
- package/dist/display/TableCellEditor.svelte.d.ts.map +1 -0
- package/dist/display/Timeline.svelte +1258 -0
- package/dist/display/Timeline.svelte.d.ts +43 -0
- package/dist/display/Timeline.svelte.d.ts.map +1 -0
- package/dist/display/Tree.svelte +1740 -0
- package/dist/display/Tree.svelte.d.ts +74 -0
- package/dist/display/Tree.svelte.d.ts.map +1 -0
- package/dist/display/Typewriter.svelte +338 -0
- package/dist/display/Typewriter.svelte.d.ts +22 -0
- package/dist/display/Typewriter.svelte.d.ts.map +1 -0
- package/dist/display/index.d.ts +24 -0
- package/dist/display/index.d.ts.map +1 -0
- package/dist/display/index.js +18 -0
- package/dist/feedback/Callout.svelte +529 -0
- package/dist/feedback/Callout.svelte.d.ts +24 -0
- package/dist/feedback/Callout.svelte.d.ts.map +1 -0
- package/dist/feedback/Confetti.svelte +631 -0
- package/dist/feedback/Confetti.svelte.d.ts +90 -0
- package/dist/feedback/Confetti.svelte.d.ts.map +1 -0
- package/dist/feedback/Progress.svelte +382 -0
- package/dist/feedback/Progress.svelte.d.ts +25 -0
- package/dist/feedback/Progress.svelte.d.ts.map +1 -0
- package/dist/feedback/Toast.svelte +967 -0
- package/dist/feedback/Toast.svelte.d.ts +54 -0
- package/dist/feedback/Toast.svelte.d.ts.map +1 -0
- package/dist/feedback/index.d.ts +7 -0
- package/dist/feedback/index.d.ts.map +1 -0
- package/dist/feedback/index.js +4 -0
- package/dist/form/Checkbox.svelte +449 -0
- package/dist/form/Checkbox.svelte.d.ts +27 -0
- package/dist/form/Checkbox.svelte.d.ts.map +1 -0
- package/dist/form/Fieldset.svelte +410 -0
- package/dist/form/Fieldset.svelte.d.ts +22 -0
- package/dist/form/Fieldset.svelte.d.ts.map +1 -0
- package/dist/form/FileUpload.svelte +934 -0
- package/dist/form/FileUpload.svelte.d.ts +41 -0
- package/dist/form/FileUpload.svelte.d.ts.map +1 -0
- package/dist/form/Form.svelte +530 -0
- package/dist/form/Form.svelte.d.ts +120 -0
- package/dist/form/Form.svelte.d.ts.map +1 -0
- package/dist/form/Input.svelte +2858 -0
- package/dist/form/Input.svelte.d.ts +66 -0
- package/dist/form/Input.svelte.d.ts.map +1 -0
- package/dist/form/Radio.svelte +507 -0
- package/dist/form/Radio.svelte.d.ts +39 -0
- package/dist/form/Radio.svelte.d.ts.map +1 -0
- package/dist/form/Range.svelte +912 -0
- package/dist/form/Range.svelte.d.ts +33 -0
- package/dist/form/Range.svelte.d.ts.map +1 -0
- package/dist/form/Rating.svelte +429 -0
- package/dist/form/Rating.svelte.d.ts +28 -0
- package/dist/form/Rating.svelte.d.ts.map +1 -0
- package/dist/form/Select.svelte +1933 -0
- package/dist/form/Select.svelte.d.ts +54 -0
- package/dist/form/Select.svelte.d.ts.map +1 -0
- package/dist/form/Toggle.svelte +645 -0
- package/dist/form/Toggle.svelte.d.ts +50 -0
- package/dist/form/Toggle.svelte.d.ts.map +1 -0
- package/dist/form/index.d.ts +15 -0
- package/dist/form/index.d.ts.map +1 -0
- package/dist/form/index.js +10 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/layout/README.md +172 -0
- package/dist/media/Carousel.svelte +2424 -0
- package/dist/media/Carousel.svelte.d.ts +47 -0
- package/dist/media/Carousel.svelte.d.ts.map +1 -0
- package/dist/media/Gallery.svelte +2881 -0
- package/dist/media/Gallery.svelte.d.ts +82 -0
- package/dist/media/Gallery.svelte.d.ts.map +1 -0
- package/dist/media/Image.svelte +389 -0
- package/dist/media/Image.svelte.d.ts +33 -0
- package/dist/media/Image.svelte.d.ts.map +1 -0
- package/dist/media/PDF.svelte +1793 -0
- package/dist/media/PDF.svelte.d.ts +44 -0
- package/dist/media/PDF.svelte.d.ts.map +1 -0
- package/dist/media/Panorama.svelte +1391 -0
- package/dist/media/Panorama.svelte.d.ts +47 -0
- package/dist/media/Panorama.svelte.d.ts.map +1 -0
- package/dist/media/Video.svelte +2501 -0
- package/dist/media/Video.svelte.d.ts +58 -0
- package/dist/media/Video.svelte.d.ts.map +1 -0
- package/dist/media/carousel.d.ts +211 -0
- package/dist/media/carousel.d.ts.map +1 -0
- package/dist/media/carousel.js +408 -0
- package/dist/media/index.d.ts +11 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/index.js +5 -0
- package/dist/navigation/BottomSheet.svelte +636 -0
- package/dist/navigation/BottomSheet.svelte.d.ts +27 -0
- package/dist/navigation/BottomSheet.svelte.d.ts.map +1 -0
- package/dist/navigation/Breadcrumbs.svelte +611 -0
- package/dist/navigation/Breadcrumbs.svelte.d.ts +28 -0
- package/dist/navigation/Breadcrumbs.svelte.d.ts.map +1 -0
- package/dist/navigation/Pagination.svelte +641 -0
- package/dist/navigation/Pagination.svelte.d.ts +27 -0
- package/dist/navigation/Pagination.svelte.d.ts.map +1 -0
- package/dist/navigation/Steps.svelte +965 -0
- package/dist/navigation/Steps.svelte.d.ts +43 -0
- package/dist/navigation/Steps.svelte.d.ts.map +1 -0
- package/dist/navigation/Tabs.svelte +698 -0
- package/dist/navigation/Tabs.svelte.d.ts +41 -0
- package/dist/navigation/Tabs.svelte.d.ts.map +1 -0
- package/dist/navigation/index.d.ts +8 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +5 -0
- package/package.json +139 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { tooltip } from '@delightstack/utilities';
|
|
3
|
+
import { type Snippet } from 'svelte';
|
|
4
|
+
|
|
5
|
+
const propId = $props.id();
|
|
6
|
+
let {
|
|
7
|
+
/** Image source URL */
|
|
8
|
+
src = undefined as string | undefined,
|
|
9
|
+
|
|
10
|
+
/** Name used for initials fallback and alt text */
|
|
11
|
+
name = undefined as string | undefined,
|
|
12
|
+
|
|
13
|
+
/** Stable seed for the generated background color; falls back to `name` when absent */
|
|
14
|
+
color_seed = undefined as string | undefined,
|
|
15
|
+
|
|
16
|
+
/** Size preset: 0=24px, 1=32px, 2=40px, 3=56px, 4=80px, 5=120px */
|
|
17
|
+
size = '1' as '0' | '1' | '2' | '3' | '4' | '5',
|
|
18
|
+
|
|
19
|
+
/** Square shape instead of circle */
|
|
20
|
+
square = false,
|
|
21
|
+
|
|
22
|
+
/** Online status indicator */
|
|
23
|
+
status = undefined as 'online' | 'away' | 'busy' | 'offline' | undefined,
|
|
24
|
+
|
|
25
|
+
/** Position of the status dot */
|
|
26
|
+
status_position = 'bottom' as 'top' | 'bottom',
|
|
27
|
+
|
|
28
|
+
/** Badge: true for dot, number for count */
|
|
29
|
+
badge = undefined as number | boolean | undefined,
|
|
30
|
+
|
|
31
|
+
/** Show a ring around the avatar */
|
|
32
|
+
ring = false,
|
|
33
|
+
|
|
34
|
+
/** Custom ring color */
|
|
35
|
+
ring_color = undefined as string | undefined,
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Show a skeleton shimmer placeholder until the avatar has real
|
|
39
|
+
* content to show: it dismisses itself once the image loads (or, for
|
|
40
|
+
* initials avatars, as soon as `name` is available). Set `false` to
|
|
41
|
+
* never show it.
|
|
42
|
+
*/
|
|
43
|
+
skeleton = false,
|
|
44
|
+
|
|
45
|
+
/** Tooltip message */
|
|
46
|
+
tooltip: tooltip_message = '',
|
|
47
|
+
|
|
48
|
+
/** Click handler — makes the avatar interactive */
|
|
49
|
+
onclick = undefined as ((e: MouseEvent) => void) | undefined,
|
|
50
|
+
|
|
51
|
+
/** Element ID */
|
|
52
|
+
id = propId,
|
|
53
|
+
|
|
54
|
+
/** Additional CSS classes */
|
|
55
|
+
class: class_name = '',
|
|
56
|
+
|
|
57
|
+
/** Custom children content (replaces default avatar content) */
|
|
58
|
+
children = undefined as Snippet | undefined,
|
|
59
|
+
} = $props();
|
|
60
|
+
|
|
61
|
+
let imgError = $state(false);
|
|
62
|
+
let imgLoaded = $state(false);
|
|
63
|
+
let img_el = $state<HTMLImageElement | undefined>(undefined);
|
|
64
|
+
|
|
65
|
+
function getInitials(value: string): string {
|
|
66
|
+
const parts = value.trim().split(/\s+/);
|
|
67
|
+
if (parts.length === 1) return parts[0][0].toUpperCase();
|
|
68
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function hashName(value: string): number {
|
|
72
|
+
let hash = 0;
|
|
73
|
+
for (let i = 0; i < value.length; i++) {
|
|
74
|
+
hash = hash + value.charCodeAt(i);
|
|
75
|
+
}
|
|
76
|
+
return hash;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getNameColor(value: string): string {
|
|
80
|
+
const hash = hashName(value);
|
|
81
|
+
const hue = hash % 360;
|
|
82
|
+
const lightness = 0.55 + (hash % 21) * 0.01;
|
|
83
|
+
const chroma = 0.12 + (hash % 7) * 0.01;
|
|
84
|
+
return `oklch(${lightness} ${chroma} ${hue})`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const showImage = $derived(src && !imgError);
|
|
88
|
+
const showInitials = $derived(!showImage && name);
|
|
89
|
+
const showIcon = $derived(!showImage && !name);
|
|
90
|
+
|
|
91
|
+
/* The skeleton auto-dismisses the moment the avatar has something real to
|
|
92
|
+
render: a loaded (or failed-over) image, initials, or custom children.
|
|
93
|
+
While an image is in flight it keeps loading underneath the shimmer. */
|
|
94
|
+
const show_skeleton = $derived.by(() => {
|
|
95
|
+
if (!skeleton) return false;
|
|
96
|
+
if (children) return false;
|
|
97
|
+
if (src) return !imgLoaded && !imgError;
|
|
98
|
+
return !name;
|
|
99
|
+
});
|
|
100
|
+
const initials = $derived(name ? getInitials(name) : '');
|
|
101
|
+
const colorKey = $derived(color_seed ?? name);
|
|
102
|
+
const nameColor = $derived(colorKey ? getNameColor(colorKey) : undefined);
|
|
103
|
+
const isInteractive = $derived(!!onclick);
|
|
104
|
+
const badgeText = $derived(
|
|
105
|
+
badge === true
|
|
106
|
+
? undefined
|
|
107
|
+
: typeof badge === 'number'
|
|
108
|
+
? badge > 99
|
|
109
|
+
? '99+'
|
|
110
|
+
: String(badge)
|
|
111
|
+
: undefined,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const statusLabel: Record<string, string> = {
|
|
115
|
+
online: 'Online',
|
|
116
|
+
away: 'Away',
|
|
117
|
+
busy: 'Busy',
|
|
118
|
+
offline: 'Offline',
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
function handleKeyDown(e: KeyboardEvent) {
|
|
122
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
123
|
+
e.preventDefault();
|
|
124
|
+
onclick?.(e as unknown as MouseEvent);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function handleImgError() {
|
|
129
|
+
imgError = true;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Reset load/error state when src changes
|
|
133
|
+
$effect(() => {
|
|
134
|
+
if (src) {
|
|
135
|
+
imgError = false;
|
|
136
|
+
imgLoaded = false;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Sync with the actual <img> state — cached/SSR'd images can be complete
|
|
141
|
+
// before hydration attaches the onload listener.
|
|
142
|
+
$effect(() => {
|
|
143
|
+
void src;
|
|
144
|
+
if (!img_el || !img_el.complete) return;
|
|
145
|
+
if (img_el.naturalWidth > 0) imgLoaded = true;
|
|
146
|
+
else imgError = true;
|
|
147
|
+
});
|
|
148
|
+
</script>
|
|
149
|
+
|
|
150
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
151
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
152
|
+
<div
|
|
153
|
+
{id}
|
|
154
|
+
class={['avatar', `size-${size}`, class_name].filter(Boolean).join(' ')}
|
|
155
|
+
class:square
|
|
156
|
+
class:ring
|
|
157
|
+
class:interactive={isInteractive}
|
|
158
|
+
class:skeleton={show_skeleton}
|
|
159
|
+
role={isInteractive ? 'button' : 'img'}
|
|
160
|
+
tabindex={isInteractive ? 0 : undefined}
|
|
161
|
+
aria-label={name || 'Avatar'}
|
|
162
|
+
style:--ring-color={ring_color || null}
|
|
163
|
+
style:--name-color={nameColor || null}
|
|
164
|
+
{onclick}
|
|
165
|
+
onkeydown={isInteractive ? handleKeyDown : undefined}
|
|
166
|
+
{@attach tooltip(tooltip_message)}>
|
|
167
|
+
{#if show_skeleton}
|
|
168
|
+
<div class="skeleton-inner"></div>
|
|
169
|
+
{/if}
|
|
170
|
+
{#if children}
|
|
171
|
+
{@render children()}
|
|
172
|
+
{:else if showImage}
|
|
173
|
+
<!-- Kept mounted while the skeleton overlays it so the image actually
|
|
174
|
+
loads (the skeleton dismisses itself from its onload). -->
|
|
175
|
+
<img
|
|
176
|
+
{src}
|
|
177
|
+
alt={name || ''}
|
|
178
|
+
bind:this={img_el}
|
|
179
|
+
onload={() => (imgLoaded = true)}
|
|
180
|
+
onerror={handleImgError}
|
|
181
|
+
draggable="false" />
|
|
182
|
+
{:else if showInitials}
|
|
183
|
+
<span class="initials" style:background={nameColor}>
|
|
184
|
+
{initials}
|
|
185
|
+
</span>
|
|
186
|
+
{:else if !show_skeleton}
|
|
187
|
+
<span class="icon">
|
|
188
|
+
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
189
|
+
<path
|
|
190
|
+
d="M12 12c2.7 0 4.8-2.1 4.8-4.8S14.7 2.4 12 2.4 7.2 4.5 7.2 7.2 9.3 12 12 12zm0 2.4c-3.2 0-9.6 1.6-9.6 4.8v1.2c0 .66.54 1.2 1.2 1.2h16.8c.66 0 1.2-.54 1.2-1.2v-1.2c0-3.2-6.4-4.8-9.6-4.8z" />
|
|
191
|
+
</svg>
|
|
192
|
+
</span>
|
|
193
|
+
{/if}
|
|
194
|
+
|
|
195
|
+
{#if status}
|
|
196
|
+
<span
|
|
197
|
+
class="status {status}"
|
|
198
|
+
class:top={status_position === 'top'}
|
|
199
|
+
class:bottom={status_position === 'bottom'}
|
|
200
|
+
aria-label={statusLabel[status]}>
|
|
201
|
+
</span>
|
|
202
|
+
{/if}
|
|
203
|
+
|
|
204
|
+
{#if badge !== undefined && badge !== false}
|
|
205
|
+
<span
|
|
206
|
+
class="badge"
|
|
207
|
+
class:dot={badge === true}
|
|
208
|
+
aria-label={typeof badge === 'number' ? `${badge} notifications` : 'Notification'}>
|
|
209
|
+
{#if badgeText}{badgeText}{/if}
|
|
210
|
+
</span>
|
|
211
|
+
{/if}
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<style>
|
|
215
|
+
.avatar {
|
|
216
|
+
--avatar-size: 32px;
|
|
217
|
+
--avatar-font: 0.75rem;
|
|
218
|
+
--avatar-status: 11px;
|
|
219
|
+
--avatar-radius: var(--radius-full, 9999px);
|
|
220
|
+
/* Squircle corners only for the .square variant (a circle can't be a
|
|
221
|
+
squircle). The defaults below keep the round circle untouched; .square
|
|
222
|
+
opts in and doubles the radius to preserve the visual roundness. */
|
|
223
|
+
--_corner-shape: round;
|
|
224
|
+
--_corner-scale: 1;
|
|
225
|
+
|
|
226
|
+
position: relative;
|
|
227
|
+
display: inline-flex;
|
|
228
|
+
align-items: center;
|
|
229
|
+
justify-content: center;
|
|
230
|
+
width: var(--avatar-size);
|
|
231
|
+
height: var(--avatar-size);
|
|
232
|
+
border-radius: var(--avatar-radius);
|
|
233
|
+
@supports (corner-shape: squircle) {
|
|
234
|
+
corner-shape: var(--_corner-shape);
|
|
235
|
+
border-radius: calc(var(--avatar-radius) * var(--_corner-scale));
|
|
236
|
+
}
|
|
237
|
+
flex-shrink: 0;
|
|
238
|
+
user-select: none;
|
|
239
|
+
vertical-align: middle;
|
|
240
|
+
overflow: visible;
|
|
241
|
+
font-size: var(--avatar-font);
|
|
242
|
+
line-height: 1;
|
|
243
|
+
|
|
244
|
+
&.size-0 {
|
|
245
|
+
--avatar-size: 24px;
|
|
246
|
+
--avatar-font: 0.625rem;
|
|
247
|
+
--avatar-status: 10px;
|
|
248
|
+
}
|
|
249
|
+
&.size-1 {
|
|
250
|
+
--avatar-size: 32px;
|
|
251
|
+
--avatar-font: 0.75rem;
|
|
252
|
+
--avatar-status: 13px;
|
|
253
|
+
}
|
|
254
|
+
&.size-2 {
|
|
255
|
+
--avatar-size: 40px;
|
|
256
|
+
--avatar-font: 0.875rem;
|
|
257
|
+
--avatar-status: 15px;
|
|
258
|
+
}
|
|
259
|
+
&.size-3 {
|
|
260
|
+
--avatar-size: 56px;
|
|
261
|
+
--avatar-font: 1.125rem;
|
|
262
|
+
--avatar-status: 19px;
|
|
263
|
+
}
|
|
264
|
+
&.size-4 {
|
|
265
|
+
--avatar-size: 80px;
|
|
266
|
+
--avatar-font: 1.5rem;
|
|
267
|
+
--avatar-status: 25px;
|
|
268
|
+
}
|
|
269
|
+
&.size-5 {
|
|
270
|
+
--avatar-size: 120px;
|
|
271
|
+
--avatar-font: 2.25rem;
|
|
272
|
+
--avatar-status: 34px;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
&.square {
|
|
276
|
+
--avatar-radius: var(--radius-lg, 8px);
|
|
277
|
+
--_corner-shape: squircle;
|
|
278
|
+
--_corner-scale: var(--squircle-ratio, 2);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
&.ring {
|
|
282
|
+
box-shadow: 0 0 0 2px var(--ring-color, var(--color-accent, currentColor));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
&.interactive {
|
|
286
|
+
cursor: pointer;
|
|
287
|
+
outline: none;
|
|
288
|
+
transition:
|
|
289
|
+
transform 150ms ease,
|
|
290
|
+
box-shadow 200ms ease;
|
|
291
|
+
|
|
292
|
+
&:hover {
|
|
293
|
+
transform: scale(1.05);
|
|
294
|
+
}
|
|
295
|
+
&:active {
|
|
296
|
+
transform: scale(0.97);
|
|
297
|
+
}
|
|
298
|
+
&:focus-visible {
|
|
299
|
+
box-shadow:
|
|
300
|
+
0 0 0 2px var(--color-bg, #fff),
|
|
301
|
+
0 0 0 4px var(--color-accent, currentColor);
|
|
302
|
+
}
|
|
303
|
+
&.ring:focus-visible {
|
|
304
|
+
box-shadow:
|
|
305
|
+
0 0 0 2px var(--ring-color, var(--color-accent, currentColor)),
|
|
306
|
+
0 0 0 4px var(--color-bg, #fff),
|
|
307
|
+
0 0 0 6px var(--color-accent, currentColor);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
img {
|
|
312
|
+
display: block;
|
|
313
|
+
width: 100%;
|
|
314
|
+
height: 100%;
|
|
315
|
+
object-fit: cover;
|
|
316
|
+
border-radius: var(--avatar-radius);
|
|
317
|
+
@supports (corner-shape: squircle) {
|
|
318
|
+
corner-shape: var(--_corner-shape);
|
|
319
|
+
border-radius: calc(var(--avatar-radius) * var(--_corner-scale));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.initials {
|
|
324
|
+
display: flex;
|
|
325
|
+
align-items: center;
|
|
326
|
+
justify-content: center;
|
|
327
|
+
width: 100%;
|
|
328
|
+
height: 100%;
|
|
329
|
+
border-radius: var(--avatar-radius);
|
|
330
|
+
@supports (corner-shape: squircle) {
|
|
331
|
+
corner-shape: var(--_corner-shape);
|
|
332
|
+
border-radius: calc(var(--avatar-radius) * var(--_corner-scale));
|
|
333
|
+
}
|
|
334
|
+
color: #fff;
|
|
335
|
+
font-weight: 600;
|
|
336
|
+
letter-spacing: 0.02em;
|
|
337
|
+
text-transform: uppercase;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.icon {
|
|
341
|
+
display: flex;
|
|
342
|
+
align-items: center;
|
|
343
|
+
justify-content: center;
|
|
344
|
+
width: 100%;
|
|
345
|
+
height: 100%;
|
|
346
|
+
border-radius: var(--avatar-radius);
|
|
347
|
+
@supports (corner-shape: squircle) {
|
|
348
|
+
corner-shape: var(--_corner-shape);
|
|
349
|
+
border-radius: calc(var(--avatar-radius) * var(--_corner-scale));
|
|
350
|
+
}
|
|
351
|
+
background: light-dark(var(--color-border, #d1d5db), var(--color-border, #4b5563));
|
|
352
|
+
color: light-dark(
|
|
353
|
+
var(--color-text-muted, #6b7280),
|
|
354
|
+
var(--color-text-muted, #9ca3af)
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
svg {
|
|
358
|
+
width: 60%;
|
|
359
|
+
height: 60%;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.status {
|
|
364
|
+
position: absolute;
|
|
365
|
+
width: var(--avatar-status);
|
|
366
|
+
height: var(--avatar-status);
|
|
367
|
+
border-radius: var(--radius-full, 9999px);
|
|
368
|
+
border: 2px solid light-dark(var(--color-bg, #fff), var(--color-bg, #1f2937));
|
|
369
|
+
z-index: 1;
|
|
370
|
+
|
|
371
|
+
&.bottom {
|
|
372
|
+
bottom: -1px;
|
|
373
|
+
right: -1px;
|
|
374
|
+
}
|
|
375
|
+
&.top {
|
|
376
|
+
top: -1px;
|
|
377
|
+
right: -1px;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
&.online {
|
|
381
|
+
background-color: var(--color-success, #22c55e);
|
|
382
|
+
animation: avatar-pulse 2s ease-in-out infinite;
|
|
383
|
+
}
|
|
384
|
+
&.away {
|
|
385
|
+
background-color: var(--color-warning, #eab308);
|
|
386
|
+
}
|
|
387
|
+
&.busy {
|
|
388
|
+
background-color: var(--color-error, #ef4444);
|
|
389
|
+
}
|
|
390
|
+
&.offline {
|
|
391
|
+
background-color: light-dark(
|
|
392
|
+
var(--color-text-muted, #9ca3af),
|
|
393
|
+
var(--color-text-muted, #6b7280)
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
&.square .status {
|
|
399
|
+
&.bottom {
|
|
400
|
+
bottom: -2px;
|
|
401
|
+
right: -2px;
|
|
402
|
+
}
|
|
403
|
+
&.top {
|
|
404
|
+
top: -2px;
|
|
405
|
+
right: -2px;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/* Count badges hang off the top-right corner. Anchoring the badge's
|
|
410
|
+
* LEFT edge to the avatar's right edge (rather than its right edge) makes
|
|
411
|
+
* it grow outward to the right as the value widens, so long values like
|
|
412
|
+
* "99+" stay pinned to the side instead of sliding back over the avatar. */
|
|
413
|
+
.badge {
|
|
414
|
+
position: absolute;
|
|
415
|
+
top: 0;
|
|
416
|
+
left: 100%;
|
|
417
|
+
translate: -45% -30%;
|
|
418
|
+
display: flex;
|
|
419
|
+
align-items: center;
|
|
420
|
+
justify-content: center;
|
|
421
|
+
background-color: var(--color-accent, var(--color-error, #ef4444));
|
|
422
|
+
color: var(--color-accent-text, #fff);
|
|
423
|
+
border-radius: var(--radius-full, 9999px);
|
|
424
|
+
font-size: 0.8rem;
|
|
425
|
+
font-weight: 700;
|
|
426
|
+
line-height: 1;
|
|
427
|
+
min-width: 1.5em;
|
|
428
|
+
height: 1.5em;
|
|
429
|
+
padding: 0 0.45em;
|
|
430
|
+
border: 2px solid light-dark(var(--color-bg, #fff), var(--color-bg, #1f2937));
|
|
431
|
+
z-index: 1;
|
|
432
|
+
pointer-events: none;
|
|
433
|
+
white-space: nowrap;
|
|
434
|
+
|
|
435
|
+
/* A bare dot is square, so the width never grows — pin it to the
|
|
436
|
+
* corner directly and let it hug the avatar's edge. */
|
|
437
|
+
&.dot {
|
|
438
|
+
left: auto;
|
|
439
|
+
right: 0;
|
|
440
|
+
width: 0.95em;
|
|
441
|
+
min-width: 0.95em;
|
|
442
|
+
height: 0.95em;
|
|
443
|
+
padding: 0;
|
|
444
|
+
translate: 25% -25%;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
&.size-0 .badge {
|
|
448
|
+
font-size: 0.6rem;
|
|
449
|
+
}
|
|
450
|
+
&.size-2 .badge {
|
|
451
|
+
font-size: 0.85rem;
|
|
452
|
+
}
|
|
453
|
+
&.size-3 .badge {
|
|
454
|
+
font-size: 0.95rem;
|
|
455
|
+
}
|
|
456
|
+
&.size-4 .badge {
|
|
457
|
+
font-size: 1.1rem;
|
|
458
|
+
}
|
|
459
|
+
&.size-5 .badge {
|
|
460
|
+
font-size: 1.3rem;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
&.skeleton {
|
|
464
|
+
pointer-events: none;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/* Overlays the (still-loading) image so the photo can stream in
|
|
468
|
+
underneath and the swap is seamless when the shimmer dismisses. */
|
|
469
|
+
.skeleton-inner {
|
|
470
|
+
position: absolute;
|
|
471
|
+
inset: 0;
|
|
472
|
+
z-index: 1;
|
|
473
|
+
border-radius: var(--avatar-radius);
|
|
474
|
+
@supports (corner-shape: squircle) {
|
|
475
|
+
corner-shape: var(--_corner-shape);
|
|
476
|
+
border-radius: calc(var(--avatar-radius) * var(--_corner-scale));
|
|
477
|
+
}
|
|
478
|
+
background: var(--skeleton-bg, rgb(from var(--color-text, #888) r g b / 0.1));
|
|
479
|
+
overflow: hidden;
|
|
480
|
+
|
|
481
|
+
&::after {
|
|
482
|
+
content: '';
|
|
483
|
+
position: absolute;
|
|
484
|
+
inset: 0;
|
|
485
|
+
transform: translateX(-100%);
|
|
486
|
+
background-image: linear-gradient(
|
|
487
|
+
105deg,
|
|
488
|
+
transparent 25%,
|
|
489
|
+
var(--skeleton-sheen, rgb(from var(--color-text, #888) r g b / 0.12)) 50%,
|
|
490
|
+
transparent 75%
|
|
491
|
+
);
|
|
492
|
+
animation: delight-skeleton-shimmer var(--skeleton-duration, 2.4s) ease-in-out
|
|
493
|
+
infinite;
|
|
494
|
+
animation-delay: var(--shimmer-delay, 0s);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
@keyframes avatar-pulse {
|
|
500
|
+
0%,
|
|
501
|
+
100% {
|
|
502
|
+
box-shadow: 0 0 0 0 rgb(from var(--color-success, #22c55e) r g b / 0.4);
|
|
503
|
+
}
|
|
504
|
+
50% {
|
|
505
|
+
box-shadow: 0 0 0 3px rgb(from var(--color-success, #22c55e) r g b / 0);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
@keyframes -global-delight-skeleton-shimmer {
|
|
510
|
+
0% {
|
|
511
|
+
transform: translateX(-100%);
|
|
512
|
+
}
|
|
513
|
+
55%,
|
|
514
|
+
100% {
|
|
515
|
+
transform: translateX(100%);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
@media (prefers-reduced-motion: reduce) {
|
|
520
|
+
.avatar .status.online {
|
|
521
|
+
animation: none;
|
|
522
|
+
}
|
|
523
|
+
.avatar .skeleton-inner::after {
|
|
524
|
+
animation: none;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
declare const Avatar: import("svelte").Component<{
|
|
3
|
+
src?: string | undefined;
|
|
4
|
+
name?: string | undefined;
|
|
5
|
+
color_seed?: string | undefined;
|
|
6
|
+
size?: "0" | "1" | "2" | "3" | "4" | "5";
|
|
7
|
+
square?: boolean;
|
|
8
|
+
status?: "online" | "away" | "busy" | "offline" | undefined;
|
|
9
|
+
status_position?: "top" | "bottom";
|
|
10
|
+
badge?: number | boolean | undefined;
|
|
11
|
+
ring?: boolean;
|
|
12
|
+
ring_color?: string | undefined;
|
|
13
|
+
skeleton?: boolean;
|
|
14
|
+
tooltip?: string;
|
|
15
|
+
onclick?: ((e: MouseEvent) => void) | undefined;
|
|
16
|
+
id?: string;
|
|
17
|
+
class?: string;
|
|
18
|
+
children?: Snippet | undefined;
|
|
19
|
+
}, {}, "">;
|
|
20
|
+
type Avatar = ReturnType<typeof Avatar>;
|
|
21
|
+
export default Avatar;
|
|
22
|
+
//# sourceMappingURL=Avatar.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Avatar.svelte.d.ts","sourceRoot":"","sources":["../../src/display/Avatar.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AA8LtC,QAAA,MAAM,MAAM;UAxLmE,MAAM,GAAG,SAAS;WAAS,MAAM,GAAG,SAAS;iBAAe,MAAM,GAAG,SAAS;WAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;aAAW,OAAO;aAAW,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS;sBAAoB,KAAK,GAAG,QAAQ;YAAU,MAAM,GAAG,OAAO,GAAG,SAAS;WAAS,OAAO;iBAAe,MAAM,GAAG,SAAS;eAAa,OAAO;cAAY,MAAM;cAAY,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS;;YAA8B,MAAM;eAAa,OAAO,GAAG,SAAS;UAwLxf,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
|