feat: shadcn-style mobile menu
This commit is contained in:
parent
2211c4bbf3
commit
72655a8317
5 changed files with 70 additions and 8 deletions
|
@ -16,7 +16,7 @@ const { name, avatar, bio, pronouns, github, twitter, linkedin, website } =
|
||||||
---
|
---
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="rounded-xl border p-4 transition-colors duration-300 ease-in-out has-[a:hover]:bg-secondary/50"
|
class="overflow-hidden rounded-xl border p-4 transition-colors duration-300 ease-in-out has-[a:hover]:bg-secondary/50"
|
||||||
>
|
>
|
||||||
<div class="flex flex-wrap gap-4">
|
<div class="flex flex-wrap gap-4">
|
||||||
<Link
|
<Link
|
||||||
|
@ -35,7 +35,7 @@ const { name, avatar, bio, pronouns, github, twitter, linkedin, website } =
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<div class="flex flex-grow flex-col justify-between">
|
<div class="flex flex-grow flex-col justify-between gap-y-4">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<h3 class="text-lg font-semibold">{name}</h3>
|
<h3 class="text-lg font-semibold">{name}</h3>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { ModeToggle } from '@/components/ui/mode-toggle'
|
import { ModeToggle } from '@/components/ui/mode-toggle'
|
||||||
import Container from '@components/Container.astro'
|
import Container from '@components/Container.astro'
|
||||||
import Link from '@components/Link.astro'
|
import Link from '@components/Link.astro'
|
||||||
|
import MobileMenu from '@components/ui/mobile-menu'
|
||||||
import { NAV_LINKS, SITE } from '@consts'
|
import { NAV_LINKS, SITE } from '@consts'
|
||||||
import { Image } from 'astro:assets'
|
import { Image } from 'astro:assets'
|
||||||
import logo from '../../public/static/logo.svg'
|
import logo from '../../public/static/logo.svg'
|
||||||
|
@ -20,8 +21,8 @@ import logo from '../../public/static/logo.svg'
|
||||||
<Image src={logo} alt="Logo" class="size-8 rounded-sm" />
|
<Image src={logo} alt="Logo" class="size-8 rounded-sm" />
|
||||||
{SITE.TITLE}
|
{SITE.TITLE}
|
||||||
</Link>
|
</Link>
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-2 md:gap-4">
|
||||||
<nav class="flex items-center gap-4 text-sm sm:gap-6">
|
<nav class="hidden items-center gap-4 text-sm sm:gap-6 md:flex">
|
||||||
{
|
{
|
||||||
NAV_LINKS.map((item) => (
|
NAV_LINKS.map((item) => (
|
||||||
<Link
|
<Link
|
||||||
|
@ -33,7 +34,8 @@ import logo from '../../public/static/logo.svg'
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</nav>
|
</nav>
|
||||||
<ModeToggle client:load />
|
<MobileMenu client:load transition:persist />
|
||||||
|
<ModeToggle client:load transition:persist />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -23,7 +23,7 @@ const AvatarImage = React.forwardRef<
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<AvatarPrimitive.Image
|
<AvatarPrimitive.Image
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn('aspect-square h-full w-full', className)}
|
className={cn('aspect-square size-full', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
@ -36,7 +36,7 @@ const AvatarFallback = React.forwardRef<
|
||||||
<AvatarPrimitive.Fallback
|
<AvatarPrimitive.Fallback
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-full w-full items-center justify-center bg-muted',
|
'flex size-full items-center justify-center bg-muted',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
60
src/components/ui/mobile-menu.tsx
Normal file
60
src/components/ui/mobile-menu.tsx
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import React, { useState, useEffect } from 'react'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu'
|
||||||
|
import { NAV_LINKS } from '@consts'
|
||||||
|
import { Menu } from 'lucide-react'
|
||||||
|
|
||||||
|
const MobileMenu = () => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleViewTransitionStart = () => {
|
||||||
|
setIsOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('astro:before-swap', handleViewTransitionStart)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener(
|
||||||
|
'astro:before-swap',
|
||||||
|
handleViewTransitionStart,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu open={isOpen} onOpenChange={setIsOpen} modal={false}>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
className="md:hidden"
|
||||||
|
title="Menu"
|
||||||
|
>
|
||||||
|
<Menu className="h-5 w-5" />
|
||||||
|
<span className="sr-only">Toggle menu</span>
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end" className="mr-4 bg-background">
|
||||||
|
{NAV_LINKS.map((item) => (
|
||||||
|
<DropdownMenuItem key={item.href} asChild>
|
||||||
|
<a
|
||||||
|
href={item.href}
|
||||||
|
className="w-full text-lg font-medium capitalize"
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</a>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MobileMenu
|
|
@ -40,7 +40,7 @@ export function ModeToggle() {
|
||||||
<span className="sr-only">Toggle theme</span>
|
<span className="sr-only">Toggle theme</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end" className="bg-background">
|
<DropdownMenuContent align="end" className="mr-4 bg-background">
|
||||||
<DropdownMenuItem onClick={() => setThemeState('theme-light')}>
|
<DropdownMenuItem onClick={() => setThemeState('theme-light')}>
|
||||||
<Sun className="mr-2 size-4" />
|
<Sun className="mr-2 size-4" />
|
||||||
<span>Light</span>
|
<span>Light</span>
|
||||||
|
|
Loading…
Add table
Reference in a new issue