/* * Copyright (C) 2026 Fluxer Contributors * * This file is part of Fluxer. * * Fluxer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Fluxer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Fluxer. If not, see . */ /** @jsxRuntime automatic */ /** @jsxImportSource hono/jsx */ import {getAccessibleSections} from '@fluxer/admin/src/Navigation'; import type {Session} from '@fluxer/admin/src/types/App'; import type {AdminConfig as Config} from '@fluxer/admin/src/types/Config'; import type {Flash} from '@fluxer/hono/src/Flash'; import type {UserAdminResponse} from '@fluxer/schema/src/domains/admin/AdminUserSchemas'; import {CsrfInput} from '@fluxer/ui/src/components/CsrfInput'; import {FlashMessage} from '@fluxer/ui/src/components/Flash'; import {formatDiscriminator, getUserAvatarUrl} from '@fluxer/ui/src/utils/FormatUser'; import type {FC, PropsWithChildren} from 'hono/jsx'; interface LayoutProps { title: string; activePage: string; config: Config; session: Session; currentAdmin: UserAdminResponse | undefined; flash: Flash | undefined; autoRefresh?: boolean; assetVersion: string; csrfToken: string; extraScripts?: string; inspectedVoiceRegionId?: string; } function cacheBustedAsset(basePath: string, assetVersion: string, path: string): string { return `${basePath}${path}?t=${assetVersion}`; } const Head: FC<{ title: string; basePath: string; staticCdnEndpoint: string; assetVersion: string; autoRefresh: boolean | undefined; }> = ({title, basePath, staticCdnEndpoint, assetVersion, autoRefresh}) => ( {autoRefresh && } {title} ~ Fluxer Admin ); const SidebarSection: FC> = ({title, children}) => (
{title}
{children}
); const SidebarItem: FC<{title: string; path: string; active: boolean; basePath: string}> = ({ title, path, active, basePath, }) => { const classes = active ? 'block px-3 py-2 rounded bg-neutral-800 text-white text-sm transition-colors' : 'block px-3 py-2 rounded text-neutral-300 hover:bg-neutral-800 hover:text-white text-sm transition-colors'; return ( {title} ); }; const Sidebar: FC<{ activePage: string; adminAcls: Array; basePath: string; selfHosted: boolean; inspectedVoiceRegionId?: string; }> = ({activePage, adminAcls, basePath, selfHosted, inspectedVoiceRegionId}) => { const sections = getAccessibleSections(adminAcls, {selfHosted, inspectedVoiceRegionId}); return (