@manafishrov/ui 1.0.5 → 1.2.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/dist/_virtual/calendar-month.js +10 -0
- package/dist/_virtual/calendar-month.js.map +1 -0
- package/dist/_virtual/check-circle.js +10 -0
- package/dist/_virtual/check-circle.js.map +1 -0
- package/dist/_virtual/check.js +10 -0
- package/dist/_virtual/check.js.map +1 -0
- package/dist/_virtual/{outline-check.js → chevron-left.js} +4 -4
- package/dist/_virtual/chevron-left.js.map +1 -0
- package/dist/_virtual/{outline-expand-more.js → chevron-right.js} +4 -4
- package/dist/_virtual/chevron-right.js.map +1 -0
- package/dist/_virtual/close.js +10 -0
- package/dist/_virtual/close.js.map +1 -0
- package/dist/_virtual/error.js +10 -0
- package/dist/_virtual/error.js.map +1 -0
- package/dist/_virtual/{outline-expand-less.js → expand-less.js} +2 -2
- package/dist/_virtual/expand-less.js.map +1 -0
- package/dist/_virtual/expand-more.js +10 -0
- package/dist/_virtual/expand-more.js.map +1 -0
- package/dist/_virtual/info.js +10 -0
- package/dist/_virtual/info.js.map +1 -0
- package/dist/_virtual/more-horiz.js +10 -0
- package/dist/_virtual/more-horiz.js.map +1 -0
- package/dist/_virtual/progress-activity.js +10 -0
- package/dist/_virtual/progress-activity.js.map +1 -0
- package/dist/_virtual/search.js +10 -0
- package/dist/_virtual/search.js.map +1 -0
- package/dist/_virtual/side-navigation.js +10 -0
- package/dist/_virtual/side-navigation.js.map +1 -0
- package/dist/_virtual/visibility-off.js +10 -0
- package/dist/_virtual/visibility-off.js.map +1 -0
- package/dist/_virtual/visibility.js +10 -0
- package/dist/_virtual/visibility.js.map +1 -0
- package/dist/_virtual/warning.js +10 -0
- package/dist/_virtual/warning.js.map +1 -0
- package/dist/components/Accordion.js +1 -1
- package/dist/components/Accordion.js.map +1 -1
- package/dist/components/Breadcrumb.js +28 -24
- package/dist/components/Breadcrumb.js.map +1 -1
- package/dist/components/Carousel.js +23 -23
- package/dist/components/Carousel.js.map +1 -1
- package/dist/components/Checkbox.js +11 -11
- package/dist/components/Checkbox.js.map +1 -1
- package/dist/components/Combobox.js +15 -15
- package/dist/components/Combobox.js.map +1 -1
- package/dist/components/DatePicker.js +21 -21
- package/dist/components/DatePicker.js.map +1 -1
- package/dist/components/Dialog.js +7 -7
- package/dist/components/Dialog.js.map +1 -1
- package/dist/components/Menu.js +5 -5
- package/dist/components/Menu.js.map +1 -1
- package/dist/components/MenuCombobox.js +29 -29
- package/dist/components/MenuCombobox.js.map +1 -1
- package/dist/components/NavigationMenu.js +5 -5
- package/dist/components/NavigationMenu.js.map +1 -1
- package/dist/components/NumberInput.js +2 -2
- package/dist/components/NumberInput.js.map +1 -1
- package/dist/components/Pagination.js +18 -18
- package/dist/components/Pagination.js.map +1 -1
- package/dist/components/PasswordInput.js +11 -11
- package/dist/components/PasswordInput.js.map +1 -1
- package/dist/components/PinInput.js +24 -24
- package/dist/components/PinInput.js.map +1 -1
- package/dist/components/Select.js +8 -8
- package/dist/components/Select.js.map +1 -1
- package/dist/components/Sheet.js +10 -10
- package/dist/components/Sheet.js.map +1 -1
- package/dist/components/Spinner.js +17 -13
- package/dist/components/Spinner.js.map +1 -1
- package/dist/components/TagsInput.js +6 -6
- package/dist/components/TagsInput.js.map +1 -1
- package/dist/components/TreeView.js +1 -1
- package/dist/components/TreeView.js.map +1 -1
- package/dist/components/sidebar/Sidebar.d.ts +2 -1
- package/dist/components/sidebar/Sidebar.js +25 -18
- package/dist/components/sidebar/Sidebar.js.map +1 -1
- package/dist/components/sidebar/SidebarDesktop.js +39 -27
- package/dist/components/sidebar/SidebarDesktop.js.map +1 -1
- package/dist/components/sidebar/SidebarMenu.d.ts +5 -1
- package/dist/components/sidebar/SidebarMenu.js +96 -89
- package/dist/components/sidebar/SidebarMenu.js.map +1 -1
- package/dist/components/sidebar/SidebarMobile.js +30 -31
- package/dist/components/sidebar/SidebarMobile.js.map +1 -1
- package/dist/components/sidebar/SidebarProvider.d.ts +5 -2
- package/dist/components/sidebar/SidebarProvider.js +46 -50
- package/dist/components/sidebar/SidebarProvider.js.map +1 -1
- package/dist/components/sidebar/SidebarSubComponents.js +79 -64
- package/dist/components/sidebar/SidebarSubComponents.js.map +1 -1
- package/dist/components/sidebar/context.d.ts +1 -0
- package/dist/components/sidebar/context.js.map +1 -1
- package/dist/components/sidebar/index.js +23 -22
- package/dist/components/toaster/Toaster.js +11 -11
- package/dist/components/toaster/Toaster.js.map +1 -1
- package/dist/paraglide/messages/ui_breadcrumb_label.js +21 -0
- package/dist/paraglide/messages/ui_breadcrumb_label.js.map +1 -0
- package/dist/theme.css +1 -1
- package/package.json +3 -3
- package/src/components/Accordion.tsx +2 -2
- package/src/components/Breadcrumb.tsx +12 -5
- package/src/components/Carousel.tsx +4 -4
- package/src/components/Checkbox.tsx +2 -2
- package/src/components/Combobox.tsx +8 -8
- package/src/components/DatePicker.tsx +6 -6
- package/src/components/Dialog.tsx +2 -2
- package/src/components/Menu.tsx +8 -8
- package/src/components/MenuCombobox.tsx +7 -7
- package/src/components/NavigationMenu.tsx +6 -6
- package/src/components/NumberInput.tsx +4 -4
- package/src/components/Pagination.tsx +6 -6
- package/src/components/PasswordInput.tsx +4 -4
- package/src/components/PinInput.tsx +3 -3
- package/src/components/Select.tsx +6 -6
- package/src/components/Sheet.tsx +6 -6
- package/src/components/Spinner.tsx +2 -9
- package/src/components/TagsInput.tsx +9 -9
- package/src/components/TreeView.tsx +2 -2
- package/src/components/sidebar/Sidebar.tsx +20 -4
- package/src/components/sidebar/SidebarDesktop.tsx +47 -19
- package/src/components/sidebar/SidebarMenu.tsx +64 -17
- package/src/components/sidebar/SidebarMobile.tsx +6 -2
- package/src/components/sidebar/SidebarProvider.tsx +36 -35
- package/src/components/sidebar/SidebarSubComponents.tsx +19 -9
- package/src/components/sidebar/context.ts +1 -0
- package/src/components/toaster/Toaster.tsx +12 -12
- package/src/theme.css +9 -6
- package/dist/_virtual/outline-calendar-month.js +0 -10
- package/dist/_virtual/outline-calendar-month.js.map +0 -1
- package/dist/_virtual/outline-check-circle.js +0 -10
- package/dist/_virtual/outline-check-circle.js.map +0 -1
- package/dist/_virtual/outline-check.js.map +0 -1
- package/dist/_virtual/outline-chevron-left.js +0 -10
- package/dist/_virtual/outline-chevron-left.js.map +0 -1
- package/dist/_virtual/outline-chevron-right.js +0 -10
- package/dist/_virtual/outline-chevron-right.js.map +0 -1
- package/dist/_virtual/outline-close.js +0 -10
- package/dist/_virtual/outline-close.js.map +0 -1
- package/dist/_virtual/outline-error.js +0 -10
- package/dist/_virtual/outline-error.js.map +0 -1
- package/dist/_virtual/outline-expand-less.js.map +0 -1
- package/dist/_virtual/outline-expand-more.js.map +0 -1
- package/dist/_virtual/outline-info.js +0 -10
- package/dist/_virtual/outline-info.js.map +0 -1
- package/dist/_virtual/outline-more-horiz.js +0 -10
- package/dist/_virtual/outline-more-horiz.js.map +0 -1
- package/dist/_virtual/outline-remove.js +0 -10
- package/dist/_virtual/outline-remove.js.map +0 -1
- package/dist/_virtual/outline-search.js +0 -10
- package/dist/_virtual/outline-search.js.map +0 -1
- package/dist/_virtual/outline-view-sidebar.js +0 -10
- package/dist/_virtual/outline-view-sidebar.js.map +0 -1
- package/dist/_virtual/outline-visibility-off.js +0 -10
- package/dist/_virtual/outline-visibility-off.js.map +0 -1
- package/dist/_virtual/outline-visibility.js +0 -10
- package/dist/_virtual/outline-visibility.js.map +0 -1
- package/dist/_virtual/outline-warning.js +0 -10
- package/dist/_virtual/outline-warning.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TagsInput as TagsInputPrimitive } from '@ark-ui/solid/tags-input';
|
|
2
2
|
import { type Component, splitProps } from 'solid-js';
|
|
3
3
|
import { cn } from 'tailwind-variants';
|
|
4
|
-
import
|
|
4
|
+
import CloseIcon from '~icons/material-symbols/close';
|
|
5
5
|
|
|
6
6
|
export const TagsInput = TagsInputPrimitive.Root;
|
|
7
7
|
export const TagsInputContext = TagsInputPrimitive.Context;
|
|
@@ -23,7 +23,7 @@ export const TagsInputControl: Component<TagsInputPrimitive.ControlProps> = (pro
|
|
|
23
23
|
return (
|
|
24
24
|
<TagsInputPrimitive.Control
|
|
25
25
|
class={cn(
|
|
26
|
-
'group
|
|
26
|
+
'group min-h-10 py-1.5 pr-8 pl-2.5 text-sm [&_svg:not([class*="size-"])]:size-4 gap-1 shadow-sm relative flex w-full flex-wrap items-center rounded-lg border border-input bg-transparent transition-colors outline-none disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input/30 dark:hover:bg-input/50 [&_svg]:pointer-events-none [&_svg]:shrink-0',
|
|
27
27
|
'focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50',
|
|
28
28
|
'data-[invalid=true]:border-destructive data-[invalid=true]:ring-[3px] data-[invalid=true]:ring-destructive/20 dark:data-[invalid=true]:ring-destructive/40',
|
|
29
29
|
'data-[disabled=true]:bg-input/50 data-[disabled=true]:opacity-50 dark:data-[disabled=true]:bg-input/80',
|
|
@@ -57,12 +57,12 @@ export const TagsInputClearTrigger: Component<TagsInputPrimitive.ClearTriggerPro
|
|
|
57
57
|
return (
|
|
58
58
|
<TagsInputPrimitive.ClearTrigger
|
|
59
59
|
class={cn(
|
|
60
|
-
'right-2
|
|
60
|
+
'right-2 p-0.5 absolute top-1/2 -translate-y-1/2 rounded-sm text-muted-foreground transition-colors hover:text-foreground',
|
|
61
61
|
local.class,
|
|
62
62
|
)}
|
|
63
63
|
{...others}
|
|
64
64
|
>
|
|
65
|
-
{local.children ?? <
|
|
65
|
+
{local.children ?? <CloseIcon class='size-3.5 pointer-events-none' />}
|
|
66
66
|
</TagsInputPrimitive.ClearTrigger>
|
|
67
67
|
);
|
|
68
68
|
};
|
|
@@ -71,7 +71,7 @@ export const TagsInputItem: Component<TagsInputPrimitive.ItemProps> = (props) =>
|
|
|
71
71
|
const [local, others] = splitProps(props, ['class', 'children']);
|
|
72
72
|
return (
|
|
73
73
|
<TagsInputPrimitive.Item
|
|
74
|
-
class={cn('inline-flex items-center outline-none
|
|
74
|
+
class={cn('inline-flex cursor-default items-center outline-none', local.class)}
|
|
75
75
|
{...others}
|
|
76
76
|
>
|
|
77
77
|
{local.children}
|
|
@@ -85,8 +85,8 @@ export const TagsInputItemPreview: Component<TagsInputPrimitive.ItemPreviewProps
|
|
|
85
85
|
<TagsInputPrimitive.ItemPreview
|
|
86
86
|
data-slot='tags-input-item-preview'
|
|
87
87
|
class={cn(
|
|
88
|
-
'h-6 gap-1 px-1.5 text-xs font-medium
|
|
89
|
-
'data-highlighted:
|
|
88
|
+
'h-6 gap-1 px-1.5 text-xs font-medium has-data-[slot=tags-input-item-delete-trigger]:pr-0 inline-flex items-center justify-center rounded-md border border-transparent bg-muted whitespace-nowrap text-foreground transition-colors',
|
|
89
|
+
'data-highlighted:border-ring data-highlighted:bg-accent data-highlighted:text-accent-foreground',
|
|
90
90
|
'data-disabled:pointer-events-none data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50',
|
|
91
91
|
local.class,
|
|
92
92
|
)}
|
|
@@ -106,7 +106,7 @@ export const TagsInputItemInput: Component<TagsInputPrimitive.ItemInputProps> =
|
|
|
106
106
|
<TagsInputPrimitive.ItemInput
|
|
107
107
|
class={cn(
|
|
108
108
|
'py-0 px-1.5 h-6 text-xs rounded-md border border-input bg-background text-foreground outline-none',
|
|
109
|
-
'focus-visible:ring-[3px] focus-visible:ring-ring/50
|
|
109
|
+
'focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50',
|
|
110
110
|
local.class,
|
|
111
111
|
)}
|
|
112
112
|
{...others}
|
|
@@ -127,7 +127,7 @@ export const TagsInputItemDeleteTrigger: Component<TagsInputPrimitive.ItemDelete
|
|
|
127
127
|
)}
|
|
128
128
|
{...others}
|
|
129
129
|
>
|
|
130
|
-
{local.children ?? <
|
|
130
|
+
{local.children ?? <CloseIcon class='size-3 pointer-events-none' />}
|
|
131
131
|
</TagsInputPrimitive.ItemDeleteTrigger>
|
|
132
132
|
);
|
|
133
133
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TreeView as TreeViewPrimitive, createTreeCollection } from '@ark-ui/solid/tree-view';
|
|
2
2
|
import { Show, splitProps, type Component } from 'solid-js';
|
|
3
3
|
import { cn } from 'tailwind-variants';
|
|
4
|
-
import
|
|
4
|
+
import ChevronRightIcon from '~icons/material-symbols/chevron-right';
|
|
5
5
|
|
|
6
6
|
export const TreeView = TreeViewPrimitive.Root;
|
|
7
7
|
export const TreeViewLabel = TreeViewPrimitive.Label;
|
|
@@ -46,7 +46,7 @@ export const TreeViewBranchControl: Component<TreeViewPrimitive.BranchControlPro
|
|
|
46
46
|
{...others}
|
|
47
47
|
>
|
|
48
48
|
<TreeViewPrimitive.BranchIndicator class='text-muted-foreground transition-transform data-[state=open]:rotate-90'>
|
|
49
|
-
<
|
|
49
|
+
<ChevronRightIcon class='size-4' />
|
|
50
50
|
</TreeViewPrimitive.BranchIndicator>
|
|
51
51
|
<Show when={local.children} fallback={<TreeViewPrimitive.BranchText />}>
|
|
52
52
|
{local.children}
|
|
@@ -1,23 +1,39 @@
|
|
|
1
|
-
import { type Component, type ComponentProps, createEffect } from 'solid-js';
|
|
1
|
+
import { type Component, type ComponentProps, createEffect, onCleanup } from 'solid-js';
|
|
2
|
+
|
|
3
|
+
import { createMediaQuery } from '@/primitives/createMediaQuery';
|
|
2
4
|
|
|
3
5
|
import { useSidebar } from './context';
|
|
4
6
|
import { SidebarDesktop } from './SidebarDesktop';
|
|
5
7
|
import { SidebarMobile } from './SidebarMobile';
|
|
6
8
|
|
|
7
|
-
export type SidebarProps = ComponentProps<'
|
|
9
|
+
export type SidebarProps = ComponentProps<'aside'> & {
|
|
8
10
|
side?: 'left' | 'right';
|
|
9
11
|
variant?: 'sidebar' | 'floating' | 'inset';
|
|
10
12
|
collapsible?: 'offcanvas' | 'icon' | 'none';
|
|
13
|
+
disableMobileSidebar?: boolean;
|
|
11
14
|
};
|
|
12
15
|
|
|
13
16
|
export const Sidebar: Component<SidebarProps> = (props) => {
|
|
14
|
-
const { isMobile, setSide } = useSidebar();
|
|
17
|
+
const { isMobile, setMobileDisabled, setOpen, setSide } = useSidebar();
|
|
18
|
+
const isViewportMobile = createMediaQuery('(max-width: 768px)');
|
|
19
|
+
|
|
20
|
+
onCleanup(() => {
|
|
21
|
+
setMobileDisabled(false);
|
|
22
|
+
});
|
|
15
23
|
|
|
16
|
-
// Set side on initial render and track changes
|
|
17
24
|
createEffect(() => {
|
|
18
25
|
const currentSide = props.side ?? 'left';
|
|
26
|
+
const mobileDisabled = props.disableMobileSidebar ?? false;
|
|
19
27
|
setSide(currentSide);
|
|
28
|
+
setMobileDisabled(mobileDisabled);
|
|
20
29
|
});
|
|
30
|
+
|
|
31
|
+
createEffect(() => {
|
|
32
|
+
if (props.disableMobileSidebar === true && props.collapsible === 'icon') {
|
|
33
|
+
setOpen(!isViewportMobile());
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
21
37
|
return (
|
|
22
38
|
<Show
|
|
23
39
|
when={!isMobile()}
|
|
@@ -1,24 +1,57 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
createMemo,
|
|
3
|
+
type Component,
|
|
4
|
+
type ComponentProps,
|
|
5
|
+
type JSX,
|
|
6
|
+
type JSXElement,
|
|
7
|
+
} from 'solid-js';
|
|
3
8
|
import { cn } from 'tailwind-variants';
|
|
4
9
|
|
|
5
10
|
import type { SidebarProps } from './Sidebar';
|
|
6
11
|
|
|
12
|
+
import { SIDEBAR_WIDTH, SIDEBAR_WIDTH_ICON } from './constants';
|
|
7
13
|
import { useSidebar } from './context';
|
|
8
14
|
|
|
9
|
-
type SidebarDesktopContainerProps = ComponentProps<'
|
|
15
|
+
type SidebarDesktopContainerProps = ComponentProps<'aside'> & {
|
|
10
16
|
variant: string;
|
|
11
17
|
side: string;
|
|
12
18
|
children: JSXElement;
|
|
13
19
|
};
|
|
14
20
|
|
|
21
|
+
const getSidebarDesktopRootClass = (
|
|
22
|
+
disableMobileSidebar: boolean | undefined,
|
|
23
|
+
): ComponentProps<'div'>['class'] =>
|
|
24
|
+
cn(
|
|
25
|
+
disableMobileSidebar === true
|
|
26
|
+
? 'group peer min-h-0 relative block self-stretch text-sidebar-foreground'
|
|
27
|
+
: 'group peer md:block min-h-0 relative hidden self-stretch text-sidebar-foreground',
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const getSidebarGapClass = (variant: SidebarProps['variant']): ComponentProps<'div'>['class'] =>
|
|
31
|
+
cn(
|
|
32
|
+
'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',
|
|
33
|
+
'group-data-[collapsible=offcanvas]:w-0',
|
|
34
|
+
'group-data-[side=right]:rotate-180',
|
|
35
|
+
variant === 'floating' || variant === 'inset'
|
|
36
|
+
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem)]'
|
|
37
|
+
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const getSidebarStyle = (style: SidebarProps['style']): JSX.CSSProperties => {
|
|
41
|
+
const base: JSX.CSSProperties = {
|
|
42
|
+
'--sidebar-width': SIDEBAR_WIDTH,
|
|
43
|
+
'--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
|
|
44
|
+
};
|
|
45
|
+
return typeof style === 'object' && style !== null ? { ...base, ...style } : base;
|
|
46
|
+
};
|
|
47
|
+
|
|
15
48
|
const SidebarDesktopContainer: Component<SidebarDesktopContainerProps> = (props) => {
|
|
16
49
|
const [local, others] = splitProps(props, ['variant', 'side', 'class', 'children']);
|
|
17
50
|
return (
|
|
18
|
-
<
|
|
51
|
+
<aside
|
|
19
52
|
data-slot='sidebar-container'
|
|
20
53
|
class={cn(
|
|
21
|
-
'
|
|
54
|
+
'top-0 bottom-0 md:flex absolute z-10 hidden w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear',
|
|
22
55
|
local.side === 'left'
|
|
23
56
|
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
|
|
24
57
|
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
|
|
@@ -36,7 +69,7 @@ const SidebarDesktopContainer: Component<SidebarDesktopContainerProps> = (props)
|
|
|
36
69
|
>
|
|
37
70
|
{local.children}
|
|
38
71
|
</div>
|
|
39
|
-
</
|
|
72
|
+
</aside>
|
|
40
73
|
);
|
|
41
74
|
};
|
|
42
75
|
|
|
@@ -46,34 +79,29 @@ export const SidebarDesktop: Component<SidebarProps> = (props) => {
|
|
|
46
79
|
'side',
|
|
47
80
|
'variant',
|
|
48
81
|
'collapsible',
|
|
82
|
+
'disableMobileSidebar',
|
|
83
|
+
'style',
|
|
49
84
|
'class',
|
|
50
85
|
'children',
|
|
51
86
|
]);
|
|
52
87
|
|
|
88
|
+
const style = createMemo(() => getSidebarStyle(local.style));
|
|
89
|
+
|
|
53
90
|
return (
|
|
54
91
|
<div
|
|
55
|
-
|
|
92
|
+
style={style()}
|
|
93
|
+
class={getSidebarDesktopRootClass(local.disableMobileSidebar)}
|
|
56
94
|
data-state={state()}
|
|
57
95
|
data-collapsible={state() === 'collapsed' ? (local.collapsible ?? 'offcanvas') : ''}
|
|
58
96
|
data-variant={local.variant ?? 'sidebar'}
|
|
59
97
|
data-side={local.side ?? 'left'}
|
|
60
98
|
data-slot='sidebar'
|
|
61
99
|
>
|
|
62
|
-
<div
|
|
63
|
-
data-slot='sidebar-gap'
|
|
64
|
-
class={cn(
|
|
65
|
-
'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',
|
|
66
|
-
'group-data-[collapsible=offcanvas]:w-0',
|
|
67
|
-
'group-data-[side=right]:rotate-180',
|
|
68
|
-
local.variant === 'floating' || local.variant === 'inset'
|
|
69
|
-
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem)]'
|
|
70
|
-
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
|
|
71
|
-
)}
|
|
72
|
-
/>
|
|
100
|
+
<div data-slot='sidebar-gap' class={getSidebarGapClass(local.variant)} />
|
|
73
101
|
<SidebarDesktopContainer
|
|
74
102
|
variant={local.variant ?? 'sidebar'}
|
|
75
103
|
side={local.side ?? 'left'}
|
|
76
|
-
class={local.class}
|
|
104
|
+
class={cn(local.disableMobileSidebar === true ? 'flex' : 'md:flex hidden', local.class)}
|
|
77
105
|
{...others}
|
|
78
106
|
>
|
|
79
107
|
{local.children}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ark } from '@ark-ui/solid/factory';
|
|
2
|
+
import { createMemo, type Component, type ComponentProps, type JSX } from 'solid-js';
|
|
2
3
|
import { type VariantProps, tv, cn } from 'tailwind-variants';
|
|
3
4
|
|
|
4
5
|
import { Skeleton } from '@/components/Skeleton';
|
|
@@ -57,12 +58,20 @@ export const sidebarMenuButtonVariants = tv({
|
|
|
57
58
|
},
|
|
58
59
|
});
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
type SidebarMenuButtonAsChild = ComponentProps<typeof ark.button>['asChild'];
|
|
62
|
+
|
|
63
|
+
export type SidebarMenuButtonProps = Omit<ComponentProps<'button'>, 'asChild'> &
|
|
61
64
|
VariantProps<typeof sidebarMenuButtonVariants> & {
|
|
65
|
+
asChild?: SidebarMenuButtonAsChild;
|
|
62
66
|
isActive?: boolean;
|
|
63
67
|
tooltip?: string | ComponentProps<typeof TooltipContent>;
|
|
64
68
|
};
|
|
65
69
|
|
|
70
|
+
type SidebarMenuButtonStyleProps = Pick<
|
|
71
|
+
SidebarMenuButtonProps,
|
|
72
|
+
'size' | 'isActive' | 'variant' | 'class'
|
|
73
|
+
>;
|
|
74
|
+
|
|
66
75
|
type SidebarMenuButtonDataProps = {
|
|
67
76
|
'data-slot': 'sidebar-menu-button';
|
|
68
77
|
'data-sidebar': 'menu-button';
|
|
@@ -88,32 +97,70 @@ const getTooltipChildren = (
|
|
|
88
97
|
return tooltip.children;
|
|
89
98
|
};
|
|
90
99
|
|
|
100
|
+
const getSidebarMenuButtonDataProps = (
|
|
101
|
+
local: SidebarMenuButtonStyleProps,
|
|
102
|
+
): SidebarMenuButtonDataProps => ({
|
|
103
|
+
'data-slot': 'sidebar-menu-button',
|
|
104
|
+
'data-sidebar': 'menu-button',
|
|
105
|
+
'data-size': local.size ?? 'default',
|
|
106
|
+
'data-active': local.isActive,
|
|
107
|
+
class: sidebarMenuButtonVariants({
|
|
108
|
+
variant: local.variant,
|
|
109
|
+
size: local.size,
|
|
110
|
+
class: local.class,
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const getSidebarMenuButtonAsChildProps = (
|
|
115
|
+
asChild: SidebarMenuButtonProps['asChild'],
|
|
116
|
+
): Pick<ComponentProps<typeof ark.button>, 'asChild'> => (asChild ? { asChild } : {});
|
|
117
|
+
|
|
118
|
+
const renderSidebarMenuButton = (
|
|
119
|
+
asChild: SidebarMenuButtonProps['asChild'],
|
|
120
|
+
props: ComponentProps<'button'>,
|
|
121
|
+
children: SidebarMenuButtonProps['children'],
|
|
122
|
+
): JSX.Element => (
|
|
123
|
+
<ark.button {...props} {...getSidebarMenuButtonAsChildProps(asChild)}>
|
|
124
|
+
{children}
|
|
125
|
+
</ark.button>
|
|
126
|
+
);
|
|
127
|
+
|
|
91
128
|
export const SidebarMenuButton: Component<SidebarMenuButtonProps> = (props) => {
|
|
92
|
-
const [local, others] = splitProps(props, [
|
|
129
|
+
const [local, others] = splitProps(props, [
|
|
130
|
+
'asChild',
|
|
131
|
+
'children',
|
|
132
|
+
'isActive',
|
|
133
|
+
'variant',
|
|
134
|
+
'size',
|
|
135
|
+
'tooltip',
|
|
136
|
+
'class',
|
|
137
|
+
]);
|
|
93
138
|
const { isMobile, state, side } = useSidebar();
|
|
94
139
|
|
|
95
140
|
const tooltipPlacement = createMemo(() => (side() === 'left' ? 'right' : 'left'));
|
|
96
|
-
|
|
97
|
-
const buttonProps = (): SidebarMenuButtonDataProps => ({
|
|
98
|
-
'data-slot': 'sidebar-menu-button',
|
|
99
|
-
'data-sidebar': 'menu-button',
|
|
100
|
-
'data-size': local.size ?? 'default',
|
|
101
|
-
'data-active': local.isActive,
|
|
102
|
-
class: sidebarMenuButtonVariants({
|
|
103
|
-
variant: local.variant,
|
|
104
|
-
size: local.size,
|
|
105
|
-
class: local.class,
|
|
106
|
-
}),
|
|
107
|
-
});
|
|
141
|
+
const buttonDataProps = createMemo(() => getSidebarMenuButtonDataProps(local));
|
|
108
142
|
|
|
109
143
|
return (
|
|
110
|
-
<Show
|
|
144
|
+
<Show
|
|
145
|
+
when={local.tooltip}
|
|
146
|
+
fallback={renderSidebarMenuButton(
|
|
147
|
+
local.asChild,
|
|
148
|
+
{ ...buttonDataProps(), ...others },
|
|
149
|
+
local.children,
|
|
150
|
+
)}
|
|
151
|
+
>
|
|
111
152
|
<Tooltip
|
|
112
153
|
positioning={{ placement: tooltipPlacement() }}
|
|
113
154
|
openDelay={100}
|
|
114
155
|
disabled={state() !== 'collapsed' || isMobile()}
|
|
115
156
|
>
|
|
116
|
-
<TooltipTrigger
|
|
157
|
+
<TooltipTrigger
|
|
158
|
+
{...buttonDataProps()}
|
|
159
|
+
{...others}
|
|
160
|
+
asChild={(triggerProps) =>
|
|
161
|
+
renderSidebarMenuButton(local.asChild, triggerProps(), local.children)
|
|
162
|
+
}
|
|
163
|
+
/>
|
|
117
164
|
<Portal>
|
|
118
165
|
<TooltipPositioner>
|
|
119
166
|
<TooltipContent {...getTooltipContentProps(local.tooltip)}>
|
|
@@ -2,6 +2,7 @@ import type { Component } from 'solid-js';
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
Sheet,
|
|
5
|
+
SheetCloseButton,
|
|
5
6
|
SheetContent,
|
|
6
7
|
SheetDescription,
|
|
7
8
|
SheetHeader,
|
|
@@ -18,6 +19,7 @@ import { useSidebar } from './context';
|
|
|
18
19
|
export const SidebarMobile: Component<SidebarProps> = (props) => {
|
|
19
20
|
const [local] = splitProps(props, ['side', 'children']);
|
|
20
21
|
const { openMobile, setOpenMobile } = useSidebar();
|
|
22
|
+
const side = local.side ?? 'left';
|
|
21
23
|
|
|
22
24
|
return (
|
|
23
25
|
<Sheet
|
|
@@ -26,16 +28,18 @@ export const SidebarMobile: Component<SidebarProps> = (props) => {
|
|
|
26
28
|
setOpenMobile(event.open);
|
|
27
29
|
}}
|
|
28
30
|
>
|
|
29
|
-
<SheetPositioner side={
|
|
31
|
+
<SheetPositioner side={side}>
|
|
30
32
|
<SheetContent
|
|
33
|
+
side={side}
|
|
31
34
|
data-sidebar='sidebar'
|
|
32
35
|
data-slot='sidebar'
|
|
33
36
|
data-mobile='true'
|
|
34
|
-
class='p-0 w-(--sidebar-width) bg-sidebar text-sidebar-foreground
|
|
37
|
+
class='p-0 w-(--sidebar-width) bg-sidebar text-sidebar-foreground'
|
|
35
38
|
style={{
|
|
36
39
|
'--sidebar-width': SIDEBAR_WIDTH_MOBILE,
|
|
37
40
|
}}
|
|
38
41
|
>
|
|
42
|
+
<SheetCloseButton />
|
|
39
43
|
<div class='sr-only'>
|
|
40
44
|
<SheetHeader>
|
|
41
45
|
<SheetTitle>{messages.ui_sidebar_title()}</SheetTitle>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type Component,
|
|
3
3
|
type ComponentProps,
|
|
4
|
-
createMemo,
|
|
5
4
|
createSignal,
|
|
6
5
|
onCleanup,
|
|
7
6
|
onMount,
|
|
@@ -12,20 +11,38 @@ import { cn } from 'tailwind-variants';
|
|
|
12
11
|
|
|
13
12
|
import { createMediaQuery } from '@/primitives/createMediaQuery';
|
|
14
13
|
|
|
15
|
-
import { SIDEBAR_KEYBOARD_SHORTCUT
|
|
14
|
+
import { SIDEBAR_KEYBOARD_SHORTCUT } from './constants';
|
|
16
15
|
import { SidebarContext, type SidebarContextProps } from './context';
|
|
17
16
|
import { setSidebarCookie } from './utils';
|
|
18
17
|
|
|
19
|
-
export type SidebarProviderProps =
|
|
18
|
+
export type SidebarProviderProps = {
|
|
20
19
|
defaultOpen?: boolean;
|
|
21
20
|
open?: boolean;
|
|
22
21
|
onOpenChange?: (openValue: boolean) => void;
|
|
22
|
+
children?: JSX.Element;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type SidebarLayoutProps = ComponentProps<'div'>;
|
|
26
|
+
|
|
27
|
+
export const SidebarLayout: Component<SidebarLayoutProps> = (props) => {
|
|
28
|
+
const [local, others] = splitProps(props, ['class']);
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
data-slot='sidebar-wrapper'
|
|
32
|
+
class={cn(
|
|
33
|
+
'relative flex h-full min-h-full w-full has-data-[variant=inset]:bg-sidebar',
|
|
34
|
+
local.class,
|
|
35
|
+
)}
|
|
36
|
+
{...others}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
23
39
|
};
|
|
24
40
|
|
|
25
41
|
const useSidebarState = (
|
|
26
42
|
props: SidebarProviderProps,
|
|
27
43
|
): {
|
|
28
44
|
isMobile: () => boolean;
|
|
45
|
+
setMobileDisabled: (value: boolean) => void;
|
|
29
46
|
openMobile: () => boolean;
|
|
30
47
|
setOpenMobile: (value: boolean | ((prev: boolean) => boolean)) => void;
|
|
31
48
|
open: () => boolean;
|
|
@@ -33,7 +50,9 @@ const useSidebarState = (
|
|
|
33
50
|
side: () => 'left' | 'right';
|
|
34
51
|
setSide: (value: 'left' | 'right') => void;
|
|
35
52
|
} => {
|
|
36
|
-
const
|
|
53
|
+
const isViewportMobile = createMediaQuery('(max-width: 768px)');
|
|
54
|
+
const [mobileDisabled, setMobileDisabled] = createSignal(false);
|
|
55
|
+
const isMobile = (): boolean => isViewportMobile() && !mobileDisabled();
|
|
37
56
|
const [openMobile, setOpenMobile] = createSignal(false);
|
|
38
57
|
const [internalOpen, setInternalOpen] = createSignal(props.defaultOpen ?? true);
|
|
39
58
|
const [side, setSide] = createSignal<'left' | 'right'>('left');
|
|
@@ -49,7 +68,16 @@ const useSidebarState = (
|
|
|
49
68
|
setSidebarCookie(value);
|
|
50
69
|
};
|
|
51
70
|
|
|
52
|
-
return {
|
|
71
|
+
return {
|
|
72
|
+
isMobile,
|
|
73
|
+
setMobileDisabled,
|
|
74
|
+
openMobile,
|
|
75
|
+
setOpenMobile,
|
|
76
|
+
open,
|
|
77
|
+
setOpen,
|
|
78
|
+
side,
|
|
79
|
+
setSide,
|
|
80
|
+
};
|
|
53
81
|
};
|
|
54
82
|
const useSidebarEvents = (stateSet: ReturnType<typeof useSidebarState>): { toggle: () => void } => {
|
|
55
83
|
const toggle = (): void => {
|
|
@@ -84,6 +112,7 @@ const createSidebarContextValue = (
|
|
|
84
112
|
open: stateSet.open,
|
|
85
113
|
setOpen: stateSet.setOpen,
|
|
86
114
|
isMobile: stateSet.isMobile,
|
|
115
|
+
setMobileDisabled: stateSet.setMobileDisabled,
|
|
87
116
|
openMobile: stateSet.openMobile,
|
|
88
117
|
setOpenMobile: stateSet.setOpenMobile,
|
|
89
118
|
toggleSidebar: toggle,
|
|
@@ -92,40 +121,12 @@ const createSidebarContextValue = (
|
|
|
92
121
|
});
|
|
93
122
|
|
|
94
123
|
export const SidebarProvider: Component<SidebarProviderProps> = (props) => {
|
|
95
|
-
const
|
|
96
|
-
'defaultOpen',
|
|
97
|
-
'open',
|
|
98
|
-
'onOpenChange',
|
|
99
|
-
'class',
|
|
100
|
-
'style',
|
|
101
|
-
'children',
|
|
102
|
-
]);
|
|
103
|
-
const stateSet = useSidebarState(local);
|
|
124
|
+
const stateSet = useSidebarState(props);
|
|
104
125
|
const { toggle } = useSidebarEvents(stateSet);
|
|
105
126
|
|
|
106
|
-
const style = createMemo((): JSX.CSSProperties => {
|
|
107
|
-
const base: JSX.CSSProperties = {
|
|
108
|
-
'--sidebar-width': SIDEBAR_WIDTH,
|
|
109
|
-
'--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
|
|
110
|
-
};
|
|
111
|
-
return typeof local.style === 'object' && local.style !== null
|
|
112
|
-
? { ...base, ...local.style }
|
|
113
|
-
: base;
|
|
114
|
-
});
|
|
115
|
-
|
|
116
127
|
return (
|
|
117
128
|
<SidebarContext.Provider value={createSidebarContextValue(stateSet, toggle)}>
|
|
118
|
-
|
|
119
|
-
data-slot='sidebar-wrapper'
|
|
120
|
-
style={style()}
|
|
121
|
-
class={cn(
|
|
122
|
-
'group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar',
|
|
123
|
-
local.class,
|
|
124
|
-
)}
|
|
125
|
-
{...others}
|
|
126
|
-
>
|
|
127
|
-
{local.children}
|
|
128
|
-
</div>
|
|
129
|
+
{props.children}
|
|
129
130
|
</SidebarContext.Provider>
|
|
130
131
|
);
|
|
131
132
|
};
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { Component, ComponentProps } from 'solid-js';
|
|
2
2
|
|
|
3
3
|
import { cn } from 'tailwind-variants';
|
|
4
|
-
import
|
|
4
|
+
import ViewSidebarIcon from '~icons/material-symbols/side-navigation';
|
|
5
5
|
|
|
6
6
|
import { Button } from '@/components/Button';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
ScrollArea,
|
|
9
|
+
ScrollAreaContent,
|
|
10
|
+
ScrollAreaScrollbar,
|
|
11
|
+
ScrollAreaThumb,
|
|
12
|
+
ScrollAreaViewport,
|
|
13
|
+
} from '@/components/ScrollArea';
|
|
8
14
|
import { Separator } from '@/components/Separator';
|
|
9
15
|
import * as messages from '@/paraglide/messages';
|
|
10
16
|
|
|
@@ -34,7 +40,7 @@ export const SidebarTrigger: Component<ComponentProps<typeof Button>> = (props)
|
|
|
34
40
|
onClick={handleClick}
|
|
35
41
|
{...others}
|
|
36
42
|
>
|
|
37
|
-
<
|
|
43
|
+
<ViewSidebarIcon aria-hidden='true' />
|
|
38
44
|
</Button>
|
|
39
45
|
);
|
|
40
46
|
};
|
|
@@ -140,13 +146,17 @@ export const SidebarContent: Component<ComponentProps<'div'>> = (props) => {
|
|
|
140
146
|
data-slot='sidebar-content'
|
|
141
147
|
data-sidebar='content'
|
|
142
148
|
id={typeof local.id === 'string' ? local.id : 'sidebar-content'}
|
|
143
|
-
class={cn(
|
|
144
|
-
'gap-0 min-h-0 flex flex-1 flex-col group-data-[collapsible=icon]:overflow-hidden',
|
|
145
|
-
local.class,
|
|
146
|
-
)}
|
|
149
|
+
class={cn('min-h-0 flex flex-1 flex-col', local.class)}
|
|
147
150
|
{...others}
|
|
148
151
|
>
|
|
149
|
-
|
|
152
|
+
<ScrollAreaViewport class='h-full'>
|
|
153
|
+
<ScrollAreaContent class='gap-0 flex min-h-full flex-col group-data-[collapsible=icon]:overflow-hidden'>
|
|
154
|
+
{local.children}
|
|
155
|
+
</ScrollAreaContent>
|
|
156
|
+
</ScrollAreaViewport>
|
|
157
|
+
<ScrollAreaScrollbar orientation='vertical'>
|
|
158
|
+
<ScrollAreaThumb />
|
|
159
|
+
</ScrollAreaScrollbar>
|
|
150
160
|
</ScrollArea>
|
|
151
161
|
);
|
|
152
162
|
};
|
|
@@ -170,7 +180,7 @@ export const SidebarGroupLabel: Component<ComponentProps<'div'>> = (props) => {
|
|
|
170
180
|
data-slot='sidebar-group-label'
|
|
171
181
|
data-sidebar='group-label'
|
|
172
182
|
class={cn(
|
|
173
|
-
'h-8 px-2 text-xs
|
|
183
|
+
'h-8 px-2 text-xs group-data-[collapsible=icon]:-mt-8 [&>svg]:size-4 flex shrink-0 items-center rounded-md text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:shrink-0',
|
|
174
184
|
local.class,
|
|
175
185
|
)}
|
|
176
186
|
{...others}
|
|
@@ -5,6 +5,7 @@ export type SidebarContextProps = {
|
|
|
5
5
|
openMobile: () => boolean;
|
|
6
6
|
setOpenMobile: (open: boolean) => void;
|
|
7
7
|
isMobile: () => boolean;
|
|
8
|
+
setMobileDisabled: (mobileDisabled: boolean) => void;
|
|
8
9
|
toggleSidebar: () => void;
|
|
9
10
|
side: () => 'left' | 'right';
|
|
10
11
|
setSide: (side: 'left' | 'right') => void;
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
import { type Component, type Accessor, Show } from 'solid-js';
|
|
8
8
|
import { Portal } from 'solid-js/web';
|
|
9
9
|
import { cn } from 'tailwind-variants';
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
10
|
+
import CheckCircleIcon from '~icons/material-symbols/check-circle';
|
|
11
|
+
import CloseIcon from '~icons/material-symbols/close';
|
|
12
|
+
import ErrorIcon from '~icons/material-symbols/error';
|
|
13
|
+
import InfoIcon from '~icons/material-symbols/info';
|
|
14
|
+
import WarningIcon from '~icons/material-symbols/warning';
|
|
15
15
|
|
|
16
16
|
import { Spinner } from '@/components/Spinner';
|
|
17
17
|
|
|
@@ -24,22 +24,22 @@ export const toast = createToaster({
|
|
|
24
24
|
const ToastItem: Component<{ toast: Accessor<ToastOptions> }> = (props) => (
|
|
25
25
|
<Toast.Root
|
|
26
26
|
class={cn(
|
|
27
|
-
'group gap-3 p-4 pr-10 shadow-lg pointer-events-auto relative flex
|
|
28
|
-
'data-[state=open]:
|
|
27
|
+
'group gap-3 p-4 pr-10 shadow-lg min-w-72 pointer-events-auto relative flex w-full items-center rounded-lg border bg-popover transition-all',
|
|
28
|
+
'data-[state=open]:sm:slide-in-from-bottom-full data-[state=open]:animate-in data-[state=open]:slide-in-from-top-full',
|
|
29
29
|
'border-border text-popover-foreground',
|
|
30
30
|
)}
|
|
31
31
|
>
|
|
32
32
|
<Show when={props.toast().type === 'success'}>
|
|
33
|
-
<
|
|
33
|
+
<CheckCircleIcon class={cn('size-5 text-green-500 shrink-0')} aria-hidden='true' />
|
|
34
34
|
</Show>
|
|
35
35
|
<Show when={props.toast().type === 'info'}>
|
|
36
|
-
<
|
|
36
|
+
<InfoIcon class={cn('size-5 text-blue-500 shrink-0')} aria-hidden='true' />
|
|
37
37
|
</Show>
|
|
38
38
|
<Show when={props.toast().type === 'warning'}>
|
|
39
|
-
<
|
|
39
|
+
<WarningIcon class={cn('size-5 text-amber-500 shrink-0')} aria-hidden='true' />
|
|
40
40
|
</Show>
|
|
41
41
|
<Show when={props.toast().type === 'error'}>
|
|
42
|
-
<
|
|
42
|
+
<ErrorIcon class={cn('size-5 text-red-500 shrink-0')} aria-hidden='true' />
|
|
43
43
|
</Show>
|
|
44
44
|
<Show when={props.toast().type === 'loading'}>
|
|
45
45
|
<Spinner class={cn('size-5 text-muted-foreground')} />
|
|
@@ -57,7 +57,7 @@ const ToastItem: Component<{ toast: Accessor<ToastOptions> }> = (props) => (
|
|
|
57
57
|
</Show>
|
|
58
58
|
</div>
|
|
59
59
|
<Toast.CloseTrigger class='top-2 right-2 p-1 absolute cursor-pointer rounded-md text-foreground/50 opacity-0 transition-opacity group-hover:opacity-100 hover:text-foreground focus:opacity-100 focus:outline-none'>
|
|
60
|
-
<
|
|
60
|
+
<CloseIcon class='size-4' />
|
|
61
61
|
</Toast.CloseTrigger>
|
|
62
62
|
</Toast.Root>
|
|
63
63
|
);
|