diff --git a/app/admin/configuration/page.tsx b/app/admin/configuration/page.tsx index 59d27f49..6e6435c7 100644 --- a/app/admin/configuration/page.tsx +++ b/app/admin/configuration/page.tsx @@ -1,13 +1,9 @@ -import ClearCacheButton from '@/admin/ClearCacheButton'; import AdminAppConfiguration from '@/admin/AdminAppConfiguration'; import AdminInfoPage from '@/admin/AdminInfoPage'; export default function AdminAppConfigurationPage() { return ( - } - > + ); diff --git a/app/admin/insights/page.tsx b/app/admin/insights/page.tsx index 0bf5efa4..eed08769 100644 --- a/app/admin/insights/page.tsx +++ b/app/admin/insights/page.tsx @@ -2,7 +2,7 @@ import AdminAppInsights from '@/admin/insights/AdminAppInsights'; import AdminInfoPage from '@/admin/AdminInfoPage'; export default async function AdminInsightsPage() { - return + return ; } diff --git a/src/admin/AdminAppInfoIcon.tsx b/src/admin/AdminAppInfoIcon.tsx new file mode 100644 index 00000000..73142c3c --- /dev/null +++ b/src/admin/AdminAppInfoIcon.tsx @@ -0,0 +1,36 @@ +import { useAppState } from '@/state/AppState'; +import clsx from 'clsx/lite'; +import { FaCircle } from 'react-icons/fa6'; +import { LuCog } from 'react-icons/lu'; + +export default function AdminAppInfoIcon({ + className, +}: { + className?: string +}) { + const { insightIndicatorStatus } = useAppState(); + + return ( + + + {insightIndicatorStatus && + } + + ); +} diff --git a/src/admin/AdminInfoPage.tsx b/src/admin/AdminInfoPage.tsx index 0af159ee..cb62b1ed 100644 --- a/src/admin/AdminInfoPage.tsx +++ b/src/admin/AdminInfoPage.tsx @@ -1,14 +1,27 @@ +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({ - title, - accessory, + page, children, }: { - title: string - accessory?: ReactNode + page: (typeof ADMIN_INFO_PAGES)[number]['titleShort'] children: ReactNode }) { return ( @@ -16,10 +29,28 @@ export default function AdminInfoPage({ contentMain={ - - {title} + + {ADMIN_INFO_PAGES.map(({ title, titleShort, path }) => + + + {title ?? titleShort} + + )} - {accessory} + {children} diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index c7aea84a..7255cb10 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -6,11 +6,9 @@ import Note from '@/components/Note'; import SiteGrid from '@/components/SiteGrid'; import Spinner from '@/components/Spinner'; import { - PATH_ADMIN_CONFIGURATION, PATH_ADMIN_INSIGHTS, checkPathPrefix, - isPathAdminConfiguration, - isPathAdminInsights, + isPathAdminInfo, isPathTopLevelAdmin, } from '@/app/paths'; import { useAppState } from '@/state/AppState'; @@ -19,8 +17,7 @@ import { differenceInMinutes } from 'date-fns'; import { usePathname } from 'next/navigation'; import { useEffect, useMemo, useState } from 'react'; import { FaRegClock } from 'react-icons/fa'; -import AdminAppInsightsIcon from './insights/AdminAppInsightsIcon'; -import { LuCog } from 'react-icons/lu'; +import AdminAppInfoIcon from './AdminAppInfoIcon'; // Updates considered recent if they occurred in past 5 minutes const areTimesRecent = (dates: Date[]) => dates @@ -29,6 +26,8 @@ const areTimesRecent = (dates: Date[]) => dates export default function AdminNavClient({ items, mostRecentPhotoUpdateTime, + // TODO: use this with new component + // eslint-disable-next-line @typescript-eslint/no-unused-vars includeInsights, }: { items: { @@ -91,33 +90,15 @@ export default function AdminNavClient({ ({count})} )} - - {includeInsights && - } - > - - } - } - > - - - + } + > + + {shouldShowBanner && }> diff --git a/src/app/paths.ts b/src/app/paths.ts index 302ead59..e03a7ac1 100644 --- a/src/app/paths.ts +++ b/src/app/paths.ts @@ -64,6 +64,7 @@ export const PATHS_ADMIN = [ PATH_ADMIN_PHOTOS, PATH_ADMIN_UPLOADS, PATH_ADMIN_TAGS, + PATH_ADMIN_INSIGHTS, PATH_ADMIN_CONFIGURATION, PATH_ADMIN_BASELINE, PATH_ADMIN_COMPONENTS, @@ -225,11 +226,15 @@ export const isPathAdmin = (pathname?: string) => export const isPathTopLevelAdmin = (pathname?: string) => PATHS_ADMIN.some(path => path === pathname); +export const isPathAdminInsights = (pathname?: string) => + checkPathPrefix(pathname, PATH_ADMIN_INSIGHTS); + export const isPathAdminConfiguration = (pathname?: string) => checkPathPrefix(pathname, PATH_ADMIN_CONFIGURATION); -export const isPathAdminInsights = (pathname?: string) => - checkPathPrefix(pathname, PATH_ADMIN_INSIGHTS); +export const isPathAdminInfo = (pathname?: string) => + isPathAdminInsights(pathname) || + isPathAdminConfiguration(pathname); export const isPathProtected = (pathname?: string) => checkPathPrefix(pathname, PATH_ADMIN) || diff --git a/src/components/LinkWithStatus.tsx b/src/components/LinkWithStatus.tsx index fa5a2803..b64852b5 100644 --- a/src/components/LinkWithStatus.tsx +++ b/src/components/LinkWithStatus.tsx @@ -24,6 +24,7 @@ export type LinkWithStatusProps = Omit< children: ReactNode | ((props: { isLoading: boolean }) => ReactNode) + debugLoading?: boolean } export default function LinkWithStatus({ @@ -32,12 +33,14 @@ export default function LinkWithStatus({ className, onClick, children, + debugLoading = false, ...props }: LinkWithStatusProps) { const path = usePathname(); const [pathWhenClicked, setPathWhenClicked] = useState(); - const [isLoading, setIsLoading] = useState(false); + const [_isLoading, setIsLoading] = useState(false); + const isLoading = _isLoading || debugLoading; const isLoadingStartTime = useRef(undefined); diff --git a/tailwind.css b/tailwind.css index 6aa846fe..f1368499 100644 --- a/tailwind.css +++ b/tailwind.css @@ -301,6 +301,7 @@ disabled:bg-gray-100 dark:disabled:bg-gray-900 disabled:border-gray-200 disabled:dark:border-gray-700 border-gray-900 dark:border-gray-100 + hover:border-gray-900 dark:hover:border-gray-100 active:bg-gray-700 active:border-gray-700 active:dark:bg-gray-300 active:dark:border-gray-300 shadow-none