create-better-t-stack 1.4.5 → 1.6.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.
Files changed (61) hide show
  1. package/dist/index.js +150 -98
  2. package/package.json +1 -1
  3. package/template/base/apps/{web → web-base}/_gitignore +3 -0
  4. package/template/base/apps/{web → web-base}/components.json +2 -2
  5. package/template/base/apps/{web → web-base}/src/components/mode-toggle.tsx +1 -1
  6. package/template/base/apps/{web → web-base}/src/components/theme-provider.tsx +1 -1
  7. package/template/base/apps/web-base/src/components/ui/button.tsx +59 -0
  8. package/template/base/apps/{web → web-base}/src/components/ui/card.tsx +10 -10
  9. package/template/base/apps/{web → web-base}/src/components/ui/checkbox.tsx +6 -6
  10. package/template/base/apps/web-base/src/components/ui/dropdown-menu.tsx +255 -0
  11. package/template/base/apps/web-base/src/components/ui/input.tsx +21 -0
  12. package/template/base/apps/web-base/src/components/ui/label.tsx +24 -0
  13. package/template/base/apps/web-base/src/components/ui/skeleton.tsx +13 -0
  14. package/template/base/apps/web-base/src/components/ui/sonner.tsx +23 -0
  15. package/template/base/apps/web-base/src/index.css +134 -0
  16. package/template/base/apps/web-react-router/package.json +49 -0
  17. package/template/base/apps/web-react-router/public/favicon.ico +0 -0
  18. package/template/base/apps/web-react-router/react-router.config.ts +6 -0
  19. package/template/base/apps/web-react-router/src/components/header.tsx +31 -0
  20. package/template/base/apps/web-react-router/src/root.tsx +91 -0
  21. package/template/base/apps/web-react-router/src/routes/_index.tsx +89 -0
  22. package/template/base/apps/web-react-router/src/routes.ts +4 -0
  23. package/template/base/apps/web-react-router/tsconfig.json +27 -0
  24. package/template/base/apps/web-react-router/vite.config.ts +8 -0
  25. package/template/base/apps/{web → web-tanstack-router}/package.json +2 -2
  26. package/template/base/apps/{web → web-tanstack-router}/src/routes/index.tsx +1 -4
  27. package/template/examples/ai/apps/web-react-router/src/routes/ai.tsx +64 -0
  28. package/template/examples/todo/apps/web-react-router/src/routes/todos.tsx +130 -0
  29. package/template/examples/todo/apps/{web → web-tanstack-router}/src/routes/todos.tsx +6 -8
  30. package/template/with-auth/apps/web-react-router/src/components/header.tsx +34 -0
  31. package/template/with-auth/apps/web-react-router/src/components/sign-in-form.tsx +135 -0
  32. package/template/with-auth/apps/web-react-router/src/components/sign-up-form.tsx +160 -0
  33. package/template/with-auth/apps/web-react-router/src/components/user-menu.tsx +60 -0
  34. package/template/with-auth/apps/web-react-router/src/routes/dashboard.tsx +30 -0
  35. package/template/with-auth/apps/web-react-router/src/routes/login.tsx +13 -0
  36. package/template/base/apps/web/src/components/ui/button.tsx +0 -57
  37. package/template/base/apps/web/src/components/ui/dropdown-menu.tsx +0 -199
  38. package/template/base/apps/web/src/components/ui/input.tsx +0 -22
  39. package/template/base/apps/web/src/components/ui/label.tsx +0 -24
  40. package/template/base/apps/web/src/components/ui/skeleton.tsx +0 -15
  41. package/template/base/apps/web/src/components/ui/sonner.tsx +0 -29
  42. package/template/base/apps/web/src/index.css +0 -119
  43. package/template/with-pwa/apps/web/vite.config.ts +0 -35
  44. /package/template/base/apps/{web → web-base}/src/components/loader.tsx +0 -0
  45. /package/template/base/apps/{web → web-base}/src/lib/utils.ts +0 -0
  46. /package/template/base/apps/{web → web-base}/src/utils/trpc.ts +0 -0
  47. /package/template/base/apps/{web → web-tanstack-router}/index.html +0 -0
  48. /package/template/base/apps/{web → web-tanstack-router}/src/components/header.tsx +0 -0
  49. /package/template/base/apps/{web → web-tanstack-router}/src/main.tsx +0 -0
  50. /package/template/base/apps/{web → web-tanstack-router}/src/routes/__root.tsx +0 -0
  51. /package/template/base/apps/{web → web-tanstack-router}/tsconfig.json +0 -0
  52. /package/template/base/apps/{web → web-tanstack-router}/vite.config.ts +0 -0
  53. /package/template/examples/ai/apps/{web → web-tanstack-router}/src/routes/ai.tsx +0 -0
  54. /package/template/with-auth/apps/{web → web-base}/src/lib/auth-client.ts +0 -0
  55. /package/template/with-auth/apps/{web → web-base}/src/utils/trpc.ts +0 -0
  56. /package/template/with-auth/apps/{web → web-tanstack-router}/src/components/header.tsx +0 -0
  57. /package/template/with-auth/apps/{web → web-tanstack-router}/src/components/sign-in-form.tsx +0 -0
  58. /package/template/with-auth/apps/{web → web-tanstack-router}/src/components/sign-up-form.tsx +0 -0
  59. /package/template/with-auth/apps/{web → web-tanstack-router}/src/components/user-menu.tsx +0 -0
  60. /package/template/with-auth/apps/{web → web-tanstack-router}/src/routes/dashboard.tsx +0 -0
  61. /package/template/with-auth/apps/{web → web-tanstack-router}/src/routes/login.tsx +0 -0
