[阶段10] 前端以 Framework7 重建,采用 iOS 原生形态

按要求废弃手写外壳,改用 Framework7 React(theme=ios)。参照 PeakWatch
的信息架构与卡片语言。

保留(这些是资产,不该重来):
- 数据层 services/api.ts、聚合 lib/aggregate.ts、参考区间 lib/ranges.ts
- 图表组件 Chart / Ring / Sparkline / BandBar / MetricCard / MetricStrip
- 经校验的配色令牌(色盲安全 + 对比度,浅深两档)

替换:
- 路由与外壳交给 F7:五个 Tab 各自独立导航栈,推入详情页不影响其他 Tab
- 页面转场、橡皮筋滚动、大标题折叠、半透明栏 —— 这些正是换框架的理由,
  手写做不像
- 底部标签栏改用 F7 Toolbar,触控目标与安全区由框架处理

配色接入:
- 新增 f7theme.css 把我们的令牌映射到 F7 的 CSS 变量,让它的导航栏/
  列表/面板与我们的图表同属一套设计,而不是两种视觉打架
- F7 的深色靠 .dark 类,我们的靠 data-theme,两者在 App 里同步切换

fix: 图标显示为原始名称(squ/hea/cale…)
- iconIos/iconMd 引用的是 framework7-icons 字体,没装就只会渲染出名字

其他:
- tsconfig moduleResolution 改为 bundler —— F7 用 exports 映射,
  node 解析方式找不到它的类型
- 登录页不套 Tab 外壳,未登录时不该出现导航

桌面与手机都要好看:内容在宽屏收进 1100px 居中列并加密卡片列数,
窄屏走底部标签栏;两档都已实机核对。

bundle 190KB -> 399KB,是换取原生手感的代价。

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
ericwyuan
2026-08-23 23:38:21 +08:00
parent 757afdc941
commit 7ab150537d
37 changed files with 4266 additions and 356 deletions

98
package-lock.json generated
View File

@@ -20,6 +20,9 @@
"dependencies": {
"axios": "^1.5.0",
"date-fns": "^2.30.0",
"framework7": "^9.1.2",
"framework7-icons": "^5.0.5",
"framework7-react": "^9.1.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.14.2",
@@ -7664,6 +7667,21 @@
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/dom7": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/dom7/-/dom7-4.0.6.tgz",
"integrity": "sha512-emjdpPLhpNubapLFdjNL9tP06Sr+GZkrIHEXLWvOGsytACUrkbeIdjO5g77m00BrHTznnlcNqgmn7pCN192TBA==",
"license": "MIT",
"dependencies": {
"ssr-window": "^4.0.0"
}
},
"node_modules/dom7/node_modules/ssr-window": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz",
"integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==",
"license": "MIT"
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
@@ -9448,6 +9466,49 @@
"url": "https://github.com/sponsors/rawify"
}
},
"node_modules/framework7": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/framework7/-/framework7-9.1.2.tgz",
"integrity": "sha512-XXvIeiRri3imFiz4wZZjBgr0b7mqVosFX1rRABM86iUyaWqj1GQEuQsKzaGXFw1nzEuiX7+r39vtF7Fq5bUiJA==",
"license": "MIT",
"dependencies": {
"dom7": "^4.0.6",
"htm": "^3.1.1",
"path-to-regexp": "^6.3.0",
"skeleton-elements": "^4.0.1",
"ssr-window": "^5.0.1",
"swiper": "^12.1.2"
},
"funding": {
"type": "patreon",
"url": "https://www.patreon.com/framework7"
}
},
"node_modules/framework7-icons": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/framework7-icons/-/framework7-icons-5.0.5.tgz",
"integrity": "sha512-bvHMLyujV9TFuudehd3ORZ/EvNp19Ir3ckVzYAOf3MkLymHba/9oHLsgopCh0x5UsrYZUpkrE+fd7ggj5y4wRw==",
"license": "MIT",
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/framework7-react": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/framework7-react/-/framework7-react-9.1.2.tgz",
"integrity": "sha512-uKLA29qObVZfG1OPtnLUdkxtnkqlqVJAh6GybIfE0WWGgLgAYb9X43WCeTGznRqDjfgdPVHlVesBDDBrfZqs3g==",
"license": "MIT",
"funding": {
"type": "patreon",
"url": "https://www.patreon.com/framework7"
}
},
"node_modules/framework7/node_modules/path-to-regexp": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
"license": "MIT"
},
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -10012,6 +10073,12 @@
"safe-buffer": "~5.1.0"
}
},
"node_modules/htm": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/htm/-/htm-3.1.1.tgz",
"integrity": "sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==",
"license": "Apache-2.0"
},
"node_modules/html-encoding-sniffer": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
@@ -16647,6 +16714,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/skeleton-elements": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/skeleton-elements/-/skeleton-elements-4.0.1.tgz",
"integrity": "sha512-T7YSF/Vu/raUcM6v3HiE4VSY/OvrNflg8Dur3Zza6VVJkq4slxm4pJRpGLNhoOfblIPZLQKh1cu7ADKveyqm/Q==",
"license": "MIT"
},
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -16844,6 +16917,12 @@
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/ssr-window": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-5.0.1.tgz",
"integrity": "sha512-WVXlhQsm54HC+FnJfEbccEgNF7mKXtnFUB8Xn7rx2dsWHOlBdqezdX88Vjh6pVGaa0ZvL+PoSu7rEcBuNmxt6g==",
"license": "MIT"
},
"node_modules/stable": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
@@ -17449,6 +17528,25 @@
"node": ">=4"
}
},
"node_modules/swiper": {
"version": "12.2.0",
"resolved": "https://registry.npmjs.org/swiper/-/swiper-12.2.0.tgz",
"integrity": "sha512-K8uXsBZU6ME97Ia3xbBge8IRCnR1lOmIILzvY/jGVic7dSTQ530s3uO8RvXbPUtkkXLWIwmZLRPbtDxRWVAFdg==",
"funding": [
{
"type": "custom",
"url": "https://sponsors.nolimits4web.com"
},
{
"type": "github",
"url": "https://github.com/sponsors/nolimits4web"
}
],
"license": "MIT",
"engines": {
"node": ">= 4.7.0"
}
},
"node_modules/symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",