create-better-t-stack 0.1.0 → 1.0.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.
Files changed (87) hide show
  1. package/README.md +59 -49
  2. package/dist/index.js +128 -305
  3. package/package.json +19 -11
  4. package/template/base/_gitignore +2 -0
  5. package/template/base/package.json +18 -0
  6. package/template/base/packages/client/_gitignore +23 -0
  7. package/template/base/packages/client/components.json +21 -0
  8. package/template/base/packages/client/index.html +12 -0
  9. package/template/base/packages/client/package.json +49 -0
  10. package/template/base/packages/client/src/components/header.tsx +31 -0
  11. package/template/base/packages/client/src/components/loader.tsx +9 -0
  12. package/template/base/packages/client/src/components/mode-toggle.tsx +37 -0
  13. package/template/base/packages/client/src/components/theme-provider.tsx +73 -0
  14. package/template/base/packages/client/src/components/ui/button.tsx +57 -0
  15. package/template/base/packages/client/src/components/ui/card.tsx +92 -0
  16. package/template/base/packages/client/src/components/ui/checkbox.tsx +30 -0
  17. package/template/base/packages/client/src/components/ui/dropdown-menu.tsx +199 -0
  18. package/template/base/packages/client/src/components/ui/input.tsx +22 -0
  19. package/template/base/packages/client/src/components/ui/label.tsx +24 -0
  20. package/template/base/packages/client/src/components/ui/skeleton.tsx +15 -0
  21. package/template/base/packages/client/src/components/ui/sonner.tsx +29 -0
  22. package/template/base/packages/client/src/index.css +119 -0
  23. package/template/base/packages/client/src/lib/utils.ts +6 -0
  24. package/template/base/packages/client/src/main.tsx +72 -0
  25. package/template/base/packages/client/src/routes/__root.tsx +58 -0
  26. package/template/base/packages/client/src/routes/index.tsx +97 -0
  27. package/template/base/packages/client/src/utils/trpc.ts +4 -0
  28. package/template/base/packages/client/tsconfig.json +18 -0
  29. package/template/base/packages/client/vite.config.ts +14 -0
  30. package/template/base/packages/server/_gitignore +36 -0
  31. package/template/base/packages/server/package.json +27 -0
  32. package/template/base/packages/server/src/index.ts +41 -0
  33. package/template/base/packages/server/src/lib/context.ts +13 -0
  34. package/template/base/packages/server/src/lib/trpc.ts +8 -0
  35. package/template/base/packages/server/src/routers/index.ts +11 -0
  36. package/template/base/packages/server/tsconfig.json +18 -0
  37. package/template/base/turbo.json +27 -0
  38. package/template/examples/todo/packages/client/src/routes/todos.tsx +128 -0
  39. package/template/examples/todo/packages/server/src/routers/with-drizzle-todo.ts +44 -0
  40. package/template/examples/todo/packages/server/src/routers/with-prisma-todo.ts +55 -0
  41. package/template/with-auth/packages/client/src/components/auth-forms.tsx +13 -0
  42. package/template/with-auth/packages/client/src/components/header.tsx +34 -0
  43. package/template/with-auth/packages/client/src/components/sign-in-form.tsx +139 -0
  44. package/template/with-auth/packages/client/src/components/sign-up-form.tsx +164 -0
  45. package/template/with-auth/packages/client/src/components/user-menu.tsx +62 -0
  46. package/template/with-auth/packages/client/src/lib/auth-client.ts +5 -0
  47. package/template/with-auth/packages/client/src/main.tsx +78 -0
  48. package/template/with-auth/packages/client/src/routes/dashboard.tsx +36 -0
  49. package/template/with-auth/packages/client/src/routes/index.tsx +97 -0
  50. package/template/with-auth/packages/client/src/routes/login.tsx +11 -0
  51. package/template/with-auth/packages/server/src/index.ts +46 -0
  52. package/template/with-auth/packages/server/src/lib/trpc.ts +24 -0
  53. package/template/with-auth/packages/server/src/routers/index.ts +19 -0
  54. package/template/with-biome/biome.json +42 -0
  55. package/template/with-drizzle-postgres/packages/server/drizzle.config.ts +10 -0
  56. package/template/with-drizzle-postgres/packages/server/src/db/index.ts +5 -0
  57. package/template/with-drizzle-postgres/packages/server/src/db/schema/auth.ts +47 -0
  58. package/template/with-drizzle-postgres/packages/server/src/db/schema/todo.ts +7 -0
  59. package/template/with-drizzle-postgres/packages/server/src/routers/todo.ts +44 -0
  60. package/template/with-drizzle-postgres/packages/server/src/with-auth-lib/auth.ts +15 -0
  61. package/template/with-drizzle-postgres/packages/server/src/with-auth-lib/context.ts +18 -0
  62. package/template/with-drizzle-postgres/packages/server/src/with-auth-lib/trpc.ts +24 -0
  63. package/template/with-drizzle-sqlite/packages/server/drizzle.config.ts +11 -0
  64. package/template/with-drizzle-sqlite/packages/server/src/db/index.ts +9 -0
  65. package/template/with-drizzle-sqlite/packages/server/src/db/schema/auth.ts +61 -0
  66. package/template/with-drizzle-sqlite/packages/server/src/db/schema/todo.ts +7 -0
  67. package/template/with-drizzle-sqlite/packages/server/src/with-auth-lib/auth.ts +15 -0
  68. package/template/with-drizzle-sqlite/packages/server/src/with-auth-lib/context.ts +18 -0
  69. package/template/with-drizzle-sqlite/packages/server/src/with-auth-lib/trpc.ts +24 -0
  70. package/template/with-husky/.husky/pre-commit +1 -0
  71. package/template/with-prisma-postgres/packages/server/prisma/index.ts +5 -0
  72. package/template/with-prisma-postgres/packages/server/prisma/schema/auth.prisma +59 -0
  73. package/template/with-prisma-postgres/packages/server/prisma/schema/schema.prisma +9 -0
  74. package/template/with-prisma-postgres/packages/server/prisma/schema/todo.prisma +7 -0
  75. package/template/with-prisma-postgres/packages/server/src/with-auth-lib/auth.ts +17 -0
  76. package/template/with-prisma-postgres/packages/server/src/with-auth-lib/context.ts +18 -0
  77. package/template/with-prisma-postgres/packages/server/src/with-auth-lib/trpc.ts +24 -0
  78. package/template/with-prisma-sqlite/packages/server/prisma/index.ts +5 -0
  79. package/template/with-prisma-sqlite/packages/server/prisma/schema/auth.prisma +59 -0
  80. package/template/with-prisma-sqlite/packages/server/prisma/schema/schema.prisma +8 -0
  81. package/template/with-prisma-sqlite/packages/server/prisma/schema/todo.prisma +7 -0
  82. package/template/with-prisma-sqlite/packages/server/src/with-auth-lib/auth.ts +17 -0
  83. package/template/with-prisma-sqlite/packages/server/src/with-auth-lib/context.ts +18 -0
  84. package/template/with-prisma-sqlite/packages/server/src/with-auth-lib/trpc.ts +24 -0
  85. package/template/with-pwa/packages/client/public/logo.png +0 -0
  86. package/template/with-pwa/packages/client/pwa-assets.config.ts +12 -0
  87. package/template/with-pwa/packages/client/vite.config.ts +35 -0
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ </head>
7
+
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "client",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite --port=3001",
8
+ "build": "vite build",
9
+ "serve": "vite preview",
10
+ "start": "vite",
11
+ "check-types": "tsc --noEmit"
12
+ },
13
+ "devDependencies": {
14
+ "@tanstack/router-plugin": "^1.114.27",
15
+ "@types/node": "^22.13.11",
16
+ "@types/react": "^19.0.12",
17
+ "@types/react-dom": "^19.0.4",
18
+ "@vitejs/plugin-react": "^4.3.4",
19
+ "postcss": "^8.5.3",
20
+ "tailwindcss": "^4.0.15",
21
+ "vite": "^6.2.2"
22
+ },
23
+ "dependencies": {
24
+ "@hookform/resolvers": "^3.10.0",
25
+ "@radix-ui/react-checkbox": "^1.1.4",
26
+ "@radix-ui/react-dropdown-menu": "^2.1.6",
27
+ "@radix-ui/react-label": "^2.1.2",
28
+ "@radix-ui/react-slot": "^1.1.2",
29
+ "@tanstack/react-form": "^1.0.5",
30
+ "@tailwindcss/vite": "^4.0.15",
31
+ "@tanstack/react-query": "^5.69.0",
32
+ "@tanstack/react-query-devtools": "^5.69.0",
33
+ "@tanstack/react-router": "^1.114.25",
34
+ "@tanstack/router-devtools": "^1.114.25",
35
+ "@trpc/client": "^11.0.0",
36
+ "@trpc/react-query": "^11.0.0",
37
+ "@trpc/server": "^11.0.0",
38
+ "class-variance-authority": "^0.7.1",
39
+ "clsx": "^2.1.1",
40
+ "lucide-react": "^0.473.0",
41
+ "next-themes": "^0.4.6",
42
+ "react": "^19.0.0",
43
+ "react-dom": "^19.0.0",
44
+ "sonner": "^1.7.4",
45
+ "tailwind-merge": "^2.6.0",
46
+ "tailwindcss-animate": "^1.0.7",
47
+ "zod": "^3.24.2"
48
+ }
49
+ }
@@ -0,0 +1,31 @@
1
+ import { Link } from "@tanstack/react-router";
2
+ import { ModeToggle } from "./mode-toggle";
3
+
4
+ export default function Header() {
5
+ const links = [
6
+ { to: "/", label: "Home" },
7
+ ];
8
+
9
+ return (
10
+ <div>
11
+ <div className="flex flex-row items-center justify-between px-2 py-1">
12
+ <nav className="flex gap-4 text-lg">
13
+ {links.map(({ to, label }) => (
14
+ <Link
15
+ key={to}
16
+ to={to}
17
+ activeProps={{ className: "font-bold" }}
18
+ activeOptions={{ exact: true }}
19
+ >
20
+ {label}
21
+ </Link>
22
+ ))}
23
+ </nav>
24
+ <div className="flex items-center gap-2">
25
+ <ModeToggle />
26
+ </div>
27
+ </div>
28
+ <hr />
29
+ </div>
30
+ );
31
+ }
@@ -0,0 +1,9 @@
1
+ import { Loader2 } from "lucide-react";
2
+
3
+ export default function Loader() {
4
+ return (
5
+ <div className="flex h-full items-center justify-center pt-8">
6
+ <Loader2 className="animate-spin" />
7
+ </div>
8
+ );
9
+ }
@@ -0,0 +1,37 @@
1
+ import { Moon, Sun } from "lucide-react";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import {
5
+ DropdownMenu,
6
+ DropdownMenuContent,
7
+ DropdownMenuItem,
8
+ DropdownMenuTrigger,
9
+ } from "@/components/ui/dropdown-menu";
10
+ import { useTheme } from "@/components/theme-provider";
11
+
12
+ export function ModeToggle() {
13
+ const { setTheme, theme } = useTheme();
14
+
15
+ return (
16
+ <DropdownMenu>
17
+ <DropdownMenuTrigger asChild>
18
+ <Button variant="outline" size="icon">
19
+ <Sun className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
20
+ <Moon className="absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
21
+ <span className="sr-only">Toggle theme</span>
22
+ </Button>
23
+ </DropdownMenuTrigger>
24
+ <DropdownMenuContent align="end">
25
+ <DropdownMenuItem onClick={() => setTheme("light")}>
26
+ Light
27
+ </DropdownMenuItem>
28
+ <DropdownMenuItem onClick={() => setTheme("dark")}>
29
+ Dark
30
+ </DropdownMenuItem>
31
+ <DropdownMenuItem onClick={() => setTheme("system")}>
32
+ System
33
+ </DropdownMenuItem>
34
+ </DropdownMenuContent>
35
+ </DropdownMenu>
36
+ );
37
+ }
@@ -0,0 +1,73 @@
1
+ import { createContext, useContext, useEffect, useState } from "react";
2
+
3
+ type Theme = "dark" | "light" | "system";
4
+
5
+ type ThemeProviderProps = {
6
+ children: React.ReactNode;
7
+ defaultTheme?: Theme;
8
+ storageKey?: string;
9
+ };
10
+
11
+ type ThemeProviderState = {
12
+ theme: Theme;
13
+ setTheme: (theme: Theme) => void;
14
+ };
15
+
16
+ const initialState: ThemeProviderState = {
17
+ theme: "system",
18
+ setTheme: () => null,
19
+ };
20
+
21
+ const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
22
+
23
+ export function ThemeProvider({
24
+ children,
25
+ defaultTheme = "system",
26
+ storageKey = "vite-ui-theme",
27
+ ...props
28
+ }: ThemeProviderProps) {
29
+ const [theme, setTheme] = useState<Theme>(
30
+ () => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
31
+ );
32
+
33
+ useEffect(() => {
34
+ const root = window.document.documentElement;
35
+
36
+ root.classList.remove("light", "dark");
37
+
38
+ if (theme === "system") {
39
+ const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
40
+ .matches
41
+ ? "dark"
42
+ : "light";
43
+
44
+ root.classList.add(systemTheme);
45
+ return;
46
+ }
47
+
48
+ root.classList.add(theme);
49
+ }, [theme]);
50
+
51
+ const value = {
52
+ theme,
53
+ setTheme: (theme: Theme) => {
54
+ localStorage.setItem(storageKey, theme);
55
+ setTheme(theme);
56
+ },
57
+ };
58
+
59
+ return (
60
+ <ThemeProviderContext.Provider {...props} value={value}>
61
+ {children}
62
+ </ThemeProviderContext.Provider>
63
+ );
64
+ }
65
+
66
+ export const useTheme = () => {
67
+ const context = useContext(ThemeProviderContext);
68
+
69
+ if (context === undefined)
70
+ throw new Error("useTheme must be used within a ThemeProvider");
71
+
72
+ return context;
73
+ };
@@ -0,0 +1,57 @@
1
+ import * as React from "react"
2
+ import { Slot } from "@radix-ui/react-slot"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const buttonVariants = cva(
8
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
14
+ destructive:
15
+ "bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90",
16
+ outline:
17
+ "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
18
+ secondary:
19
+ "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
20
+ ghost: "hover:bg-accent hover:text-accent-foreground",
21
+ link: "text-primary underline-offset-4 hover:underline",
22
+ },
23
+ size: {
24
+ default: "h-9 px-4 py-2",
25
+ sm: "h-8 rounded-md px-3 text-xs",
26
+ lg: "h-10 rounded-md px-8",
27
+ icon: "h-9 w-9",
28
+ },
29
+ },
30
+ defaultVariants: {
31
+ variant: "default",
32
+ size: "default",
33
+ },
34
+ }
35
+ )
36
+
37
+ export interface ButtonProps
38
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
39
+ VariantProps<typeof buttonVariants> {
40
+ asChild?: boolean
41
+ }
42
+
43
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
44
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
45
+ const Comp = asChild ? Slot : "button"
46
+ return (
47
+ <Comp
48
+ className={cn(buttonVariants({ variant, size, className }))}
49
+ ref={ref}
50
+ {...props}
51
+ />
52
+ )
53
+ }
54
+ )
55
+ Button.displayName = "Button"
56
+
57
+ export { Button, buttonVariants }
@@ -0,0 +1,92 @@
1
+ import * as React from "react"
2
+
3
+ import { cn } from "@/lib/utils"
4
+
5
+ function Card({ className, ...props }: React.ComponentProps<"div">) {
6
+ return (
7
+ <div
8
+ data-slot="card"
9
+ className={cn(
10
+ "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
19
+ return (
20
+ <div
21
+ data-slot="card-header"
22
+ className={cn(
23
+ "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ )
29
+ }
30
+
31
+ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
32
+ return (
33
+ <div
34
+ data-slot="card-title"
35
+ className={cn("leading-none font-semibold", className)}
36
+ {...props}
37
+ />
38
+ )
39
+ }
40
+
41
+ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
42
+ return (
43
+ <div
44
+ data-slot="card-description"
45
+ className={cn("text-muted-foreground text-sm", className)}
46
+ {...props}
47
+ />
48
+ )
49
+ }
50
+
51
+ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
52
+ return (
53
+ <div
54
+ data-slot="card-action"
55
+ className={cn(
56
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
57
+ className
58
+ )}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
65
+ return (
66
+ <div
67
+ data-slot="card-content"
68
+ className={cn("px-6", className)}
69
+ {...props}
70
+ />
71
+ )
72
+ }
73
+
74
+ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
75
+ return (
76
+ <div
77
+ data-slot="card-footer"
78
+ className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
79
+ {...props}
80
+ />
81
+ )
82
+ }
83
+
84
+ export {
85
+ Card,
86
+ CardHeader,
87
+ CardFooter,
88
+ CardTitle,
89
+ CardAction,
90
+ CardDescription,
91
+ CardContent,
92
+ }
@@ -0,0 +1,30 @@
1
+ import * as React from "react"
2
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
3
+ import { CheckIcon } from "lucide-react"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ function Checkbox({
8
+ className,
9
+ ...props
10
+ }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
11
+ return (
12
+ <CheckboxPrimitive.Root
13
+ data-slot="checkbox"
14
+ className={cn(
15
+ "peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
16
+ className
17
+ )}
18
+ {...props}
19
+ >
20
+ <CheckboxPrimitive.Indicator
21
+ data-slot="checkbox-indicator"
22
+ className="flex items-center justify-center text-current transition-none"
23
+ >
24
+ <CheckIcon className="size-3.5" />
25
+ </CheckboxPrimitive.Indicator>
26
+ </CheckboxPrimitive.Root>
27
+ )
28
+ }
29
+
30
+ export { Checkbox }
@@ -0,0 +1,199 @@
1
+ import * as React from "react"
2
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
3
+ import { Check, ChevronRight, Circle } from "lucide-react"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const DropdownMenu = DropdownMenuPrimitive.Root
8
+
9
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
10
+
11
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group
12
+
13
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal
14
+
15
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub
16
+
17
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
18
+
19
+ const DropdownMenuSubTrigger = React.forwardRef<
20
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
21
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
22
+ inset?: boolean
23
+ }
24
+ >(({ className, inset, children, ...props }, ref) => (
25
+ <DropdownMenuPrimitive.SubTrigger
26
+ ref={ref}
27
+ className={cn(
28
+ "flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
29
+ inset && "pl-8",
30
+ className
31
+ )}
32
+ {...props}
33
+ >
34
+ {children}
35
+ <ChevronRight className="ml-auto" />
36
+ </DropdownMenuPrimitive.SubTrigger>
37
+ ))
38
+ DropdownMenuSubTrigger.displayName =
39
+ DropdownMenuPrimitive.SubTrigger.displayName
40
+
41
+ const DropdownMenuSubContent = React.forwardRef<
42
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
43
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
44
+ >(({ className, ...props }, ref) => (
45
+ <DropdownMenuPrimitive.SubContent
46
+ ref={ref}
47
+ className={cn(
48
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-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",
49
+ className
50
+ )}
51
+ {...props}
52
+ />
53
+ ))
54
+ DropdownMenuSubContent.displayName =
55
+ DropdownMenuPrimitive.SubContent.displayName
56
+
57
+ const DropdownMenuContent = React.forwardRef<
58
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
59
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
60
+ >(({ className, sideOffset = 4, ...props }, ref) => (
61
+ <DropdownMenuPrimitive.Portal>
62
+ <DropdownMenuPrimitive.Content
63
+ ref={ref}
64
+ sideOffset={sideOffset}
65
+ className={cn(
66
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
67
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-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",
68
+ className
69
+ )}
70
+ {...props}
71
+ />
72
+ </DropdownMenuPrimitive.Portal>
73
+ ))
74
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
75
+
76
+ const DropdownMenuItem = React.forwardRef<
77
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
78
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
79
+ inset?: boolean
80
+ }
81
+ >(({ className, inset, ...props }, ref) => (
82
+ <DropdownMenuPrimitive.Item
83
+ ref={ref}
84
+ className={cn(
85
+ "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
86
+ inset && "pl-8",
87
+ className
88
+ )}
89
+ {...props}
90
+ />
91
+ ))
92
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
93
+
94
+ const DropdownMenuCheckboxItem = React.forwardRef<
95
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
96
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
97
+ >(({ className, children, checked, ...props }, ref) => (
98
+ <DropdownMenuPrimitive.CheckboxItem
99
+ ref={ref}
100
+ className={cn(
101
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
102
+ className
103
+ )}
104
+ checked={checked}
105
+ {...props}
106
+ >
107
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
108
+ <DropdownMenuPrimitive.ItemIndicator>
109
+ <Check className="h-4 w-4" />
110
+ </DropdownMenuPrimitive.ItemIndicator>
111
+ </span>
112
+ {children}
113
+ </DropdownMenuPrimitive.CheckboxItem>
114
+ ))
115
+ DropdownMenuCheckboxItem.displayName =
116
+ DropdownMenuPrimitive.CheckboxItem.displayName
117
+
118
+ const DropdownMenuRadioItem = React.forwardRef<
119
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
120
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
121
+ >(({ className, children, ...props }, ref) => (
122
+ <DropdownMenuPrimitive.RadioItem
123
+ ref={ref}
124
+ className={cn(
125
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
126
+ className
127
+ )}
128
+ {...props}
129
+ >
130
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
131
+ <DropdownMenuPrimitive.ItemIndicator>
132
+ <Circle className="h-2 w-2 fill-current" />
133
+ </DropdownMenuPrimitive.ItemIndicator>
134
+ </span>
135
+ {children}
136
+ </DropdownMenuPrimitive.RadioItem>
137
+ ))
138
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
139
+
140
+ const DropdownMenuLabel = React.forwardRef<
141
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
142
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
143
+ inset?: boolean
144
+ }
145
+ >(({ className, inset, ...props }, ref) => (
146
+ <DropdownMenuPrimitive.Label
147
+ ref={ref}
148
+ className={cn(
149
+ "px-2 py-1.5 text-sm font-semibold",
150
+ inset && "pl-8",
151
+ className
152
+ )}
153
+ {...props}
154
+ />
155
+ ))
156
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
157
+
158
+ const DropdownMenuSeparator = React.forwardRef<
159
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
160
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
161
+ >(({ className, ...props }, ref) => (
162
+ <DropdownMenuPrimitive.Separator
163
+ ref={ref}
164
+ className={cn("-mx-1 my-1 h-px bg-muted", className)}
165
+ {...props}
166
+ />
167
+ ))
168
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
169
+
170
+ const DropdownMenuShortcut = ({
171
+ className,
172
+ ...props
173
+ }: React.HTMLAttributes<HTMLSpanElement>) => {
174
+ return (
175
+ <span
176
+ className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
177
+ {...props}
178
+ />
179
+ )
180
+ }
181
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
182
+
183
+ export {
184
+ DropdownMenu,
185
+ DropdownMenuTrigger,
186
+ DropdownMenuContent,
187
+ DropdownMenuItem,
188
+ DropdownMenuCheckboxItem,
189
+ DropdownMenuRadioItem,
190
+ DropdownMenuLabel,
191
+ DropdownMenuSeparator,
192
+ DropdownMenuShortcut,
193
+ DropdownMenuGroup,
194
+ DropdownMenuPortal,
195
+ DropdownMenuSub,
196
+ DropdownMenuSubContent,
197
+ DropdownMenuSubTrigger,
198
+ DropdownMenuRadioGroup,
199
+ }
@@ -0,0 +1,22 @@
1
+ import * as React from "react"
2
+
3
+ import { cn } from "@/lib/utils"
4
+
5
+ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
6
+ ({ className, type, ...props }, ref) => {
7
+ return (
8
+ <input
9
+ type={type}
10
+ className={cn(
11
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
12
+ className
13
+ )}
14
+ ref={ref}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+ )
20
+ Input.displayName = "Input"
21
+
22
+ export { Input }
@@ -0,0 +1,24 @@
1
+ import * as React from "react"
2
+ import * as LabelPrimitive from "@radix-ui/react-label"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const labelVariants = cva(
8
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
9
+ )
10
+
11
+ const Label = React.forwardRef<
12
+ React.ElementRef<typeof LabelPrimitive.Root>,
13
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
14
+ VariantProps<typeof labelVariants>
15
+ >(({ className, ...props }, ref) => (
16
+ <LabelPrimitive.Root
17
+ ref={ref}
18
+ className={cn(labelVariants(), className)}
19
+ {...props}
20
+ />
21
+ ))
22
+ Label.displayName = LabelPrimitive.Root.displayName
23
+
24
+ export { Label }
@@ -0,0 +1,15 @@
1
+ import { cn } from "@/lib/utils"
2
+
3
+ function Skeleton({
4
+ className,
5
+ ...props
6
+ }: React.HTMLAttributes<HTMLDivElement>) {
7
+ return (
8
+ <div
9
+ className={cn("animate-pulse rounded-md bg-primary/10", className)}
10
+ {...props}
11
+ />
12
+ )
13
+ }
14
+
15
+ export { Skeleton }