diff --git a/.cursor/commands/release-pr-tag.md b/.cursor/commands/release-pr-tag.md index 87bbc48..2436a31 100644 --- a/.cursor/commands/release-pr-tag.md +++ b/.cursor/commands/release-pr-tag.md @@ -10,7 +10,7 @@ description: 从 release 分支发起合并 master 的 PR、打 v 标签并依 ## 1. 前置检查 - `git fetch origin && git status`,当前应在目标 **release 分支**(如 `release/v0.1.2`),工作区干净。 -- 确认版本与文档一致:`apps/desktop/package.json`、`apps/desktop/src-tauri/Cargo.toml` 中 `version`,以及根目录 `CHANGELOG.md` / `docs/CHANGELOG.md`。 +- 确认版本与文档一致:`apps/desktop/package.json`、`apps/desktop/src-tauri/Cargo.toml` 中 `version`,以及根目录 `CHANGELOG.md` / `docs/CHANGELOG.md`和`apps/desktop/src-tauri/tauri.conf.json`。 - 校验关于页数据源与根目录 CHANGELOG 一致:在仓库根执行 `bun run sync:changelog`,再 `git diff apps/desktop/src/data/app-changelog.md` 应为空;若有差异则提交后再继续。 ## 2. 确认合并关系(可选但推荐) diff --git a/.cursor/plans/ui-sync-with-demo_7774ca21.plan.md b/.cursor/plans/ui-sync-with-demo_7774ca21.plan.md new file mode 100644 index 0000000..10c5768 --- /dev/null +++ b/.cursor/plans/ui-sync-with-demo_7774ca21.plan.md @@ -0,0 +1,59 @@ +--- +name: ui-sync-with-demo +overview: 完全按照 design/ui_demo.html 原型还原项目的顶部导航、左侧目录树、顶部搜索栏、会话列表以及知识库视图,消除现存的样式差异。 +todos: + - id: sync-session-toolbar + content: 重构 SessionToolbar.vue 搜索与分段过滤器的布局和胶囊样式 + status: completed + - id: sync-sidebar-tree + content: 定制 Sidebar.vue 目录树源/主机/项目层级的视觉渲染样式,并在会话整理模式下处理多选框的交互样式 + status: completed + - id: sync-session-card + content: 将 SessionCard.vue 会话卡片重写为原型的上下垂直布局结构 + status: completed + - id: sync-knowledge-view + content: 还原 KnowledgeView.vue 的顶部操作栏布局和视图切换器样式 + status: completed + - id: sync-topbar + content: 核对 TopBar.vue 中切换按钮的最终呈现细节 + status: completed +isProject: false +--- + +# UI 样式深度还原计划 + +根据您提供的对比图与 `design/ui_demo.html` 原型,发现当前的实现与设计稿在组件布局和细节上有较大偏离。接下来的工作将严格对齐原型,执行以下重构: + +## 1. 顶部搜索栏与过滤区域 (`SessionToolbar.vue`) + +- **布局重构**:将搜索栏和过滤操作从现有的平铺结构改为上下两行布局。 + - 第一行:宽大的搜索框 + 次级“刷新”按钮。 + - 第二行:左侧为“分段选择器(Segmented Control)”样式(全部会话 / 待分析 / 已分析),包含带数字徽标的“待分析”状态;右侧为记录总数与 Tooltip 提示收纳。 +- **视觉风格**:去除当前原生的 `n-button` 过滤组,采用原型中胶囊背景槽加悬浮滑块的无边框设计。 + +## 2. 侧边栏目录树 (`Sidebar.vue`) + +- **节点自定义渲染**:使用 `n-tree` 的自定义渲染(`renderLabel`, `renderPrefix`, `renderSuffix`)精确控制每级节点的 DOM。 +- **层级样式对齐**: + - 一级(来源):使用特定的品牌色图标(如蓝色 Cursor、橙色 Claude Code 等)配合加粗标题。 + - 二级(主机):增加层级缩进,图标换为 `lucide-server`。 + - 三级(项目):带 `lucide-corner-down-right` 拐角指引和不同状态的文件夹图标,鼠标悬停时节点增加圆角高亮。 + - 数量徽标:放置在最右侧,使用单色等宽字体对齐(`font-mono text-[10px]`)。 +- **会话整理模式处理**:特别处理点击「会话整理」进入多选状态(`checkable=true`)时的交互样式,确保左侧的复选框能优雅融入自定义渲染的节点,且选择高亮时背景和样式保持整洁,与设计稿多选风格对齐。 + +## 3. 会话卡片列表 (`SessionCard.vue`) + +- **回归垂直排版**:抛弃目前采用的横向左右分列设计,严格按照原型的上下两层布局重构。 + - **上层视线区**:先展示状态 Tag(如:待分析 / 高价值)与来源角标,下方为主标题和摘要文字;最右侧为 Hover 显现的操作按钮。 + - **下层元数据区**:用顶部细线分割(`border-t`),采用横向平铺展示所属项目文件夹(带浅灰底色块)、时间、对话数与大小数据。 + +## 4. 知识库 Tab 页 (`KnowledgeView.vue`) + +- **操作栏还原**:顶部操作栏左侧为标题与记录数,右侧为并排的操作按钮组。 +- **功能按钮整合**:将“全选当页”与“清除选择”逻辑整合为一个按钮,并在选中时变为文字按钮外观。 +- **视图切换组件**:深度覆写 `n-radio-group` 的样式,使用和对话页同源的“大胶囊底槽”设计,配合白底阴影块实现列表/卡片的平滑切换效果。 + +## 5. 顶栏细节兜底 (`TopBar.vue`) + +- 确保中间的“对话记录 / 知识库”切换器彻底还原 `bg-slate-100/80` 胶囊包裹的方案,消除由于历史残留导致的 UI 割裂。 + diff --git a/.cursor/skills/pitfall-documentation/SKILL.md b/.cursor/skills/pitfall-documentation/SKILL.md index bbbfaf8..1858aaf 100644 --- a/.cursor/skills/pitfall-documentation/SKILL.md +++ b/.cursor/skills/pitfall-documentation/SKILL.md @@ -30,10 +30,11 @@ description: 将已解决的问题整理为仓库内「踩坑」文档(问题 ## 放在哪、怎么命名 -- **目录**:优先 `docs/踩坑/`(与仓库现有文档一致)。 +- **目录**:优先 `docs/踩坑/`(与仓库现有文档一致)。索引与命名约定见同目录 [README.md](../../../docs/踩坑/README.md)。 - **新文件 vs 合并**: - 与已有某篇 **同一主题线**(如同一模块、同一子系统)→ **打开该文件**,在文末或合适位置 **新增小节**,并必要时更新文件顶部摘要句。 - - 新领域或主题正交 → **新建** `领域-简短主题.md`。 + - 新领域或主题正交 → **新建** Markdown 文件。 +- **文件名**:**以中文为主**概括主题,用连字符 `-` 分段(例:`桌面应用-脚手架-UnoCSS-Tauri与存储层常见问题.md`、`工具结果-正则匹配失败.md`)。技术专名可保留英文:`UnoCSS`、`Tauri`、`CLI`、`JSON`、`WebView`、`Tailwind`、`FTS5`、`MATCH` 等。 - **标题风格**:可参考现有踩坑文:先 `# 踩坑:…`,再分「现象 / 根因 / 解决方法」。 ## Agent 执行要点 diff --git a/.cursor/skills/pitfall-documentation/reference-template.md b/.cursor/skills/pitfall-documentation/reference-template.md index 8cb6d03..ab79780 100644 --- a/.cursor/skills/pitfall-documentation/reference-template.md +++ b/.cursor/skills/pitfall-documentation/reference-template.md @@ -28,5 +28,6 @@ ## 文件命名建议 -- 形式:`领域或应用名-主题关键词.md`,例如:`桌面应用-会话提炼-JSON解析与标签技术栈.md`。 +- **以中文为主**、`-` 分段;技术专名可保留英文(`UnoCSS`、`CLI`、`JSON` 等)。示例:`桌面应用-会话提炼-JSON解析与标签技术栈.md`。 +- 完整约定与索引见仓库 [`docs/踩坑/README.md`](../../../docs/踩坑/README.md)。 - 同一主题持续踩坑:优先 **合并进已有文件** 为新 `##` / `###` 小节,避免碎片化。 diff --git a/CHANGELOG.md b/CHANGELOG.md index 76ca9dd..72022b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ > 面向使用者的更新说明。实现细节见 `docs/CHANGELOG.md`。 +## 0.1.3(2026-03-25) + +### 新增 + +- **知识库筛选**:侧栏支持按 **技术栈** 多选筛选(与标签同为「且」关系),并与列表、全文搜索参数对齐;主区域可展示并快速清除当前筛选条件。 +- **侧栏体验**:知识库「类型 / 标签 / 技术栈」支持 **折叠面板**(`n-collapse`),减少多重滚动条。 + +### 体验改进 + +- **界面**:顶栏 Tab、会话状态分段、知识库视图切换等与 `design/ui_demo` 对齐;修复 WebView 下原生 **分段按钮** 系统灰底问题(`segment-pill-btn`)。 +- **会话列表**:会话卡片 **信息密度** 提升(标题与摘要更紧凑、未分析卡片更省高、底栏间距收紧);批量选中描边改用 **内环**(`ring-inset`),避免与 `overflow-hidden` 裁切冲突。 + +--- + ## 0.1.2(2026-03-22 – 2026-03-23) ### 新增 diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 77f0f44..ca06fa4 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@xunji/desktop", "private": true, - "version": "0.1.2", + "version": "0.1.3", "type": "module", "scripts": { "dev": "vite", diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml index f0cf002..69ea5f6 100644 --- a/apps/desktop/src-tauri/Cargo.toml +++ b/apps/desktop/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xunji-desktop" -version = "0.1.2" +version = "0.1.3" description = "寻迹 - AI 编程知识管理平台" authors = ["XunJi"] edition = "2021" diff --git a/apps/desktop/src-tauri/src/commands/cards.rs b/apps/desktop/src-tauri/src/commands/cards.rs index eeeeadc..1443630 100644 --- a/apps/desktop/src-tauri/src/commands/cards.rs +++ b/apps/desktop/src-tauri/src/commands/cards.rs @@ -15,6 +15,7 @@ pub async fn search_cards( query: String, tags: Option>, card_type: Option, + tech_stack: Option>, ) -> Result, String> { let db = state.db.clone(); let filters = CardFilters { @@ -22,6 +23,7 @@ pub async fn search_cards( card_type, value: None, search: None, + tech_stack, }; tokio::task::spawn_blocking(move || db.search_cards(&query, &filters).map_err(|e| e.to_string())) .await @@ -35,6 +37,7 @@ pub async fn list_cards( tags: Option>, card_type: Option, value: Option, + tech_stack: Option>, page: Option, page_size: Option, ) -> Result, String> { @@ -44,6 +47,7 @@ pub async fn list_cards( card_type, value, search: None, + tech_stack, }; let page = page.unwrap_or(1).max(1); let page_size = page_size.unwrap_or(20).max(1).min(200); diff --git a/apps/desktop/src-tauri/src/storage/cards.rs b/apps/desktop/src-tauri/src/storage/cards.rs index 0f5f73b..019dc70 100644 --- a/apps/desktop/src-tauri/src/storage/cards.rs +++ b/apps/desktop/src-tauri/src/storage/cards.rs @@ -72,10 +72,9 @@ fn card_from_row(row: &Row<'_>) -> rusqlite::Result { // // 被 list_cards 和 search_cards 共用。 // -// 标签筛选使用 AND 语义(必须同时包含所有指定标签): -// SELECT card_id FROM card_tags -// JOIN tags ... WHERE name IN (...) -// GROUP BY card_id HAVING COUNT(DISTINCT name) = N +// 标签、技术栈筛选均为 AND 语义(须同时满足): +// - 标签:card_tags 子查询 HAVING COUNT(DISTINCT name) = N +// - 技术栈:cards.tech_stack 为逗号串,对每项用 instr 边界匹配(大小写不敏感) /// 根据 CardFilters 构建 WHERE 子句和参数列表 pub(super) fn build_card_where(filters: &CardFilters) -> (String, Vec) { @@ -110,6 +109,25 @@ pub(super) fn build_card_where(filters: &CardFilters) -> (String, Vec) { } } + // 技术栈存为逗号分隔字符串;用边界匹配避免子串误命中(如 go / golang) + if let Some(ref stacks) = filters.tech_stack { + let unique: Vec<&String> = { + let mut seen = std::collections::HashSet::new(); + stacks + .iter() + .filter(|s| !s.trim().is_empty()) + .filter(|s| seen.insert(*s)) + .collect() + }; + for s in unique { + conds.push( + "instr(',' || lower(ifnull(c.tech_stack, '')) || ',', ',' || lower(?) || ',') > 0" + .to_string(), + ); + params.push(s.clone()); + } + } + let where_sql = if conds.is_empty() { String::new() } else { diff --git a/apps/desktop/src-tauri/src/storage/models.rs b/apps/desktop/src-tauri/src/storage/models.rs index df03efb..ee71c33 100644 --- a/apps/desktop/src-tauri/src/storage/models.rs +++ b/apps/desktop/src-tauri/src/storage/models.rs @@ -383,4 +383,6 @@ pub struct CardFilters { pub value: Option, /// FTS5 全文搜索关键词 pub search: Option, + /// 按技术栈名称筛选(AND 语义;与 `cards.tech_stack` 逗号分隔字段逐 token 匹配,大小写不敏感) + pub tech_stack: Option>, } diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json index d001c85..d037754 100644 --- a/apps/desktop/src-tauri/tauri.conf.json +++ b/apps/desktop/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-cli/schema.json", "productName": "寻迹", - "version": "0.1.2", + "version": "0.1.3", "identifier": "com.xunji.app", "build": { "frontendDist": "../dist", diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index f52b6b5..5d14ed8 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -61,4 +61,16 @@ body { .dark ::-webkit-scrollbar-thumb { background-color: rgba(75, 85, 99, 0.35); } + +/** + * 分段条内的原生