Skip to content

Commit abc0846

Browse files
wangshu24TheOrcDev
andauthored
Feat/drawer (#195)
* setting up 8bit version of the drawer component, setting up the template for the drawer page and example from shadcn * made drawer component for content, trigger, footer and header into 8bit pixel style * added example of drawer component, metadata graph image and ran registry build * fix issue with dark mode button border not yellow * reran registry build * rewrite content component to make use of vaul primitive drawer content and modify drawer handle * reran registry build * remove top side for drawer content * reran registry build * refactor: update drawer and sheet components styling and positioning * feat(drawer) change example code --------- Co-authored-by: OrcDev <urosmiric88@gmail.com>
1 parent d86ce2e commit abc0846

File tree

8 files changed

+432
-0
lines changed

8 files changed

+432
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import * as React from "react"
2+
import { Metadata } from "next"
3+
4+
import { drawerMetaData } from "@/lib/metadata"
5+
import { Separator } from "@/components/ui/separator"
6+
import { DrawerExample } from "@/components/examples/drawer"
7+
import CodeSnippet from "@/app/docs/components/code-snippet"
8+
import CopyCommandButton from "@/app/docs/components/copy-command-button"
9+
import InstallationCommands from "@/app/docs/components/installation-commands"
10+
import { OpenInV0Button } from "@/app/docs/components/open-in-v0-button"
11+
12+
export const metadata: Metadata = {
13+
title: "8-bit Drawer",
14+
description: "Displays an 8-bit drawer component.",
15+
openGraph: {
16+
images: drawerMetaData,
17+
},
18+
}
19+
20+
export default function DrawerPaged() {
21+
return (
22+
<div className="flex flex-col gap-4">
23+
<div className="flex flex-col md:flex-row items-center justify-between gap-2">
24+
<h1 className="text-3xl font-bold">Drawer</h1>
25+
<CopyCommandButton
26+
copyCommand={`pnpm dlx shadcn@canary add ${process.env.NEXT_PUBLIC_BASE_URL}/r/8bit-drawer.json`}
27+
command={"pnpm dlx shadcn@canary add 8bit-drawer"}
28+
/>
29+
</div>
30+
31+
<p className="text-muted-foreground">
32+
Displays an 8-bit drawer component.
33+
</p>
34+
35+
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px]">
36+
<div className="flex items-center justify-between">
37+
<h2 className="text-sm text-muted-foreground sm:pl-3">
38+
8-bit drawer component
39+
</h2>
40+
41+
<div className="flex items-center gap-2">
42+
<OpenInV0Button name="8bit-drawer" className="w-fit" />
43+
</div>
44+
</div>
45+
<div className="flex items-center justify-center min-h-[400px] relative">
46+
{/* {Demo here} */}
47+
<DrawerExample />
48+
</div>
49+
</div>
50+
51+
<h3 className="text-lg font-bold">Installation</h3>
52+
53+
<Separator />
54+
55+
<InstallationCommands
56+
packageUrl={`${process.env.NEXT_PUBLIC_BASE_URL}/r/8bit-drawer.json`}
57+
/>
58+
59+
<h3 className="text-lg font-bold mt-10">Usage</h3>
60+
61+
<Separator />
62+
63+
<CodeSnippet>{`import {
64+
Drawer,
65+
DrawerClose,
66+
DrawerContent,
67+
DrawerDescription,
68+
DrawerFooter,
69+
DrawerHeader,
70+
DrawerTitle,
71+
DrawerTrigger,
72+
} from "@/components/ui/8bit/drawer"`}</CodeSnippet>
73+
74+
<CodeSnippet>{`<Drawer>
75+
<DrawerTrigger>Open</DrawerTrigger>
76+
<DrawerContent>
77+
<DrawerHeader>
78+
<DrawerTitle>Are you absolutely sure?</DrawerTitle>
79+
<DrawerDescription>This action cannot be undone.</DrawerDescription>
80+
</DrawerHeader>
81+
<DrawerFooter>
82+
<Button>Submit</Button>
83+
<DrawerClose>
84+
<Button variant="outline">Cancel</Button>
85+
</DrawerClose>
86+
</DrawerFooter>
87+
</DrawerContent>
88+
</Drawer>`}</CodeSnippet>
89+
</div>
90+
)
91+
}

