sync: upstream genoffice 7023e63 (dark/light theme, engine fixes, markdown app) - #50
Conversation
* feat(shell): add light/dark/system theme support Add a theme toggle to the account menu with three options: - Light: explicit light theme - Dark: explicit dark theme - System: follows OS prefers-color-scheme Changes: - Add UiTheme type and getTheme/setTheme IPC to home-api - Add theme persistence in app-settings.json - Add theme IPC handlers in main process and preload bridge - Add Theme row + flyout in AccountEntry (same UX as Language) - Apply data-theme attribute before first paint to avoid flash - Add dark mode CSS variables for all shell surfaces - Add dark mode overrides for 40+ hardcoded color selectors - Add dark mode treatment for onboarding modal - Add theme i18n strings in all 19 languages The theme toggle lives in the account popup menu between Language and Update Channel, using the same flyout pattern. * perf(shell): cache settings reads + consolidate CSS dark mode + fix button hover Performance improvements: #7: Cache settings reads - Add cachedUpdateChannel/cachedTheme module-level variables - currentUpdateChannel() and currentTheme() now cache like currentLang() - set handlers update the cache on write - Eliminates disk reads on every IPC call #11: Consolidate CSS dark mode selectors - Convert 20+ hardcoded colors to CSS custom properties - Remove ~300 lines of duplicated element-level dark mode overrides - All element rules now use variables, auto-switch via :root overrides - Single source of truth for dark mode palette #17: Replace filter+transform on button hover - Replace filter: brightness() with opacity transitions - Add specific hover states for btn-secondary and btn-danger - Avoids GPU compositing overhead from filter property --------- Co-authored-by: alfirus <alfirus@users.noreply.github.com>
- New AI Markdown app - the fifth suite app, with local image assets and ribbon AI entry points - Shell: dark/light/system theme (imports public PR #41) with lint fix and dark-mode onboarding polish - Docs: Word rendering fidelity fixes, 4x faster repagination, Shape Format contextual tab, auto-refreshing TOC page numbers - Slides: built-in standard layouts, anchored zoom and jump-free editing, selectable Draw pen thickness - Sheets: Insert Equation/Checkbox/Timeline, editing polish with undo for manual inserts and localized save errors - Bump pdfjs-dist to 6.2.108 and js-yaml to 4.3.1 Co-authored-by: GenOffice <merrick-2002@users.noreply.github.com>
Saving a workbook on Windows failed with "error invoking remote method
'workbook:save': EPERM: operation not permitted" — the save dialog appeared,
then the save threw regardless of the chosen directory.
promoteFileAtomically (and writeXlsxAtomically) opened the freshly written
temp file read-only ('r') and then called handle.sync(). On Windows,
FlushFileBuffers requires a writable handle, so fsync on a read-only handle
fails with "EPERM: operation not permitted, fsync" — before the rename that
promotes the temp file over the target ever runs.
Open the handle read-write ('r+') at both sites.
Reproduced and verified fixed on Windows 11 Pro: with 'r' the save fails on
fsync with EPERM; with 'r+' the sync and the rename over an existing file
both succeed and the workbook saves.
The two XMLParser instances in file-parse ran with fast-xml-parser's defaults, so element text was numerically coerced and trimmed before it reached the model: <t>02139</t> read as 2139, and the space carried by an xml:space="preserve" run was dropped, so a bolded word in a slide turned "Quarterly revenue grew 12% in Q3" into "Quarterlyrevenuegrew12%inQ3". Set trimValues and parseTagValue to false on both, matching docx-engine's xml-utils and pptx-engine's parse. trimValues is per parser rather than per element, so two readers that were relying on it change with it: the xlsx parser keeps collapsing attribute whitespace, since r:id, Target and the cell ref are structural and a padded Target otherwise drops a whole sheet, and collectText now pushes a primitive only when it came from an a:t, so an <a:br> written across lines no longer leaks into the paragraph.
…y notices (#52) SRC_GLOBS hardcodes five app source trees and enumerates packages/* dynamically, so apps/markdown was never scanned. The app ships: shell's electron-builder config copies ../markdown/out into every installer, and npm run notices is a prerequisite of dist:mac, dist:win and dist:linux. So the notices file that ships as extraResources omits the licenses of everything only markdown imports. Scanning it alone is not enough. markdown pins @tiptap 3.29.2 while docs takes ^3.28.0, so npm keeps markdown's copies under its own workspace, and starter-kit's own extensions land under a scoped package. pkgDir looked in neither: it iterated the entries of the root node_modules, which for a scoped package is the scope directory rather than the package, and never looked at workspace roots. Adds both lookups, unscoped owners first so packages that already resolved keep resolving to the same copy. Net effect on the generated file: 29 npm packages added, none removed, no version changed, and the "not installed, skipped" warning is now empty.
The markdown app shipped in the 2026-08-07 snapshot and the docs never followed it. README's intro and CONTRIBUTING's layout section still count five apps, README still says the shell hosts four editors and that npm run dev starts four, SECURITY.md's renderer-lockdown list names every window class except markdown (whose windows do set the same three flags), and neither issue template offers Markdown even though both dropdowns are required and the installer registers .md and .markdown associations. Separately, .nvmrc pinned 20 and CONTRIBUTING said Node 20+, while package.json engines requires >=22.12.0 and all three workflows run node-version: 22, so following the checked-in version gives an install npm rejects and a toolchain that does not match CI. README's Apps table also has no row for markdown. That one needs product wording rather than a count, so it is left for a maintainer.
… (#63) comments.xml and footnotes/endnotes.xml are rebuilt by splicing unchanged entries back in as their original bytes, then wrapping them in a root with a hardcoded namespace list. The bytes and the root disagree: w:comments declares w and w14, so a preserved comment holding <w:hyperlink r:id="..."> leaves r unbound NOTE_NS declares w and r, so a preserved paragraph holding w14:paraId, which Word writes on every paragraph, leaves w14 unbound Both parse clean with fast-xml-parser's validator, which is not namespace aware, and fail a namespace-aware parse with "unbound prefix". Word reports that as unreadable content, so adding one comment to a document with a linked comment, or one footnote to any Word-authored document, is enough. Reuse the original part's root attributes when there is an original, keeping the literal list only for parts created from scratch. The regression test checks prefixes are bound rather than calling the XML validator, which cannot see this class of defect.
The rich header/footer writer hand-builds its paragraph properties and emits only w:jc, so editing an RTL header drops w:bidi entirely. It also writes the alignment back unswapped: parse.ts converts Word's logical w:jc to a visual direction on read for bidi paragraphs, so para.align holds the visual value, and writing it straight out turns right into left. Both faults together: before <w:pPr><w:bidi/><w:jc w:val="right"/></w:pPr> after <w:pPr><w:jc w:val="left"/></w:pPr> The header looks right in the app and is wrong the moment Word reopens it: an Arabic header carrying a Latin or numeric run loses its paragraph direction, so the neutral characters around it resolve to the other end of the line. Build the properties with mergePPrFormat instead, so the bidi swap lives in one place rather than two. Spacing, indent, borders and tab stops in headers come along for free. That makes this the first caller of mergePPrFormat outside the tests, and its fresh-build branch, the one '<w:pPr/>' takes, joined the model's children in emission order. Every other path sorts: generateParagraphXml sorts its own children by PPR_CHILD_ORDER, and so does the interleaving branch of mergePPrFormat itself. Over every combination of the fourteen ParaFormat fields formatPPrChildren reads, 8168 of 16384 came out in the wrong CT_PPr order, the smallest being align plus tabStops emitting w:jc before w:tabs. Wrong CT_PPr order is what makes Word show the repair dialog, which schema-order.test.ts already exists to prevent; its cases just never reached the self-closing branch. Sorted there too, and extended that test to cover it.
- PDF: in-place text editing — paragraph block selection with reflow, bold/italic and alignment controls, selection-level text color, original-font preservation - PDF: AI image tools (search/generate, insert, transform, delete) plus image rotation and in-place replacement - Docs: picture rotation and mirror flips, in-place image byte swap for crop/background removal, and several Word-fidelity rendering fixes - Docs: fix a renderer hang on tab-heavy forms and a crash when exporting large documents - Slides: AI picture tools (crop, opacity, replace), picture border controls, in-place picture source swap - Linux: AppImage and deb packaging with stable/beta auto-update channels - Refresh the README and clean up internal design-audit artifacts Co-authored-by: GenOffice <merrick-2002@users.noreply.github.com>
- Update the README download links to the unified v0.6.13 release Co-authored-by: GenOffice <merrick-2002@users.noreply.github.com>
- Remove internal Linux release and stable-promotion pipeline files from the public repo (they require internal publish secrets and fail on public main) Co-authored-by: GenOffice <merrick-2002@users.noreply.github.com>
- Improve DOCX rendering fidelity, pagination, image handling, and Markdown paste - Expand PDF text editing with paragraph reflow, style preservation, and more reliable text matching - Harden XLSX sheet deletion, localized date formats, multi-row autofit, charts, and system font support - Add inline AI turn rollback and sent-attachment visibility across editors - Add Office-style ScreenTips and refine ribbons, dialogs, menus, and themes - Improve Slides cropping, rotate and flip tools, printing, animations, and editing workflows - Add shell settings, configurable save locations, account credits, and update recovery guidance - Add Intel macOS and RPM download support and refresh public documentation Co-authored-by: GenOffice <merrick-2002@users.noreply.github.com>
…rkdown app Merge of 17 upstream commits (snapshots through 2026-08-10): - feat(shell): dark/light/system theme + performance optimizations (SettingsModal, UiTheme, configurable default save dir) - fix(engines): docx header/footer RTL + root namespaces + nil border guard; sheets alignment attributes + Save As without edits + Windows fsync; file-parse pptx line breaks/attachments verbatim; pptx picture replacement - feat(apps): new Markdown editor app (electron-vite workspace) - feat(pdf): image edit mode (pdfium wasm, page previews, text rebuild fonts) Fork layer re-applied over upstream: Hermes gateway account status + share bridge + cloud sync (shell), Hermes AI capabilities in pdf/slides (filePath, webSearch, edit-state rollback, watermark/header-footer, notes, page moves), provider 'hermes' defaults, branding (HermesMark, HermesOffice save dir), updater onOpenDownload, and @hermesoffice scoped renames across all workspaces. Rebrand check clean; 4426 tests pass.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8e72b9333b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| }, | ||
| } | ||
|
|
||
| contextBridge.exposeInMainWorld('aiOfficeCloud', cloudApi) | ||
| contextBridge.exposeInMainWorld('aiOfficeTabs', tabsApi) |
There was a problem hiding this comment.
Restore the cloud preload bridge
Restore aiOfficeCloud in addition to exposing aiOfficeTabs. The Home screen always mounts CloudSyncEntry, whose effect immediately calls window.aiOfficeCloud.getAuthState(), getStates(), and getConfig() (Home.tsx:169-174); after this preload change, that global is never defined, so opening the Home tab throws at runtime and the cloud-sync UI cannot initialize.
Useful? React with 👍 / 👎.
| @@ -1867,6 +1715,7 @@ body.vib .home { | |||
| transform: rotate(360deg); | |||
| } | |||
| } | |||
| <<<<<<< HEAD | |||
There was a problem hiding this comment.
Resolve the Home stylesheet conflict
Remove the merge markers and retain both intended CSS sections. Browsers parse the marker-prefixed .cloud-panel rule as an invalid selector, and the later ======= marker similarly encloses and discards the new prefers-reduced-motion block, so the cloud panel loses its container spacing and the advertised motion-accessibility behavior never applies.
Useful? React with 👍 / 👎.
| @@ -321,6 +322,7 @@ | |||
| outline-offset: 2px; | |||
| } | |||
|
|
|||
| <<<<<<< HEAD | |||
There was a problem hiding this comment.
Resolve the onboarding stylesheet conflict
Remove these merge markers while preserving both the Hermes slide styles and the dark-mode overrides. The initial marker invalidates the .onb-hermes rule, while the =======/>>>>>>> section causes the browser to discard the explicit and system dark-theme rules, leaving the onboarding card styled with light-theme colors when dark mode is selected.
Useful? React with 👍 / 👎.
home.css/onboarding.css still carried orphaned upstream/main conflict markers (the earlier grep only covered ts/json extensions) and the union dropped two closing braces. Fixed both, then ran prettier over the 7 files CI's format:check flagged against the merge base.
The upstream theme commit introduced raw colors in onboarding.css and tabbar.css dark overrides; CI's check-theme-colors (diff vs merge base) flags them as new. Move the raw values into custom properties on the theme override blocks and reference them via var().
The upstream merge dropped 99 @rollup/@esbuild/@swc/napi platform entries from package-lock.json (only host-arch darwin-arm64 survived), so the CI linux runner failed with 'Cannot find module @rollup/rollup-linux-x64-gnu' (npm optional-deps bug). Restored the missing entries from the upstream lockfile; npm ci dry-run validates.
The rebuilt registerHomeIpc registered 'home:account-status' twice, which made the E2E shell test fail with 'Attempted to register a second handler' on every launch. Keep the single fork gateway-health handler.
The upstream shell preload dropped the fork's cloudApi bridge; Home.tsx calls window.aiOfficeCloud.getAuthState() on mount, so the renderer crashed with 'Cannot read properties of undefined (reading getAuthState')' and every E2E spec failed to find .home-hero. Restored the CLOUD_CHANNELS import and the aiOfficeCloud contextBridge exposure.
Sync do upstream GenOffice (17 commits, snapshots ate 2026-08-10).
Destaques do upstream
Camada Hermes re-aplicada
Validacao