@nikala-ui/core 0.10.1 → 0.11.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/package.json +1 -1
- package/registry/bubble.json +18 -0
- package/registry/button-group.json +20 -0
- package/registry/create-chat-scroll.json +13 -0
- package/registry/create-drop-zone.json +13 -0
- package/registry/create-pagination.json +13 -0
- package/registry/dropzone.json +21 -0
- package/registry/footer.json +18 -0
- package/registry/forgot-password-01.json +28 -0
- package/registry/hero-01.json +22 -0
- package/registry/index.json +331 -0
- package/registry/login-01.json +28 -0
- package/registry/marker.json +17 -0
- package/registry/marquee.json +17 -0
- package/registry/message.json +17 -0
- package/registry/navbar.json +19 -0
- package/registry/navigation-menu.json +22 -0
- package/registry/otp-verification-01.json +26 -0
- package/registry/pagination.json +22 -0
- package/registry/rating.json +19 -0
- package/registry/register-01.json +31 -0
- package/registry/review-card.json +23 -0
- package/registry/scroll-area.json +1 -1
- package/registry/sidebar.json +24 -0
- package/registry/spinner.json +1 -1
- package/registry/stat.json +19 -0
- package/registry/table.json +17 -0
- package/registry/timeline.json +18 -0
- package/registry/toggle-group.json +21 -0
- package/src/registry/blocks/forgot-password-01.tsx +141 -0
- package/src/registry/blocks/hero-01.tsx +28 -0
- package/src/registry/blocks/login-01.tsx +231 -0
- package/src/registry/blocks/otp-verification-01.tsx +170 -0
- package/src/registry/blocks/register-01.tsx +318 -0
- package/src/registry/components/ui/bubble.tsx +142 -0
- package/src/registry/components/ui/button-group.tsx +42 -0
- package/src/registry/components/ui/dropzone.tsx +189 -0
- package/src/registry/components/ui/footer.tsx +247 -0
- package/src/registry/components/ui/marker.tsx +102 -0
- package/src/registry/components/ui/marquee.tsx +118 -0
- package/src/registry/components/ui/message.tsx +168 -0
- package/src/registry/components/ui/navbar.tsx +368 -0
- package/src/registry/components/ui/navigation-menu.tsx +358 -0
- package/src/registry/components/ui/pagination.tsx +258 -0
- package/src/registry/components/ui/rating.tsx +185 -0
- package/src/registry/components/ui/review-card.tsx +195 -0
- package/src/registry/components/ui/scroll-area.tsx +2 -2
- package/src/registry/components/ui/sidebar.tsx +692 -0
- package/src/registry/components/ui/spinner.tsx +1 -1
- package/src/registry/components/ui/stat.tsx +245 -0
- package/src/registry/components/ui/table.tsx +160 -0
- package/src/registry/components/ui/timeline.tsx +350 -0
- package/src/registry/components/ui/toggle-group.tsx +203 -0
- package/src/registry/index.ts +3 -3
- package/src/registry/metadata.ts +141 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
createSignal,
|
|
4
|
+
useContext,
|
|
5
|
+
splitProps,
|
|
6
|
+
Show,
|
|
7
|
+
type JSX,
|
|
8
|
+
type ParentComponent,
|
|
9
|
+
type Component,
|
|
10
|
+
type Accessor,
|
|
11
|
+
} from "solid-js";
|
|
12
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
13
|
+
import { Menu, X } from "lucide-solid";
|
|
14
|
+
import { cn } from "@/lib/cn";
|
|
15
|
+
|
|
16
|
+
/* --- Navbar Context --- */
|
|
17
|
+
interface NavbarContextValue {
|
|
18
|
+
isOpen: Accessor<boolean>;
|
|
19
|
+
setIsOpen: (open: boolean) => void;
|
|
20
|
+
toggleMobileMenu: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const NavbarContext = createContext<NavbarContextValue>();
|
|
24
|
+
|
|
25
|
+
export function useNavbar() {
|
|
26
|
+
const context = useContext(NavbarContext);
|
|
27
|
+
if (!context) {
|
|
28
|
+
throw new Error("useNavbar must be used within a <Navbar /> component");
|
|
29
|
+
}
|
|
30
|
+
return context;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* --- Root Navbar --- */
|
|
34
|
+
export const navbarVariants = cva(
|
|
35
|
+
"w-full transition-all duration-200 z-40",
|
|
36
|
+
{
|
|
37
|
+
variants: {
|
|
38
|
+
variant: {
|
|
39
|
+
default: "border-b border-border/60 bg-background/80 backdrop-blur-md",
|
|
40
|
+
floating: "my-3 rounded-lg border border-border/80 bg-background/90 backdrop-blur-md shadow-sm",
|
|
41
|
+
bordered: "border-b border-border bg-background",
|
|
42
|
+
transparent: "bg-transparent border-transparent",
|
|
43
|
+
},
|
|
44
|
+
isSticky: {
|
|
45
|
+
true: "sticky top-0",
|
|
46
|
+
false: "relative",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
defaultVariants: {
|
|
50
|
+
variant: "default",
|
|
51
|
+
isSticky: true,
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
export interface NavbarProps
|
|
57
|
+
extends JSX.HTMLAttributes<HTMLElement>,
|
|
58
|
+
VariantProps<typeof navbarVariants> {
|
|
59
|
+
maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "full";
|
|
60
|
+
open?: boolean;
|
|
61
|
+
onOpenChange?: (open: boolean) => void;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const Navbar: ParentComponent<NavbarProps> = (props) => {
|
|
65
|
+
const [local, rest] = splitProps(props, [
|
|
66
|
+
"class",
|
|
67
|
+
"variant",
|
|
68
|
+
"isSticky",
|
|
69
|
+
"maxWidth",
|
|
70
|
+
"open",
|
|
71
|
+
"onOpenChange",
|
|
72
|
+
"children",
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
const [internalOpen, setInternalOpen] = createSignal(false);
|
|
76
|
+
const isOpen = () => (local.open !== undefined ? local.open : internalOpen());
|
|
77
|
+
|
|
78
|
+
const setIsOpen = (open: boolean) => {
|
|
79
|
+
if (local.open === undefined) {
|
|
80
|
+
setInternalOpen(open);
|
|
81
|
+
}
|
|
82
|
+
local.onOpenChange?.(open);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const toggleMobileMenu = () => setIsOpen(!isOpen());
|
|
86
|
+
|
|
87
|
+
const maxWidthClass = () => {
|
|
88
|
+
switch (local.maxWidth) {
|
|
89
|
+
case "sm":
|
|
90
|
+
return "max-w-screen-sm";
|
|
91
|
+
case "md":
|
|
92
|
+
return "max-w-screen-md";
|
|
93
|
+
case "lg":
|
|
94
|
+
return "max-w-screen-lg";
|
|
95
|
+
case "xl":
|
|
96
|
+
return "max-w-screen-xl";
|
|
97
|
+
case "full":
|
|
98
|
+
return "max-w-full";
|
|
99
|
+
case "2xl":
|
|
100
|
+
default:
|
|
101
|
+
return "max-w-screen-2xl";
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<NavbarContext.Provider value={{ isOpen, setIsOpen, toggleMobileMenu }}>
|
|
107
|
+
<header
|
|
108
|
+
class={cn(
|
|
109
|
+
navbarVariants({
|
|
110
|
+
variant: local.variant,
|
|
111
|
+
isSticky: local.isSticky,
|
|
112
|
+
}),
|
|
113
|
+
local.variant === "floating" && cn("mx-auto", maxWidthClass()),
|
|
114
|
+
local.class
|
|
115
|
+
)}
|
|
116
|
+
{...rest}
|
|
117
|
+
>
|
|
118
|
+
<div class={cn("w-full", local.variant !== "floating" && cn("mx-auto", maxWidthClass()))}>
|
|
119
|
+
{local.children}
|
|
120
|
+
</div>
|
|
121
|
+
</header>
|
|
122
|
+
</NavbarContext.Provider>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/* --- Navbar Container (Top Flex Row) --- */
|
|
127
|
+
export interface NavbarContainerProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
128
|
+
class?: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const NavbarContainer: ParentComponent<NavbarContainerProps> = (props) => {
|
|
132
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<div
|
|
136
|
+
class={cn(
|
|
137
|
+
"flex h-14 md:h-16 items-center justify-between px-4 sm:px-6 lg:px-8 gap-3 w-full",
|
|
138
|
+
local.class
|
|
139
|
+
)}
|
|
140
|
+
{...rest}
|
|
141
|
+
>
|
|
142
|
+
{local.children}
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/* --- Navbar Brand / Logo Container --- */
|
|
148
|
+
export interface NavbarBrandProps extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
149
|
+
class?: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export const NavbarBrand: ParentComponent<NavbarBrandProps> = (props) => {
|
|
153
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<a
|
|
157
|
+
class={cn(
|
|
158
|
+
"flex items-center gap-2 font-bold text-foreground transition-opacity hover:opacity-90 cursor-pointer shrink-0",
|
|
159
|
+
local.class
|
|
160
|
+
)}
|
|
161
|
+
{...rest}
|
|
162
|
+
>
|
|
163
|
+
{local.children}
|
|
164
|
+
</a>
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/* --- Navbar Content / Section --- */
|
|
169
|
+
export const navbarContentVariants = cva("flex items-center gap-1 sm:gap-2 h-full", {
|
|
170
|
+
variants: {
|
|
171
|
+
justify: {
|
|
172
|
+
start: "justify-start flex-1",
|
|
173
|
+
center: "justify-center flex-1",
|
|
174
|
+
end: "justify-end flex-1",
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
defaultVariants: {
|
|
178
|
+
justify: "center",
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
export interface NavbarContentProps
|
|
183
|
+
extends JSX.HTMLAttributes<HTMLDivElement>,
|
|
184
|
+
VariantProps<typeof navbarContentVariants> {
|
|
185
|
+
class?: string;
|
|
186
|
+
hideOnMobile?: boolean;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export const NavbarContent: ParentComponent<NavbarContentProps> = (props) => {
|
|
190
|
+
const [local, rest] = splitProps(props, ["class", "justify", "hideOnMobile", "children"]);
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<div
|
|
194
|
+
class={cn(
|
|
195
|
+
navbarContentVariants({ justify: local.justify }),
|
|
196
|
+
local.hideOnMobile !== false && "hidden md:flex",
|
|
197
|
+
local.class
|
|
198
|
+
)}
|
|
199
|
+
{...rest}
|
|
200
|
+
>
|
|
201
|
+
{local.children}
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/* --- Navbar Item --- */
|
|
207
|
+
export interface NavbarItemProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
208
|
+
class?: string;
|
|
209
|
+
isActive?: boolean;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export const NavbarItem: ParentComponent<NavbarItemProps> = (props) => {
|
|
213
|
+
const [local, rest] = splitProps(props, ["class", "isActive", "children"]);
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
<div
|
|
217
|
+
class={cn(
|
|
218
|
+
"relative flex items-center h-full text-sm font-medium",
|
|
219
|
+
local.class
|
|
220
|
+
)}
|
|
221
|
+
{...rest}
|
|
222
|
+
>
|
|
223
|
+
{local.children}
|
|
224
|
+
<Show when={local.isActive}>
|
|
225
|
+
<div class="absolute -bottom-px left-0 right-0 h-0.5 bg-primary rounded-lg z-10" />
|
|
226
|
+
</Show>
|
|
227
|
+
</div>
|
|
228
|
+
);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/* --- Navbar Link --- */
|
|
232
|
+
export const navbarLinkVariants = cva(
|
|
233
|
+
"inline-flex h-9 items-center justify-center rounded-md px-3 text-sm font-medium transition-colors cursor-pointer select-none focus-visible:outline-hidden",
|
|
234
|
+
{
|
|
235
|
+
variants: {
|
|
236
|
+
variant: {
|
|
237
|
+
default:
|
|
238
|
+
"text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
239
|
+
active:
|
|
240
|
+
"text-foreground font-semibold bg-muted/80",
|
|
241
|
+
ghost:
|
|
242
|
+
"text-foreground hover:text-primary",
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
defaultVariants: {
|
|
246
|
+
variant: "default",
|
|
247
|
+
},
|
|
248
|
+
}
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
export interface NavbarLinkProps
|
|
252
|
+
extends JSX.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
253
|
+
VariantProps<typeof navbarLinkVariants> {
|
|
254
|
+
class?: string;
|
|
255
|
+
isActive?: boolean;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export const NavbarLink: ParentComponent<NavbarLinkProps> = (props) => {
|
|
259
|
+
const [local, rest] = splitProps(props, ["class", "variant", "isActive", "children"]);
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<a
|
|
263
|
+
class={cn(
|
|
264
|
+
navbarLinkVariants({
|
|
265
|
+
variant: local.isActive ? "active" : local.variant,
|
|
266
|
+
}),
|
|
267
|
+
local.class
|
|
268
|
+
)}
|
|
269
|
+
{...rest}
|
|
270
|
+
>
|
|
271
|
+
{local.children}
|
|
272
|
+
</a>
|
|
273
|
+
);
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
/* --- Navbar Actions Container --- */
|
|
277
|
+
export interface NavbarActionsProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
278
|
+
class?: string;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export const NavbarActions: ParentComponent<NavbarActionsProps> = (props) => {
|
|
282
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
283
|
+
|
|
284
|
+
return (
|
|
285
|
+
<div class={cn("flex items-center gap-2 shrink-0", local.class)} {...rest}>
|
|
286
|
+
{local.children}
|
|
287
|
+
</div>
|
|
288
|
+
);
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
/* --- Navbar Mobile Toggle Button --- */
|
|
292
|
+
export interface NavbarMobileToggleProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
293
|
+
class?: string;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export const NavbarMobileToggle: Component<NavbarMobileToggleProps> = (props) => {
|
|
297
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
298
|
+
const { isOpen, toggleMobileMenu } = useNavbar();
|
|
299
|
+
|
|
300
|
+
return (
|
|
301
|
+
<button
|
|
302
|
+
type="button"
|
|
303
|
+
onClick={toggleMobileMenu}
|
|
304
|
+
aria-label="Toggle navigation menu"
|
|
305
|
+
aria-expanded={isOpen()}
|
|
306
|
+
class={cn(
|
|
307
|
+
"inline-flex md:hidden size-8 items-center justify-center rounded-md border border-border/60 bg-muted/30 text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring shrink-0",
|
|
308
|
+
local.class
|
|
309
|
+
)}
|
|
310
|
+
{...rest}
|
|
311
|
+
>
|
|
312
|
+
<Show when={isOpen()} fallback={<Menu class="size-4" />}>
|
|
313
|
+
<X class="size-4" />
|
|
314
|
+
</Show>
|
|
315
|
+
</button>
|
|
316
|
+
);
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
/* --- Navbar Mobile Menu Container --- */
|
|
320
|
+
export interface NavbarMobileMenuProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
321
|
+
class?: string;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export const NavbarMobileMenu: ParentComponent<NavbarMobileMenuProps> = (props) => {
|
|
325
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
326
|
+
const { isOpen } = useNavbar();
|
|
327
|
+
|
|
328
|
+
return (
|
|
329
|
+
<Show when={isOpen()}>
|
|
330
|
+
<div
|
|
331
|
+
class={cn(
|
|
332
|
+
"md:hidden w-full border-t border-border/60 bg-background/95 backdrop-blur-lg px-4 py-3 space-y-1 shadow-md transition-all",
|
|
333
|
+
local.class
|
|
334
|
+
)}
|
|
335
|
+
{...rest}
|
|
336
|
+
>
|
|
337
|
+
{local.children}
|
|
338
|
+
</div>
|
|
339
|
+
</Show>
|
|
340
|
+
);
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
/* --- Navbar Mobile Item & Link --- */
|
|
344
|
+
export interface NavbarMobileLinkProps extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
345
|
+
class?: string;
|
|
346
|
+
isActive?: boolean;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export const NavbarMobileLink: ParentComponent<NavbarMobileLinkProps> = (props) => {
|
|
350
|
+
const [local, rest] = splitProps(props, ["class", "isActive", "children"]);
|
|
351
|
+
const { setIsOpen } = useNavbar();
|
|
352
|
+
|
|
353
|
+
return (
|
|
354
|
+
<a
|
|
355
|
+
onClick={() => setIsOpen(false)}
|
|
356
|
+
class={cn(
|
|
357
|
+
"flex w-full items-center justify-between rounded-md px-3 py-2 text-sm font-medium transition-colors cursor-pointer",
|
|
358
|
+
local.isActive
|
|
359
|
+
? "bg-primary text-primary-foreground font-semibold shadow-2xs"
|
|
360
|
+
: "text-muted-foreground hover:bg-muted/80 hover:text-foreground",
|
|
361
|
+
local.class
|
|
362
|
+
)}
|
|
363
|
+
{...rest}
|
|
364
|
+
>
|
|
365
|
+
{local.children}
|
|
366
|
+
</a>
|
|
367
|
+
);
|
|
368
|
+
};
|