components/examples/drawer.tsx

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import { Minus, Plus } from "lucide-react"
5+
import { Bar, BarChart, ResponsiveContainer } from "recharts"
6+
7+
import { Button } from "@/components/ui/8bit/button"
8+
import {
9+
Drawer,
10+
DrawerClose,
11+
DrawerContent,
12+
DrawerDescription,
13+
DrawerFooter,
14+
DrawerHeader,
15+
DrawerTitle,
16+
DrawerTrigger,
17+
} from "@/components/ui/8bit/drawer"
18+
19+
const data = [
20+
{
21+
goal: 400,
22+
},
23+
{
24+
goal: 300,
25+
},
26+
{
27+
goal: 200,
28+
},
29+
{
30+
goal: 300,
31+
},
32+
{
33+
goal: 200,
34+
},
35+
{
36+
goal: 278,
37+
},
38+
{
39+
goal: 189,
40+
},
41+
{
42+
goal: 239,
43+
},
44+
{
45+
goal: 300,
46+
},
47+
{
48+
goal: 200,
49+
},
50+
{
51+
goal: 278,
52+
},
53+
{
54+
goal: 189,
55+
},
56+
{
57+
goal: 349,
58+
},
59+
]
60+
61+
export function DrawerExample() {
62+
const [goal, setGoal] = React.useState(350)
63+
64+
function onClick(adjustment: number) {
65+
setGoal(Math.max(200, Math.min(400, goal + adjustment)))
66+
}
67+
68+
return (
69+
<Drawer>
70+
<DrawerTrigger asChild className="border-none">
71+
<Button variant="outline">Open Drawer</Button>
72+
</DrawerTrigger>
73+
<DrawerContent side="bottom">
74+
<div className="mx-auto w-full max-w-sm">
75+
<DrawerHeader>
76+
<DrawerTitle>Move Goal</DrawerTitle>
77+
<DrawerDescription>Set your daily activity goal.</DrawerDescription>
78+
</DrawerHeader>
79+
<div className="p-4 pb-0">
80+
<div className="flex items-center justify-center space-x-2">
81+
<Button
82+
variant="outline"
83+
size="icon"
84+
className="size-10 shrink-0"
85+
onClick={() => onClick(-10)}
86+
disabled={goal <= 200}
87+
>
88+
<Minus />
89+
<span className="sr-only">Decrease</span>
90+
</Button>
91+
<div className="flex-1 text-center">
92+
<div className="text-3xl sm:text-7xl font-bold tracking-tighter">
93+
{goal}
94+
</div>
95+
<div className="text-[0.70rem] uppercase text-muted-foreground">
96+
Calories/day
97+
</div>
98+
</div>
99+
<Button
100+
variant="outline"
101+
size="icon"
102+
className="size-10 shrink-0"
103+
onClick={() => onClick(10)}
104+
disabled={goal >= 400}
105+
>
106+
<Plus />
107+
<span className="sr-only">Increase</span>
108+
</Button>
109+
</div>
110+
<div className="mt-3 h-[120px]">
111+
<ResponsiveContainer width="100%" height="100%">
112+
<BarChart data={data}>
113+
<Bar
114+
dataKey="goal"
115+
style={
116+
{
117+
fill: "white",
118+
opacity: 0.9,
119+
} as React.CSSProperties
120+
}
121+
/>
122+
</BarChart>
123+
</ResponsiveContainer>
124+
</div>
125+
</div>
126+
<DrawerFooter className="flex flex-col gap-5">
127+
<Button>Submit</Button>
128+
<DrawerClose asChild>
129+
<Button variant="outline">Cancel</Button>
130+
</DrawerClose>
131+
</DrawerFooter>
132+
</div>
133+
</DrawerContent>
134+
</Drawer>
135+
)
136+
}

