Freehand drawing: add black swatch + sync first swatch with active theme #122

Open
opened 2026-04-30 12:03:22 +00:00 by AhmedHanafy725 · 2 comments
Member

Summary

Two small improvements to the freehand drawing sub-toolbar:

  1. Add a black swatch to the stroke-color row. Today the row offers light gray, white, blue, green, yellow, red, purple, pink — black is missing.
  2. Make the first swatch theme-aware. Today the first swatch is hard-coded to light gray (#dee2e6), which makes it a poor "default" on the Light or Minimal themes (the stroke is barely visible against the canvas). It should match the active theme's draw-stroke token: #dee2e6 for Dark, #0f172a for Light, #64ffda for Ocean, #f59e0b for Warm, #374151 for Minimal — and update live when the user switches themes.

Why

Black is a common request and missing for no good reason. The first swatch is the implicit default when the user opens the freehand tool fresh, so it should produce visible strokes regardless of which theme the board is on.

Files involved

  • crates/hero_whiteboard_ui/templates/web/board.html — add the black button to #draw-colors, tag the first swatch with data-theme-default so JS can keep it in sync.
  • crates/hero_whiteboard_ui/static/web/js/whiteboard/toolbar.js — add refreshDrawDefault() that reads WhiteboardThemes.get('draw-stroke') and updates the tagged swatch (color, background, and the active draw color if that swatch is selected). Call it from init().
  • crates/hero_whiteboard_ui/static/web/js/whiteboard/themes.js — call WhiteboardToolbar.refreshDrawDefault() from applyTheme so theme switches re-sync the swatch.
## Summary Two small improvements to the freehand drawing sub-toolbar: 1. **Add a black swatch** to the stroke-color row. Today the row offers light gray, white, blue, green, yellow, red, purple, pink — black is missing. 2. **Make the first swatch theme-aware.** Today the first swatch is hard-coded to light gray (`#dee2e6`), which makes it a poor "default" on the Light or Minimal themes (the stroke is barely visible against the canvas). It should match the active theme's `draw-stroke` token: `#dee2e6` for Dark, `#0f172a` for Light, `#64ffda` for Ocean, `#f59e0b` for Warm, `#374151` for Minimal — and update live when the user switches themes. ## Why Black is a common request and missing for no good reason. The first swatch is the implicit default when the user opens the freehand tool fresh, so it should produce visible strokes regardless of which theme the board is on. ## Files involved - `crates/hero_whiteboard_ui/templates/web/board.html` — add the black button to `#draw-colors`, tag the first swatch with `data-theme-default` so JS can keep it in sync. - `crates/hero_whiteboard_ui/static/web/js/whiteboard/toolbar.js` — add `refreshDrawDefault()` that reads `WhiteboardThemes.get('draw-stroke')` and updates the tagged swatch (color, background, and the active draw color if that swatch is selected). Call it from `init()`. - `crates/hero_whiteboard_ui/static/web/js/whiteboard/themes.js` — call `WhiteboardToolbar.refreshDrawDefault()` from `applyTheme` so theme switches re-sync the swatch.
Author
Member

Implementation Spec for Issue #122

Objective

Add black to the freehand drawing palette and make the leftmost (default) swatch automatically match the active theme's draw-stroke token, updating live when the user switches themes.

Files to Modify

  • crates/hero_whiteboard_ui/templates/web/board.html — add a black <button> in #draw-colors, tag the first swatch with data-theme-default.
  • crates/hero_whiteboard_ui/static/web/js/whiteboard/toolbar.js — new refreshDrawDefault() function that reads WhiteboardThemes.get('draw-stroke') and updates the tagged swatch in place; expose on the public API; call from init().
  • crates/hero_whiteboard_ui/static/web/js/whiteboard/themes.js — invoke WhiteboardToolbar.refreshDrawDefault() from applyTheme so the swatch tracks theme changes.

Implementation Plan

Step 1: Markup — black swatch + theme-default attribute

File: crates/hero_whiteboard_ui/templates/web/board.html

Inside <div class="subtoolbar-colors" id="draw-colors">:

  • Tag the existing first swatch:
    <button class="sub-color active" data-theme-default ... title="Theme default">
  • Insert a black swatch right after the white one (so the row reads light gray (default) → white → black → blue → ...):
    <button class="sub-color" data-color="#000000" style="background:#000000;" title="Black"></button>

The title="Theme default" (or "Default") is a small UX nudge; the swatch's actual rendered color follows the theme.

Dependencies: none.

Step 2: JS — refreshDrawDefault helper

File: crates/hero_whiteboard_ui/static/web/js/whiteboard/toolbar.js

Add to the IIFE:

function refreshDrawDefault() {
    var btn = document.querySelector('#draw-colors .sub-color[data-theme-default]');
    if (!btn) return;
    var stroke = (typeof WhiteboardThemes !== 'undefined' && WhiteboardThemes.get)
        ? WhiteboardThemes.get('draw-stroke')
        : '#dee2e6';
    btn.setAttribute('data-color', stroke);
    btn.style.background = stroke;
    if (btn.classList.contains('active') && typeof WhiteboardTools !== 'undefined' && WhiteboardTools.setDrawColor) {
        WhiteboardTools.setDrawColor(stroke);
    }
}

Call refreshDrawDefault() once at the end of init() so the swatch picks up the current theme's draw-stroke even if the user never switches themes.

Expose refreshDrawDefault on the returned API object.

Dependencies: none. Safe-guarded against WhiteboardThemes being undefined (the script load order means it'll always be defined when init() runs, but defensive is cheap).

Step 3: themes.js — invoke the toolbar refresh

File: crates/hero_whiteboard_ui/static/web/js/whiteboard/themes.js

In applyTheme, after the existing redraw loop and WhiteboardConnectors.applyTheme() call, add:

if (typeof WhiteboardToolbar !== 'undefined' && WhiteboardToolbar.refreshDrawDefault) {
    WhiteboardToolbar.refreshDrawDefault();
}

Dependencies: Step 2.

Acceptance Criteria

  • Open the freehand drawing tool — black appears in the row of color swatches.
  • On a fresh Light board, the first swatch renders dark (the theme's draw-stroke is #0f172a); strokes are visible against the white canvas.
  • Switch to Dark — the first swatch becomes #dee2e6 (light gray), matching the previous default. Existing strokes already on the canvas keep their persisted colors.
  • Switch to Ocean / Warm / Minimal — the first swatch updates to the theme's draw-stroke. If that swatch was the active selection, the live WhiteboardTools.drawColor updates too.
  • Picking any non-default swatch (including black) sets and keeps that color regardless of theme switches.
  • cargo fmt, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace --lib clean.

Notes

  • Why data-theme-default instead of an id: it's a single dedicated swatch today, but the same pattern is reusable for other tool palettes later (e.g. shape stroke, sticky default) — the attribute is a generic marker.
  • WhiteboardTools.drawColor only updates when the theme-default swatch is active. If the user has picked a non-default color, theme switches don't surprise them by changing what they draw with — they only change the default swatch's appearance.
  • Existing strokes are not retroactively recolored. Persisted user-drawn strokes keep their saved color across theme switches; this matches the pattern from #116 (existing stickies/shapes also keep their colors).
## Implementation Spec for Issue #122 ### Objective Add black to the freehand drawing palette and make the leftmost (default) swatch automatically match the active theme's `draw-stroke` token, updating live when the user switches themes. ### Files to Modify - `crates/hero_whiteboard_ui/templates/web/board.html` — add a black `<button>` in `#draw-colors`, tag the first swatch with `data-theme-default`. - `crates/hero_whiteboard_ui/static/web/js/whiteboard/toolbar.js` — new `refreshDrawDefault()` function that reads `WhiteboardThemes.get('draw-stroke')` and updates the tagged swatch in place; expose on the public API; call from `init()`. - `crates/hero_whiteboard_ui/static/web/js/whiteboard/themes.js` — invoke `WhiteboardToolbar.refreshDrawDefault()` from `applyTheme` so the swatch tracks theme changes. ### Implementation Plan #### Step 1: Markup — black swatch + theme-default attribute File: `crates/hero_whiteboard_ui/templates/web/board.html` Inside `<div class="subtoolbar-colors" id="draw-colors">`: - Tag the existing first swatch: `<button class="sub-color active" data-theme-default ... title="Theme default">` - Insert a black swatch right after the white one (so the row reads light gray (default) → white → black → blue → ...): `<button class="sub-color" data-color="#000000" style="background:#000000;" title="Black"></button>` The `title="Theme default"` (or "Default") is a small UX nudge; the swatch's actual rendered color follows the theme. Dependencies: none. #### Step 2: JS — refreshDrawDefault helper File: `crates/hero_whiteboard_ui/static/web/js/whiteboard/toolbar.js` Add to the IIFE: ```js function refreshDrawDefault() { var btn = document.querySelector('#draw-colors .sub-color[data-theme-default]'); if (!btn) return; var stroke = (typeof WhiteboardThemes !== 'undefined' && WhiteboardThemes.get) ? WhiteboardThemes.get('draw-stroke') : '#dee2e6'; btn.setAttribute('data-color', stroke); btn.style.background = stroke; if (btn.classList.contains('active') && typeof WhiteboardTools !== 'undefined' && WhiteboardTools.setDrawColor) { WhiteboardTools.setDrawColor(stroke); } } ``` Call `refreshDrawDefault()` once at the end of `init()` so the swatch picks up the current theme's draw-stroke even if the user never switches themes. Expose `refreshDrawDefault` on the returned API object. Dependencies: none. Safe-guarded against `WhiteboardThemes` being undefined (the script load order means it'll always be defined when `init()` runs, but defensive is cheap). #### Step 3: themes.js — invoke the toolbar refresh File: `crates/hero_whiteboard_ui/static/web/js/whiteboard/themes.js` In `applyTheme`, after the existing redraw loop and `WhiteboardConnectors.applyTheme()` call, add: ```js if (typeof WhiteboardToolbar !== 'undefined' && WhiteboardToolbar.refreshDrawDefault) { WhiteboardToolbar.refreshDrawDefault(); } ``` Dependencies: Step 2. ### Acceptance Criteria - [ ] Open the freehand drawing tool — black appears in the row of color swatches. - [ ] On a fresh Light board, the first swatch renders dark (the theme's `draw-stroke` is `#0f172a`); strokes are visible against the white canvas. - [ ] Switch to Dark — the first swatch becomes `#dee2e6` (light gray), matching the previous default. Existing strokes already on the canvas keep their persisted colors. - [ ] Switch to Ocean / Warm / Minimal — the first swatch updates to the theme's `draw-stroke`. If that swatch was the active selection, the live `WhiteboardTools.drawColor` updates too. - [ ] Picking any non-default swatch (including black) sets and keeps that color regardless of theme switches. - [ ] `cargo fmt`, `cargo clippy --workspace --all-targets -- -D warnings`, `cargo test --workspace --lib` clean. ### Notes - **Why `data-theme-default` instead of an `id`**: it's a single dedicated swatch today, but the same pattern is reusable for other tool palettes later (e.g. shape stroke, sticky default) — the attribute is a generic marker. - **`WhiteboardTools.drawColor` only updates when the theme-default swatch is active.** If the user has picked a non-default color, theme switches don't surprise them by changing what they draw with — they only change the default swatch's appearance. - **Existing strokes are not retroactively recolored.** Persisted user-drawn strokes keep their saved color across theme switches; this matches the pattern from #116 (existing stickies/shapes also keep their colors).
Author
Member

Implementation Summary

crates/hero_whiteboard_ui/templates/web/board.html

  • Added a black swatch to #draw-colors (between white and blue).
  • Tagged the first swatch with data-theme-default and set its title to "Theme default" so JS can keep it in sync without coupling to a specific color value.

crates/hero_whiteboard_ui/static/web/js/whiteboard/toolbar.js

  • New refreshDrawDefault() function: reads WhiteboardThemes.get('draw-stroke') and updates the tagged swatch's data-color and CSS background. If that swatch is currently active, also pushes the new color into WhiteboardTools.setDrawColor so the live draw color updates.
  • Called from the end of init() so the swatch picks up the theme on first paint.
  • Exposed on the public API.

crates/hero_whiteboard_ui/static/web/js/whiteboard/themes.js

  • applyTheme now invokes WhiteboardToolbar.refreshDrawDefault() after the redraw loop and WhiteboardConnectors.applyTheme() so theme switches re-sync the draw swatch live.

Files Changed

  • crates/hero_whiteboard_ui/templates/web/board.html+2 / -1
  • crates/hero_whiteboard_ui/static/web/js/whiteboard/toolbar.js+22 / -1
  • crates/hero_whiteboard_ui/static/web/js/whiteboard/themes.js+4 / 0

Test Results

  • cargo fmt --all -- --check — clean
  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • cargo test --workspace --lib — 0 failed
  • node --check toolbar.js && node --check themes.js — clean
  • cargo check -p hero_whiteboard_ui — clean (Askama re-compiled the template)

Manual smoke

  1. Open the freehand drawing tool — black is now in the swatch row.
  2. On a fresh Light board, the first swatch is dark (#0f172a); strokes are visible against the white canvas.
  3. Switch to Ocean / Warm / Minimal — the first swatch updates to that theme's draw-stroke.
  4. Pick a non-default swatch (e.g. black) — switching themes does not change the active draw color, since the user has already overridden it.
  5. Existing drawn strokes keep their persisted colors.

Notes

  • The active draw color only follows theme changes when the theme-default swatch is the selected one. If the user picked any other swatch, theme switches don't surprise them by changing what they're drawing with.
## Implementation Summary ### `crates/hero_whiteboard_ui/templates/web/board.html` - Added a black swatch to `#draw-colors` (between white and blue). - Tagged the first swatch with `data-theme-default` and set its title to "Theme default" so JS can keep it in sync without coupling to a specific color value. ### `crates/hero_whiteboard_ui/static/web/js/whiteboard/toolbar.js` - New `refreshDrawDefault()` function: reads `WhiteboardThemes.get('draw-stroke')` and updates the tagged swatch's `data-color` and CSS background. If that swatch is currently active, also pushes the new color into `WhiteboardTools.setDrawColor` so the live draw color updates. - Called from the end of `init()` so the swatch picks up the theme on first paint. - Exposed on the public API. ### `crates/hero_whiteboard_ui/static/web/js/whiteboard/themes.js` - `applyTheme` now invokes `WhiteboardToolbar.refreshDrawDefault()` after the redraw loop and `WhiteboardConnectors.applyTheme()` so theme switches re-sync the draw swatch live. ### Files Changed - `crates/hero_whiteboard_ui/templates/web/board.html` — `+2 / -1` - `crates/hero_whiteboard_ui/static/web/js/whiteboard/toolbar.js` — `+22 / -1` - `crates/hero_whiteboard_ui/static/web/js/whiteboard/themes.js` — `+4 / 0` ### Test Results - `cargo fmt --all -- --check` — clean - `cargo clippy --workspace --all-targets -- -D warnings` — clean - `cargo test --workspace --lib` — 0 failed - `node --check toolbar.js && node --check themes.js` — clean - `cargo check -p hero_whiteboard_ui` — clean (Askama re-compiled the template) ### Manual smoke 1. Open the freehand drawing tool — black is now in the swatch row. 2. On a fresh Light board, the first swatch is dark (`#0f172a`); strokes are visible against the white canvas. 3. Switch to Ocean / Warm / Minimal — the first swatch updates to that theme's `draw-stroke`. 4. Pick a non-default swatch (e.g. black) — switching themes does **not** change the active draw color, since the user has already overridden it. 5. Existing drawn strokes keep their persisted colors. ### Notes - The active draw color only follows theme changes when the theme-default swatch is the selected one. If the user picked any other swatch, theme switches don't surprise them by changing what they're drawing with.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_whiteboard#122
No description provided.