Skip to content

Commit

Permalink
feat: 新增路由动画
Browse files Browse the repository at this point in the history
  • Loading branch information
besscroft committed Apr 8, 2024
1 parent f9131e6 commit e9b00d5
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 55 deletions.
9 changes: 7 additions & 2 deletions app/(default)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Header from '~/components/Header'
import Transitions, { Animate } from '~/components/Transitions'

export default async function DefaultLayout({
children,
Expand All @@ -7,8 +8,12 @@ export default async function DefaultLayout({
}>) {
return (
<>
<Header/>
{children}
<Transitions className="h-full flex flex-col">
<Header/>
<Animate className="flex-1">
{children}
</Animate>
</Transitions>
</>
);
}
23 changes: 14 additions & 9 deletions app/admin/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import DashHeader from '~/components/DashHeader'
import { BaseSide } from '~/components/BaseSide'
import Transitions, { Animate } from '~/components/Transitions'

export default function AdminLayout({
children,
Expand All @@ -9,15 +10,19 @@ export default function AdminLayout({
return (
<>
<div className="flex flex-col h-screen">
<DashHeader/>
<div className="grid flex-1 sm:grid-cols-[200px_1fr] h-full w-full bg-gray-100 dark:bg-zinc-900">
<aside className="hidden w-[200px] flex-col sm:flex">
<BaseSide/>
</aside>
<main className="flex w-full h-full flex-1 flex-col overflow-hidden p-2">
{children}
</main>
</div>
<Transitions className="h-full flex flex-col">
<DashHeader/>
<div className="grid flex-1 sm:grid-cols-[200px_1fr] h-full w-full bg-gray-100 dark:bg-zinc-900">
<aside className="hidden w-[200px] flex-col sm:flex">
<BaseSide/>
</aside>
<main className="flex w-full h-full flex-1 flex-col overflow-hidden p-2">
<Animate className="flex-1">
{children}
</Animate>
</main>
</div>
</Transitions>
</div>
</>
);
Expand Down
16 changes: 6 additions & 10 deletions components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
'use client'

import { Navbar, NavbarBrand, NavbarContent, NavbarItem, Link } from '@nextui-org/react'
import { Navbar, NavbarBrand, NavbarContent, NavbarItem } from '@nextui-org/react'
import Logo from '~/components/Logo'
import DynamicNavbar from '~/components/DynamicNavbar'
import { useRouter } from 'next-nprogress-bar'
import Link from 'next/link'

export default function Header() {
const router = useRouter()

return (
<Navbar>
<NavbarBrand>
<Logo />
</NavbarBrand>
<NavbarContent className="hidden sm:flex gap-4 select-none" justify="center">
<NavbarItem onClick={() => router.push('/')} className="cursor-pointer">
首页
<NavbarItem className="cursor-pointer">
<Link href="/">首页</Link>
</NavbarItem>
<NavbarItem onClick={() => router.push('/about')} className="cursor-pointer">
关于
<NavbarItem className="cursor-pointer">
<Link href="/about">关于</Link>
</NavbarItem>
</NavbarContent>
<NavbarContent justify="end">
Expand Down
80 changes: 80 additions & 0 deletions components/Transitions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
'use client'

import { AnimatePresence, motion } from 'framer-motion'
import { useRouter } from 'next-nprogress-bar'
import {
createContext,
MouseEventHandler,
PropsWithChildren,
use,
useTransition,
} from 'react'

export const DELAY = 200;

const sleep = (ms: number) =>
new Promise<void>((resolve) => setTimeout(() => resolve(), ms));
const noop = () => {};

type TransitionContext = {
pending: boolean;
navigate: (url: string) => void;
};
const Context = createContext<TransitionContext>({
pending: false,
navigate: noop,
});
export const usePageTransition = () => use(Context);

type Props = PropsWithChildren<{
className?: string;
}>;

export default function Transitions({ children, className }: Props) {
const [pending, start] = useTransition();
const router = useRouter();

const navigate = (href: string) => {
start(async () => {
router.push(href);
await sleep(DELAY);
});
};

const onClick: MouseEventHandler<HTMLDivElement> = (e) => {
const a = (e.target as Element).closest("a");
if (a) {
e.preventDefault();
const href = a.getAttribute("href");
if (href) {
navigate(href);
}
}
};

return (
<Context.Provider value={{ pending, navigate }}>
<div onClickCapture={onClick} className={className}>
{children}
</div>
</Context.Provider>
);
}

export function Animate({ children, className }: Props) {
const { pending } = usePageTransition();
return (
<AnimatePresence>
{!pending && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className={className}
>
{children}
</motion.div>
)}
</AnimatePresence>
);
}
62 changes: 28 additions & 34 deletions components/VaulDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
SunIcon
} from '@radix-ui/react-icons'


export default function VaulDrawer() {
const { data: session, status } = useSession()
const router = useRouter()
Expand Down Expand Up @@ -56,39 +55,34 @@ export default function VaulDrawer() {
<Listbox
aria-label="移动端菜单"
>
{
pathname.startsWith('/admin') ?
pathname === '/admin' ?
<ListboxItem
key="home"
startContent={<HomeIcon className={iconClasses} />}
onClick={() => router.push('/')}
>
<Drawer.Close className="w-full text-left">
首页
</Drawer.Close>
</ListboxItem>
:
<ListboxItem
key="home"
startContent={<DesktopIcon className={iconClasses} />}
onClick={() => router.push('/admin')}
>
<Drawer.Close className="w-full text-left">
控制台
</Drawer.Close>
</ListboxItem>
:
<ListboxItem
key="home"
startContent={<DesktopIcon className={iconClasses} />}
onClick={() => router.push('/admin')}
>
<Drawer.Close className="w-full text-left">
控制台
</Drawer.Close>
</ListboxItem>
}
<ListboxItem
key="home"
startContent={<HomeIcon className={iconClasses} />}
onClick={() => router.push('/')}
>
<Drawer.Close className="w-full text-left">
首页
</Drawer.Close>
</ListboxItem>
<ListboxItem
key="about"
startContent={<InfoCircledIcon className={iconClasses} />}
onClick={() => router.push('/about')}
showDivider
>
<Drawer.Close className="w-full text-left">
关于
</Drawer.Close>
</ListboxItem>
<ListboxItem
key="admin"
startContent={<DesktopIcon className={iconClasses} />}
onClick={() => router.push('/admin')}
>
<Drawer.Close className="w-full text-left">
控制台
</Drawer.Close>
</ListboxItem>
<ListboxItem
key="upload"
startContent={<RocketIcon className={iconClasses} />}
Expand Down

0 comments on commit e9b00d5

Please sign in to comment.