components/ui/8bit/drawer.tsx

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import { Press_Start_2P } from "next/font/google"
2+
import { cva, VariantProps } from "class-variance-authority"
3+
import { Drawer as DrawerPrimitive } from "vaul"
4+
5+
import { cn } from "@/lib/utils"
6+
import {
7+
Drawer as ShadcnDrawer,
8+
DrawerClose as ShadcnDrawerClose,
9+
DrawerDescription as ShadcnDrawerDescription,
10+
DrawerFooter as ShadcnDrawerFooter,
11+
DrawerHeader as ShadcnDrawerHeader,
12+
DrawerOverlay as ShadcnDrawerOverlay,
13+
DrawerPortal as ShadcnDrawerPortal,
14+
DrawerTitle as ShadcnDrawerTitle,
15+
DrawerTrigger as ShadcnDrawerTrigger,
16+
} from "@/components/ui/drawer"
17+
18+
const pressStart = Press_Start_2P({
19+
weight: ["400"],
20+
subsets: ["latin"],
21+
})
22+
23+
const Drawer = ShadcnDrawer
24+
25+
const DrawerPortal = ShadcnDrawerPortal
26+
27+
const DrawerOverlay = ShadcnDrawerOverlay
28+
29+
const DrawerClose = ShadcnDrawerClose
30+
31+
function DrawerTitle({
32+
className,
33+
children,
34+
...props
35+
}: React.ComponentProps<typeof DrawerPrimitive.Title>) {
36+
return (
37+
<ShadcnDrawerTitle
38+
className={cn(className, pressStart.className)}
39+
{...props}
40+
>
41+
{children}
42+
</ShadcnDrawerTitle>
43+
)
44+
}
45+
46+
function DrawerDescription({
47+
className,
48+
children,
49+
...props
50+
}: React.ComponentProps<typeof DrawerPrimitive.Description>) {
51+
return (
52+
<ShadcnDrawerDescription
53+
className={cn(className, pressStart.className)}
54+
{...props}
55+
>
56+
{children}
57+
</ShadcnDrawerDescription>
58+
)
59+
}
60+
61+
function DrawerTrigger({
62+
className,
63+
children,
64+
...props
65+
}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
66+
return (
67+
<>
68+
<ShadcnDrawerTrigger
69+
className={cn(
70+
"border-foreground dark:border-ring hover:bg-transparent active:bg-transparent focus:bg-transparent rounded-none border-4 focus:border-foreground hover:border-foreground dark:focus:border-ring bg-transparent data-[state=open]:bg-transparent data-[state=open]:border-foreground dark:data-[state=open]:border-ring",
71+
className,
72+
pressStart.className
73+
)}
74+
{...props}
75+
>
76+
{children}
77+
</ShadcnDrawerTrigger>
78+
</>
79+
)
80+
}
81+
82+
export const drawerVariants = cva("", {
83+
variants: {
84+
font: {
85+
normal: "",
86+
retro: pressStart.className,
87+
},
88+
},
89+
defaultVariants: {
90+
font: "retro",
91+
},
92+
})
93+
94+
export type DrawerProps = React.ComponentProps<typeof DrawerPrimitive.Content> &
95+
VariantProps<typeof drawerVariants> & {
96+
side?: "right" | "bottom" | "left"
97+
}
98+
99+
function DrawerContent({ className, children, side, ...props }: DrawerProps) {
100+
return (
101+
<ShadcnDrawerPortal data-slot="drawer-portal">
102+
<ShadcnDrawerOverlay />
103+
<DrawerPrimitive.Content
104+
data-slot="drawer-content"
105+
className={cn(
106+
"border-foreground dark:border-ring rounded-none",
107+
"group/drawer-content bg-background fixed z-50 flex h-auto flex-col",
108+
side === "right" &&
109+
"border-l-4 data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 sm:max-w-sm",
110+
side === "left" &&
111+
"border-r-4 data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 sm:max-w-sm",
112+
side === "bottom" &&
113+
"border-t-4 data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto",
114+
className,
115+
pressStart.className
116+
)}
117+
{...props}
118+
>
119+
<div className="bg-muted mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-none group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
120+
{children}
121+
</DrawerPrimitive.Content>
122+
</ShadcnDrawerPortal>
123+
)
124+
}
125+
126+
function DrawerHeader({
127+
className,
128+
children,
129+
...props
130+
}: React.ComponentProps<"div">) {
131+
return (
132+
<ShadcnDrawerHeader
133+
className={cn("", className, pressStart.className)}
134+
{...props}
135+
>
136+
{children}
137+
</ShadcnDrawerHeader>
138+
)
139+
}
140+
141+
function DrawerFooter({
142+
className,
143+
children,
144+
...props
145+
}: React.ComponentProps<"div">) {
146+
return (
147+
<ShadcnDrawerFooter
148+
className={cn("", className, pressStart.className)}
149+
{...props}
150+
>
151+
{children}
152+
</ShadcnDrawerFooter>
153+
)
154+
}
155+
156+
export {
157+
Drawer,
158+
DrawerHeader,
159+
DrawerFooter,
160+
DrawerClose,
161+
DrawerTrigger,
162+
DrawerContent,
163+
DrawerOverlay,
164+
DrawerPortal,
165+
DrawerTitle,
166+
DrawerDescription,
167+
}

0 commit comments

Comments
 (0)