Added mobile support
This commit is contained in:
67
package-lock.json
generated
67
package-lock.json
generated
@@ -10,10 +10,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^3.7.0",
|
"@hookform/resolvers": "^3.7.0",
|
||||||
"@radix-ui/react-checkbox": "^1.1.1",
|
"@radix-ui/react-checkbox": "^1.1.1",
|
||||||
|
"@radix-ui/react-dialog": "^1.1.1",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.0",
|
"@radix-ui/react-navigation-menu": "^1.2.0",
|
||||||
|
"@radix-ui/react-scroll-area": "^1.1.0",
|
||||||
"@radix-ui/react-select": "^2.1.1",
|
"@radix-ui/react-select": "^2.1.1",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
"@radix-ui/react-tabs": "^1.1.0",
|
"@radix-ui/react-tabs": "^1.1.0",
|
||||||
@@ -2938,6 +2940,41 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.0",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.0",
|
||||||
|
"@radix-ui/react-context": "1.1.0",
|
||||||
|
"@radix-ui/react-dismissable-layer": "1.1.0",
|
||||||
|
"@radix-ui/react-focus-guards": "1.1.0",
|
||||||
|
"@radix-ui/react-focus-scope": "1.1.0",
|
||||||
|
"@radix-ui/react-id": "1.1.0",
|
||||||
|
"@radix-ui/react-portal": "1.1.1",
|
||||||
|
"@radix-ui/react-presence": "1.1.0",
|
||||||
|
"@radix-ui/react-primitive": "2.0.0",
|
||||||
|
"@radix-ui/react-slot": "1.1.0",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||||
|
"aria-hidden": "^1.1.1",
|
||||||
|
"react-remove-scroll": "2.5.7"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-direction": {
|
"node_modules/@radix-ui/react-direction": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
|
||||||
@@ -3294,6 +3331,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-scroll-area": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-9ArIZ9HWhsrfqS765h+GZuLoxaRHD/j0ZWOWilsCvYTpYJp8XwCqNG7Dt9Nu/TItKOdgLGkOPCodQvDc+UMwYg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/number": "1.1.0",
|
||||||
|
"@radix-ui/primitive": "1.1.0",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.0",
|
||||||
|
"@radix-ui/react-context": "1.1.0",
|
||||||
|
"@radix-ui/react-direction": "1.1.0",
|
||||||
|
"@radix-ui/react-presence": "1.1.0",
|
||||||
|
"@radix-ui/react-primitive": "2.0.0",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-select": {
|
"node_modules/@radix-ui/react-select": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz",
|
||||||
|
|||||||
@@ -11,10 +11,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^3.7.0",
|
"@hookform/resolvers": "^3.7.0",
|
||||||
"@radix-ui/react-checkbox": "^1.1.1",
|
"@radix-ui/react-checkbox": "^1.1.1",
|
||||||
|
"@radix-ui/react-dialog": "^1.1.1",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.0",
|
"@radix-ui/react-navigation-menu": "^1.2.0",
|
||||||
|
"@radix-ui/react-scroll-area": "^1.1.0",
|
||||||
"@radix-ui/react-select": "^2.1.1",
|
"@radix-ui/react-select": "^2.1.1",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
"@radix-ui/react-tabs": "^1.1.0",
|
"@radix-ui/react-tabs": "^1.1.0",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ function getDefaultPlatformBasedOnUserAgent() {
|
|||||||
userAgent = window.navigator.userAgent;
|
userAgent = window.navigator.userAgent;
|
||||||
}
|
}
|
||||||
if (userAgent.includes("Win")) {
|
if (userAgent.includes("Win")) {
|
||||||
return "WindowsStubInstaller";
|
return "WindowsInstaller";
|
||||||
}
|
}
|
||||||
if (userAgent.includes("Mac")) {
|
if (userAgent.includes("Mac")) {
|
||||||
return "MacOS";
|
return "MacOS";
|
||||||
@@ -56,8 +56,8 @@ export default function DownloadPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full relative h-screen flex items-center justify-center">
|
<div className="w-full relative h-screen flex items-center justify-center flex-col lg:flex-row">
|
||||||
<div className="w-1/2 relative h-full px-64 flex items-cetner justify-center flex-col">
|
<div className="w-full lg:w-1/2 relative h-full px-12 lg:px-24 xl:px-32 2xl:px-64 text-center flex items-cetner justify-center flex-col">
|
||||||
<GridPattern
|
<GridPattern
|
||||||
numSquares={30}
|
numSquares={30}
|
||||||
maxOpacity={0.5}
|
maxOpacity={0.5}
|
||||||
@@ -80,8 +80,8 @@ export default function DownloadPage() {
|
|||||||
Get started with Zen Browser today. Get back to browsing the web with peace of mind.
|
Get started with Zen Browser today. Get back to browsing the web with peace of mind.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-1/2 relative flex flex-col relative items-cetner justify-start">
|
<div className="w-full lg:w-1/2 relative flex flex-col relative items-cetner justify-start">
|
||||||
<div className="w-1/2 relative">
|
<div className="w-full lg:w-2/3 relative flex flex-col items-center mx-auto mt-10 lg:mt-0">
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="w-2/3 space-y-6">
|
<form onSubmit={form.handleSubmit(onSubmit)} className="w-2/3 space-y-6">
|
||||||
<FormField
|
<FormField
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import TextReveal from "./ui/text-reveal";
|
|||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
return (
|
return (
|
||||||
<div className="font-medium border-t w-full border-grey py-10 mt-10 flex justify-center align-center">
|
<div className="font-medium flex-col md:flex-row px-10 md:px-0 border-t w-full border-grey py-10 mt-10 flex justify-center align-center">
|
||||||
Zen Browser © {new Date().getFullYear()} -
|
Zen Browser © {new Date().getFullYear()} -
|
||||||
Made with ❤️ by the Zen team.
|
Made with ❤️ by the Zen team.
|
||||||
<a className="ml-2 font-bold" href="https://github.com/zen-browser" target="_blank">Source Code</a>
|
<a className="mt-5 md:mt-0 md:ml-2 font-bold" href="https://github.com/zen-browser" target="_blank">Source Code</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
100
src/components/mobile-nav.tsx
Normal file
100
src/components/mobile-nav.tsx
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { SidebarOpen } from 'lucide-react'
|
||||||
|
import type { LinkProps } from 'next/link'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import * as React from 'react'
|
||||||
|
import { Sheet, SheetContent, SheetTrigger } from './ui/sheet'
|
||||||
|
import { Button } from './ui/button'
|
||||||
|
import { ScrollArea } from './ui/scroll-area'
|
||||||
|
import Logo from './logo'
|
||||||
|
import { ny } from '@/lib/utils'
|
||||||
|
import { components } from './navigation'
|
||||||
|
|
||||||
|
export function MobileNav() {
|
||||||
|
const [open, setOpen] = React.useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Sheet open={open} onOpenChange={setOpen}>
|
||||||
|
<SheetTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="mr-2 px-0 ml-auto text-base hover:bg-transparent focus-visible:bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 sm:hidden"
|
||||||
|
>
|
||||||
|
<SidebarOpen className="size-6" />
|
||||||
|
<span className="sr-only">Toggle Menu</span>
|
||||||
|
</Button>
|
||||||
|
</SheetTrigger>
|
||||||
|
<SheetContent side="left" className="pr-0">
|
||||||
|
<MobileLink
|
||||||
|
href="/"
|
||||||
|
className="flex items-center"
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
>
|
||||||
|
<Logo withText />
|
||||||
|
</MobileLink>
|
||||||
|
<ScrollArea className="my-4 h-[calc(100vh-8rem)] pb-10 pl-6">
|
||||||
|
<div className="flex flex-col space-y-3">
|
||||||
|
<MobileLink
|
||||||
|
href="/download"
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</MobileLink>
|
||||||
|
<MobileLink
|
||||||
|
href="/release-notes"
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
>
|
||||||
|
Release Notes
|
||||||
|
</MobileLink>
|
||||||
|
<MobileLink
|
||||||
|
href="https://github.com/zen-browser"
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
>
|
||||||
|
Source Code
|
||||||
|
</MobileLink>
|
||||||
|
{components.map(({title, href, description}) => (
|
||||||
|
<MobileLink
|
||||||
|
href={href}
|
||||||
|
key={href}
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</MobileLink>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
</SheetContent>
|
||||||
|
</Sheet>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MobileLinkProps extends LinkProps {
|
||||||
|
onOpenChange?: (open: boolean) => void
|
||||||
|
children: React.ReactNode
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function MobileLink({
|
||||||
|
href,
|
||||||
|
onOpenChange,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: MobileLinkProps) {
|
||||||
|
const router = useRouter()
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
href={href}
|
||||||
|
onClick={() => {
|
||||||
|
router.push(href.toString())
|
||||||
|
onOpenChange?.(false)
|
||||||
|
}}
|
||||||
|
className={ny(className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -15,8 +15,9 @@ import {
|
|||||||
} from "@/components/ui/navigation-menu"
|
} from "@/components/ui/navigation-menu"
|
||||||
import Logo from "./logo"
|
import Logo from "./logo"
|
||||||
import { ModeToggle } from "./mode-toggle"
|
import { ModeToggle } from "./mode-toggle"
|
||||||
|
import { MobileNav } from "./mobile-nav"
|
||||||
|
|
||||||
const components: { title: string; href: string; description: string }[] = [
|
export const components: { title: string; href: string; description: string }[] = [
|
||||||
{
|
{
|
||||||
title: "Privacy Policy",
|
title: "Privacy Policy",
|
||||||
href: "/privacy-policy",
|
href: "/privacy-policy",
|
||||||
@@ -32,8 +33,9 @@ const components: { title: string; href: string; description: string }[] = [
|
|||||||
export function Navigation() {
|
export function Navigation() {
|
||||||
return (
|
return (
|
||||||
<div className="bg-background fixed z-10 top-0 left-0 w-full flex fixed border-b border-grey p-2 items-center justify-center">
|
<div className="bg-background fixed z-10 top-0 left-0 w-full flex fixed border-b border-grey p-2 items-center justify-center">
|
||||||
|
<MobileNav />
|
||||||
<NavigationMenu>
|
<NavigationMenu>
|
||||||
<NavigationMenuList className="w-full">
|
<NavigationMenuList className="w-full hidden sm:flex">
|
||||||
<NavigationMenuItem className="cursor-pointer mr-20">
|
<NavigationMenuItem className="cursor-pointer mr-20">
|
||||||
<NavigationMenuLink href="/">
|
<NavigationMenuLink href="/">
|
||||||
<Logo withText />
|
<Logo withText />
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Button } from "./ui/button";
|
|||||||
export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) {
|
export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col mt-52 mb-24">
|
<div className="flex flex-col mt-52 mb-24">
|
||||||
<div className="mx-auto w-1/3">
|
<div className="mx-auto w-full px-10 md:px-0 md:w-1/2 lg:w-1/3">
|
||||||
<h1 className="text-4xl font-bold">Release notes for {data.version} 🎉</h1>
|
<h1 className="text-4xl font-bold">Release notes for {data.version} 🎉</h1>
|
||||||
<p className="text-sm mt-1 font-bold text-muted-foreground">{data.date}</p>
|
<p className="text-sm mt-1 font-bold text-muted-foreground">{data.date}</p>
|
||||||
{data.extra && (
|
{data.extra && (
|
||||||
|
|||||||
48
src/components/ui/scroll-area.tsx
Normal file
48
src/components/ui/scroll-area.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import * as React from 'react'
|
||||||
|
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
|
||||||
|
|
||||||
|
import { ny } from '@/lib/utils'
|
||||||
|
|
||||||
|
const ScrollArea = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<ScrollAreaPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={ny('relative overflow-hidden', className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ScrollAreaPrimitive.Viewport className="size-full rounded-[inherit]">
|
||||||
|
{children}
|
||||||
|
</ScrollAreaPrimitive.Viewport>
|
||||||
|
<ScrollBar />
|
||||||
|
<ScrollAreaPrimitive.Corner />
|
||||||
|
</ScrollAreaPrimitive.Root>
|
||||||
|
))
|
||||||
|
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
||||||
|
|
||||||
|
const ScrollBar = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||||
|
>(({ className, orientation = 'vertical', ...props }, ref) => (
|
||||||
|
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||||
|
ref={ref}
|
||||||
|
orientation={orientation}
|
||||||
|
className={ny(
|
||||||
|
'flex touch-none select-none transition-colors',
|
||||||
|
orientation === 'vertical'
|
||||||
|
&& 'h-full w-2.5 border-l border-l-transparent p-px',
|
||||||
|
orientation === 'horizontal'
|
||||||
|
&& 'h-2.5 flex-col border-t border-t-transparent p-px',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ScrollAreaPrimitive.ScrollAreaThumb className="bg-border relative flex-1 rounded-full" />
|
||||||
|
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||||
|
))
|
||||||
|
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
||||||
|
|
||||||
|
export { ScrollArea, ScrollBar }
|
||||||
144
src/components/ui/sheet.tsx
Normal file
144
src/components/ui/sheet.tsx
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import * as React from 'react'
|
||||||
|
import * as SheetPrimitive from '@radix-ui/react-dialog'
|
||||||
|
import { Cross2Icon } from '@radix-ui/react-icons'
|
||||||
|
import { type VariantProps, cva } from 'class-variance-authority'
|
||||||
|
|
||||||
|
import { ny } from '@/lib/utils'
|
||||||
|
|
||||||
|
const Sheet = SheetPrimitive.Root
|
||||||
|
|
||||||
|
const SheetTrigger = SheetPrimitive.Trigger
|
||||||
|
|
||||||
|
const SheetClose = SheetPrimitive.Close
|
||||||
|
|
||||||
|
const SheetPortal = SheetPrimitive.Portal
|
||||||
|
|
||||||
|
const SheetOverlay = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SheetPrimitive.Overlay
|
||||||
|
className={ny(
|
||||||
|
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
|
||||||
|
|
||||||
|
const sheetVariants = cva(
|
||||||
|
'fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out',
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
side: {
|
||||||
|
top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
|
||||||
|
bottom:
|
||||||
|
'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
|
||||||
|
left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
|
||||||
|
right:
|
||||||
|
'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
side: 'right',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
interface SheetContentProps
|
||||||
|
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
||||||
|
VariantProps<typeof sheetVariants> {}
|
||||||
|
|
||||||
|
const SheetContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SheetPrimitive.Content>,
|
||||||
|
SheetContentProps
|
||||||
|
>(({ side = 'right', className, children, ...props }, ref) => (
|
||||||
|
<SheetPortal>
|
||||||
|
<SheetOverlay />
|
||||||
|
<SheetPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={ny(sheetVariants({ side }), className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
|
||||||
|
<Cross2Icon className="size-4" />
|
||||||
|
<span className="sr-only">Close</span>
|
||||||
|
</SheetPrimitive.Close>
|
||||||
|
{children}
|
||||||
|
</SheetPrimitive.Content>
|
||||||
|
</SheetPortal>
|
||||||
|
))
|
||||||
|
SheetContent.displayName = SheetPrimitive.Content.displayName
|
||||||
|
|
||||||
|
function SheetHeader({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ny(
|
||||||
|
'flex flex-col space-y-2 text-center sm:text-left',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SheetHeader.displayName = 'SheetHeader'
|
||||||
|
|
||||||
|
function SheetFooter({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ny(
|
||||||
|
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SheetFooter.displayName = 'SheetFooter'
|
||||||
|
|
||||||
|
const SheetTitle = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SheetPrimitive.Title>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SheetPrimitive.Title
|
||||||
|
ref={ref}
|
||||||
|
className={ny('text-foreground text-lg font-semibold', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
SheetTitle.displayName = SheetPrimitive.Title.displayName
|
||||||
|
|
||||||
|
const SheetDescription = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SheetPrimitive.Description>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SheetPrimitive.Description
|
||||||
|
ref={ref}
|
||||||
|
className={ny('text-muted-foreground text-sm', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
SheetDescription.displayName = SheetPrimitive.Description.displayName
|
||||||
|
|
||||||
|
export {
|
||||||
|
Sheet,
|
||||||
|
SheetPortal,
|
||||||
|
SheetOverlay,
|
||||||
|
SheetTrigger,
|
||||||
|
SheetClose,
|
||||||
|
SheetContent,
|
||||||
|
SheetHeader,
|
||||||
|
SheetFooter,
|
||||||
|
SheetTitle,
|
||||||
|
SheetDescription,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user