feat: 版本时间戳统一 UTC+8; 适配全面屏安全区; 页面切换加过渡动画
Android Build & Publish / build-android (push) Successful in 22m27s
Docker Build and Push / build-image (push) Successful in 1m45s

- vite buildId 统一按 Asia/Shanghai 生成, CI(UTC) 与本地时区不再漂移
- index.html 加 viewport-fit=cover (env(safe-area-inset-*) 才生效)
- app-shell 顶部 +20px+safe inset, bottom-nav 底部 +20px+safe inset 防状态栏/手势条遮内容
- 页面跳转加淡入上滑动画 (Layout 内嵌页面按 pathname 重挂载, Landing/Login 同款)
This commit is contained in:
jif2.zhang
2026-09-16 10:21:07 +08:00
parent 5d9870fbb3
commit bb1c2718df
5 changed files with 32 additions and 9 deletions
+2 -2
View File
@@ -39,7 +39,7 @@ function RootGate() {
const effective = user ?? getStoredUser();
return <Navigate to={effective ? "/home" : "/login"} replace />;
}
return <Landing />;
return <div className="page-enter"><Landing /></div>;
}
function RouterGate() {
@@ -65,7 +65,7 @@ function RouterGate() {
return (
<Routes>
<Route path="/" element={<RootGate />} />
<Route path="/login" element={<Login />} />
<Route path="/login" element={<div className="page-enter"><Login /></div>} />
<Route element={<ProtectedRoute><Layout /></ProtectedRoute>}>
<Route path="/home" element={<Home />} />
<Route path="/closet" element={<Closet />} />
+11 -2
View File
@@ -1,3 +1,4 @@
import { useEffect, useRef } from "react";
import { Outlet, useNavigate, useLocation } from "react-router-dom";
import { useAppStore } from "../stores/app";
@@ -12,6 +13,12 @@ export default function Layout() {
const navigate = useNavigate();
const location = useLocation();
const user = useAppStore((s) => s.user);
const contentRef = useRef<HTMLDivElement>(null);
// 切换页面时回到顶部 + 触发过渡动画 (key 随路径重挂载)
useEffect(() => {
contentRef.current?.scrollTo({ top: 0 });
}, [location.pathname]);
const isActive = (path: string) =>
path === "/home" ? location.pathname === "/home" || location.pathname === "/" : location.pathname.startsWith(path);
@@ -23,8 +30,10 @@ export default function Layout() {
return (
<div className="app-shell">
<div className="app-content">
<Outlet />
<div className="app-content" ref={contentRef}>
<div key={location.pathname} className="page-enter">
<Outlet />
</div>
</div>
<nav className="bottom-nav">
<button className={"nav-item" + (isActive("/home") ? " active" : "")} onClick={() => navigate("/home")}>
+14 -1
View File
@@ -61,6 +61,8 @@ textarea {
height: 100%;
max-width: 500px;
margin: 0 auto;
/* 顶部避开状态栏/刘海, 再多让出一个行高 (edge-to-edge 时 env() 才生效) */
padding-top: calc(env(safe-area-inset-top) + 20px);
}
.app-content {
@@ -92,7 +94,8 @@ textarea {
background: var(--bg-card);
border-top: 1px solid var(--border);
padding: 6px 8px;
padding-bottom: calc(6px + env(safe-area-inset-bottom));
/* 底部避开手势条, 再多让出一个行高, 避免文字被遮挡 */
padding-bottom: calc(20px + env(safe-area-inset-bottom));
}
.nav-item {
@@ -270,4 +273,14 @@ textarea {
@keyframes toast-in {
from { opacity: 0; transform: translateX(-50%) translateY(-8px); }
to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
/* 页面切换动画 (Layout 内嵌页面与 Landing/Login 共用) */
.page-enter {
animation: page-in 0.26s ease forwards;
}
@keyframes page-in {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}