@marianmeres/stuic 2.65.0 → 3.0.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 +292 -4
- package/dist/README.md +41 -18
- package/dist/actions/popover/README.md +19 -0
- package/dist/actions/popover/index.css +6 -9
- package/dist/actions/popover/popover.svelte.js +2 -2
- package/dist/actions/tooltip/README.md +18 -0
- package/dist/actions/tooltip/index.css +5 -8
- package/dist/actions/tooltip/tooltip.svelte.js +1 -1
- package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte +9 -10
- package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte.d.ts +3 -3
- package/dist/components/AlertConfirmPrompt/Current.svelte +15 -17
- package/dist/components/AlertConfirmPrompt/Current.svelte.d.ts +5 -3
- package/dist/components/AlertConfirmPrompt/acp-icons.js +5 -4
- package/dist/components/AlertConfirmPrompt/index.css +62 -0
- package/dist/components/AssetsPreview/AssetsPreview.svelte +92 -73
- package/dist/components/AssetsPreview/AssetsPreview.svelte.d.ts +1 -0
- package/dist/components/AssetsPreview/index.css +59 -0
- package/dist/components/Avatar/Avatar.svelte +32 -18
- package/dist/components/Avatar/Avatar.svelte.d.ts +1 -0
- package/dist/components/Avatar/README.md +166 -0
- package/dist/components/Avatar/index.css +128 -0
- package/dist/components/Backdrop/Backdrop.svelte +8 -2
- package/dist/components/Backdrop/Backdrop.svelte.d.ts +1 -0
- package/dist/components/Backdrop/README.md +71 -6
- package/dist/components/Backdrop/index.css +29 -0
- package/dist/components/Button/Button.svelte +117 -124
- package/dist/components/Button/Button.svelte.d.ts +35 -23
- package/dist/components/Button/README.md +87 -21
- package/dist/components/Button/index.css +473 -9
- package/dist/components/Button/index.d.ts +1 -1
- package/dist/components/Button/index.js +1 -1
- package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte +7 -38
- package/dist/components/ButtonGroupRadio/README.md +82 -4
- package/dist/components/ButtonGroupRadio/index.css +152 -14
- package/dist/components/Collapsible/Collapsible.svelte +7 -7
- package/dist/components/Collapsible/Collapsible.svelte.d.ts +2 -2
- package/dist/components/Collapsible/README.md +34 -2
- package/dist/components/Collapsible/index.css +38 -0
- package/dist/components/CommandMenu/CommandMenu.svelte +13 -24
- package/dist/components/CommandMenu/README.md +39 -0
- package/dist/components/CommandMenu/index.css +45 -2
- package/dist/components/DismissibleMessage/DismissibleMessage.svelte +53 -50
- package/dist/components/DismissibleMessage/DismissibleMessage.svelte.d.ts +6 -5
- package/dist/components/DismissibleMessage/README.md +93 -11
- package/dist/components/DismissibleMessage/index.css +122 -8
- package/dist/components/DismissibleMessage/index.d.ts +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.svelte +14 -50
- package/dist/components/DropdownMenu/DropdownMenu.svelte.d.ts +6 -6
- package/dist/components/DropdownMenu/README.md +132 -0
- package/dist/components/DropdownMenu/index.css +231 -27
- package/dist/components/Input/FieldAssets.svelte +8 -5
- package/dist/components/Input/FieldCheckbox.svelte +7 -44
- package/dist/components/Input/FieldFile.svelte +1 -6
- package/dist/components/Input/FieldInput.svelte +1 -1
- package/dist/components/Input/FieldOptions.svelte +41 -38
- package/dist/components/Input/FieldRadios.svelte +7 -16
- package/dist/components/Input/FieldSelect.svelte +1 -1
- package/dist/components/Input/FieldSwitch.svelte +1 -5
- package/dist/components/Input/FieldTextarea.svelte +1 -1
- package/dist/components/Input/README.md +194 -0
- package/dist/components/Input/_internal/FieldRadioInternal.svelte +2 -40
- package/dist/components/Input/_internal/InputWrap.svelte +8 -48
- package/dist/components/Input/index.css +522 -127
- package/dist/components/ListItemButton/ListItemButton.svelte +37 -73
- package/dist/components/ListItemButton/ListItemButton.svelte.d.ts +1 -9
- package/dist/components/ListItemButton/README.md +100 -45
- package/dist/components/ListItemButton/index.css +175 -56
- package/dist/components/ListItemButton/index.d.ts +1 -1
- package/dist/components/ListItemButton/index.js +1 -1
- package/dist/components/Modal/Modal.svelte +2 -8
- package/dist/components/Modal/Modal.svelte.d.ts +1 -0
- package/dist/components/Modal/README.md +29 -0
- package/dist/components/Modal/index.css +36 -0
- package/dist/components/ModalDialog/ModalDialog.svelte +2 -21
- package/dist/components/ModalDialog/README.md +35 -0
- package/dist/components/ModalDialog/index.css +57 -0
- package/dist/components/Notifications/Notifications.svelte +44 -128
- package/dist/components/Notifications/Notifications.svelte.d.ts +9 -17
- package/dist/components/Notifications/README.md +186 -70
- package/dist/components/Notifications/index.css +212 -15
- package/dist/components/Progress/README.md +15 -0
- package/dist/components/Progress/_internal/Bar.svelte +2 -2
- package/dist/components/Progress/index.css +4 -4
- package/dist/components/Skeleton/Skeleton.svelte +3 -2
- package/dist/components/Skeleton/index.css +11 -14
- package/dist/components/Spinner/Spinner.svelte +2 -2
- package/dist/components/Spinner/SpinnerCircle.svelte +1 -1
- package/dist/components/Switch/README.md +15 -0
- package/dist/components/Switch/Switch.svelte +4 -7
- package/dist/components/Switch/Switch.svelte.d.ts +1 -1
- package/dist/components/Switch/SwitchButton.svelte +4 -5
- package/dist/components/Switch/index.css +3 -4
- package/dist/components/TabbedMenu/README.md +26 -21
- package/dist/components/TabbedMenu/TabbedMenu.svelte +5 -5
- package/dist/components/TabbedMenu/index.css +7 -22
- package/dist/components/ThemePreview/README.md +289 -0
- package/dist/components/ThemePreview/ThemePreview.svelte +341 -0
- package/dist/components/ThemePreview/ThemePreview.svelte.d.ts +33 -0
- package/dist/components/ThemePreview/index.css +493 -0
- package/dist/components/ThemePreview/index.d.ts +1 -0
- package/dist/components/ThemePreview/index.js +1 -0
- package/dist/components/TwCheck/TwCheck.svelte +4 -4
- package/dist/components/TwCheck/index.css +3 -2
- package/dist/components/TypeaheadInput/TypeaheadInput.svelte +1 -1
- package/dist/components/X/X.svelte +16 -4
- package/dist/components/X/X.svelte.d.ts +1 -0
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.css +31 -16
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/themes/blue-orange.css +163 -0
- package/dist/themes/blue-orange.d.ts +6 -0
- package/dist/themes/blue-orange.js +151 -0
- package/dist/themes/cyan-red.css +163 -0
- package/dist/themes/cyan-red.d.ts +6 -0
- package/dist/themes/cyan-red.js +151 -0
- package/dist/themes/cyan-slate.css +163 -0
- package/dist/themes/cyan-slate.d.ts +6 -0
- package/dist/themes/cyan-slate.js +151 -0
- package/dist/themes/emerald-pink.css +163 -0
- package/dist/themes/emerald-pink.d.ts +6 -0
- package/dist/themes/emerald-pink.js +151 -0
- package/dist/themes/fuchsia-emerald.css +163 -0
- package/dist/themes/fuchsia-emerald.d.ts +6 -0
- package/dist/themes/fuchsia-emerald.js +151 -0
- package/dist/themes/gray.css +163 -0
- package/dist/themes/gray.d.ts +6 -0
- package/dist/themes/gray.js +151 -0
- package/dist/themes/indigo-amber.css +163 -0
- package/dist/themes/indigo-amber.d.ts +6 -0
- package/dist/themes/indigo-amber.js +151 -0
- package/dist/themes/neutral.css +163 -0
- package/dist/themes/neutral.d.ts +6 -0
- package/dist/themes/neutral.js +151 -0
- package/dist/themes/pink-emerald.css +163 -0
- package/dist/themes/pink-emerald.d.ts +6 -0
- package/dist/themes/pink-emerald.js +151 -0
- package/dist/themes/purple-yellow.css +163 -0
- package/dist/themes/purple-yellow.d.ts +6 -0
- package/dist/themes/purple-yellow.js +151 -0
- package/dist/themes/rainbow.css +163 -0
- package/dist/themes/rainbow.d.ts +6 -0
- package/dist/themes/rainbow.js +156 -0
- package/dist/themes/red-blue.css +163 -0
- package/dist/themes/red-blue.d.ts +6 -0
- package/dist/themes/red-blue.js +151 -0
- package/dist/themes/red-cyan.css +163 -0
- package/dist/themes/red-cyan.d.ts +6 -0
- package/dist/themes/red-cyan.js +151 -0
- package/dist/themes/rose-teal.css +163 -0
- package/dist/themes/rose-teal.d.ts +6 -0
- package/dist/themes/rose-teal.js +151 -0
- package/dist/themes/sky-amber.css +163 -0
- package/dist/themes/sky-amber.d.ts +6 -0
- package/dist/themes/sky-amber.js +151 -0
- package/dist/themes/slate-cyan.css +163 -0
- package/dist/themes/slate-cyan.d.ts +6 -0
- package/dist/themes/slate-cyan.js +151 -0
- package/dist/themes/tailwind-color-pairs.md +31 -0
- package/dist/themes/teal-rose.css +163 -0
- package/dist/themes/teal-rose.d.ts +6 -0
- package/dist/themes/teal-rose.js +151 -0
- package/dist/themes/violet-lime.css +163 -0
- package/dist/themes/violet-lime.d.ts +6 -0
- package/dist/themes/violet-lime.js +151 -0
- package/dist/utils/design-tokens.d.ts +43 -0
- package/dist/utils/design-tokens.js +100 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +22 -2
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { IntentColorKey } from "../../utils/design-tokens.js";
|
|
1
2
|
import { type AlertConfirmPromptStack } from "./alert-confirm-prompt-stack.svelte.js";
|
|
3
|
+
import "./index.css";
|
|
2
4
|
interface Props {
|
|
3
5
|
acp?: AlertConfirmPromptStack;
|
|
4
6
|
isPending?: boolean;
|
|
@@ -19,9 +21,9 @@ interface Props {
|
|
|
19
21
|
classButtonCancel?: string;
|
|
20
22
|
classButtonCustom?: string;
|
|
21
23
|
classButtonPrimary?: string;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
intentButtonCancel?: IntentColorKey;
|
|
25
|
+
intentButtonCustom?: IntentColorKey;
|
|
26
|
+
intentButtonPrimary?: IntentColorKey;
|
|
25
27
|
classSpinnerBox?: string;
|
|
26
28
|
defaultIcons?: Partial<Record<"info" | "success" | "warn" | "error" | "spinner", () => string | undefined>>;
|
|
27
29
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { iconAlertInfo, iconAlertSuccess, iconAlertWarning, iconAlertError, iconRefresh, } from "../../icons/index.js";
|
|
2
|
+
const size = 23;
|
|
2
3
|
export const acpDefaultIcons = {
|
|
3
|
-
info: () => iconAlertInfo({ size
|
|
4
|
-
success: () => iconAlertSuccess({}),
|
|
5
|
-
warn: () => iconAlertWarning({ class: "-mt-[
|
|
6
|
-
error: () => iconAlertError({}),
|
|
4
|
+
info: () => iconAlertInfo({ size }),
|
|
5
|
+
success: () => iconAlertSuccess({ size }),
|
|
6
|
+
warn: () => iconAlertWarning({ size, class: "-mt-[2px]" }), // move up a little because it looks better with the triangle
|
|
7
|
+
error: () => iconAlertError({ size }),
|
|
7
8
|
spinner: () => iconRefresh({ size: 32, class: "opacity-50" }),
|
|
8
9
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
ALERT CONFIRM PROMPT COMPONENT TOKENS
|
|
3
|
+
Override globally: :root { --stuic-acp-icon-box-radius: 0; }
|
|
4
|
+
Override locally: <AlertConfirmPrompt style="--stuic-acp-icon-box-radius: 4px;">
|
|
5
|
+
============================================================================ */
|
|
6
|
+
|
|
7
|
+
:root {
|
|
8
|
+
--stuic-acp-icon-box-radius: 9999px;
|
|
9
|
+
--stuic-acp-spinner-overlay-opacity: 0.75;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* ============================================================================
|
|
13
|
+
ICON BOX - colors set by variant
|
|
14
|
+
============================================================================ */
|
|
15
|
+
|
|
16
|
+
.stuic-acp .icon-box {
|
|
17
|
+
background: var(--_icon-bg);
|
|
18
|
+
color: var(--_icon-text);
|
|
19
|
+
border-radius: var(--stuic-acp-icon-box-radius);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* ============================================================================
|
|
23
|
+
SPINNER OVERLAY - uses surface color
|
|
24
|
+
============================================================================ */
|
|
25
|
+
|
|
26
|
+
.stuic-acp .spinner-box {
|
|
27
|
+
background: color-mix(
|
|
28
|
+
in srgb,
|
|
29
|
+
var(--stuic-color-surface) calc(var(--stuic-acp-spinner-overlay-opacity) * 100%),
|
|
30
|
+
transparent
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* ============================================================================
|
|
35
|
+
VARIANT COLOR MAPPING
|
|
36
|
+
Each variant sets internal CSS vars for the icon box.
|
|
37
|
+
============================================================================ */
|
|
38
|
+
|
|
39
|
+
/* Variant: info (default) */
|
|
40
|
+
.stuic-acp[data-variant='info'],
|
|
41
|
+
.stuic-acp:not([data-variant]) {
|
|
42
|
+
--_icon-bg: color-mix(in srgb, var(--stuic-color-info) 15%, transparent);
|
|
43
|
+
--_icon-text: var(--stuic-color-info);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Variant: success */
|
|
47
|
+
.stuic-acp[data-variant='success'] {
|
|
48
|
+
--_icon-bg: color-mix(in srgb, var(--stuic-color-success) 15%, transparent);
|
|
49
|
+
--_icon-text: var(--stuic-color-success);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Variant: warn */
|
|
53
|
+
.stuic-acp[data-variant='warn'] {
|
|
54
|
+
--_icon-bg: color-mix(in srgb, var(--stuic-color-warning) 15%, transparent);
|
|
55
|
+
--_icon-text: var(--stuic-color-warning);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Variant: error */
|
|
59
|
+
.stuic-acp[data-variant='error'] {
|
|
60
|
+
--_icon-bg: color-mix(in srgb, var(--stuic-color-destructive) 15%, transparent);
|
|
61
|
+
--_icon-text: var(--stuic-color-destructive);
|
|
62
|
+
}
|
|
@@ -171,6 +171,8 @@
|
|
|
171
171
|
</script>
|
|
172
172
|
|
|
173
173
|
<script lang="ts">
|
|
174
|
+
import "./index.css";
|
|
175
|
+
import Button from "../Button/Button.svelte";
|
|
174
176
|
const clog = createClog("AssetsPreview", { color: "auto" });
|
|
175
177
|
|
|
176
178
|
let {
|
|
@@ -219,7 +221,13 @@
|
|
|
219
221
|
let imgEl: HTMLImageElement | null = null;
|
|
220
222
|
let containerEl: HTMLDivElement | null = $state(null);
|
|
221
223
|
|
|
222
|
-
const
|
|
224
|
+
const BUTTON_CLS = "stuic-assets-preview-control pointer-events-auto p-0!";
|
|
225
|
+
|
|
226
|
+
const BUTTON_PROPS = {
|
|
227
|
+
aspect1: true,
|
|
228
|
+
variant: "soft",
|
|
229
|
+
roundedFull: true,
|
|
230
|
+
};
|
|
223
231
|
|
|
224
232
|
$effect(() => {
|
|
225
233
|
const visible = modal?.visibility().visible;
|
|
@@ -457,6 +465,7 @@
|
|
|
457
465
|
previewIdx = idx % assets.length;
|
|
458
466
|
}
|
|
459
467
|
|
|
468
|
+
const ICON_SIZE = 24;
|
|
460
469
|
// $inspect(assets).with(clog);
|
|
461
470
|
</script>
|
|
462
471
|
|
|
@@ -513,7 +522,9 @@
|
|
|
513
522
|
class: "mx-auto",
|
|
514
523
|
})}
|
|
515
524
|
</div>
|
|
516
|
-
<div class="
|
|
525
|
+
<div class="text-(--stuic-color-muted-foreground) mt-4">
|
|
526
|
+
{t("unable_to_preview")}
|
|
527
|
+
</div>
|
|
517
528
|
</div>
|
|
518
529
|
{/if}
|
|
519
530
|
|
|
@@ -521,95 +532,103 @@
|
|
|
521
532
|
<div
|
|
522
533
|
class="absolute inset-0 flex items-center justify-between pointer-events-none"
|
|
523
534
|
>
|
|
524
|
-
|
|
525
|
-
|
|
535
|
+
<!-- class={twMerge("p-4 aspect-square pointer-events-auto", classControls)} -->
|
|
536
|
+
<Button
|
|
537
|
+
class={twMerge(BUTTON_CLS, "ml-4", classControls)}
|
|
526
538
|
onclick={preview_previous}
|
|
527
539
|
type="button"
|
|
540
|
+
{...BUTTON_PROPS}
|
|
528
541
|
>
|
|
529
|
-
<span class="
|
|
530
|
-
|
|
531
|
-
</span>
|
|
532
|
-
</
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
542
|
+
<!-- <span class="stuic-assets-preview-control-nav p-3 block"> -->
|
|
543
|
+
{@html iconPrevious({ size: ICON_SIZE })}
|
|
544
|
+
<!-- </span> -->
|
|
545
|
+
</Button>
|
|
546
|
+
|
|
547
|
+
<!-- class={twMerge("p-4 aspect-square pointer-events-auto", classControls)} -->
|
|
548
|
+
<Button
|
|
549
|
+
class={twMerge(BUTTON_CLS, "mr-4", classControls)}
|
|
536
550
|
onclick={preview_next}
|
|
537
551
|
type="button"
|
|
552
|
+
{...BUTTON_PROPS}
|
|
538
553
|
>
|
|
539
|
-
<span class="
|
|
540
|
-
|
|
541
|
-
</span>
|
|
542
|
-
</
|
|
554
|
+
<!-- <span class="stuic-assets-preview-control-nav p-3 block"> -->
|
|
555
|
+
{@html iconNext({ size: ICON_SIZE })}
|
|
556
|
+
<!-- </span> -->
|
|
557
|
+
</Button>
|
|
543
558
|
</div>
|
|
544
559
|
{/if}
|
|
545
560
|
|
|
546
561
|
<div class="absolute top-4 left-4 right-4 flex items-center justify-between gap-3">
|
|
547
562
|
{#if !noName && previewAsset?.name}
|
|
548
|
-
<span class="truncate
|
|
563
|
+
<span class="stuic-assets-preview-label truncate px-1">
|
|
549
564
|
{previewAsset?.name}
|
|
550
565
|
</span>
|
|
551
566
|
{:else}
|
|
552
567
|
<span></span>
|
|
553
568
|
{/if}
|
|
554
569
|
<div class="flex items-center space-x-3 shrink-0">
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
570
|
+
{#if previewAsset.isImage}
|
|
571
|
+
<Button
|
|
572
|
+
class={twMerge(BUTTON_CLS, classControls)}
|
|
573
|
+
type="button"
|
|
574
|
+
onclick={zoomOut}
|
|
575
|
+
disabled={zoomLevelIdx === 0}
|
|
576
|
+
aria-label={t("zoom_out")}
|
|
577
|
+
tooltip={t("zoom_out")}
|
|
578
|
+
{...BUTTON_PROPS}
|
|
579
|
+
>
|
|
580
|
+
{@html iconZoomOut({ size: ICON_SIZE })}
|
|
581
|
+
</Button>
|
|
582
|
+
|
|
583
|
+
<Button
|
|
584
|
+
class={twMerge(BUTTON_CLS, classControls)}
|
|
585
|
+
type="button"
|
|
586
|
+
onclick={zoomIn}
|
|
587
|
+
disabled={zoomLevelIdx === ZOOM_LEVELS.length - 1}
|
|
588
|
+
aria-label={t("zoom_in")}
|
|
589
|
+
tooltip={t("zoom_in")}
|
|
590
|
+
{...BUTTON_PROPS}
|
|
591
|
+
>
|
|
592
|
+
{@html iconZoomIn({ size: ICON_SIZE })}
|
|
593
|
+
</Button>
|
|
594
|
+
{/if}
|
|
595
|
+
|
|
596
|
+
{#if typeof onDelete === "function"}
|
|
597
|
+
<Button
|
|
598
|
+
class={twMerge(BUTTON_CLS, classControls)}
|
|
599
|
+
type="button"
|
|
600
|
+
onclick={() => onDelete(previewAsset, previewIdx, { close })}
|
|
601
|
+
aria-label={t("delete")}
|
|
602
|
+
tooltip={t("delete")}
|
|
603
|
+
{...BUTTON_PROPS}
|
|
604
|
+
>
|
|
605
|
+
{@html iconDelete({ size: ICON_SIZE })}
|
|
606
|
+
</Button>
|
|
607
|
+
{/if}
|
|
608
|
+
|
|
609
|
+
<Button
|
|
610
|
+
class={twMerge(BUTTON_CLS, classControls)}
|
|
569
611
|
type="button"
|
|
570
|
-
onclick={
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
612
|
+
onclick={(e) => {
|
|
613
|
+
e.preventDefault();
|
|
614
|
+
forceDownload(String(previewAsset.url.original), previewAsset?.name || "");
|
|
615
|
+
}}
|
|
616
|
+
aria-label={t("download")}
|
|
617
|
+
tooltip={t("download")}
|
|
618
|
+
{...BUTTON_PROPS}
|
|
574
619
|
>
|
|
575
|
-
{@html
|
|
576
|
-
</
|
|
577
|
-
{/if}
|
|
620
|
+
{@html iconDownload({ size: ICON_SIZE })}
|
|
621
|
+
</Button>
|
|
578
622
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
623
|
+
<Button
|
|
624
|
+
class={twMerge(BUTTON_CLS, classControls)}
|
|
625
|
+
onclick={modal?.close}
|
|
626
|
+
aria-label={t("close")}
|
|
582
627
|
type="button"
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
{@html iconDelete({ class: "size-6" })}
|
|
588
|
-
</button>
|
|
589
|
-
{/if}
|
|
590
|
-
|
|
591
|
-
<button
|
|
592
|
-
class={twMerge(TOP_BUTTON_CLS, classControls)}
|
|
593
|
-
type="button"
|
|
594
|
-
onclick={(e) => {
|
|
595
|
-
e.preventDefault();
|
|
596
|
-
forceDownload(String(previewAsset.url.original), previewAsset?.name || "");
|
|
597
|
-
}}
|
|
598
|
-
aria-label={t("download")}
|
|
599
|
-
use:tooltip
|
|
600
|
-
>
|
|
601
|
-
{@html iconDownload({ class: "size-6" })}
|
|
602
|
-
</button>
|
|
603
|
-
|
|
604
|
-
<button
|
|
605
|
-
class={twMerge(TOP_BUTTON_CLS, classControls)}
|
|
606
|
-
onclick={modal?.close}
|
|
607
|
-
aria-label={t("close")}
|
|
608
|
-
type="button"
|
|
609
|
-
use:tooltip
|
|
610
|
-
>
|
|
611
|
-
<X />
|
|
612
|
-
</button>
|
|
628
|
+
tooltip={t("close")}
|
|
629
|
+
{...BUTTON_PROPS}
|
|
630
|
+
x
|
|
631
|
+
/>
|
|
613
632
|
</div>
|
|
614
633
|
</div>
|
|
615
634
|
|
|
@@ -619,7 +638,7 @@
|
|
|
619
638
|
class="absolute bottom-10 left-0 right-0 text-center"
|
|
620
639
|
transition:fade={{ duration: 100 }}
|
|
621
640
|
>
|
|
622
|
-
<span class="
|
|
641
|
+
<span class="stuic-assets-preview-label p-1">
|
|
623
642
|
{dotTooltip}
|
|
624
643
|
</span>
|
|
625
644
|
</div>
|
|
@@ -630,8 +649,8 @@
|
|
|
630
649
|
<button
|
|
631
650
|
type="button"
|
|
632
651
|
class={twMerge(
|
|
633
|
-
"
|
|
634
|
-
i === previewIdx ? "
|
|
652
|
+
"stuic-assets-preview-dot",
|
|
653
|
+
i === previewIdx ? "active" : ""
|
|
635
654
|
)}
|
|
636
655
|
onclick={() => {
|
|
637
656
|
previewIdx = i;
|
|
@@ -26,6 +26,7 @@ export interface Props {
|
|
|
26
26
|
clampPan?: boolean;
|
|
27
27
|
}
|
|
28
28
|
export declare function getAssetIcon(ext?: string): CallableFunction;
|
|
29
|
+
import "./index.css";
|
|
29
30
|
declare const AssetsPreview: import("svelte").Component<Props, {
|
|
30
31
|
open: (index?: number) => void;
|
|
31
32
|
close: () => void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
ASSETS PREVIEW COMPONENT TOKENS
|
|
3
|
+
Override globally: :root { --stuic-assets-preview-control-bg: var(--stuic-color-muted); }
|
|
4
|
+
Override locally: <AssetsPreview style="--stuic-assets-preview-control-bg: red;">
|
|
5
|
+
============================================================================ */
|
|
6
|
+
|
|
7
|
+
:root {
|
|
8
|
+
/* Control buttons (zoom, download, close, prev/next) */
|
|
9
|
+
|
|
10
|
+
/* Labels (filename, tooltip) */
|
|
11
|
+
--stuic-assets-preview-label-bg: var(--stuic-color-surface);
|
|
12
|
+
--stuic-assets-preview-label-text: var(--stuic-color-surface-foreground);
|
|
13
|
+
--stuic-assets-preview-label-radius: var(--radius-sm);
|
|
14
|
+
|
|
15
|
+
/* Dot indicators */
|
|
16
|
+
--stuic-assets-preview-dot-size: 0.75rem;
|
|
17
|
+
--stuic-assets-preview-dot-bg: color-mix(
|
|
18
|
+
in srgb,
|
|
19
|
+
var(--stuic-color-surface) 50%,
|
|
20
|
+
transparent
|
|
21
|
+
);
|
|
22
|
+
--stuic-assets-preview-dot-bg-active: var(--stuic-color-surface);
|
|
23
|
+
--stuic-assets-preview-dot-bg-hover: var(--stuic-color-surface-hover);
|
|
24
|
+
--stuic-assets-preview-dot-border: var(--stuic-color-border);
|
|
25
|
+
|
|
26
|
+
/* Transition */
|
|
27
|
+
--stuic-assets-preview-transition: 150ms;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* ============================================================================
|
|
31
|
+
LABELS (filename display, tooltip)
|
|
32
|
+
============================================================================ */
|
|
33
|
+
|
|
34
|
+
.stuic-assets-preview-label {
|
|
35
|
+
background: var(--stuic-assets-preview-label-bg);
|
|
36
|
+
color: var(--stuic-assets-preview-label-text);
|
|
37
|
+
border-radius: var(--stuic-assets-preview-label-radius);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* ============================================================================
|
|
41
|
+
DOT INDICATORS (pagination dots)
|
|
42
|
+
============================================================================ */
|
|
43
|
+
|
|
44
|
+
.stuic-assets-preview-dot {
|
|
45
|
+
width: var(--stuic-assets-preview-dot-size);
|
|
46
|
+
height: var(--stuic-assets-preview-dot-size);
|
|
47
|
+
border-radius: 9999px;
|
|
48
|
+
background: var(--stuic-assets-preview-dot-bg);
|
|
49
|
+
border: 1px solid var(--stuic-assets-preview-dot-border);
|
|
50
|
+
transition: background var(--stuic-assets-preview-transition);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.stuic-assets-preview-dot:hover {
|
|
54
|
+
background: var(--stuic-assets-preview-dot-bg-hover);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.stuic-assets-preview-dot.active {
|
|
58
|
+
background: var(--stuic-assets-preview-dot-bg-active);
|
|
59
|
+
}
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
</script>
|
|
40
40
|
|
|
41
41
|
<script lang="ts">
|
|
42
|
+
import "./index.css";
|
|
42
43
|
import { twMerge } from "../../utils/tw-merge.js";
|
|
43
44
|
import { generateAvatarColors } from "../../utils/avatar-colors.js";
|
|
44
45
|
import { iconUser as defaultIconUser } from "../../icons/index.js";
|
|
@@ -60,14 +61,19 @@
|
|
|
60
61
|
el = $bindable(),
|
|
61
62
|
}: Props = $props();
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
// Icon sizes for preset sizes (visual sizes are handled by CSS)
|
|
65
|
+
const ICON_SIZES: Record<string, number> = {
|
|
66
|
+
sm: 16,
|
|
67
|
+
md: 20,
|
|
68
|
+
lg: 28,
|
|
69
|
+
xl: 32,
|
|
70
|
+
"2xl": 36,
|
|
69
71
|
};
|
|
70
72
|
|
|
73
|
+
// Check if size is a known preset
|
|
74
|
+
const isPresetSize = (s: string): s is "sm" | "md" | "lg" | "xl" | "2xl" =>
|
|
75
|
+
s in ICON_SIZES;
|
|
76
|
+
|
|
71
77
|
// Extract initials from input string (email, name, or raw initials)
|
|
72
78
|
function extractInitials(input: string, length: number): string {
|
|
73
79
|
let _input = (input || "").trim();
|
|
@@ -145,8 +151,7 @@
|
|
|
145
151
|
|
|
146
152
|
// Get icon size based on preset or custom size
|
|
147
153
|
let iconSize = $derived.by(() => {
|
|
148
|
-
|
|
149
|
-
if (preset) return preset.icon;
|
|
154
|
+
if (isPresetSize(size)) return ICON_SIZES[size];
|
|
150
155
|
|
|
151
156
|
// For custom sizes, try to parse size-N pattern
|
|
152
157
|
const match = size?.match(/size-(\d+)/);
|
|
@@ -162,25 +167,21 @@
|
|
|
162
167
|
autoColor ? generateAvatarColors(hashSource || initialsProp || "") : null
|
|
163
168
|
);
|
|
164
169
|
|
|
165
|
-
let sizeClass = $derived(SIZE_PRESETS[size]?.container || size);
|
|
166
|
-
|
|
167
170
|
let style = $derived(
|
|
168
171
|
autoColor && colors
|
|
169
172
|
? `background-color: ${colors.bg}; color: ${colors.text};`
|
|
170
173
|
: undefined
|
|
171
174
|
);
|
|
172
175
|
|
|
176
|
+
// Build class string - base class for CSS targeting, allow user overrides via classProp
|
|
173
177
|
let baseClass = $derived(
|
|
174
178
|
twMerge(
|
|
175
179
|
"stuic-avatar",
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
"bg-neutral-200 text-neutral-700 dark:bg-neutral-700 dark:text-neutral-200",
|
|
180
|
-
sizeClass,
|
|
180
|
+
// Custom size classes when not using preset (preset sizes handled by data-size in CSS)
|
|
181
|
+
!isPresetSize(size) && size,
|
|
182
|
+
// User-provided Tailwind overrides for colors (only when not using autoColor)
|
|
181
183
|
!autoColor && bg,
|
|
182
184
|
!autoColor && textColor,
|
|
183
|
-
onclick && "select-none cursor-pointer",
|
|
184
185
|
classProp
|
|
185
186
|
)
|
|
186
187
|
);
|
|
@@ -191,7 +192,15 @@
|
|
|
191
192
|
</script>
|
|
192
193
|
|
|
193
194
|
{#if onclick}
|
|
194
|
-
<button
|
|
195
|
+
<button
|
|
196
|
+
bind:this={el}
|
|
197
|
+
type="button"
|
|
198
|
+
class={baseClass}
|
|
199
|
+
{style}
|
|
200
|
+
{onclick}
|
|
201
|
+
data-size={isPresetSize(size) ? size : undefined}
|
|
202
|
+
data-interactive="true"
|
|
203
|
+
>
|
|
195
204
|
{#if renderMode === "photo"}
|
|
196
205
|
<img {src} {alt} class="size-full object-cover" onerror={handleImageError} />
|
|
197
206
|
{:else if renderMode === "initials"}
|
|
@@ -201,7 +210,12 @@
|
|
|
201
210
|
{/if}
|
|
202
211
|
</button>
|
|
203
212
|
{:else}
|
|
204
|
-
<div
|
|
213
|
+
<div
|
|
214
|
+
bind:this={el}
|
|
215
|
+
class={baseClass}
|
|
216
|
+
{style}
|
|
217
|
+
data-size={isPresetSize(size) ? size : undefined}
|
|
218
|
+
>
|
|
205
219
|
{#if renderMode === "photo"}
|
|
206
220
|
<img {src} {alt} class="size-full object-cover" onerror={handleImageError} />
|
|
207
221
|
{:else if renderMode === "initials"}
|
|
@@ -37,6 +37,7 @@ export interface Props {
|
|
|
37
37
|
/** Bindable element reference */
|
|
38
38
|
el?: HTMLDivElement | HTMLButtonElement;
|
|
39
39
|
}
|
|
40
|
+
import "./index.css";
|
|
40
41
|
declare const Avatar: import("svelte").Component<Props, {}, "el">;
|
|
41
42
|
type Avatar = ReturnType<typeof Avatar>;
|
|
42
43
|
export default Avatar;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Avatar
|
|
2
|
+
|
|
3
|
+
A flexible avatar component that displays user photos, initials, or icons with automatic fallback handling and optional deterministic color generation.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `src` | `string` | - | Photo URL - when provided, renders in photo mode |
|
|
10
|
+
| `alt` | `string` | - | Alt text for photo mode |
|
|
11
|
+
| `initials` | `string` | - | String to extract initials from. Supports: "AB", "John Doe", or "john.doe@example.com" |
|
|
12
|
+
| `initialsLength` | `number` | `2` | Maximum length of extracted initials |
|
|
13
|
+
| `icon` | `IconFn` | - | Icon function to display - when provided alone, renders in icon mode |
|
|
14
|
+
| `fallback` | `AvatarFallback` | `"icon"` | Fallback when photo fails to load |
|
|
15
|
+
| `hashSource` | `string` | - | String for color hash calculation (e.g., email, user ID). Falls back to `initials` |
|
|
16
|
+
| `size` | `"sm" \| "md" \| "lg" \| "xl" \| "2xl" \| string` | `"md"` | Size preset or custom Tailwind size class |
|
|
17
|
+
| `onclick` | `(event: MouseEvent) => void` | - | Click handler - when provided, renders as a button |
|
|
18
|
+
| `bg` | `string` | - | Background color (Tailwind class). Ignored if `autoColor=true` |
|
|
19
|
+
| `textColor` | `string` | - | Text color (Tailwind class). Ignored if `autoColor=true` |
|
|
20
|
+
| `autoColor` | `boolean` | `false` | Generate deterministic pastel colors from hashSource/initials |
|
|
21
|
+
| `class` | `string` | - | Additional CSS classes |
|
|
22
|
+
| `el` | `HTMLElement` | - | Bindable element reference |
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Basic
|
|
27
|
+
|
|
28
|
+
```svelte
|
|
29
|
+
<script lang="ts">
|
|
30
|
+
import { Avatar } from '@marianmeres/stuic';
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<!-- Photo -->
|
|
34
|
+
<Avatar src="/path/to/photo.jpg" alt="John Doe" />
|
|
35
|
+
|
|
36
|
+
<!-- Initials -->
|
|
37
|
+
<Avatar initials="John Doe" />
|
|
38
|
+
|
|
39
|
+
<!-- Icon (default fallback) -->
|
|
40
|
+
<Avatar />
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Sizes
|
|
44
|
+
|
|
45
|
+
```svelte
|
|
46
|
+
<Avatar initials="AB" size="sm" />
|
|
47
|
+
<Avatar initials="AB" size="md" />
|
|
48
|
+
<Avatar initials="AB" size="lg" />
|
|
49
|
+
<Avatar initials="AB" size="xl" />
|
|
50
|
+
<Avatar initials="AB" size="2xl" />
|
|
51
|
+
|
|
52
|
+
<!-- Custom size with Tailwind -->
|
|
53
|
+
<Avatar initials="AB" size="size-20" />
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Auto Color
|
|
57
|
+
|
|
58
|
+
Generate deterministic pastel colors based on a hash source:
|
|
59
|
+
|
|
60
|
+
```svelte
|
|
61
|
+
<!-- Same input always produces same color -->
|
|
62
|
+
<Avatar initials="john@example.com" autoColor />
|
|
63
|
+
<Avatar initials="Jane Smith" autoColor hashSource="user-123" />
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Photo with Fallback
|
|
67
|
+
|
|
68
|
+
```svelte
|
|
69
|
+
<!-- Falls back to icon on error -->
|
|
70
|
+
<Avatar src="/maybe-broken.jpg" fallback="icon" />
|
|
71
|
+
|
|
72
|
+
<!-- Falls back to initials on error -->
|
|
73
|
+
<Avatar src="/maybe-broken.jpg" fallback="initials" initials="JD" />
|
|
74
|
+
|
|
75
|
+
<!-- Falls back to specific initials -->
|
|
76
|
+
<Avatar src="/maybe-broken.jpg" fallback={{ initials: "AB" }} />
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### As Button
|
|
80
|
+
|
|
81
|
+
```svelte
|
|
82
|
+
<Avatar
|
|
83
|
+
src="/photo.jpg"
|
|
84
|
+
onclick={() => console.log('clicked')}
|
|
85
|
+
/>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Custom Colors
|
|
89
|
+
|
|
90
|
+
```svelte
|
|
91
|
+
<!-- Using Tailwind classes -->
|
|
92
|
+
<Avatar initials="AB" bg="bg-blue-500" textColor="text-white" />
|
|
93
|
+
|
|
94
|
+
<!-- Using inline style for component tokens -->
|
|
95
|
+
<Avatar
|
|
96
|
+
initials="AB"
|
|
97
|
+
style="--stuic-avatar-bg: #3b82f6; --stuic-avatar-fg: white;"
|
|
98
|
+
/>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## CSS Variables
|
|
102
|
+
|
|
103
|
+
### Component Tokens
|
|
104
|
+
|
|
105
|
+
Override globally in `:root` or locally via `style` prop:
|
|
106
|
+
|
|
107
|
+
| Variable | Default | Description |
|
|
108
|
+
|----------|---------|-------------|
|
|
109
|
+
| `--stuic-avatar-radius` | `9999px` | Border radius (circle by default) |
|
|
110
|
+
| `--stuic-avatar-font-weight` | `--font-weight-medium` | Font weight for initials |
|
|
111
|
+
| `--stuic-avatar-transition` | `150ms` | Transition duration |
|
|
112
|
+
| `--stuic-avatar-bg` | `--stuic-color-muted` | Default background color |
|
|
113
|
+
| `--stuic-avatar-fg` | `--stuic-color-muted-foreground` | Default text/icon color |
|
|
114
|
+
| `--stuic-avatar-ring-width` | `3px` | Focus ring width (button mode) |
|
|
115
|
+
| `--stuic-avatar-ring-color` | `--stuic-color-ring` | Focus ring color |
|
|
116
|
+
|
|
117
|
+
### Size Tokens
|
|
118
|
+
|
|
119
|
+
Each size preset has corresponding tokens (font sizes use Tailwind CSS variables):
|
|
120
|
+
|
|
121
|
+
| Size | Width/Height | Font Size |
|
|
122
|
+
|------|--------------|-----------|
|
|
123
|
+
| `sm` | `--stuic-avatar-size-sm` (2rem) | `--stuic-avatar-font-size-sm` (`--text-xs`) |
|
|
124
|
+
| `md` | `--stuic-avatar-size-md` (2.5rem) | `--stuic-avatar-font-size-md` (`--text-base`) |
|
|
125
|
+
| `lg` | `--stuic-avatar-size-lg` (3rem) | `--stuic-avatar-font-size-lg` (`--text-lg`) |
|
|
126
|
+
| `xl` | `--stuic-avatar-size-xl` (3.5rem) | `--stuic-avatar-font-size-xl` (`--text-xl`) |
|
|
127
|
+
| `2xl` | `--stuic-avatar-size-2xl` (4rem) | `--stuic-avatar-font-size-2xl` (`--text-2xl`) |
|
|
128
|
+
|
|
129
|
+
### Customization Examples
|
|
130
|
+
|
|
131
|
+
```css
|
|
132
|
+
/* Global override - square avatars */
|
|
133
|
+
:root {
|
|
134
|
+
--stuic-avatar-radius: 0.5rem;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Global override - larger default size */
|
|
138
|
+
:root {
|
|
139
|
+
--stuic-avatar-size-md: 3rem;
|
|
140
|
+
--stuic-avatar-font-size-md: 1.25rem;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```svelte
|
|
145
|
+
<!-- Local override - square avatar -->
|
|
146
|
+
<Avatar initials="AB" style="--stuic-avatar-radius: 0.25rem;" />
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Data Attributes
|
|
150
|
+
|
|
151
|
+
The component uses data attributes for CSS styling:
|
|
152
|
+
|
|
153
|
+
| Attribute | Values | Description |
|
|
154
|
+
|-----------|--------|-------------|
|
|
155
|
+
| `data-size` | `sm`, `md`, `lg`, `xl`, `2xl` | Size preset (only for preset sizes) |
|
|
156
|
+
| `data-interactive` | `true` | Present when `onclick` is provided |
|
|
157
|
+
|
|
158
|
+
## Theming
|
|
159
|
+
|
|
160
|
+
The Avatar component uses theme tokens for default colors:
|
|
161
|
+
|
|
162
|
+
- Background: `--stuic-color-muted`
|
|
163
|
+
- Foreground: `--stuic-color-muted-foreground`
|
|
164
|
+
- Focus ring: `--stuic-color-ring`
|
|
165
|
+
|
|
166
|
+
These automatically adapt to light/dark mode when using the theming system.
|