diff --git a/app/globals.css b/app/globals.css
index b50d60c..595d8de 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -12,12 +12,30 @@
--copper-deep: #964722;
--olive: #76845e;
--olive-deep: #596946;
+ --font-body:
+ system-ui,
+ -apple-system,
+ BlinkMacSystemFont,
+ "Segoe UI",
+ "PingFang SC",
+ "Hiragino Sans GB",
+ "Microsoft YaHei UI",
+ "Microsoft YaHei",
+ sans-serif;
+ --font-display:
+ ui-serif,
+ "Songti SC",
+ "STSong",
+ "SimSun",
+ "Times New Roman",
+ serif;
}
@theme inline {
--color-background: var(--paper);
--color-foreground: var(--ink);
--font-sans: var(--font-body);
+ --font-serif: var(--font-display);
}
* {
@@ -52,6 +70,26 @@ select {
background: rgba(199, 103, 51, 0.18);
}
+@keyframes route-progress-slide {
+ 0% {
+ transform: translateX(-140%) scaleX(0.72);
+ }
+
+ 55% {
+ transform: translateX(78%) scaleX(1);
+ }
+
+ 100% {
+ transform: translateX(240%) scaleX(0.86);
+ }
+}
+
+.route-progress-bar {
+ animation: route-progress-slide 1.15s ease-in-out infinite;
+ transform-origin: left center;
+ box-shadow: 0 0 18px rgba(199, 103, 51, 0.28);
+}
+
.paper-panel {
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(255, 249, 241, 0.84)),
diff --git a/app/layout.tsx b/app/layout.tsx
index 5171711..c440f11 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,18 +1,7 @@
import type { Metadata, Viewport } from "next";
-import { Noto_Sans_SC, Noto_Serif_SC } from "next/font/google";
import "./globals.css";
-const bodyFont = Noto_Sans_SC({
- variable: "--font-body",
- subsets: ["latin"],
- weight: ["400", "500", "700"],
-});
-
-const displayFont = Noto_Serif_SC({
- variable: "--font-display",
- subsets: ["latin"],
- weight: ["400", "600", "700"],
-});
+import { NavigationProgressProvider } from "@/components/navigation-progress";
export const metadata: Metadata = {
metadataBase: new URL("https://digital-human.xn--876a.net"),
@@ -58,8 +47,10 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
-
-
{children}
+
+
+ {children}
+
);
}
diff --git a/app/scan/page.tsx b/app/scan/page.tsx
index fb10b40..54cbe35 100644
--- a/app/scan/page.tsx
+++ b/app/scan/page.tsx
@@ -1,40 +1,59 @@
import Link from "next/link";
+import { PanelShell } from "@/components/panel-shell";
import { ScanClient } from "@/components/scan-client";
+import { requireCaregiverSession } from "@/lib/page-auth";
+import { getCaregiverDisplayName } from "@/lib/session";
+
+export const dynamic = "force-dynamic";
+
+export default async function ScanPage() {
+ const caregiver = await requireCaregiverSession("/scan");
-export default function ScanPage() {
return (
-
-
-
+
+
+
- 扫码连接
+ 扫码步骤
-
+
对准长辈手机上的二维码
-
+
- 扫描成功后,系统会自动将长辈的设备连接到您的账号。之后就能随时查看长辈的留言和使用动态。
+ 扫描成功后,系统会自动把长辈的设备连接到当前账号。连接完成后,就能继续查看留言、动态和设备详情。
-
+
1. 让长辈打开手机上的「家人连接」页面。
2. 将镜头对准屏幕上的二维码,保持一两秒即可。
3. 连接成功后会自动跳转。
+
+
小提醒
+
+ 如果当前设备没有摄像头,或者浏览器没有拿到拍照权限,可以回到设备页,改用粘贴设备码的方式继续连接。
+
+
+
返回设备页
-
+
-
+
);
}
\ No newline at end of file
diff --git a/app/settings/page.tsx b/app/settings/page.tsx
index 0bd09fa..c93f817 100644
--- a/app/settings/page.tsx
+++ b/app/settings/page.tsx
@@ -15,7 +15,7 @@ export default async function SettingsPage() {
diff --git a/components/account-auth-form.tsx b/components/account-auth-form.tsx
index cb53d04..7c6a801 100644
--- a/components/account-auth-form.tsx
+++ b/components/account-auth-form.tsx
@@ -3,6 +3,8 @@
import { useRouter } from "next/navigation";
import { startTransition, useState } from "react";
+import { useNavigationProgress } from "@/components/navigation-progress";
+
type AccountAuthFormProps = {
redirectTo: string;
};
@@ -11,6 +13,7 @@ type AuthMode = "login" | "register";
export function AccountAuthForm({ redirectTo }: AccountAuthFormProps) {
const router = useRouter();
+ const { beginNavigationProgress } = useNavigationProgress();
const [mode, setMode] = useState("login");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
@@ -70,6 +73,7 @@ export function AccountAuthForm({ redirectTo }: AccountAuthFormProps) {
setNotice(mode === "login" ? "登录成功,正在进入……" : "账号已创建,正在进入……");
startTransition(() => {
+ beginNavigationProgress();
router.replace(payload?.redirectTo || redirectTo);
router.refresh();
});
diff --git a/components/dashboard-actions.tsx b/components/dashboard-actions.tsx
index 4da908b..3102dbe 100644
--- a/components/dashboard-actions.tsx
+++ b/components/dashboard-actions.tsx
@@ -2,10 +2,13 @@
import Link from "next/link";
import { useRouter } from "next/navigation";
-import { startTransition, useEffect, useState } from "react";
+import { startTransition, useRef, useState } from "react";
+
+import { useNavigationProgress } from "@/components/navigation-progress";
export function BindDeviceForm() {
const router = useRouter();
+ const { beginNavigationProgress } = useNavigationProgress();
const [rawCode, setRawCode] = useState("");
const [submitting, setSubmitting] = useState(false);
const [notice, setNotice] = useState(null);
@@ -22,6 +25,7 @@ export function BindDeviceForm() {
setNotice("正在前往绑定页面,请稍候……");
startTransition(() => {
+ beginNavigationProgress();
router.push(`/bind?deviceUuid=${encodeURIComponent(rawCode.trim())}`);
});
}
@@ -210,17 +214,15 @@ export function ManageDeviceForm({
deviceLabel,
}: ManageDeviceFormProps) {
const router = useRouter();
- const [alias, setAlias] = useState(initialAlias ?? "");
+ const { beginNavigationProgress } = useNavigationProgress();
+ const aliasInputRef = useRef(null);
const [saving, setSaving] = useState(false);
const [unbinding, setUnbinding] = useState(false);
const [notice, setNotice] = useState(null);
- useEffect(() => {
- setAlias(initialAlias ?? "");
- }, [initialAlias]);
-
async function handleSaveAlias(event: React.FormEvent) {
event.preventDefault();
+ const alias = aliasInputRef.current?.value ?? "";
setSaving(true);
setNotice("正在保存设备别名……");
@@ -244,7 +246,9 @@ export function ManageDeviceForm({
throw new Error(payload?.error || "设备别名保存失败。");
}
- setAlias(payload?.alias?.trim() || "");
+ if (aliasInputRef.current) {
+ aliasInputRef.current.value = payload?.alias?.trim() || "";
+ }
setNotice(
payload?.alias?.trim()
? `已将这台设备备注为“${payload.alias.trim()}”。\n`
@@ -290,6 +294,7 @@ export function ManageDeviceForm({
}
startTransition(() => {
+ beginNavigationProgress();
router.push("/devices");
router.refresh();
});
@@ -315,8 +320,9 @@ export function ManageDeviceForm({