feat: add import directory button to sidebar header#5
Conversation
feat(annotation): 添加圈点批注功能
## 问题 1. iTerm2 环境中 PATH 不包含 ~/.bun/bin,导致找不到 mdv 命令 2. mdv 脚本依赖 `#!/usr/bin/env bun`,在受限环境中无法执行 3. dispatcher 脚本退出码处理不明确 4. 调试日志污染 /tmp/my.log ## 修复 1. **dispatcher 脚本** (scripts/mdv-iterm2-dispatcher.sh) - 移除硬编码路径和调试日志 - 添加结构化的调试日志(时间戳格式) - 直接查找 bun 和 mdv 的完整路径(支持多个可能位置) - 使用 `bun run script.ts` 方式调用,不依赖 PATH - 显式 `exit 0` 确保退出码正确 2. **CLI 退出码** (src/cli.ts) - 成功时显式调用 `process.exit(0)` 3. **检查脚本** (scripts/check-iterm2-setup.sh) - 更新为检查 ~/.bun/bin 而不是 ~/bin - 使用 `command -v` 动态查找命令 4. **简化安装** (package.json) - 移除不需要的 postinstall 脚本 - 通过 bin 字段自动安装所有命令 5. **文档** - 更新设计文档,反映实际安装方式 - 添加修复报告和退出码问题详解 - 创建快速配置指南 ## 测试 ✅ 在受限 PATH 环境下测试通过(模拟 iTerm2) ✅ 所有路径格式正确解析(绝对、相对、basename) ✅ 退出码始终为 0 ✅ 用户实际 iTerm2 环境验证通过 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
调试日志已注释,需要时可以取消注释启用。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 在 tabs 按钮上显示当前打开的文件总数 - 提取 tab 批量操作逻辑到独立的 tab-batch.ts 工具模块 - 优化 tabs 渲染性能,避免不必要的 DOM 重建 - 修复 tabs 滚动位置保持问题 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
## 方案概述 通过 Bun 编译为自包含二进制,使用 Homebrew 分发 ## 核心特性 - ✅ 完全自包含(不需要 bun/node 运行时) - ✅ 跨平台支持(macOS Intel/ARM, Linux x64/ARM64) - ✅ 一键安装(brew install md-viewer) - ✅ 自动更新(brew upgrade md-viewer) - ✅ 只依赖系统自带库 ## 文件大小 - CLI 工具: ~58MB - 包含完整 Bun 运行时和所有依赖 ## 实施计划 - Week 1: 基础架构(静态资源、路径处理) - Week 2: 打包与分发(构建脚本、Formula) - Week 3: 自动化(CI/CD、GitHub Actions) - Week 4: 测试与发布 ## 工具 - 添加 scripts/test-compile.sh 用于测试编译功能 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
## 问题 为什么 Bun 编译的二进制这么大(58MB),而 Go 只有 2MB? ## 对比测试 - C: 16KB (优化后) - Rust: 300KB - Go: 1.6MB - Bun: 58MB ## 根本原因 Bun 58MB = 完整的 JavaScript 运行时 ├── JavaScriptCore 引擎 (40MB) - 4层JIT编译器 ├── Node.js API 兼容层 (10MB) - 40+个模块 ├── 内置工具 (5MB) - 包管理/打包/测试 └── 原生依赖 (3MB) - SQLite/压缩/加密 ## 对比分析 - Go: 简单GC + 静态类型 = 2MB - Rust: 零运行时 + 编译时检查 = 300KB - Bun: 完整JS引擎 + JIT + 兼容层 = 58MB ## 结论 对于 md-viewer: ✅ 58MB 是合理的代价 ✅ 用户体验优先(一键安装、快速启动) ✅ 开发效率高(TypeScript + JS生态)⚠️ 在文档中说明大小原因 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
核心方案: - 单一二进制 mdv(TypeScript 编译,60MB) - 统一 CLI:mdv server/open/config/stats - 前端资源嵌入 - 5 个实施 Phase Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Homebrew distribution support - Create unified CLI (mdv command) - Embed frontend resources (client.js, CSS, favicon) - Add server management (foreground/daemon mode) - Add operational commands (stats, cleanup, logs) - Add comments management commands - Create build and packaging scripts - Setup GitHub Actions for multi-platform builds - Add comprehensive documentation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move Formula to dedicated tap repo (huanghao/homebrew-tap) - Update installation instructions (brew tap huanghao/tap) - Add sync-formula-to-tap.sh script for automation - Update all documentation references Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Change macos-13 to macos-13-xlarge for x64 builds - Add fail-fast: false to continue building other platforms on failure - Add BUN_TARGET environment variable for cross-compilation - Update build-all.sh to support --target flag - Update package.sh to accept platform parameter - Add --frozen-lockfile to bun install for reproducible builds - Improve server detection in cli.ts with HTTP reachability check Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove --frozen-lockfile flag to allow lockfile updates - Change macos-13-xlarge to macos-13 (standard Intel runner) - Use bun-darwin-x64-baseline target for better compatibility Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add retry logic for bun install to handle transient network errors - Use macos-latest for darwin-x64 with cross-compilation instead of macos-13 - This avoids the 'macos-13-us-default' configuration error Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Disable errexit during retry loop - Re-enable errexit after successful install - This allows retries to work properly in GitHub Actions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Increase retry attempts from 3 to 5 - Verify critical packages (esbuild, typescript) are actually installed - Clean node_modules between retries - Increase sleep time to 10 seconds - Add final verification check Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Node.js setup with npm cache - Try bun install first, fall back to npm if it fails - Use npm (more reliable in CI) as fallback - Simplify retry logic with explicit fallback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace bun install with npm ci (more reliable in CI) - npm ci uses package-lock.json for reproducible builds - Avoid network issues with bun's registry Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
npm ci requires package-lock.json to be in sync, use npm install for flexibility Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
package-lock.json contains internal registry URLs (sankuai.com) that are not accessible from GitHub Actions. Force official registry. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove internal registry URLs (sankuai.com) from package-lock.json to make CI builds work on GitHub Actions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Artifacts are downloaded flat, not in subdirectories. Fix SHA256 calculation to handle both structures. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Avoid shell glob expansion issues by checking file type directly Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add packages/*.tar.gz to handle flat artifact downloads Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…arTab/focusWindowKey
Update renderWorkspaceSidebar to reference state.config.sidebarTab ('focus' | 'full' | 'list')
instead of the deprecated state.config.sidebarView.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s with tree-item Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…m styles Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… tags - Add markdownTheme and codeTheme fields to AppConfig interface - Add corresponding defaults (both set to 'github') - Add id attributes (theme-md-css, theme-hl-css) to style tags for dynamic theme switching Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…logs were invisible
Adds a folder icon button in the top-left sidebar header (next to the MD Viewer logo) that opens the existing "Add Workspace" dialog. Previously the only way to import a directory was to switch to the workspace view (focus/full tab) and find the "+" button there. This change makes directory import accessible from any sidebar mode without requiring a tab switch. Implementation: - html.ts: add .import-dir-btn button inside <h1>, calls showAddWorkspaceDialog() which is already wired to window by sidebar-workspace.ts - css.ts: style the button — transparent background, 26×26px, hover state matches existing icon button patterns; margin-left:auto pushes it to the far right of the h1 row No new logic or API changes needed; the dialog and workspace scan flow are fully reused. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces an "Import Directory" button to the MD Viewer header, including its HTML structure and CSS styling. The review feedback focuses on improving the button's visual consistency with existing UI elements by adjusting the border radius and transitions, as well as enhancing accessibility for screen readers by adding an aria-label.
| .import-dir-btn { | ||
| margin-left: auto; | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| width: 26px; | ||
| height: 26px; | ||
| padding: 0; | ||
| border: none; | ||
| border-radius: 5px; | ||
| background: transparent; | ||
| color: #57606a; | ||
| cursor: pointer; | ||
| flex-shrink: 0; | ||
| transition: background 0.15s, color 0.15s; | ||
| } | ||
| .import-dir-btn:hover { | ||
| background: #e8eaed; | ||
| color: #24292e; | ||
| } |
There was a problem hiding this comment.
For consistency with other interactive elements in this repository, the border-radius should be 6px and the transition should explicitly use background-color with the ease timing function. Additionally, adding an :active state with a slight scale effect would match the behavior of other buttons in the UI (like the copy buttons).
.import-dir-btn {
margin-left: auto;
display: flex;
align-items: center;
justify-content: center;
width: 26px;
height: 26px;
padding: 0;
border: none;
border-radius: 6px;
background: transparent;
color: #57606a;
cursor: pointer;
flex-shrink: 0;
transition: background-color 0.15s ease, color 0.15s ease;
}
.import-dir-btn:hover {
background: #e8eaed;
color: #24292e;
}
.import-dir-btn:active {
transform: scale(0.95);
}| <button | ||
| class="import-dir-btn" | ||
| onclick="showAddWorkspaceDialog()" | ||
| title="导入目录" | ||
| > |
There was a problem hiding this comment.
To ensure accessibility for screen readers and maintain consistency with other icon-only buttons in the sidebar (such as the annotation density and filter toggles), please add an aria-label attribute to this button.
| <button | |
| class="import-dir-btn" | |
| onclick="showAddWorkspaceDialog()" | |
| title="导入目录" | |
| > | |
| <button | |
| class="import-dir-btn" | |
| onclick="showAddWorkspaceDialog()" | |
| title="导入目录" | |
| aria-label="导入目录" | |
| > |
On macOS, clicking the import button now opens a native Finder folder
picker (via osascript) instead of a text input dialog.
- handlers.ts: add handlePickDirectory — spawns osascript to show the
system folder chooser, returns { path } on confirm or { cancelled }
on dismiss
- server.ts: register POST /api/pick-directory
- sidebar-workspace.ts: showAddWorkspaceDialog now calls the API first;
on success it adds the workspace directly; on cancel it does nothing;
on error (non-macOS or API failure) it falls back to the text dialog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…all) Right-clicking any tab now shows a native-style context menu with three actions: - 关闭当前 — closes the tab that was right-clicked - 关闭其他 — closes every tab except the one right-clicked (uses that tab as the pivot, not necessarily the active tab) - 关闭所有 — closes all open tabs Implementation: - sidebar.ts: showTabContextMenu() builds and positions a fixed-overlay menu element, wires click handlers, and auto-dismisses on any outside click/contextmenu; applyTabBatchAction gains an optional pivotPath param so "close-others" works correctly from the context menu - css.ts: .tab-context-menu / .tab-context-item styles, matching the app's existing GitHub-inspired design language Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
Adds a folder icon button in the top-left sidebar header (next to the MD Viewer logo) that opens the existing "Add Workspace" dialog.
Before: the only way to import a directory was to switch to the workspace view (焦点/全量 tab) and find the
+button there — not obvious for new users.After: a small folder icon sits in the header, always visible regardless of which sidebar tab is active.
Changes
src/client/html.ts: add.import-dir-btnbutton inside<h1>, callsshowAddWorkspaceDialog()which is already exposed onwindowbysidebar-workspace.tssrc/client/css.ts: style the button — 26×26px, transparent background, hover state consistent with existing toolbar icon buttons;margin-left: autopushes it to the far right of the header rowNo new logic or API changes — the dialog, path autocomplete, and workspace scan flow are fully reused.
Test plan
🤖 Generated with Claude Code