Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursor/commands/release-pr-tag.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. 确认合并关系(可选但推荐)
Expand Down
59 changes: 59 additions & 0 deletions .cursor/plans/ui-sync-with-demo_7774ca21.plan.md
Original file line number Diff line number Diff line change
@@ -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 割裂。

5 changes: 3 additions & 2 deletions .cursor/skills/pitfall-documentation/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 执行要点
Expand Down
3 changes: 2 additions & 1 deletion .cursor/skills/pitfall-documentation/reference-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@

## 文件命名建议

- 形式:`领域或应用名-主题关键词.md`,例如:`桌面应用-会话提炼-JSON解析与标签技术栈.md`。
- **以中文为主**、`-` 分段;技术专名可保留英文(`UnoCSS`、`CLI`、`JSON` 等)。示例:`桌面应用-会话提炼-JSON解析与标签技术栈.md`。
- 完整约定与索引见仓库 [`docs/踩坑/README.md`](../../../docs/踩坑/README.md)。
- 同一主题持续踩坑:优先 **合并进已有文件** 为新 `##` / `###` 小节,避免碎片化。
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

### 新增
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@xunji/desktop",
"private": true,
"version": "0.1.2",
"version": "0.1.3",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "xunji-desktop"
version = "0.1.2"
version = "0.1.3"
description = "寻迹 - AI 编程知识管理平台"
authors = ["XunJi"]
edition = "2021"
Expand Down
4 changes: 4 additions & 0 deletions apps/desktop/src-tauri/src/commands/cards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ pub async fn search_cards(
query: String,
tags: Option<Vec<String>>,
card_type: Option<String>,
tech_stack: Option<Vec<String>>,
) -> Result<Vec<CardSummary>, String> {
let db = state.db.clone();
let filters = CardFilters {
tags,
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
Expand All @@ -35,6 +37,7 @@ pub async fn list_cards(
tags: Option<Vec<String>>,
card_type: Option<String>,
value: Option<String>,
tech_stack: Option<Vec<String>>,
page: Option<u32>,
page_size: Option<u32>,
) -> Result<PaginatedResult<CardSummary>, String> {
Expand All @@ -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);
Expand Down
26 changes: 22 additions & 4 deletions apps/desktop/src-tauri/src/storage/cards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,9 @@ fn card_from_row(row: &Row<'_>) -> rusqlite::Result<Card> {
//
// 被 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<String>) {
Expand Down Expand Up @@ -110,6 +109,25 @@ pub(super) fn build_card_where(filters: &CardFilters) -> (String, Vec<String>) {
}
}

// 技术栈存为逗号分隔字符串;用边界匹配避免子串误命中(如 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 {
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src-tauri/src/storage/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,6 @@ pub struct CardFilters {
pub value: Option<String>,
/// FTS5 全文搜索关键词
pub search: Option<String>,
/// 按技术栈名称筛选(AND 语义;与 `cards.tech_stack` 逗号分隔字段逐 token 匹配,大小写不敏感)
pub tech_stack: Option<Vec<String>>,
}
2 changes: 1 addition & 1 deletion apps/desktop/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
12 changes: 12 additions & 0 deletions apps/desktop/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,16 @@ body {
.dark ::-webkit-scrollbar-thumb {
background-color: rgba(75, 85, 99, 0.35);
}

/**
* 分段条内的原生 <button>:Tauri/WebKit 会套用系统按钮外观(灰底、凸起),
* 未选中项看起来像「实心灰块」,浅色/深色下都会破坏与 ui_demo 一致的扁平分段样式。
* 仅对带 .segment-pill-btn 的按钮去外观,避免影响 Naive UI 的 n-button。
*/
button.segment-pill-btn {
-webkit-appearance: none;
appearance: none;
margin: 0;
font: inherit;
}
</style>
2 changes: 1 addition & 1 deletion apps/desktop/src/components/AppLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import AnalysisQueuePanel from './AnalysisQueuePanel.vue'
<TopBar />
<div class="flex flex-1 min-h-0">
<Sidebar />
<main class="flex-1 min-w-0 min-h-0 overflow-hidden bg-neutral-50/50 dark:bg-neutral-950">
<main class="flex-1 min-w-0 min-h-0 overflow-hidden bg-[#fafafa] dark:bg-neutral-950">
<router-view />
</main>
</div>
Expand Down
Loading
Loading