forked from syntaxbullet/aurorabot
feat: Implement new settings pages and refactor application layout and navigation with new components and hooks.
This commit is contained in:
146
web/src/contexts/navigation-context.tsx
Normal file
146
web/src/contexts/navigation-context.tsx
Normal file
@@ -0,0 +1,146 @@
|
||||
import * as React from "react"
|
||||
import { useLocation, type Location } from "react-router-dom"
|
||||
import { Home, Palette, ShieldCheck, Users, Settings, BarChart3, Scroll, type LucideIcon } from "lucide-react"
|
||||
|
||||
export interface NavSubItem {
|
||||
title: string
|
||||
url: string
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
export interface NavItem {
|
||||
title: string
|
||||
url: string
|
||||
icon: LucideIcon
|
||||
isActive?: boolean
|
||||
subItems?: NavSubItem[]
|
||||
}
|
||||
|
||||
export interface Breadcrumb {
|
||||
title: string
|
||||
url: string
|
||||
}
|
||||
|
||||
interface NavigationContextProps {
|
||||
navItems: NavItem[]
|
||||
breadcrumbs: Breadcrumb[]
|
||||
currentPath: string
|
||||
currentTitle: string
|
||||
}
|
||||
|
||||
const NavigationContext = React.createContext<NavigationContextProps | null>(null)
|
||||
|
||||
interface NavConfigItem extends Omit<NavItem, "isActive" | "subItems"> {
|
||||
subItems?: Omit<NavSubItem, "isActive">[]
|
||||
}
|
||||
|
||||
const NAV_CONFIG: NavConfigItem[] = [
|
||||
{ title: "Home", url: "/", icon: Home },
|
||||
|
||||
{ title: "Design System", url: "/design-system", icon: Palette },
|
||||
{
|
||||
title: "Admin",
|
||||
url: "/admin",
|
||||
icon: ShieldCheck,
|
||||
subItems: [
|
||||
{ title: "Overview", url: "/admin/overview" },
|
||||
{ title: "Quests", url: "/admin/quests" },
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Settings",
|
||||
url: "/settings",
|
||||
icon: Settings,
|
||||
subItems: [
|
||||
{ title: "General", url: "/settings/general" },
|
||||
{ title: "Economy", url: "/settings/economy" },
|
||||
{ title: "Systems", url: "/settings/systems" },
|
||||
{ title: "Roles", url: "/settings/roles" },
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
function generateBreadcrumbs(location: Location): Breadcrumb[] {
|
||||
const pathParts = location.pathname.split("/").filter(Boolean)
|
||||
const breadcrumbs: Breadcrumb[] = []
|
||||
|
||||
let currentPath = ""
|
||||
for (const part of pathParts) {
|
||||
currentPath += `/${part}`
|
||||
// Capitalize and clean up the part for display
|
||||
const title = part
|
||||
.split("-")
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(" ")
|
||||
breadcrumbs.push({ title, url: currentPath })
|
||||
}
|
||||
|
||||
return breadcrumbs
|
||||
}
|
||||
|
||||
function getPageTitle(pathname: string): string {
|
||||
// Check top-level items first
|
||||
for (const item of NAV_CONFIG) {
|
||||
if (item.url === pathname) return item.title
|
||||
// Check sub-items
|
||||
if (item.subItems) {
|
||||
const subItem = item.subItems.find((sub) => sub.url === pathname)
|
||||
if (subItem) return subItem.title
|
||||
}
|
||||
}
|
||||
|
||||
// Handle nested routes
|
||||
const parts = pathname.split("/").filter(Boolean)
|
||||
const lastPart = parts[parts.length - 1]
|
||||
if (lastPart) {
|
||||
return lastPart
|
||||
.split("-")
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
return "Aurora"
|
||||
}
|
||||
|
||||
export function NavigationProvider({ children }: { children: React.ReactNode }) {
|
||||
const location = useLocation()
|
||||
|
||||
const value = React.useMemo<NavigationContextProps>(() => {
|
||||
const navItems = NAV_CONFIG.map((item) => {
|
||||
const isParentActive = item.subItems
|
||||
? location.pathname.startsWith(item.url)
|
||||
: location.pathname === item.url
|
||||
|
||||
return {
|
||||
...item,
|
||||
isActive: isParentActive,
|
||||
subItems: item.subItems?.map((subItem) => ({
|
||||
...subItem,
|
||||
isActive: location.pathname === subItem.url,
|
||||
})),
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
navItems,
|
||||
breadcrumbs: generateBreadcrumbs(location),
|
||||
currentPath: location.pathname,
|
||||
currentTitle: getPageTitle(location.pathname),
|
||||
}
|
||||
}, [location.pathname])
|
||||
|
||||
return (
|
||||
<NavigationContext.Provider value={value}>
|
||||
{children}
|
||||
</NavigationContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useNavigation() {
|
||||
const context = React.useContext(NavigationContext)
|
||||
if (!context) {
|
||||
throw new Error("useNavigation must be used within a NavigationProvider")
|
||||
}
|
||||
return context
|
||||
}
|
||||
Reference in New Issue
Block a user