@snow-labs/brutal-ui 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/brutal/cta-section.d.ts +7 -2
- package/dist/components/brutal/cta-section.js +136 -32
- package/dist/components/brutal/cta-section.js.map +1 -1
- package/dist/components/brutal/faq.d.ts +16 -0
- package/dist/components/brutal/faq.js +163 -0
- package/dist/components/brutal/faq.js.map +1 -0
- package/dist/components/brutal/feature-grid.d.ts +6 -2
- package/dist/components/brutal/feature-grid.js +73 -10
- package/dist/components/brutal/feature-grid.js.map +1 -1
- package/dist/components/brutal/footer.d.ts +14 -1
- package/dist/components/brutal/footer.js +181 -18
- package/dist/components/brutal/footer.js.map +1 -1
- package/dist/components/brutal/hero.d.ts +9 -2
- package/dist/components/brutal/hero.js +67 -22
- package/dist/components/brutal/hero.js.map +1 -1
- package/dist/components/brutal/index.d.ts +7 -2
- package/dist/components/brutal/index.js +1035 -128
- package/dist/components/brutal/index.js.map +1 -1
- package/dist/components/brutal/integration-grid.d.ts +1 -1
- package/dist/components/brutal/integration-grid.js +13 -5
- package/dist/components/brutal/integration-grid.js.map +1 -1
- package/dist/components/brutal/logo-cloud.d.ts +17 -0
- package/dist/components/brutal/logo-cloud.js +93 -0
- package/dist/components/brutal/logo-cloud.js.map +1 -0
- package/dist/components/brutal/nav.d.ts +3 -1
- package/dist/components/brutal/nav.js +166 -9
- package/dist/components/brutal/nav.js.map +1 -1
- package/dist/components/brutal/newsletter.d.ts +14 -0
- package/dist/components/brutal/newsletter.js +169 -0
- package/dist/components/brutal/newsletter.js.map +1 -0
- package/dist/components/brutal/pricing-table.d.ts +27 -0
- package/dist/components/brutal/pricing-table.js +251 -0
- package/dist/components/brutal/pricing-table.js.map +1 -0
- package/dist/components/brutal/section-divider.d.ts +14 -0
- package/dist/components/brutal/section-divider.js +70 -0
- package/dist/components/brutal/section-divider.js.map +1 -0
- package/dist/components/brutal/section.d.ts +7 -3
- package/dist/components/brutal/section.js +13 -5
- package/dist/components/brutal/section.js.map +1 -1
- package/dist/components/brutal/stats-bar.d.ts +16 -0
- package/dist/components/brutal/stats-bar.js +127 -0
- package/dist/components/brutal/stats-bar.js.map +1 -0
- package/dist/components/brutal/testimonials.d.ts +11 -3
- package/dist/components/brutal/testimonials.js +126 -33
- package/dist/components/brutal/testimonials.js.map +1 -1
- package/dist/components/brutal/wave-divider.d.ts +2 -12
- package/dist/components/brutal/wave-divider.js +54 -26
- package/dist/components/brutal/wave-divider.js.map +1 -1
- package/dist/components/dashboard/activity-feed.d.ts +18 -0
- package/dist/components/dashboard/activity-feed.js +105 -0
- package/dist/components/dashboard/activity-feed.js.map +1 -0
- package/dist/components/dashboard/app-shell.d.ts +19 -0
- package/dist/components/dashboard/app-shell.js +206 -0
- package/dist/components/dashboard/app-shell.js.map +1 -0
- package/dist/components/dashboard/empty-state.d.ts +14 -0
- package/dist/components/dashboard/empty-state.js +96 -0
- package/dist/components/dashboard/empty-state.js.map +1 -0
- package/dist/components/dashboard/file-upload.d.ts +12 -0
- package/dist/components/dashboard/file-upload.js +86 -0
- package/dist/components/dashboard/file-upload.js.map +1 -0
- package/dist/components/dashboard/index.d.ts +10 -0
- package/dist/components/dashboard/index.js +755 -0
- package/dist/components/dashboard/index.js.map +1 -0
- package/dist/components/dashboard/search-bar.d.ts +12 -0
- package/dist/components/dashboard/search-bar.js +49 -0
- package/dist/components/dashboard/search-bar.js.map +1 -0
- package/dist/components/dashboard/sidebar.d.ts +23 -0
- package/dist/components/dashboard/sidebar.js +113 -0
- package/dist/components/dashboard/sidebar.js.map +1 -0
- package/dist/components/dashboard/stat-card.d.ts +13 -0
- package/dist/components/dashboard/stat-card.js +55 -0
- package/dist/components/dashboard/stat-card.js.map +1 -0
- package/dist/components/dashboard/user-menu.d.ts +16 -0
- package/dist/components/dashboard/user-menu.js +179 -0
- package/dist/components/dashboard/user-menu.js.map +1 -0
- package/dist/components/dashboard/view-switcher.d.ts +12 -0
- package/dist/components/dashboard/view-switcher.js +130 -0
- package/dist/components/dashboard/view-switcher.js.map +1 -0
- package/dist/components/views/calendar-view.d.ts +17 -0
- package/dist/components/views/calendar-view.js +182 -0
- package/dist/components/views/calendar-view.js.map +1 -0
- package/dist/components/views/data-table.d.ts +15 -0
- package/dist/components/views/data-table.js +204 -0
- package/dist/components/views/data-table.js.map +1 -0
- package/dist/components/views/grid-view.d.ts +11 -0
- package/dist/components/views/grid-view.js +31 -0
- package/dist/components/views/grid-view.js.map +1 -0
- package/dist/components/views/index.d.ts +7 -0
- package/dist/components/views/index.js +542 -0
- package/dist/components/views/index.js.map +1 -0
- package/dist/components/views/kanban-board.d.ts +21 -0
- package/dist/components/views/kanban-board.js +153 -0
- package/dist/components/views/kanban-board.js.map +1 -0
- package/dist/components/views/list-view.d.ts +19 -0
- package/dist/components/views/list-view.js +96 -0
- package/dist/components/views/list-view.js.map +1 -0
- package/dist/index.d.ts +27 -3
- package/dist/index.js +1881 -142
- package/dist/index.js.map +1 -1
- package/dist/lib/animations.d.ts +68 -0
- package/dist/lib/animations.js +44 -0
- package/dist/lib/animations.js.map +1 -0
- package/dist/templates/dashboard.d.ts +40 -0
- package/dist/templates/dashboard.js +658 -0
- package/dist/templates/dashboard.js.map +1 -0
- package/dist/templates/index.d.ts +4 -0
- package/dist/templates/index.js +2001 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/saas-launch.d.ts +113 -0
- package/dist/templates/saas-launch.js +1394 -0
- package/dist/templates/saas-launch.js.map +1 -0
- package/dist/templates/studio.d.ts +72 -0
- package/dist/templates/studio.js +1099 -0
- package/dist/templates/studio.js.map +1 -0
- package/dist/theme.css +58 -15
- package/package.json +48 -2
|
@@ -0,0 +1,755 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { clsx } from 'clsx';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { createContext, useContext, useState, useCallback } from 'react';
|
|
6
|
+
import { Dialog } from '@base-ui/react/dialog';
|
|
7
|
+
import { Button as Button$1 } from '@base-ui/react/button';
|
|
8
|
+
import { cva } from 'class-variance-authority';
|
|
9
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
10
|
+
import { XIcon } from 'lucide-react';
|
|
11
|
+
import { Avatar as Avatar$1 } from '@base-ui/react/avatar';
|
|
12
|
+
import { Input as Input$1 } from '@base-ui/react/input';
|
|
13
|
+
import { Menu } from '@base-ui/react/menu';
|
|
14
|
+
import { Toggle } from '@base-ui/react/toggle';
|
|
15
|
+
import { ToggleGroup as ToggleGroup$1 } from '@base-ui/react/toggle-group';
|
|
16
|
+
|
|
17
|
+
// src/lib/utils.ts
|
|
18
|
+
function cn(...inputs) {
|
|
19
|
+
return twMerge(clsx(inputs));
|
|
20
|
+
}
|
|
21
|
+
var buttonVariants = cva(
|
|
22
|
+
"group/button inline-flex shrink-0 items-center justify-center rounded-lg whitespace-nowrap font-bold transition-all duration-150 select-none outline-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
23
|
+
{
|
|
24
|
+
variants: {
|
|
25
|
+
variant: {
|
|
26
|
+
// Primary: Black bg, white text, offset shadow
|
|
27
|
+
default: "border-brutal border-foreground bg-primary text-primary-foreground shadow-brutal hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-brutal-lg active:translate-x-px active:translate-y-px active:shadow-brutal-sm",
|
|
28
|
+
// CTA: Mint green bg — the Bannerbear signature
|
|
29
|
+
cta: "border-brutal border-foreground bg-cta text-cta-foreground shadow-brutal hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-brutal-lg active:translate-x-px active:translate-y-px active:shadow-brutal-sm",
|
|
30
|
+
// Brand: Dynamic brand color bg
|
|
31
|
+
brand: "border-brutal border-foreground bg-brand text-brand-foreground shadow-brutal hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-brutal-lg active:translate-x-px active:translate-y-px active:shadow-brutal-sm",
|
|
32
|
+
// Outline: White bg, black border, offset shadow
|
|
33
|
+
outline: "border-brutal border-foreground bg-background text-foreground shadow-brutal hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-brutal-lg active:translate-x-px active:translate-y-px active:shadow-brutal-sm",
|
|
34
|
+
// Secondary: Light bg, border, smaller shadow
|
|
35
|
+
secondary: "border-brutal border-foreground bg-secondary text-secondary-foreground shadow-brutal-sm hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-brutal active:translate-x-px active:translate-y-px active:shadow-none",
|
|
36
|
+
// Ghost: No border/shadow, subtle hover
|
|
37
|
+
ghost: "hover:bg-secondary hover:text-foreground",
|
|
38
|
+
// Link: Text only
|
|
39
|
+
link: "text-foreground underline-offset-4 hover:underline",
|
|
40
|
+
// Destructive
|
|
41
|
+
destructive: "border-brutal border-destructive bg-destructive text-destructive-foreground shadow-brutal hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-brutal-lg active:translate-x-px active:translate-y-px active:shadow-brutal-sm",
|
|
42
|
+
// Nav: Thin border, no shadow (for nav Sign In buttons)
|
|
43
|
+
nav: "border border-foreground bg-background text-foreground hover:bg-foreground hover:text-background"
|
|
44
|
+
},
|
|
45
|
+
size: {
|
|
46
|
+
xs: "h-7 gap-1 px-2.5 text-xs",
|
|
47
|
+
sm: "h-8 gap-1.5 px-3 text-sm",
|
|
48
|
+
default: "h-10 gap-2 px-5 text-sm",
|
|
49
|
+
lg: "h-12 gap-2 px-7 text-base",
|
|
50
|
+
xl: "h-14 gap-2.5 px-9 text-lg",
|
|
51
|
+
icon: "size-10",
|
|
52
|
+
"icon-sm": "size-8",
|
|
53
|
+
"icon-lg": "size-12"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
defaultVariants: {
|
|
57
|
+
variant: "default",
|
|
58
|
+
size: "default"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
function Button({
|
|
63
|
+
className,
|
|
64
|
+
variant = "default",
|
|
65
|
+
size = "default",
|
|
66
|
+
...props
|
|
67
|
+
}) {
|
|
68
|
+
return /* @__PURE__ */ jsx(
|
|
69
|
+
Button$1,
|
|
70
|
+
{
|
|
71
|
+
"data-slot": "button",
|
|
72
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
73
|
+
...props
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
function Sheet({ ...props }) {
|
|
78
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { "data-slot": "sheet", ...props });
|
|
79
|
+
}
|
|
80
|
+
function SheetPortal({ ...props }) {
|
|
81
|
+
return /* @__PURE__ */ jsx(Dialog.Portal, { "data-slot": "sheet-portal", ...props });
|
|
82
|
+
}
|
|
83
|
+
function SheetOverlay({ className, ...props }) {
|
|
84
|
+
return /* @__PURE__ */ jsx(
|
|
85
|
+
Dialog.Backdrop,
|
|
86
|
+
{
|
|
87
|
+
"data-slot": "sheet-overlay",
|
|
88
|
+
className: cn(
|
|
89
|
+
"fixed inset-0 z-50 bg-black/60 transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0",
|
|
90
|
+
className
|
|
91
|
+
),
|
|
92
|
+
...props
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
function SheetContent({
|
|
97
|
+
className,
|
|
98
|
+
children,
|
|
99
|
+
side = "right",
|
|
100
|
+
showCloseButton = true,
|
|
101
|
+
...props
|
|
102
|
+
}) {
|
|
103
|
+
return /* @__PURE__ */ jsxs(SheetPortal, { children: [
|
|
104
|
+
/* @__PURE__ */ jsx(SheetOverlay, {}),
|
|
105
|
+
/* @__PURE__ */ jsxs(
|
|
106
|
+
Dialog.Popup,
|
|
107
|
+
{
|
|
108
|
+
"data-slot": "sheet-content",
|
|
109
|
+
"data-side": side,
|
|
110
|
+
className: cn(
|
|
111
|
+
"fixed z-50 flex flex-col gap-4 border-brutal border-foreground bg-background bg-clip-padding text-sm shadow-brutal-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
|
|
112
|
+
className
|
|
113
|
+
),
|
|
114
|
+
...props,
|
|
115
|
+
children: [
|
|
116
|
+
children,
|
|
117
|
+
showCloseButton && /* @__PURE__ */ jsxs(
|
|
118
|
+
Dialog.Close,
|
|
119
|
+
{
|
|
120
|
+
"data-slot": "sheet-close",
|
|
121
|
+
render: /* @__PURE__ */ jsx(
|
|
122
|
+
Button,
|
|
123
|
+
{
|
|
124
|
+
variant: "ghost",
|
|
125
|
+
className: "absolute top-3 right-3",
|
|
126
|
+
size: "icon-sm"
|
|
127
|
+
}
|
|
128
|
+
),
|
|
129
|
+
children: [
|
|
130
|
+
/* @__PURE__ */ jsx(
|
|
131
|
+
XIcon,
|
|
132
|
+
{}
|
|
133
|
+
),
|
|
134
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
] });
|
|
142
|
+
}
|
|
143
|
+
function SheetTitle({ className, ...props }) {
|
|
144
|
+
return /* @__PURE__ */ jsx(
|
|
145
|
+
Dialog.Title,
|
|
146
|
+
{
|
|
147
|
+
"data-slot": "sheet-title",
|
|
148
|
+
className: cn("text-base font-bold text-foreground", className),
|
|
149
|
+
...props
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
var AppShellContext = createContext({
|
|
154
|
+
collapsed: false,
|
|
155
|
+
setCollapsed: () => {
|
|
156
|
+
},
|
|
157
|
+
mobileOpen: false,
|
|
158
|
+
setMobileOpen: () => {
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
var useAppShell = () => useContext(AppShellContext);
|
|
162
|
+
function AppShell({
|
|
163
|
+
sidebar,
|
|
164
|
+
header,
|
|
165
|
+
children,
|
|
166
|
+
defaultCollapsed = false,
|
|
167
|
+
className
|
|
168
|
+
}) {
|
|
169
|
+
const [collapsed, setCollapsed] = useState(defaultCollapsed);
|
|
170
|
+
const [mobileOpen, setMobileOpen] = useState(false);
|
|
171
|
+
return /* @__PURE__ */ jsx(
|
|
172
|
+
AppShellContext.Provider,
|
|
173
|
+
{
|
|
174
|
+
value: { collapsed, setCollapsed, mobileOpen, setMobileOpen },
|
|
175
|
+
children: /* @__PURE__ */ jsxs("div", { className: cn("flex h-screen bg-background", className), children: [
|
|
176
|
+
/* @__PURE__ */ jsx(
|
|
177
|
+
"aside",
|
|
178
|
+
{
|
|
179
|
+
className: cn(
|
|
180
|
+
"hidden border-r-brutal border-foreground bg-background transition-all duration-200 md:block",
|
|
181
|
+
collapsed ? "w-16" : "w-64"
|
|
182
|
+
),
|
|
183
|
+
children: sidebar
|
|
184
|
+
}
|
|
185
|
+
),
|
|
186
|
+
/* @__PURE__ */ jsx(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "w-64 p-0 md:hidden", children: [
|
|
187
|
+
/* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
|
|
188
|
+
sidebar
|
|
189
|
+
] }) }),
|
|
190
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
|
|
191
|
+
header && /* @__PURE__ */ jsxs("header", { className: "flex h-14 items-center gap-4 border-b-brutal border-foreground px-6", children: [
|
|
192
|
+
/* @__PURE__ */ jsx(
|
|
193
|
+
Button,
|
|
194
|
+
{
|
|
195
|
+
variant: "ghost",
|
|
196
|
+
size: "sm",
|
|
197
|
+
className: "md:hidden",
|
|
198
|
+
onClick: () => setMobileOpen(true),
|
|
199
|
+
children: "\u2630"
|
|
200
|
+
}
|
|
201
|
+
),
|
|
202
|
+
header
|
|
203
|
+
] }),
|
|
204
|
+
/* @__PURE__ */ jsx("main", { className: "flex-1 overflow-auto p-6", children })
|
|
205
|
+
] })
|
|
206
|
+
] })
|
|
207
|
+
}
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
function Sidebar({
|
|
211
|
+
logo,
|
|
212
|
+
logoCollapsed,
|
|
213
|
+
groups,
|
|
214
|
+
footer,
|
|
215
|
+
className
|
|
216
|
+
}) {
|
|
217
|
+
const { collapsed, setCollapsed } = useAppShell();
|
|
218
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full flex-col", className), children: [
|
|
219
|
+
/* @__PURE__ */ jsxs("div", { className: "flex h-14 items-center justify-between border-b-brutal border-foreground px-4", children: [
|
|
220
|
+
/* @__PURE__ */ jsx("div", { className: "font-black", children: collapsed ? logoCollapsed || logo : logo }),
|
|
221
|
+
/* @__PURE__ */ jsx(
|
|
222
|
+
"button",
|
|
223
|
+
{
|
|
224
|
+
onClick: () => setCollapsed(!collapsed),
|
|
225
|
+
className: "hidden text-xs text-muted-foreground hover:text-foreground md:block",
|
|
226
|
+
children: collapsed ? "\u2192" : "\u2190"
|
|
227
|
+
}
|
|
228
|
+
)
|
|
229
|
+
] }),
|
|
230
|
+
/* @__PURE__ */ jsx("nav", { className: "flex-1 overflow-auto p-2", children: groups.map((group, gi) => /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
231
|
+
group.title && !collapsed && /* @__PURE__ */ jsx("p", { className: "brutal-label mb-2 px-2 text-muted-foreground", children: group.title }),
|
|
232
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5", children: group.links.map((link) => /* @__PURE__ */ jsxs(
|
|
233
|
+
"a",
|
|
234
|
+
{
|
|
235
|
+
href: link.href,
|
|
236
|
+
className: cn(
|
|
237
|
+
"flex items-center gap-3 rounded-sm px-3 py-2 text-sm font-medium transition-colors",
|
|
238
|
+
link.active ? "bg-brand text-brand-foreground" : "hover:bg-secondary",
|
|
239
|
+
collapsed && "justify-center"
|
|
240
|
+
),
|
|
241
|
+
title: collapsed ? link.label : void 0,
|
|
242
|
+
children: [
|
|
243
|
+
/* @__PURE__ */ jsx("span", { className: "size-5 shrink-0", children: link.icon }),
|
|
244
|
+
!collapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
245
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: link.label }),
|
|
246
|
+
link.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "border border-foreground bg-brand-muted px-1.5 font-mono text-[10px] font-bold", children: link.badge })
|
|
247
|
+
] })
|
|
248
|
+
]
|
|
249
|
+
},
|
|
250
|
+
link.href
|
|
251
|
+
)) })
|
|
252
|
+
] }, gi)) }),
|
|
253
|
+
footer && /* @__PURE__ */ jsx("div", { className: "border-t-brutal border-foreground p-3", children: footer })
|
|
254
|
+
] });
|
|
255
|
+
}
|
|
256
|
+
function StatCard({
|
|
257
|
+
label,
|
|
258
|
+
value,
|
|
259
|
+
change,
|
|
260
|
+
changeLabel,
|
|
261
|
+
icon,
|
|
262
|
+
className
|
|
263
|
+
}) {
|
|
264
|
+
return /* @__PURE__ */ jsxs(
|
|
265
|
+
"div",
|
|
266
|
+
{
|
|
267
|
+
className: cn(
|
|
268
|
+
"border-brutal border-foreground bg-background p-5 shadow-brutal",
|
|
269
|
+
className
|
|
270
|
+
),
|
|
271
|
+
children: [
|
|
272
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center justify-between", children: [
|
|
273
|
+
/* @__PURE__ */ jsx("p", { className: "brutal-label text-muted-foreground", children: label }),
|
|
274
|
+
icon && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: icon })
|
|
275
|
+
] }),
|
|
276
|
+
/* @__PURE__ */ jsx("p", { className: "brutal-h1 mb-1", children: value }),
|
|
277
|
+
change !== void 0 && /* @__PURE__ */ jsxs(
|
|
278
|
+
"p",
|
|
279
|
+
{
|
|
280
|
+
className: cn(
|
|
281
|
+
"flex items-center gap-1 font-mono text-xs font-bold",
|
|
282
|
+
change >= 0 ? "text-cta" : "text-destructive"
|
|
283
|
+
),
|
|
284
|
+
children: [
|
|
285
|
+
/* @__PURE__ */ jsx("span", { children: change >= 0 ? "\u2191" : "\u2193" }),
|
|
286
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
287
|
+
Math.abs(change),
|
|
288
|
+
"%"
|
|
289
|
+
] }),
|
|
290
|
+
changeLabel && /* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: changeLabel })
|
|
291
|
+
]
|
|
292
|
+
}
|
|
293
|
+
)
|
|
294
|
+
]
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
function Avatar({
|
|
299
|
+
className,
|
|
300
|
+
size = "default",
|
|
301
|
+
...props
|
|
302
|
+
}) {
|
|
303
|
+
return /* @__PURE__ */ jsx(
|
|
304
|
+
Avatar$1.Root,
|
|
305
|
+
{
|
|
306
|
+
"data-slot": "avatar",
|
|
307
|
+
"data-size": size,
|
|
308
|
+
className: cn(
|
|
309
|
+
"group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten",
|
|
310
|
+
className
|
|
311
|
+
),
|
|
312
|
+
...props
|
|
313
|
+
}
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
function AvatarImage({ className, ...props }) {
|
|
317
|
+
return /* @__PURE__ */ jsx(
|
|
318
|
+
Avatar$1.Image,
|
|
319
|
+
{
|
|
320
|
+
"data-slot": "avatar-image",
|
|
321
|
+
className: cn(
|
|
322
|
+
"aspect-square size-full rounded-full object-cover",
|
|
323
|
+
className
|
|
324
|
+
),
|
|
325
|
+
...props
|
|
326
|
+
}
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
function AvatarFallback({
|
|
330
|
+
className,
|
|
331
|
+
...props
|
|
332
|
+
}) {
|
|
333
|
+
return /* @__PURE__ */ jsx(
|
|
334
|
+
Avatar$1.Fallback,
|
|
335
|
+
{
|
|
336
|
+
"data-slot": "avatar-fallback",
|
|
337
|
+
className: cn(
|
|
338
|
+
"flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs",
|
|
339
|
+
className
|
|
340
|
+
),
|
|
341
|
+
...props
|
|
342
|
+
}
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
function formatDate(d) {
|
|
346
|
+
const date = typeof d === "string" ? new Date(d) : d;
|
|
347
|
+
return date.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
348
|
+
}
|
|
349
|
+
function formatTime(d) {
|
|
350
|
+
const date = typeof d === "string" ? new Date(d) : d;
|
|
351
|
+
return date.toLocaleTimeString("en-US", {
|
|
352
|
+
hour: "numeric",
|
|
353
|
+
minute: "2-digit"
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
function ActivityFeed({
|
|
357
|
+
entries,
|
|
358
|
+
groupByDate = true,
|
|
359
|
+
className
|
|
360
|
+
}) {
|
|
361
|
+
const grouped = groupByDate ? entries.reduce((acc, entry) => {
|
|
362
|
+
const key = formatDate(entry.timestamp);
|
|
363
|
+
(acc[key] ?? (acc[key] = [])).push(entry);
|
|
364
|
+
return acc;
|
|
365
|
+
}, {}) : { "": entries };
|
|
366
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-6", className), children: Object.entries(grouped).map(([date, items]) => /* @__PURE__ */ jsxs("div", { children: [
|
|
367
|
+
date && /* @__PURE__ */ jsx("p", { className: "brutal-label mb-3 text-muted-foreground", children: date }),
|
|
368
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex flex-col gap-0 pl-6", children: [
|
|
369
|
+
/* @__PURE__ */ jsx("div", { className: "absolute bottom-2 left-2 top-2 w-px bg-foreground/10" }),
|
|
370
|
+
items.map((entry) => /* @__PURE__ */ jsxs("div", { className: "relative flex items-start gap-3 py-2", children: [
|
|
371
|
+
/* @__PURE__ */ jsx("div", { className: "absolute left-[-18px] top-3 size-2 border border-foreground bg-brand" }),
|
|
372
|
+
/* @__PURE__ */ jsxs(Avatar, { className: "size-7 shrink-0", children: [
|
|
373
|
+
entry.avatar && /* @__PURE__ */ jsx(AvatarImage, { src: entry.avatar, alt: entry.name }),
|
|
374
|
+
/* @__PURE__ */ jsx(AvatarFallback, { className: "text-[10px]", children: entry.name[0] })
|
|
375
|
+
] }),
|
|
376
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
377
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
|
|
378
|
+
/* @__PURE__ */ jsx("span", { className: "font-bold", children: entry.name }),
|
|
379
|
+
" ",
|
|
380
|
+
entry.action
|
|
381
|
+
] }),
|
|
382
|
+
/* @__PURE__ */ jsx("p", { className: "font-mono text-xs text-muted-foreground", children: formatTime(entry.timestamp) }),
|
|
383
|
+
entry.metadata
|
|
384
|
+
] })
|
|
385
|
+
] }, entry.id))
|
|
386
|
+
] })
|
|
387
|
+
] }, date)) });
|
|
388
|
+
}
|
|
389
|
+
function EmptyState({
|
|
390
|
+
icon,
|
|
391
|
+
headline,
|
|
392
|
+
description,
|
|
393
|
+
ctaText,
|
|
394
|
+
ctaHref,
|
|
395
|
+
onAction,
|
|
396
|
+
className
|
|
397
|
+
}) {
|
|
398
|
+
return /* @__PURE__ */ jsxs(
|
|
399
|
+
"div",
|
|
400
|
+
{
|
|
401
|
+
className: cn(
|
|
402
|
+
"flex flex-col items-center justify-center py-16 text-center",
|
|
403
|
+
className
|
|
404
|
+
),
|
|
405
|
+
children: [
|
|
406
|
+
icon && /* @__PURE__ */ jsx("div", { className: "mb-4 flex size-16 items-center justify-center border-brutal border-foreground bg-secondary text-3xl shadow-brutal-sm", children: icon }),
|
|
407
|
+
/* @__PURE__ */ jsx("h3", { className: "brutal-h3 mb-2", children: headline }),
|
|
408
|
+
description && /* @__PURE__ */ jsx("p", { className: "brutal-body mb-6 max-w-sm text-muted-foreground", children: description }),
|
|
409
|
+
ctaText && (ctaHref ? /* @__PURE__ */ jsx(Button, { variant: "cta", render: /* @__PURE__ */ jsx("a", { href: ctaHref }), children: ctaText }) : /* @__PURE__ */ jsx(Button, { variant: "cta", onClick: onAction, children: ctaText }))
|
|
410
|
+
]
|
|
411
|
+
}
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
function Input({ className, type, ...props }) {
|
|
415
|
+
return /* @__PURE__ */ jsx(
|
|
416
|
+
Input$1,
|
|
417
|
+
{
|
|
418
|
+
type,
|
|
419
|
+
"data-slot": "input",
|
|
420
|
+
className: cn(
|
|
421
|
+
"h-10 w-full min-w-0 rounded-lg border-brutal border-foreground bg-background px-3 py-2 text-base font-medium shadow-brutal-sm transition-all outline-none placeholder:text-muted-foreground focus:shadow-brutal focus:-translate-x-0.5 focus:-translate-y-0.5 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive md:text-sm",
|
|
422
|
+
className
|
|
423
|
+
),
|
|
424
|
+
...props
|
|
425
|
+
}
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
function SearchBar({
|
|
429
|
+
placeholder = "Search...",
|
|
430
|
+
shortcut = "\u2318K",
|
|
431
|
+
value,
|
|
432
|
+
onChange,
|
|
433
|
+
className
|
|
434
|
+
}) {
|
|
435
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
|
|
436
|
+
/* @__PURE__ */ jsx(
|
|
437
|
+
Input,
|
|
438
|
+
{
|
|
439
|
+
type: "search",
|
|
440
|
+
placeholder,
|
|
441
|
+
value,
|
|
442
|
+
onChange: (e) => onChange?.(e.target.value),
|
|
443
|
+
className: "pr-12"
|
|
444
|
+
}
|
|
445
|
+
),
|
|
446
|
+
shortcut && /* @__PURE__ */ jsx("span", { className: "absolute right-2 top-1/2 -translate-y-1/2 border border-foreground bg-secondary px-1.5 font-mono text-[10px] text-muted-foreground", children: shortcut })
|
|
447
|
+
] });
|
|
448
|
+
}
|
|
449
|
+
function DropdownMenu({ ...props }) {
|
|
450
|
+
return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
|
|
451
|
+
}
|
|
452
|
+
function DropdownMenuTrigger({ ...props }) {
|
|
453
|
+
return /* @__PURE__ */ jsx(Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
454
|
+
}
|
|
455
|
+
function DropdownMenuContent({
|
|
456
|
+
align = "start",
|
|
457
|
+
alignOffset = 0,
|
|
458
|
+
side = "bottom",
|
|
459
|
+
sideOffset = 4,
|
|
460
|
+
className,
|
|
461
|
+
...props
|
|
462
|
+
}) {
|
|
463
|
+
return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
|
|
464
|
+
Menu.Positioner,
|
|
465
|
+
{
|
|
466
|
+
className: "isolate z-50 outline-none",
|
|
467
|
+
align,
|
|
468
|
+
alignOffset,
|
|
469
|
+
side,
|
|
470
|
+
sideOffset,
|
|
471
|
+
children: /* @__PURE__ */ jsx(
|
|
472
|
+
Menu.Popup,
|
|
473
|
+
{
|
|
474
|
+
"data-slot": "dropdown-menu-content",
|
|
475
|
+
className: cn("z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg border-brutal border-foreground bg-popover p-1 text-popover-foreground shadow-brutal duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95", className),
|
|
476
|
+
...props
|
|
477
|
+
}
|
|
478
|
+
)
|
|
479
|
+
}
|
|
480
|
+
) });
|
|
481
|
+
}
|
|
482
|
+
function DropdownMenuGroup({ ...props }) {
|
|
483
|
+
return /* @__PURE__ */ jsx(Menu.Group, { "data-slot": "dropdown-menu-group", ...props });
|
|
484
|
+
}
|
|
485
|
+
function DropdownMenuLabel({
|
|
486
|
+
className,
|
|
487
|
+
inset,
|
|
488
|
+
...props
|
|
489
|
+
}) {
|
|
490
|
+
return /* @__PURE__ */ jsx(
|
|
491
|
+
Menu.GroupLabel,
|
|
492
|
+
{
|
|
493
|
+
"data-slot": "dropdown-menu-label",
|
|
494
|
+
"data-inset": inset,
|
|
495
|
+
className: cn(
|
|
496
|
+
"px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
|
|
497
|
+
className
|
|
498
|
+
),
|
|
499
|
+
...props
|
|
500
|
+
}
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
function DropdownMenuItem({
|
|
504
|
+
className,
|
|
505
|
+
inset,
|
|
506
|
+
variant = "default",
|
|
507
|
+
...props
|
|
508
|
+
}) {
|
|
509
|
+
return /* @__PURE__ */ jsx(
|
|
510
|
+
Menu.Item,
|
|
511
|
+
{
|
|
512
|
+
"data-slot": "dropdown-menu-item",
|
|
513
|
+
"data-inset": inset,
|
|
514
|
+
"data-variant": variant,
|
|
515
|
+
className: cn(
|
|
516
|
+
"group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
|
|
517
|
+
className
|
|
518
|
+
),
|
|
519
|
+
...props
|
|
520
|
+
}
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
function DropdownMenuSeparator({
|
|
524
|
+
className,
|
|
525
|
+
...props
|
|
526
|
+
}) {
|
|
527
|
+
return /* @__PURE__ */ jsx(
|
|
528
|
+
Menu.Separator,
|
|
529
|
+
{
|
|
530
|
+
"data-slot": "dropdown-menu-separator",
|
|
531
|
+
className: cn("-mx-1 my-1 h-px bg-border", className),
|
|
532
|
+
...props
|
|
533
|
+
}
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
function UserMenu({ name, email, avatar, items, onSignOut }) {
|
|
537
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
538
|
+
/* @__PURE__ */ jsxs(
|
|
539
|
+
DropdownMenuTrigger,
|
|
540
|
+
{
|
|
541
|
+
className: "inline-flex shrink-0 cursor-pointer items-center gap-2 rounded-lg px-3 py-1.5 text-sm font-medium outline-none hover:bg-secondary",
|
|
542
|
+
children: [
|
|
543
|
+
/* @__PURE__ */ jsxs(Avatar, { className: "size-7", children: [
|
|
544
|
+
avatar && /* @__PURE__ */ jsx(AvatarImage, { src: avatar, alt: name }),
|
|
545
|
+
/* @__PURE__ */ jsx(AvatarFallback, { children: name[0] })
|
|
546
|
+
] }),
|
|
547
|
+
/* @__PURE__ */ jsx("span", { className: "hidden text-sm font-medium sm:inline", children: name })
|
|
548
|
+
]
|
|
549
|
+
}
|
|
550
|
+
),
|
|
551
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-48", children: [
|
|
552
|
+
/* @__PURE__ */ jsxs(DropdownMenuLabel, { children: [
|
|
553
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-bold", children: name }),
|
|
554
|
+
email && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: email })
|
|
555
|
+
] }),
|
|
556
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
557
|
+
items && /* @__PURE__ */ jsx(DropdownMenuGroup, { children: items.map((item) => /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: item.onClick, children: item.href ? /* @__PURE__ */ jsx("a", { href: item.href, children: item.label }) : item.label }, item.label)) }),
|
|
558
|
+
onSignOut && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
559
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
560
|
+
/* @__PURE__ */ jsx(DropdownMenuItem, { onClick: onSignOut, children: "Sign out" })
|
|
561
|
+
] })
|
|
562
|
+
] })
|
|
563
|
+
] });
|
|
564
|
+
}
|
|
565
|
+
var toggleVariants = cva(
|
|
566
|
+
"group/toggle inline-flex items-center justify-center gap-1 rounded-lg text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:border-brutal aria-pressed:border-foreground aria-pressed:bg-muted aria-pressed:shadow-brutal-sm data-[state=on]:border-brutal data-[state=on]:border-foreground data-[state=on]:bg-muted data-[state=on]:shadow-brutal-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
567
|
+
{
|
|
568
|
+
variants: {
|
|
569
|
+
variant: {
|
|
570
|
+
default: "bg-transparent",
|
|
571
|
+
outline: "border-brutal border-foreground bg-transparent shadow-brutal-sm hover:bg-muted"
|
|
572
|
+
},
|
|
573
|
+
size: {
|
|
574
|
+
default: "h-8 min-w-8 px-2",
|
|
575
|
+
sm: "h-7 min-w-7 rounded-[min(var(--radius-md),12px)] px-1.5 text-[0.8rem]",
|
|
576
|
+
lg: "h-9 min-w-9 px-2.5"
|
|
577
|
+
}
|
|
578
|
+
},
|
|
579
|
+
defaultVariants: {
|
|
580
|
+
variant: "default",
|
|
581
|
+
size: "default"
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
);
|
|
585
|
+
var ToggleGroupContext = React.createContext({
|
|
586
|
+
size: "default",
|
|
587
|
+
variant: "default",
|
|
588
|
+
spacing: 0,
|
|
589
|
+
orientation: "horizontal"
|
|
590
|
+
});
|
|
591
|
+
function ToggleGroup({
|
|
592
|
+
className,
|
|
593
|
+
variant,
|
|
594
|
+
size,
|
|
595
|
+
spacing = 0,
|
|
596
|
+
orientation = "horizontal",
|
|
597
|
+
children,
|
|
598
|
+
...props
|
|
599
|
+
}) {
|
|
600
|
+
return /* @__PURE__ */ jsx(
|
|
601
|
+
ToggleGroup$1,
|
|
602
|
+
{
|
|
603
|
+
"data-slot": "toggle-group",
|
|
604
|
+
"data-variant": variant,
|
|
605
|
+
"data-size": size,
|
|
606
|
+
"data-spacing": spacing,
|
|
607
|
+
"data-orientation": orientation,
|
|
608
|
+
style: { "--gap": spacing },
|
|
609
|
+
className: cn(
|
|
610
|
+
"group/toggle-group flex w-fit flex-row items-center gap-[var(--gap)] rounded-lg border-brutal border-foreground data-vertical:flex-col data-vertical:items-stretch",
|
|
611
|
+
className
|
|
612
|
+
),
|
|
613
|
+
...props,
|
|
614
|
+
children: /* @__PURE__ */ jsx(
|
|
615
|
+
ToggleGroupContext.Provider,
|
|
616
|
+
{
|
|
617
|
+
value: { variant, size, spacing, orientation },
|
|
618
|
+
children
|
|
619
|
+
}
|
|
620
|
+
)
|
|
621
|
+
}
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
function ToggleGroupItem({
|
|
625
|
+
className,
|
|
626
|
+
children,
|
|
627
|
+
variant = "default",
|
|
628
|
+
size = "default",
|
|
629
|
+
...props
|
|
630
|
+
}) {
|
|
631
|
+
const context = React.useContext(ToggleGroupContext);
|
|
632
|
+
return /* @__PURE__ */ jsx(
|
|
633
|
+
Toggle,
|
|
634
|
+
{
|
|
635
|
+
"data-slot": "toggle-group-item",
|
|
636
|
+
"data-variant": context.variant || variant,
|
|
637
|
+
"data-size": context.size || size,
|
|
638
|
+
"data-spacing": context.spacing,
|
|
639
|
+
className: cn(
|
|
640
|
+
"shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 focus:z-10 focus-visible:z-10 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-lg group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t",
|
|
641
|
+
toggleVariants({
|
|
642
|
+
variant: context.variant || variant,
|
|
643
|
+
size: context.size || size
|
|
644
|
+
}),
|
|
645
|
+
className
|
|
646
|
+
),
|
|
647
|
+
...props,
|
|
648
|
+
children
|
|
649
|
+
}
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
var viewLabels = {
|
|
653
|
+
table: "Table",
|
|
654
|
+
kanban: "Board",
|
|
655
|
+
grid: "Grid",
|
|
656
|
+
calendar: "Calendar",
|
|
657
|
+
list: "List"
|
|
658
|
+
};
|
|
659
|
+
function ViewSwitcher({
|
|
660
|
+
value,
|
|
661
|
+
onChange,
|
|
662
|
+
views = ["table", "kanban", "grid", "calendar", "list"],
|
|
663
|
+
className
|
|
664
|
+
}) {
|
|
665
|
+
return /* @__PURE__ */ jsx(
|
|
666
|
+
ToggleGroup,
|
|
667
|
+
{
|
|
668
|
+
value: [value],
|
|
669
|
+
onValueChange: (vals) => {
|
|
670
|
+
if (vals.length > 0) {
|
|
671
|
+
onChange(vals[0]);
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
className,
|
|
675
|
+
children: views.map((view) => /* @__PURE__ */ jsx(ToggleGroupItem, { value: view, className: "brutal-label text-xs", children: viewLabels[view] }, view))
|
|
676
|
+
}
|
|
677
|
+
);
|
|
678
|
+
}
|
|
679
|
+
function FileUpload({
|
|
680
|
+
onFiles,
|
|
681
|
+
accept,
|
|
682
|
+
maxFiles = 10,
|
|
683
|
+
maxSize,
|
|
684
|
+
className
|
|
685
|
+
}) {
|
|
686
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
687
|
+
const [files, setFiles] = useState([]);
|
|
688
|
+
const handleFiles = useCallback(
|
|
689
|
+
(newFiles) => {
|
|
690
|
+
const arr = Array.from(newFiles).slice(0, maxFiles);
|
|
691
|
+
setFiles(arr);
|
|
692
|
+
onFiles(arr);
|
|
693
|
+
},
|
|
694
|
+
[maxFiles, onFiles]
|
|
695
|
+
);
|
|
696
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-4", className), children: [
|
|
697
|
+
/* @__PURE__ */ jsxs(
|
|
698
|
+
"div",
|
|
699
|
+
{
|
|
700
|
+
onDragOver: (e) => {
|
|
701
|
+
e.preventDefault();
|
|
702
|
+
setIsDragging(true);
|
|
703
|
+
},
|
|
704
|
+
onDragLeave: () => setIsDragging(false),
|
|
705
|
+
onDrop: (e) => {
|
|
706
|
+
e.preventDefault();
|
|
707
|
+
setIsDragging(false);
|
|
708
|
+
handleFiles(e.dataTransfer.files);
|
|
709
|
+
},
|
|
710
|
+
className: cn(
|
|
711
|
+
"flex cursor-pointer flex-col items-center justify-center border-2 border-dashed border-foreground p-8 text-center transition-colors",
|
|
712
|
+
isDragging && "border-brand bg-brand-muted"
|
|
713
|
+
),
|
|
714
|
+
onClick: () => {
|
|
715
|
+
const input = document.createElement("input");
|
|
716
|
+
input.type = "file";
|
|
717
|
+
input.multiple = maxFiles > 1;
|
|
718
|
+
if (accept) input.accept = accept;
|
|
719
|
+
input.onchange = (e) => {
|
|
720
|
+
const target = e.target;
|
|
721
|
+
if (target.files) handleFiles(target.files);
|
|
722
|
+
};
|
|
723
|
+
input.click();
|
|
724
|
+
},
|
|
725
|
+
children: [
|
|
726
|
+
/* @__PURE__ */ jsx("p", { className: "brutal-h4 mb-1", children: "Drop files here" }),
|
|
727
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "or click to browse" }),
|
|
728
|
+
maxSize && /* @__PURE__ */ jsxs("p", { className: "mt-2 font-mono text-xs text-muted-foreground", children: [
|
|
729
|
+
"Max ",
|
|
730
|
+
Math.round(maxSize / 1024 / 1024),
|
|
731
|
+
"MB"
|
|
732
|
+
] })
|
|
733
|
+
]
|
|
734
|
+
}
|
|
735
|
+
),
|
|
736
|
+
files.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: files.map((file, i) => /* @__PURE__ */ jsxs(
|
|
737
|
+
"div",
|
|
738
|
+
{
|
|
739
|
+
className: "flex items-center justify-between border border-foreground bg-secondary px-3 py-2 text-sm",
|
|
740
|
+
children: [
|
|
741
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: file.name }),
|
|
742
|
+
/* @__PURE__ */ jsxs("span", { className: "font-mono text-xs text-muted-foreground", children: [
|
|
743
|
+
(file.size / 1024).toFixed(0),
|
|
744
|
+
"KB"
|
|
745
|
+
] })
|
|
746
|
+
]
|
|
747
|
+
},
|
|
748
|
+
i
|
|
749
|
+
)) })
|
|
750
|
+
] });
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
export { ActivityFeed, AppShell, EmptyState, FileUpload, SearchBar, Sidebar, StatCard, UserMenu, ViewSwitcher, useAppShell };
|
|
754
|
+
//# sourceMappingURL=index.js.map
|
|
755
|
+
//# sourceMappingURL=index.js.map
|