Added mobile support

This commit is contained in:
Mauro Balades
2024-07-12 00:22:11 +02:00
parent 68ff4a7308
commit d9ff1a48b4
9 changed files with 373 additions and 10 deletions

67
package-lock.json generated
View File

@@ -10,10 +10,12 @@
"dependencies": {
"@hookform/resolvers": "^3.7.0",
"@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-icons": "^1.3.0",
"@radix-ui/react-label": "^2.1.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-slot": "^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": {
"version": "1.1.0",
"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": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz",

View File

@@ -11,10 +11,12 @@
"dependencies": {
"@hookform/resolvers": "^3.7.0",
"@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-icons": "^1.3.0",
"@radix-ui/react-label": "^2.1.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-slot": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.0",

View File

@@ -19,7 +19,7 @@ function getDefaultPlatformBasedOnUserAgent() {
userAgent = window.navigator.userAgent;
}
if (userAgent.includes("Win")) {
return "WindowsStubInstaller";
return "WindowsInstaller";
}
if (userAgent.includes("Mac")) {
return "MacOS";
@@ -56,8 +56,8 @@ export default function DownloadPage() {
}
return (
<div className="w-full relative h-screen flex items-center justify-center">
<div className="w-1/2 relative h-full px-64 flex items-cetner justify-center flex-col">
<div className="w-full relative h-screen flex items-center justify-center flex-col lg:flex-row">
<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
numSquares={30}
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.
</p>
</div>
<div className="w-1/2 relative flex flex-col relative items-cetner justify-start">
<div className="w-1/2 relative">
<div className="w-full lg:w-1/2 relative flex flex-col relative items-cetner justify-start">
<div className="w-full lg:w-2/3 relative flex flex-col items-center mx-auto mt-10 lg:mt-0">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="w-2/3 space-y-6">
<FormField

View File

@@ -3,10 +3,10 @@ import TextReveal from "./ui/text-reveal";
export default function Footer() {
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()} -
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>
);
}

View 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>
)
}

View File

@@ -15,8 +15,9 @@ import {
} from "@/components/ui/navigation-menu"
import Logo from "./logo"
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",
href: "/privacy-policy",
@@ -32,8 +33,9 @@ const components: { title: string; href: string; description: string }[] = [
export function Navigation() {
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">
<MobileNav />
<NavigationMenu>
<NavigationMenuList className="w-full">
<NavigationMenuList className="w-full hidden sm:flex">
<NavigationMenuItem className="cursor-pointer mr-20">
<NavigationMenuLink href="/">
<Logo withText />

View File

@@ -6,7 +6,7 @@ import { Button } from "./ui/button";
export default function ReleaseNoteElement({ data }: { data: ReleaseNote }) {
return (
<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>
<p className="text-sm mt-1 font-bold text-muted-foreground">{data.date}</p>
{data.extra && (

View 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
View 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,
}