Refactor admin subnav
This commit is contained in:
parent
783a4f1988
commit
d2494e66d5
@ -3,7 +3,7 @@ import AdminInfoPage from '@/admin/AdminInfoPage';
|
|||||||
|
|
||||||
export default function AdminAppConfigurationPage() {
|
export default function AdminAppConfigurationPage() {
|
||||||
return (
|
return (
|
||||||
<AdminInfoPage page="Config">
|
<AdminInfoPage>
|
||||||
<AdminAppConfiguration />
|
<AdminAppConfiguration />
|
||||||
</AdminInfoPage>
|
</AdminInfoPage>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import AdminAppInsights from '@/admin/insights/AdminAppInsights';
|
|||||||
import AdminInfoPage from '@/admin/AdminInfoPage';
|
import AdminInfoPage from '@/admin/AdminInfoPage';
|
||||||
|
|
||||||
export default async function AdminInsightsPage() {
|
export default async function AdminInsightsPage() {
|
||||||
return <AdminInfoPage page="Insights">
|
return <AdminInfoPage>
|
||||||
<AdminAppInsights />
|
<AdminAppInsights />
|
||||||
</AdminInfoPage>;
|
</AdminInfoPage>;
|
||||||
}
|
}
|
||||||
|
|||||||
64
src/admin/AdminInfoNav.tsx
Normal file
64
src/admin/AdminInfoNav.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,61 +1,18 @@
|
|||||||
import { PATH_ADMIN_CONFIGURATION, PATH_ADMIN_INSIGHTS } from '@/app/paths';
|
|
||||||
import Container from '@/components/Container';
|
import Container from '@/components/Container';
|
||||||
import LinkWithStatus from '@/components/LinkWithStatus';
|
|
||||||
import ResponsiveText from '@/components/primitives/ResponsiveText';
|
|
||||||
import SiteGrid from '@/components/SiteGrid';
|
import SiteGrid from '@/components/SiteGrid';
|
||||||
import clsx from 'clsx/lite';
|
|
||||||
import { ReactNode } from 'react';
|
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({
|
export default function AdminInfoPage({
|
||||||
page,
|
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
page: (typeof ADMIN_INFO_PAGES)[number]['titleShort']
|
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<SiteGrid
|
<SiteGrid
|
||||||
contentMain={
|
contentMain={
|
||||||
<div className="space-y-4">
|
<Container spaceChildren={false}>
|
||||||
<div className="flex items-center gap-4 min-h-9">
|
{children}
|
||||||
<div className={clsx(
|
</Container>}
|
||||||
'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>}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import Note from '@/components/Note';
|
|||||||
import SiteGrid from '@/components/SiteGrid';
|
import SiteGrid from '@/components/SiteGrid';
|
||||||
import Spinner from '@/components/Spinner';
|
import Spinner from '@/components/Spinner';
|
||||||
import {
|
import {
|
||||||
|
PATH_ADMIN_CONFIGURATION,
|
||||||
PATH_ADMIN_INSIGHTS,
|
PATH_ADMIN_INSIGHTS,
|
||||||
checkPathPrefix,
|
checkPathPrefix,
|
||||||
isPathAdminInfo,
|
isPathAdminInfo,
|
||||||
@ -18,6 +19,7 @@ import { usePathname } from 'next/navigation';
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { FaRegClock } from 'react-icons/fa';
|
import { FaRegClock } from 'react-icons/fa';
|
||||||
import AdminAppInfoIcon from './AdminAppInfoIcon';
|
import AdminAppInfoIcon from './AdminAppInfoIcon';
|
||||||
|
import AdminInfoNav from './AdminInfoNav';
|
||||||
|
|
||||||
// Updates considered recent if they occurred in past 5 minutes
|
// Updates considered recent if they occurred in past 5 minutes
|
||||||
const areTimesRecent = (dates: Date[]) => dates
|
const areTimesRecent = (dates: Date[]) => dates
|
||||||
@ -26,9 +28,7 @@ const areTimesRecent = (dates: Date[]) => dates
|
|||||||
export default function AdminNavClient({
|
export default function AdminNavClient({
|
||||||
items,
|
items,
|
||||||
mostRecentPhotoUpdateTime,
|
mostRecentPhotoUpdateTime,
|
||||||
// TODO: use this with new <AdminSubNav> component
|
includeInsights = true,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
includeInsights,
|
|
||||||
}: {
|
}: {
|
||||||
items: {
|
items: {
|
||||||
label: string,
|
label: string,
|
||||||
@ -91,7 +91,9 @@ export default function AdminNavClient({
|
|||||||
</LinkWithStatus>)}
|
</LinkWithStatus>)}
|
||||||
</div>
|
</div>
|
||||||
<LinkWithLoader
|
<LinkWithLoader
|
||||||
href={PATH_ADMIN_INSIGHTS}
|
href={includeInsights
|
||||||
|
? PATH_ADMIN_INSIGHTS
|
||||||
|
: PATH_ADMIN_CONFIGURATION}
|
||||||
className={isPathAdminInfo(pathname)
|
className={isPathAdminInfo(pathname)
|
||||||
? 'font-bold'
|
? 'font-bold'
|
||||||
: 'text-dim'}
|
: 'text-dim'}
|
||||||
@ -105,6 +107,8 @@ export default function AdminNavClient({
|
|||||||
Photo updates detected—they may take several minutes to show up
|
Photo updates detected—they may take several minutes to show up
|
||||||
for visitors
|
for visitors
|
||||||
</Note>}
|
</Note>}
|
||||||
|
{isPathAdminInfo(pathname) &&
|
||||||
|
<AdminInfoNav {...{ includeInsights }} />}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user