Skip to content

SpreadSheet Editor Dark Mode (dark document) 🌘 β€” companion to sdkjs PR - #187

Open
j-base64 wants to merge 11 commits into
mainfrom
fix/117-dark-theme-canvas-background
Open

SpreadSheet Editor Dark Mode (dark document) 🌘 β€” companion to sdkjs PR#187
j-base64 wants to merge 11 commits into
mainfrom
fix/117-dark-theme-canvas-background

Conversation

@j-base64

@j-base64 j-base64 commented Aug 3, 2026

Copy link
Copy Markdown

Origin

Issue #117 pinpoints the lack of dark mode in the spreadsheet editor, unlike the document editor, which already has one.

Originally noticed on web-apps, the fix requires changes to both sdkjs and web-apps, plus optionally DocumentServer for e2e smoke tests.

Approach

This PR brings dark mode (dark document feature) to the spreadsheet editor with a simple starting approach, rather than full negative-inversion or full token-based re-theming:

SSE-DarkMode_ScreenCapture_300729.mp4

What this dark mode DOES βœ…

  • Define & Apply a dark mode colorset to background, text, and border color of cells left on automatic colorsΒΉ
  • Honors print/print preview with an always light theme
  • Sets automatic text to white on cells with an explicit dark background (see Design Notes)
  • Handles:
    • Partially colored text
    • Merged and conditionally-formatted cells
    • Search-highlighted cells
    • Row/column guide color when resizing

Design notes 🌈

  • To maximise compatibility of designed cells in light mode, the automatic text color of cells with an explicit background is computed the same way as in light mode. This led to a design choice: flip automatic text from black to white on darkened cells, so a user isn't surprised to set a black background on a cell and find its text invisible. However, users can override text color with an explicit color. Try it and see.
  • In the future, it probably makes sense to simplify by merging the dark theme and dark document features into one sun/moon-style switch, like many modern products do.

What this dark mode DOESN'T DO ❌

  • Affect inserted elements like images, shapes, charts
  • Fix certain table templates that use transparent instead of white to draw "white" rows
  • Rely on inverting colors of the document (negative method) or the UI color palette
  • Ship on mobile

Known tradeoffs

  • Equations are not supported yet (remains black), should be fixed on an update
  • A cell being actively edited keeps its previous theme's colors until you click away. Prototyped a fix, reverted it, not worth the complexity for a small, self-correcting gap.

ΒΉ Automatic color = different from explicit color (those explicitly set by the user or a table style template)

Basic manual testing

  1. Create content and colorisations on a sheet
    • Type text in a few cells, set an explicit/custom text color on a whole cell, and on just some words or letters within another cell.
    • Add a border to two cells, set explicit/custom border color for one of the cells.
    • Add a predesigned table 5 cols x 5 rows.
  2. Under View tab > Make sure the interface theme is Dark.
  3. Switch Dark Document button to see differences.
  4. In dark mode
    • Search for some text.
    • Resize a column or row. The drag guide should be visible against the dark background.
    • Open Print Preview.

Automated testing

  • Proposed on DocumentServer see below, 13 smoke tests covering cell fill/border/text correction, merged cells, page-break-preview, gradient/pattern fill in the cell editor, print-preview, column-resize guide color, search-highlight contrast, mid-edit-toggle behavior, interface-theme interaction, and toolbar sync

Code

This PR spans BOTH sdkjs, web-apps, and optionally DocumentServer:

AI assistance

  • Developed with AI assistance (Claude Code, mainly claude-sonnet-5)
🌘 First PRs in the project, feedback and reviews welcome :)

j-base64 added 11 commits August 3, 2026 19:15
Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
…sdkjs commit too

Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
…ark-mode correction)

Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
Clean up dark-mode toggle debounce comment in ViewTab.js

Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
…theme switches

Signed-off-by: j-base64 <jcentenero@arsys.es>
Assisted-by: ClaudeCode:claude-sonnet-5
@MonaAghili

Copy link
Copy Markdown

Review: SpreadSheet Editor Dark Mode (web-apps portion)

Must fix

1. [High] Missing lostConnect/disableOnStart locks on btnDarkDocument
πŸ“ apps/spreadsheeteditor/main/app/view/ViewTab.js:391-401
Button is created with lock: [_set.inLightTheme] only. documenteditor's equivalent button uses lock: [_set.inLightTheme, _set.lostConnect, _set.disableOnStart]. Because Common.Utils.lockControls (apps/common/main/lib/util/utils.js:1101) only locks a control for a cause present in its own options.lock, this button stays clickable before the document/API is ready and after a lost collaborative connection β€” unlike every sibling toolbar control.
Fix: lock: [_set.inLightTheme, _set.lostConnect, _set.disableOnStart]

2. [Medium] Triplicated lockControls(inLightTheme, ...) calls + unnecessary setTimeout(0)
πŸ“ apps/spreadsheeteditor/main/app/controller/ViewTab.js:298-301 (controller), apps/spreadsheeteditor/main/app/view/ViewTab.js:636-645 (view)
The identical lock-update call fires three times per theme switch: inline in the menu item:click handler, again inside a setTimeout(fn, 0), and again in the controller's onThemeChanged β€” which already runs synchronously via the uitheme:changed notification chain triggered by setTheme(). The two calls in the view are dead weight; the setTimeout(0) looks like an uncertainty patch rather than a fix for a real async gap (notifications in this codebase fire synchronously).
Fix: delete both calls from the item:click handler in the view; rely solely on onThemeChanged.

Worth a comment, not blocking

3. [Low] Shared Themes.js behavior change affects all editors
πŸ“ apps/common/main/lib/controller/Themes.js:406-410
New Common.NotificationCenter.trigger('contenttheme:dark', false) on the "leave dark UI theme" branch is in the shared controller, not spreadsheet-specific code. Looks correct and likely also fixes a latent bug in documenteditor, but worth confirming it was manually verified there too, since it's outside this PR's stated scope.

4. [Low] Duplicated onChangeDarkMode/debounce logic across editors
πŸ“ apps/spreadsheeteditor/main/app/controller/ViewTab.js:76-91 (controller) vs apps/documenteditor/main/app/controller/ViewTab.js:414-427
Copy-pasted verbatim, including the stale // TODO: look if is not a better solution comment on the 500ms debounce. Not a blocker, but worth a follow-up issue to lift into a shared base rather than letting a third editor copy it again later.

5. [Low, out of scope] Duplicate id="btn-dark-mode" in common/main/icons.svg
Already present twice on main before this PR (from deploy-sprites.js concatenating each editor's same-named icon file); this PR adds a third occurrence. Pre-existing structural risk in the sprite-generation script's id scheme (bare filename as id, no per-editor namespacing) β€” flag as a separate build-tooling issue, not something to fix in this PR.

Missing test coverage

  • Lock/enable state of btnDarkDocument across lostConnect and pre-document-load (disableOnStart) β€” would have caught fix: use env variable for versionΒ #1.
  • inLightTheme lock actually disabling the button outside dark UI theme.
  • Rapid double-toggle within the 500ms debounce window.

Summary

  • Overall code quality: 6/10
  • Merge readiness: Needs minor changes
  • Positives: correctly reuses the shared Common.UI.Themes controller instead of inventing spreadsheet-specific theming logic; icon assets added consistently in both required sprite locations; defensive asc_setContentDarkMode existence checks in Themes.js are a good, minimal cross-app safety fix; unusually thorough PR description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants