docs: align dashboard ux contract with refined ui

This commit is contained in:
Research Assistant 2026-05-10 19:15:10 +08:00
parent 09a520fb7a
commit d8a0d4d83e
2 changed files with 23 additions and 12 deletions

View file

@ -47,10 +47,10 @@
| Step ID | Trigger | Action | Measurable Outcome | Error Contract |
|---------|---------|--------|-------------------|----------------|
| W4-S1 | User opens Obsidian vault | Plugin loads and registers dashboard view | Plugin view registered; sidebar icon visible; clicking opens PaperForge dashboard panel | Plugin not loaded; console shows "Failed to register PaperForge view" |
| W4-S2 | User opens a `.base` file | Collection mode activates | Dashboard switches to `collection` mode; shows: workflow funnel (Total → PDF Ready → OCR Done → Deep Read), OCR pipeline progress bar scoped to current base, issue summary (compact, only when issues exist), action buttons (Sync Library, Run OCR) | Falls to global mode; missing stats |
| W4-S3 | User opens a formal note (`.md` with `zotero_key`) | Paper mode activates | Dashboard switches to `paper` mode; shows: status strip (PDF/OCR/DeepRead pills), paper overview card (Pass 1 summary from `## 🔍 精读`), workflow toggle checkboxes (`do_ocr`/`analyze` — sync to Base), next-step card, files row (Open PDF / Open Fulltext), collapsible technical details | Falls to global mode; components empty or erroring |
| W4-S2 | User opens a `.base` file | Collection mode activates | Dashboard switches to `collection` mode; preserves module order: header, workflow funnel (Total → PDF Ready → OCR Done → Deep Read), OCR pipeline scoped to current base, collection-scoped issue/health messaging only inside the collection view, then action buttons (Run OCR primary, Sync Library secondary) | Falls to global mode; missing stats; collection issues appear as a separate extra module outside the collection view |
| W4-S3 | User opens a formal note (`.md` with `zotero_key`) | Paper mode activates | Dashboard switches to `paper` mode; preserves module order: paper header, status/file row, paper overview card, next-step or complete row, discussion card, collapsible technical details; panel keeps bottom-safe-area padding so final content is fully visible; expanding technical details does not trigger scrollbar reflow/width jump; first discussion expand does not collapse on the first click | Falls to global mode; components empty or erroring; bottom content is clipped; expanding discussion/technical details causes collapse or layout jump |
| W4-S4 | User opens `fulltext.md` or other workspace file | Paper mode activates via workspace detection | Dashboard stays in `paper` mode for any file inside a paper workspace directory (`{key} - {title}/`). zotero_key resolved from dirname pattern | Falls to global mode |
| W4-S5 | User opens no file or non-workspace `.md` | Global mode activates | Dashboard shows: library snapshot (papers / PDFs / OCR done / deep-read done), system status grid (runtime / index / Zotero export / OCR token), issues panel (only when anomalies exist with Run Doctor / Repair Issues), action buttons (Open Literature Hub / Sync Library) | Shows loading/empty state; console errors |
| W4-S5 | User opens no file or non-workspace `.md` | Global mode activates | Dashboard shows, in preserved order: library snapshot (papers / PDFs / OCR done / deep-read done), system status grid (runtime / index / Zotero export / OCR token), optional issues panel (only when anomalies exist with Run Doctor / Repair Issues), then action buttons (Open Literature Hub primary / Sync Library secondary); light and dark themes both keep muted accents, readable contrast, and visible keyboard focus on collection/global action controls | Shows loading/empty state; console errors; module order changes unexpectedly; light/dark theme contrast or focus visibility regresses |
| W4-S6 | User toggles `do_ocr` or `analyze` checkbox | Workflow toggle writes to frontmatter | Checkbox state writes to formal note YAML frontmatter via `processFrontMatter`; Base view reflects change immediately (reads from file); dashboard auto-refreshes via `modify` event | Frontmatter not written; notice shows "Note file not found" |
---

View file

@ -1316,7 +1316,7 @@ class PaperForgeStatusView extends ItemView {
const actionsRow = view.createEl('div', { cls: 'paperforge-global-actions' });
actionsRow.createEl('div', { cls: 'paperforge-section-label', text: 'Start Working' });
const btnsRow = actionsRow.createEl('div', { cls: 'paperforge-global-actions-row' });
const hubBtn = btnsRow.createEl('button', { cls: 'paperforge-contextual-btn' });
const hubBtn = btnsRow.createEl('button', { cls: 'paperforge-contextual-btn primary' });
hubBtn.createEl('span', { cls: 'paperforge-contextual-btn-icon', text: '\uD83D\uDCC1' });
hubBtn.createEl('span', { text: 'Open Literature Hub' });
hubBtn.addEventListener('click', () => {
@ -1817,6 +1817,14 @@ class PaperForgeStatusView extends ItemView {
// ── Contextual Actions ──
const actionsRow = view.createEl('div', { cls: 'paperforge-collection-actions' });
const ocrActionBtn = actionsRow.createEl('button', { cls: 'paperforge-contextual-btn primary' });
ocrActionBtn.createEl('span', { cls: 'paperforge-contextual-btn-icon', text: '\u229E' });
ocrActionBtn.createEl('span', { text: 'Run OCR' });
ocrActionBtn.addEventListener('click', () => {
const action = ACTIONS.find(a => a.id === 'paperforge-ocr');
if (action) this._runAction(action, ocrActionBtn);
});
const syncBtn = actionsRow.createEl('button', { cls: 'paperforge-contextual-btn' });
syncBtn.createEl('span', { cls: 'paperforge-contextual-btn-icon', text: '\u21BB' });
syncBtn.createEl('span', { text: 'Sync Library' });
@ -1824,14 +1832,6 @@ class PaperForgeStatusView extends ItemView {
const action = ACTIONS.find(a => a.id === 'paperforge-sync');
if (action) this._runAction(action, syncBtn);
});
const ocrActionBtn = actionsRow.createEl('button', { cls: 'paperforge-contextual-btn' });
ocrActionBtn.createEl('span', { cls: 'paperforge-contextual-btn-icon', text: '\u229E' });
ocrActionBtn.createEl('span', { text: 'Run OCR' });
ocrActionBtn.addEventListener('click', () => {
const action = ACTIONS.find(a => a.id === 'paperforge-ocr');
if (action) this._runAction(action, ocrActionBtn);
});
}
/* ── Refresh current mode (called on index change, D-09, REFR-01) ── */
@ -2067,6 +2067,17 @@ class PaperForgeStatusView extends ItemView {
const leafHandler = this.app.workspace.on('active-leaf-change', () => {
clearTimeout(this._leafChangeTimer);
this._leafChangeTimer = setTimeout(() => {
const resolved = this._resolveModeForFile(this.app.workspace.getActiveFile());
const nextMode = resolved.mode;
const nextFilePath = resolved.filePath;
// Clicking inside the dashboard can activate its leaf without changing
// the underlying paper/base context. Avoid rebuilding the whole mode
// tree in that case, or transient UI state like discussion expansion resets.
if (this._currentMode === nextMode && this._currentFilePath === nextFilePath) {
return;
}
this._detectAndSwitch();
}, 300);
});