feat: 完成 4 个TabBar 页面初版样式修改
@@ -12,13 +12,15 @@
|
|||||||
|
|
||||||
### 1.1 核心原则
|
### 1.1 核心原则
|
||||||
|
|
||||||
|
|
||||||
| 原则 | 说明 |
|
| 原则 | 说明 |
|
||||||
| ------------ | ------------------------------------------------------------------------------------------------- |
|
| -------- | ------------------------------------------------------- |
|
||||||
| **成本优先** | 现阶段用云开发免费额度控制成本;**2026-09-15** 前复盘是否续用或迁移自建;核心逻辑仍保持前端执行 |
|
| **成本优先** | 现阶段用云开发免费额度控制成本;**2026-09-15** 前复盘是否续用或迁移自建;核心逻辑仍保持前端执行 |
|
||||||
| **渐进增强** | 先小程序跑通,后续再扩展 PC Web,不为未来过度设计 |
|
| **渐进增强** | 先小程序跑通,后续再扩展 PC Web,不为未来过度设计 |
|
||||||
| **前端为主** | Canvas 渲染、随机生成、PNG 导出等核心逻辑保持前端执行,零服务器成本;后端仅做必要的数据存储和服务 |
|
| **前端为主** | Canvas 渲染、随机生成、PNG 导出等核心逻辑保持前端执行,零服务器成本;后端仅做必要的数据存储和服务 |
|
||||||
| **可迁移** | 核心绘制逻辑与平台 API 解耦,为将来迁移 Web 做准备 |
|
| **可迁移** | 核心绘制逻辑与平台 API 解耦,为将来迁移 Web 做准备 |
|
||||||
|
|
||||||
|
|
||||||
### 1.2 后端方案决策
|
### 1.2 后端方案决策
|
||||||
|
|
||||||
#### 需要后端的场景 vs 不需要的场景
|
#### 需要后端的场景 vs 不需要的场景
|
||||||
@@ -51,8 +53,9 @@
|
|||||||
|
|
||||||
#### 方案对比与选择
|
#### 方案对比与选择
|
||||||
|
|
||||||
|
|
||||||
| 维度 | 微信云开发 | 自有云服务器(NestJS) | 现阶段决策(至 2026-09-15) |
|
| 维度 | 微信云开发 | 自有云服务器(NestJS) | 现阶段决策(至 2026-09-15) |
|
||||||
| ----------- | ----------------------------- | --------------------------- | --------------------------- |
|
| --------- | ------------------ | ------------------ | ------------------- |
|
||||||
| 接入成本 | ⭐ 极低(原生集成) | ⭐⭐ 需搭建部署(~3-5天) | **云开发 ✅** |
|
| 接入成本 | ⭐ 极低(原生集成) | ⭐⭐ 需搭建部署(~3-5天) | **云开发 ✅** |
|
||||||
| 运维成本 | ⭐ 免运维 | ⭐⭐ 需简单维护(PM2 守护) | **云开发 ✅** |
|
| 运维成本 | ⭐ 免运维 | ⭐⭐ 需简单维护(PM2 守护) | **云开发 ✅** |
|
||||||
| 费用 | 免费额度内 ¥0;超出按套餐计费 | 已有服务器可零增量 | **云开发(阶段内)✅** |
|
| 费用 | 免费额度内 ¥0;超出按套餐计费 | 已有服务器可零增量 | **云开发(阶段内)✅** |
|
||||||
@@ -61,6 +64,7 @@
|
|||||||
| 灵活性 | ⭐⭐ 受限于云开发 SDK | ⭐ 完全自由 | 到期后按需评估 |
|
| 灵活性 | ⭐⭐ 受限于云开发 SDK | ⭐ 完全自由 | 到期后按需评估 |
|
||||||
| 数据迁移 | ⭐⭐ 可导出 | ⭐ 标准 MySQL | 到期后按需评估 |
|
| 数据迁移 | ⭐⭐ 可导出 | ⭐ 标准 MySQL | 到期后按需评估 |
|
||||||
|
|
||||||
|
|
||||||
**最终决策(分阶段)**
|
**最终决策(分阶段)**
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -162,8 +166,9 @@ miniprogram/
|
|||||||
|
|
||||||
**问题分析:**
|
**问题分析:**
|
||||||
|
|
||||||
|
|
||||||
| 问题 | 详情 |
|
| 问题 | 详情 |
|
||||||
| -------------- | ------------------------------------------------------------------- |
|
| ---------- | ------------------------------------------------------------- |
|
||||||
| Mixin 模式笨重 | `pageMixin` 通过对象展开合并,无类型安全,难以追踪数据流 |
|
| Mixin 模式笨重 | `pageMixin` 通过对象展开合并,无类型安全,难以追踪数据流 |
|
||||||
| Draw 服务分散 | 每个分包下各有 `shared/service/`,大量重复的绘制工具方法 |
|
| Draw 服务分散 | 每个分包下各有 `shared/service/`,大量重复的绘制工具方法 |
|
||||||
| 平台耦合严重 | Draw 服务直接使用 `wx.createImage`、`canvas.createImage` 等 API |
|
| 平台耦合严重 | Draw 服务直接使用 `wx.createImage`、`canvas.createImage` 等 API |
|
||||||
@@ -171,6 +176,7 @@ miniprogram/
|
|||||||
| 无共享核心 | 数据模型、生成算法与 UI 逻辑混在一起,无法跨平台复用 |
|
| 无共享核心 | 数据模型、生成算法与 UI 逻辑混在一起,无法跨平台复用 |
|
||||||
| 状态管理原始 | 纯 `setData`,无统一的状态管理方案 |
|
| 状态管理原始 | 纯 `setData`,无统一的状态管理方案 |
|
||||||
|
|
||||||
|
|
||||||
### 3.2 目标架构
|
### 3.2 目标架构
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -958,22 +964,26 @@ createPage({
|
|||||||
|
|
||||||
### 6.1 现阶段:微信云开发(摘要)
|
### 6.1 现阶段:微信云开发(摘要)
|
||||||
|
|
||||||
|
|
||||||
| 组件 | 技术 | 说明 |
|
| 组件 | 技术 | 说明 |
|
||||||
| ---------- | ---------------------------- | -------------------------------------- |
|
| ----- | ---------------------------- | ----------------------------------- |
|
||||||
| 数据 | 云数据库(文档型) | worksheets / categories / users 等集合 |
|
| 数据 | 云数据库(文档型) | worksheets / categories / users 等集合 |
|
||||||
| 文件 | 云存储(COS) | 预览图、涂色线稿、字体等 |
|
| 文件 | 云存储(COS) | 预览图、涂色线稿、字体等 |
|
||||||
| 逻辑 | 云函数(Node.js) | 统一入口路由、业务 action |
|
| 逻辑 | 云函数(Node.js) | 统一入口路由、业务 action |
|
||||||
| 小程序接入 | `wx.cloud` + `cloud-adapter` | 与业务服务层解耦,便于日后替换为 HTTP |
|
| 小程序接入 | `wx.cloud` + `cloud-adapter` | 与业务服务层解耦,便于日后替换为 HTTP |
|
||||||
|
|
||||||
|
|
||||||
### 6.2 远期可选:自建 NestJS(摘要)
|
### 6.2 远期可选:自建 NestJS(摘要)
|
||||||
|
|
||||||
|
|
||||||
| 组件 | 技术 | 说明 |
|
| 组件 | 技术 | 说明 |
|
||||||
| ---- | ----------------------- | --------------------------- |
|
| --- | --------------------- | ---------------- |
|
||||||
| 应用 | NestJS + TypeScript | RESTful API,多端统一 |
|
| 应用 | NestJS + TypeScript | RESTful API,多端统一 |
|
||||||
| 数据 | MySQL 8.0 + Prisma | 关系型存储与迁移 |
|
| 数据 | MySQL 8.0 + Prisma | 关系型存储与迁移 |
|
||||||
| 文件 | 本地磁盘 + Nginx | 静态素材 URL 由自有域名提供 |
|
| 文件 | 本地磁盘 + Nginx | 静态素材 URL 由自有域名提供 |
|
||||||
| 鉴权 | 微信 code2Session + JWT | 小程序与 Web 可共用逻辑 |
|
| 鉴权 | 微信 code2Session + JWT | 小程序与 Web 可共用逻辑 |
|
||||||
|
|
||||||
|
|
||||||
(接口路径、表结构、部署步骤等以 [后端部署方案](./后端部署方案.md) 为准,此处不重复。)
|
(接口路径、表结构、部署步骤等以 [后端部署方案](./后端部署方案.md) 为准,此处不重复。)
|
||||||
|
|
||||||
### 6.3 数据加载策略(两阶段一致的产品策略)
|
### 6.3 数据加载策略(两阶段一致的产品策略)
|
||||||
@@ -1180,8 +1190,9 @@ PDF 导出方案(远期增值功能,会员专属):
|
|||||||
|
|
||||||
## 十一、技术风险与应对
|
## 十一、技术风险与应对
|
||||||
|
|
||||||
|
|
||||||
| 风险 | 影响 | 应对方案 |
|
| 风险 | 影响 | 应对方案 |
|
||||||
| -------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------- |
|
| ------------- | --------- | ----------------------------------------------------------------------- |
|
||||||
| 云开发免费额度不足 | 功能受限或需付费 | ① 优化查询与缓存 ② 控制云函数调用 ③ **2026-09-15 前**复盘是否升级套餐或迁移 [后端部署方案](./后端部署方案.md) |
|
| 云开发免费额度不足 | 功能受限或需付费 | ① 优化查询与缓存 ② 控制云函数调用 ③ **2026-09-15 前**复盘是否升级套餐或迁移 [后端部署方案](./后端部署方案.md) |
|
||||||
| 服务器宕机(迁移自建后) | 后端不可用 | ① PM2 自动重启 ② 前端兜底数据 ③ 定期备份数据库 |
|
| 服务器宕机(迁移自建后) | 后端不可用 | ① PM2 自动重启 ② 前端兜底数据 ③ 定期备份数据库 |
|
||||||
| Canvas 兼容性 | 低端机渲染异常 | ① 使用 Canvas 2D(已采用)② 控制单次绘制复杂度 ③ 降级方案 |
|
| Canvas 兼容性 | 低端机渲染异常 | ① 使用 Canvas 2D(已采用)② 控制单次绘制复杂度 ③ 降级方案 |
|
||||||
@@ -1190,22 +1201,24 @@ PDF 导出方案(远期增值功能,会员专属):
|
|||||||
| 跨平台迁移成本 | Web 端重复开发 | ① core/ 层保持平台无关 ② 适配器隔离差异(详见 [PC-Web端技术预案](./PC-Web端技术预案.md)) |
|
| 跨平台迁移成本 | Web 端重复开发 | ① core/ 层保持平台无关 ② 适配器隔离差异(详见 [PC-Web端技术预案](./PC-Web端技术预案.md)) |
|
||||||
| 带宽与加载(迁移自建远期) | 素材加载慢 | ① 图片压缩 ② 长缓存 ③ 可接入 CDN |
|
| 带宽与加载(迁移自建远期) | 素材加载慢 | ① 图片压缩 ② 长缓存 ③ 可接入 CDN |
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 附录 A:现有代码与目标架构映射
|
## 附录 A:现有代码与目标架构映射
|
||||||
|
|
||||||
|
|
||||||
| 现有文件 | 目标位置 | 迁移动作 |
|
| 现有文件 | 目标位置 | 迁移动作 |
|
||||||
| -------------------------------- | -------------------------------------- | ------------------------------------------------ |
|
| -------------------------------- | ------------------------------------- | --------------------------------------- |
|
||||||
| `constants/mathFunctions.ts` | `core/data/worksheets.ts` | 合并,增加字段 |
|
| `constants/mathFunctions.ts` | `core/data/worksheets.ts` | 合并,增加字段 |
|
||||||
| `constants/focusFunctions.ts` | `core/data/worksheets.ts` | 合并,增加字段 |
|
| `constants/focusFunctions.ts` | `core/data/worksheets.ts` | 合并,增加字段 |
|
||||||
| `constants/words.ts` | `core/data/words.ts` | 移动 |
|
| `constants/words.ts` | `core/data/words.ts` | 移动 |
|
||||||
| `constants/colors.ts` | `core/data/colors.ts` | 移动 |
|
| `constants/colors.ts` | `core/data/colors.ts` | 移动 |
|
||||||
| `constants/shapes.ts` | `core/data/shapes.ts` | 移动 |
|
| `constants/shapes.ts` | `core/data/shapes.ts` | 移动 |
|
||||||
| `service/baseDraw.ts` | `core/draw/base-draw.ts` | 重构,去除 wx.\* 依赖 |
|
| `service/baseDraw.ts` | `core/draw/base-draw.ts` | 重构,去除 wx. 依赖 |
|
||||||
| `service/wordDrawService.ts` | `core/draw/chinese-draw/word-draw.ts` | 移动,去除 wx.\* |
|
| `service/wordDrawService.ts` | `core/draw/chinese-draw/word-draw.ts` | 移动,去除 wx. |
|
||||||
| `service/drawServiceFactory.ts` | `core/draw/draw-factory.ts` | 扩展 |
|
| `service/drawServiceFactory.ts` | `core/draw/draw-factory.ts` | 扩展 |
|
||||||
| `mathPages/shared/service/*.ts` | `core/draw/legacy/math-draw/*.ts` | 移入 legacy,去除 wx.\*,逐步迁移到模板引擎 |
|
| `mathPages/shared/service/*.ts` | `core/draw/legacy/math-draw/*.ts` | 移入 legacy,去除 wx.,逐步迁移到模板引擎 |
|
||||||
| `focusPages/shared/service/*.ts` | `core/draw/legacy/focus-draw/*.ts` | 移入 legacy,去除 wx.\*,逐步迁移到模板引擎 |
|
| `focusPages/shared/service/*.ts` | `core/draw/legacy/focus-draw/*.ts` | 移入 legacy,去除 wx.,逐步迁移到模板引擎 |
|
||||||
| `base/pageMixin.ts` | `services/print-service.ts` + 页面代码 | 拆分职责 |
|
| `base/pageMixin.ts` | `services/print-service.ts` + 页面代码 | 拆分职责 |
|
||||||
| `base/callCloud.ts` | `platform/cloud-adapter.ts` | 封装 wx.cloud;迁移 NestJS 后再考虑 http-adapter |
|
| `base/callCloud.ts` | `platform/cloud-adapter.ts` | 封装 wx.cloud;迁移 NestJS 后再考虑 http-adapter |
|
||||||
| `utils/saveImage.ts` | `platform/canvas-adapter.ts` | 合并到适配器 |
|
| `utils/saveImage.ts` | `platform/canvas-adapter.ts` | 合并到适配器 |
|
||||||
@@ -1213,13 +1226,17 @@ PDF 导出方案(远期增值功能,会员专属):
|
|||||||
| `utils/tracker.ts` | `services/stats-service.ts` | 整合 |
|
| `utils/tracker.ts` | `services/stats-service.ts` | 整合 |
|
||||||
| `config/config.ts` | `core/models/print-config.ts` | 类型化 |
|
| `config/config.ts` | `core/models/print-config.ts` | 类型化 |
|
||||||
|
|
||||||
|
|
||||||
## 附录 B:技术选型决策记录
|
## 附录 B:技术选型决策记录
|
||||||
|
|
||||||
|
|
||||||
| 决策点 | 选项 | 决策 | 理由 |
|
| 决策点 | 选项 | 决策 | 理由 |
|
||||||
| --------- | ---------------------------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
| -------- | -------------------------- | ------------------------ | -------------------------------------------------------------------------- |
|
||||||
| 跨端框架 | Taro / uni-app / 原生 | **原生** | 项目已用原生开发,迁移成本高;Taro 等框架对 Canvas 2D 支持有限;core/ 层抽取足以实现代码复用 |
|
| 跨端框架 | Taro / uni-app / 原生 | **原生** | 项目已用原生开发,迁移成本高;Taro 等框架对 Canvas 2D 支持有限;core/ 层抽取足以实现代码复用 |
|
||||||
| 状态管理 | MobX / 自定义 / 原生 setData | **轻量自定义** | 小程序场景简单,不需要 Redux 级方案;页面级 setData + 全局 Store 够用 |
|
| 状态管理 | MobX / 自定义 / 原生 setData | **轻量自定义** | 小程序场景简单,不需要 Redux 级方案;页面级 setData + 全局 Store 够用 |
|
||||||
| UI 组件库 | Vant / 自研 | **Vant + 自定义组件** | 已用 Vant,保持;业务组件自研 |
|
| UI 组件库 | Vant / 自研 | **Vant + 自定义组件** | 已用 Vant,保持;业务组件自研 |
|
||||||
| 后端方案 | 云开发 / 自有云服务器 | **现阶段云开发(至 2026-09-15)** | 详见 [小程序云开发方案](./小程序云开发方案.md);到期后可选迁移 [后端部署方案](./后端部署方案.md)(NestJS) |
|
| 后端方案 | 云开发 / 自有云服务器 | **现阶段云开发(至 2026-09-15)** | 详见 [小程序云开发方案](./小程序云开发方案.md);到期后可选迁移 [后端部署方案](./后端部署方案.md)(NestJS) |
|
||||||
| 导出方案 | PNG 保存相册 / PDF | **PNG 为主,PDF 为增值** | PNG 保存到相册是手机端最短路径(用户教育成本低、零服务器开销);PDF 作为远期会员增值功能,服务端 pdfkit 合并,Web 用 jsPDF |
|
| 导出方案 | PNG 保存相册 / PDF | **PNG 为主,PDF 为增值** | PNG 保存到相册是手机端最短路径(用户教育成本低、零服务器开销);PDF 作为远期会员增值功能,服务端 pdfkit 合并,Web 用 jsPDF |
|
||||||
| Monorepo | pnpm workspace / Turborepo | **暂不采用** | 当前只有小程序,过早引入增加复杂度;core/ 作为目录组织,未来再拆包 |
|
| Monorepo | pnpm workspace / Turborepo | **暂不采用** | 当前只有小程序,过早引入增加复杂度;core/ 作为目录组织,未来再拆包 |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,8 @@
|
|||||||
"pages/age/age",
|
"pages/age/age",
|
||||||
"pages/favorites/favorites",
|
"pages/favorites/favorites",
|
||||||
"pages/profile/profile",
|
"pages/profile/profile",
|
||||||
"pages/category/category",
|
|
||||||
"pages/guide/guide",
|
"pages/guide/guide",
|
||||||
"pages/index/index",
|
"pages/index/index"
|
||||||
"pages/copyBook/copyBook",
|
|
||||||
"pages/mathIndex/mathIndex",
|
|
||||||
"pages/focusIndex/focusIndex",
|
|
||||||
"pages/debug/debug"
|
|
||||||
],
|
],
|
||||||
"subPackages": [
|
"subPackages": [
|
||||||
{
|
{
|
||||||
@@ -59,10 +54,6 @@
|
|||||||
"pages/home/home": {
|
"pages/home/home": {
|
||||||
"network": "all",
|
"network": "all",
|
||||||
"packages": ["mathPages", "focusPages"]
|
"packages": ["mathPages", "focusPages"]
|
||||||
},
|
|
||||||
"pages/category/category": {
|
|
||||||
"network": "all",
|
|
||||||
"packages": ["mathPages", "focusPages"]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"window": {},
|
"window": {},
|
||||||
@@ -85,33 +76,33 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
"color": "#999999",
|
"color": "#322e25",
|
||||||
"selectedColor": "#FFD709",
|
"selectedColor": "#322e25",
|
||||||
"backgroundColor": "#F8F0E0",
|
"backgroundColor": "#F8F0E0",
|
||||||
"borderStyle": "white",
|
"borderStyle": "white",
|
||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"pagePath": "pages/home/home",
|
"pagePath": "pages/home/home",
|
||||||
"iconPath": "assets/tabBar/icon-home.png",
|
"iconPath": "assets/tabBar/home.png",
|
||||||
"selectedIconPath": "assets/tabBar/icon-home-active.png",
|
"selectedIconPath": "assets/tabBar/home-active.png",
|
||||||
"text": "发现"
|
"text": "发现"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/age/age",
|
"pagePath": "pages/age/age",
|
||||||
"iconPath": "assets/tabBar/icon-age.png",
|
"iconPath": "assets/tabBar/age.png",
|
||||||
"selectedIconPath": "assets/tabBar/icon-age-active.png",
|
"selectedIconPath": "assets/tabBar/age-active.png",
|
||||||
"text": "分龄"
|
"text": "分龄"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/favorites/favorites",
|
"pagePath": "pages/favorites/favorites",
|
||||||
"iconPath": "assets/tabBar/icon-fav.png",
|
"iconPath": "assets/tabBar/favorites.png",
|
||||||
"selectedIconPath": "assets/tabBar/icon-fav-active.png",
|
"selectedIconPath": "assets/tabBar/favorites-active.png",
|
||||||
"text": "收藏"
|
"text": "收藏"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/profile/profile",
|
"pagePath": "pages/profile/profile",
|
||||||
"iconPath": "assets/tabBar/icon-profile.png",
|
"iconPath": "assets/tabBar/profile.png",
|
||||||
"selectedIconPath": "assets/tabBar/icon-profile-active.png",
|
"selectedIconPath": "assets/tabBar/profile-active.png",
|
||||||
"text": "我的"
|
"text": "我的"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 191 B |
|
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 191 B |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 219 B After Width: | Height: | Size: 219 B |
|
Before Width: | Height: | Size: 219 B After Width: | Height: | Size: 219 B |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 238 B |
|
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 238 B |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"navigationBarTitleText": "分龄推荐",
|
"navigationStyle": "custom",
|
||||||
"navigationBarTextStyle": "black",
|
"navigationBarTextStyle": "black",
|
||||||
"navigationBarBackgroundColor": "#ffffff",
|
"navigationBarBackgroundColor": "#FEF6E7",
|
||||||
"backgroundColor": "#F5F5F5",
|
"backgroundColor": "#FEF6E7",
|
||||||
"enablePullDownRefresh": false,
|
"enablePullDownRefresh": false,
|
||||||
"usingComponents": {}
|
"usingComponents": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,108 +1,412 @@
|
|||||||
|
@import '../../style/theme3.less';
|
||||||
|
|
||||||
|
@age-tab-gap: 32rpx;
|
||||||
|
@age-tab-w: 226rpx;
|
||||||
|
@age-tab-h: 156rpx;
|
||||||
|
@age-badge-current: #005e17;
|
||||||
|
/* 选中态 box-shadow + scale 外溢;内层留白 + 外层负 margin 抵消,整体上下不占更多间距 */
|
||||||
|
@age-tab-shadow-bleed-t: 36rpx;
|
||||||
|
@age-tab-shadow-bleed-b: 52rpx;
|
||||||
|
|
||||||
.age-page {
|
.age-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #f5f5f5;
|
background: @bg-page;
|
||||||
padding-bottom: 48rpx;
|
padding-bottom: calc(48rpx + env(safe-area-inset-bottom));
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-hero {
|
.age-nav {
|
||||||
background: #fff;
|
position: fixed;
|
||||||
padding: 40rpx 32rpx 36rpx;
|
top: 0;
|
||||||
margin-bottom: 24rpx;
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background: fade(@bg-header, 85%);
|
||||||
|
backdrop-filter: blur(40rpx);
|
||||||
|
-webkit-backdrop-filter: blur(40rpx);
|
||||||
|
box-shadow: 0 2rpx 12rpx rgba(50, 46, 37, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-hero__title {
|
.age-nav__inner {
|
||||||
display: block;
|
height: @nav-inner-height;
|
||||||
font-size: 44rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
color: rgba(0, 0, 0, 0.88);
|
|
||||||
margin-bottom: 12rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.age-hero__subtitle {
|
|
||||||
display: block;
|
|
||||||
font-size: 26rpx;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.age-grid {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
align-items: center;
|
||||||
gap: 24rpx;
|
justify-content: flex-start;
|
||||||
padding: 0 24rpx;
|
padding: 0 @page-padding-x;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-card {
|
.age-nav__title {
|
||||||
width: calc((100% - 24rpx) / 2);
|
font-size: @fs-nav-title;
|
||||||
background: #fff;
|
font-weight: @fw-nav-title;
|
||||||
border-radius: 32rpx;
|
color: @color-nav-title;
|
||||||
|
letter-spacing: @ls-nav-title;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-body {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 横向年龄 Tab — Stitch 为你推荐版 */
|
||||||
|
.age-tab-scroll {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: @section-gap-sm 0 @section-gap-xs;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-top: -@age-tab-shadow-bleed-t;
|
||||||
|
margin-bottom: -@age-tab-shadow-bleed-b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-tab-scroll__inner {
|
||||||
|
padding: @age-tab-shadow-bleed-t 0 @age-tab-shadow-bleed-b;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-tab-row {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: @age-tab-gap;
|
||||||
|
padding: 0 @page-padding-x;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-tab {
|
||||||
|
position: relative;
|
||||||
|
width: @age-tab-w;
|
||||||
|
height: @age-tab-h;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 24rpx 16rpx;
|
||||||
|
border-radius: @radius-lg;
|
||||||
|
background: @bg-muted;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
border: 2rpx solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-tab--active {
|
||||||
|
background: @brand;
|
||||||
|
border-color: @bg-white;
|
||||||
|
box-shadow: 0 16rpx 48rpx rgba(255, 215, 9, 0.38);
|
||||||
|
transform: scale(1.05);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-tab__current {
|
||||||
|
position: absolute;
|
||||||
|
top: -8rpx;
|
||||||
|
right: -8rpx;
|
||||||
|
padding: 4rpx 14rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
font-size: 18rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-white;
|
||||||
|
background: @age-badge-current;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-tab__range {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
color: @text-title;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-tab--active .age-tab__range {
|
||||||
|
color: @text-selected-btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-tab__sub {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: @text-light;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-tab--active .age-tab__sub {
|
||||||
|
color: fade(@text-selected-btn, 85%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-panel {
|
||||||
|
margin: 0 @page-padding-x;
|
||||||
|
background: @bg-white;
|
||||||
|
border-radius: @radius-lg;
|
||||||
|
border: 1rpx solid fade(@bg-gray, 90%);
|
||||||
|
box-shadow: @shadow;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.06);
|
}
|
||||||
|
|
||||||
|
.age-goal-panel {
|
||||||
|
padding: 36rpx @page-padding-x 40rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-card__art {
|
.age-goal-head {
|
||||||
height: 160rpx;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12rpx;
|
||||||
|
margin-bottom: @section-gap-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-goal-head__icon-wrap {
|
||||||
|
width: 56rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: @brand-light;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-card__emoji {
|
.age-goal-head__icon {
|
||||||
font-size: 72rpx;
|
font-size: 28rpx;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-card__body {
|
.age-goal-head__title {
|
||||||
padding: 24rpx 24rpx 28rpx;
|
font-size: @fs-section-head-title;
|
||||||
|
font-weight: 800;
|
||||||
|
color: @text-selected-btn;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-card__label {
|
.age-goal-list {
|
||||||
display: block;
|
display: flex;
|
||||||
font-size: 32rpx;
|
flex-direction: column;
|
||||||
font-weight: 700;
|
gap: 24rpx;
|
||||||
color: rgba(0, 0, 0, 0.88);
|
|
||||||
margin-bottom: 8rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-card__desc {
|
.age-goal-item {
|
||||||
display: block;
|
display: flex;
|
||||||
font-size: 24rpx;
|
flex-direction: column;
|
||||||
color: #999;
|
align-items: flex-start;
|
||||||
margin-bottom: 12rpx;
|
gap: 12rpx;
|
||||||
|
padding: 28rpx @page-padding-inner-x;
|
||||||
|
border-radius: @radius;
|
||||||
|
background: @bg-header;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1rpx solid rgba(229, 220, 201, 0.55);
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-card__count {
|
.age-goal-item__top {
|
||||||
display: block;
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.age-tip {
|
|
||||||
margin: 40rpx 24rpx 0;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 24rpx;
|
|
||||||
padding: 28rpx 24rpx;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
gap: 20rpx;
|
gap: 12rpx;
|
||||||
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.04);
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-tip__duck {
|
.age-goal-item__emoji {
|
||||||
font-size: 64rpx;
|
font-size: 40rpx;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.age-tip__text {
|
.age-goal-item__title {
|
||||||
flex: 1;
|
font-size: 28rpx;
|
||||||
font-size: 26rpx;
|
font-weight: 700;
|
||||||
line-height: 1.55;
|
color: @text-selected-btn;
|
||||||
color: rgba(0, 0, 0, 0.65);
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-goal-item__desc {
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: @text-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-path-head {
|
||||||
|
margin: @section-gap-lg @page-padding-x @section-gap-xs;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-path-head__left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20rpx;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-path-head__bar {
|
||||||
|
width: 16rpx;
|
||||||
|
height: 64rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: @text-selected-btn;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-path-head__title {
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
color: @text-title;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-path-head__badge {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-secondary;
|
||||||
|
background: @bg-header;
|
||||||
|
padding: 10rpx 20rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
border: @border;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-list {
|
||||||
|
padding: 0 @page-padding-x;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: @section-gap-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-card {
|
||||||
|
background: @bg-white;
|
||||||
|
border-radius: @radius-lg;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1rpx solid rgba(50, 46, 37, 0.08);
|
||||||
|
box-shadow: @shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-card__head {
|
||||||
|
padding: 28rpx @page-padding-x;
|
||||||
|
background: @bg-week-head;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-card__week {
|
||||||
|
font-size: @fs-section-head-title;
|
||||||
|
font-weight: 800;
|
||||||
|
color: @text-title;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-card__theme {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: @text-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-card__body {
|
||||||
|
padding: 0 @page-padding-x 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 20rpx;
|
||||||
|
padding: 32rpx 0;
|
||||||
|
border-bottom: 1rpx solid #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-row__title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-title;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-row__btn {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6rpx;
|
||||||
|
padding: 14rpx 28rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: @brand;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-selected-btn;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(255, 215, 9, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-week-row__btn-arrow {
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* [为你推荐] — Stitch 栅格 */
|
||||||
|
.age-rec {
|
||||||
|
margin-top: @section-gap-lg;
|
||||||
|
padding: 0 @page-padding-x @section-gap-xs;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-rec__head {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: @section-gap-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-rec__title {
|
||||||
|
font-size: @fs-section-head-title;
|
||||||
|
font-weight: 800;
|
||||||
|
color: @text-title;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-rec__more {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-selected-btn;
|
||||||
|
padding: 8rpx 0 8rpx 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-rec__grid {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
row-gap: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-rec__card {
|
||||||
|
width: calc(50% - 16rpx);
|
||||||
|
background: @bg-white;
|
||||||
|
border-radius: @radius-lg;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1rpx solid rgba(50, 46, 37, 0.08);
|
||||||
|
box-shadow: @shadow;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-rec__img {
|
||||||
|
width: 100%;
|
||||||
|
height: 200rpx;
|
||||||
|
display: block;
|
||||||
|
background: fade(@brand, 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-rec__body {
|
||||||
|
padding: 20rpx 20rpx 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.age-rec__card-title {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-title;
|
||||||
|
line-height: 1.35;
|
||||||
}
|
}
|
||||||
@@ -1,44 +1,243 @@
|
|||||||
import { ALL_WORKSHEETS, getWorksheetsByAge } from '../../core/data/worksheets';
|
import { AGE_BANDS, AgeBandKey } from '../../core/data/difficulty';
|
||||||
|
import { NAV_INNER_PX } from '../../utils/navMetrics';
|
||||||
|
|
||||||
interface AgeGroup {
|
type AbilityItem = {
|
||||||
label: string;
|
icon: string;
|
||||||
|
title: string;
|
||||||
desc: string;
|
desc: string;
|
||||||
emoji: string;
|
};
|
||||||
minAge: number;
|
|
||||||
maxAge: number;
|
type WeekExercise = {
|
||||||
count: number;
|
title: string;
|
||||||
gradient: string;
|
};
|
||||||
}
|
|
||||||
|
type WeekPlan = {
|
||||||
|
week: number;
|
||||||
|
theme: string;
|
||||||
|
exercises: WeekExercise[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const AGE_TAB_SUB: Record<AgeBandKey, string> = {
|
||||||
|
'3-4': '启蒙认知',
|
||||||
|
'4-5': '基础练习',
|
||||||
|
'5-6': '能力提升',
|
||||||
|
'6-7': '幼小衔接',
|
||||||
|
'7-8': '知识拓展',
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Stitch「为你推荐」占位图(需在小程序后台配置 download 合法域名含 lh3.googleusercontent.com) */
|
||||||
|
const RECOMMENDED_FROM_STITCH: { title: string; image: string }[] = [
|
||||||
|
{
|
||||||
|
title: '10以内加减法',
|
||||||
|
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuD-3lADhclTGODN9WtNh5v8bQPLysbllbKNkH40bAmVyE5d54PwfTBOiX9nER1hpE4rzHAfsmM_JhVnsE4EbdA914rYIb3S3e4r9QKFjUqYmj2XpE4MlYr_vLkG4oeMnvnHOqGC96nLGrPSOq-fpIddV7RSlYLDeNccBs0G2oUOy-6jIMujzTuEGk4nnxme5rpxs7rYjwcvVsqM5dlkpJthY42e4B3lSPH7ezx187WRSk--m4ZiWmAI52mMOiygzTSWoNormlvfvdM',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '拼音描红',
|
||||||
|
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBYS4O7PyflR5q8M6oXKwj_8QHzex3OL3YvdHBncutm7a_bjlZj83-8UBpGUQvJO20V0BnAdU3iKEoLlUqwpS60CiPhVyxYaHEAqv52P5YUhJdjf0hpLir1Li4rdI_-eqGkPTasYl-5kD2r8-RjUokKg_HiW5_TF72UbxFXHQh4BefYJZfl0Oc9-aTQvkbFL0C3tagi9Qv1jRsgQldMFU4M7cHt8KkxhO1QDF7-R85ZFORJM0RiqV2l-jn0c-UscKtuWtroiX6UUKk',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '趣味找不同',
|
||||||
|
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBSafbTyucs8JLpTgibRWwAJsHukrklTAuEnaAzax_Kr1RNCwHjqpQjta0Q-h47ClufzEmaHPgCIOlm_a2lL4gNlgBDyraCwzRU7aWCf_Fj_dM1cLGzROJmtqrdHKjQzTbCp0_Da8BvXi4a4H2X4RAYVPnLbZVmbgPXrTvpKgEI605kIMmr3n0--WojJQRsF4B_xCho80gABbIaMTHJHrs9xdEY6fZKg8ArQx7lRbJ6_EsLLB_C5a5crZ_begwruXKr3pmdU6KneC8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '走迷宫大挑战',
|
||||||
|
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuAOZHI1Dz6ax4iFUb3QYL-EWp2euA_3kyUeCcu6V57BBCzarMwKnFzcpJxJn4X4woklWFB08Ii1w6zsk0H5eDaPdgUYmsvY0NFqvAhKN_IbZGZjZnclZlBHkLRcX64Nl767L2pg01FQu9Tp6nq2p3lAuYeEQ2fiIdXh4j-QHyikbmx4_aDlx5X5fC0fqMMxWykhwLNkDzl2Rs3ucXj7zYnUP-dNNY-aj_JvqkY4pqoXQDt9ZJcfSeL0dWes7nvD5U2C_JFhrk1bVkw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '数字点连线',
|
||||||
|
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuD-3lADhclTGODN9WtNh5v8bQPLysbllbKNkH40bAmVyE5d54PwfTBOiX9nER1hpE4rzHAfsmM_JhVnsE4EbdA914rYIb3S3e4r9QKFjUqYmj2XpE4MlYr_vLkG4oeMnvnHOqGC96nLGrPSOq-fpIddV7RSlYLDeNccBs0G2oUOy-6jIMujzTuEGk4nnxme5rpxs7rYjwcvVsqM5dlkpJthY42e4B3lSPH7ezx187WRSk--m4ZiWmAI52mMOiygzTSWoNormlvfvdM',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '方格推理高手',
|
||||||
|
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBYS4O7PyflR5q8M6oXKwj_8QHzex3OL3YvdHBncutm7a_bjlZj83-8UBpGUQvJO20V0BnAdU3iKEoLlUqwpS60CiPhVyxYaHEAqv52P5YUhJdjf0hpLir1Li4rdI_-eqGkPTasYl-5kD2r8-RjUokKg_HiW5_TF72UbxFXHQh4BefYJZfl0Oc9-aTQvkbFL0C3tagi9Qv1jRsgQldMFU4M7cHt8KkxhO1QDF7-R85ZFORJM0RiqV2l-jn0c-UscKtuWtroiX6UUKk',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/** 各年龄段能力目标(Mock) */
|
||||||
|
const MOCK_ABILITY: Record<AgeBandKey, AbilityItem[]> = {
|
||||||
|
'3-4': [
|
||||||
|
{
|
||||||
|
icon: '🔢',
|
||||||
|
title: '数感',
|
||||||
|
desc: '认读 1-5、点数对应',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: '✏️',
|
||||||
|
title: '书写',
|
||||||
|
desc: '涂鸦线条、简单描红',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: '🧩',
|
||||||
|
title: '思维',
|
||||||
|
desc: '找相同、简单配对',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'4-5': [
|
||||||
|
{
|
||||||
|
icon: '🔢',
|
||||||
|
title: '数感',
|
||||||
|
desc: '10 以内数数、比大小',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: '✏️',
|
||||||
|
title: '书写',
|
||||||
|
desc: '笔画模仿、图形描边',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: '🧩',
|
||||||
|
title: '思维',
|
||||||
|
desc: '规律排序、图形分类',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'5-6': [
|
||||||
|
{
|
||||||
|
icon: '🔢',
|
||||||
|
title: '数感',
|
||||||
|
desc: '10以内加减法、凑十法',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: '✏️',
|
||||||
|
title: '书写',
|
||||||
|
desc: '练字帖、拼音入门',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: '🧩',
|
||||||
|
title: '思维',
|
||||||
|
desc: '方格推理、格子仿画 5×5',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'6-7': [
|
||||||
|
{
|
||||||
|
icon: '🔢',
|
||||||
|
title: '数感',
|
||||||
|
desc: '20 以内运算、应用题启蒙',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: '✏️',
|
||||||
|
title: '书写',
|
||||||
|
desc: '常用字书写、词语积累',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: '🧩',
|
||||||
|
title: '思维',
|
||||||
|
desc: '逻辑填空、空间想象',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'7-8': [
|
||||||
|
{
|
||||||
|
icon: '🔢',
|
||||||
|
title: '数感',
|
||||||
|
desc: '乘除启蒙、巧算练习',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: '✏️',
|
||||||
|
title: '书写',
|
||||||
|
desc: '段落抄写、古诗诵读',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: '🧩',
|
||||||
|
title: '思维',
|
||||||
|
desc: '数独入门、综合推理',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 4 周路线(各年龄段共用结构,内容 Mock) */
|
||||||
|
const MOCK_WEEKS: WeekPlan[] = [
|
||||||
|
{
|
||||||
|
week: 1,
|
||||||
|
theme: '数感启蒙',
|
||||||
|
exercises: [
|
||||||
|
{ title: '找数字涂一涂' },
|
||||||
|
{ title: '5 以内加法' },
|
||||||
|
{ title: '数数连一连' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
week: 2,
|
||||||
|
theme: '形状与连线',
|
||||||
|
exercises: [
|
||||||
|
{ title: '识别形状' },
|
||||||
|
{ title: '线条识别' },
|
||||||
|
{ title: '数字点连线' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
week: 3,
|
||||||
|
theme: '趣味专注',
|
||||||
|
exercises: [
|
||||||
|
{ title: '颜色找规律' },
|
||||||
|
{ title: '方格推理' },
|
||||||
|
{ title: '格子仿画' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
week: 4,
|
||||||
|
theme: '综合练习',
|
||||||
|
exercises: [
|
||||||
|
{ title: '10以内加减法' },
|
||||||
|
{ title: '识字卡' },
|
||||||
|
{ title: '连连看' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const DEFAULT_AGE: AgeBandKey = '5-6';
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
ageGroups: [] as AgeGroup[],
|
statusBarHeight: 0,
|
||||||
|
navBlockHeight: 0,
|
||||||
|
ageTabs: AGE_BANDS.map((b) => ({
|
||||||
|
key: b.key,
|
||||||
|
rangeText: b.label.replace(/\s*岁\s*$/, ''),
|
||||||
|
subLabel: AGE_TAB_SUB[b.key],
|
||||||
|
})),
|
||||||
|
activeAgeKey: DEFAULT_AGE,
|
||||||
|
goalTitle: '',
|
||||||
|
abilityItems: [] as AbilityItem[],
|
||||||
|
weekPlans: MOCK_WEEKS,
|
||||||
|
recommendedItems: RECOMMENDED_FROM_STITCH,
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
const groups = [
|
const win = wx.getWindowInfo();
|
||||||
{ label: '3-4 岁', desc: '启蒙认知', emoji: '👶', minAge: 3, maxAge: 4, gradient: 'linear-gradient(135deg, #fff9c4, #fff176)' },
|
this.setData({
|
||||||
{ label: '4-5 岁', desc: '基础练习', emoji: '🧒', minAge: 4, maxAge: 5, gradient: 'linear-gradient(135deg, #c8e6c9, #81c784)' },
|
statusBarHeight: win.statusBarHeight,
|
||||||
{ label: '5-6 岁', desc: '能力提升', emoji: '👦', minAge: 5, maxAge: 6, gradient: 'linear-gradient(135deg, #bbdefb, #64b5f6)' },
|
navBlockHeight: win.statusBarHeight + NAV_INNER_PX,
|
||||||
{ label: '6-7 岁', desc: '幼小衔接', emoji: '👧', minAge: 6, maxAge: 7, gradient: 'linear-gradient(135deg, #e1bee7, #ba68c8)' },
|
});
|
||||||
{ label: '7-8 岁', desc: '巩固挑战', emoji: '🎒', minAge: 7, maxAge: 8, gradient: 'linear-gradient(135deg, #ffccbc, #ff8a65)' },
|
this.applyAge(DEFAULT_AGE);
|
||||||
];
|
|
||||||
|
|
||||||
const ageGroups = groups.map((g) => ({
|
|
||||||
...g,
|
|
||||||
count: getWorksheetsByAge(ALL_WORKSHEETS, g.minAge).length,
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.setData({ ageGroups });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onAgeCardTap(e: WechatMiniprogram.TouchEvent) {
|
applyAge(key: AgeBandKey) {
|
||||||
const minAge = Number(e.currentTarget.dataset.minAge);
|
const band = AGE_BANDS.find((b) => b.key === key);
|
||||||
const maxAge = Number(e.currentTarget.dataset.maxAge);
|
const goalTitle = band ? `${band.label}能力目标` : '能力目标';
|
||||||
if (Number.isNaN(minAge) || Number.isNaN(maxAge)) return;
|
this.setData({
|
||||||
const title = `${minAge}-${maxAge}岁推荐`;
|
activeAgeKey: key,
|
||||||
wx.navigateTo({
|
goalTitle,
|
||||||
url: `/pages/category/category?minAge=${minAge}&maxAge=${maxAge}&title=${encodeURIComponent(title)}`,
|
abilityItems: MOCK_ABILITY[key],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onAgeTabTap(e: WechatMiniprogram.TouchEvent) {
|
||||||
|
const key = e.currentTarget.dataset.key as AgeBandKey | undefined;
|
||||||
|
if (!key) return;
|
||||||
|
this.applyAge(key);
|
||||||
|
},
|
||||||
|
|
||||||
|
onPracticeTap(e: WechatMiniprogram.TouchEvent) {
|
||||||
|
const title = e.currentTarget.dataset.title as string | undefined;
|
||||||
|
if (!title) return;
|
||||||
|
wx.showToast({ title: `即将前往:${title}`, icon: 'none' });
|
||||||
|
},
|
||||||
|
|
||||||
|
onRecommendMore() {
|
||||||
|
wx.switchTab({ url: '/pages/home/home' });
|
||||||
|
},
|
||||||
|
|
||||||
|
onRecommendTap(e: WechatMiniprogram.TouchEvent) {
|
||||||
|
const title = e.currentTarget.dataset.title as string | undefined;
|
||||||
|
if (!title) return;
|
||||||
|
wx.showToast({ title: `去看看:${title}`, icon: 'none' });
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,31 +1,110 @@
|
|||||||
<view class="age-page">
|
<view class="age-page">
|
||||||
<view class="age-hero">
|
<view class="age-nav" style="padding-top: {{statusBarHeight}}px;">
|
||||||
<text class="age-hero__title">分龄推荐</text>
|
<view class="age-nav__inner">
|
||||||
<text class="age-hero__subtitle">按年龄段挑选适合的练习单,循序渐进更省心</text>
|
<text class="age-nav__title">按年龄学</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="age-grid">
|
<view class="age-body" style="padding-top: {{navBlockHeight}}px;">
|
||||||
|
<scroll-view class="age-tab-scroll" scroll-x enable-flex>
|
||||||
|
<view class="age-tab-scroll__inner">
|
||||||
|
<view class="age-tab-row">
|
||||||
<view
|
<view
|
||||||
wx:for="{{ageGroups}}"
|
wx:for="{{ageTabs}}"
|
||||||
wx:key="label"
|
wx:key="key"
|
||||||
class="age-card"
|
class="age-tab {{activeAgeKey === item.key ? 'age-tab--active' : ''}}"
|
||||||
bindtap="onAgeCardTap"
|
data-key="{{item.key}}"
|
||||||
data-min-age="{{item.minAge}}"
|
bindtap="onAgeTabTap">
|
||||||
data-max-age="{{item.maxAge}}"
|
<text class="age-tab__range">{{item.rangeText}}</text>
|
||||||
>
|
<text class="age-tab__sub">{{item.subLabel}}</text>
|
||||||
<view class="age-card__art" style="background: {{item.gradient}}">
|
|
||||||
<text class="age-card__emoji">{{item.emoji}}</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="age-card__body">
|
</view>
|
||||||
<text class="age-card__label">{{item.label}}</text>
|
</view>
|
||||||
<text class="age-card__desc">{{item.desc}}</text>
|
</scroll-view>
|
||||||
<text class="age-card__count">{{item.count}} 个练习</text>
|
|
||||||
|
<view class="age-panel age-goal-panel">
|
||||||
|
<view class="age-goal-head">
|
||||||
|
<view class="age-goal-head__icon-wrap">
|
||||||
|
<text class="age-goal-head__icon" aria-hidden="true"
|
||||||
|
>⭐</text
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
<text class="age-goal-head__title">{{goalTitle}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="age-goal-list">
|
||||||
|
<view
|
||||||
|
wx:for="{{abilityItems}}"
|
||||||
|
wx:key="title"
|
||||||
|
class="age-goal-item">
|
||||||
|
<view class="age-goal-item__top">
|
||||||
|
<text class="age-goal-item__emoji">{{item.icon}}</text>
|
||||||
|
<text class="age-goal-item__title">{{item.title}}</text>
|
||||||
|
</view>
|
||||||
|
<text class="age-goal-item__desc">{{item.desc}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="age-tip">
|
<view class="age-path-head">
|
||||||
<text class="age-tip__duck">🦆</text>
|
<view class="age-path-head__left">
|
||||||
<text class="age-tip__text">建议家长根据孩子当前能力微调难度,不必严格按年龄划分哦~</text>
|
<view class="age-path-head__bar" />
|
||||||
|
<text class="age-path-head__title">4 周推荐学习路线</text>
|
||||||
|
</view>
|
||||||
|
<view class="age-path-head__badge">4 周 · 每周 3 练</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="age-week-list">
|
||||||
|
<view wx:for="{{weekPlans}}" wx:key="week" class="age-week-card">
|
||||||
|
<view class="age-week-card__head">
|
||||||
|
<text class="age-week-card__week">第 {{item.week}} 周</text>
|
||||||
|
<text class="age-week-card__theme">{{item.theme}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="age-week-card__body">
|
||||||
|
<view
|
||||||
|
wx:for="{{item.exercises}}"
|
||||||
|
wx:for-item="ex"
|
||||||
|
wx:key="title"
|
||||||
|
class="age-week-row">
|
||||||
|
<text class="age-week-row__title">{{ex.title}}</text>
|
||||||
|
<view
|
||||||
|
class="age-week-row__btn"
|
||||||
|
data-title="{{ex.title}}"
|
||||||
|
catchtap="onPracticeTap">
|
||||||
|
<text>去练习</text>
|
||||||
|
<text
|
||||||
|
class="age-week-row__btn-arrow"
|
||||||
|
aria-hidden="true"
|
||||||
|
>→</text
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="age-rec">
|
||||||
|
<view class="age-rec__head">
|
||||||
|
<text class="age-rec__title">为你推荐</text>
|
||||||
|
<text class="age-rec__more" bindtap="onRecommendMore"
|
||||||
|
>更多</text
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
<view class="age-rec__grid">
|
||||||
|
<view
|
||||||
|
wx:for="{{recommendedItems}}"
|
||||||
|
wx:key="title"
|
||||||
|
class="age-rec__card"
|
||||||
|
data-title="{{item.title}}"
|
||||||
|
bindtap="onRecommendTap">
|
||||||
|
<image
|
||||||
|
class="age-rec__img"
|
||||||
|
src="{{item.image}}"
|
||||||
|
mode="aspectFill" />
|
||||||
|
<view class="age-rec__body">
|
||||||
|
<text class="age-rec__card-title">{{item.title}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"navigationBarTitleText": "分类",
|
|
||||||
"navigationBarTextStyle": "black",
|
|
||||||
"navigationBarBackgroundColor": "#ffffff",
|
|
||||||
"backgroundColor": "#F6F6F6",
|
|
||||||
"usingComponents": {
|
|
||||||
"worksheet-card": "../../components3.0/worksheet-card/worksheet-card",
|
|
||||||
"detail-card": "../../components3.0/detail-card/detail-card"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
.category-page {
|
|
||||||
min-height: 100vh;
|
|
||||||
background: #f6f6f6;
|
|
||||||
padding-bottom: 48rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__header {
|
|
||||||
padding: 24rpx 32rpx 16rpx;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__header-title {
|
|
||||||
font-size: 34rpx;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__filters {
|
|
||||||
background: #fff;
|
|
||||||
padding: 24rpx;
|
|
||||||
margin-bottom: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__filter-row {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: flex-start;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__filter-row:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__filter-label {
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 72rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #999;
|
|
||||||
line-height: 56rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__pills {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__pill {
|
|
||||||
font-size: 24rpx;
|
|
||||||
padding: 8rpx 20rpx;
|
|
||||||
border-radius: 24rpx;
|
|
||||||
background: #f5f5f5;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__pill--active {
|
|
||||||
background: #f7ee47;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__card-wrap {
|
|
||||||
margin: 0 24rpx 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__empty {
|
|
||||||
padding: 120rpx 48rpx;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-page__empty-text {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
import type {
|
|
||||||
WorksheetDefinition,
|
|
||||||
WorksheetType,
|
|
||||||
} from '../../core/models/worksheet';
|
|
||||||
import {
|
|
||||||
getWorksheetPath,
|
|
||||||
getWorksheetsByAge,
|
|
||||||
getWorksheetsByCategory,
|
|
||||||
} from '../../core/data/worksheets';
|
|
||||||
|
|
||||||
type AgeFilterKey = 'all' | '3-4' | '4-5' | '5-6' | '6-7' | '7-8';
|
|
||||||
type DiffFilterKey = 'all' | 'beginner' | 'basic' | 'intermediate';
|
|
||||||
|
|
||||||
const AGE_BAND: Record<Exclude<AgeFilterKey, 'all'>, [number, number]> = {
|
|
||||||
'3-4': [3, 4],
|
|
||||||
'4-5': [4, 5],
|
|
||||||
'5-6': [5, 6],
|
|
||||||
'6-7': [6, 7],
|
|
||||||
'7-8': [7, 8],
|
|
||||||
};
|
|
||||||
|
|
||||||
const DIFF_LABEL: Record<string, string> = {
|
|
||||||
beginner: '入门',
|
|
||||||
basic: '基础',
|
|
||||||
intermediate: '进阶',
|
|
||||||
advanced: '进阶+',
|
|
||||||
};
|
|
||||||
|
|
||||||
type DisplayItem = WorksheetType & {
|
|
||||||
ageRangeLabel: string;
|
|
||||||
difficultyLabel: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
function filterByAgeBand(
|
|
||||||
list: WorksheetType[],
|
|
||||||
band: AgeFilterKey,
|
|
||||||
): WorksheetType[] {
|
|
||||||
if (band === 'all') return list;
|
|
||||||
const [lo, hi] = AGE_BAND[band];
|
|
||||||
const map = new Map<string, WorksheetType>();
|
|
||||||
for (let age = lo; age <= hi; age += 1) {
|
|
||||||
getWorksheetsByAge(list, age).forEach((w) => map.set(w.id, w));
|
|
||||||
}
|
|
||||||
return Array.from(map.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterByDifficulty(
|
|
||||||
list: WorksheetType[],
|
|
||||||
diff: DiffFilterKey,
|
|
||||||
): WorksheetType[] {
|
|
||||||
if (diff === 'all') return list;
|
|
||||||
return list.filter((w) => w.difficulty === diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toDisplayList(list: WorksheetType[]): DisplayItem[] {
|
|
||||||
return list.map((w) => ({
|
|
||||||
...w,
|
|
||||||
ageRangeLabel:
|
|
||||||
w.ageRange && w.ageRange.length === 2
|
|
||||||
? `${w.ageRange[0]}-${w.ageRange[1]}岁`
|
|
||||||
: '',
|
|
||||||
difficultyLabel: w.difficulty ? DIFF_LABEL[w.difficulty] || '' : '',
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Page({
|
|
||||||
data: {
|
|
||||||
title: '分类',
|
|
||||||
sourceItems: [] as WorksheetDefinition[],
|
|
||||||
items: [] as DisplayItem[],
|
|
||||||
ageFilters: [
|
|
||||||
{ key: 'all', label: '全部' },
|
|
||||||
{ key: '3-4', label: '3-4岁' },
|
|
||||||
{ key: '4-5', label: '4-5岁' },
|
|
||||||
{ key: '5-6', label: '5-6岁' },
|
|
||||||
{ key: '6-7', label: '6-7岁' },
|
|
||||||
{ key: '7-8', label: '7-8岁' },
|
|
||||||
],
|
|
||||||
diffFilters: [
|
|
||||||
{ key: 'all', label: '全部' },
|
|
||||||
{ key: 'beginner', label: '⭐ 入门' },
|
|
||||||
{ key: 'basic', label: '⭐⭐ 基础' },
|
|
||||||
{ key: 'intermediate', label: '⭐⭐⭐ 进阶' },
|
|
||||||
],
|
|
||||||
activeAge: 'all' as AgeFilterKey,
|
|
||||||
activeDiff: 'all' as DiffFilterKey,
|
|
||||||
},
|
|
||||||
|
|
||||||
onLoad(options: {
|
|
||||||
category?: string;
|
|
||||||
minAge?: string;
|
|
||||||
maxAge?: string;
|
|
||||||
title?: string;
|
|
||||||
}) {
|
|
||||||
const category = options.category || 'all';
|
|
||||||
let base = getWorksheetsByCategory(category);
|
|
||||||
|
|
||||||
const minAge = options.minAge != null ? Number(options.minAge) : NaN;
|
|
||||||
const maxAge = options.maxAge != null ? Number(options.maxAge) : NaN;
|
|
||||||
if (!Number.isNaN(minAge) && !Number.isNaN(maxAge)) {
|
|
||||||
const map = new Map<string, WorksheetDefinition>();
|
|
||||||
const lo = Math.min(minAge, maxAge);
|
|
||||||
const hi = Math.max(minAge, maxAge);
|
|
||||||
for (let age = lo; age <= hi; age += 1) {
|
|
||||||
getWorksheetsByAge(base, age).forEach((w) => map.set(w.id, w));
|
|
||||||
}
|
|
||||||
base = Array.from(map.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
const title = options.title
|
|
||||||
? decodeURIComponent(options.title)
|
|
||||||
: '分类';
|
|
||||||
|
|
||||||
this.setData({
|
|
||||||
title,
|
|
||||||
sourceItems: base,
|
|
||||||
});
|
|
||||||
wx.setNavigationBarTitle({ title });
|
|
||||||
this.applyFilters();
|
|
||||||
},
|
|
||||||
|
|
||||||
applyFilters() {
|
|
||||||
const { sourceItems, activeAge, activeDiff } = this.data;
|
|
||||||
let next = filterByAgeBand(sourceItems, activeAge);
|
|
||||||
next = filterByDifficulty(next, activeDiff);
|
|
||||||
this.setData({ items: toDisplayList(next) });
|
|
||||||
},
|
|
||||||
|
|
||||||
onAgeFilter(e: WechatMiniprogram.TouchEvent) {
|
|
||||||
const key = e.currentTarget.dataset.key as AgeFilterKey;
|
|
||||||
if (!key) return;
|
|
||||||
this.setData({ activeAge: key }, () => this.applyFilters());
|
|
||||||
},
|
|
||||||
|
|
||||||
onDiffFilter(e: WechatMiniprogram.TouchEvent) {
|
|
||||||
const key = e.currentTarget.dataset.key as DiffFilterKey;
|
|
||||||
if (!key) return;
|
|
||||||
this.setData({ activeDiff: key }, () => this.applyFilters());
|
|
||||||
},
|
|
||||||
|
|
||||||
buildWorksheetUrl(w: WorksheetType): string {
|
|
||||||
let url = getWorksheetPath(w);
|
|
||||||
if (!url) return '';
|
|
||||||
if (w.mode) {
|
|
||||||
url += url.includes('?') ? `&mode=${w.mode}` : `?mode=${w.mode}`;
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
},
|
|
||||||
|
|
||||||
onCardTap(e: WechatMiniprogram.TouchEvent) {
|
|
||||||
const id = e.currentTarget.dataset.id as string;
|
|
||||||
const w = this.data.items.find((item) => item.id === id);
|
|
||||||
if (!w) return;
|
|
||||||
const url = this.buildWorksheetUrl(w);
|
|
||||||
if (!url) {
|
|
||||||
wx.showToast({ title: '暂无法打开', icon: 'none' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wx.navigateTo({ url });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
<view class="category-page">
|
|
||||||
<view class="category-page__header">
|
|
||||||
<text class="category-page__header-title">{{title}}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="category-page__filters">
|
|
||||||
<view class="category-page__filter-row">
|
|
||||||
<text class="category-page__filter-label">年龄</text>
|
|
||||||
<view class="category-page__pills">
|
|
||||||
<view
|
|
||||||
wx:for="{{ageFilters}}"
|
|
||||||
wx:key="key"
|
|
||||||
class="category-page__pill {{activeAge === item.key ? 'category-page__pill--active' : ''}}"
|
|
||||||
data-key="{{item.key}}"
|
|
||||||
bindtap="onAgeFilter"
|
|
||||||
>
|
|
||||||
{{item.label}}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="category-page__filter-row">
|
|
||||||
<text class="category-page__filter-label">难度</text>
|
|
||||||
<view class="category-page__pills">
|
|
||||||
<view
|
|
||||||
wx:for="{{diffFilters}}"
|
|
||||||
wx:key="key"
|
|
||||||
class="category-page__pill {{activeDiff === item.key ? 'category-page__pill--active' : ''}}"
|
|
||||||
data-key="{{item.key}}"
|
|
||||||
bindtap="onDiffFilter"
|
|
||||||
>
|
|
||||||
{{item.label}}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view wx:if="{{items.length}}" class="category-page__list">
|
|
||||||
<view
|
|
||||||
wx:for="{{items}}"
|
|
||||||
wx:key="id"
|
|
||||||
class="category-page__card-wrap"
|
|
||||||
>
|
|
||||||
<detail-card
|
|
||||||
title="{{item.title}}"
|
|
||||||
preview-bg="{{item.previewBg}}"
|
|
||||||
preview-text="{{item.previewText}}"
|
|
||||||
age-range="{{item.ageRangeLabel}}"
|
|
||||||
difficulty="{{item.difficultyLabel}}"
|
|
||||||
data-id="{{item.id}}"
|
|
||||||
bind:tap="onCardTap"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view wx:else class="category-page__empty">
|
|
||||||
<text class="category-page__empty-text">暂无符合条件的练习纸</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
{
|
{
|
||||||
|
"navigationStyle": "custom",
|
||||||
"navigationBarTitleText": "我的收藏",
|
"navigationBarTitleText": "我的收藏",
|
||||||
"navigationBarTextStyle": "black",
|
"navigationBarTextStyle": "black",
|
||||||
"navigationBarBackgroundColor": "#ffffff",
|
"navigationBarBackgroundColor": "#F8F0E0",
|
||||||
"backgroundColor": "#F6F6F6"
|
"backgroundColor": "#FEF6E7",
|
||||||
|
"usingComponents": {
|
||||||
|
"van-icon": "@vant/weapp/icon/index"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,88 +1,452 @@
|
|||||||
.favorites-page {
|
@import '../../style/theme3.less';
|
||||||
|
|
||||||
|
@fav-seg-track: #f0e7d6;
|
||||||
|
@fav-thumb-placeholder: #e5dcc9;
|
||||||
|
@fav-secondary-cta-bg: #ffc697;
|
||||||
|
@fav-secondary-cta-text: #6d3b00;
|
||||||
|
@fav-heart: #b02500;
|
||||||
|
|
||||||
|
.fav-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #f6f6f6;
|
background: @bg-page;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__title {
|
.fav-nav {
|
||||||
padding: 32rpx 32rpx 24rpx;
|
position: fixed;
|
||||||
font-size: 40rpx;
|
top: 0;
|
||||||
font-weight: 600;
|
left: 0;
|
||||||
color: #333;
|
right: 0;
|
||||||
background: #fff;
|
z-index: 100;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: fade(@bg-header, 82%);
|
||||||
|
backdrop-filter: blur(40rpx);
|
||||||
|
-webkit-backdrop-filter: blur(40rpx);
|
||||||
|
box-shadow: 0 2rpx 12rpx rgba(50, 46, 37, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__tabs {
|
.fav-nav__inner {
|
||||||
|
height: @nav-inner-height;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
background: #fff;
|
align-items: center;
|
||||||
border-bottom: 1rpx solid #eee;
|
justify-content: flex-start;
|
||||||
|
padding: 0 @page-padding-x;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__tab {
|
.fav-nav__title {
|
||||||
flex: 1;
|
font-size: @fs-nav-title;
|
||||||
text-align: center;
|
font-weight: @fw-nav-title;
|
||||||
padding: 24rpx 0;
|
color: @color-nav-title;
|
||||||
font-size: 30rpx;
|
letter-spacing: @ls-nav-title;
|
||||||
color: #666;
|
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__tab--active {
|
.fav-nav__actions {
|
||||||
color: #333;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
min-width: 120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-nav__icon-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 8rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-nav__clear {
|
||||||
|
font-size: 26rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
color: fade(@text-selected-btn, 65%);
|
||||||
|
padding: 12rpx 20rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__tab--active::after {
|
.fav-scroll {
|
||||||
content: '';
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-body {
|
||||||
|
padding: @section-gap-xs @page-padding-x;
|
||||||
|
padding-bottom: calc(48rpx + env(safe-area-inset-bottom) + 120rpx);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Segmented(Stitch 胶囊) */
|
||||||
|
.fav-seg {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: stretch;
|
||||||
|
padding: 12rpx;
|
||||||
|
margin-bottom: @section-gap-sm;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: @fav-seg-track;
|
||||||
|
box-shadow: @shadow;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-seg__pill {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 22rpx 16rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-seg__pill--active {
|
||||||
|
background: @brand;
|
||||||
|
box-shadow: @shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-seg__text {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-seg__pill--active .fav-seg__text {
|
||||||
|
color: @text-selected-btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 收藏列表卡片 */
|
||||||
|
.fav-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-card {
|
||||||
|
border-radius: @radius-lg;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-card--row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32rpx;
|
||||||
|
padding: 32rpx;
|
||||||
|
background: @bg-header;
|
||||||
|
box-shadow: @shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-card__thumb {
|
||||||
|
width: 160rpx;
|
||||||
|
height: 160rpx;
|
||||||
|
border-radius: @radius;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: @fav-thumb-placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-card__main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-card__title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-title;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-card__meta {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-card__meta-text {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: @text-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-card__stars {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-card__badge {
|
||||||
|
margin-top: 4rpx;
|
||||||
|
font-size: 18rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: @text-gray;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 6rpx 16rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: @fav-seg-track;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-card__heart {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bento 大卡 */
|
||||||
|
.fav-card--bento {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 48rpx 140rpx 48rpx 40rpx;
|
||||||
|
background: @fav-seg-track;
|
||||||
|
box-shadow: @shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-bento__content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-bento__title {
|
||||||
|
font-size: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-bento__meta {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: @text-secondary;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
margin-bottom: 28rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-bento__tags {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-bento__tag {
|
||||||
|
padding: 8rpx 22rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @fav-secondary-cta-text;
|
||||||
|
background: rgba(255, 255, 255, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-bento__deco {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
right: -40rpx;
|
||||||
bottom: 0;
|
bottom: -48rpx;
|
||||||
transform: translateX(-50%);
|
z-index: 0;
|
||||||
width: 48rpx;
|
pointer-events: none;
|
||||||
height: 6rpx;
|
|
||||||
background: #f7ee47;
|
|
||||||
border-radius: 3rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__empty {
|
.fav-bento__heart {
|
||||||
|
position: absolute;
|
||||||
|
top: 40rpx;
|
||||||
|
right: 32rpx;
|
||||||
|
z-index: 2;
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部去发现 */
|
||||||
|
.fav-cta {
|
||||||
|
margin-top: @section-gap;
|
||||||
|
padding: 48rpx 0 24rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
|
||||||
padding: 120rpx 48rpx 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__emoji {
|
.fav-cta__hint {
|
||||||
font-size: 96rpx;
|
font-size: 26rpx;
|
||||||
line-height: 1.2;
|
font-weight: 600;
|
||||||
|
color: @text-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-cta__btn {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
padding: 22rpx 64rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
background: @fav-secondary-cta-bg !important;
|
||||||
|
color: @fav-secondary-cta-text !important;
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: @shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-cta__btn::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下载历史 */
|
||||||
|
.fav-dl {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl__section-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-gray;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 8rpx 16rpx 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl__items {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 32rpx;
|
||||||
margin-bottom: 32rpx;
|
margin-bottom: 32rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__empty-msg {
|
.fav-dl-row {
|
||||||
margin-bottom: 48rpx;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32rpx;
|
||||||
|
padding: 32rpx;
|
||||||
|
background: @bg-header;
|
||||||
|
border-radius: @radius-lg;
|
||||||
|
box-shadow: @shadow;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__empty-line {
|
.fav-dl-row--muted {
|
||||||
display: block;
|
opacity: 0.92;
|
||||||
font-size: 28rpx;
|
|
||||||
color: #666;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 1.6;
|
|
||||||
margin-bottom: 8rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__btn {
|
.fav-dl-row__thumb {
|
||||||
width: 280rpx;
|
width: 160rpx;
|
||||||
height: 80rpx;
|
height: 160rpx;
|
||||||
line-height: 80rpx;
|
border-radius: @radius;
|
||||||
background: #f7ee47;
|
flex-shrink: 0;
|
||||||
color: #333;
|
background: @fav-thumb-placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl-row__thumb--ph {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: linear-gradient(145deg, @fav-secondary-cta-bg 0%, fade(@brand, 35%) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl-row__main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl-row__title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-title;
|
||||||
|
line-height: 1.25;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl-row__meta {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: fade(@text-secondary, 88%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl-row__time {
|
||||||
|
color: fade(@text-secondary, 88%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl-row__dot {
|
||||||
|
width: 8rpx;
|
||||||
|
height: 8rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: @text-gray;
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl-row__status {
|
||||||
|
color: fade(@text-secondary, 65%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl-row__status--hi {
|
||||||
|
color: #006b1b;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-dl-row__more {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 72rpx;
|
||||||
|
height: 72rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 空状态 */
|
||||||
|
.fav-empty {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 120rpx 32rpx 64rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-empty__emoji {
|
||||||
|
font-size: 100rpx;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-empty__icon {
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-empty__msg {
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
border-radius: 40rpx;
|
color: @text-title;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-empty__sub {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: @text-secondary;
|
||||||
|
margin-bottom: 40rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fav-empty__btn {
|
||||||
|
padding: 20rpx 56rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
background: @brand;
|
||||||
|
color: @text-selected-btn;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.favorites-page__btn::after {
|
.fav-empty__btn::after {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,136 @@
|
|||||||
|
import { NAV_INNER_PX } from '../../utils/navMetrics';
|
||||||
|
|
||||||
type FavoritesTab = 'favorites' | 'downloads';
|
type FavoritesTab = 'favorites' | 'downloads';
|
||||||
|
|
||||||
|
type FavoriteItem =
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
variant: 'standard';
|
||||||
|
title: string;
|
||||||
|
metaLine: string;
|
||||||
|
stars: number;
|
||||||
|
timeBadge: string;
|
||||||
|
thumb: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
variant: 'featured';
|
||||||
|
title: string;
|
||||||
|
metaLine: string;
|
||||||
|
tags: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type DownloadRow = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
time: string;
|
||||||
|
status: string;
|
||||||
|
statusHighlight: boolean;
|
||||||
|
thumb?: string;
|
||||||
|
placeholder?: 'draw';
|
||||||
|
};
|
||||||
|
|
||||||
|
type DownloadSection = {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
items: DownloadRow[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const MOCK_FAVORITES: FavoriteItem[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
variant: 'standard',
|
||||||
|
title: '10以内加法',
|
||||||
|
metaLine: '数学启蒙 · 4-6岁 · ',
|
||||||
|
stars: 2,
|
||||||
|
timeBadge: '收藏于 3 天前',
|
||||||
|
thumb: 'https://lh3.googleusercontent.com/aida-public/AB6AXuD7khp0rJABfa9yFrMt9ZgIhAPyN44XmJ2pXNBgCzbgBvwA5ptFZVty013JedVzbE9_VvCQnToN7QETLDKjtiX22igzK-a5h4E8wjKrembFW4eVuk1RsJIbHjx3_cCz0hJ7_t76hF8t-Qdod_5R9sNMor1ZEjf6dGNp6UI_eIBjsN9b22iCTJ2VB-IEh0Rmil6_iC4Og-4I03IcQDV2rTHYIXcZxjiay1IiYGXw3wJ3bfo2SF2N7ZFT00akTgYU-9JyF7xJ6n15Yzc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
variant: 'standard',
|
||||||
|
title: '图形连连看',
|
||||||
|
metaLine: '逻辑思维 · 3-5岁 · ',
|
||||||
|
stars: 1,
|
||||||
|
timeBadge: '收藏于 5 天前',
|
||||||
|
thumb: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBY_0Rr153ZBT4IHcMyFtrcgl-y2ZRyVnOuGecnn7f4PZKoAx2lOuCorsMmfRa72s0JmbXrt4XT3QU1x7cIbZUyhv_EXwCfMaNxtkHc-ymIBIQ5jqm5oiQebrEWH4kjv14JdkCiziT4xzac4TdVN5yqpk7Wlg80QBl_ldDmAQqIgcUeN2PvlVvhmpOYmFeWE2HS3I_e4vV1J8s_cfV9_4g7y8SbxlSfnTmgQNeXrVbcdwaNEAGQWp92Iif0d2pVIqdfuUHO1pTw8oQ',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
variant: 'standard',
|
||||||
|
title: '拼音字母认读',
|
||||||
|
metaLine: '语文基础 · 5-7岁 · ',
|
||||||
|
stars: 3,
|
||||||
|
timeBadge: '收藏于 1 周前',
|
||||||
|
thumb: 'https://lh3.googleusercontent.com/aida-public/AB6AXuC54mXQ8620XwIsWmUHBHJGdmpF8uE4cSYxwR2NLJTsa6gYdTCHz2tqrKbGOye-y0CGgCPPWwJXzEuB2ZYrQ3CWWPlamvbjhTUDYf8yoA9Lyapll1t2w17AqzSHrbBPNFrq931IUCis64b51kslQZoq3c0KslZsBQiky-YSnuE7xUuNsgiF4hOak_ReFFufWE53h1sPkjHFeRM-H34b-e1MCNxGObGPhI0mNlJ_qz0c8aCuS-jdnDocSvIYda-iVcJLWcIT-mO6klw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
variant: 'featured',
|
||||||
|
title: '趣味英语单词卡',
|
||||||
|
metaLine: '语言学习 · 4-8岁 · ⭐⭐⭐',
|
||||||
|
tags: ['畅销经典', '全彩打印'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const MOCK_DOWNLOADS: DownloadSection[] = [
|
||||||
|
{
|
||||||
|
key: 'today',
|
||||||
|
label: '今天',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'd1',
|
||||||
|
title: '拼音描红 · 声母表',
|
||||||
|
time: '14:32',
|
||||||
|
status: '已保存相册',
|
||||||
|
statusHighlight: true,
|
||||||
|
thumb: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBCm6X4rhibw2_WxP-U0dDyOsiYol3y12OnEXHRkPONZYMQBUcr3Grqo1IbwH3sdWPg5jIUeIbr_AEwv_hFwUOMMz9jTIIMc6Pke1bzSvlQcgdDq-zMEIU4A--IQFX59ac-8BscCajXZcd4v8rE6JEZFf1-aztKclPTkE_Rrgj-nbVCy5V6bOE6yDOB67VdTbcqiOdaFN18ju_MgWVo3FQZLwIUZOBahkPl0vDIKA0mkiaGK9eiFpfnERYxkYG3eWJZ40umTYp46Jo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'd2',
|
||||||
|
title: '趣味口算题卡',
|
||||||
|
time: '09:15',
|
||||||
|
status: '已下载 PDF',
|
||||||
|
statusHighlight: false,
|
||||||
|
thumb: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBxNORxN_vftYMLaMjZVscL-o9bZnBrfUi7IAqOrFATIztGV12_0ggwgae-fmk0cORWtysZWJJDcAzj0NEyniFxbREoGDuq9U4kytprJkA70_k0MCzPgStmq0bRwu1Gx1j4peglFam8PH6IlPvOMbiHQ7-fMFfYTSBtA1p7Dp06NDOzS2VrMlF8VxjEgihVmhHUrHePVvXlktUkXBKNzrXEXrogO3iOyouTUKyvJh0TeChKUv3KohMoD5ol7C3fjBhdHf7QD4StOQ4',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'yesterday',
|
||||||
|
label: '昨天',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'd3',
|
||||||
|
title: '汉字笔画基础训练',
|
||||||
|
time: '16:40',
|
||||||
|
status: '已发送邮件',
|
||||||
|
statusHighlight: false,
|
||||||
|
placeholder: 'draw',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
|
statusBarHeight: 0,
|
||||||
|
navBlockHeight: 0,
|
||||||
|
/** 纵向 scroll-view 可视高度(窗口高 − 顶栏占位,避免内容滚入导航下) */
|
||||||
|
favScrollHeight: 0,
|
||||||
activeTab: 'favorites' as FavoritesTab,
|
activeTab: 'favorites' as FavoritesTab,
|
||||||
favoriteList: [] as unknown[],
|
favoriteList: MOCK_FAVORITES as FavoriteItem[],
|
||||||
downloadList: [] as unknown[],
|
downloadSections: MOCK_DOWNLOADS as DownloadSection[],
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad() {
|
||||||
|
const win = wx.getWindowInfo();
|
||||||
|
const navBlockHeight = win.statusBarHeight + NAV_INNER_PX;
|
||||||
|
this.setData({
|
||||||
|
statusBarHeight: win.statusBarHeight,
|
||||||
|
navBlockHeight,
|
||||||
|
favScrollHeight: win.windowHeight - navBlockHeight,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
@@ -24,4 +150,33 @@ Page({
|
|||||||
onDiscoverTap() {
|
onDiscoverTap() {
|
||||||
wx.switchTab({ url: '/pages/home/home' });
|
wx.switchTab({ url: '/pages/home/home' });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onSearchTap() {
|
||||||
|
wx.showToast({ title: '搜索功能开发中', icon: 'none' });
|
||||||
|
},
|
||||||
|
|
||||||
|
onRemoveFavorite(e: WechatMiniprogram.TouchEvent) {
|
||||||
|
const id = e.currentTarget.dataset.id as string | undefined;
|
||||||
|
if (!id) return;
|
||||||
|
const list = (this.data.favoriteList as FavoriteItem[]).filter((item) => item.id !== id);
|
||||||
|
this.setData({ favoriteList: list });
|
||||||
|
wx.showToast({ title: '已取消收藏', icon: 'none' });
|
||||||
|
},
|
||||||
|
|
||||||
|
onClearHistory() {
|
||||||
|
wx.showModal({
|
||||||
|
title: '清空下载历史',
|
||||||
|
content: '确定清空本地展示的历史记录吗?',
|
||||||
|
success: (res) => {
|
||||||
|
if (!res.confirm) return;
|
||||||
|
this.setData({ downloadSections: [] });
|
||||||
|
wx.showToast({ title: '已清空', icon: 'none' });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onDownloadMore(e: WechatMiniprogram.TouchEvent) {
|
||||||
|
const id = e.currentTarget.dataset.id as string | undefined;
|
||||||
|
wx.showToast({ title: id ? `更多操作:${id}` : '更多', icon: 'none' });
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,38 +1,216 @@
|
|||||||
<view class="favorites-page">
|
<view class="fav-page">
|
||||||
<view class="favorites-page__title">我的收藏</view>
|
<view class="fav-nav" style="padding-top: {{statusBarHeight}}px;">
|
||||||
|
<view class="fav-nav__inner">
|
||||||
|
<text class="fav-nav__title">我的收藏</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="favorites-page__tabs">
|
<scroll-view
|
||||||
|
class="fav-scroll"
|
||||||
|
style="height: {{favScrollHeight}}px; margin-top: {{navBlockHeight}}px;"
|
||||||
|
scroll-y
|
||||||
|
enhanced
|
||||||
|
show-scrollbar="{{false}}">
|
||||||
|
<view class="fav-body">
|
||||||
|
<view class="fav-seg">
|
||||||
<view
|
<view
|
||||||
class="favorites-page__tab {{activeTab === 'favorites' ? 'favorites-page__tab--active' : ''}}"
|
class="fav-seg__pill {{activeTab === 'favorites' ? 'fav-seg__pill--active' : ''}}"
|
||||||
data-tab="favorites"
|
data-tab="favorites"
|
||||||
bindtap="onTabSwitch"
|
bindtap="onTabSwitch">
|
||||||
>
|
<text class="fav-seg__text">收藏的题型</text>
|
||||||
收藏的题型
|
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
class="favorites-page__tab {{activeTab === 'downloads' ? 'favorites-page__tab--active' : ''}}"
|
class="fav-seg__pill {{activeTab === 'downloads' ? 'fav-seg__pill--active' : ''}}"
|
||||||
data-tab="downloads"
|
data-tab="downloads"
|
||||||
bindtap="onTabSwitch"
|
bindtap="onTabSwitch">
|
||||||
|
<text class="fav-seg__text">下载历史</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 收藏的题型 -->
|
||||||
|
<block wx:if="{{activeTab === 'favorites'}}">
|
||||||
|
<view wx:if="{{favoriteList.length === 0}}" class="fav-empty">
|
||||||
|
<text class="fav-empty__emoji">🦆</text>
|
||||||
|
<text class="fav-empty__msg">鸭丫还没找到收藏呢</text>
|
||||||
|
<text class="fav-empty__sub">去发现好玩的练习纸吧~</text>
|
||||||
|
<button class="fav-empty__btn" bindtap="onDiscoverTap">
|
||||||
|
去发现
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
<view wx:else class="fav-list">
|
||||||
|
<block wx:for="{{favoriteList}}" wx:key="id">
|
||||||
|
<view
|
||||||
|
wx:if="{{item.variant === 'standard'}}"
|
||||||
|
class="fav-card fav-card--row">
|
||||||
|
<image
|
||||||
|
class="fav-card__thumb"
|
||||||
|
src="{{item.thumb}}"
|
||||||
|
mode="aspectFill" />
|
||||||
|
<view class="fav-card__main">
|
||||||
|
<text class="fav-card__title"
|
||||||
|
>{{item.title}}</text
|
||||||
>
|
>
|
||||||
下载历史
|
<view class="fav-card__meta">
|
||||||
|
<text class="fav-card__meta-text"
|
||||||
|
>{{item.metaLine}}</text
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="fav-card__stars"
|
||||||
|
aria-label="{{item.stars}} 星">
|
||||||
|
<van-icon
|
||||||
|
wx:if="{{item.stars >= 1}}"
|
||||||
|
name="star"
|
||||||
|
size="22rpx"
|
||||||
|
color="#d4a900" />
|
||||||
|
<van-icon
|
||||||
|
wx:if="{{item.stars >= 2}}"
|
||||||
|
name="star"
|
||||||
|
size="22rpx"
|
||||||
|
color="#d4a900" />
|
||||||
|
<van-icon
|
||||||
|
wx:if="{{item.stars >= 3}}"
|
||||||
|
name="star"
|
||||||
|
size="22rpx"
|
||||||
|
color="#d4a900" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<text class="fav-card__badge"
|
||||||
|
>{{item.timeBadge}}</text
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="fav-card__heart"
|
||||||
|
data-id="{{item.id}}"
|
||||||
|
catchtap="onRemoveFavorite"
|
||||||
|
aria-role="button"
|
||||||
|
aria-label="取消收藏">
|
||||||
|
<van-icon
|
||||||
|
name="like"
|
||||||
|
size="40rpx"
|
||||||
|
color="#b02500" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
wx:elif="{{item.variant === 'featured'}}"
|
||||||
|
class="fav-card fav-card--bento">
|
||||||
|
<view class="fav-bento__content">
|
||||||
|
<text class="fav-card__title fav-bento__title"
|
||||||
|
>{{item.title}}</text
|
||||||
|
>
|
||||||
|
<text class="fav-bento__meta"
|
||||||
|
>{{item.metaLine}}</text
|
||||||
|
>
|
||||||
|
<view class="fav-bento__tags">
|
||||||
|
<text
|
||||||
|
wx:for="{{item.tags}}"
|
||||||
|
wx:for-item="tag"
|
||||||
|
wx:key="*this"
|
||||||
|
class="fav-bento__tag"
|
||||||
|
># {{tag}}</text
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<van-icon
|
||||||
|
class="fav-bento__deco"
|
||||||
|
name="font-o"
|
||||||
|
size="200rpx"
|
||||||
|
color="rgba(108, 90, 0, 0.12)" />
|
||||||
|
<view
|
||||||
|
class="fav-bento__heart"
|
||||||
|
data-id="{{item.id}}"
|
||||||
|
catchtap="onRemoveFavorite"
|
||||||
|
aria-role="button">
|
||||||
|
<van-icon
|
||||||
|
name="like"
|
||||||
|
size="40rpx"
|
||||||
|
color="#b02500" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view wx:if="{{favoriteList.length > 0}}" class="fav-cta">
|
||||||
|
<text class="fav-cta__hint">发现更多有趣的内容?</text>
|
||||||
|
<button class="fav-cta__btn" bindtap="onDiscoverTap">
|
||||||
|
去发现页看看
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
<view wx:if="{{activeTab === 'favorites' && favoriteList.length === 0}}" class="favorites-page__empty">
|
<!-- 下载历史 -->
|
||||||
<text class="favorites-page__emoji">🦆</text>
|
<block wx:if="{{activeTab === 'downloads'}}">
|
||||||
<view class="favorites-page__empty-msg">
|
<view
|
||||||
<text class="favorites-page__empty-line">鸭丫还没找到收藏呢</text>
|
wx:if="{{downloadSections.length === 0}}"
|
||||||
<text class="favorites-page__empty-line">去发现好玩的练习纸吧~</text>
|
class="fav-empty">
|
||||||
|
<van-icon
|
||||||
|
name="clock"
|
||||||
|
size="120rpx"
|
||||||
|
color="#b3ac9f"
|
||||||
|
class="fav-empty__icon" />
|
||||||
|
<text class="fav-empty__msg">暂无下载记录</text>
|
||||||
|
<button class="fav-empty__btn" bindtap="onDiscoverTap">
|
||||||
|
去发现
|
||||||
|
</button>
|
||||||
</view>
|
</view>
|
||||||
<button class="favorites-page__btn" bindtap="onDiscoverTap">去发现</button>
|
<view wx:else class="fav-dl">
|
||||||
|
<block
|
||||||
|
wx:for="{{downloadSections}}"
|
||||||
|
wx:for-item="section"
|
||||||
|
wx:key="key">
|
||||||
|
<text class="fav-dl__section-label"
|
||||||
|
>{{section.label}}</text
|
||||||
|
>
|
||||||
|
<view class="fav-dl__items">
|
||||||
|
<view
|
||||||
|
wx:for="{{section.items}}"
|
||||||
|
wx:for-item="row"
|
||||||
|
wx:key="id"
|
||||||
|
class="fav-dl-row {{row.placeholder === 'draw' ? 'fav-dl-row--muted' : ''}}">
|
||||||
|
<view
|
||||||
|
wx:if="{{row.placeholder === 'draw'}}"
|
||||||
|
class="fav-dl-row__thumb fav-dl-row__thumb--ph">
|
||||||
|
<van-icon
|
||||||
|
name="brush-o"
|
||||||
|
size="56rpx"
|
||||||
|
color="#6d5720" />
|
||||||
</view>
|
</view>
|
||||||
|
<image
|
||||||
<view wx:elif="{{activeTab === 'downloads' && downloadList.length === 0}}" class="favorites-page__empty">
|
wx:else
|
||||||
<text class="favorites-page__emoji">🦆</text>
|
class="fav-dl-row__thumb"
|
||||||
<view class="favorites-page__empty-msg">
|
src="{{row.thumb}}"
|
||||||
<text class="favorites-page__empty-line">还没有下载记录哦</text>
|
mode="aspectFill" />
|
||||||
<text class="favorites-page__empty-line">快去生成练习纸吧~</text>
|
<view class="fav-dl-row__main">
|
||||||
</view>
|
<text class="fav-dl-row__title"
|
||||||
<button class="favorites-page__btn" bindtap="onDiscoverTap">去发现</button>
|
>{{row.title}}</text
|
||||||
|
>
|
||||||
|
<view class="fav-dl-row__meta">
|
||||||
|
<van-icon
|
||||||
|
name="clock"
|
||||||
|
size="26rpx"
|
||||||
|
color="#605b50" />
|
||||||
|
<text class="fav-dl-row__time"
|
||||||
|
>{{row.time}}</text
|
||||||
|
>
|
||||||
|
<view class="fav-dl-row__dot" />
|
||||||
|
<text
|
||||||
|
class="fav-dl-row__status {{row.statusHighlight ? 'fav-dl-row__status--hi' : ''}}"
|
||||||
|
>{{row.status}}</text
|
||||||
|
>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view
|
||||||
|
class="fav-dl-row__more"
|
||||||
|
data-id="{{row.id}}"
|
||||||
|
catchtap="onDownloadMore">
|
||||||
|
<van-icon
|
||||||
|
name="ellipsis"
|
||||||
|
size="40rpx"
|
||||||
|
color="#7c766a" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
|||||||
@@ -0,0 +1,748 @@
|
|||||||
|
import { AGE_BANDS } from '../../core/data/difficulty';
|
||||||
|
|
||||||
|
export type HomeDisplayItem = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
description?: string;
|
||||||
|
category: 'math' | 'chinese' | 'english' | 'puzzle' | 'craft';
|
||||||
|
ageBand: string;
|
||||||
|
difficulty: '入门' | '基础' | '进阶' | '挑战';
|
||||||
|
icon: string;
|
||||||
|
badge?: string;
|
||||||
|
path: string;
|
||||||
|
available: boolean;
|
||||||
|
source?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HomeDisplaySection = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
morePath?: string;
|
||||||
|
items: HomeDisplayItem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HomeDisplayDataset = {
|
||||||
|
searchPlaceholder: string;
|
||||||
|
categoryTabs: Array<{
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
path?: string;
|
||||||
|
}>;
|
||||||
|
ageBands: Array<{
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
desc: string;
|
||||||
|
path: string;
|
||||||
|
}>;
|
||||||
|
featured: HomeDisplayItem[];
|
||||||
|
hot: HomeDisplayItem[];
|
||||||
|
sections: HomeDisplaySection[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const HOME_CATEGORY_TABS = [
|
||||||
|
{ id: 'all', name: '全部' },
|
||||||
|
{ id: 'math', name: '数感启蒙' },
|
||||||
|
{ id: 'puzzle', name: '益智游戏' },
|
||||||
|
{ id: 'chinese', name: '趣味识字' },
|
||||||
|
{ id: 'english', name: '英语启蒙' },
|
||||||
|
{ id: 'craft', name: '创意手工' },
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const HOME_AGE_BANDS = AGE_BANDS.map((item, index) => ({
|
||||||
|
key: item.key,
|
||||||
|
label: item.label,
|
||||||
|
desc: ['启蒙认知', '基础练习', '能力提升', '幼小衔接', '知识拓展'][index],
|
||||||
|
path: '/pages/age/age',
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const HOME_PRODUCT_TARGET_DATA: HomeDisplayDataset = {
|
||||||
|
searchPlaceholder: '搜索你喜欢的练习册...',
|
||||||
|
categoryTabs: [...HOME_CATEGORY_TABS],
|
||||||
|
ageBands: HOME_AGE_BANDS,
|
||||||
|
featured: [
|
||||||
|
{
|
||||||
|
id: 'target-featured-1',
|
||||||
|
title: '圣诞主题涂色卡',
|
||||||
|
subtitle: '节日限定创意内容',
|
||||||
|
description: '首页推荐位示例,强调季节热点与真实打印效果。',
|
||||||
|
category: 'craft',
|
||||||
|
ageBand: '3-8岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '🎄',
|
||||||
|
badge: 'NEW',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 5.1 今日推荐',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-featured-2',
|
||||||
|
title: '走迷宫大挑战',
|
||||||
|
subtitle: '热门趣味训练',
|
||||||
|
description: '产品规划中的高趣味内容,用于首页焦点推荐。',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '4-7岁',
|
||||||
|
difficulty: '进阶',
|
||||||
|
icon: '🌀',
|
||||||
|
badge: 'HOT',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P2-22',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-featured-3',
|
||||||
|
title: '拼音描红',
|
||||||
|
subtitle: '幼小衔接高频内容',
|
||||||
|
description: '语文模块重点新增内容,适合推荐位曝光。',
|
||||||
|
category: 'chinese',
|
||||||
|
ageBand: '5-7岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🔤',
|
||||||
|
badge: '推荐',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P1-12',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hot: [
|
||||||
|
{
|
||||||
|
id: 'target-hot-1',
|
||||||
|
title: '迷宫',
|
||||||
|
subtitle: '高趣味路径探索',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '4-7岁',
|
||||||
|
difficulty: '进阶',
|
||||||
|
icon: '🧭',
|
||||||
|
badge: '热门',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 5.1 热门下载',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-hot-2',
|
||||||
|
title: '涂色卡',
|
||||||
|
subtitle: '动物与节日主题',
|
||||||
|
category: 'craft',
|
||||||
|
ageBand: '3-6岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '🎨',
|
||||||
|
badge: '热门',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P3-29',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-hot-3',
|
||||||
|
title: '加减法',
|
||||||
|
subtitle: '家长高频打印内容',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '5-7岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '➕',
|
||||||
|
badge: '热门',
|
||||||
|
path: '/mathPages/addition/addition',
|
||||||
|
available: true,
|
||||||
|
source: '现有加减法页面可承接',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
id: 'math',
|
||||||
|
title: '数学启蒙',
|
||||||
|
subtitle: '数字认知、计数练习、加减运算、时钟与形状',
|
||||||
|
morePath: '/pages/mathIndex/mathIndex',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'target-math-1',
|
||||||
|
title: '数字认知',
|
||||||
|
subtitle: '认识数字 1-10',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '3-4岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '🔢',
|
||||||
|
path: '/mathPages/numberFind/numberFind',
|
||||||
|
available: true,
|
||||||
|
source: '现有 找数字/写数字 能力',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-math-2',
|
||||||
|
title: '计数练习',
|
||||||
|
subtitle: '数一数、连一连、选一选',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '4-5岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🧮',
|
||||||
|
path: '/mathPages/countMatch/countMatch',
|
||||||
|
available: true,
|
||||||
|
source: '现有 countMatch/countingSelect',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-math-3',
|
||||||
|
title: '加减运算',
|
||||||
|
subtitle: '从 5 以内到 100 以内',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '5-7岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '➕',
|
||||||
|
path: '/mathPages/addition/addition',
|
||||||
|
available: true,
|
||||||
|
source: '现有 addition/calculationPractice',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-math-4',
|
||||||
|
title: '时钟练习',
|
||||||
|
subtitle: '认识钟表与时间',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '5-7岁',
|
||||||
|
difficulty: '进阶',
|
||||||
|
icon: '🕒',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P1-7',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-math-5',
|
||||||
|
title: '形状认知',
|
||||||
|
subtitle: '图形分类与空间感',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '3-5岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '📐',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 3.1 信息架构',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'chinese',
|
||||||
|
title: '语文启蒙',
|
||||||
|
subtitle: '识字、练字、拼音、表达训练',
|
||||||
|
morePath: '/pages/index/index',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'target-chinese-1',
|
||||||
|
title: '识字卡',
|
||||||
|
subtitle: '自定义汉字卡片',
|
||||||
|
category: 'chinese',
|
||||||
|
ageBand: '3-6岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '📖',
|
||||||
|
path: '/pages/index/index',
|
||||||
|
available: true,
|
||||||
|
source: '现有识字页',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-chinese-2',
|
||||||
|
title: '练字帖',
|
||||||
|
subtitle: '田字格笔顺练习',
|
||||||
|
category: 'chinese',
|
||||||
|
ageBand: '4-7岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '✏️',
|
||||||
|
path: '/pages/copyBook/copyBook',
|
||||||
|
available: true,
|
||||||
|
source: '现有练字页',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-chinese-3',
|
||||||
|
title: '拼音练习',
|
||||||
|
subtitle: '声母韵母描红',
|
||||||
|
category: 'chinese',
|
||||||
|
ageBand: '5-7岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🔤',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P1-12',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-chinese-4',
|
||||||
|
title: '看图说话',
|
||||||
|
subtitle: '图片引导表达',
|
||||||
|
category: 'chinese',
|
||||||
|
ageBand: '5-7岁',
|
||||||
|
difficulty: '进阶',
|
||||||
|
icon: '🗣️',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P1-15',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'english',
|
||||||
|
title: '英语启蒙',
|
||||||
|
subtitle: '字母学习、闪卡、描红与自然拼读',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'target-english-1',
|
||||||
|
title: '字母描红',
|
||||||
|
subtitle: 'A-Z 大小写练习',
|
||||||
|
category: 'english',
|
||||||
|
ageBand: '4-6岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '🔠',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P1-17',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-english-2',
|
||||||
|
title: '字母闪卡',
|
||||||
|
subtitle: '字母与单词联想',
|
||||||
|
category: 'english',
|
||||||
|
ageBand: '3-6岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '🪪',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P1-18',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-english-3',
|
||||||
|
title: '自然拼读练习纸',
|
||||||
|
subtitle: 'CVC 单词启蒙',
|
||||||
|
category: 'english',
|
||||||
|
ageBand: '5-7岁',
|
||||||
|
difficulty: '进阶',
|
||||||
|
icon: '🔡',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P1-21',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'puzzle',
|
||||||
|
title: '益智游戏',
|
||||||
|
subtitle: '迷宫、找不同、连线、数独与控笔',
|
||||||
|
morePath: '/pages/focusIndex/focusIndex',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'target-puzzle-1',
|
||||||
|
title: '迷宫',
|
||||||
|
subtitle: '不同难度路径挑战',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '4-7岁',
|
||||||
|
difficulty: '进阶',
|
||||||
|
icon: '🌀',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P2-22',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-puzzle-2',
|
||||||
|
title: '找不同',
|
||||||
|
subtitle: '观察力与专注力训练',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '4-7岁',
|
||||||
|
difficulty: '进阶',
|
||||||
|
icon: '🔍',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P2-23',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-puzzle-3',
|
||||||
|
title: '连线题',
|
||||||
|
subtitle: '数字点连线与物品连线',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '4-6岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🧵',
|
||||||
|
path: '/focusPages/dotConnect/dotConnect',
|
||||||
|
available: true,
|
||||||
|
source: '现有 dotConnect/matchConnect',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-puzzle-4',
|
||||||
|
title: '数独入门',
|
||||||
|
subtitle: '4x4 / 6x6 逻辑启蒙',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '6-8岁',
|
||||||
|
difficulty: '挑战',
|
||||||
|
icon: '🧠',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P2-24',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'craft',
|
||||||
|
title: '创意手工',
|
||||||
|
subtitle: '涂色卡、折纸、贴纸和主题手工',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'target-craft-1',
|
||||||
|
title: '涂色卡',
|
||||||
|
subtitle: '动物、交通、节日主题',
|
||||||
|
category: 'craft',
|
||||||
|
ageBand: '3-6岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '🎨',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P3-29',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-craft-2',
|
||||||
|
title: '折纸模板',
|
||||||
|
subtitle: '打印后即可折叠',
|
||||||
|
category: 'craft',
|
||||||
|
ageBand: '4-7岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🪭',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P3-30',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'target-craft-3',
|
||||||
|
title: '贴纸打印',
|
||||||
|
subtitle: '奖励贴纸与装饰贴纸',
|
||||||
|
category: 'craft',
|
||||||
|
ageBand: '3-8岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '⭐',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品设计文档 P3-33',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HOME_CURRENT_CAPABILITY_DATA: HomeDisplayDataset = {
|
||||||
|
searchPlaceholder: '搜索你喜欢的练习册...',
|
||||||
|
categoryTabs: [...HOME_CATEGORY_TABS],
|
||||||
|
ageBands: HOME_AGE_BANDS,
|
||||||
|
featured: [
|
||||||
|
{
|
||||||
|
id: 'current-featured-1',
|
||||||
|
title: '10以内加减法',
|
||||||
|
subtitle: '最适合首页推荐的高频内容',
|
||||||
|
description: '现有数学能力中最接近产品文档“热门下载”的内容。',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '5-6岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '➕',
|
||||||
|
badge: 'HOT',
|
||||||
|
path: '/mathPages/addition/addition',
|
||||||
|
available: true,
|
||||||
|
source: '现有功能清单 addition',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-featured-2',
|
||||||
|
title: '涂色识字卡',
|
||||||
|
subtitle: '兼顾识字与趣味涂色',
|
||||||
|
description: '当前最接近创意内容的主包能力,可承接语文与创意入口。',
|
||||||
|
category: 'chinese',
|
||||||
|
ageBand: '3-6岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '📚',
|
||||||
|
badge: '推荐',
|
||||||
|
path: '/pages/index/index',
|
||||||
|
available: true,
|
||||||
|
source: '现有识字页',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-featured-3',
|
||||||
|
title: '数字点连线',
|
||||||
|
subtitle: '用连点成图提升专注力',
|
||||||
|
description: '能承担产品文档中“益智游戏”内容氛围。',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '4-6岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🔗',
|
||||||
|
badge: '热门',
|
||||||
|
path: '/focusPages/dotConnect/dotConnect',
|
||||||
|
available: true,
|
||||||
|
source: '现有功能清单 dot-connect',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hot: [
|
||||||
|
{
|
||||||
|
id: 'current-hot-1',
|
||||||
|
title: '找数字,涂一涂',
|
||||||
|
subtitle: '低龄启蒙高频内容',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '3-4岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '🔢',
|
||||||
|
badge: '热门',
|
||||||
|
path: '/mathPages/numberFind/numberFind',
|
||||||
|
available: true,
|
||||||
|
source: 'number-find',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-hot-2',
|
||||||
|
title: '数一数,连一连',
|
||||||
|
subtitle: '点数和数字对应',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '4-5岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🧮',
|
||||||
|
badge: '热门',
|
||||||
|
path: '/mathPages/countMatch/countMatch',
|
||||||
|
available: true,
|
||||||
|
source: 'counting-matching',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-hot-3',
|
||||||
|
title: '格子仿画 5×5',
|
||||||
|
subtitle: '图形观察与耐心训练',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '5-7岁',
|
||||||
|
difficulty: '进阶',
|
||||||
|
icon: '🟨',
|
||||||
|
badge: '热门',
|
||||||
|
path: '/focusPages/gridDrawing/gridDrawing',
|
||||||
|
available: true,
|
||||||
|
source: 'grid-drawing-5x5',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
id: 'math',
|
||||||
|
title: '数感启蒙',
|
||||||
|
subtitle: '优先展示现有高价值、高覆盖的数感与运算内容',
|
||||||
|
morePath: '/pages/mathIndex/mathIndex',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'current-math-1',
|
||||||
|
title: '数字认知',
|
||||||
|
subtitle: '找数字、写数字',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '3-4岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '🔢',
|
||||||
|
path: '/mathPages/numberFind/numberFind',
|
||||||
|
available: true,
|
||||||
|
source: 'number-find / number-write',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-math-2',
|
||||||
|
title: '计数练习',
|
||||||
|
subtitle: '数一数、连一连、选一选',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '4-5岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🧮',
|
||||||
|
path: '/mathPages/countMatch/countMatch',
|
||||||
|
available: true,
|
||||||
|
source: 'countMatch / countingSelect',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-math-3',
|
||||||
|
title: '数字序列',
|
||||||
|
subtitle: '数字排序与缺失填空',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '4-5岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '📈',
|
||||||
|
path: '/mathPages/numberSort/numberSort',
|
||||||
|
available: true,
|
||||||
|
source: 'numberSort / missingNumber',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-math-4',
|
||||||
|
title: '加减运算',
|
||||||
|
subtitle: '5以内到100以内逐步进阶',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '5-7岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '➕',
|
||||||
|
path: '/mathPages/addition/addition',
|
||||||
|
available: true,
|
||||||
|
source: 'addition / calculationPractice',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-math-5',
|
||||||
|
title: '乘法口诀',
|
||||||
|
subtitle: '九九乘法表启蒙',
|
||||||
|
category: 'math',
|
||||||
|
ageBand: '7-8岁',
|
||||||
|
difficulty: '挑战',
|
||||||
|
icon: '✖️',
|
||||||
|
path: '/mathPages/multiplicationTable/multiplicationTable',
|
||||||
|
available: true,
|
||||||
|
source: 'multiplicationTable',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'chinese',
|
||||||
|
title: '趣味识字',
|
||||||
|
subtitle: '用现有识字与练字能力先覆盖核心语文场景',
|
||||||
|
morePath: '/pages/index/index',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'current-chinese-1',
|
||||||
|
title: '识字卡',
|
||||||
|
subtitle: '最多 6 个汉字,自定义颜色',
|
||||||
|
category: 'chinese',
|
||||||
|
ageBand: '3-6岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '📖',
|
||||||
|
path: '/pages/index/index',
|
||||||
|
available: true,
|
||||||
|
source: 'pages/index/index',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-chinese-2',
|
||||||
|
title: '找一找识字',
|
||||||
|
subtitle: '识字 find 模板,更接近游戏化练习',
|
||||||
|
category: 'chinese',
|
||||||
|
ageBand: '4-6岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🔍',
|
||||||
|
path: '/pages/index/index',
|
||||||
|
available: true,
|
||||||
|
source: '识字页 find 模板',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-chinese-3',
|
||||||
|
title: '笔顺练字帖',
|
||||||
|
subtitle: '田字格与笔顺描红',
|
||||||
|
category: 'chinese',
|
||||||
|
ageBand: '4-7岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '✏️',
|
||||||
|
path: '/pages/copyBook/copyBook',
|
||||||
|
available: true,
|
||||||
|
source: 'pages/copyBook/copyBook',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'puzzle',
|
||||||
|
title: '益智游戏',
|
||||||
|
subtitle: '从现有专注力模块中抽取最符合产品重设计的内容',
|
||||||
|
morePath: '/pages/focusIndex/focusIndex',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'current-puzzle-1',
|
||||||
|
title: '数字点连线',
|
||||||
|
subtitle: '按顺序连点成图',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '4-6岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🔗',
|
||||||
|
path: '/focusPages/dotConnect/dotConnect',
|
||||||
|
available: true,
|
||||||
|
source: 'dot-connect',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-puzzle-2',
|
||||||
|
title: '连连看',
|
||||||
|
subtitle: '物品配对与关系匹配',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '4-6岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🧵',
|
||||||
|
path: '/focusPages/matchConnect/matchConnect',
|
||||||
|
available: true,
|
||||||
|
source: 'match-connect',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-puzzle-3',
|
||||||
|
title: '颜色找规律',
|
||||||
|
subtitle: '模式识别与推理',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '4-6岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🌈',
|
||||||
|
path: '/focusPages/colorPattern/colorPattern',
|
||||||
|
available: true,
|
||||||
|
source: 'color-pattern',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-puzzle-4',
|
||||||
|
title: '方格推理',
|
||||||
|
subtitle: '逻辑关系与观察力',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '5-7岁',
|
||||||
|
difficulty: '进阶',
|
||||||
|
icon: '🧠',
|
||||||
|
path: '/focusPages/gridReasoning/gridReasoning',
|
||||||
|
available: true,
|
||||||
|
source: 'grid-reasoning',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-puzzle-5',
|
||||||
|
title: '格子仿画',
|
||||||
|
subtitle: '3×3 / 5×5 / 7×7 逐级挑战',
|
||||||
|
category: 'puzzle',
|
||||||
|
ageBand: '4-7岁',
|
||||||
|
difficulty: '进阶',
|
||||||
|
icon: '🟨',
|
||||||
|
path: '/focusPages/gridDrawing/gridDrawing',
|
||||||
|
available: true,
|
||||||
|
source: 'grid-drawing',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'craft',
|
||||||
|
title: '创意手工',
|
||||||
|
subtitle: '暂用最接近创意表达的现有能力承接展示位',
|
||||||
|
morePath: '/pages/index/index',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'current-craft-1',
|
||||||
|
title: '涂色识字卡',
|
||||||
|
subtitle: '在识字场景里提供涂色表达',
|
||||||
|
category: 'craft',
|
||||||
|
ageBand: '3-6岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '🎨',
|
||||||
|
path: '/pages/index/index',
|
||||||
|
available: true,
|
||||||
|
source: '现有识字卡着色能力',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'current-craft-2',
|
||||||
|
title: '字帖打印',
|
||||||
|
subtitle: '打印后可反复练习',
|
||||||
|
category: 'craft',
|
||||||
|
ageBand: '4-7岁',
|
||||||
|
difficulty: '基础',
|
||||||
|
icon: '🖌️',
|
||||||
|
path: '/pages/copyBook/copyBook',
|
||||||
|
available: true,
|
||||||
|
source: '练字页打印能力',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'english',
|
||||||
|
title: '英语启蒙',
|
||||||
|
subtitle:
|
||||||
|
'当前暂无真实英语页面,先保留结构占位,便于首页保持完整信息架构',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'current-english-1',
|
||||||
|
title: '英语启蒙即将上线',
|
||||||
|
subtitle: '字母描红、闪卡、自然拼读',
|
||||||
|
category: 'english',
|
||||||
|
ageBand: '4-7岁',
|
||||||
|
difficulty: '入门',
|
||||||
|
icon: '🔤',
|
||||||
|
badge: 'Soon',
|
||||||
|
path: '',
|
||||||
|
available: false,
|
||||||
|
source: '产品目标结构保留位',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HOME_DISPLAY_DATA = {
|
||||||
|
productTarget: HOME_PRODUCT_TARGET_DATA,
|
||||||
|
currentCapability: HOME_CURRENT_CAPABILITY_DATA,
|
||||||
|
} as const;
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
@import '../../style/theme3.less';
|
@import '../../style/theme3.less';
|
||||||
|
|
||||||
@home-padding: 28rpx;
|
|
||||||
@home-section-mt: 48rpx;
|
|
||||||
@home-track-gap: 16rpx;
|
@home-track-gap: 16rpx;
|
||||||
|
|
||||||
.home-page {
|
.home-page {
|
||||||
@@ -10,16 +8,23 @@
|
|||||||
padding-bottom: 48rpx;
|
padding-bottom: 48rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: @text-secondary;
|
color: @text-secondary;
|
||||||
// padding: 0 24rpx 48rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-nav {
|
.home-nav {
|
||||||
background: @bg-header;
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background: fade(@bg-header, 85%);
|
||||||
|
backdrop-filter: blur(40rpx);
|
||||||
|
-webkit-backdrop-filter: blur(40rpx);
|
||||||
|
box-shadow: 0 2rpx 12rpx rgba(50, 46, 37, 0.05);
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-nav__inner {
|
.home-nav__inner {
|
||||||
height: 44px;
|
height: @nav-inner-height;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -35,15 +40,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.home-nav__name {
|
.home-nav__name {
|
||||||
font-size: 17px;
|
font-size: @fs-nav-title;
|
||||||
font-weight: 700;
|
font-weight: @fw-nav-title;
|
||||||
color: @text-title;
|
color: @color-nav-title;
|
||||||
|
letter-spacing: @ls-nav-title;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.home-body {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
.home-search-wrap {
|
.home-search-wrap {
|
||||||
margin-top: 28rpx;
|
margin-top: @section-gap-xs;
|
||||||
padding: 0 @home-padding;
|
padding: 0 @page-padding-x;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,26 +81,117 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.home-tabs-wrap {
|
.home-tabs-wrap {
|
||||||
margin-top: 48rpx;
|
margin-top: @section-gap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-hero-placeholder {
|
.home-hero-placeholder {
|
||||||
// margin: 8rpx auto 0;
|
margin: @section-gap @page-padding-x 0;
|
||||||
margin: 48rpx 24rpx 0;
|
|
||||||
// width: 684rpx;
|
|
||||||
height: 480rpx;
|
height: 480rpx;
|
||||||
border-radius: 40rpx;
|
border-radius: 40rpx;
|
||||||
background: rgba(50, 46, 37, 0.04);
|
background: rgba(50, 46, 37, 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-section-panel {
|
.home-track-row--hero {
|
||||||
margin-top: @home-section-mt;
|
padding-left: @page-padding-x;
|
||||||
padding: 0 @home-padding;
|
padding-top: 24rpx;
|
||||||
box-sizing: border-box;
|
padding-bottom: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-section-panel--hot {
|
.home-hero-card {
|
||||||
margin-top: @home-section-mt;
|
width: 560rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 32rpx;
|
||||||
|
/* 让阴影不被自身 overflow: hidden 裁切 */
|
||||||
|
overflow: visible;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 10rpx 28rpx rgba(50, 46, 37, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-hero-card__top {
|
||||||
|
height: 260rpx;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
/* 顶部背景用自身圆角裁切,替代 card 的 overflow: hidden */
|
||||||
|
border-top-left-radius: 32rpx;
|
||||||
|
border-top-right-radius: 32rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-hero-card__icon {
|
||||||
|
font-size: 96rpx;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-hero-card__badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 24rpx;
|
||||||
|
right: 24rpx;
|
||||||
|
padding: 8rpx 18rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: rgba(50, 46, 37, 0.12);
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: @text-title;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-hero-card__body {
|
||||||
|
padding: 28rpx @page-padding-inner-x 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-hero-card__title-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16rpx;
|
||||||
|
/* 允许 flex 子项在文本过长时正确截断 */
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-hero-card__title {
|
||||||
|
font-size: 34rpx;
|
||||||
|
line-height: 1.35;
|
||||||
|
color: @text-title;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
/* 标题与 meta 同行:超出后省略号(避免高度抖动) */
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-hero-card__sub {
|
||||||
|
margin-top: 10rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: @text-secondary;
|
||||||
|
/* 第二行:超出后省略号 */
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.home-hero-card__meta {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: @text-gray;
|
||||||
|
/* meta 也做单行截断,防止极端长文本把布局挤爆 */
|
||||||
|
flex: 0 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-section-panel {
|
||||||
|
margin-top: @section-gap;
|
||||||
|
padding: 0 @page-padding-x;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-section-head {
|
.home-section-head {
|
||||||
@@ -99,7 +201,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.home-section-head__title {
|
.home-section-head__title {
|
||||||
font-size: 32rpx;
|
font-size: @fs-section-head-title;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: @text-title;
|
color: @text-title;
|
||||||
}
|
}
|
||||||
@@ -110,26 +212,27 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.home-section-head__title--module {
|
.home-section-head__title--module {
|
||||||
font-size: 28rpx;
|
font-size: @fs-section-head-title;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-track-scroll {
|
.home-track-scroll {
|
||||||
margin-top: 24rpx;
|
margin-top: @section-gap-sm;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
padding: 16rpx 0 20rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-track-row {
|
.home-track-row {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: @home-track-gap;
|
gap: @section-gap-sm;
|
||||||
padding-right: @home-padding;
|
padding-right: @page-padding-x;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 可视约 2.2 张:2*w + 2*gap + 0.2*w ≈ 屏宽减左右 padding */
|
|
||||||
.home-track-card {
|
.home-track-card {
|
||||||
width: calc((750rpx - 2 * @home-padding - 2 * @home-track-gap) / 2.2);
|
width: calc((750rpx - 2 * @page-padding-x - 2 * @home-track-gap) / 2.2);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -150,7 +253,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.home-track-card__body {
|
.home-track-card__body {
|
||||||
padding: 20rpx 18rpx 22rpx;
|
padding: 20rpx @page-padding-inner-x 22rpx;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +280,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.home-age-scroll {
|
.home-age-scroll {
|
||||||
margin-top: 32rpx;
|
margin-top: @section-gap-sm;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
@@ -186,12 +289,11 @@
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: 12rpx;
|
gap: 12rpx;
|
||||||
padding-right: @home-padding;
|
padding-right: @page-padding-x;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-age-item {
|
.home-age-item {
|
||||||
/* 目标:首屏露出 3.5 个(第 4 个露出约 50%) */
|
width: calc((750rpx - 2 * @page-padding-x - 36rpx) / 3.5);
|
||||||
width: calc((750rpx - 48rpx - 36rpx) / 3.5);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -225,17 +327,24 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.home-age-item__desc {
|
||||||
|
margin-top: 8rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: @text-gray;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.home-hot-list {
|
.home-hot-list {
|
||||||
margin-top: 36rpx;
|
margin-top: @section-gap-sm;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 28rpx;
|
gap: @section-gap-stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-hot-card {
|
.home-hot-card {
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
padding: 24rpx;
|
padding: 24rpx @page-padding-inner-x;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20rpx;
|
gap: 20rpx;
|
||||||
@@ -246,7 +355,6 @@
|
|||||||
width: 144rpx;
|
width: 144rpx;
|
||||||
height: 144rpx;
|
height: 144rpx;
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
background: linear-gradient(140deg, #ad060f 0%, #d93b0d 40%, #a20606 100%);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -289,7 +397,7 @@
|
|||||||
.home-hot-card__tag {
|
.home-hot-card__tag {
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
color: @text-selected-btn;
|
color: @text-selected-btn;
|
||||||
background: #ffd709;
|
background: @brand;
|
||||||
border-radius: 999rpx;
|
border-radius: 999rpx;
|
||||||
padding: 4rpx 16rpx;
|
padding: 4rpx 16rpx;
|
||||||
}
|
}
|
||||||
@@ -303,7 +411,7 @@
|
|||||||
width: 56rpx;
|
width: 56rpx;
|
||||||
height: 56rpx;
|
height: 56rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #ffd709;
|
background: @brand;
|
||||||
color: #2b2b2b;
|
color: #2b2b2b;
|
||||||
font-size: 36rpx;
|
font-size: 36rpx;
|
||||||
line-height: 56rpx;
|
line-height: 56rpx;
|
||||||
@@ -311,6 +419,22 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.home-section-panel__sub {
|
||||||
|
margin-top: 10rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: @text-gray;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-track-card__meta {
|
||||||
|
margin-top: 12rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: @text-gray;
|
||||||
|
line-height: 1.3;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.home-page .category-tabs {
|
.home-page .category-tabs {
|
||||||
background: @bg-page;
|
background: @bg-page;
|
||||||
}
|
}
|
||||||
@@ -321,7 +445,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.home-page .category-tabs__pill--active {
|
.home-page .category-tabs__pill--active {
|
||||||
background: #ffd709;
|
background: @brand;
|
||||||
color: @text-selected-btn;
|
color: @text-selected-btn;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
@@ -1,169 +1,185 @@
|
|||||||
import { CATEGORIES } from '../../core/data/categories';
|
import { NAV_INNER_PX } from '../../utils/navMetrics';
|
||||||
import { AGE_BANDS, AgeBandKey } from '../../core/data/difficulty';
|
import {
|
||||||
|
HOME_CURRENT_CAPABILITY_DATA,
|
||||||
|
type HomeDisplayItem,
|
||||||
|
type HomeDisplaySection,
|
||||||
|
} from './home.data';
|
||||||
|
|
||||||
const CATEGORY_TABS = [
|
type AgeBandKey = string;
|
||||||
{ id: 'all', name: '全部' },
|
|
||||||
...CATEGORIES.map((c) => ({ id: c.id, name: c.name })),
|
|
||||||
];
|
|
||||||
|
|
||||||
const AGE_BAND_ICONS = ['🌱', '🚀', '🎓', '🧠', '🏆'] as const;
|
type HomeTab = {
|
||||||
|
|
||||||
type HomeTrackCard = {
|
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
name: string;
|
||||||
subtitle: string;
|
};
|
||||||
|
|
||||||
|
type HomeAgeBandView = {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
desc: string;
|
||||||
|
path: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type HomeDisplayItemView = HomeDisplayItem & {
|
||||||
topBg: string;
|
topBg: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MOCK_MATH_TRACK: HomeTrackCard[] = [
|
type HomeDisplaySectionView = HomeDisplaySection & {
|
||||||
{
|
anchorId: string;
|
||||||
id: 'm1',
|
items: HomeDisplayItemView[];
|
||||||
title: '认识数字1-10',
|
};
|
||||||
subtitle: '启蒙第一课',
|
|
||||||
icon: '🔢',
|
|
||||||
topBg: '#fff3c4',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'm2',
|
|
||||||
title: '形状对对碰',
|
|
||||||
subtitle: '空间感训练',
|
|
||||||
icon: '📐',
|
|
||||||
topBg: '#f5e6dc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'm3',
|
|
||||||
title: '数量比一比',
|
|
||||||
subtitle: '数感小游戏',
|
|
||||||
icon: '⚖️',
|
|
||||||
topBg: '#d8f0d0',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'm4',
|
|
||||||
title: '规律找一找',
|
|
||||||
subtitle: '逻辑思维',
|
|
||||||
icon: '🔍',
|
|
||||||
topBg: '#e8f4ff',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'm5',
|
|
||||||
title: '简单加减',
|
|
||||||
subtitle: '动手练一练',
|
|
||||||
icon: '➕',
|
|
||||||
topBg: '#fce4ec',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const MOCK_CHINESE_TRACK: HomeTrackCard[] = [
|
const AGE_BAND_ICONS = ['🌱', '🚀', '🎓', '🧠', '🏆'] as const;
|
||||||
{
|
|
||||||
id: 'c1',
|
|
||||||
title: '基础笔画连连看',
|
|
||||||
subtitle: '书法初体验',
|
|
||||||
icon: '🖌',
|
|
||||||
topBg: '#f5e6dc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'c2',
|
|
||||||
title: '看图识汉字',
|
|
||||||
subtitle: '字形联想',
|
|
||||||
icon: '📖',
|
|
||||||
topBg: '#d8f0d0',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'c3',
|
|
||||||
title: '拼音小闯关',
|
|
||||||
subtitle: '声母韵母',
|
|
||||||
icon: '🔤',
|
|
||||||
topBg: '#fff3c4',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'c4',
|
|
||||||
title: '词语搭配',
|
|
||||||
subtitle: '词汇积累',
|
|
||||||
icon: '✏️',
|
|
||||||
topBg: '#e8f4ff',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'c5',
|
|
||||||
title: '古诗诵读',
|
|
||||||
subtitle: '语感培养',
|
|
||||||
icon: '🎵',
|
|
||||||
topBg: '#fce4ec',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const MOCK_HOT_RECOMMENDS = [
|
const CATEGORY_TOP_BG: Record<HomeDisplayItem['category'], string> = {
|
||||||
{
|
math: '#fff3c4',
|
||||||
id: 'hot-1',
|
chinese: '#d8f0d0',
|
||||||
title: '100以内的加减法',
|
english: '#e8f4ff',
|
||||||
desc: '让算术变得像游戏一样简单',
|
puzzle: '#f5e6dc',
|
||||||
tag: '数学',
|
craft: '#fce4ec',
|
||||||
score: '4.8',
|
};
|
||||||
emoji: '🍊',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'hot-2',
|
|
||||||
title: '创意涂鸦大作战',
|
|
||||||
desc: '释放孩子的艺术想象力',
|
|
||||||
tag: '艺术',
|
|
||||||
score: '4.9',
|
|
||||||
emoji: '🎨',
|
|
||||||
},
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
const { statusBarHeight } = wx.getWindowInfo();
|
const SECTION_ANCHOR_PREFIX = 'section-';
|
||||||
|
const TAB_BAR_PATHS = new Set([
|
||||||
|
'/pages/home/home',
|
||||||
|
'/pages/age/age',
|
||||||
|
'/pages/favorites/favorites',
|
||||||
|
'/pages/profile/profile',
|
||||||
|
]);
|
||||||
|
|
||||||
|
function toItemView(item: HomeDisplayItem): HomeDisplayItemView {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
topBg: CATEGORY_TOP_BG[item.category],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortSectionsByTabs(
|
||||||
|
tabs: readonly { id: string }[],
|
||||||
|
sections: HomeDisplaySection[],
|
||||||
|
): HomeDisplaySectionView[] {
|
||||||
|
const orderMap = tabs.reduce<Record<string, number>>((acc, tab, index) => {
|
||||||
|
acc[tab.id] = index;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return [...sections]
|
||||||
|
.sort((a, b) => {
|
||||||
|
const aOrder = orderMap[a.id];
|
||||||
|
const bOrder = orderMap[b.id];
|
||||||
|
// 注意:0 需要保留(不能用 || 进行兜底)
|
||||||
|
return (aOrder ?? 999) - (bOrder ?? 999);
|
||||||
|
})
|
||||||
|
.map((section) => ({
|
||||||
|
...section,
|
||||||
|
anchorId: `${SECTION_ANCHOR_PREFIX}${section.id}`,
|
||||||
|
items: section.items.map(toItemView),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateByPath(path?: string, fallbackTitle?: string) {
|
||||||
|
if (!path) {
|
||||||
|
wx.showToast({
|
||||||
|
title: fallbackTitle ? `${fallbackTitle} 即将上线` : '即将上线',
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TAB_BAR_PATHS.has(path)) {
|
||||||
|
wx.switchTab({ url: path });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wx.navigateTo({ url: path });
|
||||||
|
}
|
||||||
|
|
||||||
|
const win = wx.getWindowInfo();
|
||||||
|
const HOME_DATA = HOME_CURRENT_CAPABILITY_DATA;
|
||||||
|
const HOME_TABS: HomeTab[] = HOME_DATA.categoryTabs.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
name: item.name,
|
||||||
|
}));
|
||||||
|
const HOME_SECTIONS = sortSectionsByTabs(HOME_TABS, HOME_DATA.sections);
|
||||||
|
console.log('HOME_DATA', HOME_DATA);
|
||||||
|
console.log('HOME_SECTIONS', HOME_SECTIONS);
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
statusBarHeight,
|
statusBarHeight: win.statusBarHeight,
|
||||||
tabs: CATEGORY_TABS,
|
navBlockHeight: win.statusBarHeight + NAV_INNER_PX,
|
||||||
|
searchPlaceholder: HOME_DATA.searchPlaceholder,
|
||||||
|
tabs: HOME_TABS,
|
||||||
activeTab: 'all',
|
activeTab: 'all',
|
||||||
ageBands: AGE_BANDS.map((item, idx) => ({
|
ageBands: HOME_DATA.ageBands.map((item, idx) => ({
|
||||||
...item,
|
...item,
|
||||||
icon: AGE_BAND_ICONS[idx] || '🌟',
|
icon: AGE_BAND_ICONS[idx] || '🌟',
|
||||||
})),
|
})) as HomeAgeBandView[],
|
||||||
activeAgeBand: AGE_BANDS[0].key as AgeBandKey,
|
activeAgeBand: HOME_DATA.ageBands[0]?.key || ('3-4' as AgeBandKey),
|
||||||
hotRecommends: [...MOCK_HOT_RECOMMENDS],
|
featuredItems: HOME_DATA.featured.map(toItemView),
|
||||||
mathTrackCards: MOCK_MATH_TRACK,
|
hotRecommends: HOME_DATA.hot.map(toItemView),
|
||||||
chineseTrackCards: MOCK_CHINESE_TRACK,
|
sections: HOME_SECTIONS,
|
||||||
},
|
},
|
||||||
|
|
||||||
onTabChange(e: WechatMiniprogram.CustomEvent) {
|
onTabChange(e: WechatMiniprogram.CustomEvent) {
|
||||||
this.setData({ activeTab: e.detail.id });
|
const id = e.detail.id as string | undefined;
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
this.setData({ activeTab: id });
|
||||||
|
|
||||||
|
if (id === 'all') {
|
||||||
|
wx.pageScrollTo({
|
||||||
|
scrollTop: 0,
|
||||||
|
duration: 400,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wx.pageScrollTo({
|
||||||
|
selector: `#${SECTION_ANCHOR_PREFIX}${id}`,
|
||||||
|
duration: 400,
|
||||||
|
offsetTop: -(win.statusBarHeight + NAV_INNER_PX + 24),
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onTapAgeBand(e: WechatMiniprogram.TouchEvent) {
|
onTapAgeBand(e: WechatMiniprogram.TouchEvent) {
|
||||||
const key = e.currentTarget.dataset.key as AgeBandKey | undefined;
|
const key = e.currentTarget.dataset.key as AgeBandKey | undefined;
|
||||||
|
const path = e.currentTarget.dataset.path as string | undefined;
|
||||||
if (!key) return;
|
if (!key) return;
|
||||||
this.setData({ activeAgeBand: key });
|
this.setData({ activeAgeBand: key });
|
||||||
|
navigateByPath(path, '分龄内容');
|
||||||
|
},
|
||||||
|
|
||||||
|
onTapFeatured(e: WechatMiniprogram.TouchEvent) {
|
||||||
|
const path = e.currentTarget.dataset.path as string | undefined;
|
||||||
|
const title = e.currentTarget.dataset.title as string | undefined;
|
||||||
|
navigateByPath(path, title);
|
||||||
},
|
},
|
||||||
|
|
||||||
onTapHotRecommend(e: WechatMiniprogram.TouchEvent) {
|
onTapHotRecommend(e: WechatMiniprogram.TouchEvent) {
|
||||||
|
const path = e.currentTarget.dataset.path as string | undefined;
|
||||||
const title = e.currentTarget.dataset.title as string | undefined;
|
const title = e.currentTarget.dataset.title as string | undefined;
|
||||||
if (!title) return;
|
navigateByPath(path, title);
|
||||||
wx.showToast({ title: `已选择:${title}`, icon: 'none' });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onTapAgeMore() {
|
onTapAgeMore() {
|
||||||
wx.showToast({ title: '分龄全部 即将上线', icon: 'none' });
|
wx.switchTab({ url: '/pages/age/age' });
|
||||||
},
|
},
|
||||||
|
|
||||||
onTapHotMore() {
|
onTapHotMore() {
|
||||||
wx.showToast({ title: '热门推荐 即将上线', icon: 'none' });
|
wx.showToast({ title: '热门内容整理中', icon: 'none' });
|
||||||
},
|
},
|
||||||
|
|
||||||
onTapTrackMore(e: WechatMiniprogram.TouchEvent) {
|
onTapTrackMore(e: WechatMiniprogram.TouchEvent) {
|
||||||
const category = e.currentTarget.dataset.category as string | undefined;
|
const path = e.currentTarget.dataset.path as string | undefined;
|
||||||
if (!category) return;
|
const title = e.currentTarget.dataset.title as string | undefined;
|
||||||
wx.navigateTo({
|
navigateByPath(path, title);
|
||||||
url: `/pages/category/category?category=${category}`,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onTapTrackCard(e: WechatMiniprogram.TouchEvent) {
|
onTapTrackCard(e: WechatMiniprogram.TouchEvent) {
|
||||||
|
const path = e.currentTarget.dataset.path as string | undefined;
|
||||||
const title = e.currentTarget.dataset.title as string | undefined;
|
const title = e.currentTarget.dataset.title as string | undefined;
|
||||||
if (!title) return;
|
navigateByPath(path, title);
|
||||||
wx.showToast({ title, icon: 'none' });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onShareAppMessage() {
|
onShareAppMessage() {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view class="home-body" style="padding-top: {{navBlockHeight}}px;">
|
||||||
<view class="home-search-wrap">
|
<view class="home-search-wrap">
|
||||||
<view class="home-search">
|
<view class="home-search">
|
||||||
<van-icon
|
<van-icon
|
||||||
@@ -16,7 +17,7 @@
|
|||||||
size="36rpx"
|
size="36rpx"
|
||||||
color="rgba(50, 46, 37, 0.45)"
|
color="rgba(50, 46, 37, 0.45)"
|
||||||
class="home-search__icon" />
|
class="home-search__icon" />
|
||||||
<text class="home-search__placeholder">搜索你喜欢的练习册...</text>
|
<text class="home-search__placeholder">{{searchPlaceholder}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -27,10 +28,35 @@
|
|||||||
bind:change="onTabChange" />
|
bind:change="onTabChange" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<scroll-view class="home-track-scroll" scroll-x enable-flex>
|
||||||
|
<view class="home-track-row home-track-row--hero">
|
||||||
<view
|
<view
|
||||||
class="home-hero-placeholder"
|
wx:for="{{featuredItems}}"
|
||||||
aria-role="img"
|
wx:key="id"
|
||||||
aria-label="推荐位占位" />
|
class="home-hero-card"
|
||||||
|
data-title="{{item.title}}"
|
||||||
|
data-path="{{item.path}}"
|
||||||
|
bindtap="onTapFeatured">
|
||||||
|
<view
|
||||||
|
class="home-hero-card__top"
|
||||||
|
style="background-color: {{item.topBg}}">
|
||||||
|
<text class="home-hero-card__icon">{{item.icon}}</text>
|
||||||
|
<text wx:if="{{item.badge}}" class="home-hero-card__badge"
|
||||||
|
>{{item.badge}}</text
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
<view class="home-hero-card__body">
|
||||||
|
<view class="home-hero-card__title-row">
|
||||||
|
<text class="home-hero-card__title">{{item.title}}</text>
|
||||||
|
<text class="home-hero-card__meta"
|
||||||
|
>{{item.ageBand}} · {{item.difficulty}}</text
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
<text class="home-hero-card__sub">{{item.subtitle}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
<view class="home-section-panel">
|
<view class="home-section-panel">
|
||||||
<view class="home-section-head">
|
<view class="home-section-head">
|
||||||
@@ -46,12 +72,14 @@
|
|||||||
wx:key="key"
|
wx:key="key"
|
||||||
class="home-age-item"
|
class="home-age-item"
|
||||||
data-key="{{item.key}}"
|
data-key="{{item.key}}"
|
||||||
|
data-path="{{item.path}}"
|
||||||
bindtap="onTapAgeBand">
|
bindtap="onTapAgeBand">
|
||||||
<view
|
<view
|
||||||
class="home-age-item__icon-wrap {{activeAgeBand === item.key ? 'home-age-item__icon-wrap--active' : ''}}">
|
class="home-age-item__icon-wrap {{activeAgeBand === item.key ? 'home-age-item__icon-wrap--active' : ''}}">
|
||||||
<text class="home-age-item__icon">{{item.icon}}</text>
|
<text class="home-age-item__icon">{{item.icon}}</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="home-age-item__label">{{item.label}}</text>
|
<text class="home-age-item__label">{{item.label}}</text>
|
||||||
|
<text class="home-age-item__desc">{{item.desc}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
@@ -70,47 +98,58 @@
|
|||||||
wx:key="id"
|
wx:key="id"
|
||||||
class="home-hot-card"
|
class="home-hot-card"
|
||||||
data-title="{{item.title}}"
|
data-title="{{item.title}}"
|
||||||
|
data-path="{{item.path}}"
|
||||||
bindtap="onTapHotRecommend">
|
bindtap="onTapHotRecommend">
|
||||||
<view class="home-hot-card__thumb">
|
<view
|
||||||
|
class="home-hot-card__thumb"
|
||||||
|
style="background-color: {{item.topBg}}">
|
||||||
<text class="home-hot-card__thumb-emoji"
|
<text class="home-hot-card__thumb-emoji"
|
||||||
>{{item.emoji}}</text
|
>{{item.icon}}</text
|
||||||
>
|
>
|
||||||
</view>
|
</view>
|
||||||
<view class="home-hot-card__content">
|
<view class="home-hot-card__content">
|
||||||
<text class="home-hot-card__title">{{item.title}}</text>
|
<text class="home-hot-card__title">{{item.title}}</text>
|
||||||
<text class="home-hot-card__desc">{{item.desc}}</text>
|
<text class="home-hot-card__desc">{{item.subtitle}}</text>
|
||||||
<view class="home-hot-card__meta">
|
<view class="home-hot-card__meta">
|
||||||
<text class="home-hot-card__tag">{{item.tag}}</text>
|
<text class="home-hot-card__tag">{{item.ageBand}}</text>
|
||||||
<text class="home-hot-card__score"
|
<text class="home-hot-card__score"
|
||||||
>{{item.score}} ★</text
|
>{{item.difficulty}}</text
|
||||||
>
|
>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="home-hot-card__action">+</view>
|
<view class="home-hot-card__action">›</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="home-section-panel">
|
<view
|
||||||
|
wx:for="{{sections}}"
|
||||||
|
wx:key="id"
|
||||||
|
id="{{item.anchorId}}"
|
||||||
|
class="home-section-panel">
|
||||||
<view class="home-section-head">
|
<view class="home-section-head">
|
||||||
<text
|
<text
|
||||||
class="home-section-head__title home-section-head__title--module"
|
class="home-section-head__title home-section-head__title--module"
|
||||||
>数感启蒙</text
|
>{{item.title}}</text
|
||||||
>
|
>
|
||||||
<text
|
<text
|
||||||
|
wx:if="{{item.morePath}}"
|
||||||
class="home-section-head__more"
|
class="home-section-head__more"
|
||||||
data-category="math"
|
data-title="{{item.title}}"
|
||||||
|
data-path="{{item.morePath}}"
|
||||||
bindtap="onTapTrackMore"
|
bindtap="onTapTrackMore"
|
||||||
>更多</text
|
>更多</text
|
||||||
>
|
>
|
||||||
</view>
|
</view>
|
||||||
|
<text class="home-section-panel__sub">{{item.subtitle}}</text>
|
||||||
<scroll-view class="home-track-scroll" scroll-x enable-flex>
|
<scroll-view class="home-track-scroll" scroll-x enable-flex>
|
||||||
<view class="home-track-row">
|
<view class="home-track-row">
|
||||||
<view
|
<view
|
||||||
wx:for="{{mathTrackCards}}"
|
wx:for="{{item.items}}"
|
||||||
wx:key="id"
|
wx:key="id"
|
||||||
class="home-track-card"
|
class="home-track-card"
|
||||||
data-title="{{item.title}}"
|
data-title="{{item.title}}"
|
||||||
|
data-path="{{item.path}}"
|
||||||
bindtap="onTapTrackCard">
|
bindtap="onTapTrackCard">
|
||||||
<view
|
<view
|
||||||
class="home-track-card__top"
|
class="home-track-card__top"
|
||||||
@@ -124,44 +163,8 @@
|
|||||||
<text class="home-track-card__sub"
|
<text class="home-track-card__sub"
|
||||||
>{{item.subtitle}}</text
|
>{{item.subtitle}}</text
|
||||||
>
|
>
|
||||||
</view>
|
<text class="home-track-card__meta"
|
||||||
</view>
|
>{{item.ageBand}} · {{item.difficulty}}</text
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="home-section-panel">
|
|
||||||
<view class="home-section-head">
|
|
||||||
<text
|
|
||||||
class="home-section-head__title home-section-head__title--module"
|
|
||||||
>趣味中文</text
|
|
||||||
>
|
|
||||||
<text
|
|
||||||
class="home-section-head__more"
|
|
||||||
data-category="chinese"
|
|
||||||
bindtap="onTapTrackMore"
|
|
||||||
>更多</text
|
|
||||||
>
|
|
||||||
</view>
|
|
||||||
<scroll-view class="home-track-scroll" scroll-x enable-flex>
|
|
||||||
<view class="home-track-row">
|
|
||||||
<view
|
|
||||||
wx:for="{{chineseTrackCards}}"
|
|
||||||
wx:key="id"
|
|
||||||
class="home-track-card"
|
|
||||||
data-title="{{item.title}}"
|
|
||||||
bindtap="onTapTrackCard">
|
|
||||||
<view
|
|
||||||
class="home-track-card__top"
|
|
||||||
style="background-color: {{item.topBg}}">
|
|
||||||
<text class="home-track-card__icon">{{item.icon}}</text>
|
|
||||||
</view>
|
|
||||||
<view class="home-track-card__body">
|
|
||||||
<text class="home-track-card__title"
|
|
||||||
>{{item.title}}</text
|
|
||||||
>
|
|
||||||
<text class="home-track-card__sub"
|
|
||||||
>{{item.subtitle}}</text
|
|
||||||
>
|
>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -169,3 +172,4 @@
|
|||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
{
|
{
|
||||||
|
"navigationStyle": "custom",
|
||||||
"navigationBarTitleText": "我的",
|
"navigationBarTitleText": "我的",
|
||||||
"navigationBarTextStyle": "black",
|
"navigationBarTextStyle": "black",
|
||||||
"navigationBarBackgroundColor": "#ffffff",
|
"navigationBarBackgroundColor": "#F8F0E0",
|
||||||
"backgroundColor": "#F6F6F6"
|
"backgroundColor": "#F8F0E0",
|
||||||
|
"usingComponents": {
|
||||||
|
"van-icon": "@vant/weapp/icon/index"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,115 +1,357 @@
|
|||||||
|
@import '../../style/theme3.less';
|
||||||
|
|
||||||
|
@profile-premium-bg: #2d2a26;
|
||||||
|
|
||||||
|
/* 整页滚动:避免 scroll-view 在真机因未给出明确高度而高度为 0 */
|
||||||
|
page {
|
||||||
|
min-height: 100%;
|
||||||
|
background: @bg-header;
|
||||||
|
}
|
||||||
|
|
||||||
.profile-page {
|
.profile-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #f6f6f6;
|
background: @bg-header;
|
||||||
padding-bottom: 48rpx;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__header {
|
/* 顶栏:固定于顶部,正文区独立滚动 */
|
||||||
|
.profile-nav {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: fade(@bg-header, 85%);
|
||||||
|
backdrop-filter: blur(40rpx);
|
||||||
|
-webkit-backdrop-filter: blur(40rpx);
|
||||||
|
box-shadow: 0 2rpx 12rpx rgba(50, 46, 37, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-nav__inner {
|
||||||
|
height: @nav-inner-height;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: #f7ee47;
|
justify-content: flex-start;
|
||||||
padding: 48rpx 32rpx;
|
padding: 0 @page-padding-x;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__avatar {
|
.profile-nav__title {
|
||||||
width: 112rpx;
|
font-size: @fs-nav-title;
|
||||||
height: 112rpx;
|
font-weight: @fw-nav-title;
|
||||||
border-radius: 50%;
|
color: @color-nav-title;
|
||||||
background: #fff;
|
letter-spacing: @ls-nav-title;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 56rpx;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__header-info {
|
.profile-nav__brand {
|
||||||
margin-left: 28rpx;
|
font-size: 40rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
color: @brand;
|
||||||
|
letter-spacing: -0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-body {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-main {
|
||||||
|
padding: @section-gap-xs @page-padding-x;
|
||||||
|
padding-bottom: calc(32rpx + env(safe-area-inset-bottom) + 120rpx);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 用户主卡 */
|
||||||
|
.profile-hero {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-page__name {
|
|
||||||
font-size: 36rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 12rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-page__stat {
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-page__group {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 32rpx;
|
|
||||||
margin: 24rpx 24rpx 0;
|
|
||||||
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.06);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-page__item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 28rpx 32rpx;
|
padding: 80rpx @page-padding-inner-x 64rpx;
|
||||||
border-bottom: 1rpx solid #f0f0f0;
|
background: @bg-white;
|
||||||
|
border-radius: @radius-xl;
|
||||||
|
border: 1rpx solid rgba(124, 118, 106, 0.12);
|
||||||
|
box-shadow: @shadow;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: @section-gap-xs;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__item--last {
|
.profile-hero__tint {
|
||||||
border-bottom: none;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 192rpx;
|
||||||
|
background: @brand;
|
||||||
|
opacity: 0.1;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__icon {
|
.profile-hero__avatar-wrap {
|
||||||
font-size: 36rpx;
|
position: relative;
|
||||||
margin-right: 20rpx;
|
margin-top: 16rpx;
|
||||||
width: 44rpx;
|
}
|
||||||
|
|
||||||
|
.profile-hero__avatar {
|
||||||
|
width: 256rpx;
|
||||||
|
height: 256rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 8rpx solid @bg-white;
|
||||||
|
background: @bg-gray;
|
||||||
|
box-shadow: @shadow;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-hero__avatar-emoji {
|
||||||
|
font-size: 112rpx;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-hero__avatar-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-hero__edit-badge {
|
||||||
|
position: absolute;
|
||||||
|
right: 8rpx;
|
||||||
|
bottom: 8rpx;
|
||||||
|
width: 56rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: @brand;
|
||||||
|
border: 8rpx solid @bg-white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: @shadow;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-hero__name {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-title;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__label {
|
.profile-hero__stats {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 64rpx;
|
||||||
|
padding: 0 @page-padding-inner-x;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-hero__stat {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 30rpx;
|
background: @bg-header;
|
||||||
color: #333;
|
border-radius: @radius;
|
||||||
|
border: 1rpx solid rgba(124, 118, 106, 0.12);
|
||||||
|
padding: 32rpx 24rpx;
|
||||||
|
text-align: center;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__badge {
|
.profile-hero__stat+.profile-hero__stat {
|
||||||
font-size: 20rpx;
|
margin-left: 32rpx;
|
||||||
color: #fff;
|
|
||||||
background: #ff4757;
|
|
||||||
padding: 4rpx 12rpx;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
margin-right: 12rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__arrow {
|
.profile-hero__stat-num {
|
||||||
|
display: block;
|
||||||
font-size: 36rpx;
|
font-size: 36rpx;
|
||||||
color: #ccc;
|
font-weight: 800;
|
||||||
font-weight: 300;
|
color: @text-title;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__footer {
|
.profile-hero__stat-label {
|
||||||
|
display: block;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: @text-secondary;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 双格 */
|
||||||
|
.profile-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-bottom: @section-gap-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-grid__cell {
|
||||||
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 64rpx 32rpx 32rpx;
|
padding: 48rpx 24rpx;
|
||||||
|
background: @bg-white;
|
||||||
|
border-radius: @radius-xl;
|
||||||
|
border: 1rpx solid rgba(124, 118, 106, 0.12);
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__footer-emoji {
|
.profile-grid__cell+.profile-grid__cell {
|
||||||
font-size: 72rpx;
|
margin-left: 32rpx;
|
||||||
margin-bottom: 16rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__footer-slogan {
|
.profile-grid__icon-wrap {
|
||||||
font-size: 26rpx;
|
width: 96rpx;
|
||||||
color: #999;
|
height: 96rpx;
|
||||||
margin-bottom: 12rpx;
|
border-radius: 50%;
|
||||||
|
background: @brand;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 32rpx;
|
||||||
|
box-shadow: @shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-page__footer-version {
|
.profile-grid__title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: @text-title;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-grid__sub {
|
||||||
|
margin-top: 8rpx;
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
color: #ccc;
|
color: @text-secondary;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 圆角列表 */
|
||||||
|
.profile-rows {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: @section-gap-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 40rpx 40rpx;
|
||||||
|
background: @bg-white;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
border: 1rpx solid rgba(124, 118, 106, 0.12);
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-bottom: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-row--last {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-row__left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-row__icon-bg {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: fade(@brand, 18%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 32rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-row__label {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: @text-title;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-row__chevron {
|
||||||
|
font-size: 40rpx;
|
||||||
|
color: @text-gray;
|
||||||
|
font-weight: 300;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 专业版卡 */
|
||||||
|
.profile-upsell {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background: @profile-premium-bg;
|
||||||
|
border-radius: @radius-xl;
|
||||||
|
padding: 64rpx 48rpx;
|
||||||
|
box-shadow: @shadow-lg;
|
||||||
|
margin-bottom: @section-gap-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-upsell__deco {
|
||||||
|
position: absolute;
|
||||||
|
top: -24rpx;
|
||||||
|
right: -32rpx;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-upsell__body {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-upsell__title {
|
||||||
|
display: block;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
color: @text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-upsell__desc {
|
||||||
|
display: block;
|
||||||
|
margin-top: 16rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
line-height: 1.45;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
max-width: 400rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-upsell__btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 48rpx;
|
||||||
|
padding: 24rpx 64rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: @brand;
|
||||||
|
color: @text-selected-btn;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
box-shadow: @shadow-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-version {
|
||||||
|
text-align: center;
|
||||||
|
padding: 24rpx 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-version__text {
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: @text-secondary;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,38 @@
|
|||||||
|
import { getTodayDownloadCount } from '../../utils/downloadPrint';
|
||||||
|
import { NAV_INNER_PX } from '../../utils/navMetrics';
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
generateCount: 0,
|
statusBarHeight: 0,
|
||||||
|
/** 状态栏 + 导航条高度,用于固定顶栏占位 */
|
||||||
|
navBlockHeight: 0,
|
||||||
|
userName: '微信用户',
|
||||||
|
avatarUrl: '',
|
||||||
|
printCount: 0,
|
||||||
|
favoriteCount: 0,
|
||||||
version: '',
|
version: '',
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
const win = wx.getWindowInfo();
|
||||||
const info = wx.getAccountInfoSync();
|
const info = wx.getAccountInfoSync();
|
||||||
const version = info.miniProgram.version || '开发版';
|
const version = info.miniProgram.version || '开发版';
|
||||||
this.setData({ version });
|
this.setData({
|
||||||
|
statusBarHeight: win.statusBarHeight,
|
||||||
|
navBlockHeight: win.statusBarHeight + NAV_INNER_PX,
|
||||||
|
version,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
this.refreshStats();
|
||||||
|
},
|
||||||
|
|
||||||
|
refreshStats() {
|
||||||
|
const printCount = getTodayDownloadCount();
|
||||||
|
// 收藏数待与收藏页数据源打通后接入
|
||||||
|
const favoriteCount = 0;
|
||||||
|
this.setData({ printCount, favoriteCount });
|
||||||
},
|
},
|
||||||
|
|
||||||
onGoToDownloads() {
|
onGoToDownloads() {
|
||||||
@@ -20,14 +45,6 @@ Page({
|
|||||||
wx.switchTab({ url: '/pages/favorites/favorites' });
|
wx.switchTab({ url: '/pages/favorites/favorites' });
|
||||||
},
|
},
|
||||||
|
|
||||||
onGoToPrintPlan() {
|
|
||||||
wx.showToast({ title: '功能开发中', icon: 'none' });
|
|
||||||
},
|
|
||||||
|
|
||||||
onGoToStats() {
|
|
||||||
wx.showToast({ title: '功能开发中', icon: 'none' });
|
|
||||||
},
|
|
||||||
|
|
||||||
onGoToGuide() {
|
onGoToGuide() {
|
||||||
wx.navigateTo({ url: '/pages/guide/guide' });
|
wx.navigateTo({ url: '/pages/guide/guide' });
|
||||||
},
|
},
|
||||||
@@ -36,6 +53,10 @@ Page({
|
|||||||
wx.showToast({ title: '功能开发中', icon: 'none' });
|
wx.showToast({ title: '功能开发中', icon: 'none' });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onGoToSettings() {
|
||||||
|
wx.showToast({ title: '功能开发中', icon: 'none' });
|
||||||
|
},
|
||||||
|
|
||||||
onGoToFeedback() {
|
onGoToFeedback() {
|
||||||
wx.showToast({ title: '功能开发中', icon: 'none' });
|
wx.showToast({ title: '功能开发中', icon: 'none' });
|
||||||
},
|
},
|
||||||
@@ -43,4 +64,8 @@ Page({
|
|||||||
onGoToAbout() {
|
onGoToAbout() {
|
||||||
wx.showToast({ title: '涂鸦丫练习纸', icon: 'none' });
|
wx.showToast({ title: '涂鸦丫练习纸', icon: 'none' });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onGoToPremium() {
|
||||||
|
wx.showToast({ title: '功能开发中', icon: 'none' });
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,62 +1,145 @@
|
|||||||
<view class="profile-page">
|
<view class="profile-page">
|
||||||
<view class="profile-page__header">
|
<view class="profile-nav" style="padding-top: {{statusBarHeight}}px;">
|
||||||
<view class="profile-page__avatar">🦆</view>
|
<view class="profile-nav__inner">
|
||||||
<view class="profile-page__header-info">
|
<text class="profile-nav__title">个人中心</text>
|
||||||
<text class="profile-page__name">微信用户</text>
|
|
||||||
<text class="profile-page__stat">已生成 {{generateCount}} 张练习纸</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="profile-page__group">
|
<view class="profile-body" style="padding-top: {{navBlockHeight}}px;">
|
||||||
<view class="profile-page__item" bindtap="onGoToDownloads">
|
<view class="profile-main">
|
||||||
<text class="profile-page__icon">📥</text>
|
<!-- 用户卡(Stitch:白底大圆角 + 顶条淡黄) -->
|
||||||
<text class="profile-page__label">下载历史</text>
|
<view class="profile-hero">
|
||||||
<text class="profile-page__arrow">›</text>
|
<view class="profile-hero__tint"></view>
|
||||||
|
<view class="profile-hero__avatar-wrap">
|
||||||
|
<view class="profile-hero__avatar">
|
||||||
|
<text
|
||||||
|
class="profile-hero__avatar-emoji"
|
||||||
|
wx:if="{{!avatarUrl}}"
|
||||||
|
>🦆</text
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
wx:else
|
||||||
|
class="profile-hero__avatar-img"
|
||||||
|
src="{{avatarUrl}}"
|
||||||
|
mode="aspectFill" />
|
||||||
</view>
|
</view>
|
||||||
<view class="profile-page__item" bindtap="onGoToFavorites">
|
<view
|
||||||
<text class="profile-page__icon">❤️</text>
|
class="profile-hero__edit-badge"
|
||||||
<text class="profile-page__label">我的收藏</text>
|
aria-role="button"
|
||||||
<text class="profile-page__arrow">›</text>
|
aria-label="编辑头像">
|
||||||
|
<van-icon name="edit" size="28rpx" color="#6c5a00" />
|
||||||
</view>
|
</view>
|
||||||
<view class="profile-page__item" bindtap="onGoToPrintPlan">
|
|
||||||
<text class="profile-page__icon">📋</text>
|
|
||||||
<text class="profile-page__label">每日打印计划</text>
|
|
||||||
<view class="profile-page__badge">即将上线</view>
|
|
||||||
<text class="profile-page__arrow">›</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="profile-page__item profile-page__item--last" bindtap="onGoToStats">
|
<text class="profile-hero__name">{{userName}}</text>
|
||||||
<text class="profile-page__icon">📊</text>
|
<view class="profile-hero__stats">
|
||||||
<text class="profile-page__label">学习统计</text>
|
<view class="profile-hero__stat">
|
||||||
<text class="profile-page__arrow">›</text>
|
<text class="profile-hero__stat-num"
|
||||||
|
>{{printCount}}</text
|
||||||
|
>
|
||||||
|
<text class="profile-hero__stat-label">打印</text>
|
||||||
|
</view>
|
||||||
|
<view class="profile-hero__stat">
|
||||||
|
<text class="profile-hero__stat-num"
|
||||||
|
>{{favoriteCount}}</text
|
||||||
|
>
|
||||||
|
<text class="profile-hero__stat-label">收藏</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="profile-page__group">
|
<!-- 双格入口 -->
|
||||||
<view class="profile-page__item" bindtap="onGoToGuide">
|
<view class="profile-grid">
|
||||||
<text class="profile-page__icon">🖨️</text>
|
<view class="profile-grid__cell" bindtap="onGoToFavorites">
|
||||||
<text class="profile-page__label">打印指南</text>
|
<view class="profile-grid__icon-wrap">
|
||||||
<text class="profile-page__arrow">›</text>
|
<van-icon name="like" size="44rpx" color="#6c5a00" />
|
||||||
</view>
|
</view>
|
||||||
<view class="profile-page__item" bindtap="onGoToPrintSettings">
|
<text class="profile-grid__title">我的收藏</text>
|
||||||
<text class="profile-page__icon">⚙️</text>
|
<text class="profile-grid__sub">已保存的练习题</text>
|
||||||
<text class="profile-page__label">打印设置</text>
|
|
||||||
<text class="profile-page__arrow">›</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="profile-page__item" bindtap="onGoToFeedback">
|
<view class="profile-grid__cell" bindtap="onGoToDownloads">
|
||||||
<text class="profile-page__icon">💬</text>
|
<view class="profile-grid__icon-wrap">
|
||||||
<text class="profile-page__label">意见反馈</text>
|
<van-icon name="down" size="44rpx" color="#6c5a00" />
|
||||||
<text class="profile-page__arrow">›</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="profile-page__item profile-page__item--last" bindtap="onGoToAbout">
|
<text class="profile-grid__title">下载历史</text>
|
||||||
<text class="profile-page__icon">ℹ️</text>
|
<text class="profile-grid__sub">查看历史文件</text>
|
||||||
<text class="profile-page__label">关于涂鸦丫</text>
|
|
||||||
<text class="profile-page__arrow">›</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="profile-page__footer">
|
<!-- 圆角列表行 -->
|
||||||
<text class="profile-page__footer-emoji">🦆</text>
|
<view class="profile-rows">
|
||||||
<text class="profile-page__footer-slogan">陪孩子一起,把学习变成游戏</text>
|
<view class="profile-row" bindtap="onGoToGuide">
|
||||||
<text class="profile-page__footer-version">v{{version}}</text>
|
<view class="profile-row__left">
|
||||||
|
<view class="profile-row__icon-bg">
|
||||||
|
<van-icon
|
||||||
|
name="printer"
|
||||||
|
size="40rpx"
|
||||||
|
color="#322e25" />
|
||||||
|
</view>
|
||||||
|
<text class="profile-row__label">打印指南</text>
|
||||||
|
</view>
|
||||||
|
<text class="profile-row__chevron">›</text>
|
||||||
|
</view>
|
||||||
|
<view class="profile-row" bindtap="onGoToFeedback">
|
||||||
|
<view class="profile-row__left">
|
||||||
|
<view class="profile-row__icon-bg">
|
||||||
|
<van-icon
|
||||||
|
name="chat-o"
|
||||||
|
size="40rpx"
|
||||||
|
color="#322e25" />
|
||||||
|
</view>
|
||||||
|
<text class="profile-row__label">提交反馈</text>
|
||||||
|
</view>
|
||||||
|
<text class="profile-row__chevron">›</text>
|
||||||
|
</view>
|
||||||
|
<view class="profile-row" bindtap="onGoToSettings">
|
||||||
|
<view class="profile-row__left">
|
||||||
|
<view class="profile-row__icon-bg">
|
||||||
|
<van-icon
|
||||||
|
name="setting-o"
|
||||||
|
size="40rpx"
|
||||||
|
color="#322e25" />
|
||||||
|
</view>
|
||||||
|
<text class="profile-row__label">设置</text>
|
||||||
|
</view>
|
||||||
|
<text class="profile-row__chevron">›</text>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="profile-row profile-row--last"
|
||||||
|
bindtap="onGoToAbout">
|
||||||
|
<view class="profile-row__left">
|
||||||
|
<view class="profile-row__icon-bg">
|
||||||
|
<van-icon
|
||||||
|
name="info-o"
|
||||||
|
size="40rpx"
|
||||||
|
color="#322e25" />
|
||||||
|
</view>
|
||||||
|
<text class="profile-row__label">关于涂鸦丫</text>
|
||||||
|
</view>
|
||||||
|
<text class="profile-row__chevron">›</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 专业版推广(Stitch 深色卡) -->
|
||||||
|
<view class="profile-upsell" bindtap="onGoToPremium">
|
||||||
|
<van-icon
|
||||||
|
name="gem-o"
|
||||||
|
class="profile-upsell__deco"
|
||||||
|
size="200rpx"
|
||||||
|
color="rgba(255,255,255,0.12)" />
|
||||||
|
<view class="profile-upsell__body">
|
||||||
|
<text class="profile-upsell__title">升级专业版</text>
|
||||||
|
<text class="profile-upsell__desc"
|
||||||
|
>解锁 500+ 精选教育模板并获得优先体验。</text
|
||||||
|
>
|
||||||
|
<view class="profile-upsell__btn">立即升级</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="profile-version">
|
||||||
|
<text class="profile-version__text"
|
||||||
|
>Doodle Mini v{{version}}</text
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,53 +1,79 @@
|
|||||||
// v3.0 主题色体系(theme3)
|
/**
|
||||||
// 主题色 #FFD709 · 页背景 #FEF6E7 · Header #F8F0E0 · 主标题字 #322E25 · 选中按钮字 #6C5A00
|
* v3.0 主题令牌(Less 变量)
|
||||||
|
*
|
||||||
|
* 使用:在页面/组件 less 顶部 @import '../../style/theme3.less',再用 @brand、@page-padding-x、@fs-nav-title 等
|
||||||
|
*
|
||||||
|
* 色谱速览:主题 #FFD709 · 页背景 #FEF6E7 · Header #F8F0E0
|
||||||
|
* · 主标题 #322E25 · 选中/强调字 #6C5A00
|
||||||
|
*/
|
||||||
|
|
||||||
// 品牌 / 主题色
|
// ========== 品牌 / 主题色 ==========
|
||||||
@brand: #ffd709;
|
@brand: #ffd709;
|
||||||
@brand-dark: #e5c200;
|
@brand-dark: #e5c200; // 按下、加深态
|
||||||
@brand-light: #fff4c4;
|
@brand-light: #fff4c4; // 浅底、高亮背景
|
||||||
|
|
||||||
// 与 theme.less 对齐的别名
|
// 与 theme.less 对齐的别名
|
||||||
@primary-color: @brand;
|
@primary-color: @brand;
|
||||||
@select-color: @brand;
|
@select-color: @brand;
|
||||||
|
|
||||||
// 页面结构背景
|
// ========== 页面结构背景 ==========
|
||||||
@bg-page: #fef6e7;
|
@bg-page: #fef6e7;
|
||||||
@bg-header: #f8f0e0;
|
@bg-header: #f8f0e0;
|
||||||
@bg-default: @bg-page;
|
@bg-default: @bg-page;
|
||||||
@bg-white: #ffffff;
|
@bg-white: #ffffff;
|
||||||
@bg-gray: #f5edd8;
|
@bg-gray: #f5edd8;
|
||||||
|
@bg-muted: #f5f5f5; // 分龄 Tab 未选中等弱对比底(Stitch)
|
||||||
|
@bg-week-head: #fafafa; // 分龄周卡头部(Stitch stone-50)
|
||||||
|
|
||||||
// 文本:标题 / title
|
// ========== 文本色 ==========
|
||||||
@text-title: #322e25;
|
@text-title: #322e25;
|
||||||
@text-primary: @text-title;
|
@text-primary: @text-title;
|
||||||
@text-default: @text-title;
|
@text-default: @text-title;
|
||||||
|
@text-selected-btn: #6c5a00; // 黄底按钮上的字、强调整示
|
||||||
// 选中态按钮上的文字
|
|
||||||
@text-selected-btn: #6c5a00;
|
|
||||||
|
|
||||||
// 辅助文本(正文可读色,可与标题区分)
|
|
||||||
@text-secondary: #605b50;
|
@text-secondary: #605b50;
|
||||||
@text-light: rgba(50, 46, 37, 0.45);
|
@text-light: rgba(50, 46, 37, 0.45);
|
||||||
@text-gray: #8a8478;
|
@text-gray: #8a8478;
|
||||||
@text-white: #ffffff;
|
@text-white: #ffffff;
|
||||||
@text-disable: rgba(50, 46, 37, 0.35);
|
@text-disable: rgba(50, 46, 37, 0.35);
|
||||||
|
|
||||||
// 链接与外链(沿用可读蓝绿,可按需覆盖)
|
// ========== 链接与外链 ==========
|
||||||
@link-color: #2794f4;
|
@link-color: #2794f4;
|
||||||
@wechat-color: #1fe000;
|
@wechat-color: #1fe000;
|
||||||
|
|
||||||
// 边框(适配暖色底)
|
// ========== 边框 ==========
|
||||||
@border: 1rpx solid rgba(50, 46, 37, 0.08);
|
@border: 1rpx solid rgba(50, 46, 37, 0.08);
|
||||||
@border-color: rgba(255, 215, 9, 0.35);
|
@border-color: rgba(255, 215, 9, 0.35);
|
||||||
|
|
||||||
// 圆角
|
// ========== 页面水平内边距 ==========
|
||||||
|
// 主内容区与屏幕左右对齐;卡片内略小,避免双重视觉边距
|
||||||
|
@page-padding-x: 40rpx;
|
||||||
|
@page-padding-inner-x: 26rpx;
|
||||||
|
|
||||||
|
// ========== 区块纵向间距 ==========
|
||||||
|
@section-gap: 60rpx; // 主区块之间(按年龄挑选 ↔ 热门推荐 等)
|
||||||
|
@section-gap-lg: 48rpx; // 主区块之间(按年龄挑选 ↔ 热门推荐 等)
|
||||||
|
@section-gap-sm: 32rpx; // 区块内:标题与下方列表 / 横向列表顶距
|
||||||
|
@section-gap-stack: 28rpx; // 同级卡片堆叠(周卡、热门列表卡片等)
|
||||||
|
@section-gap-xs: 24rpx; // 更小块间(搜索区顶、Tab 区等)
|
||||||
|
|
||||||
|
|
||||||
|
// ========== 圆角 ==========
|
||||||
@radius-sm: 16rpx;
|
@radius-sm: 16rpx;
|
||||||
@radius: 24rpx;
|
@radius: 24rpx;
|
||||||
@radius-lg: 32rpx;
|
@radius-lg: 32rpx;
|
||||||
|
@radius-xl: 48rpx; // 大卡片(如个人中心主卡,对齐 Stitch 1.5rem)
|
||||||
|
|
||||||
// 阴影
|
// ========== 阴影 ==========
|
||||||
@shadow: 0 4rpx 16rpx rgba(50, 46, 37, 0.06);
|
@shadow: 0 4rpx 16rpx rgba(50, 46, 37, 0.06);
|
||||||
@shadow-lg: 0 8rpx 32rpx rgba(50, 46, 37, 0.1);
|
@shadow-lg: 0 8rpx 32rpx rgba(50, 46, 37, 0.1);
|
||||||
|
|
||||||
// icon
|
// ========== 字号 ==========
|
||||||
@font-size-icon: 40rpx;
|
@font-size-icon: 40rpx;
|
||||||
|
@fs-section-head-title: 36rpx; // 板块主标题(如首页区块头、分龄路径头等)
|
||||||
|
|
||||||
|
// ========== 顶栏(Tab 页固定导航标题)==========
|
||||||
|
@nav-inner-height: 44px;
|
||||||
|
@fs-nav-title: 34rpx;
|
||||||
|
@fw-nav-title: 700;
|
||||||
|
@color-nav-title: @text-title;
|
||||||
|
@ls-nav-title: -0.02em;
|
||||||
@@ -29,9 +29,9 @@ function getTodayDateString(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取今日下载次数
|
* 获取今日下载次数(供个人中心等展示;与内部计数逻辑一致)
|
||||||
*/
|
*/
|
||||||
function getTodayDownloadCount(): number {
|
export function getTodayDownloadCount(): number {
|
||||||
const today = getTodayDateString();
|
const today = getTodayDateString();
|
||||||
const downloadDate = wx.getStorageSync(STORAGE_KEY_DOWNLOAD_DATE);
|
const downloadDate = wx.getStorageSync(STORAGE_KEY_DOWNLOAD_DATE);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/** 与 style/theme3.less 中 @nav-inner-height 对齐(px) */
|
||||||
|
export const NAV_INNER_PX = 44;
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
|
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
|
||||||
"projectname": "doodle-mini",
|
"projectname": "doodle-mini",
|
||||||
"setting": {
|
"setting": {
|
||||||
"compileHotReLoad": false,
|
"compileHotReLoad": true,
|
||||||
"urlCheck": true,
|
"urlCheck": true,
|
||||||
"coverView": false,
|
"coverView": false,
|
||||||
"lazyloadPlaceholderEnable": false,
|
"lazyloadPlaceholderEnable": false,
|
||||||
@@ -24,12 +24,19 @@
|
|||||||
"miniprogram": {
|
"miniprogram": {
|
||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"name": "pages/copyBook/copyBook",
|
"name": "pages/age/age",
|
||||||
"pathName": "pages/copyBook/copyBook",
|
"pathName": "pages/age/age",
|
||||||
"query": "",
|
"query": "",
|
||||||
"scene": null,
|
"scene": null,
|
||||||
"launchMode": "default"
|
"launchMode": "default"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "pages/copyBook/copyBook",
|
||||||
|
"pathName": "pages/copyBook/copyBook",
|
||||||
|
"query": "",
|
||||||
|
"launchMode": "default",
|
||||||
|
"scene": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "mathPages/multiplicationTable/multiplicationTable",
|
"name": "mathPages/multiplicationTable/multiplicationTable",
|
||||||
"pathName": "mathPages/multiplicationTable/multiplicationTable",
|
"pathName": "mathPages/multiplicationTable/multiplicationTable",
|
||||||
|
|||||||
@@ -0,0 +1,371 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||||
|
<script id="tailwind-config">
|
||||||
|
tailwind.config = {
|
||||||
|
darkMode: "class",
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
"surface-container-highest": "#e5dcc9",
|
||||||
|
"surface-bright": "#fef6e7",
|
||||||
|
"secondary-container": "#ffc697",
|
||||||
|
"on-secondary": "#fff0e6",
|
||||||
|
"surface-variant": "#e5dcc9",
|
||||||
|
"primary-fixed-dim": "#efc900",
|
||||||
|
"primary-dim": "#5e4e00",
|
||||||
|
"primary-container": "#ffd709",
|
||||||
|
"inverse-surface": "#110e06",
|
||||||
|
"on-background": "#322e25",
|
||||||
|
"inverse-on-surface": "#a29c8f",
|
||||||
|
"on-secondary-fixed": "#512a00",
|
||||||
|
"on-tertiary-fixed": "#00480f",
|
||||||
|
"surface-container": "#f0e7d6",
|
||||||
|
"secondary-fixed": "#ffc697",
|
||||||
|
"tertiary-fixed-dim": "#83e881",
|
||||||
|
"secondary-dim": "#794200",
|
||||||
|
"on-primary-fixed": "#453900",
|
||||||
|
"surface-container-high": "#eae2d0",
|
||||||
|
"on-tertiary-fixed-variant": "#00691a",
|
||||||
|
"on-surface-variant": "#605b50",
|
||||||
|
"on-surface": "#322e25",
|
||||||
|
"on-tertiary-container": "#005e17",
|
||||||
|
"surface": "#fef6e7",
|
||||||
|
"tertiary-container": "#91f78e",
|
||||||
|
"tertiary-dim": "#005d16",
|
||||||
|
"outline-variant": "#b3ac9f",
|
||||||
|
"error": "#b02500",
|
||||||
|
"on-primary-fixed-variant": "#665500",
|
||||||
|
"on-primary-container": "#5b4b00",
|
||||||
|
"background": "#fef6e7",
|
||||||
|
"on-secondary-fixed-variant": "#7a4300",
|
||||||
|
"on-secondary-container": "#6d3b00",
|
||||||
|
"on-primary": "#fff2cd",
|
||||||
|
"inverse-primary": "#ffd709",
|
||||||
|
"outline": "#7c766a",
|
||||||
|
"error-dim": "#b92902",
|
||||||
|
"surface-container-lowest": "#ffffff",
|
||||||
|
"on-error": "#ffefec",
|
||||||
|
"tertiary": "#006b1b",
|
||||||
|
"secondary": "#8a4c00",
|
||||||
|
"on-tertiary": "#d1ffc8",
|
||||||
|
"primary": "#6c5a00",
|
||||||
|
"surface-container-low": "#f8f0e0",
|
||||||
|
"surface-dim": "#dcd4c0",
|
||||||
|
"secondary-fixed-dim": "#ffb470",
|
||||||
|
"surface-tint": "#6c5a00",
|
||||||
|
"primary-fixed": "#ffd709",
|
||||||
|
"on-error-container": "#520c00",
|
||||||
|
"tertiary-fixed": "#91f78e",
|
||||||
|
"error-container": "#f95630"
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
"headline": ["Plus Jakarta Sans"],
|
||||||
|
"body": ["Plus Jakarta Sans"],
|
||||||
|
"label": ["Plus Jakarta Sans"]
|
||||||
|
},
|
||||||
|
borderRadius: {"DEFAULT": "0.75rem", "lg": "1rem", "xl": "1.5rem", "full": "9999px"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.material-symbols-outlined {
|
||||||
|
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.hide-scrollbar::-webkit-scrollbar { display: none; }
|
||||||
|
.hide-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
body {
|
||||||
|
min-height: max(884px, 100dvh);
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-background font-body text-on-surface selection:bg-primary-container">
|
||||||
|
<!-- TopAppBar -->
|
||||||
|
<header class="fixed top-0 w-full z-50 bg-[#fef6e7]/80 dark:bg-stone-900/80 backdrop-blur-xl">
|
||||||
|
<div class="flex justify-between items-center w-full px-6 py-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="material-symbols-outlined text-[#6c5a00] dark:text-yellow-500 text-2xl hover:scale-95 transition-transform cursor-pointer">arrow_back</span>
|
||||||
|
<div class="w-10 h-10 rounded-full bg-primary-container flex items-center justify-center overflow-hidden border-2 border-white shadow-sm">
|
||||||
|
<img alt="Duck icon" data-alt="cute stylized duck head illustration in warm yellow and orange colors, playful nursery art style" src="https://lh3.googleusercontent.com/aida-public/AB6AXuDvc8PWsCtmX47Is3M__zrkzx_wmWFN3lZV-S1KZ1eKQDxsP5GGmrNMyWi2IjqRDxRvFo2t1-HZrrlUuRBTXk0lOrZGY6nZfs3fS26fjQ2lK_dFTWf4i4pijmIlZw7clKCT4r7XrgxPrGm173B32CRtocnaLSgKmvDKlV695U-_J9fai85AAD2FXkoEbOeYQf4vo0EWuXCzUsuc7_93R4xWz_5NFcunMraCNELOvS3t9jv2vm44th_W6k5_KLR2F-LazXHyYEzhLq8"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h1 class="font-headline font-bold tracking-tight text-[#322e25] dark:text-stone-100 text-xl">按年龄学</h1>
|
||||||
|
<span class="material-symbols-outlined text-[#6c5a00] dark:text-yellow-500 text-2xl hover:scale-95 transition-transform cursor-pointer">account_circle</span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="pt-24 pb-32 px-6 max-w-2xl mx-auto space-y-10">
|
||||||
|
<!-- Age Selector Section -->
|
||||||
|
<section class="relative">
|
||||||
|
<div class="flex gap-4 overflow-x-auto hide-scrollbar py-4 -mx-2 px-2 snap-x items-center"><!-- 3-4岁 -->
|
||||||
|
<div class="snap-center shrink-0 w-32 h-24 rounded-xl bg-[#f5f5f5] flex flex-col items-center justify-center transition-all">
|
||||||
|
<div class="font-bold text-xl text-[#322e25]">3-4 岁</div>
|
||||||
|
<div class="text-xs text-[#322e25]/60 mt-1">启蒙认知</div>
|
||||||
|
</div>
|
||||||
|
<!-- 4-5岁 -->
|
||||||
|
<div class="snap-center shrink-0 w-32 h-24 rounded-xl bg-[#f5f5f5] flex flex-col items-center justify-center transition-all">
|
||||||
|
<div class="font-bold text-xl text-[#322e25]">4-5 岁</div>
|
||||||
|
<div class="text-xs text-[#322e25]/60 mt-1">基础练习</div>
|
||||||
|
</div>
|
||||||
|
<!-- 5-6岁 (Active) -->
|
||||||
|
<div class="snap-center shrink-0 w-32 h-24 rounded-xl bg-[#FFD700] border-2 border-white shadow-[0_8px_20px_rgba(255,215,0,0.3)] flex flex-col items-center justify-center scale-110 relative z-10 transition-all">
|
||||||
|
<div class="font-black text-xl text-[#6c5a00]">5-6 岁</div>
|
||||||
|
<div class="text-xs font-bold text-[#6c5a00]/80 mt-1">能力提升</div>
|
||||||
|
<div class="absolute -top-2 -right-2 bg-on-tertiary-container text-white text-[10px] px-2 py-0.5 rounded-full">当前</div>
|
||||||
|
</div>
|
||||||
|
<!-- 6-7岁 -->
|
||||||
|
<div class="snap-center shrink-0 w-32 h-24 rounded-xl bg-[#f5f5f5] flex flex-col items-center justify-center transition-all">
|
||||||
|
<div class="font-bold text-xl text-[#322e25]">6-7 岁</div>
|
||||||
|
<div class="text-xs text-[#322e25]/60 mt-1">幼小衔接</div>
|
||||||
|
</div>
|
||||||
|
<!-- 7-8岁 -->
|
||||||
|
<div class="snap-center shrink-0 w-32 h-24 rounded-xl bg-[#f5f5f5] flex flex-col items-center justify-center transition-all">
|
||||||
|
<div class="font-bold text-xl text-[#322e25]">7-8 岁</div>
|
||||||
|
<div class="text-xs text-[#322e25]/60 mt-1">知识拓展</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<!-- Ability Goals Card -->
|
||||||
|
<section class="bg-surface-container-lowest rounded-xl p-6 shadow-sm border border-surface-container">
|
||||||
|
<h2 class="text-xl font-extrabold text-on-secondary-container mb-6 flex items-center gap-2">
|
||||||
|
<span class="material-symbols-outlined text-primary" style="font-variation-settings: 'FILL' 1;">stars</span>
|
||||||
|
5-6 岁能力目标
|
||||||
|
</h2>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
|
<div class="p-4 rounded-lg bg-surface-container-low border border-surface-variant/30">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<span class="text-xl">🔢</span>
|
||||||
|
<span class="font-bold text-primary">数感</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-on-surface-variant leading-relaxed">10以内加减法、凑十法</p>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 rounded-lg bg-surface-container-low border border-surface-variant/30">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<span class="text-xl">✏️</span>
|
||||||
|
<span class="font-bold text-primary">书写</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-on-surface-variant leading-relaxed">练字帖、拼音入门</p>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 rounded-lg bg-surface-container-low border border-surface-variant/30">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<span class="text-xl">🧩</span>
|
||||||
|
<span class="font-bold text-primary">思维</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-on-surface-variant leading-relaxed">方格推理、格子仿画 5x5</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Learning Path Section -->
|
||||||
|
<section class="space-y-6">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h2 class="text-2xl font-extrabold text-on-surface tracking-tight flex items-center gap-3">
|
||||||
|
<span class="w-2 h-8 bg-primary rounded-full"></span>
|
||||||
|
4 周推荐学习路线
|
||||||
|
</h2>
|
||||||
|
<div class="bg-surface-container px-3 py-1 rounded-full flex items-center gap-1">
|
||||||
|
<span class="text-[10px] font-bold text-on-surface-variant">4 周 • 每周 3 练</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-8">
|
||||||
|
<!-- Week 1 -->
|
||||||
|
<div class="bg-white rounded-xl border border-stone-100 overflow-hidden shadow-sm">
|
||||||
|
<div class="px-5 py-4 flex items-baseline gap-3 bg-stone-50">
|
||||||
|
<span class="font-black text-xl text-[#333333]">第 1 周</span>
|
||||||
|
<span class="font-bold text-sm text-stone-500">数感启蒙</span>
|
||||||
|
</div>
|
||||||
|
<div class="divide-y divide-stone-100">
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">找数字涂一涂</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">5 以内加法</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">数数连一连</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Week 2 -->
|
||||||
|
<div class="bg-white rounded-xl border border-stone-100 overflow-hidden shadow-sm">
|
||||||
|
<div class="px-5 py-4 flex items-baseline gap-3 bg-stone-50">
|
||||||
|
<span class="font-black text-xl text-[#333333]">第 2 周</span>
|
||||||
|
<span class="font-bold text-sm text-stone-500">形状与连线</span>
|
||||||
|
</div>
|
||||||
|
<div class="divide-y divide-stone-100">
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">识别形状</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">线条识别</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">数字点连线</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Week 3 -->
|
||||||
|
<div class="bg-white rounded-xl border border-stone-100 overflow-hidden shadow-sm">
|
||||||
|
<div class="px-5 py-4 flex items-baseline gap-3 bg-stone-50">
|
||||||
|
<span class="font-black text-xl text-[#333333]">第 3 周</span>
|
||||||
|
<span class="font-bold text-sm text-stone-500">趣味专注</span>
|
||||||
|
</div>
|
||||||
|
<div class="divide-y divide-stone-100">
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">颜色找规律</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">方格推理</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">格子仿画</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Week 4 -->
|
||||||
|
<div class="bg-white rounded-xl border border-stone-100 overflow-hidden shadow-sm">
|
||||||
|
<div class="px-5 py-4 flex items-baseline gap-3 bg-stone-50">
|
||||||
|
<span class="font-black text-xl text-[#333333]">第 4 周</span>
|
||||||
|
<span class="font-bold text-sm text-stone-500">综合练习</span>
|
||||||
|
</div>
|
||||||
|
<div class="divide-y divide-stone-100">
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">10以内加减法</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">识字卡</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">连连看</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Recommended Section -->
|
||||||
|
<section class="space-y-4">
|
||||||
|
<div class="flex justify-between items-end">
|
||||||
|
<h2 class="text-xl font-extrabold text-on-surface">[为你推荐]</h2>
|
||||||
|
<span class="text-sm font-bold text-primary cursor-pointer">更多</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<!-- Card 1 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="vibrant educational math worksheet showing numbers and colorful apples for counting, soft sunny lighting" src="https://lh3.googleusercontent.com/aida-public/AB6AXuD-3lADhclTGODN9WtNh5v8bQPLysbllbKNkH40bAmVyE5d54PwfTBOiX9nER1hpE4rzHAfsmM_JhVnsE4EbdA914rYIb3S3e4r9QKFjUqYmj2XpE4MlYr_vLkG4oeMnvnHOqGC96nLGrPSOq-fpIddV7RSlYLDeNccBs0G2oUOy-6jIMujzTuEGk4nnxme5rpxs7rYjwcvVsqM5dlkpJthY42e4B3lSPH7ezx187WRSk--m4ZiWmAI52mMOiygzTSWoNormlvfvdM"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">10以内加减法</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card 2 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="preschool addition flashcards with cute animal illustrations, warm morning light in a classroom" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBYS4O7PyflR5q8M6oXKwj_8QHzex3OL3YvdHBncutm7a_bjlZj83-8UBpGUQvJO20V0BnAdU3iKEoLlUqwpS60CiPhVyxYaHEAqv52P5YUhJdjf0hpLir1Li4rdI_-eqGkPTasYl-5kD2r8-RjUokKg_HiW5_TF72UbxFXHQh4BefYJZfl0Oc9-aTQvkbFL0C3tagi9Qv1jRsgQldMFU4M7cHt8KkxhO1QDF7-R85ZFORJM0RiqV2l-jn0c-UscKtuWtroiX6UUKk"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">拼音描红</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card 3 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="logical pattern game for kids with colorful geometric shapes and grids, clean minimalist aesthetic" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBSafbTyucs8JLpTgibRWwAJsHukrklTAuEnaAzax_Kr1RNCwHjqpQjta0Q-h47ClufzEmaHPgCIOlm_a2lL4gNlgBDyraCwzRU7aWCf_Fj_dM1cLGzROJmtqrdHKjQzTbCp0_Da8BvXi4a4H2X4RAYVPnLbZVmbgPXrTvpKgEI605kIMmr3n0--WojJQRsF4B_xCho80gABbIaMTHJHrs9xdEY6fZKg8ArQx7lRbJ6_EsLLB_C5a5crZ_begwruXKr3pmdU6KneC8"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">趣味找不同</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card 4 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="visual tracking exercise showing a winding maze path with a small mouse and cheese, soft pastel colors" src="https://lh3.googleusercontent.com/aida-public/AB6AXuAOZHI1Dz6ax4iFUb3QYL-EWp2euA_3kyUeCcu6V57BBCzarMwKnFzcpJxJn4X4woklWFB08Ii1w6zsk0H5eDaPdgUYmsvY0NFqvAhKN_IbZGZjZnclZlBHkLRcX64Nl767L2pg01FQu9Tp6nq2p3lAuYeEQ2fiIdXh4j-QHyikbmx4_aDlx5X5fC0fqMMxWykhwLNkDzl2Rs3ucXj7zYnUP-dNNY-aj_JvqkY4pqoXQDt9ZJcfSeL0dWes7nvD5U2C_JFhrk1bVkw"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">走迷宫大挑战</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card 5 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden bg-primary-container/20">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="creative dot-to-dot puzzle for kids forming a friendly dinosaur, soft natural lighting" src="https://lh3.googleusercontent.com/aida-public/AB6AXuD-3lADhclTGODN9WtNh5v8bQPLysbllbKNkH40bAmVyE5d54PwfTBOiX9nER1hpE4rzHAfsmM_JhVnsE4EbdA914rYIb3S3e4r9QKFjUqYmj2XpE4MlYr_vLkG4oeMnvnHOqGC96nLGrPSOq-fpIddV7RSlYLDeNccBs0G2oUOy-6jIMujzTuEGk4nnxme5rpxs7rYjwcvVsqM5dlkpJthY42e4B3lSPH7ezx187WRSk--m4ZiWmAI52mMOiygzTSWoNormlvfvdM"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">数字点连线</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card 6 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden bg-secondary-container/20">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="kids handwriting practice sheet with chinese characters and stroke order guides, neat layout" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBYS4O7PyflR5q8M6oXKwj_8QHzex3OL3YvdHBncutm7a_bjlZj83-8UBpGUQvJO20V0BnAdU3iKEoLlUqwpS60CiPhVyxYaHEAqv52P5YUhJdjf0hpLir1Li4rdI_-eqGkPTasYl-5kD2r8-RjUokKg_HiW5_TF72UbxFXHQh4BefYJZfl0Oc9-aTQvkbFL0C3tagi9Qv1jRsgQldMFU4M7cHt8KkxhO1QDF7-R85ZFORJM0RiqV2l-jn0c-UscKtuWtroiX6UUKk"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">方格推理高手</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<!-- BottomNavBar -->
|
||||||
|
<nav class="fixed bottom-0 left-0 w-full flex justify-around items-center px-4 pb-8 pt-3 bg-[#f8f0e0]/80 dark:bg-stone-800/80 backdrop-blur-xl rounded-t-[1.5rem] z-50 shadow-[0_-8px_32px_rgba(50,46,37,0.06)]">
|
||||||
|
<div class="flex flex-col items-center justify-center text-[#322e25]/60 dark:text-stone-400 px-5 py-2 hover:bg-[#f0e7d6] dark:hover:bg-stone-700 rounded-full transition-all cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined text-2xl">map</span>
|
||||||
|
<span class="font-headline text-xs font-semibold mt-1">学习地图</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center justify-center bg-[#ffd709] dark:bg-yellow-600 text-[#6c5a00] dark:text-yellow-950 rounded-full px-5 py-2 scale-105 shadow-md transition-all active:scale-90">
|
||||||
|
<span class="material-symbols-outlined text-2xl" style="font-variation-settings: 'FILL' 1;">local_library</span>
|
||||||
|
<span class="font-headline text-xs font-semibold mt-1">我的课程</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center justify-center text-[#322e25]/60 dark:text-stone-400 px-5 py-2 hover:bg-[#f0e7d6] dark:hover:bg-stone-700 rounded-full transition-all cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined text-2xl">explore</span>
|
||||||
|
<span class="font-headline text-xs font-semibold mt-1">发现</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center justify-center text-[#322e25]/60 dark:text-stone-400 px-5 py-2 hover:bg-[#f0e7d6] dark:hover:bg-stone-700 rounded-full transition-all cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined text-2xl">family_restroom</span>
|
||||||
|
<span class="font-headline text-xs font-semibold mt-1">家长中心</span>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</body></html>
|
||||||
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,54 @@
|
|||||||
|
# Design System Strategy: Doodle Mini
|
||||||
|
|
||||||
|
## 1. Overview & Creative North Star: "The Sun-Drenched Studio"
|
||||||
|
The creative direction for this design system is **"The Sun-Drenched Studio."** We are moving away from the cold, clinical "educational app" look and toward a space that feels like a physical, tactile craft room bathed in morning light.
|
||||||
|
|
||||||
|
Instead of a rigid, boxed-in grid, we embrace **Organic Asymmetry**. Elements should feel like they were placed on a table by hand, not snapped to a pixel-perfect wireframe. We break the "template" look by using exaggerated corner radii, overlapping "paper" layers, and a hierarchy that prioritizes warmth and play over traditional data density.
|
||||||
|
|
||||||
|
## 2. Colors: Tonal Radiance
|
||||||
|
The palette is anchored by `primary` (#6c5a00) and `primary_container` (#ffd709), creating a "Yaya Yellow" experience that is vibrant yet sophisticated.
|
||||||
|
|
||||||
|
* **The "No-Line" Rule:** Under no circumstances should 1px solid borders be used to separate content. We define boundaries exclusively through background shifts. Use `surface_container_low` (#f8f0e0) for main content areas and `surface` (#fef6e7) for the global backdrop.
|
||||||
|
* **Surface Hierarchy & Nesting:** Treat the UI as stacked sheets of heavy-weight construction paper.
|
||||||
|
* **Level 0:** `background` (#fef6e7) – The desk surface.
|
||||||
|
* **Level 1:** `surface_container` (#f0e7d6) – The worksheet base.
|
||||||
|
* **Level 2:** `surface_container_lowest` (#ffffff) – Active drawing cards or "Paper" modals.
|
||||||
|
* **The Glass & Gradient Rule:** For navigation bars or floating tool palettes, use Glassmorphism. Apply `surface_container_low` at 80% opacity with a `20px` backdrop blur. This ensures the "sunny" background bleeds through, maintaining the "Sun-Drenched" atmosphere.
|
||||||
|
* **Signature Textures:** Main CTAs should not be flat. Apply a subtle linear gradient from `primary_fixed` (#ffd709) to `primary_fixed_dim` (#efc900) at a 145-degree angle to give buttons a "pillowy" 3D volume.
|
||||||
|
|
||||||
|
## 3. Typography: The Friendly Guide
|
||||||
|
We use **Plus Jakarta Sans** exclusively. Its geometric yet soft terminals provide a modern, legible, and approachable voice.
|
||||||
|
|
||||||
|
* **Display & Headlines:** Use `display-lg` (3.5rem) for "Doodle Mini" brand moments. Headlines (`headline-md`) should use a tighter letter-spacing (-0.02em) to feel "hugged" and friendly.
|
||||||
|
* **Body & Labels:** Use `body-lg` for all instructional text. In a children's context, readability is paramount; ensure a line height of at least 1.6x the font size.
|
||||||
|
* **Hierarchy as Personality:** Use `on_secondary_container` (#6d3b00) for sub-headers to provide a warm, "chocolatey" contrast against the yellow, moving away from harsh blacks.
|
||||||
|
|
||||||
|
## 4. Elevation & Depth: Tonal Layering
|
||||||
|
Depth in this system is a result of light and shadow, not lines and strokes.
|
||||||
|
|
||||||
|
* **The Layering Principle:** To lift a component, place a `surface_container_highest` (#e5dcc9) element inside a `surface_container_low` (#f8f0e0) environment. This creates a "recessed" or "elevated" feel through color value alone.
|
||||||
|
* **Ambient Shadows:** Use shadows sparingly. When an object "floats" (like a floating action button), use a shadow color derived from `on_surface` (#322e25) at 6% opacity, with a blur of `32px` and a Y-offset of `8px`. It should look like a soft glow, not a drop shadow.
|
||||||
|
* **The "Ghost Border" Fallback:** If a separator is required for accessibility in input fields, use `outline_variant` (#b3ac9f) at **15% opacity**. It should be felt, not seen.
|
||||||
|
|
||||||
|
## 5. Components: Tactile & Safe
|
||||||
|
Every component must feel "squishy" and safe to touch.
|
||||||
|
|
||||||
|
* **Buttons:**
|
||||||
|
* **Primary:** Uses `primary_container` (#ffd709) with a `full` (9999px) radius.
|
||||||
|
* **States:** On press, scale the button down to 96% size to simulate a physical "click" into the screen.
|
||||||
|
* **Cards & Lists:** Forbid divider lines. Separate list items using a `spacing-3` (1rem) gap and alternating background colors between `surface_container_low` and `surface_container`.
|
||||||
|
* **Input Fields:** Use `surface_container_highest` for the input track. Corners must be `xl` (3rem). Labels sit *above* the field in `title-sm` to ensure children can always see the context.
|
||||||
|
* **Selection Chips:** Use `secondary_container` (#ffc697) for selected states. The roundedness must be `full` to mimic smooth river stones.
|
||||||
|
* **The "Joy" Progress Bar:** A custom component for Doodle Mini. Use a thick track (`1.5rem` height) in `surface_container_highest` with the progress indicator using a gradient of `tertiary` (#006b1b) to `tertiary_fixed` (#91f78e).
|
||||||
|
|
||||||
|
## 6. Do’s and Don’ts
|
||||||
|
|
||||||
|
### Do:
|
||||||
|
* **Do** use `xl` and `full` corner radii for almost everything. Sharp corners are "scary."
|
||||||
|
* **Do** lean into white space. Use `spacing-12` (4rem) between major sections to let the design breathe.
|
||||||
|
* **Do** use `on_tertiary_container` (dark green) for success states; it feels organic and "earthy" against the yellow.
|
||||||
|
|
||||||
|
### Don’t:
|
||||||
|
* **Don’t** use pure black (#000000). Use `on_surface` (#322e25) for all dark text to maintain the warm, sunny tone.
|
||||||
|
* **Don’t** use 1px dividers. If you feel you need one, use a `surface_variant` (#e5dcc9) color block that is `4px` thick with `full` rounded caps.
|
||||||
|
* **Don’t** crowd the interface. If a screen feels busy, increase the background "paper" size and use a scrollable layout instead of shrinking elements.
|
||||||
@@ -0,0 +1,371 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||||
|
<script id="tailwind-config">
|
||||||
|
tailwind.config = {
|
||||||
|
darkMode: "class",
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
"surface-container-highest": "#e5dcc9",
|
||||||
|
"surface-bright": "#fef6e7",
|
||||||
|
"secondary-container": "#ffc697",
|
||||||
|
"on-secondary": "#fff0e6",
|
||||||
|
"surface-variant": "#e5dcc9",
|
||||||
|
"primary-fixed-dim": "#efc900",
|
||||||
|
"primary-dim": "#5e4e00",
|
||||||
|
"primary-container": "#ffd709",
|
||||||
|
"inverse-surface": "#110e06",
|
||||||
|
"on-background": "#322e25",
|
||||||
|
"inverse-on-surface": "#a29c8f",
|
||||||
|
"on-secondary-fixed": "#512a00",
|
||||||
|
"on-tertiary-fixed": "#00480f",
|
||||||
|
"surface-container": "#f0e7d6",
|
||||||
|
"secondary-fixed": "#ffc697",
|
||||||
|
"tertiary-fixed-dim": "#83e881",
|
||||||
|
"secondary-dim": "#794200",
|
||||||
|
"on-primary-fixed": "#453900",
|
||||||
|
"surface-container-high": "#eae2d0",
|
||||||
|
"on-tertiary-fixed-variant": "#00691a",
|
||||||
|
"on-surface-variant": "#605b50",
|
||||||
|
"on-surface": "#322e25",
|
||||||
|
"on-tertiary-container": "#005e17",
|
||||||
|
"surface": "#fef6e7",
|
||||||
|
"tertiary-container": "#91f78e",
|
||||||
|
"tertiary-dim": "#005d16",
|
||||||
|
"outline-variant": "#b3ac9f",
|
||||||
|
"error": "#b02500",
|
||||||
|
"on-primary-fixed-variant": "#665500",
|
||||||
|
"on-primary-container": "#5b4b00",
|
||||||
|
"background": "#fef6e7",
|
||||||
|
"on-secondary-fixed-variant": "#7a4300",
|
||||||
|
"on-secondary-container": "#6d3b00",
|
||||||
|
"on-primary": "#fff2cd",
|
||||||
|
"inverse-primary": "#ffd709",
|
||||||
|
"outline": "#7c766a",
|
||||||
|
"error-dim": "#b92902",
|
||||||
|
"surface-container-lowest": "#ffffff",
|
||||||
|
"on-error": "#ffefec",
|
||||||
|
"tertiary": "#006b1b",
|
||||||
|
"secondary": "#8a4c00",
|
||||||
|
"on-tertiary": "#d1ffc8",
|
||||||
|
"primary": "#6c5a00",
|
||||||
|
"surface-container-low": "#f8f0e0",
|
||||||
|
"surface-dim": "#dcd4c0",
|
||||||
|
"secondary-fixed-dim": "#ffb470",
|
||||||
|
"surface-tint": "#6c5a00",
|
||||||
|
"primary-fixed": "#ffd709",
|
||||||
|
"on-error-container": "#520c00",
|
||||||
|
"tertiary-fixed": "#91f78e",
|
||||||
|
"error-container": "#f95630"
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
"headline": ["Plus Jakarta Sans"],
|
||||||
|
"body": ["Plus Jakarta Sans"],
|
||||||
|
"label": ["Plus Jakarta Sans"]
|
||||||
|
},
|
||||||
|
borderRadius: {"DEFAULT": "0.75rem", "lg": "1rem", "xl": "1.5rem", "full": "9999px"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.material-symbols-outlined {
|
||||||
|
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.hide-scrollbar::-webkit-scrollbar { display: none; }
|
||||||
|
.hide-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
body {
|
||||||
|
min-height: max(884px, 100dvh);
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-background font-body text-on-surface selection:bg-primary-container">
|
||||||
|
<!-- TopAppBar -->
|
||||||
|
<header class="fixed top-0 w-full z-50 bg-[#fef6e7]/80 dark:bg-stone-900/80 backdrop-blur-xl">
|
||||||
|
<div class="flex justify-between items-center w-full px-6 py-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="material-symbols-outlined text-[#6c5a00] dark:text-yellow-500 text-2xl hover:scale-95 transition-transform cursor-pointer">arrow_back</span>
|
||||||
|
<div class="w-10 h-10 rounded-full bg-primary-container flex items-center justify-center overflow-hidden border-2 border-white shadow-sm">
|
||||||
|
<img alt="Duck icon" data-alt="cute stylized duck head illustration in warm yellow and orange colors, playful nursery art style" src="https://lh3.googleusercontent.com/aida-public/AB6AXuDvc8PWsCtmX47Is3M__zrkzx_wmWFN3lZV-S1KZ1eKQDxsP5GGmrNMyWi2IjqRDxRvFo2t1-HZrrlUuRBTXk0lOrZGY6nZfs3fS26fjQ2lK_dFTWf4i4pijmIlZw7clKCT4r7XrgxPrGm173B32CRtocnaLSgKmvDKlV695U-_J9fai85AAD2FXkoEbOeYQf4vo0EWuXCzUsuc7_93R4xWz_5NFcunMraCNELOvS3t9jv2vm44th_W6k5_KLR2F-LazXHyYEzhLq8"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h1 class="font-headline font-bold tracking-tight text-[#322e25] dark:text-stone-100 text-xl">按年龄学</h1>
|
||||||
|
<span class="material-symbols-outlined text-[#6c5a00] dark:text-yellow-500 text-2xl hover:scale-95 transition-transform cursor-pointer">account_circle</span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="pt-24 pb-32 px-6 max-w-2xl mx-auto space-y-10">
|
||||||
|
<!-- Age Selector Section -->
|
||||||
|
<section class="relative">
|
||||||
|
<div class="flex gap-4 overflow-x-auto hide-scrollbar py-4 -mx-2 px-2 snap-x items-center"><!-- 3-4岁 -->
|
||||||
|
<div class="snap-center shrink-0 w-32 h-24 rounded-xl bg-[#f5f5f5] flex flex-col items-center justify-center transition-all">
|
||||||
|
<div class="font-bold text-xl text-[#322e25]">3-4 岁</div>
|
||||||
|
<div class="text-xs text-[#322e25]/60 mt-1">启蒙认知</div>
|
||||||
|
</div>
|
||||||
|
<!-- 4-5岁 -->
|
||||||
|
<div class="snap-center shrink-0 w-32 h-24 rounded-xl bg-[#f5f5f5] flex flex-col items-center justify-center transition-all">
|
||||||
|
<div class="font-bold text-xl text-[#322e25]">4-5 岁</div>
|
||||||
|
<div class="text-xs text-[#322e25]/60 mt-1">基础练习</div>
|
||||||
|
</div>
|
||||||
|
<!-- 5-6岁 (Active) -->
|
||||||
|
<div class="snap-center shrink-0 w-32 h-24 rounded-xl bg-[#FFD700] border-2 border-white shadow-[0_8px_20px_rgba(255,215,0,0.3)] flex flex-col items-center justify-center scale-110 relative z-10 transition-all">
|
||||||
|
<div class="font-black text-xl text-[#6c5a00]">5-6 岁</div>
|
||||||
|
<div class="text-xs font-bold text-[#6c5a00]/80 mt-1">能力提升</div>
|
||||||
|
<div class="absolute -top-2 -right-2 bg-on-tertiary-container text-white text-[10px] px-2 py-0.5 rounded-full">当前</div>
|
||||||
|
</div>
|
||||||
|
<!-- 6-7岁 -->
|
||||||
|
<div class="snap-center shrink-0 w-32 h-24 rounded-xl bg-[#f5f5f5] flex flex-col items-center justify-center transition-all">
|
||||||
|
<div class="font-bold text-xl text-[#322e25]">6-7 岁</div>
|
||||||
|
<div class="text-xs text-[#322e25]/60 mt-1">幼小衔接</div>
|
||||||
|
</div>
|
||||||
|
<!-- 7-8岁 -->
|
||||||
|
<div class="snap-center shrink-0 w-32 h-24 rounded-xl bg-[#f5f5f5] flex flex-col items-center justify-center transition-all">
|
||||||
|
<div class="font-bold text-xl text-[#322e25]">7-8 岁</div>
|
||||||
|
<div class="text-xs text-[#322e25]/60 mt-1">知识拓展</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<!-- Ability Goals Card -->
|
||||||
|
<section class="bg-surface-container-lowest rounded-xl p-6 shadow-sm border border-surface-container">
|
||||||
|
<h2 class="text-xl font-extrabold text-on-secondary-container mb-6 flex items-center gap-2">
|
||||||
|
<span class="material-symbols-outlined text-primary" style="font-variation-settings: 'FILL' 1;">stars</span>
|
||||||
|
5-6 岁能力目标
|
||||||
|
</h2>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
|
<div class="p-4 rounded-lg bg-surface-container-low border border-surface-variant/30">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<span class="text-xl">🔢</span>
|
||||||
|
<span class="font-bold text-primary">数感</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-on-surface-variant leading-relaxed">10以内加减法、凑十法</p>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 rounded-lg bg-surface-container-low border border-surface-variant/30">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<span class="text-xl">✏️</span>
|
||||||
|
<span class="font-bold text-primary">书写</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-on-surface-variant leading-relaxed">练字帖、拼音入门</p>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 rounded-lg bg-surface-container-low border border-surface-variant/30">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<span class="text-xl">🧩</span>
|
||||||
|
<span class="font-bold text-primary">思维</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-on-surface-variant leading-relaxed">方格推理、格子仿画 5x5</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Learning Path Section -->
|
||||||
|
<section class="space-y-6">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h2 class="text-2xl font-extrabold text-on-surface tracking-tight flex items-center gap-3">
|
||||||
|
<span class="w-2 h-8 bg-primary rounded-full"></span>
|
||||||
|
4 周推荐学习路线
|
||||||
|
</h2>
|
||||||
|
<div class="bg-surface-container px-3 py-1 rounded-full flex items-center gap-1">
|
||||||
|
<span class="text-[10px] font-bold text-on-surface-variant">4 周 • 每周 3 练</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-8">
|
||||||
|
<!-- Week 1 -->
|
||||||
|
<div class="bg-white rounded-xl border border-stone-100 overflow-hidden shadow-sm">
|
||||||
|
<div class="px-5 py-4 flex items-baseline gap-3 bg-stone-50">
|
||||||
|
<span class="font-black text-xl text-[#333333]">第 1 周</span>
|
||||||
|
<span class="font-bold text-sm text-stone-500">数感启蒙</span>
|
||||||
|
</div>
|
||||||
|
<div class="divide-y divide-stone-100">
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">找数字涂一涂</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">5 以内加法</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">数数连一连</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Week 2 -->
|
||||||
|
<div class="bg-white rounded-xl border border-stone-100 overflow-hidden shadow-sm">
|
||||||
|
<div class="px-5 py-4 flex items-baseline gap-3 bg-stone-50">
|
||||||
|
<span class="font-black text-xl text-[#333333]">第 2 周</span>
|
||||||
|
<span class="font-bold text-sm text-stone-500">形状与连线</span>
|
||||||
|
</div>
|
||||||
|
<div class="divide-y divide-stone-100">
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">识别形状</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">线条识别</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">数字点连线</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Week 3 -->
|
||||||
|
<div class="bg-white rounded-xl border border-stone-100 overflow-hidden shadow-sm">
|
||||||
|
<div class="px-5 py-4 flex items-baseline gap-3 bg-stone-50">
|
||||||
|
<span class="font-black text-xl text-[#333333]">第 3 周</span>
|
||||||
|
<span class="font-bold text-sm text-stone-500">趣味专注</span>
|
||||||
|
</div>
|
||||||
|
<div class="divide-y divide-stone-100">
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">颜色找规律</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">方格推理</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">格子仿画</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Week 4 -->
|
||||||
|
<div class="bg-white rounded-xl border border-stone-100 overflow-hidden shadow-sm">
|
||||||
|
<div class="px-5 py-4 flex items-baseline gap-3 bg-stone-50">
|
||||||
|
<span class="font-black text-xl text-[#333333]">第 4 周</span>
|
||||||
|
<span class="font-bold text-sm text-stone-500">综合练习</span>
|
||||||
|
</div>
|
||||||
|
<div class="divide-y divide-stone-100">
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">10以内加减法</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">识字卡</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="px-5 py-4 flex items-center justify-between group hover:bg-stone-50/50 transition-colors">
|
||||||
|
<span class="font-bold text-[#333333]">连连看</span>
|
||||||
|
<button class="flex items-center gap-1 bg-[#FFD700] text-[#6c5a00] px-4 py-1.5 rounded-full text-sm font-bold shadow-sm active:scale-95 transition-all">
|
||||||
|
去练习 <span class="material-symbols-outlined text-sm">arrow_forward</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Recommended Section -->
|
||||||
|
<section class="space-y-4">
|
||||||
|
<div class="flex justify-between items-end">
|
||||||
|
<h2 class="text-xl font-extrabold text-on-surface">[为你推荐]</h2>
|
||||||
|
<span class="text-sm font-bold text-primary cursor-pointer">更多</span>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<!-- Card 1 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="vibrant educational math worksheet showing numbers and colorful apples for counting, soft sunny lighting" src="https://lh3.googleusercontent.com/aida-public/AB6AXuD-3lADhclTGODN9WtNh5v8bQPLysbllbKNkH40bAmVyE5d54PwfTBOiX9nER1hpE4rzHAfsmM_JhVnsE4EbdA914rYIb3S3e4r9QKFjUqYmj2XpE4MlYr_vLkG4oeMnvnHOqGC96nLGrPSOq-fpIddV7RSlYLDeNccBs0G2oUOy-6jIMujzTuEGk4nnxme5rpxs7rYjwcvVsqM5dlkpJthY42e4B3lSPH7ezx187WRSk--m4ZiWmAI52mMOiygzTSWoNormlvfvdM"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">10以内加减法</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card 2 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="preschool addition flashcards with cute animal illustrations, warm morning light in a classroom" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBYS4O7PyflR5q8M6oXKwj_8QHzex3OL3YvdHBncutm7a_bjlZj83-8UBpGUQvJO20V0BnAdU3iKEoLlUqwpS60CiPhVyxYaHEAqv52P5YUhJdjf0hpLir1Li4rdI_-eqGkPTasYl-5kD2r8-RjUokKg_HiW5_TF72UbxFXHQh4BefYJZfl0Oc9-aTQvkbFL0C3tagi9Qv1jRsgQldMFU4M7cHt8KkxhO1QDF7-R85ZFORJM0RiqV2l-jn0c-UscKtuWtroiX6UUKk"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">拼音描红</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card 3 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="logical pattern game for kids with colorful geometric shapes and grids, clean minimalist aesthetic" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBSafbTyucs8JLpTgibRWwAJsHukrklTAuEnaAzax_Kr1RNCwHjqpQjta0Q-h47ClufzEmaHPgCIOlm_a2lL4gNlgBDyraCwzRU7aWCf_Fj_dM1cLGzROJmtqrdHKjQzTbCp0_Da8BvXi4a4H2X4RAYVPnLbZVmbgPXrTvpKgEI605kIMmr3n0--WojJQRsF4B_xCho80gABbIaMTHJHrs9xdEY6fZKg8ArQx7lRbJ6_EsLLB_C5a5crZ_begwruXKr3pmdU6KneC8"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">趣味找不同</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card 4 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="visual tracking exercise showing a winding maze path with a small mouse and cheese, soft pastel colors" src="https://lh3.googleusercontent.com/aida-public/AB6AXuAOZHI1Dz6ax4iFUb3QYL-EWp2euA_3kyUeCcu6V57BBCzarMwKnFzcpJxJn4X4woklWFB08Ii1w6zsk0H5eDaPdgUYmsvY0NFqvAhKN_IbZGZjZnclZlBHkLRcX64Nl767L2pg01FQu9Tp6nq2p3lAuYeEQ2fiIdXh4j-QHyikbmx4_aDlx5X5fC0fqMMxWykhwLNkDzl2Rs3ucXj7zYnUP-dNNY-aj_JvqkY4pqoXQDt9ZJcfSeL0dWes7nvD5U2C_JFhrk1bVkw"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">走迷宫大挑战</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card 5 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden bg-primary-container/20">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="creative dot-to-dot puzzle for kids forming a friendly dinosaur, soft natural lighting" src="https://lh3.googleusercontent.com/aida-public/AB6AXuD-3lADhclTGODN9WtNh5v8bQPLysbllbKNkH40bAmVyE5d54PwfTBOiX9nER1hpE4rzHAfsmM_JhVnsE4EbdA914rYIb3S3e4r9QKFjUqYmj2XpE4MlYr_vLkG4oeMnvnHOqGC96nLGrPSOq-fpIddV7RSlYLDeNccBs0G2oUOy-6jIMujzTuEGk4nnxme5rpxs7rYjwcvVsqM5dlkpJthY42e4B3lSPH7ezx187WRSk--m4ZiWmAI52mMOiygzTSWoNormlvfvdM"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">数字点连线</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card 6 -->
|
||||||
|
<div class="bg-white rounded-xl overflow-hidden border border-stone-100 shadow-sm flex flex-col">
|
||||||
|
<div class="aspect-[4/3] w-full overflow-hidden bg-secondary-container/20">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="kids handwriting practice sheet with chinese characters and stroke order guides, neat layout" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBYS4O7PyflR5q8M6oXKwj_8QHzex3OL3YvdHBncutm7a_bjlZj83-8UBpGUQvJO20V0BnAdU3iKEoLlUqwpS60CiPhVyxYaHEAqv52P5YUhJdjf0hpLir1Li4rdI_-eqGkPTasYl-5kD2r8-RjUokKg_HiW5_TF72UbxFXHQh4BefYJZfl0Oc9-aTQvkbFL0C3tagi9Qv1jRsgQldMFU4M7cHt8KkxhO1QDF7-R85ZFORJM0RiqV2l-jn0c-UscKtuWtroiX6UUKk"/>
|
||||||
|
</div>
|
||||||
|
<div class="p-3">
|
||||||
|
<h4 class="font-bold text-sm text-[#333333]">方格推理高手</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<!-- BottomNavBar -->
|
||||||
|
<nav class="fixed bottom-0 left-0 w-full flex justify-around items-center px-4 pb-8 pt-3 bg-[#f8f0e0]/80 dark:bg-stone-800/80 backdrop-blur-xl rounded-t-[1.5rem] z-50 shadow-[0_-8px_32px_rgba(50,46,37,0.06)]">
|
||||||
|
<div class="flex flex-col items-center justify-center text-[#322e25]/60 dark:text-stone-400 px-5 py-2 hover:bg-[#f0e7d6] dark:hover:bg-stone-700 rounded-full transition-all cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined text-2xl">map</span>
|
||||||
|
<span class="font-headline text-xs font-semibold mt-1">学习地图</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center justify-center bg-[#ffd709] dark:bg-yellow-600 text-[#6c5a00] dark:text-yellow-950 rounded-full px-5 py-2 scale-105 shadow-md transition-all active:scale-90">
|
||||||
|
<span class="material-symbols-outlined text-2xl" style="font-variation-settings: 'FILL' 1;">local_library</span>
|
||||||
|
<span class="font-headline text-xs font-semibold mt-1">我的课程</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center justify-center text-[#322e25]/60 dark:text-stone-400 px-5 py-2 hover:bg-[#f0e7d6] dark:hover:bg-stone-700 rounded-full transition-all cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined text-2xl">explore</span>
|
||||||
|
<span class="font-headline text-xs font-semibold mt-1">发现</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center justify-center text-[#322e25]/60 dark:text-stone-400 px-5 py-2 hover:bg-[#f0e7d6] dark:hover:bg-stone-700 rounded-full transition-all cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined text-2xl">family_restroom</span>
|
||||||
|
<span class="font-headline text-xs font-semibold mt-1">家长中心</span>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</body></html>
|
||||||
|
After Width: | Height: | Size: 149 KiB |
@@ -0,0 +1,209 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html class="light" lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<title>我的收藏 - 下载历史</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||||
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
|
<script id="tailwind-config">
|
||||||
|
tailwind.config = {
|
||||||
|
darkMode: "class",
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
"surface-variant": "#e5dcc9",
|
||||||
|
"on-tertiary-fixed-variant": "#00691a",
|
||||||
|
"secondary-container": "#ffc697",
|
||||||
|
"error-container": "#f95630",
|
||||||
|
"error-dim": "#b92902",
|
||||||
|
"tertiary-fixed-dim": "#83e881",
|
||||||
|
"primary-fixed-dim": "#efc900",
|
||||||
|
"on-secondary-container": "#6d3b00",
|
||||||
|
"on-error": "#ffefec",
|
||||||
|
"on-background": "#322e25",
|
||||||
|
"surface-container": "#f0e7d6",
|
||||||
|
"secondary-fixed-dim": "#ffb470",
|
||||||
|
"surface-tint": "#6c5a00",
|
||||||
|
"on-primary-container": "#5b4b00",
|
||||||
|
"inverse-primary": "#ffd709",
|
||||||
|
"primary": "#6c5a00",
|
||||||
|
"inverse-surface": "#110e06",
|
||||||
|
"surface-container-lowest": "#ffffff",
|
||||||
|
"primary-fixed": "#ffd709",
|
||||||
|
"surface-bright": "#fef6e7",
|
||||||
|
"surface-dim": "#dcd4c0",
|
||||||
|
"outline": "#7c766a",
|
||||||
|
"background": "#fef6e7",
|
||||||
|
"surface-container-high": "#eae2d0",
|
||||||
|
"on-primary-fixed-variant": "#665500",
|
||||||
|
"primary-container": "#ffd709",
|
||||||
|
"on-surface": "#322e25",
|
||||||
|
"primary-dim": "#5e4e00",
|
||||||
|
"surface-container-low": "#f8f0e0",
|
||||||
|
"on-tertiary": "#d1ffc8",
|
||||||
|
"on-secondary": "#fff0e6",
|
||||||
|
"outline-variant": "#b3ac9f",
|
||||||
|
"inverse-on-surface": "#a29c8f",
|
||||||
|
"on-surface-variant": "#605b50",
|
||||||
|
"on-tertiary-container": "#005e17",
|
||||||
|
"tertiary-fixed": "#91f78e",
|
||||||
|
"secondary": "#8a4c00",
|
||||||
|
"on-secondary-fixed": "#512a00",
|
||||||
|
"secondary-fixed": "#ffc697",
|
||||||
|
"on-error-container": "#520c00",
|
||||||
|
"secondary-dim": "#794200",
|
||||||
|
"on-primary": "#fff2cd",
|
||||||
|
"tertiary-dim": "#005d16",
|
||||||
|
"surface": "#fef6e7",
|
||||||
|
"tertiary": "#006b1b",
|
||||||
|
"on-tertiary-fixed": "#00480f",
|
||||||
|
"on-primary-fixed": "#453900",
|
||||||
|
"on-secondary-fixed-variant": "#7a4300",
|
||||||
|
"tertiary-container": "#91f78e",
|
||||||
|
"surface-container-highest": "#e5dcc9",
|
||||||
|
"error": "#b02500"
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
"headline": ["Plus Jakarta Sans", "system-ui", "sans-serif"],
|
||||||
|
"body": ["Plus Jakarta Sans", "system-ui", "sans-serif"],
|
||||||
|
"label": ["Plus Jakarta Sans", "system-ui", "sans-serif"]
|
||||||
|
},
|
||||||
|
borderRadius: {"DEFAULT": "1rem", "lg": "2rem", "xl": "3rem", "full": "9999px"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.material-symbols-outlined {
|
||||||
|
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
min-height: max(884px, 100dvh);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-background text-on-surface min-h-screen flex flex-col">
|
||||||
|
<!-- TopAppBar from JSON -->
|
||||||
|
<header class="bg-[#f8f0e0]/80 backdrop-blur-xl text-[#6c5a00] font-plus-jakarta docked full-width top-0 z-50 flex justify-between items-center w-full px-6 py-4 sticky">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<span class="material-symbols-outlined cursor-pointer active:scale-95 transition-transform">arrow_back</span>
|
||||||
|
<h1 class="text-2xl font-bold tracking-tight leading-[1.6]">我的收藏</h1>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<!-- Secondary action for clearing history as requested -->
|
||||||
|
<button class="text-[#6c5a00] opacity-60 text-sm font-semibold hover:opacity-100 transition-opacity px-3 py-1 rounded-full hover:bg-[#f0e7d6]">清空历史</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="flex-1 px-4 pt-4 pb-32 max-w-2xl mx-auto w-full">
|
||||||
|
<!-- Segmented Control -->
|
||||||
|
<div class="bg-surface-container rounded-full p-1.5 flex mb-8">
|
||||||
|
<button class="flex-1 py-3 text-sm font-bold text-on-surface-variant rounded-full transition-all">
|
||||||
|
收藏的题型
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 py-3 text-sm font-bold text-on-primary-container bg-primary-container rounded-full shadow-sm">
|
||||||
|
下载历史
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Download History List -->
|
||||||
|
<div class="space-y-4">
|
||||||
|
<!-- History Section: Today -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h3 class="text-xs font-bold text-outline uppercase tracking-widest px-4 mb-3">今天</h3>
|
||||||
|
<div class="space-y-4"><!-- History Item 1 -->
|
||||||
|
<div class="bg-surface-container-low rounded-2xl p-4 flex gap-4 items-center group active:scale-[0.98] transition-all">
|
||||||
|
<div class="w-20 h-20 rounded-xl overflow-hidden flex-shrink-0 bg-surface-container-highest">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="a minimalist educational worksheet preview with handwriting guides for chinese pinyin and soft warm studio lighting" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBCm6X4rhibw2_WxP-U0dDyOsiYol3y12OnEXHRkPONZYMQBUcr3Grqo1IbwH3sdWPg5jIUeIbr_AEwv_hFwUOMMz9jTIIMc6Pke1bzSvlQcgdDq-zMEIU4A--IQFX59ac-8BscCajXZcd4v8rE6JEZFf1-aztKclPTkE_Rrgj-nbVCy5V6bOE6yDOB67VdTbcqiOdaFN18ju_MgWVo3FQZLwIUZOBahkPl0vDIKA0mkiaGK9eiFpfnERYxkYG3eWJZ40umTYp46Jo"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<h4 class="text-lg font-bold text-on-surface mb-1 leading-tight">拼音描红 · 声母表</h4>
|
||||||
|
<div class="flex items-center gap-2 text-on-surface-variant/70 text-sm">
|
||||||
|
<span class="material-symbols-outlined text-sm" style="font-variation-settings: 'opsz' 18;">schedule</span>
|
||||||
|
<span>14:32</span>
|
||||||
|
<span class="w-1 h-1 bg-outline-variant rounded-full"></span>
|
||||||
|
<span class="text-tertiary font-medium">已保存相册</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-10 h-10 rounded-full flex items-center justify-center hover:bg-surface-container transition-colors">
|
||||||
|
<span class="material-symbols-outlined text-outline">more_vert</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- History Item 2 -->
|
||||||
|
<div class="bg-surface-container-low rounded-2xl p-4 flex gap-4 items-center active:scale-[0.98] transition-all">
|
||||||
|
<div class="w-20 h-20 rounded-xl overflow-hidden flex-shrink-0 bg-surface-container-highest">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="a colorful math worksheet for young kids featuring simple addition problems and hand-drawn star shapes in sunny colors" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBxNORxN_vftYMLaMjZVscL-o9bZnBrfUi7IAqOrFATIztGV12_0ggwgae-fmk0cORWtysZWJJDcAzj0NEyniFxbREoGDuq9U4kytprJkA70_k0MCzPgStmq0bRwu1Gx1j4peglFam8PH6IlPvOMbiHQ7-fMFfYTSBtA1p7Dp06NDOzS2VrMlF8VxjEgihVmhHUrHePVvXlktUkXBKNzrXEXrogO3iOyouTUKyvJh0TeChKUv3KohMoD5ol7C3fjBhdHf7QD4StOQ4"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<h4 class="text-lg font-bold text-on-surface mb-1 leading-tight">趣味口算题卡</h4>
|
||||||
|
<div class="flex items-center gap-2 text-on-surface-variant/70 text-sm">
|
||||||
|
<span class="material-symbols-outlined text-sm" style="font-variation-settings: 'opsz' 18;">schedule</span>
|
||||||
|
<span>09:15</span>
|
||||||
|
<span class="w-1 h-1 bg-outline-variant rounded-full"></span>
|
||||||
|
<span class="text-on-surface-variant/50">已下载 PDF</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-10 h-10 rounded-full flex items-center justify-center hover:bg-surface-container transition-colors">
|
||||||
|
<span class="material-symbols-outlined text-outline">more_vert</span>
|
||||||
|
</button>
|
||||||
|
</div></div>
|
||||||
|
</div>
|
||||||
|
<!-- History Section: Yesterday -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h3 class="text-xs font-bold text-outline uppercase tracking-widest px-4 mb-3">昨天</h3>
|
||||||
|
<div class="space-y-4"><!-- History Item 3 -->
|
||||||
|
<div class="bg-surface-container-low rounded-2xl p-4 flex gap-4 items-center active:scale-[0.98] transition-all opacity-90">
|
||||||
|
<div class="w-20 h-20 rounded-xl overflow-hidden flex-shrink-0 bg-surface-container-highest">
|
||||||
|
<div class="w-full h-full bg-gradient-to-br from-secondary-container to-primary-container/20 flex items-center justify-center">
|
||||||
|
<span class="material-symbols-outlined text-on-secondary-container text-3xl">draw</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<h4 class="text-lg font-bold text-on-surface mb-1 leading-tight">汉字笔画基础训练</h4>
|
||||||
|
<div class="flex items-center gap-2 text-on-surface-variant/70 text-sm">
|
||||||
|
<span class="material-symbols-outlined text-sm" style="font-variation-settings: 'opsz' 18;">schedule</span>
|
||||||
|
<span>16:40</span>
|
||||||
|
<span class="w-1 h-1 bg-outline-variant rounded-full"></span>
|
||||||
|
<span class="text-on-surface-variant/50">已发送邮件</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-10 h-10 rounded-full flex items-center justify-center hover:bg-surface-container transition-colors">
|
||||||
|
<span class="material-symbols-outlined text-outline">more_vert</span>
|
||||||
|
</button>
|
||||||
|
</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Empty State Logic (Visualized if no content) -->
|
||||||
|
<!-- <div class="hidden flex-col items-center justify-center py-20 text-center">
|
||||||
|
<span class="material-symbols-outlined text-6xl text-outline-variant mb-4">history_toggle_off</span>
|
||||||
|
<p class="text-on-surface-variant font-medium">暂无下载记录</p>
|
||||||
|
</div> -->
|
||||||
|
</main>
|
||||||
|
<!-- BottomNavBar from JSON -->
|
||||||
|
<nav class="fixed bottom-0 left-0 w-full flex justify-around items-center px-4 pb-6 pt-2 bg-[#f8f0e0]/80 backdrop-blur-xl z-50 rounded-t-[3rem] shadow-[0_-8px_32px_0_rgba(50,46,37,0.06)]">
|
||||||
|
<div class="flex flex-col items-center justify-center text-[#322e25] dark:text-[#fef6e7] opacity-70 px-4 py-2 hover:opacity-100 transition-opacity active:scale-90 duration-200 cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined">explore</span>
|
||||||
|
<span class="font-plus-jakarta text-[12px] font-semibold leading-[1.6]">发现</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center justify-center text-[#322e25] dark:text-[#fef6e7] opacity-70 px-4 py-2 hover:opacity-100 transition-opacity active:scale-90 duration-200 cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined">child_care</span>
|
||||||
|
<span class="font-plus-jakarta text-[12px] font-semibold leading-[1.6]">分龄</span>
|
||||||
|
</div>
|
||||||
|
<!-- Active Tab: 收藏 -->
|
||||||
|
<div class="flex flex-col items-center justify-center bg-[#ffd709] text-[#6d3b00] rounded-full px-6 py-2 scale-105 active:scale-90 transition-all duration-200 cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 1;">favorite</span>
|
||||||
|
<span class="font-plus-jakarta text-[12px] font-semibold leading-[1.6]">收藏</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center justify-center text-[#322e25] dark:text-[#fef6e7] opacity-70 px-4 py-2 hover:opacity-100 transition-opacity active:scale-90 duration-200 cursor-pointer">
|
||||||
|
<span class="material-symbols-outlined">person</span>
|
||||||
|
<span class="font-plus-jakarta text-[12px] font-semibold leading-[1.6]">我的</span>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html class="light" lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
.material-symbols-outlined {
|
||||||
|
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||||
|
}
|
||||||
|
.glass-nav {
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
-webkit-backdrop-filter: blur(20px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script id="tailwind-config">
|
||||||
|
tailwind.config = {
|
||||||
|
darkMode: "class",
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
"surface-variant": "#e5dcc9",
|
||||||
|
"on-tertiary-fixed-variant": "#00691a",
|
||||||
|
"secondary-container": "#ffc697",
|
||||||
|
"error-container": "#f95630",
|
||||||
|
"error-dim": "#b92902",
|
||||||
|
"tertiary-fixed-dim": "#83e881",
|
||||||
|
"primary-fixed-dim": "#efc900",
|
||||||
|
"on-secondary-container": "#6d3b00",
|
||||||
|
"on-error": "#ffefec",
|
||||||
|
"on-background": "#322e25",
|
||||||
|
"surface-container": "#f0e7d6",
|
||||||
|
"secondary-fixed-dim": "#ffb470",
|
||||||
|
"surface-tint": "#6c5a00",
|
||||||
|
"on-primary-container": "#5b4b00",
|
||||||
|
"inverse-primary": "#ffd709",
|
||||||
|
"primary": "#6c5a00",
|
||||||
|
"inverse-surface": "#110e06",
|
||||||
|
"surface-container-lowest": "#ffffff",
|
||||||
|
"primary-fixed": "#ffd709",
|
||||||
|
"surface-bright": "#fef6e7",
|
||||||
|
"surface-dim": "#dcd4c0",
|
||||||
|
"outline": "#7c766a",
|
||||||
|
"background": "#fef6e7",
|
||||||
|
"surface-container-high": "#eae2d0",
|
||||||
|
"on-primary-fixed-variant": "#665500",
|
||||||
|
"primary-container": "#ffd709",
|
||||||
|
"on-surface": "#322e25",
|
||||||
|
"primary-dim": "#5e4e00",
|
||||||
|
"surface-container-low": "#f8f0e0",
|
||||||
|
"on-tertiary": "#d1ffc8",
|
||||||
|
"on-secondary": "#fff0e6",
|
||||||
|
"outline-variant": "#b3ac9f",
|
||||||
|
"inverse-on-surface": "#a29c8f",
|
||||||
|
"on-surface-variant": "#605b50",
|
||||||
|
"on-tertiary-container": "#005e17",
|
||||||
|
"tertiary-fixed": "#91f78e",
|
||||||
|
"secondary": "#8a4c00",
|
||||||
|
"on-secondary-fixed": "#512a00",
|
||||||
|
"secondary-fixed": "#ffc697",
|
||||||
|
"on-error-container": "#520c00",
|
||||||
|
"secondary-dim": "#794200",
|
||||||
|
"on-primary": "#fff2cd",
|
||||||
|
"tertiary-dim": "#005d16",
|
||||||
|
"surface": "#fef6e7",
|
||||||
|
"tertiary": "#006b1b",
|
||||||
|
"on-tertiary-fixed": "#00480f",
|
||||||
|
"on-primary-fixed": "#453900",
|
||||||
|
"on-secondary-fixed-variant": "#7a4300",
|
||||||
|
"tertiary-container": "#91f78e",
|
||||||
|
"surface-container-highest": "#e5dcc9",
|
||||||
|
"error": "#b02500"
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
"headline": ["Plus Jakarta Sans"],
|
||||||
|
"body": ["Plus Jakarta Sans"],
|
||||||
|
"label": ["Plus Jakarta Sans"]
|
||||||
|
},
|
||||||
|
borderRadius: {"DEFAULT": "1rem", "lg": "2rem", "xl": "3rem", "full": "9999px"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
min-height: max(884px, 100dvh);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-background text-on-surface min-h-screen pb-32">
|
||||||
|
<!-- Top App Bar -->
|
||||||
|
<header class="bg-[#f8f0e0]/80 dark:bg-[#322e25]/80 backdrop-blur-xl docked full-width top-0 z-50 flex justify-between items-center w-full px-6 py-4 sticky">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<button class="w-10 h-10 flex items-center justify-center rounded-full hover:bg-[#f0e7d6] active:scale-95 transition-all text-[#6c5a00]">
|
||||||
|
<span class="material-symbols-outlined" data-icon="arrow_back">arrow_back</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="font-plus-jakarta text-2xl font-bold tracking-tight leading-[1.6] text-[#6c5a00]">我的收藏</h1>
|
||||||
|
</div>
|
||||||
|
<button class="w-10 h-10 flex items-center justify-center rounded-full hover:bg-[#f0e7d6] active:scale-95 transition-all text-[#6c5a00]">
|
||||||
|
<span class="material-symbols-outlined" data-icon="search">search</span>
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
<main class="max-w-2xl mx-auto px-6 pt-6">
|
||||||
|
<!-- Segmented Control -->
|
||||||
|
<div class="bg-surface-container p-1.5 rounded-full flex items-center mb-8 shadow-sm">
|
||||||
|
<button class="flex-1 py-3 px-4 rounded-full bg-primary-container text-on-primary-container font-bold text-sm transition-all shadow-sm">
|
||||||
|
收藏的题型
|
||||||
|
</button>
|
||||||
|
<button class="flex-1 py-3 px-4 rounded-full text-on-surface-variant font-medium text-sm hover:bg-surface-container-high transition-all">
|
||||||
|
下载历史
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Favorites List -->
|
||||||
|
<div class="space-y-4">
|
||||||
|
<!-- Card 1 -->
|
||||||
|
<div class="bg-surface-container-low p-4 flex items-center gap-4 active:scale-[0.98] transition-transform duration-200 rounded-2xl">
|
||||||
|
<div class="w-20 h-20 overflow-hidden flex-shrink-0 bg-surface-container-highest rounded-xl">
|
||||||
|
<img alt="Worksheet Thumbnail" class="w-full h-full object-cover" data-alt="Close-up of a colorful children's math worksheet with simple addition problems and cute illustrated animals on creamy paper." src="https://lh3.googleusercontent.com/aida-public/AB6AXuD7khp0rJABfa9yFrMt9ZgIhAPyN44XmJ2pXNBgCzbgBvwA5ptFZVty013JedVzbE9_VvCQnToN7QETLDKjtiX22igzK-a5h4E8wjKrembFW4eVuk1RsJIbHjx3_cCz0hJ7_t76hF8t-Qdod_5R9sNMor1ZEjf6dGNp6UI_eIBjsN9b22iCTJ2VB-IEh0Rmil6_iC4Og-4I03IcQDV2rTHYIXcZxjiay1IiYGXw3wJ3bfo2SF2N7ZFT00akTgYU-9JyF7xJ6n15Yzc"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<h3 class="font-bold text-lg text-on-surface leading-tight mb-1">10以内加法</h3>
|
||||||
|
<p class="text-on-surface-variant text-xs mb-2 flex items-center gap-1">
|
||||||
|
数学启蒙 · 4-6岁 ·
|
||||||
|
<span class="flex text-primary-fixed-dim">
|
||||||
|
<span class="material-symbols-outlined text-[14px]" style="font-variation-settings: 'FILL' 1;">star</span>
|
||||||
|
<span class="material-symbols-outlined text-[14px]" style="font-variation-settings: 'FILL' 1;">star</span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<span class="text-[10px] text-outline px-2 py-0.5 bg-surface-container rounded-full uppercase tracking-wider">收藏于 3 天前</span>
|
||||||
|
</div>
|
||||||
|
<button class="w-10 h-10 flex items-center justify-center rounded-full text-error transition-colors">
|
||||||
|
<span class="material-symbols-outlined" data-icon="favorite" style="font-variation-settings: 'FILL' 1;">favorite</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Card 2 -->
|
||||||
|
<div class="bg-surface-container-low p-4 flex items-center gap-4 active:scale-[0.98] transition-transform duration-200 rounded-2xl">
|
||||||
|
<div class="w-20 h-20 overflow-hidden flex-shrink-0 bg-surface-container-highest rounded-xl">
|
||||||
|
<img alt="Worksheet Thumbnail" class="w-full h-full object-cover" data-alt="Children's logic puzzle worksheet featuring colorful patterns and shape matching exercises in a playful studio setting." src="https://lh3.googleusercontent.com/aida-public/AB6AXuBY_0Rr153ZBT4IHcMyFtrcgl-y2ZRyVnOuGecnn7f4PZKoAx2lOuCorsMmfRa72s0JmbXrt4XT3QU1x7cIbZUyhv_EXwCfMaNxtkHc-ymIBIQ5jqm5oiQebrEWH4kjv14JdkCiziT4xzac4TdVN5yqpk7Wlg80QBl_ldDmAQqIgcUeN2PvlVvhmpOYmFeWE2HS3I_e4vV1J8s_cfV9_4g7y8SbxlSfnTmgQNeXrVbcdwaNEAGQWp92Iif0d2pVIqdfuUHO1pTw8oQ"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<h3 class="font-bold text-lg text-on-surface leading-tight mb-1">图形连连看</h3>
|
||||||
|
<p class="text-on-surface-variant text-xs mb-2 flex items-center gap-1">
|
||||||
|
逻辑思维 · 3-5岁 ·
|
||||||
|
<span class="flex text-primary-fixed-dim">
|
||||||
|
<span class="material-symbols-outlined text-[14px]" style="font-variation-settings: 'FILL' 1;">star</span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<span class="text-[10px] text-outline px-2 py-0.5 bg-surface-container rounded-full uppercase tracking-wider">收藏于 5 天前</span>
|
||||||
|
</div>
|
||||||
|
<button class="w-10 h-10 flex items-center justify-center rounded-full text-error transition-colors">
|
||||||
|
<span class="material-symbols-outlined" data-icon="favorite" style="font-variation-settings: 'FILL' 1;">favorite</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Card 3 -->
|
||||||
|
<div class="bg-surface-container-low p-4 flex items-center gap-4 active:scale-[0.98] transition-transform duration-200 rounded-2xl">
|
||||||
|
<div class="w-20 h-20 overflow-hidden flex-shrink-0 bg-surface-container-highest rounded-xl">
|
||||||
|
<img alt="Worksheet Thumbnail" class="w-full h-full object-cover" data-alt="Handwritten-style pinyin writing worksheet for kids with large guides and soft yellow accents on textured white paper." src="https://lh3.googleusercontent.com/aida-public/AB6AXuC54mXQ8620XwIsWmUHBHJGdmpF8uE4cSYxwR2NLJTsa6gYdTCHz2tqrKbGOye-y0CGgCPPWwJXzEuB2ZYrQ3CWWPlamvbjhTUDYf8yoA9Lyapll1t2w17AqzSHrbBPNFrq931IUCis64b51kslQZoq3c0KslZsBQiky-YSnuE7xUuNsgiF4hOak_ReFFufWE53h1sPkjHFeRM-H34b-e1MCNxGObGPhI0mNlJ_qz0c8aCuS-jdnDocSvIYda-iVcJLWcIT-mO6klw"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<h3 class="font-bold text-lg text-on-surface leading-tight mb-1">拼音字母认读</h3>
|
||||||
|
<p class="text-on-surface-variant text-xs mb-2 flex items-center gap-1">
|
||||||
|
语文基础 · 5-7岁 ·
|
||||||
|
<span class="flex text-primary-fixed-dim">
|
||||||
|
<span class="material-symbols-outlined text-[14px]" style="font-variation-settings: 'FILL' 1;">star</span>
|
||||||
|
<span class="material-symbols-outlined text-[14px]" style="font-variation-settings: 'FILL' 1;">star</span>
|
||||||
|
<span class="material-symbols-outlined text-[14px]" style="font-variation-settings: 'FILL' 1;">star</span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<span class="text-[10px] text-outline px-2 py-0.5 bg-surface-container rounded-full uppercase tracking-wider">收藏于 1 周前</span>
|
||||||
|
</div>
|
||||||
|
<button class="w-10 h-10 flex items-center justify-center rounded-full text-error transition-colors">
|
||||||
|
<span class="material-symbols-outlined" data-icon="favorite" style="font-variation-settings: 'FILL' 1;">favorite</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Card 4 (Bento Variation) -->
|
||||||
|
<div class="bg-surface-container p-6 relative overflow-hidden active:scale-[0.98] transition-transform duration-200 rounded-2xl">
|
||||||
|
<div class="relative z-10 pr-16">
|
||||||
|
<h3 class="font-bold text-xl text-on-surface leading-tight mb-1">趣味英语单词卡</h3>
|
||||||
|
<p class="text-on-surface-variant text-sm mb-4">语言学习 · 4-8岁 · ⭐⭐⭐</p>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<span class="px-3 py-1 bg-white/50 backdrop-blur rounded-full text-[10px] font-bold text-on-secondary-container"># 畅销经典</span>
|
||||||
|
<span class="px-3 py-1 bg-white/50 backdrop-blur rounded-full text-[10px] font-bold text-on-secondary-container"># 全彩打印</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="absolute -right-4 -bottom-4 w-32 h-32 opacity-20">
|
||||||
|
<span class="material-symbols-outlined text-[120px] text-primary" data-icon="abc">abc</span>
|
||||||
|
</div>
|
||||||
|
<button class="absolute top-6 right-6 w-10 h-10 flex items-center justify-center rounded-full text-error transition-colors">
|
||||||
|
<span class="material-symbols-outlined" data-icon="favorite" style="font-variation-settings: 'FILL' 1;">favorite</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Empty State Suggestion (Subtle) -->
|
||||||
|
<div class="mt-12 py-8 text-center">
|
||||||
|
<p class="text-outline text-sm font-medium">发现更多有趣的内容?</p>
|
||||||
|
<button class="mt-4 px-8 py-3 bg-secondary-container text-on-secondary-container rounded-full font-bold text-sm shadow-sm active:scale-95 transition-all">
|
||||||
|
去发现页看看
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<!-- Bottom Navigation Bar -->
|
||||||
|
<nav class="fixed bottom-0 left-0 w-full flex justify-around items-center px-4 pb-6 pt-2 bg-[#f8f0e0]/80 dark:bg-[#322e25]/80 backdrop-blur-xl z-50 rounded-t-[3rem] shadow-[0_-8px_32px_0_rgba(50,46,37,0.06)]">
|
||||||
|
<!-- Tab 发现 -->
|
||||||
|
<a class="flex flex-col items-center justify-center text-[#322e25] dark:text-[#fef6e7] opacity-70 px-4 py-2 hover:opacity-100 transition-opacity active:scale-90 transition-all duration-200" href="#">
|
||||||
|
<span class="material-symbols-outlined mb-1" data-icon="explore">explore</span>
|
||||||
|
<span class="font-plus-jakarta text-[12px] font-semibold leading-[1.6]">发现</span>
|
||||||
|
</a>
|
||||||
|
<!-- Tab 分龄 -->
|
||||||
|
<a class="flex flex-col items-center justify-center text-[#322e25] dark:text-[#fef6e7] opacity-70 px-4 py-2 hover:opacity-100 transition-opacity active:scale-90 transition-all duration-200" href="#">
|
||||||
|
<span class="material-symbols-outlined mb-1" data-icon="child_care">child_care</span>
|
||||||
|
<span class="font-plus-jakarta text-[12px] font-semibold leading-[1.6]">分龄</span>
|
||||||
|
</a>
|
||||||
|
<!-- Tab 收藏 (Active) -->
|
||||||
|
<a class="flex flex-col items-center justify-center bg-[#ffd709] dark:bg-[#6c5a00] text-[#6d3b00] dark:text-[#ffd709] rounded-full px-6 py-2 scale-105 active:scale-90 transition-all duration-200" href="#">
|
||||||
|
<span class="material-symbols-outlined mb-0.5" data-icon="favorite" style="font-variation-settings: 'FILL' 1;">favorite</span>
|
||||||
|
<span class="font-plus-jakarta text-[12px] font-bold leading-[1.6]">收藏</span>
|
||||||
|
</a>
|
||||||
|
<!-- Tab 我的 -->
|
||||||
|
<a class="flex flex-col items-center justify-center text-[#322e25] dark:text-[#fef6e7] opacity-70 px-4 py-2 hover:opacity-100 transition-opacity active:scale-90 transition-all duration-200" href="#">
|
||||||
|
<span class="material-symbols-outlined mb-1" data-icon="person">person</span>
|
||||||
|
<span class="font-plus-jakarta text-[12px] font-semibold leading-[1.6]">我的</span>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
</body></html>
|
||||||
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 37 KiB |
@@ -0,0 +1,176 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html lang="zh-CN"><head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||||
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Be_Vietnam_Pro:wght@400;500;600&display=swap" rel="stylesheet"/>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||||
|
<script id="tailwind-config"> tailwind.config = {
|
||||||
|
darkMode: "class",
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
"primary": "#FFD700",
|
||||||
|
"on-primary": "#2D2A00",
|
||||||
|
"background-light": "#f8f0e0",
|
||||||
|
"background-dark": "#23200f",
|
||||||
|
"surface": "#f8f0e0",
|
||||||
|
"on-surface": "#322e25",
|
||||||
|
"on-surface-variant": "#605b50",
|
||||||
|
"outline": "#7c766a",
|
||||||
|
"surface-container": "#f0e7d6",
|
||||||
|
"surface-container-low": "#f8f0e0",
|
||||||
|
"surface-container-lowest": "#ffffff"
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
"headline": ["-apple-system", "BlinkMacSystemFont", "San Francisco", "Helvetica Neue", "sans-serif"],
|
||||||
|
"body": ["-apple-system", "BlinkMacSystemFont", "San Francisco", "Helvetica Neue", "sans-serif"],
|
||||||
|
"label": ["-apple-system", "BlinkMacSystemFont", "San Francisco", "Helvetica Neue", "sans-serif"]
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
"DEFAULT": "1rem",
|
||||||
|
"lg": "2rem",
|
||||||
|
"xl": "3rem",
|
||||||
|
"full": "9999px"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}</script>
|
||||||
|
<style>
|
||||||
|
body { background-color: #f8f0e0; font-family: -apple-system, BlinkMacSystemFont, 'San Francisco', 'Helvetica Neue', sans-serif; color: #322e25; }
|
||||||
|
.material-symbols-outlined { font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
|
||||||
|
.pb-safe { padding-bottom: env(safe-area-inset-bottom); }
|
||||||
|
.glass-nav { background: rgba(248, 240, 224, 0.8); backdrop-filter: blur(20px); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-surface text-on-surface min-h-screen pb-32" style="background-color: #f8f0e0; font-family: -apple-system, BlinkMacSystemFont, 'San Francisco', 'Helvetica Neue', sans-serif;">
|
||||||
|
<!-- TopAppBar -->
|
||||||
|
<header class="fixed top-0 w-full z-50 backdrop-blur-xl h-16 flex items-center justify-between px-6 shadow-sm shadow-stone-900/5 transition-all glass-nav">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<button class="text-on-surface hover:scale-95 transition-transform duration-200">
|
||||||
|
<span class="material-symbols-outlined" data-icon="arrow_back">arrow_back</span>
|
||||||
|
</button>
|
||||||
|
<h1 class="font-headline font-bold text-xl tracking-tight text-on-surface">个人中心</h1>
|
||||||
|
</div>
|
||||||
|
<div class="font-headline font-extrabold text-2xl tracking-tighter text-[#FFD700]">涂鸦丫</div>
|
||||||
|
</header>
|
||||||
|
<main class="pt-24 px-6 max-w-2xl mx-auto space-y-10">
|
||||||
|
<!-- User Profile Header -->
|
||||||
|
<section class="relative flex flex-col items-center py-10 bg-surface-container-lowest rounded-[1.5rem] shadow-sm border border-outline/10 overflow-hidden">
|
||||||
|
<div class="absolute top-0 left-0 w-full h-24 bg-primary opacity-10"></div>
|
||||||
|
<div class="relative mt-4">
|
||||||
|
<div class="w-32 h-32 rounded-full border-4 border-surface-container-lowest overflow-hidden shadow-md">
|
||||||
|
<img class="w-full h-full object-cover" data-alt="close-up portrait of a smiling young woman" src="https://lh3.googleusercontent.com/aida-public/AB6AXuAAGKPxq5QCFibqBWRNKE2x6_7teoAJCy4pSdGtBO-U6rPl6LleUVVoMS-3ldq9k91D_1Lu7ln183WaEYvRnXoXEbS4JNiuvED2Lp48-pf4bJNFvYIutp0WfDa4wE3fqeet7zItd6VsbAB9DmvRA_iIKiPtcdHOi9JPXaDddJ_1LfSKd5BhWLcc1LCs0-KzSPknReZBpNzVOoEeOeveNhOwAV8UbpMuw7FgZMTIhsft64QSr6mAQVuOTQrvIBjXwnT9O10R3BMeCig"/>
|
||||||
|
</div>
|
||||||
|
<div class="absolute bottom-1 right-1 bg-primary text-on-primary p-2 rounded-full border-4 border-surface-container-lowest flex items-center justify-center shadow-sm">
|
||||||
|
<span class="material-symbols-outlined text-sm" style="font-variation-settings: 'FILL' 1;">edit</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 text-center">
|
||||||
|
<h2 class="font-headline font-bold text-2xl text-on-surface">Alex Rivera</h2>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-4 mt-8 w-full px-6">
|
||||||
|
<div class="flex-1 bg-surface-container-low p-4 rounded-xl text-center border border-outline/10">
|
||||||
|
<span class="block font-headline font-extrabold text-xl text-on-surface">24</span>
|
||||||
|
<span class="block font-label text-[10px] text-on-surface-variant uppercase tracking-wider">打印</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-surface-container-low p-4 rounded-xl text-center border border-outline/10">
|
||||||
|
<span class="block font-headline font-extrabold text-xl text-on-surface">12</span>
|
||||||
|
<span class="block font-label text-[10px] text-on-surface-variant uppercase tracking-wider">收藏</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Menu Grid -->
|
||||||
|
<section class="grid grid-cols-1 gap-4">
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<!-- My Favorites -->
|
||||||
|
<button class="group flex flex-col p-6 bg-surface-container-lowest rounded-[1.5rem] border border-outline/10 hover:bg-surface-container-low transition-all duration-200 active:scale-95 items-center">
|
||||||
|
<div class="w-12 h-12 rounded-full bg-primary flex items-center justify-center text-on-primary mb-4 shadow-sm">
|
||||||
|
<span class="material-symbols-outlined" data-icon="favorite" style="font-variation-settings: 'FILL' 1;">favorite</span>
|
||||||
|
</div>
|
||||||
|
<span class="font-headline font-bold text-on-surface">我的收藏</span>
|
||||||
|
<span class="font-body text-xs text-on-surface-variant mt-1 text-center">已保存的练习题</span>
|
||||||
|
</button>
|
||||||
|
<!-- Download History -->
|
||||||
|
<button class="group flex flex-col p-6 bg-surface-container-lowest rounded-[1.5rem] border border-outline/10 hover:bg-surface-container-low transition-all duration-200 active:scale-95 items-center">
|
||||||
|
<div class="w-12 h-12 rounded-full bg-primary flex items-center justify-center text-on-primary mb-4 shadow-sm">
|
||||||
|
<span class="material-symbols-outlined" data-icon="download">download</span>
|
||||||
|
</div>
|
||||||
|
<span class="font-headline font-bold text-on-surface">下载历史</span>
|
||||||
|
<span class="font-body text-xs text-on-surface-variant mt-1 text-center">查看历史文件</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- List Style for other items -->
|
||||||
|
<div class="space-y-4">
|
||||||
|
<button class="w-full flex items-center justify-between p-5 bg-surface-container-lowest rounded-full border border-outline/10 hover:bg-surface-container-low transition-colors group active:scale-[0.98]">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-on-surface">
|
||||||
|
<span class="material-symbols-outlined" data-icon="print">print</span>
|
||||||
|
</div>
|
||||||
|
<span class="font-headline font-semibold text-on-surface">打印指南</span>
|
||||||
|
</div>
|
||||||
|
<span class="material-symbols-outlined text-on-surface-variant group-hover:translate-x-1 transition-transform" data-icon="chevron_right">chevron_right</span>
|
||||||
|
</button>
|
||||||
|
<button class="w-full flex items-center justify-between p-5 bg-surface-container-lowest rounded-full border border-outline/10 hover:bg-surface-container-low transition-colors group active:scale-[0.98]">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-on-surface">
|
||||||
|
<span class="material-symbols-outlined" data-icon="chat_bubble">chat_bubble</span>
|
||||||
|
</div>
|
||||||
|
<span class="font-headline font-semibold text-on-surface">提交反馈</span>
|
||||||
|
</div>
|
||||||
|
<span class="material-symbols-outlined text-on-surface-variant group-hover:translate-x-1 transition-transform" data-icon="chevron_right">chevron_right</span>
|
||||||
|
</button><button class="w-full flex items-center justify-between p-5 bg-surface-container-lowest rounded-full border border-outline/10 hover:bg-surface-container-low transition-colors group active:scale-[0.98]">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-on-surface">
|
||||||
|
<span class="material-symbols-outlined" data-icon="settings">settings</span>
|
||||||
|
</div>
|
||||||
|
<span class="font-headline font-semibold text-on-surface">设置</span>
|
||||||
|
</div>
|
||||||
|
<span class="material-symbols-outlined text-on-surface-variant group-hover:translate-x-1 transition-transform" data-icon="chevron_right">chevron_right</span>
|
||||||
|
</button><button class="w-full flex items-center justify-between p-5 bg-surface-container-lowest rounded-full border border-outline/10 hover:bg-surface-container-low transition-colors group active:scale-[0.98]">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-on-surface">
|
||||||
|
<span class="material-symbols-outlined" data-icon="info">info</span>
|
||||||
|
</div>
|
||||||
|
<span class="font-headline font-semibold text-on-surface">关于涂鸦丫</span>
|
||||||
|
</div>
|
||||||
|
<span class="material-symbols-outlined text-on-surface-variant group-hover:translate-x-1 transition-transform" data-icon="chevron_right">chevron_right</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Premium Upsell -->
|
||||||
|
<section class="bg-[#2D2A26] p-8 rounded-[1.5rem] relative overflow-hidden shadow-xl">
|
||||||
|
<div class="absolute top-0 right-0 p-4 opacity-10 transform translate-x-4 -translate-y-4">
|
||||||
|
<span class="material-symbols-outlined text-8xl text-white" data-icon="auto_awesome">auto_awesome</span>
|
||||||
|
</div>
|
||||||
|
<div class="relative z-10">
|
||||||
|
<h3 class="font-headline font-extrabold text-xl text-white">升级专业版</h3>
|
||||||
|
<p class="font-body text-white/70 text-sm mt-2 max-w-[200px]">解锁 500+ 精选教育模板并获得优先体验。</p>
|
||||||
|
<button class="mt-6 bg-primary text-on-primary font-headline font-bold py-3 px-8 rounded-full hover:scale-105 active:scale-95 transition-all shadow-lg">立即升级</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- Bottom Settings Link -->
|
||||||
|
</main>
|
||||||
|
<!-- BottomNavBar -->
|
||||||
|
<div class="text-center py-6 pb-32">
|
||||||
|
<p class="font-label text-[10px] text-on-surface-variant uppercase tracking-[0.2em]">Doodle Mini v2.4.0</p>
|
||||||
|
</div><nav class="fixed bottom-0 left-0 w-full flex justify-around items-center px-4 py-3 backdrop-blur-xl rounded-t-[3rem] z-50 shadow-[0_-8px_32px_rgba(50,46,37,0.06)] pb-safe glass-nav">
|
||||||
|
<a class="flex flex-col items-center justify-center text-[#322e25]/70 px-4 py-2 hover:bg-[#f0e7d6] rounded-full transition-all duration-200 active:scale-90" href="#">
|
||||||
|
<span class="material-symbols-outlined" data-icon="explore">explore</span>
|
||||||
|
<span class="text-[10px] font-bold tracking-wide uppercase mt-1">发现</span>
|
||||||
|
</a>
|
||||||
|
<a class="flex flex-col items-center justify-center text-[#322e25]/70 px-4 py-2 hover:bg-[#f0e7d6] rounded-full transition-all duration-200 active:scale-90" href="#">
|
||||||
|
<span class="material-symbols-outlined" data-icon="category">category</span>
|
||||||
|
<span class="text-[10px] font-bold tracking-wide uppercase mt-1">分龄</span>
|
||||||
|
</a>
|
||||||
|
<a class="flex flex-col items-center justify-center text-[#322e25]/70 px-4 py-2 hover:bg-[#f0e7d6] rounded-full transition-all duration-200 active:scale-90" href="#">
|
||||||
|
<span class="material-symbols-outlined" data-icon="favorite">favorite</span>
|
||||||
|
<span class="text-[10px] font-bold tracking-wide uppercase mt-1">收藏</span>
|
||||||
|
</a>
|
||||||
|
<a class="flex flex-col items-center justify-center bg-[#FFD700] text-[#453900] rounded-full px-6 py-2 shadow-inner active:scale-90 transition-all duration-200 ease-out" href="#">
|
||||||
|
<span class="material-symbols-outlined" data-icon="person" style='font-variation-settings: "FILL" 1;'>person</span>
|
||||||
|
<span class="text-[10px] font-bold tracking-wide uppercase mt-1">我的</span>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
</body></html>
|
||||||
|
After Width: | Height: | Size: 23 KiB |