@@ -0,0 +1,135 @@
1
+ import { authClient } from "@/lib/auth-client";
2
+ import { useForm } from "@tanstack/react-form";
3
+ import { useNavigate } from "react-router";
4
+ import { toast } from "sonner";
5
+ import { z } from "zod";
6
+ import Loader from "./loader";
7
+ import { Button } from "./ui/button";
8
+ import { Input } from "./ui/input";
9
+ import { Label } from "./ui/label";
10
+
11
+ export default function SignInForm({
12
+ onSwitchToSignUp,
13
+ }: {
14
+ onSwitchToSignUp: () => void;
15
+ }) {
16
+ const navigate = useNavigate();
17
+ const { isPending } = authClient.useSession();
18
+
19
+ const form = useForm({
20
+ defaultValues: {
21
+ email: "",
22
+ password: "",
23
+ },
24
+ onSubmit: async ({ value }) => {
25
+ await authClient.signIn.email(
26
+ {
27
+ email: value.email,
28
+ password: value.password,
29
+ },
30
+ {
31
+ onSuccess: () => {
32
+ navigate("/dashboard");
33
+ toast.success("Sign in successful");
34
+ },
35
+ onError: (error) => {
36
+ toast.error(error.error.message);
37
+ },
38
+ }
39
+ );
40
+ },
41
+ validators: {
42
+ onSubmit: z.object({
43
+ email: z.string().email("Invalid email address"),
44
+ password: z.string().min(6, "Password must be at least 6 characters"),
45
+ }),
46
+ },
47
+ });
48
+
49
+ if (isPending) {
50
+ return <Loader />;
51
+ }
52
+
53
+ return (
54
+ <div className="mx-auto w-full mt-10 max-w-md p-6">
55
+ <h1 className="mb-6 text-center text-3xl font-bold">Welcome Back</h1>
56
+
57
+ <form
58
+ onSubmit={(e) => {
59
+ e.preventDefault();
60
+ e.stopPropagation();
61
+ void form.handleSubmit();
62
+ }}
63
+ className="space-y-4"
64
+ >
65
+ <div>
66
+ <form.Field name="email">
67
+ {(field) => (
68
+ <div className="space-y-2">
69
+ <Label htmlFor={field.name}>Email</Label>
70
+ <Input
71
+ id={field.name}
72
+ name={field.name}
73
+ type="email"
74
+ value={field.state.value}
75
+ onBlur={field.handleBlur}
76
+ onChange={(e) => field.handleChange(e.target.value)}
77
+ />
78
+ {field.state.meta.errors.map((error) => (
79
+ <p key={error?.message} className="text-red-500">
80
+ {error?.message}
81
+ </p>
82
+ ))}
83
+ </div>
84
+ )}
85
+ </form.Field>
86
+ </div>
87
+
88
+ <div>
89
+ <form.Field name="password">
90
+ {(field) => (
91
+ <div className="space-y-2">
92
+ <Label htmlFor={field.name}>Password</Label>
93
+ <Input
94
+ id={field.name}
95
+ name={field.name}
96
+ type="password"
97
+ value={field.state.value}
98
+ onBlur={field.handleBlur}
99
+ onChange={(e) => field.handleChange(e.target.value)}
100
+ />
101
+ {field.state.meta.errors.map((error) => (
102
+ <p key={error?.message} className="text-red-500">
103
+ {error?.message}
104
+ </p>
105
+ ))}
106
+ </div>
107
+ )}
108
+ </form.Field>
109
+ </div>
110
+
111
+ <form.Subscribe>
112
+ {(state) => (
113
+ <Button
114
+ type="submit"
115
+ className="w-full"
116
+ disabled={!state.canSubmit || state.isSubmitting}
117
+ >
118
+ {state.isSubmitting ? "Submitting..." : "Sign In"}
119
+ </Button>
120
+ )}
121
+ </form.Subscribe>
122
+ </form>
123
+
124
+ <div className="mt-4 text-center">
125
+ <Button
126
+ variant="link"
127
+ onClick={onSwitchToSignUp}
128
+ className="text-indigo-600 hover:text-indigo-800"
129
+ >
130
+ Need an account? Sign Up
131
+ </Button>
132
+ </div>
133
+ </div>
134
+ );
135
+ }
@@ -0,0 +1,160 @@
1
+ import { authClient } from "@/lib/auth-client";
2
+ import { useForm } from "@tanstack/react-form";
3
+ import { useNavigate } from "react-router";
4
+ import { toast } from "sonner";
5
+ import { z } from "zod";
6
+ import Loader from "./loader";
7
+ import { Button } from "./ui/button";
8
+ import { Input } from "./ui/input";
9
+ import { Label } from "./ui/label";
10
+
11
+ export default function SignUpForm({
12
+ onSwitchToSignIn,
13
+ }: {
14
+ onSwitchToSignIn: () => void;
15
+ }) {
16
+ const navigate = useNavigate();
17
+ const { isPending } = authClient.useSession();
18
+
19
+ const form = useForm({
20
+ defaultValues: {
21
+ email: "",
22
+ password: "",
23
+ name: "",
24
+ },
25
+ onSubmit: async ({ value }) => {
26
+ await authClient.signUp.email(
27
+ {
28
+ email: value.email,
29
+ password: value.password,
30
+ name: value.name,
31
+ },
32
+ {
33
+ onSuccess: () => {
34
+ navigate("/dashboard");
35
+ toast.success("Sign up successful");
36
+ },
37
+ onError: (error) => {
38
+ toast.error(error.error.message);
39
+ },
40
+ }
41
+ );
42
+ },
43
+ validators: {
44
+ onSubmit: z.object({
45
+ name: z.string().min(2, "Name must be at least 2 characters"),
46
+ email: z.string().email("Invalid email address"),
47
+ password: z.string().min(6, "Password must be at least 6 characters"),
48
+ }),
49
+ },
50
+ });
51
+
52
+ if (isPending) {
53
+ return <Loader />;
54
+ }
55
+
56
+ return (
57
+ <div className="mx-auto w-full mt-10 max-w-md p-6">
58
+ <h1 className="mb-6 text-center text-3xl font-bold">Create Account</h1>
59
+
60
+ <form
61
+ onSubmit={(e) => {
62
+ e.preventDefault();
63
+ e.stopPropagation();
64
+ void form.handleSubmit();
65
+ }}
66
+ className="space-y-4"
67
+ >
68
+ <div>
69
+ <form.Field name="name">
70
+ {(field) => (
71
+ <div className="space-y-2">
72
+ <Label htmlFor={field.name}>Name</Label>
73
+ <Input
74
+ id={field.name}
75
+ name={field.name}
76
+ value={field.state.value}
77
+ onBlur={field.handleBlur}
78
+ onChange={(e) => field.handleChange(e.target.value)}
79
+ />
80
+ {field.state.meta.errors.map((error) => (
81
+ <p key={error?.message} className="text-red-500">
82
+ {error?.message}
83
+ </p>
84
+ ))}
85
+ </div>
86
+ )}
87
+ </form.Field>
88
+ </div>
89
+
90
+ <div>
91
+ <form.Field name="email">
92
+ {(field) => (
93
+ <div className="space-y-2">
94
+ <Label htmlFor={field.name}>Email</Label>
95
+ <Input
96
+ id={field.name}
97
+ name={field.name}
98
+ type="email"
99
+ value={field.state.value}
100
+ onBlur={field.handleBlur}
101
+ onChange={(e) => field.handleChange(e.target.value)}
102
+ />
103
+ {field.state.meta.errors.map((error) => (
104
+ <p key={error?.message} className="text-red-500">
105
+ {error?.message}
106
+ </p>
107
+ ))}
108
+ </div>
109
+ )}
110
+ </form.Field>
111
+ </div>
112
+
113
+ <div>
114
+ <form.Field name="password">
115
+ {(field) => (
116
+ <div className="space-y-2">
117
+ <Label htmlFor={field.name}>Password</Label>
118
+ <Input
119
+ id={field.name}
120
+ name={field.name}
121
+ type="password"
122
+ value={field.state.value}
123
+ onBlur={field.handleBlur}
124
+ onChange={(e) => field.handleChange(e.target.value)}
125
+ />
126
+ {field.state.meta.errors.map((error) => (
127
+ <p key={error?.message} className="text-red-500">
128
+ {error?.message}
129
+ </p>
130
+ ))}
131
+ </div>
132
+ )}
133
+ </form.Field>
134
+ </div>
135
+
136
+ <form.Subscribe>
137
+ {(state) => (
138
+ <Button
139
+ type="submit"
140
+ className="w-full"
141
+ disabled={!state.canSubmit || state.isSubmitting}
142
+ >
143
+ {state.isSubmitting ? "Submitting..." : "Sign Up"}
144
+ </Button>
145
+ )}
146
+ </form.Subscribe>
147
+ </form>
148
+
149
+ <div className="mt-4 text-center">
150
+ <Button
151
+ variant="link"
152
+ onClick={onSwitchToSignIn}
153
+ className="text-indigo-600 hover:text-indigo-800"
154
+ >
155
+ Already have an account? Sign In
156
+ </Button>
157
+ </div>
158
+ </div>
159
+ );
160
+ }
@@ -0,0 +1,60 @@
1
+ import {
2
+ DropdownMenu,
3
+ DropdownMenuContent,
4
+ DropdownMenuItem,
5
+ DropdownMenuLabel,
6
+ DropdownMenuSeparator,
7
+ DropdownMenuTrigger,
8
+ } from "@/components/ui/dropdown-menu";
9
+ import { authClient } from "@/lib/auth-client";
10
+ import { useNavigate } from "react-router";
11
+ import { Button } from "./ui/button";
12
+ import { Skeleton } from "./ui/skeleton";
13
+ import { Link } from "react-router";
14
+
15
+ export default function UserMenu() {
16
+ const navigate = useNavigate();
17
+ const { data: session, isPending } = authClient.useSession();
18
+
19
+ if (isPending) {
20
+ return <Skeleton className="h-9 w-24" />;
21
+ }
22
+
23
+ if (!session) {
24
+ return (
25
+ <Button variant="outline" asChild>
26
+ <Link to="/login">Sign In</Link>
27
+ </Button>
28
+ );
29
+ }
30
+
31
+ return (
32
+ <DropdownMenu>
33
+ <DropdownMenuTrigger asChild>
34
+ <Button variant="outline">{session.user.name}</Button>
35
+ </DropdownMenuTrigger>
36
+ <DropdownMenuContent className="bg-card">
37
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
38
+ <DropdownMenuSeparator />
39
+ <DropdownMenuItem>{session.user.email}</DropdownMenuItem>
40
+ <DropdownMenuItem asChild>
41
+ <Button
42
+ variant="destructive"
43
+ className="w-full"
44
+ onClick={() => {
45
+ authClient.signOut({
46
+ fetchOptions: {
47
+ onSuccess: () => {
48
+ navigate("/");
49
+ },
50
+ },
51
+ });
52
+ }}
53
+ >
54
+ Sign Out
55
+ </Button>
56
+ </DropdownMenuItem>
57
+ </DropdownMenuContent>
58
+ </DropdownMenu>
59
+ );
60
+ }
@@ -0,0 +1,30 @@
1
+ import { authClient } from "@/lib/auth-client";
2
+ import { trpc } from "@/utils/trpc";
3
+ import { useQuery } from "@tanstack/react-query";
4
+ import { useEffect } from "react";
5
+ import { useNavigate } from "react-router";
6
+
7
+ export default function Dashboard() {
8
+ const { data: session, isPending } = authClient.useSession();
9
+ const navigate = useNavigate();
10
+
11
+ const privateData = useQuery(trpc.privateData.queryOptions());
12
+
13
+ useEffect(() => {
14
+ if (!session && !isPending) {
15
+ navigate("/login");
16
+ }
17
+ }, [session, isPending]);
18
+
19
+ if (isPending) {
20
+ return <div>Loading...</div>;
21
+ }
22
+
23
+ return (
24
+ <div>
25
+ <h1>Dashboard</h1>
26
+ <p>Welcome {session?.user.name}</p>
27
+ <p>privateData: {privateData.data?.message}</p>
28
+ </div>
29
+ );
30
+ }
@@ -0,0 +1,13 @@
1
+ import SignInForm from "@/components/sign-in-form";
2
+ import SignUpForm from "@/components/sign-up-form";
3
+ import { useState } from "react";
4
+
5
+ export default function Login() {
6
+ const [showSignIn, setShowSignIn] = useState(false);
7
+
8
+ return showSignIn ? (
9
+ <SignInForm onSwitchToSignUp={() => setShowSignIn(false)} />
10
+ ) : (
11
+ <SignUpForm onSwitchToSignIn={() => setShowSignIn(true)} />
12
+ );
13
+ }
@@ -1,57 +0,0 @@
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 }
@@ -1,199 +0,0 @@
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
- }
@@ -1,22 +0,0 @@
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 }