feat: ship blog platform admin and deploy stack

This commit is contained in:
2026-03-31 21:48:39 +08:00
parent a9a05aa105
commit 313f174fbc
210 changed files with 25476 additions and 5803 deletions

View File

@@ -1,7 +1,9 @@
import {
BarChart3,
BellRing,
BookOpenText,
ExternalLink,
History,
Image as ImageIcon,
LayoutDashboard,
Link2,
@@ -18,6 +20,7 @@ import { NavLink } from 'react-router-dom'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Separator } from '@/components/ui/separator'
import { buildFrontendUrl } from '@/lib/frontend-url'
import { cn } from '@/lib/utils'
const primaryNav = [
@@ -39,6 +42,12 @@ const primaryNav = [
description: 'Markdown 内容管理',
icon: ScrollText,
},
{
to: '/revisions',
label: '版本',
description: '历史快照与一键回滚',
icon: History,
},
{
to: '/comments',
label: '评论',
@@ -63,6 +72,18 @@ const primaryNav = [
description: '对象存储图片管理',
icon: ImageIcon,
},
{
to: '/subscriptions',
label: '订阅',
description: '邮件 / Webhook 推送',
icon: BellRing,
},
{
to: '/audit',
label: '审计',
description: '后台操作审计日志',
icon: Settings,
},
{
to: '/settings',
label: '设置',
@@ -74,12 +95,20 @@ const primaryNav = [
export function AppShell({
children,
username,
email,
authSource,
authProvider,
loggingOut,
canLogout,
onLogout,
}: {
children: ReactNode
username: string | null
email: string | null
authSource: string | null
authProvider: string | null
loggingOut: boolean
canLogout: boolean
onLogout: () => Promise<void>
}) {
return (
@@ -155,7 +184,7 @@ export function AppShell({
</p>
<p className="mt-1 text-sm text-muted-foreground">
</p>
</div>
<Badge variant="success"></Badge>
@@ -186,8 +215,13 @@ export function AppShell({
{username ?? 'admin'}
</p>
<p className="text-xs uppercase tracking-[0.18em] text-muted-foreground">
React + shadcn/ui
{authProvider ?? 'React + shadcn/ui 基础架构'}
</p>
{email ? (
<p className="text-xs text-muted-foreground">{email}</p>
) : authSource ? (
<p className="text-xs text-muted-foreground">{authSource}</p>
) : null}
</div>
</div>
@@ -213,14 +247,19 @@ export function AppShell({
<div className="flex flex-wrap items-center gap-3">
<Button variant="outline" asChild>
<a href="http://localhost:4321" target="_blank" rel="noreferrer">
<a href={buildFrontendUrl('/')} target="_blank" rel="noreferrer">
<ExternalLink className="h-4 w-4" />
</a>
</Button>
<Button variant="ghost" onClick={() => void onLogout()} disabled={loggingOut}>
<Button
variant="ghost"
onClick={() => void onLogout()}
disabled={loggingOut || !canLogout}
title={canLogout ? undefined : '当前会话由前置 SSO / 代理控制'}
>
<LogOut className="h-4 w-4" />
{loggingOut ? '退出中...' : '退出登录'}
{canLogout ? (loggingOut ? '退出中...' : '退出登录') : 'SSO 受代理保护'}
</Button>
</div>
</div>