- settings.search.engines[] 新增 icon:空=品牌图标/通用地球,'/' 开头走托管目录,或 http(s) 链接 - 后端校验图标地址(空 / 托管路径 / http(s),≤500 字符) - 后台每张引擎卡加「图标地址」输入;前后台都用组件库 EngineIcon 的 src(<img> 渲染,SVG 静态不执行脚本) - @stash/ui 0.3.4
261 lines
14 KiB
Markdown
261 lines
14 KiB
Markdown
# Stash 交接文档
|
||
|
||
> 更新于 2026-11-04 19:30(Asia/Shanghai)。本文件是当前状态,取代旧版历史快照。
|
||
> 新会话先读这份,再按需看 `README.md`、`docs/ADMIN-PLAN.md`、`stash-ui/README.md`。
|
||
|
||
## 1. 一句话现状
|
||
|
||
Stash 是「本地项目托管 + 可配置导航首页」:Rust 单 crate 内嵌 React 前端,单管理员登录,内容库为 SQLite,分组 / 条目 / 首页卡片 / 站点设置都在 `/admin` 管理。
|
||
|
||
当前开发分支 `develop`,本地服务:
|
||
|
||
- 前台 + 后台:<http://127.0.0.1:8080>
|
||
- 管理后台:<http://127.0.0.1:8080/admin>
|
||
- 接口一览:<http://127.0.0.1:8080/interface>
|
||
- Vite 开发服务器 `5173` 当前**未运行**;需要时 `cd stash-web && npm run dev`
|
||
|
||
## 2. 仓库与分支
|
||
|
||
| 仓库 | 路径 | 分支 | 状态 |
|
||
| --- | --- | --- | --- |
|
||
| 主项目 | `D:\CNWei\CNW\Rust\stash` | `develop` | 工作区干净;功能最新 `1d1ece6`,本文件随后单独提交 |
|
||
| 组件库 | `D:\CNWei\CNW\Rust\stash-ui` | `master` | 工作区只有忽略的 `.idea/`;`994436a` 最新 |
|
||
|
||
- 主项目 remote 名为 `master`(不是 `origin`),地址 `https://gitea.ngmao.com/CNWei/stash.git`。
|
||
- `develop` 比 `master/develop` **领先 20 个提交,尚未推送**;此前 HTTPS 凭据不可用,需要时先准备 Gitea 凭据。
|
||
- `stash-ui` 也有 3 个未推送提交:`b97c77e`(SearchField suffix)、`46829cd`(Input leading)、`994436a`(EngineIcon)。
|
||
- `@stash/ui` 以 `file:../../stash-ui` 引入,`stash-web` 使用其 `dist/`;改组件库后必须重新 `npm run build`。
|
||
|
||
## 3. 启动 / 构建 / 测试
|
||
|
||
前端产物会被 `build.rs` 内嵌,顺序不能反:
|
||
|
||
```powershell
|
||
cd D:\CNWei\CNW\Rust\stash\stash-web
|
||
npm run build # tsc -b + vite,产物 dist/
|
||
|
||
cd D:\CNWei\CNW\Rust\stash
|
||
Get-Process stash -ErrorAction SilentlyContinue |
|
||
Where-Object { $_.Path -like '*stash\target*' } | Stop-Process -Force # 否则 exe 被占用
|
||
cargo build
|
||
Start-Process .\target\debug\stash.exe `
|
||
-RedirectStandardOutput "$env:TEMP\stash.log" `
|
||
-RedirectStandardError "$env:TEMP\stash-err.log" -WindowStyle Hidden
|
||
```
|
||
|
||
测试(Windows 下覆盖 TEMP 权限):
|
||
|
||
```powershell
|
||
$env:TEMP = "D:\CNWei\CNW\Rust\stash\target\tmp"; $env:TMP = $env:TEMP
|
||
cargo test # 交接时 52 passed
|
||
```
|
||
|
||
组件库:
|
||
|
||
```powershell
|
||
cd D:\CNWei\CNW\Rust\stash-ui
|
||
npm run build # dist/stash-ui.js + .css + types
|
||
```
|
||
|
||
## 4. 代码地图
|
||
|
||
```
|
||
src/
|
||
main.rs / lib.rs 启动、参数、日志
|
||
config.rs 端口 / 数据目录 / 托管目录
|
||
server.rs 全部 API + 内嵌前端 + SPA 回落
|
||
listing.rs 托管目录扫描
|
||
watcher.rs 文件监听 + SSE 防抖
|
||
db/
|
||
mod.rs Db 门面 + 迁移/种子测试
|
||
schema.rs 建表、种子、v15→…→v23 迁移
|
||
auth.rs admin / session / argon2id
|
||
settings.rs settings JSON + 校验
|
||
entries.rs 条目 CRUD、浏览、点赞、审计
|
||
groups.rs 分组树 CRUD / 移动 / 排序
|
||
cards.rs 卡片与勾选分组
|
||
catalog.rs 分组树 + 条目查询组装
|
||
stash-web/src/
|
||
AppNext.tsx 前台壳:路由、卡片、侧栏、搜索框、主题
|
||
main.tsx /admin 与普通前台分流
|
||
settings.ts SiteSettings 类型 / 默认值 / API 客户端
|
||
manage.ts 分组、卡片、catalog2 客户端
|
||
items.ts 条目编辑客户端
|
||
api.ts 项目扫描 / SSE 客户端
|
||
components/
|
||
admin/AdminNext.tsx 后台全部面板
|
||
header/SiteHeader.tsx 品牌 / 滚动信息 / 操作图标
|
||
content/ 卡片、网格、详情、编辑器
|
||
sidebar/ 资料卡、本地服务、导航
|
||
stash-ui/src/components/ SearchField / Input / EngineIcon 等
|
||
```
|
||
|
||
## 5. 数据库(v23)
|
||
|
||
路径:`target/debug/data/stash.db`(`--data` 可覆盖)。
|
||
|
||
- `PRAGMA user_version = 23`;支持 0 建全量、15→16→…→23 迁移,高于程序版本拒绝启动。
|
||
- 当前表:`admin`、`audit`、`card`、`card_group`、`entry`、`entry_tag`、`node`、`session`、`setting`。
|
||
- 当前数据(交接时):15 个 node、44 条 entry、5 张 card;`PRAGMA foreign_key_check` 无异常。
|
||
- `section_block` 与 `node.view_mode / empty_text / show_in_sidebar / allow_groups` 已在 v23 删除。
|
||
- `entry.format` 是每条内容自己的 `apps / posters / articles`,同一分组可混合。
|
||
- `node.kind = 'section'` 是根分组,`group` 是子分组;`enabled` 控制整棵子树显示。
|
||
- 条目只存 `node_key`;格式、分组、卡片都通过业务 key 关联。
|
||
- 备份:`target/debug/data/stash.db.bak-pre-cleanup-v22` 是 v23 改造前快照;`/api/backup` 可下载当前快照。
|
||
- **不要直接 `cargo clean`/删除整个 `target`**:运行库和备份在 `target/debug/data/`。
|
||
|
||
## 6. settings JSON
|
||
|
||
`setting` 表 `key='site'`,API `GET/PATCH /api/settings`,`version` 乐观锁。当前字段:
|
||
|
||
```jsonc
|
||
{
|
||
"header": { "enabled": true, "speed": 24, "gap": 26, "items": [...] },
|
||
"sidebar": { "show_profile": true, "show_service": false, "show_nav": true },
|
||
"background": { "light": "", "dark": "" }, // 空 = 内置背景
|
||
"font": { "source": "builtin", "current": "", "items": [] }, // builtin = 文楷;custom = 用 items 里 current 那条
|
||
"search": {
|
||
"default": "internal",
|
||
"engines": [
|
||
{ "id": "google", "name": "Google", "url": "https://www.google.com/search?q={query}", "icon": "", "enabled": true },
|
||
{ "id": "bing", "name": "Bing", "url": "https://www.bing.com/search?q={query}", "enabled": true },
|
||
{ "id": "baidu", "name": "百度", "url": "https://www.baidu.com/s?wd={query}", "enabled": true },
|
||
{ "id": "sogou", "name": "搜狗", "url": "https://www.sogou.com/web?query={query}", "enabled": true },
|
||
{ "id": "360", "name": "360", "url": "https://www.so.com/s?q={query}", "enabled": true }
|
||
]
|
||
},
|
||
"profile": { "name": "...", "role": "...", "description": "...", "location": "...", "avatar": "" },
|
||
"site": { "title": "...", "favicon": "", "theme": "light", "brand": {...}, "actions": {...} }
|
||
}
|
||
```
|
||
|
||
- `search.default` 可以是 `internal` 或某个引擎 id;默认默认值是 `internal`。
|
||
- 上面是字段结构示例;实际值以 `GET /api/settings` 为准(交接时 `search.default=internal`、`site.theme=light`,background 两项使用自定义 picsum 图)。
|
||
- 外部引擎 URL 必须以 `http(s)://` 开头并包含 `{query}`,否则后端 400。
|
||
- 引擎 id 只能用小写字母 / 数字 / `-` / `_`(1–30 位,`internal` 保留);内置五个用品牌图标,
|
||
后台新加的引擎 id 自动生成为 `custom-xxx`、图标用通用地球(组件库 EngineIcon 自动回落)。
|
||
- 每个引擎可带 `icon`(png / svg 地址,`/` 开头的托管路径或 http(s) 链接):给了就用 `<img>` 渲染自己
|
||
的图标,留空回落到品牌图标 / 地球;SVG 走 img 是静态的,不执行脚本。
|
||
- `background.light/dark` 为空时用内置 `stash-web/src/assets/site-bg.jpg` / `site-bg-dark.jpg`;否则填托管目录 `public/` 路径或完整 URL。
|
||
- 旧 settings JSON 缺失字段会自动回落默认值;多余旧字段在下次保存时被丢弃。
|
||
|
||
## 7. 当前功能 / 后台 IA
|
||
|
||
后台左侧导航:
|
||
|
||
- **分组管理**:根分组 / 子分组树、编辑、移动、排序、启停、删除;
|
||
- **数据管理**:按主分组列出条目(含子分组),每条可选格式;
|
||
- **首页管理**
|
||
- 页头:开关、速度、滚动条目、品牌 / 图标 / 配色;
|
||
- 背景管理:亮色 / 暗色背景 URL + 预览 + 恢复内置;
|
||
- 搜索框:默认搜索项、外部引擎的名称 / URL / 启停、添加 / 删除自定义引擎、恢复默认;
|
||
- 侧边栏:资料卡 / 本地服务 / 分组导航显隐;
|
||
- 内容卡片:卡片 + 勾选分组 + 预览条数 + 排序;
|
||
- **资料管理**:头像、名称、角色、简介、位置;
|
||
- **系统管理**:改密码、下载备份、正文字体(先选内置 / 字体链接;链接模式下可存多套字体,启用其中一条)。
|
||
|
||
搜索框行为:
|
||
|
||
- 顶部悬浮标签显示当前引擎图标 + 名称,点击展开下拉;
|
||
- 第一项固定「站内搜索」,分隔线后是启用的外部引擎;
|
||
- 站内模式:输入过滤本地内容;回车打开第一个匹配条目/分组;
|
||
- 外部模式:输入**不再过滤**本地内容;回车用该引擎 URL 新标签页搜索;
|
||
- 当前选择存在本机 localStorage(`stash-search-engine`),刷新后仍用它;引擎被停用 / 删除时回落到后台默认项。
|
||
|
||
主题:
|
||
|
||
- 深色背景来自 Alright 演示站,资源 `site-bg-dark.jpg`;
|
||
- 明暗切换优先用 View Transition 整页快照交叉淡入(160ms),不支持时回退到 CSS 颜色过渡;
|
||
- 首帧由 `index.html` 内联脚本按 localStorage / 系统偏好先上色;
|
||
- 背景地址也缓存在 localStorage(`stash-background`),刷新首帧直接用它,设置回来再校准,不会先闪内置背景;
|
||
- 页头图标显示**当前**实际明暗(深色月亮 / 浅色太阳),点它是切到另一侧;
|
||
- 背景图两层(light/dark)交叉淡入。
|
||
|
||
## 8. HTTP API(当前保留)
|
||
|
||
```text
|
||
GET /api/health
|
||
GET /api/projects GET /api/projects/events (SSE)
|
||
GET /api/catalog2 分组树 + 卡片
|
||
GET /api/catalog/events SSE:catalog 变化
|
||
GET /api/settings
|
||
PATCH /api/settings 需登录,{version,settings}
|
||
GET /api/fonts font/ 目录里的字体清单(公开读)
|
||
POST /api/nodes 需登录
|
||
PATCH /api/nodes/{key} 需登录
|
||
DELETE /api/nodes/{key} 需登录
|
||
POST /api/cards 需登录
|
||
PATCH /api/cards/{id} 需登录
|
||
DELETE /api/cards/{id} 需登录
|
||
PUT /api/cards/{id}/groups 需登录
|
||
GET /api/items/{key}
|
||
POST /api/items 需登录
|
||
PATCH /api/items/{key} 需登录
|
||
DELETE /api/items/{key} 需登录
|
||
POST /api/items/{key}/view
|
||
POST /api/items/{key}/like
|
||
GET /api/backup 需登录
|
||
GET /api/auth/session
|
||
POST /api/auth/setup / login / logout
|
||
PATCH /api/auth/password
|
||
```
|
||
|
||
已删除:`/api/catalog`、`/api/categories/*`、旧 `/api/groups/{id}`。
|
||
|
||
## 9. 组件库改动(stash-ui)
|
||
|
||
- `SearchField` 新增可选 `suffix` 与 `leading` 插槽;
|
||
- `Input` 新增 `leading` ReactNode,优先于 `icon`;
|
||
- 新增 `EngineIcon`(`internal/google/bing/baidu/sogou/360`),图标路径来自参考稿;`18px` 默认、`14px` 用于顶部小标签;
|
||
- 构建产物已更新,`stash-web` 通过 file 依赖读取;改库后必须重建 dist,否则主项目构建仍用旧类型/资源。
|
||
|
||
## 10. 已知限制 / 坑
|
||
|
||
| 项 | 说明 |
|
||
| --- | --- |
|
||
| 推送 | 本地 `develop` 领先远端 20 个提交,尚未推送;Gitea HTTPS 凭据需准备 |
|
||
| 搜索引擎 | 内置五个(有品牌图标)+ 后台添加的自定义引擎(最多 10 个,通用地球图标) |
|
||
| 搜索选择记忆 | 存本机 localStorage(`stash-search-engine`);换设备 / 清站点数据后回到后台默认 |
|
||
| 图片上传 | 背景 / 头像 / Logo 只支持 URL,不支持上传 |
|
||
| 卡片/分组拖拽 | 排序用数值 / 现有 SortableList;分组拖拽排序未做 |
|
||
| 备份恢复 | 只有 `/api/backup` 下载;恢复需停机替换库文件 |
|
||
| 旧接口 | 已删;不要再按旧文档调用 `/api/catalog` 或 categories |
|
||
| 双份示例 | `public/git_helper/` 是 Rust 托管示例;`stash-web/public/git_helper/` 是 Vite dev 示例,**两份都保留** |
|
||
| exe 占用 | 重启/构建前先杀 stash.exe,否则 `cargo build` 拒绝访问 |
|
||
| 编码 | 源码 UTF-8;PowerShell 控制台可能显示乱码,以 read 工具为准,别用 Set-Content 改中文源码 |
|
||
|
||
## 11. 最近提交(主项目,倒序)
|
||
|
||
```text
|
||
1d1ece6 fix(group): 分组面包屑保留详情页外框
|
||
9d1e5dc fix(group): 分组页面包屑与详情页统一
|
||
4862f8f fix(search): 外部引擎模式不再过滤本地内容
|
||
aa6f341 feat(search): 按参考稿重做搜索框并支持后台配置
|
||
5ae2088 style(search): 引擎图标恢复 18px
|
||
200908c style(search): 引擎图标统一使用组件库图标
|
||
56f362f feat(search): 点击放大镜切换搜索引擎
|
||
8c1c658 feat(search): 效果五快捷栏加入本地搜索
|
||
038b7ec feat(search): 搜索框支持切换搜索引擎
|
||
a5d7859 fix(theme): 用整页快照过渡消除明暗割裂
|
||
5439ebf feat(admin): 增加背景管理
|
||
b9005dd style(theme): 暗色使用 Alright 同款深色背景
|
||
```
|
||
|
||
组件库最近:
|
||
|
||
```text
|
||
994436a feat(icons): 增加搜索引擎图标
|
||
46829cd feat(input): 增加左侧 leading 插槽
|
||
b97c77e feat(search): SearchField 增加 suffix 插槽
|
||
```
|
||
|
||
## 12. 新会话建议顺序
|
||
|
||
1. 打开 <http://127.0.0.1:8080> 与 `/admin` 冒烟;确认 8080 在跑(当前 PID 会变,不必依赖 PID)。
|
||
2. 改前端:`cd stash-web && npm run build` → 杀 stash → `cargo build` → 启动。
|
||
3. 改组件库:先 `cd stash-ui && npm run build`,再构建 `stash-web`,最后 Rust。
|
||
4. 改设置结构:同时改 `src/db/settings.rs`、`stash-web/src/settings.ts`、后台面板和默认值;旧 JSON 由 serde 默认值兜底。
|
||
5. 改数据库结构:升 `SCHEMA_VERSION` 并补迁移与迁移测试;先备份 `target/debug/data/stash.db`。
|
||
6. 视觉改动用 Playwright 截图到 `stash-ui/shots/` 验证;脚本在 `stash-ui/.ref/`(不提交)。
|
||
7. 收尾跑 `cargo test`(52 条)和 `npm run build`,确认工作区干净。
|