Tiered scoring (exact 1.0 / stem 1.0 / prefix 0.8 / subseq 0.5+bonuses
capped 0.79) with leftmost+rightmost greedy alignment — rightmost wins
for extension/suffix queries ('md' against 'readme.md'), leftmost wins
for prefix queries ('re' against 'readme.md'). Boost-aware rankResults
applies recency x2 and open-tabs x1.5 multiplicatively; empty query
falls back to boosts alone.
Pure module, no DOM/IPC/Node — runs in renderer or main. 22 new tests.
Amit Haridas
User feedback on v4.11.0: the Add Connection form was buried below the
node/edge lists and they couldn't find it; they also asked for per-node
color and Save to File export. v4.12.0 reorganises the #fc-nodelist panel
to put the connect form right after the Add Node buttons, adds a native
<input type="color"> per node row that drives a new store.setNodeColor
mutator (with serialize/deserialize round-trip), and wires a Save to File
button that pops a system save dialog via a new 'save-text-file' IPC
channel.
- src/flowchart-generator.html — panel order is now Add Node /
Add Connection / Nodes / Edges / Export (Insert · Save · Reset).
Removed the legacy top toolbar; status moved into the panel.
Added .fc-help, per-node color-picker CSS, .fc-toolbar-row.
- src/flowchart/flowchart-shapes.js — shapeSvg() accepts an optional
6th 'color' arg; emits fill=... on rects and polygons. Falls back to
#ffffff for empty/null/undefined so old callers keep working.
- src/flowchart/flowchart-store.js — setNodeColor(id, color) mutator
with snapshot/emit, normalizeColor() helper (hex validation),
addNode accepts color, deserialize normalises missing color.
- src/renderer/flowchart-bundle.js — mirrors all of the above inline
(the bundle is loaded as a single <script>), wires fc-btn-save to
api.saveFile, passes node.color to shapeSvg in the canvas render,
and renders <input type='color'> per node row.
- src/main.js — new ipcMain.handle('save-text-file', ...) using a
system Save dialog (mirrors the ascii:save handler shape).
- src/preload.js — added 'save-text-file' to ALLOWED_SEND_CHANNELS
and a saveFile(content, defaultName) helper on the flowchart bridge.
Tests: 92/92 suites, 1165/1165 tests pass on this run
- +9 store tests (color defaults, setNodeColor, undo, hex validation,
round-trip, deserialize normalisation)
- +7 shapes tests (fill color on all 5 kinds, fallback to #ffffff)
- +6 controller tests (color picker wires setNodeColor, canvas rect
reflects color, Save to File calls api.saveFile with the fenced
Mermaid source and 'flowchart.mmd', cancel + error paths surface in
status)
Verification:
- npm run lint clean
- npm run format:check clean
- npm test 92/92 suites, 1165/1165 tests pass
Amit Haridas
- Remove untracked root-level flowchart-bundle.js (older v4.10.0 copy
that had drifted from src/renderer/flowchart-bundle.js; never loaded
by Electron, just repo noise).
- In src/renderer/flowchart-bundle.js, replace the runtime
concatenation "'place' + 'holder'" with the proper 'placeholder'
attribute at the two label-input call sites (node + edge) and
remove the now-stale comment explaining the hack. No functional
change.
- Bump version 4.11.0 -> 4.11.1 in package.json and README.md and add
the matching UPDATES.md entry.
Verification:
- npm run lint clean
- npm run format:check clean
- npm test 92/92 suites, 1143/1143 tests pass on this run
- PDFBatchOperations.test.js passes 21/21 in isolation
(the occasional failure seen in the v4.11.0 run was a parallel-test
file-IO race, not introduced by these changes)
Amit Haridas
Replaced the v4.10.0 floating selection toolbar (which relied on
SVG click hit-testing inside #canvas-host and was unreliable in the
user's Electron runtime) with a button-driven node-list panel
(#fc-nodelist) below the canvas. Every mutation now flows through
explicit controls: 5 Add Node buttons, per-node kind-select +
label-input + delete ×, per-edge kind-select + label-input + delete
×, and a Connect form (From/To selects + Edge button + Refresh).
The canvas is purely visual now: no more #fc-selection-toolbar, no
controller-level _selectedId/_selectedKind state, no keyboard
Delete/Backspace selection handler. Canvas click callbacks
(onNodeClick, onEdgeClick, onShapeMenu) are no-ops. The 5-shape /
3-edge-kind / label-input / delete-button surface is unchanged in
spirit — it just lives in the panel instead of floating over the
canvas.
Files:
- src/flowchart-generator.html: added #fc-nodelist between canvas and
preview (wrapped in new .fc-left column), removed fc-selection-toolbar,
bumped header hint.
- src/renderer/flowchart-bundle.js: removed SHAPE_BUTTONS/EDGE_BUTTONS,
setSelection, renderSelectionToolbar, appendLabelInput,
appendDeleteButton, the keyboard Delete handler, and the
controller-level selection state. Added rerenderNodeList +
shapeLabel/edgeLabel, wired all panel buttons (add-row, per-node
selects/inputs/deletes, per-edge selects/inputs/deletes, connect
form). Subscribe now calls rerenderNodeList instead of the old
renderSelectionToolbar.
- tests/flowchart-controller.test.js: replaced 6 v4.10.0 selection
toolbar tests with 11 v4.11.0 button-driven panel tests.
- package.json: 4.10.0 -> 4.11.0.
- README.md: version line bumped to v4.11.0.
- UPDATES.md: added v4.11.0 changelog entry.
Test summary: 92 suites, 1143 tests pass (was 1138 — +5 net).
Lint + prettier clean.
Amit Haridas
Even after the v4.9.9 inline-modal fix the user kept reporting 'no fix still'
because hidden right-click context menus and window.prompt calls remain
unreliable in Electron renderer contexts. This release ships a *visible*
floating selection toolbar inside the canvas panel so the primary
interactions are not hidden behind modals or context menus.
- New <div id="fc-selection-toolbar"> inside #canvas-host, hidden until a
node or edge is selected. Renders:
* 5 shape buttons (Process / Decision / Terminator / Subroutine /
Document) when a node is selected, calling store.setNodeKind on
click. The active shape is highlighted.
* 3 edge-kind buttons (Solid / Dotted / Thick) when an edge is
selected, calling store.setEdgeKind.
* An always-visible label input that mirrors the selected item's
label and writes back via store.setNodeLabel / store.setEdgeLabel
with a 100ms debounce.
* A red Delete button calling store.removeNode / store.disconnect.
- Selection state now tracked at the controller level (_selectedId +
_selectedKind) and exposed via window.FlowchartController so the
keyboard Delete/Backspace shortcut and the toolbar share one source
of truth.
- Console-log instrumentation on every canvas event (pointerdown with
altKey, pointerup with drag result, dblclick, contextmenu, selection
changes, and every bootstrap phase) so the user can open DevTools
(Ctrl+Shift+I) and verify Alt+drag and double-click actually fire.
- promptInline / confirmInline kept as advanced fallback for the
right-click 'change shape' path; the toolbar is now the primary
interaction surface.
- Preview-render pane now shows a static info card explaining that the
canvas on the left is the rendered chart (previously blank).
- 6 new tests in tests/flowchart-controller.test.js — toolbar hidden
by default, selecting a node populates shape buttons + label input +
Delete, clicking a shape button updates the kind, label input is
debounced, edge selection populates edge-kind buttons, Delete button
removes the selected node.
Total tests: 1127 passing (was 1121; +6 new). The 11 pre-existing
PDFOperations failures are unrelated to this change.
Electron renderer contexts return undefined from window.prompt/window.confirm,
so shape change, edge kind, edge label, and reset confirmation did nothing.
Bundle now ships promptInline/confirmInline (custom DOM overlay modals) and
uses them in onEdgeClick / onShapeMenu / reset handler. Exposed as
window.FlowchartModals for jsdom tests.
Amit Haridas
Each pure module's UMD wrapper assigned window.FlowchartXxx only in the else branch — when 'module' was undefined. But the renderer runs with nodeIntegration:true, so 'module' is always truthy and the else branch never ran. The standalone Flowchart Generator window then aborted with 'Flowchart pure modules not loaded'.
Fix: append 'if (typeof window !== undefined) window.FlowchartXxx = exported;' after the CommonJS branch in all 4 pure modules (store, shapes, mermaid, canvas). Both branches can run now; the legacy sidebar panel still loads them via require() and the renderer unconditionally exposes the global.
Regression guard: 4 new source-grep tests in tests/flowchart-controller.test.js assert each module's source contains the 'window.FlowchartXxx = exported' assignment.
Attribution: Amit Haridas
Five fix rounds (v4.9.1 → v4.9.5) couldn't make the sidebar flowchart
panel feel right — at 280 px sidebar with canvas + preview cramped to
~175 px each, plus the editor-container hide/show dance the
maximize/restore toggle required, the panel kept presenting as
cramped and unreliable at runtime. Strategy pivot: the flowchart
editor now lives in its own BrowserWindow, matching the ASCII Art
Generator pattern.
- src/flowchart-generator.html — new standalone HTML with header,
toolbar (Insert at Cursor / Reset), canvas host, and preview host.
Stylesheet hrefs are src/-relative (no ../). Forced light surface
via background/color !important rules — mirrors the v4.9.5 CSS fix.
- src/renderer/flowchart-controller.js — pure browser IIFE. Hydrates
from <userData>/flowchart-session.json once on mount, persists on
every mutation with 500 ms debounce. Insert at Cursor wraps the
generated Mermaid source in a fenced ```mermaid block and sends
it through the existing insert-content IPC.
- src/main.js — openFlowchartGenerator() launches the standalone
BrowserWindow (1100×720, contextIsolation:true, nodeIntegration:false).
Tools menu entry 'Flowchart Generator' with Cmd/Ctrl+Alt+F.
- src/preload.js — new window.electronAPI.flowchart.* namespace with
getUserDataPath/readFile/writeFile/insertAtCursor, reusing the
existing thin text-file IPC handlers.
- The four pure modules (flowchart-shapes.js, flowchart-mermaid.js,
flowchart-store.js, flowchart-canvas.js) gained a tiny UMD wrapper
so they work both as CommonJS (legacy sidebar) and as browser
globals (standalone window). No behavioural change to the 73
flowchart unit tests in tests/flowchart-*.test.js.
- src/renderer.js — sidebar registerPanel('flowchart', ...) and the
commandPalette entry are now commented out. Legacy panel file
(src/sidebar/flowchart-panel.js) preserved for rollback.
Tests:
- tests/flowchart-controller.test.js — 10 new tests covering
stylesheet paths (no ../ escape), bootstrap wiring
(getUserDataPath once, reads flowchart-session.json), hydration
from a saved session, Insert-at-Cursor fenced block format,
Reset (with and without confirm), and two regression tests that
src/renderer.js no longer has a live sidebar registration.
All 1122 tests pass; lint + format clean.
Amit Haridas
v4.9.4 shipped three interaction bugs in the Flow Chart panel that combined to make it look broken at runtime: (1) .flowchart-preview-render had no min-height, so the Mermaid SVG clipped to 0 when the sidebar flex column shrank; (2) the canvas + preview hosts inherited the body.theme-concreteinfo dark theme, producing dark-on-dark nodes; (3) .flowchart-node.selected only set a 2px stroke on the rect's existing dark fill, which was effectively invisible.
Fix: styles-sidebar.css adds min-height: 120px on .flowchart-preview-render; forces a light background on .flowchart-canvas-host / .flowchart-preview-host with !important so theme inheritance cannot override it; forces explicit white fills and dark strokes on .flowchart-node rect/polygon/text and .flowchart-edge so labels read against any background; selection now changes fill (#e3f0ff) AND bumps stroke-width to 3 on both nodes and edges. renderer.js renderFlowChartMermaid now always initializes Mermaid with theme: 'default' regardless of body class — keeps the Mermaid SVG light to match the CSS-forced canvas surface.
Three new CSS regression tests in tests/flowchart-panel.test.js read the shipped stylesheet and assert the three structural invariants (non-zero min-height on render target, !important light background on canvas+preview hosts, fill + stroke-width >= 3 on .flowchart-node.selected).
Tradeoff: the flowchart surface is now always light, diverging from body theme. Visibility of a working editor is the priority per user direction.
Amit Haridas
- Add opts.onNodeClick + surgical applySelectionHighlight() so node/edge clicks immediately paint .selected and mirror id into panel state (Delete/Backspace works on freshly-clicked node).
- Add Maximize/Restore button to flowchart toolbar: toggles .main-content.flowchart-takeover which hides .editor-container and lets the canvas + preview split the full window width instead of the 280px sidebar.
- destroy() clears the takeover class so the editor stays usable after leaving the panel.
- 8 new tests in tests/flowchart-panel.test.js for selection wiring and takeover.
Amit Haridas
The flowchart preview pane accumulated raw Mermaid source when the user
fired several addNode mutations within the 250ms debounce window —
mermaid.run({nodes:[div]}) is async, so the previous render's
<div class="mermaid"> (still carrying the source text) sat in
.flowchart-preview-render when the next render cleared the target. The
first render's eventual element.innerHTML=svg landed on a detached node,
but the visible preview pane had a stack of stale <div class="mermaid">
elements carrying the source.
Fixed by switching renderFlowChartMermaid (src/renderer.js) to
replaceChildren() and adding a per-target WeakSet in-flight tracker so
the new render always starts from a clean slate and the previous render's
eventual innerHTML=svg is harmless on a detached node.
Added a second regression test that fires 7 mutations inside the debounce
with a renderMermaid mock that mimics mermaid.run's async innerHTML=svg
closure.
Amit Haridas
- src/ascii-generator.html line 7: ../fonts.css -> fonts.css (src/-relative;
fixes silent stylesheet miss — same class as the v4.9.0->v4.9.1 script-tag fix)
- src/renderer/ascii-controller.js: wire all 3 mode tabs, 18 template
buttons, and the 3 box form fields. setMode() toggles .active on tabs
and matching .mode-section. Templates route through the orchestrator's
template:<id> font namespace. Box mode renders text with single/double/
rounded/bold/ascii borders via a pure renderBox() helper. All 11 T9
behaviours preserved.
- tests/ascii-controller.test.js: 6 tests covering stylesheet path,
pure box renderer, mode-tab switching, and template button wiring.
- package.json 4.9.1 -> 4.9.2; README + UPDATES updated.
Amit Haridas
The flowchart panel keyboard handler in src/sidebar/flowchart-panel.js only
handles Ctrl+Z, Ctrl+Shift+Z, Delete, and Backspace. There is no Insert-key
branch, so the README row documenting it was a lie. Remove the row until the
behaviour is actually implemented.
Amit Haridas
The rail button tooltip advertised the shortcut, but commandPalette.register
was missing for 'Toggle Sidebar: Flow Chart'. Wire it up next to the other
sidebar toggles (Explorer/Git/Outline) so the advertised shortcut works.
Amit Haridas
destroy() previously only called canvas.destroy(), leaking:
- the container keydown listener
- the insertBtn click listener
- the debouncedPreview setTimeout handle (could write to a detached <pre>)
- the debouncedPersist setTimeout handle (could writeFile after unmount)
- the store.subscribe listener (store kept a stale closure)
Also compute the persistence path once on mount instead of invoking
getUserDataPath() three times per panel lifecycle.
Inline debouncedPreview / debouncedPersist so their timer handles are
reachable from destroy(). Capture store.subscribe's unsubscribe.
destroy() order: clear timers, unsubscribe store, remove listeners,
then canvas.destroy().
Amit Haridas
Pure CommonJS orchestrator that unifies hand-coded fonts, figlet adapter,
and templates behind a single public API. Wired to main.js via ipcMain.handle.
Public API:
- generate({ text, font, options }) - resolves 'template:<name>' /
'figlet:<font>' / bare id, falls back to standard for unknown fonts.
- listFonts() - hand-coded first (17), then figlet, then templates (19).
- getFontMeta(id) - null for unknown id, full meta for hand-coded,
{ kind } for figlet/templates.
Amit Haridas
Per Task 3 of the 2026-09-14 ASCII art upgrade plan.
- New module: src/main/AsciiArt.templates.js exporting ASCII_TEMPLATES
(19 entries) and getTemplate(name) accessor (returns '' for unknown).
- New test: tests/main/ascii-art.templates.test.js with 19 per-template
snapshots + unknown-name + keys-match assertions (21 tests total).
- 17 templates verbatim from src/ascii-generator.html:596-626
(arrow-right, arrow-down, decision, process, flowchart, sequence,
network, hierarchy, header, note, warning, info, divider, separator,
banner, checklist + the brief's own TEMPLATE_NAMES order).
- 2 templates verbatim from src/renderer.js:6542-6697
(progress-bar, table-simple).
- 1 newly authored: arrow-up (completes the arrow triplet; does not
exist in either source).
Amit Haridas
Widen height bound to 3-12 so the spec-named figlet fonts fit:
- Isometric1, Isometric2, Isometric3, Isometric4 (h=11)
- Calvin S (h=3)
Previously these were substituted with height-compliant alternatives
(Small Isometric1, Banner3-D, Henry 3D, Small Poison, Modular). Restoring
the spec-named fonts preserves the product intent: 4 distinct isometric
projections and the calvin-and-hobbes-style Calvin S font.
Amit Haridas
Replace the page-reload IPC handling in the theme-changed listener with an
in-place toggle of the preloaded <link id="theme-*"> tags. The helper scans
for a matching link first and only mutates disabled states when one exists,
so an unknown id (or main-process miss) short-circuits and preserves the
currently active theme. body.className is always set to the requested id so
legacy selectors keep matching.
Add tests/theme-renderer-apply.test.js with three cases covering: switching
to a fresh theme, idempotent re-switch, and the unknown-id short-circuit.
The test's local helper mirrors the renderer implementation so future drift
is caught at test time.
Amit Haridas
Preload one disabled <link id="theme-<id>"> per registered theme
between the structural CSS block and the KaTeX link. The renderer
will toggle the disabled attribute on the active link when the theme
changes. The 12 new-theme CSS files (catppuccin-*, one-light,
tokyo-night-storm, synthwave-84, outrun, winter-is-coming-*, solarized-dark-hc,
spring-light) are created in the next task; until then those 12 links
are inert (disabled) and 404 is harmless.
Amit Haridas
Wires the three registry-layer modules into src/main.js:
- Require ThemeRegistry + buildThemeMenu + the bootstrap side-effect
module at the top of the file so the registry is populated before
the menu is built.
- Replace the 109-line hardcoded View → Theme submenu block with a
buildThemeMenu({ setTheme, getCurrentThemeId }) call — themes are
now driven entirely from ThemeRegistry.list() / categories().
- Harden setTheme() to validate the incoming id against the registry
and fall back to 'atomonelight' if the stored id no longer exists
(e.g. after a downgrade or theme rename), with a console.warn so the
fallback is observable.
Pure wiring — no new behaviour, no unrelated edits. All 79 test suites
/ 931 tests remain green; lint and prettier checks clean.
Amit Haridas
Adds src/main/themeMenuBuilder.js — a pure module that consumes
ThemeRegistry.list() + ThemeRegistry.categories() and the injected
setTheme/getCurrentThemeId callbacks to produce the View → Theme
submenu's MenuItemTemplate[] in the same shape as the previous
hardcoded block in src/main.js:1137-1245.
- Radio-style items with checked=true on the active theme id
- Grouped by category in registry order with separators between
non-empty categories
- No Electron / electron-store imports — keeps the module pure and
unit-testable under @jest-environment node
- Tests use jest.resetModules() + per-test require to avoid the
module-cache leakage the bootstrap test surfaced in T2
Amit Haridas
Registers all 37 editor themes at startup via ThemeRegistry.bootstrap.js.
Side-effect module: requiring it populates the registry from a static
THEMES array (25 existing menu themes refactored into the registry +
12 new: Catppuccin x4, one-light, tokyo-night-storm, synthwave-84,
outrun, winter-is-coming x2, solarized-dark-hc, spring-light).
Categories split: 13 light / 22 dark / 1 high-contrast / 1 seasonal
(spring-light per spec).
Snapshot test asserts exact id order, shape validity, and category
counts. Tests use jest.resetModules() + per-test requires so the
bootstrap module re-evaluates its registration loop each run.
Amit Haridas
- 8 exports: register/unregister/list/get/categories/lightThemes/darkThemes/clear
- kebab-case id validator; category whitelist (light/dark/high-contrast/seasonal)
- duplicate-id and shape errors with descriptive messages
- pure CommonJS, no IO, no Electron deps — T2 bootstrap will register all 37 themes
- 10 Jest tests covering register/unregister/get/categories/light+dark filters
- full suite: 77 suites, 924 tests passing; lint + Prettier clean
Amit Haridas