mirror of
https://github.com/snowykami/neo-blog.git
synced 2025-09-26 19:16:24 +00:00
feat: 重构侧边栏组件,合并 NavMain 和 NavUserCenter 为 NavGroup,添加动态激活状态
This commit is contained in:
@ -4,7 +4,7 @@ import {
|
|||||||
IconInnerShadowTop,
|
IconInnerShadowTop,
|
||||||
} from "@tabler/icons-react"
|
} from "@tabler/icons-react"
|
||||||
|
|
||||||
import { NavMain } from "@/components/console/nav-main"
|
import { NavGroup } from "@/components/console/nav-group"
|
||||||
import { NavUser } from "@/components/console/nav-user"
|
import { NavUser } from "@/components/console/nav-user"
|
||||||
import {
|
import {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
@ -17,13 +17,16 @@ import {
|
|||||||
} from "@/components/ui/sidebar"
|
} from "@/components/ui/sidebar"
|
||||||
import config from "@/config"
|
import config from "@/config"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { NavUserCenter } from "./nav-ucenter"
|
|
||||||
import { sidebarData } from "./data"
|
import { sidebarData } from "./data"
|
||||||
import { ThemeModeToggle } from "../common/theme-toggle"
|
import { ThemeModeToggle } from "../common/theme-toggle"
|
||||||
|
import { useState } from "react"
|
||||||
|
import { useTranslations } from "next-intl"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||||
|
const [activeId, setActiveId] = useState("dashboard")
|
||||||
|
const consoleT = useTranslations("Console")
|
||||||
return (
|
return (
|
||||||
<Sidebar collapsible="offcanvas" {...props}>
|
<Sidebar collapsible="offcanvas" {...props}>
|
||||||
<SidebarHeader>
|
<SidebarHeader>
|
||||||
@ -42,8 +45,8 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
|||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
</SidebarHeader>
|
</SidebarHeader>
|
||||||
<SidebarContent>
|
<SidebarContent>
|
||||||
<NavMain items={sidebarData.navMain} />
|
<NavGroup title={consoleT("general")} activeId={activeId} setActiveId={setActiveId} items={sidebarData.navMain.map((item) => ({...item, title: consoleT(item.title)}))} />
|
||||||
<NavUserCenter items={sidebarData.navUserCenter} />
|
<NavGroup title={consoleT("personal")} activeId={activeId} setActiveId={setActiveId} items={sidebarData.navUserCenter.map((item) => ({...item, title: consoleT(item.title)}))} />
|
||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
<SidebarFooter>
|
<SidebarFooter>
|
||||||
<div className="mb-2 flex justify-center">
|
<div className="mb-2 flex justify-center">
|
||||||
|
@ -6,6 +6,7 @@ import { Folder, Gauge, MessageCircle, Newspaper, Palette, Settings, ShieldCheck
|
|||||||
|
|
||||||
|
|
||||||
export interface SidebarItem {
|
export interface SidebarItem {
|
||||||
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
url: string;
|
url: string;
|
||||||
icon: IconType;
|
icon: IconType;
|
||||||
@ -15,36 +16,42 @@ export interface SidebarItem {
|
|||||||
export const sidebarData: { navMain: SidebarItem[]; navUserCenter: SidebarItem[] } = {
|
export const sidebarData: { navMain: SidebarItem[]; navUserCenter: SidebarItem[] } = {
|
||||||
navMain: [
|
navMain: [
|
||||||
{
|
{
|
||||||
|
id: "dashboard",
|
||||||
title: "dashboard.title",
|
title: "dashboard.title",
|
||||||
url: consolePath.dashboard,
|
url: consolePath.dashboard,
|
||||||
icon: Gauge,
|
icon: Gauge,
|
||||||
permission: isAdmin
|
permission: isAdmin
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "post",
|
||||||
title: "post.title",
|
title: "post.title",
|
||||||
url: consolePath.post,
|
url: consolePath.post,
|
||||||
icon: Newspaper,
|
icon: Newspaper,
|
||||||
permission: isEditor
|
permission: isEditor
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "comment",
|
||||||
title: "comment.title",
|
title: "comment.title",
|
||||||
url: consolePath.comment,
|
url: consolePath.comment,
|
||||||
icon: MessageCircle,
|
icon: MessageCircle,
|
||||||
permission: isEditor
|
permission: isEditor
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "file",
|
||||||
title: "file.title",
|
title: "file.title",
|
||||||
url: consolePath.file,
|
url: consolePath.file,
|
||||||
icon: Folder,
|
icon: Folder,
|
||||||
permission: () => true
|
permission: () => true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "user",
|
||||||
title: "user.title",
|
title: "user.title",
|
||||||
url: consolePath.user,
|
url: consolePath.user,
|
||||||
icon: Users,
|
icon: Users,
|
||||||
permission: isAdmin
|
permission: isAdmin
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "global",
|
||||||
title: "global.title",
|
title: "global.title",
|
||||||
url: consolePath.global,
|
url: consolePath.global,
|
||||||
icon: Settings,
|
icon: Settings,
|
||||||
@ -53,19 +60,22 @@ export const sidebarData: { navMain: SidebarItem[]; navUserCenter: SidebarItem[]
|
|||||||
],
|
],
|
||||||
navUserCenter: [
|
navUserCenter: [
|
||||||
{
|
{
|
||||||
|
id: "user_profile",
|
||||||
title: "user_profile.title",
|
title: "user_profile.title",
|
||||||
url: consolePath.userProfile,
|
url: consolePath.userProfile,
|
||||||
icon: UserPen,
|
icon: UserPen,
|
||||||
permission: () => true
|
permission: () => true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "user_security",
|
||||||
title: "user_security.title",
|
title: "user_security.title",
|
||||||
url: consolePath.userSecurity,
|
url: consolePath.userSecurity,
|
||||||
icon: ShieldCheck,
|
icon: ShieldCheck,
|
||||||
permission: () => true
|
permission: () => true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "user-preference.title",
|
id: "user_preference",
|
||||||
|
title: "user_preference.title",
|
||||||
url: consolePath.userPreference,
|
url: consolePath.userPreference,
|
||||||
icon: Palette,
|
icon: Palette,
|
||||||
permission: () => true
|
permission: () => true
|
||||||
|
@ -10,39 +10,34 @@ import {
|
|||||||
} from "@/components/ui/sidebar"
|
} from "@/components/ui/sidebar"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { User } from "@/models/user";
|
|
||||||
import { useAuth } from "@/contexts/auth-context";
|
import { useAuth } from "@/contexts/auth-context";
|
||||||
import { IconType } from "@/types/icon";
|
|
||||||
import { useTranslations } from "next-intl";
|
|
||||||
import { consolePath } from "@/hooks/use-route";
|
import { consolePath } from "@/hooks/use-route";
|
||||||
|
import { SidebarItem } from "./data";
|
||||||
|
|
||||||
export function NavMain({
|
export function NavGroup({
|
||||||
items,
|
items,
|
||||||
|
title,
|
||||||
|
activeId,
|
||||||
|
setActiveId
|
||||||
}: {
|
}: {
|
||||||
items: {
|
items: SidebarItem[],
|
||||||
title: string
|
title: string,
|
||||||
url: string
|
activeId: string,
|
||||||
icon?: IconType;
|
setActiveId? :(id: string) => void
|
||||||
permission: ({ user }: { user: User }) => boolean
|
|
||||||
}[]
|
|
||||||
}) {
|
}) {
|
||||||
const t = useTranslations("Console")
|
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const pathname = usePathname() ?? "/"
|
|
||||||
|
|
||||||
if (!user) return null;
|
if (!user) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarGroup>
|
<SidebarGroup>
|
||||||
<SidebarGroupContent className="flex flex-col gap-2">
|
<SidebarGroupContent className="flex flex-col gap-2">
|
||||||
<SidebarGroupLabel>{t("general")}</SidebarGroupLabel>
|
<SidebarGroupLabel>{title}</SidebarGroupLabel>
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
item.permission({ user }) && <SidebarMenuItem key={item.title}>
|
item.permission({ user }) && <SidebarMenuItem key={item.title}>
|
||||||
<Link href={item.url}>
|
<Link href={item.url} onClick={() => setActiveId && setActiveId(item.id)}>
|
||||||
<SidebarMenuButton tooltip={item.title} isActive={item.url != consolePath.dashboard && pathname.startsWith(item.url) || item.url === pathname}>
|
<SidebarMenuButton tooltip={item.title} isActive={activeId === item.id}>
|
||||||
{item.icon && <item.icon />}
|
{item.icon && <item.icon />}
|
||||||
<span>{t(item.title)}</span>
|
<span>{item.title}</span>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</Link>
|
</Link>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
@ -1,50 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import {
|
|
||||||
SidebarGroup,
|
|
||||||
SidebarGroupLabel,
|
|
||||||
SidebarMenu,
|
|
||||||
SidebarMenuButton,
|
|
||||||
SidebarMenuItem,
|
|
||||||
} from "@/components/ui/sidebar"
|
|
||||||
import { User } from "@/models/user"
|
|
||||||
import Link from "next/link"
|
|
||||||
import { usePathname } from "next/navigation"
|
|
||||||
import { useAuth } from "@/contexts/auth-context"
|
|
||||||
import { IconType } from "@/types/icon"
|
|
||||||
import { useTranslations } from "next-intl"
|
|
||||||
|
|
||||||
export function NavUserCenter({
|
|
||||||
items,
|
|
||||||
}: {
|
|
||||||
items: {
|
|
||||||
title: string
|
|
||||||
url: string
|
|
||||||
icon?: IconType;
|
|
||||||
permission: ({ user }: { user: User }) => boolean
|
|
||||||
}[]
|
|
||||||
}) {
|
|
||||||
const t = useTranslations("Console")
|
|
||||||
const { user } = useAuth();
|
|
||||||
const pathname = usePathname() ?? "/"
|
|
||||||
|
|
||||||
if (!user) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SidebarGroup className="group-data-[collapsible=icon]:hidden">
|
|
||||||
<SidebarGroupLabel>{t("personal")}</SidebarGroupLabel>
|
|
||||||
<SidebarMenu>
|
|
||||||
{items.map((item) => (
|
|
||||||
item.permission({ user }) && <SidebarMenuItem key={item.title}>
|
|
||||||
<Link href={item.url}>
|
|
||||||
<SidebarMenuButton tooltip={item.title} isActive={pathname === item.url}>
|
|
||||||
{item.icon && <item.icon />}
|
|
||||||
<span>{t(item.title)}</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</Link>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
))}
|
|
||||||
</SidebarMenu>
|
|
||||||
</SidebarGroup>
|
|
||||||
)
|
|
||||||
}
|
|
@ -133,7 +133,7 @@
|
|||||||
"update_password_success": "密码已更新",
|
"update_password_success": "密码已更新",
|
||||||
"verify_code": "验证码"
|
"verify_code": "验证码"
|
||||||
},
|
},
|
||||||
"user-preference": {
|
"user_preference": {
|
||||||
"title": "个性化"
|
"title": "个性化"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user