Commit Graph
347 Commits
Author SHA1 Message Date
amitwh 09d9f6bdd1 fix(window): renderer path off-by-one; use 'close' for state save
Two related bugs in src/main/window/index.js:

1. Renderer path was ../../dist/renderer/index.html which resolves to
   src/dist/renderer/index.html (one level too deep). Production builds
   load from <project>/dist/renderer/index.html. Fix: ../../..

   This was never caught because dev mode uses VITE_DEV_SERVER_URL and
   never touches the file path; only 'electron .' (no Vite) hits it.

2. win.on('closed', state.save) calls win.getBounds() on a destroyed
   BrowserWindow. The 'closed' event fires AFTER destruction, so
   getBounds() throws 'Object has been destroyed'. Use 'close' (fires
   before destruction) and guard with isDestroyed() as a belt-and-suspenders.

Both bugs surfaced when the user clicked File → Open. The renderer
loaded a missing HTML (blank body); the openFile handler then triggered
the closed-event state save which threw.
2026-06-06 22:42:54 +05:30
amitwh f36d918871 fix(menu): require('../main') → require('../index') after main.js→index.js rename
The menu items file was using require('../main') which resolved to a
non-existent src/main/main.js. After the 054ce23 refactor that renamed
main.js → index.js, every menu click tried to require a missing module.

All 65 occurrences fixed; fileItems() now loads cleanly at app startup
and the menu doesn't throw on construction.

Caught by user clicking File → Open: showOpenDialogSync emitted through
to the lazy require at items.js:52, which failed with module-not-found
before main process handlers ran.
2026-06-06 22:42:42 +05:30
amitwh ab16998922 feat(packaging): all-platform builds with GitHub Releases
Closes the gap from the previous handoff: `npm run dist:all` now
produces Linux .deb/AppImage/snap, Windows NSIS/portable/zip, and
macOS dmg/zip artifacts. `.github/workflows/release.yml` builds all
three on tag push (v*) and attaches the union to a GitHub Release.

Bug fix in the same commit (would have broken any packaged build):

* `build.files` was `["src/**/*", ...]` — shipped `src/renderer/`
  .tsx dev source into the asar. Replaced with a whitelist
  (`src/main/**/*`, `src/preload.js`, `src/plugins/**/*`,
  `package.json`) and moved the built renderer to
  `build.extraResources` (`dist/renderer` -> `renderer/`).

* `src/main/window/index.js` now uses `process.resourcesPath` when
  `app.isPackaged` is true, plus a friendly error if the renderer is
  missing. Verified by extracting the .AppImage and launching the
  binary — main process logs
  `Production mode — loading .../resources/renderer/index.html`.

New in `package.json` build config:

* `mac.target`: dmg + zip for x64 and arm64; `darkModeSupport: true`,
  `hardenedRuntime: false`, `gatekeeperAssess: false`,
  `entitlements: null`. `mac.identity: null` retained (unsigned).
* `publish`: GitHub Releases provider. CI overrides with
  `--publish=never`.

Known limitations (intentional follow-ups, not blockers):

* No `assets/icon.icns` — macOS app uses the default Electron icon.
  This box lacks `iconutil`/`png2icns`; generating a proper .icns is
  a one-line follow-up.
* No code signing — Windows SmartScreen will warn, macOS Gatekeeper
  will quarantine. `CSC_LINK_BASE64`/`CSC_KEY_PASSWORD` secrets are
  already wired in the Windows job for when the cert is added.
* No auto-update — user decision. The `publish` block writes the
  metadata that a future `electron-updater` integration will consume.

Verified on this Linux box:

* `npm run build:renderer` then `npm run build:linux` — produced
  AppImage (291M), deb (220M), snap (245M).
* `resources/app.asar` has 0 `src/renderer/*` entries (was the
  pre-fix bug). 44 .tsx files remain in asar — all from
  `node_modules/@hookform/resolvers` and `node_modules/immer` test
  fixtures, not our code.
* Extracted `squashfs-root/resources/renderer/index.html` exists and
  is what `window/index.js` loads.
* Binary runs for >12s without crashing — `loadFile` resolves
  `process.resourcesPath/renderer/index.html` correctly.

Tests: 306/306 pass. No regressions.

Plan doc: docs/plans/2026-06-06-packaging-all-platforms.md (the
task-by-task execution guide I followed; included for traceability).
2026-06-06 21:06:20 +05:30
amitwh 58ca3014d8 fix(modals): drop shadcn-style aria-describedby to silence Radix warning
Every DialogContent had aria-describedby="X-desc" and every
DialogDescription had a matching id="X-desc". That pattern is the
default shadcn/ui recipe, but it breaks Radix 1.1.x.

Root cause: Radix auto-generates a descriptionId via useId() (e.g. :r0:)
and stores it in the Dialog context. The DescriptionWarning effect does
`document.getElementById(descriptionId)` and warns if the element is
missing. When the description element's id is overridden to
"welcome-desc", the DOM has id="welcome-desc" but the context still has
:r0:, so the lookup misses and the warning fires on every dialog open.

