@starwind-ui/core 1.13.0 → 1.15.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/index.js +28 -5
- package/dist/index.js.map +1 -1
- package/dist/src/components/badge/Badge.astro +8 -2
- package/dist/src/components/button/Button.astro +8 -7
- package/dist/src/components/collapsible/Collapsible.astro +161 -0
- package/dist/src/components/collapsible/CollapsibleContent.astro +22 -0
- package/dist/src/components/collapsible/CollapsibleTrigger.astro +44 -0
- package/dist/src/components/collapsible/index.ts +13 -0
- package/dist/src/components/dialog/Dialog.astro +35 -1
- package/dist/src/components/input-otp/InputOtp.astro +319 -0
- package/dist/src/components/input-otp/InputOtpGroup.astro +16 -0
- package/dist/src/components/input-otp/InputOtpSeparator.astro +25 -0
- package/dist/src/components/input-otp/InputOtpSlot.astro +48 -0
- package/dist/src/components/input-otp/InputOtpTypes.ts +6 -0
- package/dist/src/components/input-otp/index.ts +33 -0
- package/dist/src/components/prose/Prose.astro +617 -0
- package/dist/src/components/prose/index.ts +9 -0
- package/dist/src/components/select/Select.astro +3 -0
- package/dist/src/components/sidebar/Sidebar.astro +213 -0
- package/dist/src/components/sidebar/SidebarContent.astro +24 -0
- package/dist/src/components/sidebar/SidebarFooter.astro +21 -0
- package/dist/src/components/sidebar/SidebarGroup.astro +21 -0
- package/dist/src/components/sidebar/SidebarGroupContent.astro +21 -0
- package/dist/src/components/sidebar/SidebarGroupLabel.astro +52 -0
- package/dist/src/components/sidebar/SidebarHeader.astro +21 -0
- package/dist/src/components/sidebar/SidebarInput.astro +22 -0
- package/dist/src/components/sidebar/SidebarInset.astro +21 -0
- package/dist/src/components/sidebar/SidebarMenu.astro +21 -0
- package/dist/src/components/sidebar/SidebarMenuAction.astro +59 -0
- package/dist/src/components/sidebar/SidebarMenuBadge.astro +30 -0
- package/dist/src/components/sidebar/SidebarMenuButton.astro +129 -0
- package/dist/src/components/sidebar/SidebarMenuItem.astro +21 -0
- package/dist/src/components/sidebar/SidebarMenuSkeleton.astro +40 -0
- package/dist/src/components/sidebar/SidebarMenuSub.astro +24 -0
- package/dist/src/components/sidebar/SidebarMenuSubButton.astro +49 -0
- package/dist/src/components/sidebar/SidebarMenuSubItem.astro +16 -0
- package/dist/src/components/sidebar/SidebarProvider.astro +213 -0
- package/dist/src/components/sidebar/SidebarRail.astro +71 -0
- package/dist/src/components/sidebar/SidebarSeparator.astro +22 -0
- package/dist/src/components/sidebar/SidebarTrigger.astro +66 -0
- package/dist/src/components/sidebar/index.ts +103 -0
- package/dist/src/components/theme-toggle/ThemeToggle.astro +208 -0
- package/dist/src/components/theme-toggle/index.ts +7 -0
- package/dist/src/components/toggle/Toggle.astro +1 -1
- package/dist/src/components/tooltip/Tooltip.astro +80 -37
- package/dist/src/components/tooltip/TooltipContent.astro +9 -34
- package/package.json +1 -1
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
Sheet,
|
|
7
|
+
SheetContent,
|
|
8
|
+
SheetDescription,
|
|
9
|
+
SheetHeader,
|
|
10
|
+
SheetTitle,
|
|
11
|
+
} from "@/components/starwind/sheet";
|
|
12
|
+
|
|
13
|
+
type Props = HTMLAttributes<"div"> & {
|
|
14
|
+
/**
|
|
15
|
+
* The side of the viewport the sidebar appears on
|
|
16
|
+
* @default "left"
|
|
17
|
+
*/
|
|
18
|
+
side?: "left" | "right";
|
|
19
|
+
/**
|
|
20
|
+
* The visual variant of the sidebar
|
|
21
|
+
* @default "sidebar"
|
|
22
|
+
*/
|
|
23
|
+
variant?: "sidebar" | "floating" | "inset";
|
|
24
|
+
/**
|
|
25
|
+
* How the sidebar collapses
|
|
26
|
+
* @default "offcanvas"
|
|
27
|
+
*/
|
|
28
|
+
collapsible?: "offcanvas" | "icon" | "none";
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const sidebar = tv({
|
|
32
|
+
base: "starwind-sidebar group peer text-sidebar-foreground hidden md:block",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const sidebarGap = tv({
|
|
36
|
+
base: [
|
|
37
|
+
"relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
|
|
38
|
+
"group-data-[collapsible=offcanvas]:w-0",
|
|
39
|
+
"group-data-[side=right]:rotate-180",
|
|
40
|
+
],
|
|
41
|
+
variants: {
|
|
42
|
+
variant: {
|
|
43
|
+
sidebar: "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
|
|
44
|
+
floating: "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem)]",
|
|
45
|
+
inset: "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem)]",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
defaultVariants: {
|
|
49
|
+
variant: "sidebar",
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export const sidebarContainer = tv({
|
|
54
|
+
base: [
|
|
55
|
+
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
|
|
56
|
+
],
|
|
57
|
+
variants: {
|
|
58
|
+
side: {
|
|
59
|
+
left: "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]",
|
|
60
|
+
right: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
|
61
|
+
},
|
|
62
|
+
variant: {
|
|
63
|
+
sidebar: [
|
|
64
|
+
"group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
|
|
65
|
+
"group-data-[side=left]:border-r group-data-[side=right]:border-l",
|
|
66
|
+
],
|
|
67
|
+
floating: "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem+2px)]",
|
|
68
|
+
inset: "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem+2px)]",
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
defaultVariants: {
|
|
72
|
+
side: "left",
|
|
73
|
+
variant: "sidebar",
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
export const sidebarInner = tv({
|
|
78
|
+
base: "bg-sidebar flex h-full w-full flex-col",
|
|
79
|
+
variants: {
|
|
80
|
+
variant: {
|
|
81
|
+
sidebar: "",
|
|
82
|
+
floating: "border-sidebar-border rounded-lg border shadow-sm",
|
|
83
|
+
inset: "border-sidebar-border rounded-lg border shadow-sm",
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
defaultVariants: {
|
|
87
|
+
variant: "sidebar",
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
export const sidebarMobileContent = tv({
|
|
92
|
+
base: "bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden",
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const {
|
|
96
|
+
side = "left",
|
|
97
|
+
variant = "sidebar",
|
|
98
|
+
collapsible = "offcanvas",
|
|
99
|
+
class: className,
|
|
100
|
+
...rest
|
|
101
|
+
} = Astro.props;
|
|
102
|
+
|
|
103
|
+
const SIDEBAR_WIDTH_MOBILE = "18rem";
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
{/* Non-collapsible sidebar */}
|
|
107
|
+
{
|
|
108
|
+
collapsible === "none" ? (
|
|
109
|
+
<div
|
|
110
|
+
class:list={[
|
|
111
|
+
"bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
|
|
112
|
+
className,
|
|
113
|
+
]}
|
|
114
|
+
data-slot="sidebar"
|
|
115
|
+
{...rest}
|
|
116
|
+
>
|
|
117
|
+
<slot />
|
|
118
|
+
</div>
|
|
119
|
+
) : (
|
|
120
|
+
<>
|
|
121
|
+
{/* Desktop sidebar */}
|
|
122
|
+
<div
|
|
123
|
+
class={sidebar({ class: className })}
|
|
124
|
+
data-state="expanded"
|
|
125
|
+
data-collapsible=""
|
|
126
|
+
data-collapsible-mode={collapsible}
|
|
127
|
+
data-variant={variant}
|
|
128
|
+
data-side={side}
|
|
129
|
+
data-slot="sidebar"
|
|
130
|
+
>
|
|
131
|
+
{/* Gap placeholder for layout */}
|
|
132
|
+
<div data-slot="sidebar-gap" class={sidebarGap({ variant })} />
|
|
133
|
+
|
|
134
|
+
{/* Fixed sidebar container */}
|
|
135
|
+
<div data-slot="sidebar-container" class={sidebarContainer({ side, variant })} {...rest}>
|
|
136
|
+
<div data-slot="sidebar-inner" class={sidebarInner({ variant })}>
|
|
137
|
+
<slot />
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
{/* Mobile sidebar (Sheet) */}
|
|
143
|
+
<Sheet class="md:hidden" data-slot="sidebar-mobile">
|
|
144
|
+
<SheetContent
|
|
145
|
+
side={side}
|
|
146
|
+
class={sidebarMobileContent()}
|
|
147
|
+
style={{ "--sidebar-width": SIDEBAR_WIDTH_MOBILE }}
|
|
148
|
+
>
|
|
149
|
+
<SheetHeader class="sr-only">
|
|
150
|
+
<SheetTitle>Sidebar</SheetTitle>
|
|
151
|
+
<SheetDescription>Mobile navigation sidebar</SheetDescription>
|
|
152
|
+
</SheetHeader>
|
|
153
|
+
<div class="flex h-full w-full flex-col">
|
|
154
|
+
<slot />
|
|
155
|
+
</div>
|
|
156
|
+
</SheetContent>
|
|
157
|
+
</Sheet>
|
|
158
|
+
</>
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
<script>
|
|
163
|
+
class SidebarHandler {
|
|
164
|
+
private sidebar: HTMLElement;
|
|
165
|
+
private provider: HTMLElement;
|
|
166
|
+
private collapsibleMode: string;
|
|
167
|
+
private boundUpdateState: () => void;
|
|
168
|
+
|
|
169
|
+
constructor(sidebar: HTMLElement) {
|
|
170
|
+
this.sidebar = sidebar;
|
|
171
|
+
this.provider = sidebar.closest<HTMLElement>('[data-slot="sidebar-provider"]')!;
|
|
172
|
+
this.collapsibleMode =
|
|
173
|
+
sidebar.dataset.collapsibleMode ||
|
|
174
|
+
(sidebar.closest("[data-collapsible]") as HTMLElement)?.dataset.collapsible ||
|
|
175
|
+
"offcanvas";
|
|
176
|
+
sidebar.dataset.collapsibleMode = this.collapsibleMode;
|
|
177
|
+
|
|
178
|
+
this.boundUpdateState = this.updateState.bind(this);
|
|
179
|
+
this.init();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private init() {
|
|
183
|
+
this.updateState();
|
|
184
|
+
this.provider.addEventListener("sidebar:change", this.boundUpdateState);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private updateState() {
|
|
188
|
+
const state = this.provider.getAttribute("data-state") || "expanded";
|
|
189
|
+
this.sidebar.setAttribute("data-state", state);
|
|
190
|
+
|
|
191
|
+
if (state === "collapsed") {
|
|
192
|
+
this.sidebar.setAttribute("data-collapsible", this.collapsibleMode);
|
|
193
|
+
} else {
|
|
194
|
+
this.sidebar.setAttribute("data-collapsible", "");
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const sidebarInstances = new WeakMap<HTMLElement, SidebarHandler>();
|
|
200
|
+
|
|
201
|
+
const setupSidebars = () => {
|
|
202
|
+
document.querySelectorAll<HTMLElement>('[data-slot="sidebar"]').forEach((sidebar) => {
|
|
203
|
+
if (sidebarInstances.has(sidebar)) return;
|
|
204
|
+
const provider = sidebar.closest<HTMLElement>('[data-slot="sidebar-provider"]');
|
|
205
|
+
if (!provider) return;
|
|
206
|
+
sidebarInstances.set(sidebar, new SidebarHandler(sidebar));
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
setupSidebars();
|
|
211
|
+
document.addEventListener("astro:after-swap", setupSidebars);
|
|
212
|
+
document.addEventListener("starwind:init", setupSidebars);
|
|
213
|
+
</script>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"div">;
|
|
6
|
+
|
|
7
|
+
export const sidebarContent = tv({
|
|
8
|
+
base: [
|
|
9
|
+
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto",
|
|
10
|
+
"group-data-[collapsible=icon]:overflow-hidden",
|
|
11
|
+
],
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const { class: className, ...rest } = Astro.props;
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<div
|
|
18
|
+
class={sidebarContent({ class: className })}
|
|
19
|
+
data-slot="sidebar-content"
|
|
20
|
+
data-sidebar="content"
|
|
21
|
+
{...rest}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"div">;
|
|
6
|
+
|
|
7
|
+
export const sidebarFooter = tv({
|
|
8
|
+
base: "flex flex-col gap-2 p-2",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<div
|
|
15
|
+
class={sidebarFooter({ class: className })}
|
|
16
|
+
data-slot="sidebar-footer"
|
|
17
|
+
data-sidebar="footer"
|
|
18
|
+
{...rest}
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"div">;
|
|
6
|
+
|
|
7
|
+
export const sidebarGroup = tv({
|
|
8
|
+
base: "relative flex w-full min-w-0 flex-col p-2",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<div
|
|
15
|
+
class={sidebarGroup({ class: className })}
|
|
16
|
+
data-slot="sidebar-group"
|
|
17
|
+
data-sidebar="group"
|
|
18
|
+
{...rest}
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"div">;
|
|
6
|
+
|
|
7
|
+
export const sidebarGroupContent = tv({
|
|
8
|
+
base: "w-full text-sm",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<div
|
|
15
|
+
class={sidebarGroupContent({ class: className })}
|
|
16
|
+
data-slot="sidebar-group-content"
|
|
17
|
+
data-sidebar="group-content"
|
|
18
|
+
{...rest}
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"div"> & {
|
|
6
|
+
/**
|
|
7
|
+
* Render as a child element wrapper instead of a div
|
|
8
|
+
*/
|
|
9
|
+
asChild?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const sidebarGroupLabel = tv({
|
|
13
|
+
base: [
|
|
14
|
+
"text-sidebar-foreground/70 ring-sidebar-outline",
|
|
15
|
+
"flex h-10 shrink-0 items-center rounded-md px-2 text-sm font-medium",
|
|
16
|
+
"outline-hidden transition-[margin,opacity] duration-200 ease-linear",
|
|
17
|
+
"focus-visible:ring-2",
|
|
18
|
+
"[&>svg]:size-4.5 [&>svg]:shrink-0",
|
|
19
|
+
"group-data-[collapsible=icon]:-mt-10 group-data-[collapsible=icon]:opacity-0",
|
|
20
|
+
],
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const { asChild = false, class: className, ...rest } = Astro.props;
|
|
24
|
+
|
|
25
|
+
let hasChildren = false;
|
|
26
|
+
if (Astro.slots.has("default")) {
|
|
27
|
+
hasChildren = true;
|
|
28
|
+
}
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
{
|
|
32
|
+
asChild && hasChildren ? (
|
|
33
|
+
<div
|
|
34
|
+
class={sidebarGroupLabel({ class: className })}
|
|
35
|
+
data-slot="sidebar-group-label"
|
|
36
|
+
data-sidebar="group-label"
|
|
37
|
+
data-as-child
|
|
38
|
+
{...rest}
|
|
39
|
+
>
|
|
40
|
+
<slot />
|
|
41
|
+
</div>
|
|
42
|
+
) : (
|
|
43
|
+
<div
|
|
44
|
+
class={sidebarGroupLabel({ class: className })}
|
|
45
|
+
data-slot="sidebar-group-label"
|
|
46
|
+
data-sidebar="group-label"
|
|
47
|
+
{...rest}
|
|
48
|
+
>
|
|
49
|
+
<slot />
|
|
50
|
+
</div>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"div">;
|
|
6
|
+
|
|
7
|
+
export const sidebarHeader = tv({
|
|
8
|
+
base: "flex flex-col gap-2 p-2",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<div
|
|
15
|
+
class={sidebarHeader({ class: className })}
|
|
16
|
+
data-slot="sidebar-header"
|
|
17
|
+
data-sidebar="header"
|
|
18
|
+
{...rest}
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
import { Input } from "@/components/starwind/input";
|
|
6
|
+
|
|
7
|
+
const sidebarInput = tv({
|
|
8
|
+
base: "bg-background focus-visible:ring-sidebar-outline h-10 w-full shadow-none focus-visible:ring-2",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
type Props = ComponentProps<typeof Input>;
|
|
12
|
+
|
|
13
|
+
const { size = "md", class: className, ...rest } = Astro.props;
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<Input
|
|
17
|
+
size={size}
|
|
18
|
+
class={sidebarInput({ class: className })}
|
|
19
|
+
data-slot="sidebar-input"
|
|
20
|
+
data-sidebar="input"
|
|
21
|
+
{...rest}
|
|
22
|
+
/>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"main">;
|
|
6
|
+
|
|
7
|
+
export const sidebarInset = tv({
|
|
8
|
+
base: [
|
|
9
|
+
"bg-background relative flex w-full flex-1 flex-col",
|
|
10
|
+
"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0",
|
|
11
|
+
"md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm",
|
|
12
|
+
"md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
|
|
13
|
+
],
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const { class: className, ...rest } = Astro.props;
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<main class={sidebarInset({ class: className })} data-slot="sidebar-inset" {...rest}>
|
|
20
|
+
<slot />
|
|
21
|
+
</main>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"ul">;
|
|
6
|
+
|
|
7
|
+
export const sidebarMenu = tv({
|
|
8
|
+
base: "flex w-full min-w-0 flex-col gap-1",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<ul
|
|
15
|
+
class={sidebarMenu({ class: className })}
|
|
16
|
+
data-slot="sidebar-menu"
|
|
17
|
+
data-sidebar="menu"
|
|
18
|
+
{...rest}
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</ul>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentProps } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
import { Button } from "@/components/starwind/button";
|
|
6
|
+
|
|
7
|
+
type Props = ComponentProps<typeof Button> & {
|
|
8
|
+
/**
|
|
9
|
+
* When true, shows the action only when the menu item is hovered
|
|
10
|
+
* @default false
|
|
11
|
+
*/
|
|
12
|
+
showOnHover?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const sidebarMenuAction = tv({
|
|
16
|
+
base: [
|
|
17
|
+
"text-sidebar-foreground ring-sidebar-outline",
|
|
18
|
+
"absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0",
|
|
19
|
+
"outline-hidden transition-transform",
|
|
20
|
+
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
21
|
+
"peer-hover/menu-button:text-sidebar-accent-foreground",
|
|
22
|
+
"[&>svg]:size-4 [&>svg]:shrink-0",
|
|
23
|
+
"after:absolute after:-inset-2 md:after:hidden",
|
|
24
|
+
"peer-data-[size=sm]/menu-button:top-1",
|
|
25
|
+
"peer-data-[size=default]/menu-button:top-1.5",
|
|
26
|
+
"peer-data-[size=lg]/menu-button:top-2.5",
|
|
27
|
+
"group-data-[collapsible=icon]:hidden",
|
|
28
|
+
],
|
|
29
|
+
variants: {
|
|
30
|
+
showOnHover: {
|
|
31
|
+
true: [
|
|
32
|
+
"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
|
|
33
|
+
"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100",
|
|
34
|
+
"data-[state=open]:opacity-100",
|
|
35
|
+
"md:opacity-0",
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const {
|
|
42
|
+
showOnHover = false,
|
|
43
|
+
variant = "ghost",
|
|
44
|
+
size = "icon-sm",
|
|
45
|
+
class: className,
|
|
46
|
+
...rest
|
|
47
|
+
} = Astro.props;
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
<Button
|
|
51
|
+
variant={variant}
|
|
52
|
+
size={size}
|
|
53
|
+
class={sidebarMenuAction({ showOnHover, class: className })}
|
|
54
|
+
data-slot="sidebar-menu-action"
|
|
55
|
+
data-sidebar="menu-action"
|
|
56
|
+
{...rest}
|
|
57
|
+
>
|
|
58
|
+
<slot />
|
|
59
|
+
</Button>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"div">;
|
|
6
|
+
|
|
7
|
+
export const sidebarMenuBadge = tv({
|
|
8
|
+
base: [
|
|
9
|
+
"text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5",
|
|
10
|
+
"items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none",
|
|
11
|
+
"peer-hover/menu-button:text-sidebar-accent-foreground",
|
|
12
|
+
"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
|
|
13
|
+
"peer-data-[size=sm]/menu-button:top-1",
|
|
14
|
+
"peer-data-[size=default]/menu-button:top-1.5",
|
|
15
|
+
"peer-data-[size=lg]/menu-button:top-2.5",
|
|
16
|
+
"group-data-[collapsible=icon]:hidden",
|
|
17
|
+
],
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const { class: className, ...rest } = Astro.props;
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
<div
|
|
24
|
+
class={sidebarMenuBadge({ class: className })}
|
|
25
|
+
data-slot="sidebar-menu-badge"
|
|
26
|
+
data-sidebar="menu-badge"
|
|
27
|
+
{...rest}
|
|
28
|
+
>
|
|
29
|
+
<slot />
|
|
30
|
+
</div>
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/starwind/tooltip";
|
|
6
|
+
|
|
7
|
+
type Props = HTMLAttributes<"button"> &
|
|
8
|
+
Omit<HTMLAttributes<"a">, "type"> &
|
|
9
|
+
VariantProps<typeof sidebarMenuButton> & {
|
|
10
|
+
/**
|
|
11
|
+
* Render as a child element wrapper instead of a button
|
|
12
|
+
*/
|
|
13
|
+
asChild?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the menu item is currently active
|
|
16
|
+
*/
|
|
17
|
+
isActive?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Tooltip text to show when sidebar is collapsed
|
|
20
|
+
*/
|
|
21
|
+
tooltip?: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const sidebarMenuButton = tv({
|
|
25
|
+
base: [
|
|
26
|
+
"peer/menu-button flex w-full items-center gap-3 overflow-hidden rounded-md p-2.5 text-left",
|
|
27
|
+
"ring-sidebar-outline outline-hidden transition-[width,height,padding]",
|
|
28
|
+
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
29
|
+
"focus-visible:ring-2",
|
|
30
|
+
"active:bg-sidebar-accent active:text-sidebar-accent-foreground",
|
|
31
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
32
|
+
"aria-disabled:pointer-events-none aria-disabled:opacity-50",
|
|
33
|
+
"group-has-data-[sidebar=menu-action]/menu-item:pr-8",
|
|
34
|
+
"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[active=true]:font-medium",
|
|
35
|
+
"data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground",
|
|
36
|
+
"group-data-[collapsible=icon]:size-10! group-data-[collapsible=icon]:p-2.5!",
|
|
37
|
+
"[&>span:last-child]:truncate [&>svg]:size-4.5 [&>svg]:shrink-0",
|
|
38
|
+
],
|
|
39
|
+
variants: {
|
|
40
|
+
variant: {
|
|
41
|
+
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
42
|
+
outline: [
|
|
43
|
+
"bg-background shadow-sidebar-border shadow-xs",
|
|
44
|
+
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-sidebar-accent",
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
size: {
|
|
48
|
+
default: "h-10 text-base",
|
|
49
|
+
sm: "h-8 text-sm",
|
|
50
|
+
lg: "h-14 text-lg group-data-[collapsible=icon]:p-0!",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
defaultVariants: {
|
|
54
|
+
variant: "default",
|
|
55
|
+
size: "default",
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const {
|
|
60
|
+
asChild = false,
|
|
61
|
+
isActive = false,
|
|
62
|
+
tooltip,
|
|
63
|
+
variant,
|
|
64
|
+
size,
|
|
65
|
+
class: className,
|
|
66
|
+
...rest
|
|
67
|
+
} = Astro.props;
|
|
68
|
+
|
|
69
|
+
const Tag = Astro.props.href ? "a" : "button";
|
|
70
|
+
|
|
71
|
+
const buttonClasses = sidebarMenuButton({ variant, size, class: className });
|
|
72
|
+
const buttonDataAttrs = {
|
|
73
|
+
"data-slot": "sidebar-menu-button",
|
|
74
|
+
"data-sidebar": "menu-button",
|
|
75
|
+
"data-size": size || "default",
|
|
76
|
+
"data-active": isActive,
|
|
77
|
+
};
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
{
|
|
81
|
+
tooltip ? (
|
|
82
|
+
<Tooltip openDelay={0} closeDelay={0} class="w-full">
|
|
83
|
+
<TooltipTrigger>
|
|
84
|
+
{asChild ? (
|
|
85
|
+
<div class={buttonClasses} {...buttonDataAttrs} data-as-child>
|
|
86
|
+
<slot />
|
|
87
|
+
</div>
|
|
88
|
+
) : (
|
|
89
|
+
<Tag class={buttonClasses} {...buttonDataAttrs} {...rest}>
|
|
90
|
+
<slot />
|
|
91
|
+
</Tag>
|
|
92
|
+
)}
|
|
93
|
+
</TooltipTrigger>
|
|
94
|
+
<TooltipContent
|
|
95
|
+
side="right"
|
|
96
|
+
align="center"
|
|
97
|
+
class="starwind-sidebar-tooltip-content whitespace-nowrap"
|
|
98
|
+
>
|
|
99
|
+
{tooltip}
|
|
100
|
+
</TooltipContent>
|
|
101
|
+
</Tooltip>
|
|
102
|
+
) : asChild ? (
|
|
103
|
+
<div class={buttonClasses} {...buttonDataAttrs} data-as-child>
|
|
104
|
+
<slot />
|
|
105
|
+
</div>
|
|
106
|
+
) : (
|
|
107
|
+
<Tag class={buttonClasses} {...buttonDataAttrs} {...rest}>
|
|
108
|
+
<slot />
|
|
109
|
+
</Tag>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
<style is:global>
|
|
114
|
+
/* Hide tooltip when sidebar is expanded */
|
|
115
|
+
[data-slot="sidebar"][data-state="expanded"] .starwind-sidebar-tooltip-content,
|
|
116
|
+
[data-slot="sidebar"]:not([data-collapsible="icon"]) .starwind-sidebar-tooltip-content {
|
|
117
|
+
display: none !important;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Hide tooltips in mobile sheet */
|
|
121
|
+
.starwind-sheet .starwind-sidebar-tooltip-content {
|
|
122
|
+
display: none !important;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Only show tooltip trigger wrapper styles when collapsed */
|
|
126
|
+
.starwind-sidebar-menu-button-tooltip-trigger {
|
|
127
|
+
display: contents;
|
|
128
|
+
}
|
|
129
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"li">;
|
|
6
|
+
|
|
7
|
+
export const sidebarMenuItem = tv({
|
|
8
|
+
base: "group/menu-item relative",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<li
|
|
15
|
+
class={sidebarMenuItem({ class: className })}
|
|
16
|
+
data-slot="sidebar-menu-item"
|
|
17
|
+
data-sidebar="menu-item"
|
|
18
|
+
{...rest}
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</li>
|