-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprogress.json
More file actions
174 lines (174 loc) · 12.9 KB
/
progress.json
File metadata and controls
174 lines (174 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
{
"project": "Markover",
"description": "Markdown WYSIWYG editor with Word-like collaboration features",
"lastUpdated": "2026-03-28 (image-drop-dialog)",
"phases": [
{
"id": "phase-1",
"name": "Foundation MVP",
"status": "done",
"tasks": [
{ "id": "1.1", "name": "Electron + Vite + React scaffold", "status": "done" },
{ "id": "1.2", "name": "TipTap editor with formatting extensions", "status": "done" },
{ "id": "1.3", "name": "Toolbar with formatting buttons", "status": "done" },
{ "id": "1.4", "name": "Status bar (word count, cursor position)", "status": "done" },
{ "id": "1.5", "name": "File open/save/save-as via IPC", "status": "done" },
{ "id": "1.6", "name": "Native application menu", "status": "done" }
]
},
{
"id": "phase-2",
"name": "Advanced Markdown",
"status": "done",
"tasks": [
{ "id": "2.1", "name": "Markdown round-tripping (parser + serializer)", "status": "done" },
{ "id": "2.2", "name": "KaTeX inline/block rendering", "status": "done" },
{ "id": "2.3", "name": "KaTeX inline/block WYSIWYG editing", "status": "done", "notes": "Double-click opens KatexEditDialog with live KaTeX preview. Saves via setNodeMarkup." },
{ "id": "2.4", "name": "Mermaid diagram rendering", "status": "done" },
{ "id": "2.5", "name": "Mermaid diagram WYSIWYG editing", "status": "done", "notes": "Double-click opens MermaidEditDialog with side-by-side live preview. Saves via setNodeMarkup." },
{ "id": "2.6", "name": "Footnotes", "status": "done" },
{ "id": "2.7", "name": "YAML front matter", "status": "done" },
{ "id": "2.8", "name": "Image drop/paste insertion", "status": "done" },
{ "id": "2.8a", "name": "Image drop dialog with path/base64 options", "status": "done", "notes": "Dropping an image now shows an 'Insert Image' modal before inserting. Options: relative path (disabled with hint if doc unsaved), absolute path, or embed as Base64 data URL. Alt text pre-populated from filename. Dialog dispatched via markover:image-drop CustomEvent; App.tsx renders ImageDropDialog." },
{ "id": "2.9", "name": "Image resize UI and alt-text editing", "status": "done", "notes": "Double-click opens ImageEditDialog: edit URL, alt text, and width (presets: 25/50/75/100% or custom). Width serialized as <img> HTML tag for round-tripping. Toolbar link/image insert buttons now use proper React dialogs (window.prompt removed)." },
{ "id": "2.10", "name": "Table editing", "status": "done", "notes": "TableBubbleMenu floats when cursor is in a table: insert/delete/move columns and rows, delete table. Uses prosemirror-tables moveTableColumn/moveTableRow." },
{ "id": "2.11", "name": "Broken local images", "status": "not-started", "notes": "Images with relative file paths don't resolve because renderer base URL is the Vite dev server, not the file directory. Fix requires a custom protocol handler or path rewriting in the main process." }
]
},
{
"id": "phase-3",
"name": "Markover Codec",
"status": "done",
"tasks": [
{ "id": "3.1", "name": "Schema for metadata types", "status": "done" },
{ "id": "3.2", "name": "Parser (extract metadata from markdown)", "status": "done" },
{ "id": "3.3", "name": "Serializer (inject metadata into markdown)", "status": "done" },
{ "id": "3.4", "name": "Validator", "status": "done" }
]
},
{
"id": "phase-4",
"name": "Comments System",
"status": "done",
"tasks": [
{ "id": "4.1", "name": "Comment store (Zustand)", "status": "done" },
{ "id": "4.2", "name": "Comments sidebar panel with threads", "status": "done" },
{ "id": "4.3", "name": "Comment highlight marks in editor", "status": "done" },
{ "id": "4.4", "name": "Comment status (open/resolved/pending)", "status": "done" },
{ "id": "4.5", "name": "Fix highlight offset tracking", "status": "done", "notes": "Marks serialize as <span data-markov='hl' data-comment-id='...'> inline HTML (not HTML comments). Vite HMR watch excludes .md files to prevent page reload on save." },
{ "id": "4.6", "name": "Comment metadata round-tripping via codec", "status": "done", "notes": "Inline highlight markers survive round-trip. Comment thread metadata appended as markover:comment blocks at end of file." },
{ "id": "4.7", "name": "Replace window.prompt with inline dialog", "status": "done", "notes": "window.prompt() was unreliable in Electron. Replaced with a React modal that preserves editor selection." }
]
},
{
"id": "phase-5",
"name": "Track Changes",
"status": "done",
"tasks": [
{ "id": "5.1", "name": "Track changes store (Zustand)", "status": "done" },
{ "id": "5.2", "name": "Insert mark extension", "status": "done" },
{ "id": "5.3", "name": "Delete mark extension", "status": "done" },
{ "id": "5.4", "name": "Track changes sidebar panel (accept/reject UI)", "status": "done" },
{ "id": "5.5", "name": "Plugin intercepting transactions for insertions", "status": "done" },
{ "id": "5.6", "name": "Deletion tracking in plugin", "status": "done", "notes": "Plugin reads deleted text from oldState and re-inserts with markovDelete mark." },
{ "id": "5.7", "name": "Track change marks serialized to markdown", "status": "done", "notes": "Serializer emits <span data-markov='ins/del' ...> spans. Avoids <ins>/<del> which conflicted with TipTap's Strike extension." },
{ "id": "5.8", "name": "Track change marks parsed from markdown", "status": "done", "notes": "span[data-markov='ins/del'] parseHTML rules with priority:110. Backwards-compatible rules for old ins/del format." },
{ "id": "5.9", "name": "Accept/reject functionality", "status": "done", "notes": "Accept insertion keeps text, accept deletion removes it. Reject insertion removes text, reject deletion keeps it." },
{ "id": "5.10", "name": "Group consecutive insertions into one tracked change", "status": "done", "notes": "Plugin reuses changeId when typed characters are adjacent (lastInsertEnd === newStart). Resets on cursor move or deletion." },
{ "id": "5.11", "name": "Fix TipTap extension.storage getter bug", "status": "done", "notes": "TipTap 3's extension.storage getter returns a new copy on every access. Plugin now reads/writes via editor.storage[extensionName] (persistent extensionStorage)." }
]
},
{
"id": "phase-6",
"name": "Spell Checking",
"status": "done",
"tasks": [
{ "id": "6.1", "name": "Electron Hunspell spell check", "status": "done" },
{ "id": "6.2", "name": "Context menu with suggestions", "status": "done" },
{ "id": "6.3", "name": "Add to dictionary", "status": "done" },
{ "id": "6.4", "name": "cspell exception support in markdown", "status": "done", "notes": "Right-click misspelled word → 'Ignore in this document' adds word to cspellIgnores in metadata. Serialized as <!-- cspell:ignore word1 word2 --> at top of .md file. Parsed on load (words added to session spell checker). Preserved in published/cleaned output. Phase 6 complete." }
]
},
{
"id": "phase-7",
"name": "Print and Export",
"status": "done",
"tasks": [
{ "id": "7.1", "name": "PDF export via Electron printToPDF", "status": "done" },
{ "id": "7.2", "name": "Print support", "status": "done" },
{ "id": "7.3", "name": "Publish: export clean markdown without markover metadata", "status": "done", "notes": "File > Publish (Ctrl+Shift+P) saves plain markdown to a new file. Uses parseMarkoverFile to strip comment blocks, then regex to accept all track changes (ins=keep, del=remove) and remove comment highlights." }
]
},
{
"id": "phase-8",
"name": "Highlighting",
"status": "done",
"tasks": [
{ "id": "8.1", "name": "General-purpose text highlighting", "status": "done", "notes": "TipTap Highlight extension. Serializes as <mark> (not ==...==) so round-trip works through markdown-it." },
{ "id": "8.2", "name": "Toolbar button for standalone highlighting", "status": "done", "notes": "Highlighter icon in toolbar applies the highlight mark." }
]
},
{
"id": "phase-9",
"name": "E2E Testing",
"status": "done",
"tasks": [
{ "id": "9.1", "name": "Install Playwright with Electron support", "status": "done" },
{ "id": "9.2", "name": "Test harness and fixtures", "status": "done" },
{ "id": "9.3", "name": "E2E tests for core editing features", "status": "done" },
{ "id": "9.4", "name": "E2E tests for comments", "status": "done", "notes": "comments.spec.ts: add comment, verify highlight, sidebar visibility, cancel dialog." },
{ "id": "9.5", "name": "E2E tests for track changes", "status": "done", "notes": "track-changes.spec.ts: enable TC, insertion marks, deletion marks, panel, accept all." },
{ "id": "9.6", "name": "E2E tests for mermaid/KaTeX/tables", "status": "done", "notes": "special-blocks.spec.ts: table insert/columns/typing, code block insert/typing/language selector, raw mode toggle." },
{ "id": "9.7", "name": "E2E tests for file save/load round-tripping", "status": "done", "notes": "file-roundtrip.spec.ts: dirty indicator, word/char count, markdown round-trip for bold/italic/headings, cursor position." }
]
},
{
"id": "phase-10",
"name": "Raw Edit Mode",
"status": "done",
"tasks": [
{ "id": "10.1", "name": "Toggle between WYSIWYG and raw markdown editing", "status": "done", "notes": "FileCode button in toolbar. Switches on toggle; syncs content both ways via getMarkdown()/loadContent()." },
{ "id": "10.2", "name": "Syntax-highlighted raw editor (CodeMirror 6)", "status": "done", "notes": "Uses @uiw/react-codemirror with @codemirror/lang-markdown. One Dark theme in dark mode." },
{ "id": "10.3", "name": "Toolbar/status bar indicator for current mode", "status": "done", "notes": "FileCode button shows active state; status bar shows 'Raw Mode' in purple." }
]
},
{
"id": "phase-11",
"name": "Light/Dark Mode",
"status": "done",
"tasks": [
{ "id": "11.1", "name": "Theme store and system preference detection", "status": "done" },
{ "id": "11.2", "name": "Dark mode CSS variables and Tailwind dark classes", "status": "done" },
{ "id": "11.3", "name": "Theme toggle in toolbar or menu", "status": "done" },
{ "id": "11.4", "name": "Persist theme preference", "status": "done" }
]
},
{
"id": "phase-12",
"name": "User Guide",
"status": "done",
"tasks": [
{ "id": "12.1", "name": "User guide content (features, usage, shortcuts)", "status": "done", "notes": "HelpDialog covers all features: file ops, formatting shortcuts, comments, track changes, KaTeX, Mermaid, tables, images, file format." },
{ "id": "12.2", "name": "In-app help or bundled guide", "status": "done", "notes": "F1 or Help > User Guide opens the HelpDialog. Searchable. Also added Collaborate menu (Add Comment, Toggle Track Changes) and Help menu to native menu bar." }
]
},
{
"id": "phase-13",
"name": "Find & Replace",
"status": "done",
"tasks": [
{ "id": "13.1", "name": "Find & Replace store (Zustand)", "status": "done", "notes": "find-replace-store.ts: query, replacement, options (matchCase, wholeWord, regex, wrap, inSelection, selectionFrom, selectionTo), match state, history." },
{ "id": "13.2", "name": "FindReplaceDialog UI (draggable, tabbed)", "status": "done", "notes": "FindReplaceDialog.tsx: draggable floating panel, Find/Replace tabs, option checkboxes, status line, keyboard shortcuts (Enter/Shift+Enter/F3/Esc)." },
{ "id": "13.3", "name": "TipTap FindReplaceExtension with ProseMirror plugin", "status": "done", "notes": "find-replace-extension.ts + find-replace-plugin.ts: highlights all matches, tracks currentIndex, supports text/mermaid/math scopes, regex, wholeWord, matchCase, inSelection, track-changes-aware replace." },
{ "id": "13.4", "name": "CodeMirror (raw mode) search integration", "status": "done", "notes": "RawEditor.tsx exposes RawSearchHandle via searchRef. Uses @codemirror/search setSearchQuery.of(sq) (not the non-existent sq.asEffect()). findNext/findPrev/replace/replaceAll delegate to CodeMirror commands." },
{ "id": "13.5", "name": "Bug fixes: CodeMirror API, type declarations, inSelection reactivity", "status": "done", "notes": "Fixed sq.asEffect() → setSearchQuery.of(sq). Added declare module '@tiptap/core' Commands augmentation. Added @codemirror/search to package.json. Added inSelection/selectionFrom/selectionTo to useEffect deps." }
]
}
],
"statusLegend": {
"done": "Complete and working",
"in-progress": "Partially implemented, has known gaps",
"not-started": "Not yet implemented",
"blocked": "Blocked by another task"
}
}