Skip to content
71 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Inbox: a bell in the top bar opens it beside the page, and /inbox holds it all1import { X } from "lucide-react";
2import { Dialog as Primitive } from "radix-ui";
3import type { ComponentProps } from "react";
4
5import { cn } from "../../lib/cn";
6import { DialogOverlay } from "./dialog";
7
8// shadcn/ui's sheet, styled with g1t's tokens: a dialog that slides in
9// from the edge of the screen, for a panel to work in beside the page.
10
11export const Sheet = Primitive.Root;
12export const SheetTrigger = Primitive.Trigger;
13export const SheetClose = Primitive.Close;
14
15type Side = "right" | "left";
16
17const SIDES: Record<Side, string> = {
18 // Full width on a phone, a column beside the page from there up.
19 right:
20 "inset-y-0 right-0 border-l data-[state=open]:animate-sheet-in-right data-[state=closed]:animate-sheet-out-right sm:max-w-md",
21 left: "inset-y-0 left-0 border-r data-[state=open]:animate-sheet-in-left data-[state=closed]:animate-sheet-out-left sm:max-w-md",
22};
23
24export function SheetContent({
25 side = "right",
26 className,
27 children,
28 showClose = true,
29 ...props
30}: ComponentProps<typeof Primitive.Content> & { side?: Side; showClose?: boolean }) {
31 return (
32 <Primitive.Portal>
33 <DialogOverlay />
34 <Primitive.Content
35 className={cn(
Phones reach every page: each mode's menu from the top bar or by tapping the tab you're on, Docs first in the avatar sheet, a project's pages as a swipeable strip; dialogs as bottom sheets above the keyboard, safe areas, menus kept on screen, 40px targets, touch-visible controls, save bars above the tab bar36 // Clear of the notch and the home indicator on a phone.
37 "fixed z-50 flex h-dvh w-full flex-col border-line-strong bg-surface pt-[env(safe-area-inset-top)] pb-[env(safe-area-inset-bottom)] text-fg shadow-2xl shadow-black/60 outline-none motion-reduce:animate-none",
Inbox: a bell in the top bar opens it beside the page, and /inbox holds it all38 SIDES[side],
39 className,
40 )}
41 {...props}
42 >
43 {children}
44 {showClose && (
45 <Primitive.Close
46 aria-label="Close"
Phones reach every page: each mode's menu from the top bar or by tapping the tab you're on, Docs first in the avatar sheet, a project's pages as a swipeable strip; dialogs as bottom sheets above the keyboard, safe areas, menus kept on screen, 40px targets, touch-visible controls, save bars above the tab bar47 className="absolute top-[calc(1rem+env(safe-area-inset-top))] right-4 rounded-md p-1 text-faint transition-colors hover:bg-raised hover:text-fg max-sm:top-[calc(0.75rem+env(safe-area-inset-top))] max-sm:right-3 max-sm:flex max-sm:size-10 max-sm:items-center max-sm:justify-center"
Inbox: a bell in the top bar opens it beside the page, and /inbox holds it all48 >
49 <X size={16} />
50 </Primitive.Close>
51 )}
52 </Primitive.Content>
53 </Primitive.Portal>
54 );
55}
56
57export function SheetHeader({ className, ...props }: ComponentProps<"div">) {
58 return <div className={cn("flex flex-col gap-1.5 border-b border-line px-5 py-4 pr-12", className)} {...props} />;
59}
60
61export function SheetFooter({ className, ...props }: ComponentProps<"div">) {
62 return <div className={cn("mt-auto flex items-center gap-2 border-t border-line px-5 py-3", className)} {...props} />;
63}
64
65export function SheetTitle({ className, ...props }: ComponentProps<typeof Primitive.Title>) {
66 return <Primitive.Title className={cn("text-base font-semibold tracking-tight", className)} {...props} />;
67}
68
69export function SheetDescription({ className, ...props }: ComponentProps<typeof Primitive.Description>) {
70 return <Primitive.Description className={cn("text-sm text-muted", className)} {...props} />;
71}