metabinaries 1.0.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/LICENSE +21 -0
- package/README.md +43 -0
- package/index.js +164 -0
- package/package.json +32 -0
- package/src/constants.js +62 -0
- package/src/templates/app.js +527 -0
- package/src/templates/configs.js +303 -0
- package/src/templates/core.js +328 -0
- package/src/templates/folder-structure.js +21 -0
- package/src/templates/layout.js +279 -0
- package/src/templates/misc.js +277 -0
- package/src/templates/packages.js +42 -0
- package/src/templates/ui-2.js +585 -0
- package/src/templates/ui-3.js +606 -0
- package/src/templates/ui-4.js +615 -0
- package/src/templates/ui.js +777 -0
- package/src/utils.js +38 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
export const uiTemplates2 = {
|
|
2
|
+
'components/ui/empty.tsx': `import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
|
+
|
|
6
|
+
function Empty({ className, ...props }: React.ComponentProps<'div'>) {
|
|
7
|
+
return (
|
|
8
|
+
<div
|
|
9
|
+
data-slot='empty'
|
|
10
|
+
className={cn(
|
|
11
|
+
'flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12',
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function EmptyHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
data-slot='empty-header'
|
|
23
|
+
className={cn(
|
|
24
|
+
'flex max-w-sm flex-col items-center gap-2 text-center',
|
|
25
|
+
className
|
|
26
|
+
)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const emptyMediaVariants = cva(
|
|
33
|
+
'flex shrink-0 items-center justify-center mb-2 [&_svg]:pointer-events-none [&_svg]:shrink-0',
|
|
34
|
+
{
|
|
35
|
+
variants: {
|
|
36
|
+
variant: {
|
|
37
|
+
default: 'bg-transparent',
|
|
38
|
+
icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
defaultVariants: {
|
|
42
|
+
variant: 'default',
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
function EmptyMedia({
|
|
48
|
+
className,
|
|
49
|
+
variant = 'default',
|
|
50
|
+
...props
|
|
51
|
+
}: React.ComponentProps<'div'> & VariantProps<typeof emptyMediaVariants>) {
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
data-slot='empty-icon'
|
|
55
|
+
data-variant={variant}
|
|
56
|
+
className={cn(emptyMediaVariants({ variant, className }))}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function EmptyTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
63
|
+
return (
|
|
64
|
+
<div
|
|
65
|
+
data-slot='empty-title'
|
|
66
|
+
className={cn('text-lg font-medium tracking-tight', className)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
|
73
|
+
return (
|
|
74
|
+
<div
|
|
75
|
+
data-slot='empty-description'
|
|
76
|
+
className={cn(
|
|
77
|
+
'text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4',
|
|
78
|
+
className
|
|
79
|
+
)}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function EmptyContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
86
|
+
return (
|
|
87
|
+
<div
|
|
88
|
+
data-slot='empty-content'
|
|
89
|
+
className={cn(
|
|
90
|
+
'flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance',
|
|
91
|
+
className
|
|
92
|
+
)}
|
|
93
|
+
{...props}
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export {
|
|
99
|
+
Empty,
|
|
100
|
+
EmptyHeader,
|
|
101
|
+
EmptyTitle,
|
|
102
|
+
EmptyDescription,
|
|
103
|
+
EmptyContent,
|
|
104
|
+
EmptyMedia,
|
|
105
|
+
};`,
|
|
106
|
+
|
|
107
|
+
'components/ui/input-group.tsx': `'use client';
|
|
108
|
+
|
|
109
|
+
import * as React from 'react';
|
|
110
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
111
|
+
|
|
112
|
+
import { cn } from '@/lib/utils';
|
|
113
|
+
import { Button } from '@/components/ui/button';
|
|
114
|
+
import { Input } from '@/components/ui/input';
|
|
115
|
+
import { Textarea } from '@/components/ui/textarea';
|
|
116
|
+
|
|
117
|
+
function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
118
|
+
return (
|
|
119
|
+
<div
|
|
120
|
+
data-slot='input-group'
|
|
121
|
+
role='group'
|
|
122
|
+
className={cn(
|
|
123
|
+
'group/input-group border-input dark:bg-input/30 relative flex w-full items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none',
|
|
124
|
+
'h-9 min-w-0 has-[>textarea]:h-auto',
|
|
125
|
+
|
|
126
|
+
// Variants based on alignment.
|
|
127
|
+
'has-[>[data-align=inline-start]]:[&>input]:pl-2',
|
|
128
|
+
'has-[>[data-align=inline-end]]:[&>input]:pr-2',
|
|
129
|
+
'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',
|
|
130
|
+
'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',
|
|
131
|
+
|
|
132
|
+
// Focus state.
|
|
133
|
+
'has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]',
|
|
134
|
+
|
|
135
|
+
// Error state.
|
|
136
|
+
'has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40',
|
|
137
|
+
|
|
138
|
+
className
|
|
139
|
+
)}
|
|
140
|
+
{...props}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const inputGroupAddonVariants = cva(
|
|
146
|
+
"text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-4 [&>kbd]:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:opacity-50",
|
|
147
|
+
{
|
|
148
|
+
variants: {
|
|
149
|
+
align: {
|
|
150
|
+
'inline-start':
|
|
151
|
+
'order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]',
|
|
152
|
+
'inline-end':
|
|
153
|
+
'order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]',
|
|
154
|
+
'block-start':
|
|
155
|
+
'order-first w-full justify-start px-3 pt-3 [.border-b]:pb-3 group-has-[>input]/input-group:pt-2.5',
|
|
156
|
+
'block-end':
|
|
157
|
+
'order-last w-full justify-start px-3 pb-3 [.border-t]:pt-3 group-has-[>input]/input-group:pb-2.5',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
defaultVariants: {
|
|
161
|
+
align: 'inline-start',
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
function InputGroupAddon({
|
|
167
|
+
className,
|
|
168
|
+
align = 'inline-start',
|
|
169
|
+
...props
|
|
170
|
+
}: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {
|
|
171
|
+
return (
|
|
172
|
+
<div
|
|
173
|
+
role='group'
|
|
174
|
+
data-slot='input-group-addon'
|
|
175
|
+
data-align={align}
|
|
176
|
+
className={cn(inputGroupAddonVariants({ align }), className)}
|
|
177
|
+
onClick={e => {
|
|
178
|
+
if ((e.target as HTMLElement).closest('button')) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
e.currentTarget.parentElement?.querySelector('input')?.focus();
|
|
182
|
+
}}
|
|
183
|
+
{...props}
|
|
184
|
+
/>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const inputGroupButtonVariants = cva(
|
|
189
|
+
'text-sm shadow-none flex gap-2 items-center',
|
|
190
|
+
{
|
|
191
|
+
variants: {
|
|
192
|
+
size: {
|
|
193
|
+
xs: "h-6 gap-1 px-2 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2",
|
|
194
|
+
sm: 'h-8 px-2.5 gap-1.5 rounded-md has-[>svg]:px-2.5',
|
|
195
|
+
'icon-xs':
|
|
196
|
+
'size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0',
|
|
197
|
+
'icon-sm': 'size-8 p-0 has-[>svg]:p-0',
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
defaultVariants: {
|
|
201
|
+
size: 'xs',
|
|
202
|
+
},
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
function InputGroupButton({
|
|
207
|
+
className,
|
|
208
|
+
type = 'button',
|
|
209
|
+
variant = 'ghost',
|
|
210
|
+
size = 'xs',
|
|
211
|
+
...props
|
|
212
|
+
}: Omit<React.ComponentProps<typeof Button>, 'size'> &
|
|
213
|
+
VariantProps<typeof inputGroupButtonVariants>) {
|
|
214
|
+
return (
|
|
215
|
+
<Button
|
|
216
|
+
type={type}
|
|
217
|
+
data-size={size}
|
|
218
|
+
variant={variant}
|
|
219
|
+
className={cn(inputGroupButtonVariants({ size }), className)}
|
|
220
|
+
{...props}
|
|
221
|
+
/>
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
|
|
226
|
+
return (
|
|
227
|
+
<span
|
|
228
|
+
className={cn(
|
|
229
|
+
"text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
|
|
230
|
+
className
|
|
231
|
+
)}
|
|
232
|
+
{...props}
|
|
233
|
+
/>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function InputGroupInput({
|
|
238
|
+
className,
|
|
239
|
+
...props
|
|
240
|
+
}: React.ComponentProps<'input'>) {
|
|
241
|
+
return (
|
|
242
|
+
<Input
|
|
243
|
+
data-slot='input-group-control'
|
|
244
|
+
className={cn(
|
|
245
|
+
'flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent',
|
|
246
|
+
className
|
|
247
|
+
)}
|
|
248
|
+
{...props}
|
|
249
|
+
/>
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function InputGroupTextarea({
|
|
254
|
+
className,
|
|
255
|
+
...props
|
|
256
|
+
}: React.ComponentProps<'textarea'>) {
|
|
257
|
+
return (
|
|
258
|
+
<Textarea
|
|
259
|
+
data-slot='input-group-control'
|
|
260
|
+
className={cn(
|
|
261
|
+
'flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent',
|
|
262
|
+
className
|
|
263
|
+
)}
|
|
264
|
+
{...props}
|
|
265
|
+
/>
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export {
|
|
270
|
+
InputGroup,
|
|
271
|
+
InputGroupAddon,
|
|
272
|
+
InputGroupButton,
|
|
273
|
+
InputGroupText,
|
|
274
|
+
InputGroupInput,
|
|
275
|
+
InputGroupTextarea,
|
|
276
|
+
};`,
|
|
277
|
+
|
|
278
|
+
'components/ui/input-otp.tsx': `'use client';
|
|
279
|
+
|
|
280
|
+
import * as React from 'react';
|
|
281
|
+
import { OTPInput, OTPInputContext } from 'input-otp';
|
|
282
|
+
import { MinusIcon } from 'lucide-react';
|
|
283
|
+
|
|
284
|
+
import { cn } from '@/lib/utils';
|
|
285
|
+
|
|
286
|
+
function InputOTP({
|
|
287
|
+
className,
|
|
288
|
+
containerClassName,
|
|
289
|
+
...props
|
|
290
|
+
}: React.ComponentProps<typeof OTPInput> & {
|
|
291
|
+
containerClassName?: string;
|
|
292
|
+
}) {
|
|
293
|
+
return (
|
|
294
|
+
<OTPInput
|
|
295
|
+
data-slot='input-otp'
|
|
296
|
+
containerClassName={cn(
|
|
297
|
+
'flex items-center gap-2 has-disabled:opacity-50',
|
|
298
|
+
containerClassName
|
|
299
|
+
)}
|
|
300
|
+
className={cn('disabled:cursor-not-allowed', className)}
|
|
301
|
+
{...props}
|
|
302
|
+
/>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function InputOTPGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
307
|
+
return (
|
|
308
|
+
<div
|
|
309
|
+
data-slot='input-otp-group'
|
|
310
|
+
className={cn('flex items-center', className)}
|
|
311
|
+
{...props}
|
|
312
|
+
/>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function InputOTPSlot({
|
|
317
|
+
index,
|
|
318
|
+
className,
|
|
319
|
+
...props
|
|
320
|
+
}: React.ComponentProps<'div'> & {
|
|
321
|
+
index: number;
|
|
322
|
+
}) {
|
|
323
|
+
const inputOTPContext = React.useContext(OTPInputContext);
|
|
324
|
+
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
|
|
325
|
+
|
|
326
|
+
return (
|
|
327
|
+
<div
|
|
328
|
+
data-slot='input-otp-slot'
|
|
329
|
+
data-active={isActive}
|
|
330
|
+
className={cn(
|
|
331
|
+
'data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input relative flex h-9 w-9 items-center justify-center border-y border-r text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]',
|
|
332
|
+
className
|
|
333
|
+
)}
|
|
334
|
+
{...props}
|
|
335
|
+
>
|
|
336
|
+
{char}
|
|
337
|
+
{hasFakeCaret && (
|
|
338
|
+
<div className='pointer-events-none absolute inset-0 flex items-center justify-center'>
|
|
339
|
+
<div className='animate-caret-blink bg-foreground h-4 w-px duration-1000' />
|
|
340
|
+
</div>
|
|
341
|
+
)}
|
|
342
|
+
</div>
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function InputOTPSeparator({ ...props }: React.ComponentProps<'div'>) {
|
|
347
|
+
return (
|
|
348
|
+
<div data-slot='input-otp-separator' role='separator' {...props}>
|
|
349
|
+
<MinusIcon />
|
|
350
|
+
</div>
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };`,
|
|
355
|
+
|
|
356
|
+
'components/ui/input.tsx': `import * as React from 'react';
|
|
357
|
+
import { cn } from '@/lib/utils';
|
|
358
|
+
|
|
359
|
+
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
|
360
|
+
|
|
361
|
+
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
362
|
+
({ className, type, ...props }, ref) => {
|
|
363
|
+
return (
|
|
364
|
+
<input
|
|
365
|
+
type={type}
|
|
366
|
+
className={cn(
|
|
367
|
+
'flex h-10 w-full bg-setup-primary rounded-md border focus:border-setup-secondary border-setup-secondary px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
|
368
|
+
className
|
|
369
|
+
)}
|
|
370
|
+
ref={ref}
|
|
371
|
+
{...props}
|
|
372
|
+
/>
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
);
|
|
376
|
+
Input.displayName = 'Input';
|
|
377
|
+
|
|
378
|
+
export { Input };`,
|
|
379
|
+
|
|
380
|
+
'components/ui/label.tsx': `'use client';
|
|
381
|
+
|
|
382
|
+
import * as React from 'react';
|
|
383
|
+
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
384
|
+
|
|
385
|
+
import { cn } from '@/lib/utils';
|
|
386
|
+
|
|
387
|
+
function Label({
|
|
388
|
+
className,
|
|
389
|
+
...props
|
|
390
|
+
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
|
391
|
+
return (
|
|
392
|
+
<LabelPrimitive.Root
|
|
393
|
+
data-slot='label'
|
|
394
|
+
className={cn(
|
|
395
|
+
'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
|
|
396
|
+
className
|
|
397
|
+
)}
|
|
398
|
+
{...props}
|
|
399
|
+
/>
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export { Label };`,
|
|
404
|
+
|
|
405
|
+
'components/ui/navigation-menu.tsx': `import * as React from 'react';
|
|
406
|
+
import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu';
|
|
407
|
+
import { cva } from 'class-variance-authority';
|
|
408
|
+
import { ChevronDownIcon } from 'lucide-react';
|
|
409
|
+
|
|
410
|
+
import { cn } from '@/lib/utils';
|
|
411
|
+
|
|
412
|
+
function NavigationMenu({
|
|
413
|
+
className,
|
|
414
|
+
children,
|
|
415
|
+
viewport = true,
|
|
416
|
+
...props
|
|
417
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
|
|
418
|
+
viewport?: boolean;
|
|
419
|
+
}) {
|
|
420
|
+
return (
|
|
421
|
+
<NavigationMenuPrimitive.Root
|
|
422
|
+
data-slot='navigation-menu'
|
|
423
|
+
data-viewport={viewport}
|
|
424
|
+
className={cn(
|
|
425
|
+
'group/navigation-menu relative flex max-w-max flex-1 items-center justify-center',
|
|
426
|
+
className
|
|
427
|
+
)}
|
|
428
|
+
{...props}
|
|
429
|
+
>
|
|
430
|
+
{children}
|
|
431
|
+
{viewport && <NavigationMenuViewport />}
|
|
432
|
+
</NavigationMenuPrimitive.Root>
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function NavigationMenuList({
|
|
437
|
+
className,
|
|
438
|
+
...props
|
|
439
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
|
|
440
|
+
return (
|
|
441
|
+
<NavigationMenuPrimitive.List
|
|
442
|
+
data-slot='navigation-menu-list'
|
|
443
|
+
className={cn(
|
|
444
|
+
'group flex flex-1 list-none items-center justify-center gap-1',
|
|
445
|
+
className
|
|
446
|
+
)}
|
|
447
|
+
{...props}
|
|
448
|
+
/>
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function NavigationMenuItem({
|
|
453
|
+
className,
|
|
454
|
+
...props
|
|
455
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
|
|
456
|
+
return (
|
|
457
|
+
<NavigationMenuPrimitive.Item
|
|
458
|
+
data-slot='navigation-menu-item'
|
|
459
|
+
className={cn('relative', className)}
|
|
460
|
+
{...props}
|
|
461
|
+
/>
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const navigationMenuTriggerStyle = cva(
|
|
466
|
+
'group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1'
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
function NavigationMenuTrigger({
|
|
470
|
+
className,
|
|
471
|
+
children,
|
|
472
|
+
...props
|
|
473
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
|
|
474
|
+
return (
|
|
475
|
+
<NavigationMenuPrimitive.Trigger
|
|
476
|
+
data-slot='navigation-menu-trigger'
|
|
477
|
+
className={cn(navigationMenuTriggerStyle(), 'group', className)}
|
|
478
|
+
{...props}
|
|
479
|
+
>
|
|
480
|
+
{children}{' '}
|
|
481
|
+
<ChevronDownIcon
|
|
482
|
+
className='relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180'
|
|
483
|
+
aria-hidden='true'
|
|
484
|
+
/>
|
|
485
|
+
</NavigationMenuPrimitive.Trigger>
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function NavigationMenuContent({
|
|
490
|
+
className,
|
|
491
|
+
...props
|
|
492
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
|
|
493
|
+
return (
|
|
494
|
+
<NavigationMenuPrimitive.Content
|
|
495
|
+
data-slot='navigation-menu-content'
|
|
496
|
+
className={cn(
|
|
497
|
+
'data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto',
|
|
498
|
+
'group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none',
|
|
499
|
+
className
|
|
500
|
+
)}
|
|
501
|
+
{...props}
|
|
502
|
+
/>
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function NavigationMenuViewport({
|
|
507
|
+
className,
|
|
508
|
+
...props
|
|
509
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
|
|
510
|
+
return (
|
|
511
|
+
<div
|
|
512
|
+
className={cn(
|
|
513
|
+
'absolute top-full left-0 isolate z-50 flex justify-center'
|
|
514
|
+
)}
|
|
515
|
+
>
|
|
516
|
+
<NavigationMenuPrimitive.Viewport
|
|
517
|
+
data-slot='navigation-menu-viewport'
|
|
518
|
+
className={cn(
|
|
519
|
+
'origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]',
|
|
520
|
+
className
|
|
521
|
+
)}
|
|
522
|
+
{...props}
|
|
523
|
+
/>
|
|
524
|
+
</div>
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function NavigationMenuLink({
|
|
529
|
+
className,
|
|
530
|
+
...props
|
|
531
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
|
|
532
|
+
return (
|
|
533
|
+
<NavigationMenuPrimitive.Link
|
|
534
|
+
data-slot='navigation-menu-link'
|
|
535
|
+
className={cn(
|
|
536
|
+
"data-[active=true]:focus:bg-accent data-[active=true]:hover:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4",
|
|
537
|
+
className
|
|
538
|
+
)}
|
|
539
|
+
{...props}
|
|
540
|
+
/>
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function NavigationMenuIndicator({
|
|
545
|
+
className,
|
|
546
|
+
...props
|
|
547
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
|
|
548
|
+
return (
|
|
549
|
+
<NavigationMenuPrimitive.Indicator
|
|
550
|
+
data-slot='navigation-menu-indicator'
|
|
551
|
+
className={cn(
|
|
552
|
+
'data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden',
|
|
553
|
+
className
|
|
554
|
+
)}
|
|
555
|
+
{...props}
|
|
556
|
+
/>
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
export {
|
|
561
|
+
NavigationMenu,
|
|
562
|
+
NavigationMenuList,
|
|
563
|
+
NavigationMenuItem,
|
|
564
|
+
NavigationMenuContent,
|
|
565
|
+
NavigationMenuTrigger,
|
|
566
|
+
NavigationMenuLink,
|
|
567
|
+
NavigationMenuIndicator,
|
|
568
|
+
NavigationMenuViewport,
|
|
569
|
+
navigationMenuTriggerStyle,
|
|
570
|
+
};`,
|
|
571
|
+
|
|
572
|
+
'components/ui/skeleton.tsx': `import { cn } from '@/lib/utils';
|
|
573
|
+
|
|
574
|
+
function Skeleton({ className, ...props }: React.ComponentProps<'div'>) {
|
|
575
|
+
return (
|
|
576
|
+
<div
|
|
577
|
+
data-slot='skeleton'
|
|
578
|
+
className={cn('bg-crm-secondary/10 animate-pulse rounded-md', className)}
|
|
579
|
+
{...props}
|
|
580
|
+
/>
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
export { Skeleton };`,
|
|
585
|
+
};
|