feie9456 747dcd359a 家庭守护圈:多人加入、角色权限、24 小时邀请链接、旧设备绑定自动兼容。
家庭动态:老人/家属发言、三种可见范围,家庭内部内容不会播给老人。
共同照护:家庭备忘录、任务创建、认领、完成与交接记录。
用药闭环:计划、未来 7 天提醒实例、确认服用、延后、异常反馈。
风险闭环:红橙黄蓝分级、30 分钟去重、推送、认领、处理与误报记录。
报平安:家属发起、老人语音回应、状态同步。
Web 导航升级为守护、家庭、照护、陪伴、我的。
设备接口已升级为设备令牌认证,UUID 不再单独承担认证。
2026-07-18 19:59:20 +08:00

88 lines
2.5 KiB
TypeScript

import Link from "next/link";
import { ChevronLeft, HeartHandshake, House, ShieldCheck, Stethoscope, UserRound } from "lucide-react";
import type { ReactNode } from "react";
const navigationItems = [
{ href: "/guard", label: "守护", icon: ShieldCheck },
{ href: "/family", label: "家庭", icon: House },
{ href: "/care", label: "照护", icon: Stethoscope },
{ href: "/companion", label: "陪伴", icon: HeartHandshake },
{ href: "/settings", label: "我的", icon: UserRound },
];
function isActivePath(currentPath: string, href: string) {
return currentPath === href || currentPath.startsWith(`${href}/`);
}
type PanelShellProps = {
currentPath: string;
title: string;
description?: string;
caregiverLabel: string;
children: ReactNode;
actions?: ReactNode;
backHref?: string;
showTabs?: boolean;
unreadCount?: number;
};
export function PanelShell({
currentPath,
title,
description,
caregiverLabel,
children,
actions,
backHref,
showTabs = !backHref,
unreadCount = 0,
}: PanelShellProps) {
const initial = caregiverLabel.trim().slice(-1) || "安";
return (
<main className="app-frame">
<div className={`app-content app-stack${backHref ? " detail" : ""}`}>
{backHref ? (
<header className="detail-header">
<Link href={backHref} className="back-button" aria-label="返回">
<ChevronLeft size={20} strokeWidth={2} />
</Link>
<h1>{title}</h1>
{actions}
</header>
) : (
<header className="page-heading">
<div>
<h1>{title}</h1>
{description ? <p>{description}</p> : null}
</div>
{actions ?? (
<Link href="/settings" className="avatar" aria-label="我的">
{initial}
</Link>
)}
</header>
)}
{children}
</div>
{showTabs ? (
<nav className="bottom-nav" aria-label="主导航">
{navigationItems.map((item) => {
const active = isActivePath(currentPath, item.href);
const Icon = item.icon;
return (
<Link key={item.href} href={item.href} className={`nav-item${active ? " active" : ""}`}>
<Icon size={22} strokeWidth={1.8} />
<span>{item.label}</span>
{item.href === "/family" && unreadCount > 0 ? <span className="nav-badge">{unreadCount}</span> : null}
</Link>
);
})}
</nav>
) : null}
</main>
);
}