2026-04-17 12:58:38 +08:00

105 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Link from "next/link";
import { Home, MessageCircle, Smartphone, Activity, ScanLine } from "lucide-react";
import type { ReactNode } from "react";
const navigationItems = [
{ href: "/", label: "首页", icon: Home },
{ href: "/messages", label: "留言", icon: MessageCircle },
{ href: "/devices", label: "设备", icon: Smartphone },
{ href: "/activity", label: "动态", icon: Activity },
{ href: "/scan", label: "扫码", icon: ScanLine },
];
function isActivePath(currentPath: string, href: string) {
if (href === "/") {
return currentPath === "/";
}
return currentPath === href || currentPath.startsWith(`${href}/`);
}
type PanelShellProps = {
currentPath: string;
title: string;
description: string;
caregiverLabel: string;
children: ReactNode;
actions?: ReactNode;
eyebrow?: string;
};
export function PanelShell({
currentPath,
title,
description,
caregiverLabel,
children,
actions,
eyebrow = "家人连线",
}: PanelShellProps) {
return (
<main className="relative overflow-hidden px-4 py-6 sm:px-6 lg:px-8 lg:py-8">
<div className="pointer-events-none absolute inset-x-0 top-0 h-72 bg-[radial-gradient(circle_at_top,rgba(255,255,255,0.8),transparent_70%)]" />
<div className="mx-auto max-w-7xl space-y-6">
<header className="paper-panel relative overflow-hidden rounded-[36px] border border-white/70 px-6 py-7 shadow-[0_35px_90px_rgba(105,68,41,0.13)] sm:px-8 lg:px-10 lg:py-8">
<div className="absolute -right-12 top-[-50px] h-44 w-44 rounded-full bg-[rgba(53,84,141,0.14)] blur-2xl" />
<div className="absolute left-10 top-10 h-24 w-24 rounded-full border border-[rgba(118,132,94,0.18)] z-0 pointer-events-none" />
<div className="flex flex-col gap-6 xl:flex-row xl:items-start xl:justify-between">
<div className="max-w-4xl">
<div className="flex flex-wrap gap-2">
{navigationItems.map((item) => {
const active = isActivePath(currentPath, item.href);
const Icon = item.icon;
return (
<Link
key={item.href}
href={item.href}
className={`inline-flex h-11 items-center justify-center gap-2 rounded-full px-4 text-sm font-semibold transition ${
active
? "bg-[var(--ink)] text-white shadow-[0_12px_30px_rgba(36,27,20,0.18)]"
: "border border-[var(--line)] bg-white/82 text-[var(--ink)] hover:bg-[var(--paper-soft)]"
}`}
>
<Icon size={16} />
{item.label}
</Link>
);
})}
</div>
<p className="mt-6 text-sm font-semibold tracking-[0.24em] text-[var(--copper)] uppercase">
{eyebrow}
</p>
<h1 className="mt-4 max-w-3xl font-[family-name:var(--font-display)] text-4xl leading-[1.15] text-[var(--ink)] sm:text-5xl">
{title}
</h1>
<p className="mt-5 max-w-2xl text-base leading-8 text-[var(--muted)] sm:text-lg">
{description}
</p>
<div className="mt-6 flex flex-wrap gap-3 text-sm text-[var(--muted)]">
<span className="rounded-full border border-[var(--line)] bg-white/76 px-4 py-2">
{caregiverLabel}
</span>
<form action="/api/account/logout" method="post">
<button
type="submit"
className="inline-flex h-10 items-center justify-center rounded-full border border-[var(--line)] bg-white px-4 font-semibold text-[var(--ink)] transition hover:bg-[var(--paper-soft)]"
>
退
</button>
</form>
</div>
</div>
{actions ? <div className="w-full max-w-md xl:pt-2">{actions}</div> : null}
</div>
</header>
{children}
</div>
</main>
);
}