Fix: drop both overrides. Let Radix manage the id and aria-describedby
itself. Screen-reader semantics are unchanged (Radix still wires
Content -> Description via the auto-generated id).

Touched: 12 modal files (11 DialogContent/DialogDescription pairs +
SettingsSheet which uses Sheet). +1 regression test in
WelcomeDialog.test.tsx that spies on console.warn and asserts the
"Missing Description" message is never emitted.

Tests: 306/306 pass (was 305).

Long-term memory: radix-aria-describedby-anti-pattern.md captures the
do-not-reintroduce rule for future agents.
2026-06-06 20:45:13 +05:30
amitwh 7c1a79c724 fix(app): add Vite dev workflow, fix onLayout prop, fix icon path, allow Google Fonts CSP
The v5.0.0 React UI redesign shipped without a working dev workflow —
`npm start` only ran `electron .` which loaded the source index.html
that references raw .tsx files. The browser couldn't execute them, so
the app rendered an empty #root and the user saw 'lot of errors'.

This commit restores a real dev workflow:

1. **Vite dev server wired into npm scripts** — added `concurrently`
   + `wait-on` as devDeps. `npm run dev` now runs Vite (port 5173)
   and Electron together with `wait-on tcp:5173` so Electron only
   starts after the dev server is ready.

2. **Main process loads Vite URL in dev, dist/ in prod** — window
   module now checks `process.env.VITE_DEV_SERVER_URL` and
   `app.isPackaged` to decide what to load. Production still
   loads the built `dist/renderer/index.html`.

3. **Fixed ReferenceError: app is not defined** — window module
   referenced `app.isPackaged` but only imported `BrowserWindow`.
   Added `app` to the destructured import.

