From 8072b250ea611d8d2266b5c18c25e73facd5930d Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Tue, 10 Mar 2026 18:37:50 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20canvas=20background=20selector=20?= =?UTF-8?q?=E2=80=94=20grid,=20dot,=20or=20blank=20preference?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add user-selectable canvas background style via data-canvas-bg attribute and CSS custom properties (--rs-canvas-bg-image, --rs-canvas-bg-size). Three options: grid (default), dot, blank — persisted in localStorage. - theme.css: new tokens + [data-canvas-bg] selectors - rstack-identity.ts: Grid/Dot/Blank selector in user dropdown - canvas.html: CSS vars, zoom-aware scaling, canvas-bg-change listener - flows.css: use shared bg-image/bg-size vars (fixes rFlows theme bug) - FOUC prevention in all entry points (shell.ts, create-space.html) Co-Authored-By: Claude Opus 4.6 --- modules/rflows/components/flows.css | 4 +-- server/shell.ts | 8 ++--- shared/components/rstack-identity.ts | 46 ++++++++++++++++++++++++++++ website/canvas.html | 20 +++++++----- website/create-space.html | 2 +- website/public/theme.css | 16 ++++++++++ 6 files changed, 81 insertions(+), 15 deletions(-) diff --git a/modules/rflows/components/flows.css b/modules/rflows/components/flows.css index 23436fa..42a1b11 100644 --- a/modules/rflows/components/flows.css +++ b/modules/rflows/components/flows.css @@ -241,8 +241,8 @@ width: 100%; height: 100%; display: block; cursor: grab; background-color: var(--rs-canvas-bg); - background-image: radial-gradient(circle, var(--rs-canvas-grid) 1px, transparent 1px); - background-size: 20px 20px; + background-image: var(--rs-canvas-bg-image); + background-size: var(--rs-canvas-bg-size); } .flows-canvas-svg.panning { cursor: grabbing; } .flows-canvas-svg.dragging { cursor: move; } diff --git a/server/shell.ts b/server/shell.ts index df55b0f..2e369b1 100644 --- a/server/shell.ts +++ b/server/shell.ts @@ -111,7 +111,7 @@ export function renderShell(opts: ShellOptions): string { ${escapeHtml(title)} - + diff --git a/shared/components/rstack-identity.ts b/shared/components/rstack-identity.ts index f42449a..1da3f8e 100644 --- a/shared/components/rstack-identity.ts +++ b/shared/components/rstack-identity.ts @@ -362,6 +362,14 @@ export class RStackIdentity extends HTMLElement { 🌙 + @@ -406,6 +414,22 @@ export class RStackIdentity extends HTMLElement { this.dispatchEvent(new CustomEvent("theme-change", { bubbles: true, composed: true, detail: { theme: newTheme } })); }); } + + // Canvas background style selector + const canvasBgOptions = this.#shadow.getElementById("canvas-bg-options"); + if (canvasBgOptions) { + canvasBgOptions.addEventListener("click", (e) => { + e.stopPropagation(); + const btn = (e.target as HTMLElement).closest("[data-bg]") as HTMLElement | null; + if (!btn) return; + const bg = btn.dataset.bg!; + localStorage.setItem("canvas-bg", bg); + document.documentElement.setAttribute("data-canvas-bg", bg); + canvasBgOptions.querySelectorAll(".canvas-opt").forEach(b => b.classList.remove("active")); + btn.classList.add("active"); + window.dispatchEvent(new Event("canvas-bg-change")); + }); + } } else { this.#shadow.innerHTML = ` @@ -1402,6 +1426,28 @@ const STYLES = ` .theme-toggle input:checked + .theme-slider { background: #6366f1; } .theme-toggle input:checked + .theme-slider::before { transform: translateX(18px); } +/* Canvas background selector in dropdown */ +.dropdown-canvas-row { + display: flex; align-items: center; justify-content: center; + gap: 8px; padding: 6px 16px; +} +.canvas-label { + font-size: 0.7rem; font-weight: 600; opacity: 0.5; + text-transform: uppercase; letter-spacing: 0.04em; +} +.canvas-options { display: flex; gap: 4px; } +.canvas-opt { + font-size: 0.65rem; font-weight: 600; padding: 3px 8px; + border: 1px solid var(--rs-border); border-radius: 6px; + background: transparent; color: var(--rs-text-secondary); + cursor: pointer; transition: all 0.15s; +} +.canvas-opt:hover { background: var(--rs-bg-hover); } +.canvas-opt.active { + background: var(--rs-accent); color: white; + border-color: var(--rs-accent); +} + /* Avatar wrapper + notification badge */ .avatar-wrap { position: relative; } .notif-badge { diff --git a/website/canvas.html b/website/canvas.html index e6364ed..b3d221d 100644 --- a/website/canvas.html +++ b/website/canvas.html @@ -11,7 +11,7 @@ rSpace Canvas - +