⚠️ Core Rules
Create only one panel at a time. Each user instruction requests the creation of only one navigation panel. Never batch-generate navigation for all folders at once. Create only one component + register it to page.tsx each time.
What Is Meridian
Meridian is a local web application based on Next.js that serves as a visualization cockpit for an Obsidian vault.
Installation and Initialization (Clone the Project)
If the user's Obsidian Vault does not yet contain the Meridian project code (i.e., the 05 工具箱/vault-pilot/ directory cannot be found), you need to obtain the official code from GitHub to complete the initial installation and deployment for them:
# 进入工具箱目录拉取代码
cd "05 工具箱"
git clone https://github.com/zephyrwang6/VaultPilot.git vault-pilot
cd vault-pilot
npm install
Project Location:05 工具箱/vault-pilot/(directory name is vault-pilot, product name is Meridian)
Startup Method:cd "05 工具箱/vault-pilot" && npm run dev -- --port 3001
Access URL:http://localhost:3001
Project Structure
vault-pilot/
├── app/
│ ├── page.tsx # 主页面(侧边栏 + 内容区)
│ ├── layout.tsx # 布局 + Inter 字体
│ ├── globals.css # 暗/浅双主题 + 玻璃态
│ ├── components/
│ │ ├── AgentPanel.tsx # Agent 面板(CLI + .claude.md + Skills)
│ │ ├── FoldersPanel.tsx # 文件夹面板(文件夹树 + 快捷指令)
│ │ ├── FolderAnalysisModal.tsx # 文件夹分析弹窗(4种视图)
│ │ ├── UsagePanel.tsx # Claude Code 用量统计
│ │ ├── DynamicPanel.tsx # 动态面板渲染器
│ │ └── Onboarding.tsx # 首次引导绑定
│ └── api/
│ ├── config/route.ts # 配置读写 + .claude.md
│ ├── vault/route.ts # 文件夹结构扫描
│ ├── skills/route.ts # Skills 库扫描
│ ├── claude/route.ts # 打开终端执行
│ ├── pick-folder/route.ts # 原生文件夹选择器
│ ├── folder-analysis/route.ts # 文件夹深度分析
│ └── usage/route.ts # Claude Code 用量数据
└── lib/types.ts # 核心类型定义
Design Reference
Panel design reference: components under 05 工具箱/obsidian-dashboard/my-app/app/components/desktop/ :
| Panel | Reference File | Function |
|---|---|---|
| Overview | OverviewPanel.tsx |
Data overview, recent documents, schedule, tasks |
| Creation | ContentPanel.tsx |
Standalone article list, column chapter list |
| Planning | GoalsPanel.tsx |
Annual goals, weekly plan progress |
| Review | ReviewPanel.tsx |
This week's output statistics progress bar, completed tasks |
Note: The reference is for design style and functional layout. Meridian uses its own CSS classes (glass-card, etc.) and does not use shadcn/ui.Data must be read dynamically from the local file system; do not hardcode it.
CSS Design Specifications
| Class Name | Purpose |
|---|---|
glass-card |
Glassmorphism card container |
rounded-2xl p-5 |
Standard card padding |
stat-value |
Large numbers |
text-violet-400 |
Primary color icons |
text-muted-foreground |
Secondary text |
bg-secondary/30 |
Hover/background |
stagger-children |
Child element stagger animation |
gradient-text |
Gradient text |
Available API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/config |
GET | Read configuration + .claude.md |
/api/vault |
GET | Scan Vault folder structure |
/api/folder-analysis?path=... |
GET | Deep analysis of a specified folder |
/api/skills |
GET | Read Skills list |
/api/usage |
GET | Claude Code usage statistics |
Panel Creation Workflow
Create one panel at a time, following these steps:
Step 1: Read the Reference
# 读取 obsidian-dashboard 对应面板的设计
cat "05 工具箱/obsidian-dashboard/my-app/app/components/desktop/OverviewPanel.tsx"
Step 2: Create the Component
Under 05 工具箱/vault-pilot/app/components/ , create XxxPanel.tsx:
- Data is obtained via API (
/api/folder-analysis) or by reading files - Must use Meridian CSS classes such as glass-card, stat-value, etc.
- Do not use shadcn/ui components
Component Template:
'use client';
import { useState, useEffect } from 'react';
import { Loader2, SomeIcon } from 'lucide-react';
interface PanelProps {
vaultPath: string;
}
export function XxxPanel({ vaultPath }: PanelProps) {
const [data, setData] = useState<any>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(`/api/folder-analysis?path=${encodeURIComponent(vaultPath + '/目标文件夹')}`)
.then(r => r.json())
.then(d => { setData(d); setLoading(false); })
.catch(() => setLoading(false));
}, [vaultPath]);
if (loading) return <div className="flex justify-center py-16"><Loader2 className="h-6 w-6 animate-spin text-muted-foreground" /></div>;
return (
<div className="space-y-5 stagger-children">
<div className="grid grid-cols-3 gap-3">
<div className="glass-card rounded-xl p-4">
<div className="stat-value text-2xl">数值</div>
<div className="text-[10px] text-muted-foreground">标签</div>
</div>
</div>
<div className="glass-card rounded-2xl p-5">
<div className="text-sm font-medium mb-3">标题</div>
<div className="space-y-1.5">{/* 列表项 */}</div>
</div>
</div>
);
}
Step 3: Register to page.tsx
Modify 05 工具箱/vault-pilot/app/page.tsx; 3 places need to be changed:
// 1. 导入(在文件顶部 import 区域)
import { XxxPanel } from './components/XxxPanel';
// 2. 在 defaultNavItems 数组添加(约第 22 行)
{ id: 'xxx', label: '面板名', icon: SomeIcon },
// 3. 在 renderPanel() 的 switch 中添加 case(约第 107 行)
case 'xxx':
return <XxxPanel vaultPath={config.vaultPath} />;
Step 4: Notify the User
After completion, notify the user: The "XXX" panel has been created, please refresh http://localhost:3001 View.