4. **Fixed wrong icon path** — window creation used
   `../../assets/icon.png` from src/main/window/ which resolved
   to `src/assets/icon.png` (doesn't exist). Icon lives at
   project root, so path is now `../../../assets/icon.png`.

5. **Allowed Google Fonts in CSP** — the strict CSP
   (`font-src 'self' data:`, `connect-src 'self'`) blocked
   the preconnect/css link to fonts.googleapis.com / .gstatic.com.
   Added both domains so Plus Jakarta Sans loads.

6. **Renamed onLayout → onLayoutChange** in AppShell — react-resizable-panels
   v4 renamed the prop. The v1 name was being spread to a DOM
   div and React logged 'Unknown event handler property' warnings.
   Test mock updated for parity.

7. **show: false → show: true** — ready-to-show was hanging on
   this Wayland/container combo. Now the window is shown
   immediately on create.

Verified end-to-end:
- 305/305 vitest tests pass
- Vite dev server starts on :5173
- Electron loads localhost:5173 and React mounts
- Header 'MarkdownConverter' + sidebar with 'No files open' visible
- No onLayout warnings after HMR
- All blocked errors resolved
2026-06-06 16:17:16 +05:30
amitwh 8027d0b9b5 chore(release): bump version to 5.0.0 v5.0.0 2026-06-06 14:13:52 +05:30
amitwh c0988a0108 docs: add CHANGELOG.md (v5.0.0 entry, Keep a Changelog 1.1.0 format) 2026-06-06 14:12:27 +05:30
amitwh 18fc2317ae refactor: delete 17 legacy files (renderer.js, 8 stylesheets, 5 scripts, 2 htmls, src/index.html orphan, deprecated src/main.js) 2026-06-06 14:11:56 +05:30
amitwh 94dd62946a refactor(preload): remove 9 dead IPC channels (print-preview*, command-palette, open-*/show-* ascii/table) 2026-06-06 14:09:25 +05:30
amitwh 054ce2351a refactor(main): create src/main/{store,index}.js glue layer; new entrypoint at src/main/index.js 2026-06-06 14:08:13 +05:30
amitwh 6651dccfdf refactor(main): move WordTemplateExporter from src/wordTemplateExporter.js to src/main/word-template/ (preserved as single module) 2026-06-06 14:04:16 +05:30
amitwh 848102905e refactor(main): extract window creation to src/main/window/ (main only, ascii/table windows removed) 2026-06-06 14:03:12 +05:30
amitwh 6c7a86c99b refactor(main): extract menu to src/main/menu/ (remove dead print-preview/command-palette/ascii/table sends) 2026-06-06 14:00:29 +05:30
amitwh b46fa9abaa fix(main): remove duplicate list-directory handler from src/main/files/ (kept original in main.js) 2026-06-06 09:52:00 +05:30
amitwh 2a32e702f3 refactor(main): extract file ops to src/main/files/ (search, git, binary) 2026-06-06 09:43:31 +05:30
amitwh 356cfc5cc8 refactor(main): extract path helpers to src/main/utils/paths.js 2026-06-06 09:25:22 +05:30
amitwh a03144df5b docs(plan): Phase 10 polish + delete legacy — 10 tasks, main.js decomposition + 17 legacy file deletions + v5.0.0 2026-06-06 09:22:15 +05:30
amitwh 7fc11aed3b docs(spec): Phase 10 — fix index.html ambiguity (DELETE legacy root src/index.html, not rewrite; src/renderer/index.html is already live) 2026-06-06 09:16:02 +05:30
amitwh 095f77f5f1 docs(spec): Phase 10 polish + delete legacy design — main.js decomposition, file map, v5.0.0 2026-06-06 09:14:39 +05:30
amitwh 80afbb136b test(renderer): Phase 9 tools integration smoke test (6 commands) 2026-06-06 08:38:01 +05:30
amitwh 95bbe171b5 feat(renderer): GitStatusPanel sidebar tab + git.refresh event phase-9-advanced-tools 2026-06-06 08:28:37 +05:30
amitwh 2d77fa5456 feat(renderer): Breadcrumb shows heading symbols (settings toggleable) 2026-06-06 08:28:24 +05:30
amitwh fbaff37505 feat(renderer): Minimap (custom overview, wired to settings.minimap) 2026-06-06 08:20:48 +05:30
amitwh 1ccde4baa3 feat(renderer): Zen mode (Esc exits, hides chrome) 2026-06-06 08:13:38 +05:30
amitwh 8822c9a2f9 feat(renderer): PrintPreview overlay + App.tsx mount 2026-06-06 08:11:15 +05:30
amitwh 324e5676b8 feat(renderer): ReplPanel (markdown snippet preview) 2026-06-06 08:11:10 +05:30
amitwh a62511e7ed feat(renderer): FindInFilesDialog (cross-file search with regex) 2026-06-06 08:04:49 +05:30
amitwh a6c6e3696e feat(renderer): WordExportDialog (docx export with template picker) 2026-06-06 08:02:19 +05:30
amitwh 1b2ab437d1 feat(renderer): TableGeneratorDialog (markdown table generator) 2026-06-06 07:45:18 +05:30
amitwh efc7709f66 feat(renderer): AsciiGeneratorDialog (figlet text-to-ASCII-art) 2026-06-06 07:40:20 +05:30
amitwh a8f7547c7e feat(renderer): Phase 9 foundation — settings, modal union, ipc, commands, docx-export 2026-06-06 07:33:00 +05:30
amitwh 094b52a2b3 docs(spec): Phase 9 advanced tools design — 10 features across 3 mount strategies 2026-06-06 07:20:17 +05:30
amitwh 24c6675c82 fix(test): use mockRejectedValue for IPC error in ExportPdfDialog test phase-8-toasts 2026-06-05 23:17:57 +05:30
amitwh 929d72cf1d test(renderer): Phase 8 toasts integration smoke test 2026-06-05 23:12:26 +05:30
amitwh b40bff641c feat(renderer): export dialogs toast on success/failure 2026-06-05 23:05:32 +05:30
amitwh 338669f2db feat(renderer): file-store toasts on save/open/folder 2026-06-05 22:59:54 +05:30
amitwh 54615649f4 feat(renderer): mount Toaster in App.tsx 2026-06-05 22:52:04 +05:30
amitwh 3ff76c8c33 feat(renderer): add shadcn Toaster primitive 2026-06-05 22:50:07 +05:30
amitwh 8160ac05e0 feat(renderer): lib/toast.ts typed wrappers over sonner 2026-06-05 22:46:45 +05:30
amitwh 6762b5f9af docs(spec): Phase 8 toasts design — typed helpers, Toaster mount, 4 wire points 2026-06-05 22:41:28 +05:30
amitwh 00485d1bef feat(renderer): implement numeric right-alignment in ascii-table
Adds the actual right-alignment heuristic to toAsciiTable (was missing
from initial implementation). When any column header starts with a digit,
all columns are right-padded instead of left-padded. Matches the test
added in 53870d5 which exercises the right-alignment path with header
['Item', '7'].

All 6 ascii-table tests pass.
2026-06-05 22:18:15 +05:30
amitwh 24bb9aa9f5 test(renderer): Phase 7 modals integration smoke test phase-7-modals 2026-06-05 19:54:35 +05:30
amitwh b39bdcf475 feat(renderer): mount ModalLayer + first-launch welcome trigger 2026-06-05 19:48:37 +05:30
amitwh 9d154a8521 feat(renderer): AppHeader gets Settings + About icon buttons 2026-06-05 19:46:56 +05:30
amitwh fe62c8814c feat(renderer): register 9 modal-opening commands in command store 2026-06-05 19:44:13 +05:30
amitwh 9306a9c23b feat(renderer): SettingsSheet (5 tabs: editor, theme, export, plugins, about) 2026-06-05 19:41:18 +05:30
amitwh 88e26c130e feat(renderer): AboutSettings tab (version + links) 2026-06-05 19:39:01 +05:30
amitwh b02707ac7f feat(renderer): PluginsSettings tab placeholder (Coming soon) 2026-06-05 19:37:54 +05:30
amitwh ebc149ff0b feat(renderer): ExportSettings tab (PDF/DOCX/HTML defaults + ascii toggle) 2026-06-05 19:35:28 +05:30
amitwh be3af42fc5 feat(renderer): ThemeSettings tab (mode, accent, font) 2026-06-05 19:32:43 +05:30