Skip to content

Commit 5467d5a

Browse files
committed
Initial setup shadcn, UI, zod...
1 parent 7ea1785 commit 5467d5a

24 files changed

+1536
-7
lines changed

.vscode/settings.json

+3
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,8 @@
3939
"Readme*": "AUTHORS, Authors, BACKERS*, Backers*, CHANGELOG*, CITATION*, CODEOWNERS, CODE_OF_CONDUCT*, CONTRIBUTING*, CONTRIBUTORS, COPYING*, CREDITS, Changelog*, Citation*, Code_Of_Conduct*, Codeowners, Contributing*, Contributors, Copying*, Credits, GOVERNANCE.MD, Governance.md, HISTORY.MD, History.md, LICENSE*, License*, MAINTAINERS, Maintainers, README-*, README_*, RELEASE_NOTES*, ROADMAP.MD, Readme-*, Readme_*, Release_Notes*, Roadmap.md, SECURITY.MD, SPONSORS*, Security.md, Sponsors*, authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying*, credits, governance.md, history.md, license*, maintainers, readme-*, readme_*, release_notes*, roadmap.md, security.md, sponsors*",
4040
"README*": "AUTHORS, Authors, BACKERS*, Backers*, CHANGELOG*, CITATION*, CODEOWNERS, CODE_OF_CONDUCT*, CONTRIBUTING*, CONTRIBUTORS, COPYING*, CREDITS, Changelog*, Citation*, Code_Of_Conduct*, Codeowners, Contributing*, Contributors, Copying*, Credits, GOVERNANCE.MD, Governance.md, HISTORY.MD, History.md, LICENSE*, License*, MAINTAINERS, Maintainers, README-*, README_*, RELEASE_NOTES*, ROADMAP.MD, Readme-*, Readme_*, Release_Notes*, Roadmap.md, SECURITY.MD, SPONSORS*, Security.md, Sponsors*, authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying*, credits, governance.md, history.md, license*, maintainers, readme-*, readme_*, release_notes*, roadmap.md, security.md, sponsors*",
4141
"Dockerfile": "*.dockerfile, .devcontainer.*, .dockerignore, captain-definition, compose.*, docker-compose.*, dockerfile*"
42+
},
43+
"[prisma]": {
44+
"editor.defaultFormatter": "Prisma.prisma"
4245
}
4346
}

