feat: 实现导航页基础功能

- 添加导航条目和分类数据模型
- 实现导航卡片网格展示
- 支持点击卡片打开链接
- 添加主题样式(渐变色、卡片阴影)
- 区分系统默认和自定义条目
- 添加分类统计信息"
This commit is contained in:
2026-09-19 23:17:36 +08:00
parent 1c98340fc5
commit 039ea70edf
26 changed files with 796 additions and 2583 deletions
+28 -11
View File
@@ -27,22 +27,39 @@ cargo clippy --all-targets
```
data/
├── site.json # 站点名与搜索框提示,只读
├── system-categories.json # 内置分组,只读,自己手写维护
├── system-sites.json # 内置网站,只读
├── user-categories.json # 提交时创建的分组,自动写
└── user-sites.json # 提交 / 推送的网站,自动写
└── nav.json # 站点信息 + 分组结构 + 网站,全在这一份文档里
```
侧栏的结构和网站数据放在同一个文件里,删除网站和「它的分组要不要一起清掉」
是同一次写入完成的——不会出现网站没了、侧栏还挂着一个空分组的中间状态。
写盘用「先写临时文件再改名」,不会因为写到一半断电把文件写坏。
```json
{
"site": { "name": "Suxing Nav", "searchHint": "…", "submitUrl": "https://mattermost…" },
"groups": [
{
"id": "common", "title": "常用推荐", "source": "system", "order": 10,
"createdAt": "…", "updatedAt": "…",
"sites": [ { "id": "github", "title": "GitHub", "url": "…", "source": "system", … } ],
"children": []
}
]
}
```
启动时会自检,任何一条不通过就直接退出(避免带着坏数据继续跑):
- `system-*.json` 里的 `source` 必须全是 `system`,`user-*.json` 里必须全不是;
- 网站 id、分组 id 不能重复;
- 每个网站的 `categoryId` 必须存在,且**内置网站只能挂在内置分组下、
提交的网站只能挂在用户分组下**;
- 分组的 `parentId` 必须存在、必须是一级分组(最多两级),也不能指向自己。
- `site.name` 不能为空;
- 分组 id、网站 id 不能重复(两者共用一个 id 空间);
- 分组最多两级;
- **内置分组下只能放内置网站,用户分组下只能放用户网站**。
写盘用「先写临时文件再改名」,不会因为写到一半断电把文件写坏。
### 内置与用户数据怎么隔离
以前是「系统文件只读、用户文件可写」,现在合并成一个文件,隔离改成靠 `source`:
写操作只会碰 `source != system` 的分组和网站,内置的那部分只会被原样读出来再写回去。
启动自检会拦住「手改 JSON 把内置网站标成用户来源」这类越权。
## 接口