perf+ui: gzip (api/static precompressed), immutable attachment cache, responsive dialogs/header, safe-area + dynamic theme-color, mobile tuning
This commit is contained in:
@@ -15,9 +15,10 @@
|
||||
"title": "足迹 Footprints",
|
||||
"width": 1280,
|
||||
"height": 800,
|
||||
"minWidth": 960,
|
||||
"minHeight": 640,
|
||||
"center": true
|
||||
"minWidth": 420,
|
||||
"minHeight": 560,
|
||||
"center": true,
|
||||
"backgroundColor": "#f3f4f6"
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
|
||||
@@ -29,7 +29,7 @@ export function Header({ onMenu }: { onMenu?: () => void }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<header className="flex h-14 shrink-0 items-center gap-4 border-b border-line bg-surface px-5">
|
||||
<header className="flex h-14 shrink-0 items-center gap-2 border-b border-line bg-surface px-3 sm:gap-4 sm:px-5">
|
||||
<Button variant="ghost" size="icon" className="lg:hidden" onClick={onMenu} aria-label="打开导航">
|
||||
<Menu size={17} />
|
||||
</Button>
|
||||
@@ -39,7 +39,7 @@ export function Header({ onMenu }: { onMenu?: () => void }) {
|
||||
{meta.sub && <p className="truncate text-[11px] leading-tight text-ink-3">{meta.sub}</p>}
|
||||
</div>
|
||||
|
||||
<div className="relative ml-auto w-[280px]">
|
||||
<div className="relative ml-auto hidden w-[240px] md:block lg:w-[280px]">
|
||||
<Search size={14} className="pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-ink-3" />
|
||||
<Input
|
||||
className="pl-8"
|
||||
@@ -58,9 +58,9 @@ export function Header({ onMenu }: { onMenu?: () => void }) {
|
||||
{dark ? <Sun size={15} /> : <Moon size={15} />}
|
||||
</Button>
|
||||
|
||||
<Button variant="primary" onClick={() => navigate('/records?new=1')}>
|
||||
<Button variant="primary" onClick={() => navigate('/records?new=1')} aria-label="新建记录">
|
||||
<Plus size={14} />
|
||||
新建记录
|
||||
<span className="hidden sm:inline">新建记录</span>
|
||||
</Button>
|
||||
</header>
|
||||
);
|
||||
|
||||
@@ -21,10 +21,10 @@ export function Dialog({ open, onClose, title, width = 560, children, footer }:
|
||||
if (!open) return null;
|
||||
|
||||
return createPortal(
|
||||
<div className="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto p-6 pt-[8vh]">
|
||||
<div className="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto p-3 pt-[6vh] sm:p-6 sm:pt-[8vh]">
|
||||
<div className="fixed inset-0 bg-black/45" onClick={onClose} />
|
||||
<div
|
||||
className="relative w-full rounded-lg border border-line bg-surface shadow-pop"
|
||||
className="animate-in relative w-full rounded-lg border border-line bg-surface shadow-pop"
|
||||
style={{ maxWidth: width }}
|
||||
role="dialog"
|
||||
>
|
||||
@@ -34,9 +34,9 @@ export function Dialog({ open, onClose, title, width = 560, children, footer }:
|
||||
<X size={15} />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="px-4 py-4 max-h-[64vh] overflow-y-auto">{children}</div>
|
||||
<div className="max-h-[70vh] overflow-y-auto px-3 py-3 sm:px-4 sm:py-4">{children}</div>
|
||||
{footer && (
|
||||
<div className="flex items-center justify-end gap-2 border-t border-line px-4 h-14">
|
||||
<div className="flex flex-wrap items-center justify-end gap-2 border-t border-line px-3 py-2.5 sm:h-14 sm:flex-nowrap sm:px-4 sm:py-0">
|
||||
{footer}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -17,6 +17,14 @@ if (saved === 'dark' || (!saved && window.matchMedia('(prefers-color-scheme: dar
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
|
||||
// 状态栏/标题栏颜色跟随主题(亮暗切换实时同步)
|
||||
function syncThemeColor() {
|
||||
const bg = getComputedStyle(document.documentElement).getPropertyValue('--bg').trim();
|
||||
if (bg) document.querySelector('meta[name="theme-color"]')?.setAttribute('content', bg);
|
||||
}
|
||||
syncThemeColor();
|
||||
window.addEventListener('fp-theme-change', syncThemeColor);
|
||||
|
||||
// PWA:仅生产构建且非桌面壳时注册(桌面端走 Tauri,无需 SW)
|
||||
if ('serviceWorker' in navigator && import.meta.env.PROD && !('__TAURI_INTERNALS__' in window)) {
|
||||
window.addEventListener('load', () => {
|
||||
|
||||
@@ -80,6 +80,17 @@
|
||||
|
||||
html, body, #root { height: 100%; }
|
||||
|
||||
/* 移动端适配:禁止横向溢出 / 去点按高亮 / 双击不缩放 / 刘海安全区 */
|
||||
html, body { overflow-x: clip; }
|
||||
body {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
touch-action: manipulation;
|
||||
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
|
||||
}
|
||||
@media (pointer: coarse) {
|
||||
button, [role='button'], a { min-height: 36px; }
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--text-1);
|
||||
@@ -95,6 +106,11 @@ body {
|
||||
|
||||
h1, h2, h3 { letter-spacing: -0.022em; text-wrap: balance; }
|
||||
|
||||
/* 小屏:分区标题与卡片间距收紧 */
|
||||
@media (max-width: 640px) {
|
||||
.hover-lift:hover { transform: none; }
|
||||
}
|
||||
|
||||
.num { font-variant-numeric: tabular-nums lining-nums; font-feature-settings: 'tnum' 1, 'lnum' 1; }
|
||||
|
||||
::selection { background: color-mix(in srgb, var(--brand) 18%, transparent); }
|
||||
|
||||
Reference in New Issue
Block a user