@widgetic/design-system 0.5.22 → 0.5.23
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 +2 -0
- package/dist/components/CopyableHeader.svelte +260 -448
- package/dist/components/CopyableHeader.svelte.d.ts +8 -5
- package/dist/components/EmptyState.svelte +100 -128
- package/dist/components/EmptyState.svelte.d.ts +16 -19
- package/dist/components/GenerateLoader.svelte +17 -10
- package/dist/components/PasswordInput.svelte +41 -44
- package/dist/components/PasswordInput.svelte.d.ts +2 -0
- package/dist/components/ThumbHashImage.svelte +117 -119
- package/dist/components/WScrollArea.svelte +47 -41
- package/dist/components/chat/ActivityRow.svelte +115 -0
- package/dist/components/chat/ActivityRow.svelte.d.ts +18 -0
- package/dist/components/chat/ChatHeader.svelte +114 -0
- package/dist/components/chat/ChatHeader.svelte.d.ts +26 -0
- package/dist/components/chat/Composer.svelte +172 -0
- package/dist/components/chat/Composer.svelte.d.ts +27 -0
- package/dist/components/chat/Message.svelte +158 -0
- package/dist/components/chat/Message.svelte.d.ts +28 -0
- package/dist/components/chat/OptionRow.svelte +59 -0
- package/dist/components/chat/OptionRow.svelte.d.ts +14 -0
- package/dist/components/chat/PlanCard.svelte +220 -0
- package/dist/components/chat/PlanCard.svelte.d.ts +34 -0
- package/dist/components/chat/QuestionCard.svelte +265 -0
- package/dist/components/chat/QuestionCard.svelte.d.ts +38 -0
- package/dist/components/chat/ScrollToBottom.svelte +51 -0
- package/dist/components/chat/ScrollToBottom.svelte.d.ts +11 -0
- package/dist/components/chat/SuggestionCard.svelte +79 -0
- package/dist/components/chat/SuggestionCard.svelte.d.ts +20 -0
- package/dist/components/chat/TaskRow.svelte +59 -0
- package/dist/components/chat/TaskRow.svelte.d.ts +11 -0
- package/dist/components/chat/composerLogic.d.ts +16 -0
- package/dist/components/chat/composerLogic.js +29 -0
- package/dist/components/chat/index.d.ts +16 -0
- package/dist/components/chat/index.js +16 -0
- package/dist/components/chat/questionCardLogic.d.ts +11 -0
- package/dist/components/chat/questionCardLogic.js +39 -0
- package/dist/components/index.d.ts +10 -1
- package/dist/components/index.js +10 -0
- package/dist/components/modals/ActionModal.svelte +186 -180
- package/dist/components/modals/BaseModal.svelte +402 -399
- package/dist/components/modals/BaseModal.svelte.d.ts +1 -0
- package/dist/components/modals/NewItemDialog.svelte +200 -243
- package/dist/components/modals/Portal.svelte +107 -105
- package/dist/components/modals/README.md +16 -2
- package/dist/components/modals/RenameDialog.svelte +234 -292
- package/dist/components/navigation/Breadcrumbs.svelte +415 -377
- package/dist/components/navigation/Breadcrumbs.svelte.d.ts +3 -2
- package/dist/components/navigation/types.d.ts +2 -0
- package/dist/components/pdf/PDFViewer.svelte +1 -1
- package/dist/components/search-input/SearchInput.svelte +51 -104
- package/dist/components/search-input/SearchInput.svelte.d.ts +9 -27
- package/dist/components/shad-editor/editor.css +1 -1
- package/dist/components/shad-editor/i18n/messages.d.ts +1 -1
- package/dist/components/shad-editor/i18n/messages.js +1 -1
- package/dist/components/shell/AppShell.svelte +52 -0
- package/dist/components/shell/AppShell.svelte.d.ts +13 -0
- package/dist/components/shell/Banner.svelte +90 -0
- package/dist/components/shell/Banner.svelte.d.ts +61 -0
- package/dist/components/shell/ErrorState.svelte +60 -0
- package/dist/components/shell/ErrorState.svelte.d.ts +13 -0
- package/dist/components/shell/Link.svelte +63 -0
- package/dist/components/shell/Link.svelte.d.ts +53 -0
- package/dist/components/shell/NavDrawer.svelte +117 -0
- package/dist/components/shell/NavDrawer.svelte.d.ts +10 -0
- package/dist/components/shell/NavRow.svelte +128 -0
- package/dist/components/shell/NavRow.svelte.d.ts +65 -0
- package/dist/components/shell/NavSectionLabel.svelte +27 -0
- package/dist/components/shell/NavSectionLabel.svelte.d.ts +9 -0
- package/dist/components/shell/NotificationRow.svelte +76 -0
- package/dist/components/shell/NotificationRow.svelte.d.ts +16 -0
- package/dist/components/shell/PageHeader.svelte +42 -0
- package/dist/components/shell/PageHeader.svelte.d.ts +12 -0
- package/dist/components/shell/ProfileRow.svelte +95 -0
- package/dist/components/shell/ProfileRow.svelte.d.ts +54 -0
- package/dist/components/shell/SettingsDialog.svelte +118 -0
- package/dist/components/shell/SettingsDialog.svelte.d.ts +19 -0
- package/dist/components/shell/SettingsNav.svelte +46 -0
- package/dist/components/shell/SettingsNav.svelte.d.ts +11 -0
- package/dist/components/shell/Sidebar.svelte +82 -0
- package/dist/components/shell/Sidebar.svelte.d.ts +25 -0
- package/dist/components/shell/Stat.svelte +63 -0
- package/dist/components/shell/Stat.svelte.d.ts +58 -0
- package/dist/components/shell/TopBar.svelte +37 -0
- package/dist/components/shell/TopBar.svelte.d.ts +11 -0
- package/dist/components/shell/WidgetRow.svelte +126 -0
- package/dist/components/shell/WidgetRow.svelte.d.ts +78 -0
- package/dist/components/shell/error-state-messages.d.ts +7 -0
- package/dist/components/shell/error-state-messages.js +9 -0
- package/dist/components/shell/index.d.ts +22 -0
- package/dist/components/shell/index.js +25 -0
- package/dist/components/shell/link-external.d.ts +2 -0
- package/dist/components/shell/link-external.js +7 -0
- package/dist/components/shell/messages.d.ts +7 -0
- package/dist/components/shell/messages.js +5 -0
- package/dist/components/shell/settings-nav-types.d.ts +12 -0
- package/dist/components/shell/settings-nav-types.js +3 -0
- package/dist/components/shell/shell-utils.d.ts +7 -0
- package/dist/components/shell/shell-utils.js +27 -0
- package/dist/components/shell/stat-tone.d.ts +3 -0
- package/dist/components/shell/stat-tone.js +11 -0
- package/dist/components/toast/ToasterModal.svelte +102 -168
- package/dist/components/toast/ToasterModal.svelte.d.ts +2 -12
- package/dist/components/ui/accordion/accordion-content.svelte +3 -2
- package/dist/components/ui/accordion/accordion-item.svelte +10 -1
- package/dist/components/ui/accordion/accordion-trigger.svelte +4 -3
- package/dist/components/ui/alert/alert-description.svelte +5 -1
- package/dist/components/ui/alert/alert-title.svelte +2 -1
- package/dist/components/ui/alert/index.d.ts +13 -11
- package/dist/components/ui/alert/index.js +4 -4
- package/dist/components/ui/avatar/avatar-utils.d.ts +2 -0
- package/dist/components/ui/avatar/avatar-utils.js +9 -0
- package/dist/components/ui/avatar/avatar.svelte +63 -0
- package/dist/components/ui/avatar/avatar.svelte.d.ts +80 -0
- package/dist/components/ui/avatar/index.d.ts +4 -0
- package/dist/components/ui/avatar/index.js +4 -0
- package/dist/components/ui/badge/badge.svelte +22 -10
- package/dist/components/ui/badge/badge.svelte.d.ts +14 -15
- package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +2 -2
- package/dist/components/ui/breadcrumb/breadcrumb-link.svelte +1 -1
- package/dist/components/ui/breadcrumb/breadcrumb-page.svelte +1 -1
- package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte +2 -2
- package/dist/components/ui/button/button-padding.d.ts +9 -0
- package/dist/components/ui/button/button-padding.js +15 -0
- package/dist/components/ui/button/button.svelte +81 -31
- package/dist/components/ui/button/button.svelte.d.ts +48 -29
- package/dist/components/ui/calendar/calendar-cell.svelte +1 -1
- package/dist/components/ui/calendar/calendar-head-cell.svelte +1 -1
- package/dist/components/ui/calendar/calendar-next-button.svelte +2 -2
- package/dist/components/ui/calendar/calendar-prev-button.svelte +2 -2
- package/dist/components/ui/card/card-description.svelte +1 -1
- package/dist/components/ui/card/card-title.svelte +1 -1
- package/dist/components/ui/card/card.svelte +1 -1
- package/dist/components/ui/checkbox/checkbox.svelte +9 -5
- package/dist/components/ui/chip/chip.svelte +48 -0
- package/dist/components/ui/chip/chip.svelte.d.ts +13 -0
- package/dist/components/ui/chip/index.d.ts +2 -0
- package/dist/components/ui/chip/index.js +2 -0
- package/dist/components/ui/command/command-dialog.svelte +1 -1
- package/dist/components/ui/command/command-input.svelte +4 -4
- package/dist/components/ui/command/command-item.svelte +1 -1
- package/dist/components/ui/command/command.svelte +1 -1
- package/dist/components/ui/dialog/dialog-content.svelte +4 -4
- package/dist/components/ui/dialog/dialog-description.svelte +1 -1
- package/dist/components/ui/dialog/dialog-overlay.svelte +1 -1
- package/dist/components/ui/dialog/dialog-title.svelte +1 -1
- package/dist/components/ui/drawer/drawer-content.svelte +1 -1
- package/dist/components/ui/drawer/drawer-overlay.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +5 -5
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +20 -2
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte +5 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +3 -3
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte +2 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +3 -3
- package/dist/components/ui/field/field-ids.d.ts +7 -0
- package/dist/components/ui/field/field-ids.js +15 -0
- package/dist/components/ui/field/field.svelte +62 -0
- package/dist/components/ui/field/field.svelte.d.ts +21 -0
- package/dist/components/ui/field/index.d.ts +3 -0
- package/dist/components/ui/field/index.js +3 -0
- package/dist/components/ui/hover-card/hover-card-content.svelte +1 -1
- package/dist/components/ui/icon-button/icon-button.svelte +72 -0
- package/dist/components/ui/icon-button/icon-button.svelte.d.ts +90 -0
- package/dist/components/ui/icon-button/index.d.ts +2 -0
- package/dist/components/ui/icon-button/index.js +4 -0
- package/dist/components/ui/input/index.d.ts +1 -0
- package/dist/components/ui/input/input.svelte +11 -4
- package/dist/components/ui/input/input.svelte.d.ts +4 -1
- package/dist/components/ui/input-otp/input-otp-separator.svelte +2 -2
- package/dist/components/ui/input-otp/input-otp-slot.svelte +5 -4
- package/dist/components/ui/input-otp/input-otp-slot.svelte.d.ts +1 -1
- package/dist/components/ui/input-otp/input-otp.svelte +1 -1
- package/dist/components/ui/label/label.svelte +3 -2
- package/dist/components/ui/popover/popover-content.svelte +1 -1
- package/dist/components/ui/progress/progress.svelte +19 -5
- package/dist/components/ui/progress/progress.svelte.d.ts +4 -2
- package/dist/components/ui/radio-group/radio-group-item.svelte +4 -4
- package/dist/components/ui/range-calendar/range-calendar-head-cell.svelte +1 -1
- package/dist/components/ui/range-calendar/range-calendar-next-button.svelte +2 -2
- package/dist/components/ui/range-calendar/range-calendar-prev-button.svelte +2 -2
- package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte +4 -1
- package/dist/components/ui/scroll-area/scroll-area.svelte +1 -1
- package/dist/components/ui/select/select-content.svelte +1 -3
- package/dist/components/ui/select/select-item.svelte +5 -4
- package/dist/components/ui/select/select-scroll-down-button.svelte +2 -2
- package/dist/components/ui/select/select-scroll-up-button.svelte +2 -2
- package/dist/components/ui/select/select-trigger.svelte +4 -3
- package/dist/components/ui/skeleton/index.d.ts +2 -0
- package/dist/components/ui/skeleton/index.js +2 -0
- package/dist/components/ui/skeleton/skeleton.svelte +24 -0
- package/dist/components/ui/skeleton/skeleton.svelte.d.ts +8 -0
- package/dist/components/ui/slider/slider.svelte +5 -10
- package/dist/components/ui/sonner/sonner.svelte +19 -13
- package/dist/components/ui/stepper-button/index.d.ts +3 -0
- package/dist/components/ui/stepper-button/index.js +2 -0
- package/dist/components/ui/stepper-button/stepper-button.svelte +37 -0
- package/dist/components/ui/stepper-button/stepper-button.svelte.d.ts +9 -0
- package/dist/components/ui/switch/switch.svelte +8 -3
- package/dist/components/ui/table/table-cell.svelte +1 -1
- package/dist/components/ui/table/table-head.svelte +1 -1
- package/dist/components/ui/table/table-row.svelte +1 -1
- package/dist/components/ui/tabs/tabs-list.svelte +1 -1
- package/dist/components/ui/tabs/tabs-trigger.svelte +1 -1
- package/dist/components/ui/tag/index.d.ts +2 -0
- package/dist/components/ui/tag/index.js +2 -0
- package/dist/components/ui/tag/tag.svelte +42 -0
- package/dist/components/ui/tag/tag.svelte.d.ts +11 -0
- package/dist/components/ui/textarea/textarea.svelte +4 -3
- package/dist/components/ui/textarea/textarea.svelte.d.ts +2 -2
- package/dist/components/ui/toggle/toggle.svelte +9 -9
- package/dist/components/ui/toggle/toggle.svelte.d.ts +14 -21
- package/dist/components/ui/tooltip/tooltip-content.svelte +1 -1
- package/dist/fonts/Inter/Inter-Black.woff2 +0 -0
- package/dist/fonts/Inter/Inter-BlackItalic.woff2 +0 -0
- package/dist/fonts/Inter/Inter-Bold.woff2 +0 -0
- package/dist/fonts/Inter/Inter-BoldItalic.woff2 +0 -0
- package/dist/fonts/Inter/Inter-ExtraBold.woff2 +0 -0
- package/dist/fonts/Inter/Inter-ExtraBoldItalic.woff2 +0 -0
- package/dist/fonts/Inter/Inter-ExtraLight-BETA.woff2 +0 -0
- package/dist/fonts/Inter/Inter-ExtraLightItalic-BETA.woff2 +0 -0
- package/dist/fonts/Inter/Inter-Italic.woff2 +0 -0
- package/dist/fonts/Inter/Inter-Light-BETA.woff2 +0 -0
- package/dist/fonts/Inter/Inter-LightItalic-BETA.woff2 +0 -0
- package/dist/fonts/Inter/Inter-Medium.woff2 +0 -0
- package/dist/fonts/Inter/Inter-MediumItalic.woff2 +0 -0
- package/dist/fonts/Inter/Inter-Regular.woff2 +0 -0
- package/dist/fonts/Inter/Inter-SemiBold.woff2 +0 -0
- package/dist/fonts/Inter/Inter-SemiBoldItalic.woff2 +0 -0
- package/dist/fonts/Inter/Inter-Thin-BETA.woff2 +0 -0
- package/dist/fonts/Inter/Inter-ThinItalic-BETA.woff2 +0 -0
- package/dist/fonts/Inter/Inter-italic.var.woff2 +0 -0
- package/dist/fonts/Inter/Inter-upright.var.woff2 +0 -0
- package/dist/fonts/Inter/Inter.var.woff2 +0 -0
- package/dist/fonts/JetBrainsMono/JetBrainsMono-Regular.woff2 +0 -0
- package/dist/i18n/audit/designSystemWords.d.ts +1 -1
- package/dist/i18n/audit/designSystemWords.js +1 -1
- package/dist/styles/fonts.css +18 -14
- package/dist/styles/global.css +7 -19
- package/dist/styles/tokens.css +332 -0
- package/dist/utils.d.ts +27 -0
- package/dist/utils.js +33 -2
- package/package.json +2 -1
- package/tailwind.config.ts +7 -47
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { WithElementRef } from 'bits-ui';
|
|
2
|
+
import type { HTMLAnchorAttributes } from 'svelte/elements';
|
|
3
|
+
import type { VariantProps } from 'tailwind-variants';
|
|
4
|
+
export declare const linkVariants: import("tailwind-variants").TVReturnType<{
|
|
5
|
+
size: {
|
|
6
|
+
default: string;
|
|
7
|
+
small: string;
|
|
8
|
+
};
|
|
9
|
+
}, undefined, "inline-flex items-center gap-1 text-primary transition-colors duration-fast focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background hover:text-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:stroke-[1.333]", {
|
|
10
|
+
responsiveVariants?: boolean | (string | number | symbol)[] | {
|
|
11
|
+
size?: boolean | (string | number | symbol)[] | undefined;
|
|
12
|
+
} | undefined;
|
|
13
|
+
} & import("tailwind-variants/dist/config.js").TWMConfig & {
|
|
14
|
+
twMergeConfig: {
|
|
15
|
+
classGroups: {
|
|
16
|
+
"font-size": {
|
|
17
|
+
text: ("display-hero" | "heading-page" | "heading-section" | "body" | "body-medium" | "body-large" | "caption" | "caption-medium" | "label" | "label-small" | "code")[];
|
|
18
|
+
}[];
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
}, {
|
|
22
|
+
size: {
|
|
23
|
+
default: string;
|
|
24
|
+
small: string;
|
|
25
|
+
};
|
|
26
|
+
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
27
|
+
size: {
|
|
28
|
+
default: string;
|
|
29
|
+
small: string;
|
|
30
|
+
};
|
|
31
|
+
}, undefined, "inline-flex items-center gap-1 text-primary transition-colors duration-fast focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background hover:text-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:stroke-[1.333]", import("tailwind-variants/dist/config.js").TVConfig<{
|
|
32
|
+
size: {
|
|
33
|
+
default: string;
|
|
34
|
+
small: string;
|
|
35
|
+
};
|
|
36
|
+
}, {
|
|
37
|
+
size: {
|
|
38
|
+
default: string;
|
|
39
|
+
small: string;
|
|
40
|
+
};
|
|
41
|
+
}>, unknown, unknown, undefined>>;
|
|
42
|
+
export type LinkSize = VariantProps<typeof linkVariants>['size'];
|
|
43
|
+
export type LinkProps = WithElementRef<HTMLAnchorAttributes> & {
|
|
44
|
+
ref?: HTMLAnchorElement | null;
|
|
45
|
+
class?: string;
|
|
46
|
+
href: string;
|
|
47
|
+
label: string;
|
|
48
|
+
size?: LinkSize;
|
|
49
|
+
external?: boolean;
|
|
50
|
+
};
|
|
51
|
+
declare const Link: import("svelte").Component<LinkProps, {}, "ref">;
|
|
52
|
+
type Link = ReturnType<typeof Link>;
|
|
53
|
+
export default Link;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<!-- Figma: Responsive app shell — mobile/tablet nav drawer (ledger decisions.appShell). -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import { tick } from 'svelte';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
import { cn } from '../../utils.js';
|
|
6
|
+
import {
|
|
7
|
+
getFocusableElements,
|
|
8
|
+
navDrawerEffectiveTransitionMs,
|
|
9
|
+
navDrawerTabTarget,
|
|
10
|
+
navDrawerTransitionEasing
|
|
11
|
+
} from './shell-utils.js';
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
open = $bindable(false),
|
|
15
|
+
class: className,
|
|
16
|
+
onClose,
|
|
17
|
+
children
|
|
18
|
+
}: {
|
|
19
|
+
open?: boolean;
|
|
20
|
+
class?: string;
|
|
21
|
+
onClose?: () => void;
|
|
22
|
+
children?: Snippet;
|
|
23
|
+
} = $props();
|
|
24
|
+
|
|
25
|
+
let mounted = $state(false);
|
|
26
|
+
let visible = $state(false);
|
|
27
|
+
let panelRef = $state<HTMLElement | null>(null);
|
|
28
|
+
let reducedMotion = $state(false);
|
|
29
|
+
|
|
30
|
+
$effect(() => {
|
|
31
|
+
if (typeof window === 'undefined') return;
|
|
32
|
+
const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
33
|
+
const sync = () => {
|
|
34
|
+
reducedMotion = mq.matches;
|
|
35
|
+
};
|
|
36
|
+
sync();
|
|
37
|
+
mq.addEventListener('change', sync);
|
|
38
|
+
return () => mq.removeEventListener('change', sync);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const transitionMs = $derived(navDrawerEffectiveTransitionMs(visible, reducedMotion));
|
|
42
|
+
const transitionEase = $derived(navDrawerTransitionEasing(visible));
|
|
43
|
+
|
|
44
|
+
$effect(() => {
|
|
45
|
+
if (open) {
|
|
46
|
+
mounted = true;
|
|
47
|
+
void tick().then(() => {
|
|
48
|
+
visible = true;
|
|
49
|
+
void tick().then(() => {
|
|
50
|
+
if (!panelRef) return;
|
|
51
|
+
const first = getFocusableElements(panelRef)[0];
|
|
52
|
+
first?.focus();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
visible = false;
|
|
58
|
+
const closeMs = navDrawerEffectiveTransitionMs(false, reducedMotion);
|
|
59
|
+
const timer = window.setTimeout(() => {
|
|
60
|
+
mounted = false;
|
|
61
|
+
}, closeMs);
|
|
62
|
+
return () => window.clearTimeout(timer);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
function close() {
|
|
66
|
+
open = false;
|
|
67
|
+
onClose?.();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
71
|
+
if (!open || !mounted) return;
|
|
72
|
+
if (e.key === 'Escape') {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
close();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (e.key !== 'Tab' || !panelRef) return;
|
|
78
|
+
const active = document.activeElement;
|
|
79
|
+
if (!(active instanceof HTMLElement) || !panelRef.contains(active)) return;
|
|
80
|
+
const next = navDrawerTabTarget(panelRef, active, e.shiftKey);
|
|
81
|
+
if (!next) return;
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
next.focus();
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<svelte:window onkeydown={handleKeydown} />
|
|
88
|
+
|
|
89
|
+
{#if mounted}
|
|
90
|
+
<div class="fixed inset-0 z-40 lg:hidden" role="presentation">
|
|
91
|
+
<button
|
|
92
|
+
type="button"
|
|
93
|
+
class={cn(
|
|
94
|
+
'bg-foreground/50 absolute inset-0 motion-reduce:transition-none',
|
|
95
|
+
visible ? 'opacity-100' : 'opacity-0'
|
|
96
|
+
)}
|
|
97
|
+
style="transition: opacity {transitionMs}ms {transitionEase};"
|
|
98
|
+
aria-label="Close navigation"
|
|
99
|
+
tabindex={visible ? 0 : -1}
|
|
100
|
+
onclick={close}
|
|
101
|
+
></button>
|
|
102
|
+
<div
|
|
103
|
+
bind:this={panelRef}
|
|
104
|
+
class={cn(
|
|
105
|
+
'w-sidebar border-border bg-sidebar absolute inset-y-0 start-0 z-50 flex flex-col border-e shadow-none motion-reduce:transition-none',
|
|
106
|
+
visible ? 'translate-x-0' : '-translate-x-full rtl:translate-x-full',
|
|
107
|
+
className
|
|
108
|
+
)}
|
|
109
|
+
style="transition: transform {transitionMs}ms {transitionEase};"
|
|
110
|
+
role="dialog"
|
|
111
|
+
aria-modal="true"
|
|
112
|
+
aria-label="Navigation"
|
|
113
|
+
>
|
|
114
|
+
{@render children?.()}
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
{/if}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
open?: boolean;
|
|
4
|
+
class?: string;
|
|
5
|
+
onClose?: () => void;
|
|
6
|
+
children?: Snippet;
|
|
7
|
+
};
|
|
8
|
+
declare const NavDrawer: import("svelte").Component<$$ComponentProps, {}, "open">;
|
|
9
|
+
type NavDrawer = ReturnType<typeof NavDrawer>;
|
|
10
|
+
export default NavDrawer;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<!-- Figma: Nav Row (component set 39:3, node 39:3). -->
|
|
2
|
+
<script lang="ts" module>
|
|
3
|
+
import type { WithElementRef } from 'bits-ui';
|
|
4
|
+
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
|
5
|
+
|
|
6
|
+
export const navRowVariants = tv({
|
|
7
|
+
base: 'group/nav-row flex h-8 w-full min-w-0 items-center gap-2 rounded-lg py-1.5 ps-2 pe-2 text-start transition-colors duration-fast focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-sidebar-ring focus-visible:ring-offset-2 focus-visible:ring-offset-sidebar disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:stroke-[1.333]',
|
|
8
|
+
variants: {
|
|
9
|
+
active: {
|
|
10
|
+
true: 'bg-sidebar-accent text-sidebar-accent-foreground text-body-medium',
|
|
11
|
+
false: 'text-muted-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground'
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
defaultVariants: {
|
|
15
|
+
active: false
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export type NavRowVisualState = 'default' | 'hover' | 'active' | 'focus' | 'disabled';
|
|
20
|
+
|
|
21
|
+
export type NavRowProps = WithElementRef<HTMLButtonAttributes> &
|
|
22
|
+
WithElementRef<HTMLAnchorAttributes> & {
|
|
23
|
+
ref?: HTMLAnchorElement | HTMLButtonElement | null;
|
|
24
|
+
class?: string;
|
|
25
|
+
label: string;
|
|
26
|
+
href?: string;
|
|
27
|
+
active?: boolean;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
showIcon?: boolean;
|
|
30
|
+
showTrailing?: boolean;
|
|
31
|
+
trailing?: string;
|
|
32
|
+
/** Showcase-only forced visual state (CSS `:hover` / `:focus-visible` otherwise). */
|
|
33
|
+
visualState?: NavRowVisualState;
|
|
34
|
+
};
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<script lang="ts">
|
|
38
|
+
import type { Icon } from '@tabler/icons-svelte';
|
|
39
|
+
import type { Snippet } from 'svelte';
|
|
40
|
+
import { cn, tv } from '../../utils.js';
|
|
41
|
+
|
|
42
|
+
let {
|
|
43
|
+
ref = $bindable(null),
|
|
44
|
+
class: className,
|
|
45
|
+
label,
|
|
46
|
+
href = undefined,
|
|
47
|
+
active = false,
|
|
48
|
+
disabled = false,
|
|
49
|
+
showIcon = true,
|
|
50
|
+
showTrailing = false,
|
|
51
|
+
trailing = '',
|
|
52
|
+
visualState = undefined,
|
|
53
|
+
icon,
|
|
54
|
+
iconComponent = undefined,
|
|
55
|
+
children,
|
|
56
|
+
...restProps
|
|
57
|
+
}: NavRowProps & {
|
|
58
|
+
icon?: Snippet;
|
|
59
|
+
/** Tabler icon component (alternative to the `icon` snippet). */
|
|
60
|
+
iconComponent?: Icon;
|
|
61
|
+
children?: Snippet;
|
|
62
|
+
} = $props();
|
|
63
|
+
|
|
64
|
+
const hasIcon = $derived(showIcon && (Boolean(icon) || Boolean(iconComponent)));
|
|
65
|
+
|
|
66
|
+
const isActive = $derived(active || visualState === 'active');
|
|
67
|
+
const isDisabled = $derived(disabled || visualState === 'disabled');
|
|
68
|
+
|
|
69
|
+
const showcaseClass = $derived.by(() => {
|
|
70
|
+
if (!visualState || visualState === 'default' || visualState === 'active') return '';
|
|
71
|
+
if (visualState === 'hover') return 'bg-sidebar-accent text-sidebar-accent-foreground';
|
|
72
|
+
if (visualState === 'focus')
|
|
73
|
+
return 'ring-2 ring-sidebar-ring ring-offset-2 ring-offset-sidebar';
|
|
74
|
+
return '';
|
|
75
|
+
});
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
{#if href && !isDisabled}
|
|
79
|
+
<a
|
|
80
|
+
bind:this={ref}
|
|
81
|
+
{href}
|
|
82
|
+
class={cn(navRowVariants({ active: isActive }), showcaseClass, className)}
|
|
83
|
+
aria-current={isActive ? 'page' : undefined}
|
|
84
|
+
aria-disabled={isDisabled ? true : undefined}
|
|
85
|
+
{...restProps}
|
|
86
|
+
>
|
|
87
|
+
{#if hasIcon}
|
|
88
|
+
<span class="flex shrink-0 items-center justify-center text-current" aria-hidden="true">
|
|
89
|
+
{#if icon}
|
|
90
|
+
{@render icon()}
|
|
91
|
+
{:else if iconComponent}
|
|
92
|
+
{@const IconComp = iconComponent}
|
|
93
|
+
<IconComp />
|
|
94
|
+
{/if}
|
|
95
|
+
</span>
|
|
96
|
+
{/if}
|
|
97
|
+
<span class="min-w-0 flex-1 truncate">{label}</span>
|
|
98
|
+
{#if showTrailing && trailing}
|
|
99
|
+
<span class="text-caption text-muted-foreground shrink-0 tabular-nums">{trailing}</span>
|
|
100
|
+
{/if}
|
|
101
|
+
{@render children?.()}
|
|
102
|
+
</a>
|
|
103
|
+
{:else}
|
|
104
|
+
<button
|
|
105
|
+
bind:this={ref}
|
|
106
|
+
type="button"
|
|
107
|
+
class={cn(navRowVariants({ active: isActive }), showcaseClass, className)}
|
|
108
|
+
disabled={isDisabled}
|
|
109
|
+
aria-current={isActive ? 'page' : undefined}
|
|
110
|
+
{...restProps}
|
|
111
|
+
>
|
|
112
|
+
{#if hasIcon}
|
|
113
|
+
<span class="flex shrink-0 items-center justify-center text-current" aria-hidden="true">
|
|
114
|
+
{#if icon}
|
|
115
|
+
{@render icon()}
|
|
116
|
+
{:else if iconComponent}
|
|
117
|
+
{@const IconComp = iconComponent}
|
|
118
|
+
<IconComp />
|
|
119
|
+
{/if}
|
|
120
|
+
</span>
|
|
121
|
+
{/if}
|
|
122
|
+
<span class="min-w-0 flex-1 truncate">{label}</span>
|
|
123
|
+
{#if showTrailing && trailing}
|
|
124
|
+
<span class="text-caption text-muted-foreground shrink-0 tabular-nums">{trailing}</span>
|
|
125
|
+
{/if}
|
|
126
|
+
{@render children?.()}
|
|
127
|
+
</button>
|
|
128
|
+
{/if}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { WithElementRef } from 'bits-ui';
|
|
2
|
+
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
|
3
|
+
export declare const navRowVariants: import("tailwind-variants").TVReturnType<{
|
|
4
|
+
active: {
|
|
5
|
+
true: string;
|
|
6
|
+
false: string;
|
|
7
|
+
};
|
|
8
|
+
}, undefined, "group/nav-row flex h-8 w-full min-w-0 items-center gap-2 rounded-lg py-1.5 ps-2 pe-2 text-start transition-colors duration-fast focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-sidebar-ring focus-visible:ring-offset-2 focus-visible:ring-offset-sidebar disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:stroke-[1.333]", {
|
|
9
|
+
responsiveVariants?: boolean | (string | number | symbol)[] | {
|
|
10
|
+
active?: boolean | (string | number | symbol)[] | undefined;
|
|
11
|
+
} | undefined;
|
|
12
|
+
} & import("tailwind-variants/dist/config.js").TWMConfig & {
|
|
13
|
+
twMergeConfig: {
|
|
14
|
+
classGroups: {
|
|
15
|
+
"font-size": {
|
|
16
|
+
text: ("display-hero" | "heading-page" | "heading-section" | "body" | "body-medium" | "body-large" | "caption" | "caption-medium" | "label" | "label-small" | "code")[];
|
|
17
|
+
}[];
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
}, {
|
|
21
|
+
active: {
|
|
22
|
+
true: string;
|
|
23
|
+
false: string;
|
|
24
|
+
};
|
|
25
|
+
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
26
|
+
active: {
|
|
27
|
+
true: string;
|
|
28
|
+
false: string;
|
|
29
|
+
};
|
|
30
|
+
}, undefined, "group/nav-row flex h-8 w-full min-w-0 items-center gap-2 rounded-lg py-1.5 ps-2 pe-2 text-start transition-colors duration-fast focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-sidebar-ring focus-visible:ring-offset-2 focus-visible:ring-offset-sidebar disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:stroke-[1.333]", import("tailwind-variants/dist/config.js").TVConfig<{
|
|
31
|
+
active: {
|
|
32
|
+
true: string;
|
|
33
|
+
false: string;
|
|
34
|
+
};
|
|
35
|
+
}, {
|
|
36
|
+
active: {
|
|
37
|
+
true: string;
|
|
38
|
+
false: string;
|
|
39
|
+
};
|
|
40
|
+
}>, unknown, unknown, undefined>>;
|
|
41
|
+
export type NavRowVisualState = 'default' | 'hover' | 'active' | 'focus' | 'disabled';
|
|
42
|
+
export type NavRowProps = WithElementRef<HTMLButtonAttributes> & WithElementRef<HTMLAnchorAttributes> & {
|
|
43
|
+
ref?: HTMLAnchorElement | HTMLButtonElement | null;
|
|
44
|
+
class?: string;
|
|
45
|
+
label: string;
|
|
46
|
+
href?: string;
|
|
47
|
+
active?: boolean;
|
|
48
|
+
disabled?: boolean;
|
|
49
|
+
showIcon?: boolean;
|
|
50
|
+
showTrailing?: boolean;
|
|
51
|
+
trailing?: string;
|
|
52
|
+
/** Showcase-only forced visual state (CSS `:hover` / `:focus-visible` otherwise). */
|
|
53
|
+
visualState?: NavRowVisualState;
|
|
54
|
+
};
|
|
55
|
+
import type { Icon } from '@tabler/icons-svelte';
|
|
56
|
+
import type { Snippet } from 'svelte';
|
|
57
|
+
type $$ComponentProps = NavRowProps & {
|
|
58
|
+
icon?: Snippet;
|
|
59
|
+
/** Tabler icon component (alternative to the `icon` snippet). */
|
|
60
|
+
iconComponent?: Icon;
|
|
61
|
+
children?: Snippet;
|
|
62
|
+
};
|
|
63
|
+
declare const NavRow: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
64
|
+
type NavRow = ReturnType<typeof NavRow>;
|
|
65
|
+
export default NavRow;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!-- Figma: Nav Section Label (component set 39:29, node 39:29). -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { cn } from '../../utils.js';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
class: className,
|
|
8
|
+
label,
|
|
9
|
+
showTrailing = false,
|
|
10
|
+
trailing = '',
|
|
11
|
+
...restProps
|
|
12
|
+
}: HTMLAttributes<HTMLDivElement> & {
|
|
13
|
+
label: string;
|
|
14
|
+
showTrailing?: boolean;
|
|
15
|
+
trailing?: string;
|
|
16
|
+
} = $props();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<div
|
|
20
|
+
class={cn('flex h-8 w-full min-w-0 items-center gap-2 py-1 ps-3 pe-2 pb-1 text-start', className)}
|
|
21
|
+
{...restProps}
|
|
22
|
+
>
|
|
23
|
+
<span class="text-caption-medium text-muted-foreground min-w-0 flex-1 truncate">{label}</span>
|
|
24
|
+
{#if showTrailing && trailing}
|
|
25
|
+
<span class="text-caption text-muted-foreground shrink-0 tabular-nums">{trailing}</span>
|
|
26
|
+
{/if}
|
|
27
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
label: string;
|
|
4
|
+
showTrailing?: boolean;
|
|
5
|
+
trailing?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const NavSectionLabel: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type NavSectionLabel = ReturnType<typeof NavSectionLabel>;
|
|
9
|
+
export default NavSectionLabel;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Figma: Notification Row (component set 110:77, page Notification)
|
|
3
|
+
-->
|
|
4
|
+
<script lang="ts" module>
|
|
5
|
+
import type { WithElementRef } from 'bits-ui';
|
|
6
|
+
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
|
7
|
+
import type { Snippet } from 'svelte';
|
|
8
|
+
|
|
9
|
+
export type NotificationRowProps = WithElementRef<HTMLButtonAttributes> &
|
|
10
|
+
WithElementRef<HTMLAnchorAttributes> & {
|
|
11
|
+
ref?: HTMLButtonElement | HTMLAnchorElement | null;
|
|
12
|
+
class?: string;
|
|
13
|
+
title: string;
|
|
14
|
+
message: string;
|
|
15
|
+
time: string;
|
|
16
|
+
unread?: boolean;
|
|
17
|
+
icon: Snippet;
|
|
18
|
+
href?: string;
|
|
19
|
+
};
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<script lang="ts">
|
|
23
|
+
import { cn } from '../../utils.js';
|
|
24
|
+
|
|
25
|
+
let {
|
|
26
|
+
class: className,
|
|
27
|
+
ref = $bindable(null),
|
|
28
|
+
title,
|
|
29
|
+
message,
|
|
30
|
+
time,
|
|
31
|
+
unread = true,
|
|
32
|
+
icon,
|
|
33
|
+
href = undefined,
|
|
34
|
+
...restProps
|
|
35
|
+
}: NotificationRowProps = $props();
|
|
36
|
+
|
|
37
|
+
const rowClass = $derived(
|
|
38
|
+
cn(
|
|
39
|
+
'group flex w-full max-w-content items-center gap-4 rounded-xl px-4 py-3 text-start transition-colors duration-fast hover:bg-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',
|
|
40
|
+
className
|
|
41
|
+
)
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const titleClass = $derived(
|
|
45
|
+
unread ? 'text-body-medium text-foreground' : 'text-body text-foreground'
|
|
46
|
+
);
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
{#snippet rowInner()}
|
|
50
|
+
<span
|
|
51
|
+
class="bg-muted text-foreground duration-fast group-hover:bg-background flex size-10 shrink-0 items-center justify-center rounded-lg transition-colors"
|
|
52
|
+
>
|
|
53
|
+
{@render icon()}
|
|
54
|
+
</span>
|
|
55
|
+
<span class="min-w-0 flex-1">
|
|
56
|
+
<span class={cn('block truncate', titleClass)}>{title}</span>
|
|
57
|
+
<!-- A message of up to two lines, as in Figma: the one detail that matters is not cut to a single line -->
|
|
58
|
+
<span class="text-caption text-muted-foreground line-clamp-2">{message}</span>
|
|
59
|
+
</span>
|
|
60
|
+
<span class="flex shrink-0 items-center gap-2">
|
|
61
|
+
<span class="text-caption text-muted-foreground">{time}</span>
|
|
62
|
+
{#if unread}
|
|
63
|
+
<span class="bg-brand size-2 shrink-0 rounded-full" aria-hidden="true"></span>
|
|
64
|
+
{/if}
|
|
65
|
+
</span>
|
|
66
|
+
{/snippet}
|
|
67
|
+
|
|
68
|
+
{#if href}
|
|
69
|
+
<a bind:this={ref} {href} class={rowClass} {...restProps as HTMLAnchorAttributes}>
|
|
70
|
+
{@render rowInner()}
|
|
71
|
+
</a>
|
|
72
|
+
{:else}
|
|
73
|
+
<button bind:this={ref} type="button" class={rowClass} {...restProps as HTMLButtonAttributes}>
|
|
74
|
+
{@render rowInner()}
|
|
75
|
+
</button>
|
|
76
|
+
{/if}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { WithElementRef } from 'bits-ui';
|
|
2
|
+
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
export type NotificationRowProps = WithElementRef<HTMLButtonAttributes> & WithElementRef<HTMLAnchorAttributes> & {
|
|
5
|
+
ref?: HTMLButtonElement | HTMLAnchorElement | null;
|
|
6
|
+
class?: string;
|
|
7
|
+
title: string;
|
|
8
|
+
message: string;
|
|
9
|
+
time: string;
|
|
10
|
+
unread?: boolean;
|
|
11
|
+
icon: Snippet;
|
|
12
|
+
href?: string;
|
|
13
|
+
};
|
|
14
|
+
declare const NotificationRow: import("svelte").Component<NotificationRowProps, {}, "ref">;
|
|
15
|
+
type NotificationRow = ReturnType<typeof NotificationRow>;
|
|
16
|
+
export default NotificationRow;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!-- Figma: Page Header (component set 54:107, node 54:107). -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
import { cn } from '../../utils.js';
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
class: className,
|
|
9
|
+
title,
|
|
10
|
+
description = undefined,
|
|
11
|
+
showDescription = false,
|
|
12
|
+
/** When true, hides below the 1024px desktop breakpoint (title moves to Top Bar). */
|
|
13
|
+
hideBelowDesktop = true,
|
|
14
|
+
actions,
|
|
15
|
+
...restProps
|
|
16
|
+
}: HTMLAttributes<HTMLElement> & {
|
|
17
|
+
title: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
showDescription?: boolean;
|
|
20
|
+
hideBelowDesktop?: boolean;
|
|
21
|
+
actions?: Snippet;
|
|
22
|
+
} = $props();
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<header
|
|
26
|
+
class={cn(
|
|
27
|
+
'flex w-full flex-wrap items-center justify-between gap-4 ps-8 pe-8 pt-6 pb-4',
|
|
28
|
+
hideBelowDesktop && 'max-lg:hidden',
|
|
29
|
+
className
|
|
30
|
+
)}
|
|
31
|
+
{...restProps}
|
|
32
|
+
>
|
|
33
|
+
<div class="flex min-w-0 flex-col gap-0.5">
|
|
34
|
+
<h1 class="text-heading-page text-foreground truncate">{title}</h1>
|
|
35
|
+
{#if showDescription && description}
|
|
36
|
+
<p class="text-body text-muted-foreground">{description}</p>
|
|
37
|
+
{/if}
|
|
38
|
+
</div>
|
|
39
|
+
{#if actions}
|
|
40
|
+
<div class="flex shrink-0 flex-wrap items-center gap-2">{@render actions()}</div>
|
|
41
|
+
{/if}
|
|
42
|
+
</header>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
type $$ComponentProps = HTMLAttributes<HTMLElement> & {
|
|
4
|
+
title: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
showDescription?: boolean;
|
|
7
|
+
hideBelowDesktop?: boolean;
|
|
8
|
+
actions?: Snippet;
|
|
9
|
+
};
|
|
10
|
+
declare const PageHeader: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
11
|
+
type PageHeader = ReturnType<typeof PageHeader>;
|
|
12
|
+
export default PageHeader;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<!-- Figma: Profile Row (component set 53:3, node 53:3). -->
|
|
2
|
+
<script lang="ts" module>
|
|
3
|
+
export const profileRowVariants = tv({
|
|
4
|
+
base: 'flex h-12 w-full min-w-0 items-center gap-2 rounded-lg p-2 text-start transition-colors duration-fast focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-sidebar-ring focus-visible:ring-offset-2 focus-visible:ring-offset-sidebar',
|
|
5
|
+
variants: {
|
|
6
|
+
interactive: {
|
|
7
|
+
true: 'cursor-pointer hover:bg-sidebar-accent',
|
|
8
|
+
false: ''
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
defaultVariants: {
|
|
12
|
+
interactive: true
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export type ProfileRowVisualState = 'default' | 'hover' | 'focus';
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<script lang="ts">
|
|
20
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
21
|
+
import type { Snippet } from 'svelte';
|
|
22
|
+
import IconSelector from '@tabler/icons-svelte/icons/selector';
|
|
23
|
+
import { cn, tv } from '../../utils.js';
|
|
24
|
+
import { Avatar } from '../ui/avatar/index.js';
|
|
25
|
+
|
|
26
|
+
let {
|
|
27
|
+
class: className,
|
|
28
|
+
title,
|
|
29
|
+
subtitle = '',
|
|
30
|
+
showSubtitle = false,
|
|
31
|
+
showTrailingIcon = true,
|
|
32
|
+
name = '',
|
|
33
|
+
src = undefined,
|
|
34
|
+
visualState = undefined,
|
|
35
|
+
menu,
|
|
36
|
+
onclick,
|
|
37
|
+
...restProps
|
|
38
|
+
}: HTMLAttributes<HTMLElement> & {
|
|
39
|
+
title: string;
|
|
40
|
+
subtitle?: string;
|
|
41
|
+
showSubtitle?: boolean;
|
|
42
|
+
showTrailingIcon?: boolean;
|
|
43
|
+
name?: string;
|
|
44
|
+
src?: string;
|
|
45
|
+
visualState?: ProfileRowVisualState;
|
|
46
|
+
menu?: Snippet;
|
|
47
|
+
} = $props();
|
|
48
|
+
|
|
49
|
+
const showcaseClass = $derived.by(() => {
|
|
50
|
+
if (!visualState || visualState === 'default') return '';
|
|
51
|
+
if (visualState === 'hover') return 'bg-sidebar-accent';
|
|
52
|
+
if (visualState === 'focus')
|
|
53
|
+
return 'ring-2 ring-sidebar-ring ring-offset-2 ring-offset-sidebar';
|
|
54
|
+
return '';
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const asButton = $derived(Boolean(onclick || menu));
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
{#if asButton}
|
|
61
|
+
<button
|
|
62
|
+
type="button"
|
|
63
|
+
class={cn(profileRowVariants({ interactive: true }), showcaseClass, className)}
|
|
64
|
+
{onclick}
|
|
65
|
+
{...restProps}
|
|
66
|
+
>
|
|
67
|
+
<Avatar size="default" {name} {src} class="shrink-0" />
|
|
68
|
+
<span class="min-w-0 flex-1 flex-col gap-0 overflow-hidden">
|
|
69
|
+
<span class="text-body-medium text-foreground block truncate">{title}</span>
|
|
70
|
+
{#if showSubtitle && subtitle}
|
|
71
|
+
<span class="text-caption text-muted-foreground block truncate">{subtitle}</span>
|
|
72
|
+
{/if}
|
|
73
|
+
</span>
|
|
74
|
+
{#if showTrailingIcon}
|
|
75
|
+
<IconSelector class="text-muted-foreground size-4 shrink-0" aria-hidden="true" />
|
|
76
|
+
{/if}
|
|
77
|
+
{@render menu?.()}
|
|
78
|
+
</button>
|
|
79
|
+
{:else}
|
|
80
|
+
<div
|
|
81
|
+
class={cn(profileRowVariants({ interactive: false }), showcaseClass, className)}
|
|
82
|
+
{...restProps}
|
|
83
|
+
>
|
|
84
|
+
<Avatar size="default" {name} {src} class="shrink-0" />
|
|
85
|
+
<span class="min-w-0 flex-1 flex-col gap-0 overflow-hidden">
|
|
86
|
+
<span class="text-body-medium text-foreground block truncate">{title}</span>
|
|
87
|
+
{#if showSubtitle && subtitle}
|
|
88
|
+
<span class="text-caption text-muted-foreground block truncate">{subtitle}</span>
|
|
89
|
+
{/if}
|
|
90
|
+
</span>
|
|
91
|
+
{#if showTrailingIcon}
|
|
92
|
+
<IconSelector class="text-muted-foreground size-4 shrink-0" aria-hidden="true" />
|
|
93
|
+
{/if}
|
|
94
|
+
</div>
|
|
95
|
+
{/if}
|