feat: 添加 Dashboard 和书签页面

This commit is contained in:
2026-03-30 21:28:44 +08:00
parent 309eb8ac7e
commit 3ce981a06a
2 changed files with 168 additions and 0 deletions
@@ -0,0 +1,76 @@
import { createFileRoute, Link, useRouter } from '@tanstack/react-router'
import * as icons from 'lucide-react'
import { modules } from '@/modules/registry'
import { authClient } from '@/server/auth/client'
const iconComponents = icons as unknown as Record<string, typeof icons.Box>
export const Route = createFileRoute('/_protected' as never)({
component: DashboardPage,
})
function DashboardPage() {
const router = useRouter()
const { user } = Route.useRouteContext() as {
user: {
name: string
email: string
}
}
const enabledModules = modules.filter((mod) => mod.enabled)
const handleSignOut = async () => {
await authClient.signOut()
router.navigate({ to: '/login' as never })
}
return (
<div className="min-h-screen bg-slate-50 px-4 py-12 sm:px-6">
<div className="mx-auto max-w-4xl space-y-8">
<div className="flex items-center justify-between gap-4">
<div>
<h1 className="text-3xl font-bold tracking-tight text-slate-900">Kairos</h1>
<p className="mt-1 text-slate-500">
{user.name} · {user.email}
</p>
</div>
<button
type="button"
onClick={handleSignOut}
className="rounded-lg px-4 py-2 text-sm text-slate-600 transition-colors hover:bg-slate-100 hover:text-slate-900"
>
退
</button>
</div>
{enabledModules.length === 0 ? (
<div className="py-20 text-center text-slate-400"></div>
) : (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{enabledModules.map((mod) => {
const IconComponent = iconComponents[mod.icon] ?? icons.Box
return (
<Link
key={mod.id}
to={mod.route as never}
className="group block rounded-2xl bg-white p-6 shadow-sm ring-1 ring-slate-100 transition-all hover:shadow-md hover:ring-slate-200"
>
<div className="flex items-center gap-4">
<div className="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-xl bg-indigo-50 transition-colors group-hover:bg-indigo-100">
<IconComponent className="h-6 w-6 text-indigo-600" />
</div>
<div>
<h3 className="font-semibold text-slate-900">{mod.name}</h3>
<p className="mt-0.5 text-sm text-slate-500">{mod.description}</p>
</div>
</div>
</Link>
)
})}
</div>
)}
</div>
</div>
)
}