twintrinsic 0.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/LICENSE +674 -0
- package/README.md +150 -0
- package/dist/App/App.svelte +54 -0
- package/dist/App/App.svelte.d.ts +65 -0
- package/dist/Section.svelte +25 -0
- package/dist/Section.svelte.d.ts +34 -0
- package/dist/actions/clickOutside.d.ts +9 -0
- package/dist/actions/clickOutside.js +19 -0
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/components/Accordion/Accordion.svelte +75 -0
- package/dist/components/Accordion/Accordion.svelte.d.ts +39 -0
- package/dist/components/Accordion/AccordionItem.svelte +150 -0
- package/dist/components/Accordion/AccordionItem.svelte.d.ts +30 -0
- package/dist/components/App/App.story.md +8 -0
- package/dist/components/App/App.story.svelte +170 -0
- package/dist/components/App/App.story.svelte.d.ts +22 -0
- package/dist/components/App/App.svelte +77 -0
- package/dist/components/App/App.svelte.d.ts +66 -0
- package/dist/components/App/Split.svelte +346 -0
- package/dist/components/App/Split.svelte.d.ts +54 -0
- package/dist/components/App/index.d.ts +2 -0
- package/dist/components/App/index.js +3 -0
- package/dist/components/AppHeader/AppHeader.svelte +439 -0
- package/dist/components/AppHeader/AppHeader.svelte.d.ts +24 -0
- package/dist/components/Avatar/Avatar.svelte +300 -0
- package/dist/components/Avatar/Avatar.svelte.d.ts +48 -0
- package/dist/components/Avatar/AvatarGroup.svelte +185 -0
- package/dist/components/Avatar/AvatarGroup.svelte.d.ts +46 -0
- package/dist/components/Badge/Badge.svelte +186 -0
- package/dist/components/Badge/Badge.svelte.d.ts +51 -0
- package/dist/components/BottomBar/BottomBar.svelte +146 -0
- package/dist/components/BottomBar/BottomBar.svelte.d.ts +38 -0
- package/dist/components/Breadcrumb/Breadcrumb.svelte +77 -0
- package/dist/components/Breadcrumb/Breadcrumb.svelte.d.ts +42 -0
- package/dist/components/Breadcrumb/BreadcrumbItem.svelte +171 -0
- package/dist/components/Breadcrumb/BreadcrumbItem.svelte.d.ts +38 -0
- package/dist/components/Button/Button.svelte +252 -0
- package/dist/components/Button/Button.svelte.d.ts +80 -0
- package/dist/components/Button/ButtonGroup.svelte +127 -0
- package/dist/components/Button/ButtonGroup.svelte.d.ts +44 -0
- package/dist/components/Card/Card.svelte +152 -0
- package/dist/components/Card/Card.svelte.d.ts +55 -0
- package/dist/components/Carousel/Carousel.svelte +461 -0
- package/dist/components/Carousel/Carousel.svelte.d.ts +79 -0
- package/dist/components/Carousel/CarouselItem.svelte +149 -0
- package/dist/components/Carousel/CarouselItem.svelte.d.ts +35 -0
- package/dist/components/Chip/Chip.svelte +288 -0
- package/dist/components/Chip/Chip.svelte.d.ts +71 -0
- package/dist/components/Chip/ChipGroup.svelte +190 -0
- package/dist/components/Chip/ChipGroup.svelte.d.ts +71 -0
- package/dist/components/CodeBlock/CodeBlock.svelte +356 -0
- package/dist/components/CodeBlock/CodeBlock.svelte.d.ts +44 -0
- package/dist/components/CodeBlock/index.d.ts +1 -0
- package/dist/components/CodeBlock/index.js +1 -0
- package/dist/components/CodeBlockSpeed/CodeBlockSpeed.svelte +145 -0
- package/dist/components/CodeBlockSpeed/CodeBlockSpeed.svelte.d.ts +44 -0
- package/dist/components/CodeEditor/CodeEditor.svelte +229 -0
- package/dist/components/CodeEditor/CodeEditor.svelte.d.ts +23 -0
- package/dist/components/Combobox/Combobox.svelte +279 -0
- package/dist/components/Combobox/Combobox.svelte.d.ts +34 -0
- package/dist/components/Container/Container.svelte +45 -0
- package/dist/components/Container/Container.svelte.d.ts +36 -0
- package/dist/components/DataTable/DataTable.svelte +879 -0
- package/dist/components/DataTable/DataTable.svelte.d.ts +102 -0
- package/dist/components/Form/AutoComplete.svelte +357 -0
- package/dist/components/Form/AutoComplete.svelte.d.ts +73 -0
- package/dist/components/Form/Calendar.svelte +429 -0
- package/dist/components/Form/Calendar.svelte.d.ts +53 -0
- package/dist/components/Form/Checkbox.svelte +196 -0
- package/dist/components/Form/Checkbox.svelte.d.ts +50 -0
- package/dist/components/Form/ColorPicker.svelte +396 -0
- package/dist/components/Form/ColorPicker.svelte.d.ts +43 -0
- package/dist/components/Form/Combobox.svelte +645 -0
- package/dist/components/Form/Combobox.svelte.d.ts +93 -0
- package/dist/components/Form/Dropdown.svelte +773 -0
- package/dist/components/Form/Dropdown.svelte.d.ts +81 -0
- package/dist/components/Form/FileUpload.svelte +796 -0
- package/dist/components/Form/FileUpload.svelte.d.ts +78 -0
- package/dist/components/Form/FloatLabel.svelte +245 -0
- package/dist/components/Form/FloatLabel.svelte.d.ts +44 -0
- package/dist/components/Form/Form.svelte +281 -0
- package/dist/components/Form/Form.svelte.d.ts +54 -0
- package/dist/components/Form/FormField.svelte +218 -0
- package/dist/components/Form/FormField.svelte.d.ts +47 -0
- package/dist/components/Form/Input.svelte +340 -0
- package/dist/components/Form/Input.svelte.d.ts +79 -0
- package/dist/components/Form/InputSwitch.svelte +189 -0
- package/dist/components/Form/InputSwitch.svelte.d.ts +46 -0
- package/dist/components/Form/InvalidState.svelte +97 -0
- package/dist/components/Form/InvalidState.svelte.d.ts +37 -0
- package/dist/components/Form/Knob.svelte +537 -0
- package/dist/components/Form/Knob.svelte.d.ts +78 -0
- package/dist/components/Form/ListInput.svelte +469 -0
- package/dist/components/Form/ListInput.svelte.d.ts +70 -0
- package/dist/components/Form/Listbox.svelte +513 -0
- package/dist/components/Form/Listbox.svelte.d.ts +74 -0
- package/dist/components/Form/NumberInput.svelte +452 -0
- package/dist/components/Form/NumberInput.svelte.d.ts +82 -0
- package/dist/components/Form/Radio.svelte +192 -0
- package/dist/components/Form/Radio.svelte.d.ts +53 -0
- package/dist/components/Form/RadioGroup.svelte +155 -0
- package/dist/components/Form/RadioGroup.svelte.d.ts +48 -0
- package/dist/components/Form/Rating.svelte +380 -0
- package/dist/components/Form/Rating.svelte.d.ts +64 -0
- package/dist/components/Form/Select.svelte +436 -0
- package/dist/components/Form/Select.svelte.d.ts +49 -0
- package/dist/components/Form/SelectGroup.svelte +34 -0
- package/dist/components/Form/SelectGroup.svelte.d.ts +33 -0
- package/dist/components/Form/Slider.svelte +622 -0
- package/dist/components/Form/Slider.svelte.d.ts +73 -0
- package/dist/components/Form/Switch.svelte +192 -0
- package/dist/components/Form/Switch.svelte.d.ts +46 -0
- package/dist/components/Form/TextInput.svelte +274 -0
- package/dist/components/Form/TextInput.svelte.d.ts +74 -0
- package/dist/components/Form/Textarea.svelte +207 -0
- package/dist/components/Form/Textarea.svelte.d.ts +62 -0
- package/dist/components/Icon/Icon.svelte +140 -0
- package/dist/components/Icon/Icon.svelte.d.ts +25 -0
- package/dist/components/Icon/index.d.ts +1 -0
- package/dist/components/Icon/index.js +1 -0
- package/dist/components/Lazy/Lazy.svelte +158 -0
- package/dist/components/Lazy/Lazy.svelte.d.ts +42 -0
- package/dist/components/Masonry/Masonry.svelte +299 -0
- package/dist/components/Masonry/Masonry.svelte.d.ts +55 -0
- package/dist/components/Menu/Menu/Menu.svelte +65 -0
- package/dist/components/Menu/Menu/Menu.svelte.d.ts +17 -0
- package/dist/components/Menu/Menu/MenuItem.svelte +90 -0
- package/dist/components/Menu/Menu/MenuItem.svelte.d.ts +27 -0
- package/dist/components/Modal/Modal.svelte +334 -0
- package/dist/components/Modal/Modal.svelte.d.ts +55 -0
- package/dist/components/Panel/Card.svelte +141 -0
- package/dist/components/Panel/Card.svelte.d.ts +52 -0
- package/dist/components/Panel/Hero/Hero.story.md +9 -0
- package/dist/components/Panel/Hero/Hero.story.svelte +49 -0
- package/dist/components/Panel/Hero/Hero.story.svelte.d.ts +21 -0
- package/dist/components/Panel/Hero/Hero.svelte +24 -0
- package/dist/components/Panel/Hero/Hero.svelte.d.ts +32 -0
- package/dist/components/Panel/LazyPanel.svelte +110 -0
- package/dist/components/Panel/LazyPanel.svelte.d.ts +46 -0
- package/dist/components/Panel/Panel.svelte +205 -0
- package/dist/components/Panel/Panel.svelte.d.ts +23 -0
- package/dist/components/Progress/Progress.svelte +220 -0
- package/dist/components/Progress/Progress.svelte.d.ts +61 -0
- package/dist/components/Separator/Separator.svelte +109 -0
- package/dist/components/Separator/Separator.svelte.d.ts +35 -0
- package/dist/components/Sidebar/Sidebar.svelte +213 -0
- package/dist/components/Sidebar/Sidebar.svelte.d.ts +60 -0
- package/dist/components/Skeleton/Skeleton.svelte +170 -0
- package/dist/components/Skeleton/Skeleton.svelte.d.ts +48 -0
- package/dist/components/Stepper/Stepper.svelte +111 -0
- package/dist/components/Stepper/Stepper.svelte.d.ts +54 -0
- package/dist/components/Stepper/StepperStep.svelte +369 -0
- package/dist/components/Stepper/StepperStep.svelte.d.ts +63 -0
- package/dist/components/Table/Table.svelte +167 -0
- package/dist/components/Table/Table.svelte.d.ts +56 -0
- package/dist/components/Table/TableBody.svelte +41 -0
- package/dist/components/Table/TableBody.svelte.d.ts +33 -0
- package/dist/components/Table/TableCell.svelte +76 -0
- package/dist/components/Table/TableCell.svelte.d.ts +36 -0
- package/dist/components/Table/TableHead.svelte +41 -0
- package/dist/components/Table/TableHead.svelte.d.ts +32 -0
- package/dist/components/Table/TableHeader.svelte +148 -0
- package/dist/components/Table/TableHeader.svelte.d.ts +42 -0
- package/dist/components/Table/TableRow.svelte +99 -0
- package/dist/components/Table/TableRow.svelte.d.ts +40 -0
- package/dist/components/Tabs/Tab.svelte +145 -0
- package/dist/components/Tabs/Tab.svelte.d.ts +36 -0
- package/dist/components/Tabs/TabList.svelte +60 -0
- package/dist/components/Tabs/TabList.svelte.d.ts +32 -0
- package/dist/components/Tabs/TabPanel.svelte +118 -0
- package/dist/components/Tabs/TabPanel.svelte.d.ts +38 -0
- package/dist/components/Tabs/Tabs.svelte +287 -0
- package/dist/components/Tabs/Tabs.svelte.d.ts +50 -0
- package/dist/components/Tag/Tag.svelte +260 -0
- package/dist/components/Tag/Tag.svelte.d.ts +54 -0
- package/dist/components/Tag/TagGroup.svelte +147 -0
- package/dist/components/Tag/TagGroup.svelte.d.ts +62 -0
- package/dist/components/ThemeToggle/ThemeToggle.svelte +93 -0
- package/dist/components/ThemeToggle/ThemeToggle.svelte.d.ts +12 -0
- package/dist/components/Timeline/Timeline.svelte +144 -0
- package/dist/components/Timeline/Timeline.svelte.d.ts +48 -0
- package/dist/components/Timeline/TimelineItem.svelte +391 -0
- package/dist/components/Timeline/TimelineItem.svelte.d.ts +63 -0
- package/dist/components/Toast/Toast.svelte +313 -0
- package/dist/components/Toast/Toast.svelte.d.ts +44 -0
- package/dist/components/Toast/toastStore.d.ts +40 -0
- package/dist/components/Toast/toastStore.js +293 -0
- package/dist/components/Tooltip/Tooltip.svelte +282 -0
- package/dist/components/Tooltip/Tooltip.svelte.d.ts +55 -0
- package/dist/components/Tree/Tree.svelte +129 -0
- package/dist/components/Tree/Tree.svelte.d.ts +61 -0
- package/dist/components/Tree/TreeNode.svelte +332 -0
- package/dist/components/Tree/TreeNode.svelte.d.ts +55 -0
- package/dist/components/icons/TwintrinsicLogo.svelte +73 -0
- package/dist/components/icons/TwintrinsicLogo.svelte.d.ts +17 -0
- package/dist/components/icons/twintrinsic-source.svg +73 -0
- package/dist/components/icons/twintrinsic.svg +38 -0
- package/dist/docs/EventsTable.svelte +86 -0
- package/dist/docs/EventsTable.svelte.d.ts +27 -0
- package/dist/docs/PropsTable.svelte +103 -0
- package/dist/docs/PropsTable.svelte.d.ts +28 -0
- package/dist/docs/index.d.ts +2 -0
- package/dist/docs/index.js +2 -0
- package/dist/helpers/detectLanguage.d.ts +6 -0
- package/dist/helpers/detectLanguage.js +60 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +1 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +94 -0
- package/dist/twintrinsic.css +347 -0
- package/package.json +98 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
Avatar - A component for displaying user profile images with fallback options.
|
|
4
|
+
Provides consistent styling, accessibility features, and various display options.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
```svelte
|
|
8
|
+
<Avatar
|
|
9
|
+
src="/path/to/image.jpg"
|
|
10
|
+
alt="User Name"
|
|
11
|
+
/>
|
|
12
|
+
|
|
13
|
+
<Avatar
|
|
14
|
+
name="John Doe"
|
|
15
|
+
size="lg"
|
|
16
|
+
shape="square"
|
|
17
|
+
/>
|
|
18
|
+
|
|
19
|
+
<Avatar
|
|
20
|
+
gravatarEmail="user@example.com"
|
|
21
|
+
name="John Doe"
|
|
22
|
+
status="online"
|
|
23
|
+
/>
|
|
24
|
+
|
|
25
|
+
<Avatar
|
|
26
|
+
src="/path/to/image.jpg"
|
|
27
|
+
fallback="JD"
|
|
28
|
+
status="online"
|
|
29
|
+
/>
|
|
30
|
+
```
|
|
31
|
+
-->
|
|
32
|
+
<script lang="ts">
|
|
33
|
+
import { onMount } from "svelte"
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
/** @type {string} - Additional CSS classes */
|
|
37
|
+
class: className = "",
|
|
38
|
+
|
|
39
|
+
/** @type {string} - HTML id for accessibility */
|
|
40
|
+
id = crypto.randomUUID(),
|
|
41
|
+
|
|
42
|
+
/** @type {string} - Image source URL */
|
|
43
|
+
src,
|
|
44
|
+
|
|
45
|
+
/** @type {string} - Alt text for the image */
|
|
46
|
+
alt,
|
|
47
|
+
|
|
48
|
+
/** @type {string} - User name for generating initials */
|
|
49
|
+
name,
|
|
50
|
+
|
|
51
|
+
/** @type {string} - Fallback text when image fails to load or no src provided */
|
|
52
|
+
fallback,
|
|
53
|
+
|
|
54
|
+
/** @type {string} - Gravatar email address */
|
|
55
|
+
gravatarEmail,
|
|
56
|
+
|
|
57
|
+
/** @type {string} - Size of the avatar (xs, sm, md, lg, xl) */
|
|
58
|
+
size = "md",
|
|
59
|
+
|
|
60
|
+
/** @type {string} - Shape of the avatar (circle, square, rounded) */
|
|
61
|
+
shape = "circle",
|
|
62
|
+
|
|
63
|
+
/** @type {"online" | "offline" | "away" | "busy" | undefined} - Status indicator (online, offline, away, busy) */
|
|
64
|
+
status,
|
|
65
|
+
|
|
66
|
+
/** @type {string} - Background color for text avatars (CSS color value) */
|
|
67
|
+
bgColor,
|
|
68
|
+
|
|
69
|
+
/** @type {boolean} - Whether to show a border */
|
|
70
|
+
bordered = false,
|
|
71
|
+
|
|
72
|
+
/** @type {boolean} - Whether to add a shadow effect */
|
|
73
|
+
shadowed = false,
|
|
74
|
+
|
|
75
|
+
/** @type {Function} - Custom function to generate initials */
|
|
76
|
+
initialsGenerator,
|
|
77
|
+
} = $props()
|
|
78
|
+
|
|
79
|
+
// Component state
|
|
80
|
+
let imageLoaded = $state(false)
|
|
81
|
+
let imageError = $state(false)
|
|
82
|
+
let avatarElement
|
|
83
|
+
let gravatarUrl = $state("")
|
|
84
|
+
|
|
85
|
+
// Generate gravatar URL if email is provided
|
|
86
|
+
$effect(() => {
|
|
87
|
+
if (gravatarEmail) {
|
|
88
|
+
generateGravatarUrl(gravatarEmail).then(url => {
|
|
89
|
+
gravatarUrl = url
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Generates a Gravatar URL from an email address using MD5 hash
|
|
96
|
+
* @param {string} email - Email address
|
|
97
|
+
* @returns {Promise<string>} - Gravatar URL
|
|
98
|
+
*/
|
|
99
|
+
async function generateGravatarUrl(email: string): Promise<string> {
|
|
100
|
+
if (!email) return ""
|
|
101
|
+
|
|
102
|
+
const trimmedEmail = email.trim().toLowerCase()
|
|
103
|
+
const msgBuffer = new TextEncoder().encode(trimmedEmail)
|
|
104
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer)
|
|
105
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
|
106
|
+
const hashHex = hashArray.map(b => b.toString(16).padStart(2, "0")).join("")
|
|
107
|
+
|
|
108
|
+
return `https://www.gravatar.com/avatar/${hashHex}?d=identicon`
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Generates initials from a name
|
|
113
|
+
* @param {string} name - Full name
|
|
114
|
+
* @returns {string} - Initials (1-2 characters)
|
|
115
|
+
*/
|
|
116
|
+
function generateInitials(name: string): string {
|
|
117
|
+
if (!name) return ""
|
|
118
|
+
|
|
119
|
+
if (initialsGenerator) {
|
|
120
|
+
return initialsGenerator(name)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Default implementation: first letter of first and last name
|
|
124
|
+
const parts = name.trim().split(/\s+/)
|
|
125
|
+
|
|
126
|
+
if (parts.length === 1) {
|
|
127
|
+
return parts[0].charAt(0).toUpperCase()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase()
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Handles image load event
|
|
135
|
+
*/
|
|
136
|
+
function handleImageLoad() {
|
|
137
|
+
imageLoaded = true
|
|
138
|
+
imageError = false
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Handles image error event
|
|
143
|
+
*/
|
|
144
|
+
function handleImageError() {
|
|
145
|
+
imageLoaded = false
|
|
146
|
+
imageError = true
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Determine what to display as fallback
|
|
150
|
+
const displayFallback = $derived(fallback || (name ? generateInitials(name) : ""))
|
|
151
|
+
|
|
152
|
+
// Determine the image source (prefer explicit src over gravatar)
|
|
153
|
+
const imageSrc = $derived(src || gravatarUrl)
|
|
154
|
+
|
|
155
|
+
// Determine if we should show the image
|
|
156
|
+
const showImage = $derived(imageSrc && !imageError)
|
|
157
|
+
|
|
158
|
+
// Determine if we should show the fallback
|
|
159
|
+
const showFallback = $derived(!showImage && !!displayFallback)
|
|
160
|
+
|
|
161
|
+
// Determine size classes
|
|
162
|
+
const sizeClasses = $derived(
|
|
163
|
+
{
|
|
164
|
+
xs: "w-6 h-6 text-xs",
|
|
165
|
+
sm: "w-8 h-8 text-sm",
|
|
166
|
+
md: "w-10 h-10 text-base",
|
|
167
|
+
lg: "w-12 h-12 text-lg",
|
|
168
|
+
xl: "w-16 h-16 text-xl",
|
|
169
|
+
}[size] || "w-10 h-10 text-base"
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
// Determine shape classes
|
|
173
|
+
const shapeClasses = $derived(
|
|
174
|
+
{
|
|
175
|
+
circle: "rounded-full",
|
|
176
|
+
square: "rounded-none",
|
|
177
|
+
rounded: "rounded-md",
|
|
178
|
+
}[shape] || "rounded-full"
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
// Determine status classes
|
|
182
|
+
const statusClasses = $derived.by(() => {
|
|
183
|
+
if (status === "online") return "bg-success-500"
|
|
184
|
+
if (status === "offline") return "bg-muted"
|
|
185
|
+
if (status === "away") return "bg-warning-500"
|
|
186
|
+
if (status === "busy") return "bg-error-500"
|
|
187
|
+
return "bg-muted"
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
// Generate a random color based on the name or fallback
|
|
191
|
+
const randomBgColor = $derived(generateRandomColor())
|
|
192
|
+
|
|
193
|
+
// Function to generate a random color based on the name or fallback
|
|
194
|
+
function generateRandomColor() {
|
|
195
|
+
if (bgColor) return bgColor
|
|
196
|
+
|
|
197
|
+
const seed = name || fallback || id
|
|
198
|
+
const colors = [
|
|
199
|
+
"bg-primary-500",
|
|
200
|
+
"bg-secondary-500",
|
|
201
|
+
"bg-success-500",
|
|
202
|
+
"bg-warning-500",
|
|
203
|
+
"bg-error-500",
|
|
204
|
+
"bg-info-500",
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
// Simple hash function to get consistent color
|
|
208
|
+
let hash = 0
|
|
209
|
+
for (let i = 0; i < seed.length; i++) {
|
|
210
|
+
hash = (hash << 5) - hash + seed.charCodeAt(i)
|
|
211
|
+
hash = hash & hash // Convert to 32bit integer
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const index = Math.abs(hash) % colors.length
|
|
215
|
+
return colors[index]
|
|
216
|
+
}
|
|
217
|
+
</script>
|
|
218
|
+
|
|
219
|
+
<div
|
|
220
|
+
{id}
|
|
221
|
+
class="
|
|
222
|
+
avatar
|
|
223
|
+
{sizeClasses}
|
|
224
|
+
{shapeClasses}
|
|
225
|
+
{bordered ? 'avatar-bordered' : ''}
|
|
226
|
+
{shadowed ? 'avatar-shadowed' : ''}
|
|
227
|
+
{className}
|
|
228
|
+
"
|
|
229
|
+
aria-label={alt || name || 'Avatar'}
|
|
230
|
+
bind:this={avatarElement}
|
|
231
|
+
>
|
|
232
|
+
{#if showImage}
|
|
233
|
+
<img
|
|
234
|
+
src={imageSrc}
|
|
235
|
+
alt={alt || name || 'Avatar'}
|
|
236
|
+
class="avatar-image"
|
|
237
|
+
onload={handleImageLoad}
|
|
238
|
+
onerror={handleImageError}
|
|
239
|
+
/>
|
|
240
|
+
{:else if showFallback}
|
|
241
|
+
<div
|
|
242
|
+
class="avatar-fallback {randomBgColor}"
|
|
243
|
+
style={bgColor ? `background-color: ${bgColor}` : ''}
|
|
244
|
+
>
|
|
245
|
+
{displayFallback}
|
|
246
|
+
</div>
|
|
247
|
+
{:else}
|
|
248
|
+
<div class="avatar-placeholder">
|
|
249
|
+
<svg class="w-full h-full" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
250
|
+
<path d="M12 12a5 5 0 100-10 5 5 0 000 10zm0-2a3 3 0 100-6 3 3 0 000 6zm9 11a1 1 0 01-1 1H4a1 1 0 01-1-1v-1c0-3.87 3.13-7 7-7h4c3.87 0 7 3.13 7 7v1z"/>
|
|
251
|
+
</svg>
|
|
252
|
+
</div>
|
|
253
|
+
{/if}
|
|
254
|
+
|
|
255
|
+
{#if status}
|
|
256
|
+
<span
|
|
257
|
+
class="avatar-status {statusClasses}"
|
|
258
|
+
aria-label={`Status: ${status}`}
|
|
259
|
+
></span>
|
|
260
|
+
{/if}
|
|
261
|
+
</div>
|
|
262
|
+
|
|
263
|
+
<style>
|
|
264
|
+
@reference "../../twintrinsic.css";
|
|
265
|
+
|
|
266
|
+
.avatar {
|
|
267
|
+
@apply relative inline-flex items-center justify-center flex-shrink-0;
|
|
268
|
+
@apply bg-surface dark:bg-surface text-text dark:text-text;
|
|
269
|
+
@apply overflow-hidden;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.avatar-bordered {
|
|
273
|
+
@apply border-2 border-background dark:border-background;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.avatar-shadowed {
|
|
277
|
+
@apply shadow-md dark:shadow-lg;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.avatar-image {
|
|
281
|
+
@apply w-full h-full object-cover;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.avatar-fallback {
|
|
285
|
+
@apply w-full h-full flex items-center justify-center;
|
|
286
|
+
@apply text-white dark:text-white font-medium;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.avatar-placeholder {
|
|
290
|
+
@apply w-full h-full flex items-center justify-center;
|
|
291
|
+
@apply bg-muted/20 dark:bg-muted/20 text-muted dark:text-muted;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.avatar-status {
|
|
295
|
+
@apply absolute bottom-0 right-0;
|
|
296
|
+
@apply w-1/4 h-1/4 min-w-1.5 min-h-1.5 max-w-3 max-h-3;
|
|
297
|
+
@apply rounded-full;
|
|
298
|
+
@apply border-2 border-background dark:border-background;
|
|
299
|
+
}
|
|
300
|
+
</style>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Avatar - A component for displaying user profile images with fallback options.
|
|
3
|
+
* Provides consistent styling, accessibility features, and various display options.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* ```svelte
|
|
7
|
+
* <Avatar
|
|
8
|
+
* src="/path/to/image.jpg"
|
|
9
|
+
* alt="User Name"
|
|
10
|
+
* />
|
|
11
|
+
*
|
|
12
|
+
* <Avatar
|
|
13
|
+
* name="John Doe"
|
|
14
|
+
* size="lg"
|
|
15
|
+
* shape="square"
|
|
16
|
+
* />
|
|
17
|
+
*
|
|
18
|
+
* <Avatar
|
|
19
|
+
* gravatarEmail="user@example.com"
|
|
20
|
+
* name="John Doe"
|
|
21
|
+
* status="online"
|
|
22
|
+
* />
|
|
23
|
+
*
|
|
24
|
+
* <Avatar
|
|
25
|
+
* src="/path/to/image.jpg"
|
|
26
|
+
* fallback="JD"
|
|
27
|
+
* status="online"
|
|
28
|
+
* />
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare const Avatar: import("svelte").Component<{
|
|
32
|
+
class?: string;
|
|
33
|
+
id?: any;
|
|
34
|
+
src: any;
|
|
35
|
+
alt: any;
|
|
36
|
+
name: any;
|
|
37
|
+
fallback: any;
|
|
38
|
+
gravatarEmail: any;
|
|
39
|
+
size?: string;
|
|
40
|
+
shape?: string;
|
|
41
|
+
status: any;
|
|
42
|
+
bgColor: any;
|
|
43
|
+
bordered?: boolean;
|
|
44
|
+
shadowed?: boolean;
|
|
45
|
+
initialsGenerator: any;
|
|
46
|
+
}, {}, "">;
|
|
47
|
+
type Avatar = ReturnType<typeof Avatar>;
|
|
48
|
+
export default Avatar;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
AvatarGroup - A component for displaying multiple avatars in a compact, overlapping layout.
|
|
4
|
+
Provides consistent styling, accessibility features, and overflow handling.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
```svelte
|
|
8
|
+
<AvatarGroup>
|
|
9
|
+
<Avatar src="/user1.jpg" alt="User 1" />
|
|
10
|
+
<Avatar src="/user2.jpg" alt="User 2" />
|
|
11
|
+
<Avatar src="/user3.jpg" alt="User 3" />
|
|
12
|
+
</AvatarGroup>
|
|
13
|
+
|
|
14
|
+
<AvatarGroup max={3} total={10}>
|
|
15
|
+
<Avatar name="John Doe" />
|
|
16
|
+
<Avatar name="Jane Smith" />
|
|
17
|
+
<Avatar name="Bob Johnson" />
|
|
18
|
+
</AvatarGroup>
|
|
19
|
+
```
|
|
20
|
+
-->
|
|
21
|
+
<script>
|
|
22
|
+
import { setContext } from "svelte"
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
/** @type {string} - Additional CSS classes */
|
|
26
|
+
class: className = "",
|
|
27
|
+
|
|
28
|
+
/** @type {string} - HTML id for accessibility */
|
|
29
|
+
id = crypto.randomUUID(),
|
|
30
|
+
|
|
31
|
+
/** @type {string} - Size of the avatars (xs, sm, md, lg, xl) */
|
|
32
|
+
size = "md",
|
|
33
|
+
|
|
34
|
+
/** @type {number} - Maximum number of avatars to display */
|
|
35
|
+
max,
|
|
36
|
+
|
|
37
|
+
/** @type {number} - Total number of avatars (for overflow count) */
|
|
38
|
+
total,
|
|
39
|
+
|
|
40
|
+
/** @type {number} - Spacing between avatars (-8 to 8) */
|
|
41
|
+
spacing = -4,
|
|
42
|
+
|
|
43
|
+
/** @type {boolean} - Whether to show a border around avatars */
|
|
44
|
+
bordered = true,
|
|
45
|
+
|
|
46
|
+
/** @type {string} - ARIA label for the group */
|
|
47
|
+
ariaLabel = "Avatar group",
|
|
48
|
+
|
|
49
|
+
children,
|
|
50
|
+
} = $props()
|
|
51
|
+
|
|
52
|
+
// Provide context for child avatars
|
|
53
|
+
$effect(() => {
|
|
54
|
+
setContext("avatarGroup", {
|
|
55
|
+
size,
|
|
56
|
+
bordered,
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// Determine spacing class based on the spacing prop
|
|
61
|
+
const spacingClass = $derived(`avatar-group-spacing-${spacing}`)
|
|
62
|
+
|
|
63
|
+
// Determine if we need to show overflow
|
|
64
|
+
const showOverflow = $derived(max !== undefined && total !== undefined && total > max)
|
|
65
|
+
|
|
66
|
+
// Calculate overflow count
|
|
67
|
+
const overflowCount = $derived(showOverflow ? total - max : 0)
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<div
|
|
71
|
+
{id}
|
|
72
|
+
class="
|
|
73
|
+
avatar-group
|
|
74
|
+
{spacingClass}
|
|
75
|
+
{className}
|
|
76
|
+
"
|
|
77
|
+
role="group"
|
|
78
|
+
aria-label={ariaLabel}
|
|
79
|
+
>
|
|
80
|
+
<div class="avatar-group-items">
|
|
81
|
+
{@render children?.()}
|
|
82
|
+
|
|
83
|
+
{#if showOverflow}
|
|
84
|
+
<div class="avatar-group-overflow">
|
|
85
|
+
<span class="avatar-group-overflow-text">+{overflowCount}</span>
|
|
86
|
+
</div>
|
|
87
|
+
{/if}
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<style>
|
|
92
|
+
@reference "../../twintrinsic.css";
|
|
93
|
+
|
|
94
|
+
.avatar-group {
|
|
95
|
+
@apply inline-flex;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.avatar-group-items {
|
|
99
|
+
@apply flex items-center;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Spacing classes */
|
|
103
|
+
.avatar-group-spacing-8 :global(.avatar) {
|
|
104
|
+
@apply ml-8;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.avatar-group-spacing-6 :global(.avatar) {
|
|
108
|
+
@apply ml-6;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.avatar-group-spacing-4 :global(.avatar) {
|
|
112
|
+
@apply ml-4;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.avatar-group-spacing-2 :global(.avatar) {
|
|
116
|
+
@apply ml-2;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.avatar-group-spacing-0 :global(.avatar) {
|
|
120
|
+
@apply ml-0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.avatar-group-spacing--2 :global(.avatar) {
|
|
124
|
+
@apply -ml-2;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.avatar-group-spacing--4 :global(.avatar) {
|
|
128
|
+
@apply -ml-4;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.avatar-group-spacing--6 :global(.avatar) {
|
|
132
|
+
@apply -ml-6;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.avatar-group-spacing--8 :global(.avatar) {
|
|
136
|
+
@apply -ml-8;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* Remove margin from first avatar */
|
|
140
|
+
.avatar-group-items > :global(:first-child) {
|
|
141
|
+
@apply ml-0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* Overflow counter */
|
|
145
|
+
.avatar-group-overflow {
|
|
146
|
+
@apply flex items-center justify-center;
|
|
147
|
+
@apply bg-surface dark:bg-surface text-text dark:text-text;
|
|
148
|
+
@apply rounded-full overflow-hidden;
|
|
149
|
+
@apply border-2 border-background dark:border-background;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.avatar-group-overflow-text {
|
|
153
|
+
@apply font-medium;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* Inherit size from context */
|
|
157
|
+
.avatar-group-overflow {
|
|
158
|
+
@apply w-10 h-10 text-base;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
:global(.avatar-group-items .avatar-xs) ~ .avatar-group-overflow,
|
|
162
|
+
:global(.avatar-xs) ~ .avatar-group-overflow {
|
|
163
|
+
@apply w-6 h-6 text-xs;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
:global(.avatar-group-items .avatar-sm) ~ .avatar-group-overflow,
|
|
167
|
+
:global(.avatar-sm) ~ .avatar-group-overflow {
|
|
168
|
+
@apply w-8 h-8 text-sm;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
:global(.avatar-group-items .avatar-md) ~ .avatar-group-overflow,
|
|
172
|
+
:global(.avatar-md) ~ .avatar-group-overflow {
|
|
173
|
+
@apply w-10 h-10 text-base;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
:global(.avatar-group-items .avatar-lg) ~ .avatar-group-overflow,
|
|
177
|
+
:global(.avatar-lg) ~ .avatar-group-overflow {
|
|
178
|
+
@apply w-12 h-12 text-lg;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
:global(.avatar-group-items .avatar-xl) ~ .avatar-group-overflow,
|
|
182
|
+
:global(.avatar-xl) ~ .avatar-group-overflow {
|
|
183
|
+
@apply w-16 h-16 text-xl;
|
|
184
|
+
}
|
|
185
|
+
</style>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export default AvatarGroup;
|
|
2
|
+
type AvatarGroup = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* AvatarGroup - A component for displaying multiple avatars in a compact, overlapping layout.
|
|
8
|
+
* Provides consistent styling, accessibility features, and overflow handling.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```svelte
|
|
12
|
+
* <AvatarGroup>
|
|
13
|
+
* <Avatar src="/user1.jpg" alt="User 1" />
|
|
14
|
+
* <Avatar src="/user2.jpg" alt="User 2" />
|
|
15
|
+
* <Avatar src="/user3.jpg" alt="User 3" />
|
|
16
|
+
* </AvatarGroup>
|
|
17
|
+
*
|
|
18
|
+
* <AvatarGroup max={3} total={10}>
|
|
19
|
+
* <Avatar name="John Doe" />
|
|
20
|
+
* <Avatar name="Jane Smith" />
|
|
21
|
+
* <Avatar name="Bob Johnson" />
|
|
22
|
+
* </AvatarGroup>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare const AvatarGroup: import("svelte").Component<{
|
|
26
|
+
class?: string;
|
|
27
|
+
id?: any;
|
|
28
|
+
size?: string;
|
|
29
|
+
max: any;
|
|
30
|
+
total: any;
|
|
31
|
+
spacing?: any;
|
|
32
|
+
bordered?: boolean;
|
|
33
|
+
ariaLabel?: string;
|
|
34
|
+
children: any;
|
|
35
|
+
}, {}, "">;
|
|
36
|
+
type $$ComponentProps = {
|
|
37
|
+
class?: string;
|
|
38
|
+
id?: any;
|
|
39
|
+
size?: string;
|
|
40
|
+
max: any;
|
|
41
|
+
total: any;
|
|
42
|
+
spacing?: any;
|
|
43
|
+
bordered?: boolean;
|
|
44
|
+
ariaLabel?: string;
|
|
45
|
+
children: any;
|
|
46
|
+
};
|