@classytic/fluid 0.2.1 → 0.3.2
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/LICENSE +21 -0
- package/README.md +149 -62
- package/dist/api-pagination-CJ0vR_w6.d.mts +34 -0
- package/dist/api-pagination-DBTE0yk4.mjs +190 -0
- package/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/client/calendar.d.mts +105 -0
- package/dist/client/calendar.mjs +202 -0
- package/dist/client/core.d.mts +1614 -0
- package/dist/client/core.mjs +2779 -0
- package/dist/client/error.d.mts +125 -0
- package/dist/client/error.mjs +166 -0
- package/dist/client/hooks.d.mts +162 -0
- package/dist/client/hooks.mjs +447 -0
- package/dist/client/table.d.mts +84 -0
- package/dist/client/table.mjs +373 -0
- package/dist/client/theme.d.mts +6 -0
- package/dist/client/theme.mjs +65 -0
- package/dist/command.d.mts +134 -0
- package/dist/command.mjs +132 -0
- package/dist/compact.d.mts +359 -0
- package/dist/compact.mjs +892 -0
- package/dist/dashboard.d.mts +778 -0
- package/dist/dashboard.mjs +1617 -0
- package/dist/filter-utils-DqMmy_v-.mjs +72 -0
- package/dist/filter-utils-IZ0GtuPo.d.mts +40 -0
- package/dist/forms.d.mts +1549 -0
- package/dist/forms.mjs +3740 -0
- package/dist/index.d.mts +296 -0
- package/dist/index.mjs +432 -0
- package/dist/layouts.d.mts +215 -0
- package/dist/layouts.mjs +460 -0
- package/dist/search-context-DR7DBs7S.mjs +19 -0
- package/dist/search.d.mts +254 -0
- package/dist/search.mjs +523 -0
- package/dist/sheet-wrapper-CWNCvYMD.mjs +211 -0
- package/dist/use-base-search-BGgWnWaF.d.mts +35 -0
- package/dist/use-debounce-xmZucz5e.mjs +53 -0
- package/dist/use-keyboard-shortcut-Bl6YM5Q7.mjs +82 -0
- package/dist/use-keyboard-shortcut-_mRCh3QO.d.mts +24 -0
- package/dist/use-media-query-BnVNIKT4.mjs +17 -0
- package/dist/use-mobile-BX3SQVo2.mjs +20 -0
- package/dist/use-scroll-detection-CsgsQYvy.mjs +43 -0
- package/dist/utils-CDue7cEt.d.mts +6 -0
- package/dist/utils-DQ5SCVoW.mjs +10 -0
- package/package.json +85 -45
- package/styles.css +2 -2
- package/dist/chunk-GUHK2DTW.js +0 -15
- package/dist/chunk-GUHK2DTW.js.map +0 -1
- package/dist/chunk-H3NFL3GJ.js +0 -57
- package/dist/chunk-H3NFL3GJ.js.map +0 -1
- package/dist/chunk-J2YRTQE4.js +0 -293
- package/dist/chunk-J2YRTQE4.js.map +0 -1
- package/dist/compact.d.ts +0 -217
- package/dist/compact.js +0 -986
- package/dist/compact.js.map +0 -1
- package/dist/dashboard.d.ts +0 -386
- package/dist/dashboard.js +0 -1032
- package/dist/dashboard.js.map +0 -1
- package/dist/index.d.ts +0 -2141
- package/dist/index.js +0 -6460
- package/dist/index.js.map +0 -1
- package/dist/layout.d.ts +0 -25
- package/dist/layout.js +0 -4
- package/dist/layout.js.map +0 -1
- package/dist/search.d.ts +0 -172
- package/dist/search.js +0 -341
- package/dist/search.js.map +0 -1
- package/dist/use-base-search-AS5Z3SAy.d.ts +0 -64
- package/dist/utils-Cbsgs0XP.d.ts +0 -5
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { t as cn } from "./utils-DQ5SCVoW.mjs";
|
|
2
|
+
import { a as getApiParams, i as clearSearchAndFilterParams, n as buildListingStatusParams, r as buildSearchParams, t as buildFilterParams } from "./filter-utils-DqMmy_v-.mjs";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
5
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
|
6
|
+
import "react";
|
|
7
|
+
import { FileX2, InboxIcon, Loader2, SearchX } from "lucide-react";
|
|
8
|
+
import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "@/components/ui/empty";
|
|
9
|
+
|
|
10
|
+
//#region src/layout/section.tsx
|
|
11
|
+
const backgrounds = {
|
|
12
|
+
default: "bg-background",
|
|
13
|
+
muted: "bg-muted",
|
|
14
|
+
primary: "bg-primary text-primary-foreground",
|
|
15
|
+
transparent: "bg-transparent"
|
|
16
|
+
};
|
|
17
|
+
const paddings = {
|
|
18
|
+
none: "",
|
|
19
|
+
sm: "py-8 md:py-12",
|
|
20
|
+
md: "py-12 md:py-16",
|
|
21
|
+
lg: "py-16 md:py-24",
|
|
22
|
+
xl: "py-24 md:py-32"
|
|
23
|
+
};
|
|
24
|
+
function Section({ id, children, className, background = "default", padding = "sm" }) {
|
|
25
|
+
return /* @__PURE__ */ jsx("section", {
|
|
26
|
+
id,
|
|
27
|
+
className: cn(backgrounds[background], paddings[padding], className),
|
|
28
|
+
children
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/layout/container.tsx
|
|
34
|
+
const maxWidthClasses = {
|
|
35
|
+
sm: "max-w-screen-sm",
|
|
36
|
+
md: "max-w-screen-md",
|
|
37
|
+
lg: "max-w-screen-lg",
|
|
38
|
+
xl: "max-w-screen-xl",
|
|
39
|
+
"2xl": "max-w-screen-2xl",
|
|
40
|
+
"3xl": "max-w-3xl",
|
|
41
|
+
"4xl": "max-w-4xl",
|
|
42
|
+
"5xl": "max-w-5xl",
|
|
43
|
+
"6xl": "max-w-6xl",
|
|
44
|
+
"7xl": "max-w-7xl",
|
|
45
|
+
full: "max-w-full"
|
|
46
|
+
};
|
|
47
|
+
function Container({ children, className, maxWidth = "7xl" }) {
|
|
48
|
+
const isFullWidth = maxWidth === "full";
|
|
49
|
+
return /* @__PURE__ */ jsx("div", {
|
|
50
|
+
className: cn(isFullWidth ? "w-full px-4 sm:px-6 lg:px-10" : "mx-auto px-4 sm:px-6 lg:px-8", !isFullWidth && maxWidthClasses[maxWidth], className),
|
|
51
|
+
children
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/components/display-heading.tsx
|
|
57
|
+
/**
|
|
58
|
+
* DisplayHeading - Reusable component for hero/display headings
|
|
59
|
+
* Provides consistent typography across the platform
|
|
60
|
+
*/
|
|
61
|
+
function DisplayHeading({ children, size = "xl", align = "center", className, highlightText, highlightColor = "primary", as: Component = "h1", ...props }) {
|
|
62
|
+
const sizeClasses = {
|
|
63
|
+
lg: "text-3xl lg:text-5xl",
|
|
64
|
+
xl: "text-4xl lg:text-6xl",
|
|
65
|
+
"2xl": "text-5xl lg:text-7xl"
|
|
66
|
+
};
|
|
67
|
+
const alignClasses = {
|
|
68
|
+
left: "text-left",
|
|
69
|
+
center: "text-center",
|
|
70
|
+
right: "text-right"
|
|
71
|
+
};
|
|
72
|
+
const highlightClasses = {
|
|
73
|
+
primary: "text-primary",
|
|
74
|
+
secondary: "text-secondary",
|
|
75
|
+
accent: "text-accent",
|
|
76
|
+
gradient: "bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent"
|
|
77
|
+
};
|
|
78
|
+
const renderContent = () => {
|
|
79
|
+
if (typeof children !== "string" || !highlightText) return children;
|
|
80
|
+
const parts = children.split(highlightText);
|
|
81
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
82
|
+
parts[0],
|
|
83
|
+
/* @__PURE__ */ jsx("span", {
|
|
84
|
+
className: highlightClasses[highlightColor],
|
|
85
|
+
children: highlightText
|
|
86
|
+
}),
|
|
87
|
+
parts[1]
|
|
88
|
+
] });
|
|
89
|
+
};
|
|
90
|
+
return /* @__PURE__ */ jsx(Component, {
|
|
91
|
+
className: cn("font-bold tracking-tight text-balance leading-[1.1]", sizeClasses[size], alignClasses[align], className),
|
|
92
|
+
...props,
|
|
93
|
+
children: renderContent()
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/components/social-icons.tsx
|
|
99
|
+
const FacebookIcon = () => /* @__PURE__ */ jsx("svg", {
|
|
100
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
101
|
+
width: "18",
|
|
102
|
+
height: "18",
|
|
103
|
+
viewBox: "0 0 24 24",
|
|
104
|
+
fill: "none",
|
|
105
|
+
stroke: "currentColor",
|
|
106
|
+
strokeWidth: "2",
|
|
107
|
+
strokeLinecap: "round",
|
|
108
|
+
strokeLinejoin: "round",
|
|
109
|
+
children: /* @__PURE__ */ jsx("path", { d: "M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z" })
|
|
110
|
+
});
|
|
111
|
+
const GoogleIcon = () => /* @__PURE__ */ jsxs("svg", {
|
|
112
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
113
|
+
width: "18",
|
|
114
|
+
height: "18",
|
|
115
|
+
viewBox: "0 0 24 24",
|
|
116
|
+
fill: "currentColor",
|
|
117
|
+
children: [
|
|
118
|
+
/* @__PURE__ */ jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" }),
|
|
119
|
+
/* @__PURE__ */ jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" }),
|
|
120
|
+
/* @__PURE__ */ jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" }),
|
|
121
|
+
/* @__PURE__ */ jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" })
|
|
122
|
+
]
|
|
123
|
+
});
|
|
124
|
+
const TwitterXIcon = () => /* @__PURE__ */ jsx("svg", {
|
|
125
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
126
|
+
viewBox: "0 0 1200 1227",
|
|
127
|
+
width: "18",
|
|
128
|
+
height: "18",
|
|
129
|
+
fill: "currentColor",
|
|
130
|
+
children: /* @__PURE__ */ jsx("path", { d: "M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z" })
|
|
131
|
+
});
|
|
132
|
+
const InstagramIcon = () => /* @__PURE__ */ jsxs("svg", {
|
|
133
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
134
|
+
width: "18",
|
|
135
|
+
height: "18",
|
|
136
|
+
viewBox: "0 0 24 24",
|
|
137
|
+
fill: "none",
|
|
138
|
+
stroke: "currentColor",
|
|
139
|
+
strokeWidth: "2",
|
|
140
|
+
strokeLinecap: "round",
|
|
141
|
+
strokeLinejoin: "round",
|
|
142
|
+
children: [
|
|
143
|
+
/* @__PURE__ */ jsx("rect", {
|
|
144
|
+
x: "2",
|
|
145
|
+
y: "2",
|
|
146
|
+
width: "20",
|
|
147
|
+
height: "20",
|
|
148
|
+
rx: "5",
|
|
149
|
+
ry: "5"
|
|
150
|
+
}),
|
|
151
|
+
/* @__PURE__ */ jsx("path", { d: "M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" }),
|
|
152
|
+
/* @__PURE__ */ jsx("line", {
|
|
153
|
+
x1: "17.5",
|
|
154
|
+
y1: "6.5",
|
|
155
|
+
x2: "17.51",
|
|
156
|
+
y2: "6.5"
|
|
157
|
+
})
|
|
158
|
+
]
|
|
159
|
+
});
|
|
160
|
+
const WhatsAppIcon = () => /* @__PURE__ */ jsx("svg", {
|
|
161
|
+
viewBox: "0 0 24 24",
|
|
162
|
+
fill: "currentColor",
|
|
163
|
+
width: "18",
|
|
164
|
+
height: "18",
|
|
165
|
+
children: /* @__PURE__ */ jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" })
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/components/skeleton-wrappers.tsx
|
|
170
|
+
/**
|
|
171
|
+
* SkeletonTable - Loading skeleton for tables
|
|
172
|
+
* Matches DataTable structure for consistent loading states
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```tsx
|
|
176
|
+
* <SkeletonTable rows={5} columns={4} />
|
|
177
|
+
* <SkeletonTable headers={["Name", "Email", "Status"]} rows={10} />
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
function SkeletonTable({ rows = 5, columns = 6, headers, className }) {
|
|
181
|
+
const columnCount = headers?.length || columns;
|
|
182
|
+
return /* @__PURE__ */ jsx("div", {
|
|
183
|
+
className: cn("rounded-md border", className),
|
|
184
|
+
children: /* @__PURE__ */ jsxs(Table, { children: [/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { children: headers ? headers.map((header, i) => /* @__PURE__ */ jsx(TableHead, { children: header }, i)) : Array.from({ length: columnCount }).map((_, i) => /* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }) }, i)) }) }), /* @__PURE__ */ jsx(TableBody, { children: Array.from({ length: rows }).map((_, rowIndex) => /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: columnCount }).map((_, colIndex) => /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }) }, colIndex)) }, rowIndex)) })] })
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* SkeletonList - Compact skeleton for lists with avatars
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```tsx
|
|
192
|
+
* <SkeletonList items={5} />
|
|
193
|
+
* <SkeletonList items={3} showAvatar={false} />
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
function SkeletonList({ items = 3, className, showAvatar = true, avatarShape = "circle" }) {
|
|
197
|
+
return /* @__PURE__ */ jsx("div", {
|
|
198
|
+
className: cn("space-y-3", className),
|
|
199
|
+
children: Array.from({ length: items }).map((_, i) => /* @__PURE__ */ jsxs("div", {
|
|
200
|
+
className: "flex items-center gap-3",
|
|
201
|
+
children: [showAvatar && /* @__PURE__ */ jsx(Skeleton, { className: cn("h-10 w-10 flex-shrink-0", avatarShape === "circle" ? "rounded-full" : "rounded-md") }), /* @__PURE__ */ jsxs("div", {
|
|
202
|
+
className: "flex-1 space-y-2",
|
|
203
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-3/4" })]
|
|
204
|
+
})]
|
|
205
|
+
}, i))
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* SkeletonCard - Card skeleton for grid layouts
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```tsx
|
|
213
|
+
* <SkeletonCard />
|
|
214
|
+
* <SkeletonCard showActions={false} lines={2} />
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
function SkeletonCard({ className, showActions = true, lines = 3 }) {
|
|
218
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
219
|
+
className: cn("rounded-lg border p-4 space-y-3", className),
|
|
220
|
+
children: [
|
|
221
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-3/4" }),
|
|
222
|
+
Array.from({ length: lines - 1 }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: cn("h-4", i === lines - 2 ? "w-5/6" : "w-full") }, i)),
|
|
223
|
+
showActions && /* @__PURE__ */ jsxs("div", {
|
|
224
|
+
className: "flex gap-2 pt-2",
|
|
225
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" })]
|
|
226
|
+
})
|
|
227
|
+
]
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* SkeletonGrid - Grid of skeleton cards
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```tsx
|
|
235
|
+
* <SkeletonGrid cards={6} columns={3} />
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
function SkeletonGrid({ cards = 6, columns = 3, className, cardProps }) {
|
|
239
|
+
return /* @__PURE__ */ jsx("div", {
|
|
240
|
+
className: cn("grid gap-4", {
|
|
241
|
+
1: "grid-cols-1",
|
|
242
|
+
2: "grid-cols-1 sm:grid-cols-2",
|
|
243
|
+
3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
244
|
+
4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
|
|
245
|
+
}[columns], className),
|
|
246
|
+
children: Array.from({ length: cards }).map((_, i) => /* @__PURE__ */ jsx(SkeletonCard, { ...cardProps }, i))
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/components/loading-state.tsx
|
|
252
|
+
const SIZES = {
|
|
253
|
+
sm: "h-4 w-4",
|
|
254
|
+
md: "h-6 w-6",
|
|
255
|
+
lg: "h-10 w-10"
|
|
256
|
+
};
|
|
257
|
+
const TEXT_SIZES = {
|
|
258
|
+
sm: "text-xs",
|
|
259
|
+
md: "text-sm",
|
|
260
|
+
lg: "text-base"
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* LoadingState — Versatile loading indicator
|
|
264
|
+
*
|
|
265
|
+
* @example Default (centered, full area)
|
|
266
|
+
* ```tsx
|
|
267
|
+
* <LoadingState text="Loading projects..." />
|
|
268
|
+
* ```
|
|
269
|
+
*
|
|
270
|
+
* @example Inline (in a row)
|
|
271
|
+
* ```tsx
|
|
272
|
+
* <LoadingState variant="inline" text="Saving..." size="sm" />
|
|
273
|
+
* ```
|
|
274
|
+
*
|
|
275
|
+
* @example Minimal (just the spinner)
|
|
276
|
+
* ```tsx
|
|
277
|
+
* <LoadingState variant="minimal" />
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
function LoadingState({ text, variant = "default", size = "md", className }) {
|
|
281
|
+
const spinner = /* @__PURE__ */ jsx(Loader2, { className: cn(SIZES[size], "animate-spin text-muted-foreground") });
|
|
282
|
+
if (variant === "minimal") return /* @__PURE__ */ jsx("div", {
|
|
283
|
+
className: cn("flex items-center justify-center", className),
|
|
284
|
+
children: spinner
|
|
285
|
+
});
|
|
286
|
+
if (variant === "inline") return /* @__PURE__ */ jsxs("div", {
|
|
287
|
+
className: cn("flex items-center gap-2 text-muted-foreground", className),
|
|
288
|
+
children: [spinner, text && /* @__PURE__ */ jsx("span", {
|
|
289
|
+
className: TEXT_SIZES[size],
|
|
290
|
+
children: text
|
|
291
|
+
})]
|
|
292
|
+
});
|
|
293
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
294
|
+
className: cn("flex flex-col items-center justify-center gap-3 py-12 px-6", className),
|
|
295
|
+
children: [spinner, text && /* @__PURE__ */ jsx("p", {
|
|
296
|
+
className: cn("text-muted-foreground", TEXT_SIZES[size]),
|
|
297
|
+
children: text
|
|
298
|
+
})]
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* LoadingOverlay — Renders children with an overlay spinner on top
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```tsx
|
|
306
|
+
* <LoadingOverlay visible={isSaving} text="Saving changes...">
|
|
307
|
+
* <MyFormContent />
|
|
308
|
+
* </LoadingOverlay>
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
function LoadingOverlay({ text, visible = true, className, children }) {
|
|
312
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
313
|
+
className: cn("relative", className),
|
|
314
|
+
children: [children, visible && /* @__PURE__ */ jsxs("div", {
|
|
315
|
+
className: "absolute inset-0 z-10 flex flex-col items-center justify-center gap-3 rounded-[inherit] bg-background/90 backdrop-blur-sm",
|
|
316
|
+
children: [/* @__PURE__ */ jsx(Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground" }), text && /* @__PURE__ */ jsx("p", {
|
|
317
|
+
className: "text-sm text-muted-foreground font-medium",
|
|
318
|
+
children: text
|
|
319
|
+
})]
|
|
320
|
+
})]
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
//#endregion
|
|
325
|
+
//#region src/components/empty-state.tsx
|
|
326
|
+
const PRESETS = {
|
|
327
|
+
noResults: {
|
|
328
|
+
icon: /* @__PURE__ */ jsx(SearchX, { className: "h-6 w-6" }),
|
|
329
|
+
title: "No results found",
|
|
330
|
+
description: "Try adjusting your search or filter criteria."
|
|
331
|
+
},
|
|
332
|
+
noData: {
|
|
333
|
+
icon: /* @__PURE__ */ jsx(InboxIcon, { className: "h-6 w-6" }),
|
|
334
|
+
title: "No data yet",
|
|
335
|
+
description: "Get started by creating your first item."
|
|
336
|
+
},
|
|
337
|
+
notFound: {
|
|
338
|
+
icon: /* @__PURE__ */ jsx(FileX2, { className: "h-6 w-6" }),
|
|
339
|
+
title: "Not found",
|
|
340
|
+
description: "The item you're looking for doesn't exist or has been removed."
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
/**
|
|
344
|
+
* EmptyState — Higher-level wrapper around the composable Empty primitives.
|
|
345
|
+
*
|
|
346
|
+
* Composes: Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent
|
|
347
|
+
*
|
|
348
|
+
* @example Default
|
|
349
|
+
* ```tsx
|
|
350
|
+
* <EmptyState
|
|
351
|
+
* title="No projects yet"
|
|
352
|
+
* description="Create your first project to get started."
|
|
353
|
+
* icon={<FolderPlus className="h-6 w-6" />}
|
|
354
|
+
* action={<Button>Create Project</Button>}
|
|
355
|
+
* />
|
|
356
|
+
* ```
|
|
357
|
+
*
|
|
358
|
+
* @example Compact (inline)
|
|
359
|
+
* ```tsx
|
|
360
|
+
* <EmptyState variant="compact" title="No items" />
|
|
361
|
+
* ```
|
|
362
|
+
*
|
|
363
|
+
* @example With preset
|
|
364
|
+
* ```tsx
|
|
365
|
+
* <EmptyStateNoResults action={<Button onClick={clearFilters}>Clear filters</Button>} />
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
function EmptyState({ title = "Nothing here", description, icon = /* @__PURE__ */ jsx(InboxIcon, { className: "h-6 w-6" }), action, secondaryAction, variant = "default", className, children }) {
|
|
369
|
+
if (variant === "compact") return /* @__PURE__ */ jsxs("div", {
|
|
370
|
+
"data-slot": "empty-state",
|
|
371
|
+
className: cn("flex items-center gap-3 py-6 px-4 text-muted-foreground", className),
|
|
372
|
+
children: [
|
|
373
|
+
icon && /* @__PURE__ */ jsx("div", {
|
|
374
|
+
className: "flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
375
|
+
children: icon
|
|
376
|
+
}),
|
|
377
|
+
/* @__PURE__ */ jsxs("div", {
|
|
378
|
+
className: "flex-1 min-w-0",
|
|
379
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
380
|
+
className: "text-sm font-medium",
|
|
381
|
+
children: title
|
|
382
|
+
}), description && /* @__PURE__ */ jsx("p", {
|
|
383
|
+
className: "text-xs text-muted-foreground/80 mt-0.5",
|
|
384
|
+
children: description
|
|
385
|
+
})]
|
|
386
|
+
}),
|
|
387
|
+
action
|
|
388
|
+
]
|
|
389
|
+
});
|
|
390
|
+
return /* @__PURE__ */ jsxs(Empty, {
|
|
391
|
+
className: cn(variant === "card" && "border border-dashed", className),
|
|
392
|
+
children: [
|
|
393
|
+
/* @__PURE__ */ jsxs(EmptyHeader, { children: [
|
|
394
|
+
icon && /* @__PURE__ */ jsx(EmptyMedia, {
|
|
395
|
+
variant: "icon",
|
|
396
|
+
children: icon
|
|
397
|
+
}),
|
|
398
|
+
/* @__PURE__ */ jsx(EmptyTitle, { children: title }),
|
|
399
|
+
description && /* @__PURE__ */ jsx(EmptyDescription, { children: description })
|
|
400
|
+
] }),
|
|
401
|
+
children && /* @__PURE__ */ jsx(EmptyContent, { children }),
|
|
402
|
+
(action || secondaryAction) && /* @__PURE__ */ jsx(EmptyContent, { children: /* @__PURE__ */ jsxs("div", {
|
|
403
|
+
className: "flex items-center gap-3",
|
|
404
|
+
children: [action, secondaryAction]
|
|
405
|
+
}) })
|
|
406
|
+
]
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
/** No search results — with search icon */
|
|
410
|
+
function EmptyStateNoResults(props) {
|
|
411
|
+
return /* @__PURE__ */ jsx(EmptyState, {
|
|
412
|
+
...PRESETS.noResults,
|
|
413
|
+
...props
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
/** No data — with inbox icon */
|
|
417
|
+
function EmptyStateNoData(props) {
|
|
418
|
+
return /* @__PURE__ */ jsx(EmptyState, {
|
|
419
|
+
...PRESETS.noData,
|
|
420
|
+
...props
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
/** Not found — with file-x icon */
|
|
424
|
+
function EmptyStateNotFound(props) {
|
|
425
|
+
return /* @__PURE__ */ jsx(EmptyState, {
|
|
426
|
+
...PRESETS.notFound,
|
|
427
|
+
...props
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
//#endregion
|
|
432
|
+
export { Container, DisplayHeading, EmptyState, EmptyStateNoData, EmptyStateNoResults, EmptyStateNotFound, FacebookIcon, GoogleIcon, InstagramIcon, LoadingOverlay, LoadingState, Section, SkeletonCard, SkeletonGrid, SkeletonList, SkeletonTable, TwitterXIcon, WhatsAppIcon, buildFilterParams, buildListingStatusParams, buildSearchParams, clearSearchAndFilterParams, cn, getApiParams };
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
+
import * as react from "react";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import { LucideIcon } from "lucide-react";
|
|
5
|
+
|
|
6
|
+
//#region src/components/drawer-wrapper.d.ts
|
|
7
|
+
declare const DRAWER_SIZE_CLASSES: {
|
|
8
|
+
readonly horizontal: {
|
|
9
|
+
readonly sm: "data-[vaul-drawer-direction=right]:sm:max-w-xs data-[vaul-drawer-direction=left]:sm:max-w-xs";
|
|
10
|
+
readonly default: "data-[vaul-drawer-direction=right]:sm:max-w-sm data-[vaul-drawer-direction=left]:sm:max-w-sm";
|
|
11
|
+
readonly md: "data-[vaul-drawer-direction=right]:sm:max-w-md data-[vaul-drawer-direction=left]:sm:max-w-md";
|
|
12
|
+
readonly lg: "data-[vaul-drawer-direction=right]:w-full data-[vaul-drawer-direction=right]:sm:max-w-lg data-[vaul-drawer-direction=right]:md:max-w-2xl data-[vaul-drawer-direction=left]:w-full data-[vaul-drawer-direction=left]:sm:max-w-lg data-[vaul-drawer-direction=left]:md:max-w-2xl";
|
|
13
|
+
readonly xl: "data-[vaul-drawer-direction=right]:w-full data-[vaul-drawer-direction=right]:sm:max-w-2xl data-[vaul-drawer-direction=right]:md:max-w-4xl data-[vaul-drawer-direction=left]:w-full data-[vaul-drawer-direction=left]:sm:max-w-2xl data-[vaul-drawer-direction=left]:md:max-w-4xl";
|
|
14
|
+
readonly full: "data-[vaul-drawer-direction=right]:w-full data-[vaul-drawer-direction=right]:max-w-full data-[vaul-drawer-direction=right]:sm:max-w-full data-[vaul-drawer-direction=left]:w-full data-[vaul-drawer-direction=left]:max-w-full data-[vaul-drawer-direction=left]:sm:max-w-full";
|
|
15
|
+
};
|
|
16
|
+
readonly vertical: {
|
|
17
|
+
readonly sm: "max-h-[40vh]";
|
|
18
|
+
readonly default: "max-h-[80vh]";
|
|
19
|
+
readonly md: "max-h-[60vh]";
|
|
20
|
+
readonly lg: "max-h-[80vh]";
|
|
21
|
+
readonly xl: "max-h-[90vh]";
|
|
22
|
+
readonly full: "max-h-screen h-screen";
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
type DrawerSizeVariant = keyof (typeof DRAWER_SIZE_CLASSES)["vertical"];
|
|
26
|
+
interface DrawerWrapperProps {
|
|
27
|
+
open: boolean;
|
|
28
|
+
onOpenChange: (open: boolean) => void;
|
|
29
|
+
title?: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
footer?: ReactNode;
|
|
33
|
+
trigger?: ReactNode;
|
|
34
|
+
direction?: "top" | "bottom" | "left" | "right";
|
|
35
|
+
/** Named size preset. For left/right: controls width. For top/bottom: controls height. */
|
|
36
|
+
size?: DrawerSizeVariant;
|
|
37
|
+
className?: string;
|
|
38
|
+
headerClassName?: string;
|
|
39
|
+
contentClassName?: string;
|
|
40
|
+
footerClassName?: string;
|
|
41
|
+
hideHeader?: boolean;
|
|
42
|
+
hideTitle?: boolean;
|
|
43
|
+
hideDescription?: boolean;
|
|
44
|
+
/** Show an X close button (useful for full-size or side drawers) */
|
|
45
|
+
showCloseButton?: boolean;
|
|
46
|
+
/** Whether to show the drag handle indicator (bottom drawers only) */
|
|
47
|
+
showHandle?: boolean;
|
|
48
|
+
/** Snap points for drawer positioning */
|
|
49
|
+
snapPoints?: (number | string)[];
|
|
50
|
+
/** Whether drawer should scale background */
|
|
51
|
+
shouldScaleBackground?: boolean;
|
|
52
|
+
}
|
|
53
|
+
declare const DrawerWrapper: react.NamedExoticComponent<DrawerWrapperProps>;
|
|
54
|
+
interface FormDrawerProps extends Omit<DrawerWrapperProps, "footer"> {
|
|
55
|
+
onSubmit?: () => void;
|
|
56
|
+
onCancel?: () => void;
|
|
57
|
+
submitLabel?: string;
|
|
58
|
+
cancelLabel?: string;
|
|
59
|
+
submitDisabled?: boolean;
|
|
60
|
+
submitLoading?: boolean;
|
|
61
|
+
}
|
|
62
|
+
declare const FormDrawer: react.NamedExoticComponent<FormDrawerProps>;
|
|
63
|
+
interface ConfirmDrawerProps extends Omit<DrawerWrapperProps, "footer"> {
|
|
64
|
+
onConfirm?: () => void;
|
|
65
|
+
onCancel?: () => void;
|
|
66
|
+
confirmLabel?: string;
|
|
67
|
+
cancelLabel?: string;
|
|
68
|
+
confirmVariant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";
|
|
69
|
+
confirmDisabled?: boolean;
|
|
70
|
+
confirmLoading?: boolean;
|
|
71
|
+
}
|
|
72
|
+
declare const ConfirmDrawer: react.NamedExoticComponent<ConfirmDrawerProps>;
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/components/navigation-bar.d.ts
|
|
75
|
+
interface NavBarLink {
|
|
76
|
+
title: string;
|
|
77
|
+
href: string;
|
|
78
|
+
description?: string;
|
|
79
|
+
icon?: LucideIcon;
|
|
80
|
+
isActive?: boolean;
|
|
81
|
+
external?: boolean;
|
|
82
|
+
}
|
|
83
|
+
interface NavBarDropdown {
|
|
84
|
+
title: string;
|
|
85
|
+
icon?: LucideIcon;
|
|
86
|
+
items: NavBarLink[];
|
|
87
|
+
/** Grid columns for the dropdown (1-3) */
|
|
88
|
+
columns?: 1 | 2 | 3;
|
|
89
|
+
/** Featured item shown separately */
|
|
90
|
+
featured?: {
|
|
91
|
+
title: string;
|
|
92
|
+
description: string;
|
|
93
|
+
href: string;
|
|
94
|
+
icon?: react.ReactNode;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
type NavBarItem = NavBarLink | NavBarDropdown;
|
|
98
|
+
interface NavBarBrand {
|
|
99
|
+
title: string;
|
|
100
|
+
icon?: react.ReactNode;
|
|
101
|
+
href?: string;
|
|
102
|
+
}
|
|
103
|
+
interface NavigationBarProps {
|
|
104
|
+
/** Brand / logo section */
|
|
105
|
+
brand: NavBarBrand;
|
|
106
|
+
/** Navigation items */
|
|
107
|
+
items: NavBarItem[];
|
|
108
|
+
/** Right-side content (e.g., auth buttons, avatar) */
|
|
109
|
+
actions?: react.ReactNode;
|
|
110
|
+
/** Sticky positioning */
|
|
111
|
+
sticky?: boolean;
|
|
112
|
+
/** Show border at bottom */
|
|
113
|
+
bordered?: boolean;
|
|
114
|
+
/** Additional className */
|
|
115
|
+
className?: string;
|
|
116
|
+
/** Mobile breakpoint for showing hamburger */
|
|
117
|
+
mobileBreakpoint?: "sm" | "md" | "lg";
|
|
118
|
+
}
|
|
119
|
+
declare function NavigationBar({
|
|
120
|
+
brand,
|
|
121
|
+
items,
|
|
122
|
+
actions,
|
|
123
|
+
sticky,
|
|
124
|
+
bordered,
|
|
125
|
+
className,
|
|
126
|
+
mobileBreakpoint
|
|
127
|
+
}: NavigationBarProps): react_jsx_runtime0.JSX.Element;
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/components/context-menu-wrapper.d.ts
|
|
130
|
+
interface ContextMenuAction {
|
|
131
|
+
type?: "item" | "separator" | "label" | "checkbox" | "radio-group" | "submenu";
|
|
132
|
+
key?: string;
|
|
133
|
+
label?: string;
|
|
134
|
+
icon?: LucideIcon;
|
|
135
|
+
onClick?: () => void;
|
|
136
|
+
disabled?: boolean;
|
|
137
|
+
hidden?: boolean;
|
|
138
|
+
variant?: "default" | "destructive";
|
|
139
|
+
shortcut?: string;
|
|
140
|
+
/** For checkbox items */
|
|
141
|
+
checked?: boolean;
|
|
142
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
143
|
+
/** For radio groups */
|
|
144
|
+
radioValue?: string;
|
|
145
|
+
onRadioChange?: (value: string) => void;
|
|
146
|
+
radioOptions?: {
|
|
147
|
+
value: string;
|
|
148
|
+
label: string;
|
|
149
|
+
}[];
|
|
150
|
+
/** For submenus */
|
|
151
|
+
items?: ContextMenuAction[];
|
|
152
|
+
}
|
|
153
|
+
interface ContextMenuWrapperProps {
|
|
154
|
+
children: react.ReactNode;
|
|
155
|
+
items: ContextMenuAction[];
|
|
156
|
+
className?: string;
|
|
157
|
+
contentClassName?: string;
|
|
158
|
+
disabled?: boolean;
|
|
159
|
+
}
|
|
160
|
+
declare function ContextMenuWrapper({
|
|
161
|
+
children,
|
|
162
|
+
items,
|
|
163
|
+
className,
|
|
164
|
+
contentClassName,
|
|
165
|
+
disabled
|
|
166
|
+
}: ContextMenuWrapperProps): react_jsx_runtime0.JSX.Element;
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/components/hover-card-wrapper.d.ts
|
|
169
|
+
interface HoverCardWrapperProps {
|
|
170
|
+
trigger: react.ReactNode;
|
|
171
|
+
children: react.ReactNode;
|
|
172
|
+
side?: "top" | "bottom" | "left" | "right";
|
|
173
|
+
align?: "start" | "center" | "end";
|
|
174
|
+
sideOffset?: number;
|
|
175
|
+
className?: string;
|
|
176
|
+
contentClassName?: string;
|
|
177
|
+
/** Delay before opening (ms) */
|
|
178
|
+
openDelay?: number;
|
|
179
|
+
/** Delay before closing (ms) */
|
|
180
|
+
closeDelay?: number;
|
|
181
|
+
}
|
|
182
|
+
declare function HoverCardWrapper({
|
|
183
|
+
trigger,
|
|
184
|
+
children,
|
|
185
|
+
side,
|
|
186
|
+
align,
|
|
187
|
+
sideOffset,
|
|
188
|
+
className,
|
|
189
|
+
contentClassName,
|
|
190
|
+
openDelay,
|
|
191
|
+
closeDelay
|
|
192
|
+
}: HoverCardWrapperProps): react_jsx_runtime0.JSX.Element;
|
|
193
|
+
interface UserHoverCardProps {
|
|
194
|
+
trigger: react.ReactNode;
|
|
195
|
+
user: {
|
|
196
|
+
name: string;
|
|
197
|
+
username?: string;
|
|
198
|
+
avatar?: string;
|
|
199
|
+
bio?: string;
|
|
200
|
+
initials?: string;
|
|
201
|
+
};
|
|
202
|
+
/** Extra content below bio */
|
|
203
|
+
footer?: react.ReactNode;
|
|
204
|
+
side?: "top" | "bottom" | "left" | "right";
|
|
205
|
+
className?: string;
|
|
206
|
+
}
|
|
207
|
+
declare function UserHoverCard({
|
|
208
|
+
trigger,
|
|
209
|
+
user,
|
|
210
|
+
footer,
|
|
211
|
+
side,
|
|
212
|
+
className
|
|
213
|
+
}: UserHoverCardProps): react_jsx_runtime0.JSX.Element;
|
|
214
|
+
//#endregion
|
|
215
|
+
export { ConfirmDrawer, type ConfirmDrawerProps, type ContextMenuAction, ContextMenuWrapper, type ContextMenuWrapperProps, DrawerWrapper, type DrawerWrapperProps, FormDrawer, type FormDrawerProps, HoverCardWrapper, type HoverCardWrapperProps, type NavBarBrand, type NavBarDropdown, type NavBarItem, type NavBarLink, NavigationBar, type NavigationBarProps, UserHoverCard, type UserHoverCardProps };
|