app/components/dashboard/header.tsx

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Form, Link } from "react-router"
2+
import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar"
3+
import { Button } from "~/components/ui/button"
4+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "~/components/ui/dropdown-menu"
5+
6+
interface HeaderProps {
7+
email: string | undefined
8+
}
9+
10+
export function Header({ email }: HeaderProps) {
11+
const getInitials = (email: string) => {
12+
return email?.split("@")[0].slice(0, 2).toUpperCase() || "??"
13+
}
14+
15+
return (
16+
<header className="bg-white shadow">
17+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
18+
<div className="flex justify-between items-center">
19+
<h1 className="text-2xl font-bold text-gray-900">Dashboard</h1>
20+
<div className="flex items-center gap-4">
21+
<DropdownMenu>
22+
<DropdownMenuTrigger asChild>
23+
<Button variant="ghost" className="relative h-10 w-10 rounded-full">
24+
<Avatar>
25+
<AvatarImage src="" alt={email} />
26+
<AvatarFallback>{email ? getInitials(email) : "??"}</AvatarFallback>
27+
</Avatar>
28+
</Button>
29+
</DropdownMenuTrigger>
30+
<DropdownMenuContent align="end">
31+
<DropdownMenuItem>
32+
<Link to="/profile" className="w-full">
33+
Profile Settings
34+
</Link>
35+
</DropdownMenuItem>
36+
<DropdownMenuItem>
37+
<Form method="post" action="/logout">
38+
<button className="w-full" type="submit">
39+
Sign out
40+
</button>
41+
</Form>
42+
</DropdownMenuItem>
43+
</DropdownMenuContent>
44+
</DropdownMenu>
45+
</div>
46+
</div>
47+
</div>
48+
</header>
49+
)
50+
}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
interface StatsCardProps {
2+
title: string
3+
value: string | number
4+
description: string
5+
}
6+
7+
export function StatsCard({ title, value, description }: StatsCardProps) {
8+
return (
9+
<div className="bg-white overflow-hidden shadow rounded-lg">
10+
<div className="p-5">
11+
<div className="flex items-center">
12+
<div className="flex-1">
13+
<dt className="text-sm font-medium text-gray-500 truncate">{title}</dt>
14+
<dd className="mt-1 text-3xl font-semibold text-gray-900">{value}</dd>
15+
</div>
16+
</div>
17+
<div className="mt-4">
18+
<p className="text-sm text-gray-500">{description}</p>
19+
</div>
20+
</div>
21+
</div>
22+
)
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
interface WelcomeBannerProps {
2+
email: string | undefined
3+
}
4+
5+
export function WelcomeBanner({ email }: WelcomeBannerProps) {
6+
return (
7+
<div className="bg-white overflow-hidden shadow rounded-lg">
8+
<div className="px-4 py-5 sm:p-6">
9+
<h2 className="text-xl font-semibold text-gray-900 mb-2">Welcome back, {email}!</h2>
10+
<p className="text-gray-500">Here's what's happening with your account today.</p>
11+
</div>
12+
</div>
13+
)
14+
}

app/components/ui/avatar.tsx

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import * as React from "react"
2+
import * as AvatarPrimitive from "@radix-ui/react-avatar"
3+
import { cn } from "~/utils/css"
4+
5+
const Avatar = React.forwardRef<
6+
React.ElementRef<typeof AvatarPrimitive.Root>,
7+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
8+
>(({ className, ...props }, ref) => (
9+
<AvatarPrimitive.Root
10+
ref={ref}
11+
className={cn(
12+
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
13+
className
14+
)}
15+
{...props}
16+
/>
17+
))
18+
Avatar.displayName = AvatarPrimitive.Root.displayName
19+
20+
const AvatarImage = React.forwardRef<
21+
React.ElementRef<typeof AvatarPrimitive.Image>,
22+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
23+
>(({ className, ...props }, ref) => (
24+
<AvatarPrimitive.Image
25+
ref={ref}
26+
className={cn("aspect-square h-full w-full", className)}
27+
{...props}
28+
/>
29+
))
30+
AvatarImage.displayName = AvatarPrimitive.Image.displayName
31+
32+
const AvatarFallback = React.forwardRef<
33+
React.ElementRef<typeof AvatarPrimitive.Fallback>,
34+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
35+
>(({ className, ...props }, ref) => (
36+
<AvatarPrimitive.Fallback
37+
ref={ref}
38+
className={cn(
39+
"flex h-full w-full items-center justify-center rounded-full bg-muted",
40+
className
41+
)}
42+
{...props}
43+
/>
44+
))
45+
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
46+
47+
export { Avatar, AvatarImage, AvatarFallback }

app/components/ui/button.tsx

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import * as React from "react"
2+
import { Slot } from "@radix-ui/react-slot"
3+
import { cva, type VariantProps } from "class-variance-authority"
4+
import { cn } from "~/utils/css"
5+
6+
const buttonVariants = cva(
7+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
8+
{
9+
variants: {
10+
variant: {
11+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
12+
destructive:
13+
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
14+
outline:
15+
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
16+
secondary:
17+
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
18+
ghost: "hover:bg-accent hover:text-accent-foreground",
19+
link: "text-primary underline-offset-4 hover:underline",
20+
},
21+
size: {
22+
default: "h-10 px-4 py-2",
23+
sm: "h-9 rounded-md px-3",
24+
lg: "h-11 rounded-md px-8",
25+
icon: "h-10 w-10",
26+
},
27+
},
28+
defaultVariants: {
29+
variant: "default",
30+
size: "default",
31+
},
32+
}
33+
)
34+
35+
export interface ButtonProps
36+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
37+
VariantProps<typeof buttonVariants> {
38+
asChild?: boolean
39+
}
40+
41+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
42+
({ className, variant, size, asChild = false, ...props }, ref) => {
43+
const Comp = asChild ? Slot : "button"
44+
return (
45+
<Comp
46+
className={cn(buttonVariants({ variant, size, className }))}
47+
ref={ref}
48+
{...props}
49+
/>
50+
)
51+
}
52+
)
53+
Button.displayName = "Button"
54+
55+
export { Button, buttonVariants }

0 commit comments

Comments
 (0)