-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(admin layout): change layout style
- Loading branch information
Showing
17 changed files
with
378 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
'use client'; | ||
import { Button, Resizable, ResizableHandle, Separator } from '~/components'; | ||
import { Nav } from '~/app/admin/_components/nav'; | ||
import { Header } from '~/app/admin/_components/header'; | ||
import * as React from 'react'; | ||
import { ReactNode } from 'react'; | ||
import { cn } from '~/lib/utils'; | ||
import { | ||
DashboardIcon, | ||
MailboxIcon, | ||
NotebookIcon, | ||
RSSIcon, | ||
SettingIcon | ||
} from '~/assets'; | ||
import { ThemeSwitcher } from '~/app/_components/ThemeSwitcher'; | ||
import Link from 'next/link'; | ||
import Image from 'next/image'; | ||
import { DOMAIN, GITHUB } from '~/config/constants'; | ||
interface Props { | ||
defaultLayout: number[] | undefined; | ||
defaultCollapsed?: boolean; | ||
navCollapsedSize: number; | ||
children?: ReactNode; | ||
} | ||
|
||
export interface IMenu { | ||
label: string; | ||
icon: ReactNode; | ||
link: string; | ||
suffix?: ReactNode; | ||
} | ||
|
||
export const CommonMenus: IMenu[] = [ | ||
{ label: '数据看板', icon: <DashboardIcon />, link: '/admin/dashboard' }, | ||
{ label: '博客管理', icon: <RSSIcon />, link: '/admin/blog' }, | ||
{ label: '笔记管理', icon: <NotebookIcon />, link: '/admin/notebook' }, | ||
{ label: '留言管理', icon: <MailboxIcon />, link: '/admin/mailbox' } | ||
]; | ||
|
||
export const SettingMenus: IMenu[] = [ | ||
{ | ||
label: '后台设置', | ||
icon: <SettingIcon />, | ||
link: '/admin/setting', | ||
suffix: <ThemeSwitcher /> | ||
} | ||
]; | ||
|
||
export function ResizableLayout({ | ||
children, | ||
defaultLayout = [265, 1095], | ||
defaultCollapsed = false, | ||
navCollapsedSize | ||
}: Props) { | ||
const [isCollapsed, setIsCollapsed] = React.useState(defaultCollapsed); | ||
|
||
return ( | ||
<Resizable.PanelGroup | ||
direction="horizontal" | ||
className="min-h-screen w-full bg-muted/40" | ||
onLayout={(sizes: number[]) => { | ||
document.cookie = `react-resizable-panels:layout=${JSON.stringify( | ||
sizes | ||
)}`; | ||
}} | ||
> | ||
<Resizable.Panel | ||
defaultSize={defaultLayout[0]} | ||
collapsedSize={navCollapsedSize} | ||
collapsible={true} | ||
minSize={15} | ||
maxSize={17.5} | ||
onExpand={() => { | ||
setIsCollapsed(false); | ||
document.cookie = `react-resizable-panels:collapsed=${JSON.stringify( | ||
false | ||
)}`; | ||
}} | ||
onCollapse={() => { | ||
setIsCollapsed(true); | ||
document.cookie = `react-resizable-panels:collapsed=${JSON.stringify( | ||
true | ||
)}`; | ||
}} | ||
className={cn( | ||
'hidden sm:block', | ||
isCollapsed && 'min-w-[50px] transition-all duration-300 ease-in-out' | ||
)} | ||
> | ||
<div className="flex items-center h-[56px] px-2"> | ||
<Button className="w-10 h-10 relative" size="icon" variant="outline"> | ||
<Image | ||
className="h-full object-cover" | ||
src={GITHUB.DEFAULLT_AVATAR} | ||
alt={GITHUB.DEFAULLT_NAME} | ||
width={40} | ||
height={40} | ||
priority | ||
></Image> | ||
</Button> | ||
|
||
{!isCollapsed && ( | ||
<span className="font-bold tracking-wide text-2xl shrink text-primary italic ml-4"> | ||
{DOMAIN} | ||
</span> | ||
)} | ||
</div> | ||
<Separator /> | ||
<Nav isCollapsed={isCollapsed} menus={CommonMenus} /> | ||
<Separator /> | ||
<Nav isCollapsed={isCollapsed} menus={SettingMenus} /> | ||
</Resizable.Panel> | ||
<ResizableHandle className="hidden sm:flex" withHandle /> | ||
|
||
<Resizable.Panel | ||
defaultSize={defaultLayout[1]} | ||
minSize={30} | ||
className="transition-all duration-300 ease-in-out" | ||
> | ||
<div className="w-full h-full flex flex-col"> | ||
<Header /> | ||
<main className="p-4">{children}</main> | ||
</div> | ||
</Resizable.Panel> | ||
</Resizable.PanelGroup> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,33 @@ | ||
import { SheetNavbar } from '~/app/admin/_components/sheetNavbar'; | ||
import { HeaderBreadcrumb } from '~/app/admin/_components/headerBreadcrumb'; | ||
import { SearchIcon } from '~/assets'; | ||
import { Input } from '~/components/ui'; | ||
import { Input, Separator } from '~/components/ui'; | ||
import { UserInfo } from '~/app/_components/UserInfo'; | ||
import * as React from 'react'; | ||
import { ClientOnly } from '~/components'; | ||
import { ThemeSwitcher } from '~/app/_components/ThemeSwitcher'; | ||
|
||
export function Header() { | ||
return ( | ||
<header className="sticky top-0 z-10 h-14 border-b bg-background flex items-center gap-4 px-4 sm:static sm:px-6 sm:h-auto sm:border-transparent sm:bg-transparent transition-colors"> | ||
<SheetNavbar /> | ||
<ClientOnly> | ||
<HeaderBreadcrumb /> | ||
</ClientOnly> | ||
<div> | ||
<header className="sticky top-0 z-10 h-14 border-b bg-background flex items-center gap-4 px-4 sm:static sm:px-6 sm:16 sm:border-transparent sm:bg-transparent transition-colors"> | ||
<SheetNavbar /> | ||
<ClientOnly> | ||
<HeaderBreadcrumb /> | ||
</ClientOnly> | ||
|
||
<div className="relative flex-1 ml-auto sm:grow-0"> | ||
<SearchIcon className="absolute text-muted-foreground left-2.5 top-2.5" /> | ||
<Input | ||
type="search" | ||
placeholder="Search..." | ||
className="rounded-lg sm:w-[200px] md:w-[280px] lg:w-[320px] bg-background pl-8" | ||
/> | ||
</div> | ||
<UserInfo /> | ||
</header> | ||
<div className="relative flex-1 ml-auto sm:grow-0"> | ||
<SearchIcon className="absolute text-muted-foreground left-2.5 top-2.5" /> | ||
<Input | ||
type="search" | ||
placeholder="Search..." | ||
className="rounded-lg sm:w-[200px] md:w-[280px] lg:w-[320px] bg-background pl-8" | ||
/> | ||
</div> | ||
<UserInfo /> | ||
<ThemeSwitcher side="bottom" className="hidden sm:flex" /> | ||
</header> | ||
<Separator className="hidden sm:block" /> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
'use client'; | ||
import Link from 'next/link'; | ||
import { buttonVariants, Tooltip } from '~/components/ui'; | ||
import * as React from 'react'; | ||
import { cn } from '~/lib/utils'; | ||
import { usePathname } from 'next/navigation'; | ||
import { IMenu } from '~/app/admin/_components/ResizableLayout'; | ||
|
||
export function Nav({ | ||
isCollapsed, | ||
menus | ||
}: { | ||
isCollapsed: boolean; | ||
menus: IMenu[]; | ||
}) { | ||
const pathname = usePathname(); | ||
return ( | ||
<div | ||
data-collapsed={isCollapsed} | ||
className="group flex flex-col gap-4 py-2 data-[collapsed=true]:py-2" | ||
> | ||
<nav className="grid gap-1 px-2 group-[[data-collapsed=true]]:justify-center group-[[data-collapsed=true]]:px-2"> | ||
{menus.map((menu) => | ||
isCollapsed ? ( | ||
<Tooltip.Provider key={menu.link} delayDuration={0}> | ||
<Tooltip> | ||
<Tooltip.Trigger asChild> | ||
<Link | ||
href={menu.link} | ||
className={cn( | ||
buttonVariants({ | ||
variant: pathname.includes(menu.link) | ||
? 'default' | ||
: 'ghost', | ||
size: 'icon' | ||
}), | ||
'h-9 w-9', | ||
pathname.includes(menu.link) && | ||
'dark:bg-muted dark:text-white dark:hover:bg-muted dark:hover:text-white' | ||
)} | ||
> | ||
<span className="text-base">{menu.icon}</span> | ||
<span className="sr-only">{menu.label}</span> | ||
</Link> | ||
</Tooltip.Trigger> | ||
<Tooltip.Content | ||
side="right" | ||
className="flex items-center gap-4" | ||
custom={false} | ||
> | ||
{menu.label} | ||
</Tooltip.Content> | ||
</Tooltip> | ||
</Tooltip.Provider> | ||
) : ( | ||
<Link | ||
key={menu.link} | ||
href={menu.link} | ||
className={cn( | ||
buttonVariants({ | ||
variant: pathname.includes(menu.link) ? 'default' : 'ghost' | ||
}), | ||
pathname.includes(menu.link) && | ||
'dark:bg-muted dark:text-white dark:hover:bg-muted dark:hover:text-white', | ||
'justify-start' | ||
)} | ||
> | ||
<span className="text-base mr-2">{menu.icon}</span> | ||
{menu.label} | ||
</Link> | ||
) | ||
)} | ||
</nav> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.