Refactor admin subnav

This commit is contained in:
Sam Becker 2025-02-25 23:31:19 -06:00
parent 783a4f1988
commit d2494e66d5
5 changed files with 77 additions and 52 deletions

View File

@ -3,7 +3,7 @@ import AdminInfoPage from '@/admin/AdminInfoPage';
export default function AdminAppConfigurationPage() {
return (
<AdminInfoPage page="Config">
<AdminInfoPage>
<AdminAppConfiguration />
</AdminInfoPage>
);

View File

@ -2,7 +2,7 @@ import AdminAppInsights from '@/admin/insights/AdminAppInsights';
import AdminInfoPage from '@/admin/AdminInfoPage';
export default async function AdminInsightsPage() {
return <AdminInfoPage page="Insights">
return <AdminInfoPage>
<AdminAppInsights />
</AdminInfoPage>;
}

View File

@ -0,0 +1,64 @@
'use client';
import { PATH_ADMIN_CONFIGURATION, PATH_ADMIN_INSIGHTS } from '@/app/paths';
import LinkWithStatus from '@/components/LinkWithStatus';
import ResponsiveText from '@/components/primitives/ResponsiveText';
import clsx from 'clsx/lite';
import ClearCacheButton from '@/admin/ClearCacheButton';
import { usePathname } from 'next/navigation';
const ADMIN_INFO_PAGES = [{
titleShort: 'Insights',
path: PATH_ADMIN_INSIGHTS,
}, {
title: 'Configuration',
titleShort: 'Config',
path: PATH_ADMIN_CONFIGURATION,
}];
export default function AdminInfoPage({
includeInsights,
}: {
includeInsights: boolean
}) {
const pathname = usePathname();
const pages = ADMIN_INFO_PAGES
.filter(({ titleShort }) => (
titleShort !== 'Insights' ||
includeInsights
));
const hasMultiplePages = pages.length > 1;
return (
<div className="flex items-center gap-4 min-h-9">
<div className={clsx(
'grow -translate-x-1',
'flex items-center gap-3',
hasMultiplePages && '-translate-y-1',
)}>
{pages
.map(({ title, titleShort, path }) =>
<LinkWithStatus
key={path}
href={path}
className={clsx(
hasMultiplePages
? pathname === path
? 'underline underline-offset-10 decoration-2'
: 'text-dim'
: undefined,
'px-1 py-0.5 rounded-md',
)}
loadingClassName="bg-dim"
>
<ResponsiveText shortText={titleShort}>
{title ?? titleShort}
</ResponsiveText>
</LinkWithStatus>)}
</div>
<ClearCacheButton />
</div>
);
}

View File

@ -1,61 +1,18 @@
import { PATH_ADMIN_CONFIGURATION, PATH_ADMIN_INSIGHTS } from '@/app/paths';
import Container from '@/components/Container';
import LinkWithStatus from '@/components/LinkWithStatus';
import ResponsiveText from '@/components/primitives/ResponsiveText';
import SiteGrid from '@/components/SiteGrid';
import clsx from 'clsx/lite';
import { ReactNode } from 'react';
import ClearCacheButton from '@/admin/ClearCacheButton';
const ADMIN_INFO_PAGES = [{
titleShort: 'Insights',
path: PATH_ADMIN_INSIGHTS,
},
{
title: 'Configuration',
titleShort: 'Config',
path: PATH_ADMIN_CONFIGURATION,
}];
export default function AdminInfoPage({
page,
children,
}: {
page: (typeof ADMIN_INFO_PAGES)[number]['titleShort']
children: ReactNode
}) {
return (
<SiteGrid
contentMain={
<div className="space-y-4">
<div className="flex items-center gap-4 min-h-9">
<div className={clsx(
'grow -translate-x-1 -translate-y-1',
'flex items-center gap-3',
)}>
{ADMIN_INFO_PAGES.map(({ title, titleShort, path }) =>
<LinkWithStatus
key={path}
href={path}
className={clsx(
page === titleShort
? 'underline underline-offset-10 decoration-2'
: 'text-dim',
'px-1 py-0.5 rounded-md',
)}
loadingClassName="bg-dim"
>
<ResponsiveText shortText={titleShort}>
{title ?? titleShort}
</ResponsiveText>
</LinkWithStatus>)}
</div>
<ClearCacheButton />
</div>
<Container spaceChildren={false}>
{children}
</Container>
</div>}
</Container>}
/>
);
}

View File

@ -6,6 +6,7 @@ import Note from '@/components/Note';
import SiteGrid from '@/components/SiteGrid';
import Spinner from '@/components/Spinner';
import {
PATH_ADMIN_CONFIGURATION,
PATH_ADMIN_INSIGHTS,
checkPathPrefix,
isPathAdminInfo,
@ -18,6 +19,7 @@ import { usePathname } from 'next/navigation';
import { useEffect, useMemo, useState } from 'react';
import { FaRegClock } from 'react-icons/fa';
import AdminAppInfoIcon from './AdminAppInfoIcon';
import AdminInfoNav from './AdminInfoNav';
// Updates considered recent if they occurred in past 5 minutes
const areTimesRecent = (dates: Date[]) => dates
@ -26,9 +28,7 @@ const areTimesRecent = (dates: Date[]) => dates
export default function AdminNavClient({
items,
mostRecentPhotoUpdateTime,
// TODO: use this with new <AdminSubNav> component
// eslint-disable-next-line @typescript-eslint/no-unused-vars
includeInsights,
includeInsights = true,
}: {
items: {
label: string,
@ -91,7 +91,9 @@ export default function AdminNavClient({
</LinkWithStatus>)}
</div>
<LinkWithLoader
href={PATH_ADMIN_INSIGHTS}
href={includeInsights
? PATH_ADMIN_INSIGHTS
: PATH_ADMIN_CONFIGURATION}
className={isPathAdminInfo(pathname)
? 'font-bold'
: 'text-dim'}
@ -105,6 +107,8 @@ export default function AdminNavClient({
Photo updates detectedthey may take several minutes to show up
for visitors
</Note>}
{isPathAdminInfo(pathname) &&
<AdminInfoNav {...{ includeInsights }} />}
</div>
}
/>