diff --git a/src/app/(with-header)/dashboard/page.tsx b/src/app/(with-header)/dashboard/page.tsx new file mode 100644 index 0000000..2190c09 --- /dev/null +++ b/src/app/(with-header)/dashboard/page.tsx @@ -0,0 +1,3 @@ +export default function DashboardPage() { + return
dashboard
; +} diff --git a/src/app/(with-header)/layout.tsx b/src/app/(with-header)/layout.tsx new file mode 100644 index 0000000..5e9a1ee --- /dev/null +++ b/src/app/(with-header)/layout.tsx @@ -0,0 +1,11 @@ +import { LayoutProps } from '@/types/layout'; +import { ClientProviders } from '@/components/client-providers'; +import { HeaderSidebar } from '@/components/header-sidebar'; + +export default async function HeaderLayout({children}: LayoutProps) { + return ( + + { children } + + ) +}; diff --git a/src/app/(with-header)/settings/page.tsx b/src/app/(with-header)/settings/page.tsx new file mode 100644 index 0000000..e334d8f --- /dev/null +++ b/src/app/(with-header)/settings/page.tsx @@ -0,0 +1,3 @@ +export default function SettingsPage() { + return (
settings
); +} diff --git a/src/components/header-sidebar.tsx b/src/components/header-sidebar.tsx new file mode 100644 index 0000000..c3862fe --- /dev/null +++ b/src/components/header-sidebar.tsx @@ -0,0 +1,122 @@ +'use client'; + +import { Button, Divider } from '@nextui-org/react'; +import { Bars3Icon, ChevronLeftIcon, XMarkIcon } from '@heroicons/react/20/solid'; +import { Fragment, useState } from 'react'; +import Link from 'next/link'; +import { ThemeSwitcherDropdown, ThemeSwitcherSwitch } from '@/components/theme-switcher'; +import { AdjustmentsHorizontalIcon } from '@heroicons/react/24/solid'; +import { login, logout } from '@/actions/auth'; +import { usePathname, useRouter, useSearchParams } from 'next/navigation'; +import { UserPayload } from '@/types/user'; +import { MAIN_ROUTES, ROUTES, UserOnly } from '@/routes'; +import { useUser } from '@/helpers/use-user'; + +export type HeaderSidebarProps = { + children?: React.ReactNode +}; + +const filterUserOnly = (user: UserPayload | null | undefined, { userOnly }: { userOnly?: UserOnly }) => { + if (!userOnly) return true; + if (typeof userOnly === 'string') return user?.[userOnly]; + return user; +}; + +export const HeaderSidebar = ({ children }: HeaderSidebarProps) => { + const user = useUser(); + const path = usePathname(); + const params = useSearchParams(); + const [isMenuOpen, setMenuOpen] = useState(false); + + const from = params.get('from'); + const filter = filterUserOnly.bind(null, user); + const routeGroup = ROUTES.find(route => route.title === from || path.startsWith(route.url))!; + + return (<> +
+
setMenuOpen(false)} /> +
+
+ + +
+
+ {ROUTES.map((route, i) => +
+ {!filter(route) ?
+ {route.name} +
: setMenuOpen(false)} + className={`text-2xl transition hover:text-secondary ${route === routeGroup ? 'font-bold' : 'font-semibold'}`}> + {route.name} + } +
+ {route.routes?.filter(filter)?.map(subroute =>
+ setMenuOpen(false)} + className={`text-xl transition hover:text-secondary ${path.startsWith(subroute.url) ? 'font-semibold' : ''}`}> + {subroute.name} + +
)} +
+
+ {i < ROUTES.length - 1 && } +
)} +
+
+ + + {user && + + } +
+ +
+
+
+
+ +
+ {routeGroup.routes?.filter(filter).map(route => + + {route.name} + ) + } +
+ {routeGroup !== MAIN_ROUTES &&
+ {MAIN_ROUTES.routes.filter(filter).map(route => + {route.name} + )} +
} +
+ + {user && } + + + +
+
+
+ {children} +
+
+ ) +}; diff --git a/src/routes.ts b/src/routes.ts new file mode 100644 index 0000000..5233be8 --- /dev/null +++ b/src/routes.ts @@ -0,0 +1,50 @@ +import { UserPayload } from '@/types/user'; + +export type UserOnly = boolean | keyof UserPayload; + +type Subroute = { + url: string, + name: string, + userOnly?: UserOnly +}; + +type Route = { + url: string, + name: string, + title: string, + userOnly?: UserOnly, + routes: Subroute[] +}; + +export const MAIN_ROUTES: Route = { + url: '/', + name: "Actaeon", + title: 'Actaeon', + routes: [{ + url: '/dashboard', + name: 'Overview' + }] +}; + +export const ROUTES: Route[] = [{ + url: '/chuni', + name: 'Chunithm', + title: 'Chunithm', + userOnly: 'chuni', + routes: [{ + url: '/chuni/dashboard', + name: 'Dashboard', + userOnly: 'chuni' + }, { + url: '/chuni/music', + name: 'Music List' + }, { + url: '/chuni/playlog', + name: 'Playlog', + userOnly: 'chuni' + }, { + url: '/chuni/userbox', + name: 'Userbox', + userOnly: 'chuni' + }] +}, MAIN_ROUTES];