mirror of
https://github.com/logseq/logseq.git
synced 2026-05-18 18:02:35 +00:00
fix: avatar fallback colors update instantly on theme toggle
The avatar fallback hex (background + text) is computed in JS by `avatar-fallback-style` → `colors/read-bg-var` → `getComputedStyle`, so its output is a snapshot of the current theme's CSS variables at render time. The result is written into the element's inline style. On `tt` (theme toggle) the snapshot stayed frozen until something unrelated triggered a re-render, leaving avatars carrying the wrong theme's tone — too bright in dark mode, too dark in light mode. Two coordinated changes: 1. state/set-theme-mode! now stamps `data-theme` + body classes synchronously *before* mutating `:ui/theme`. The previous flow left the DOM update inside theme.cljs's `use-effect!`, which fires AFTER React's render commit — so subscribers re-rendering on the state change still read the old theme's CSS vars. The theme.cljs effect remains as an idempotent safety net plus the side effects (plugin hook, custom-theme application). 2. `avatar-image-cp` and `get-node-icon-cp` subscribe to `:ui/theme`. The subscribed value is discarded — the subscription's job is to tick Rum's dependency graph so the component re-renders on toggle and recomputes `avatar-fallback-style` against the (now fresh) CSS variables. Combined with the synchronous DOM update above, the read-bg-var snapshot is correct on the first render after toggle, no second tick required. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -478,6 +478,15 @@
|
||||
;; the design rationale (subscribing to the per-tx atom is
|
||||
;; what catches retractions; `model/sub-block` doesn't).
|
||||
_latest-tx (state/sub :db/latest-transacted-entity-uuids)
|
||||
;; Re-render on theme toggle so `avatar-fallback-style` re-
|
||||
;; samples `--ls-primary-background-color` from the new
|
||||
;; cascade. The avatar's inline `style` is computed in JS
|
||||
;; from a `getComputedStyle` snapshot — without a Rum
|
||||
;; subscription on `:ui/theme`, the snapshot stays frozen
|
||||
;; after a theme toggle (state.cljs:1283) and the avatar
|
||||
;; renders with the previous theme's surface tone until
|
||||
;; some unrelated re-render fires.
|
||||
_theme (state/sub :ui/theme)
|
||||
asset-entity (when (and asset-uuid (string? asset-uuid))
|
||||
(try (db/entity [:block/uuid (uuid asset-uuid)])
|
||||
(catch :default _ nil)))
|
||||
@@ -893,7 +902,16 @@
|
||||
|
||||
(rum/defc get-node-icon-cp < rum/reactive db-mixins/query
|
||||
[node-entity opts]
|
||||
(let [;; Get fresh entity using db/sub-block to make it reactive to property changes
|
||||
(let [;; Re-render on theme toggle so the bare-avatar branch inside
|
||||
;; `(icon ...)` (text/letters/emoji avatars) re-samples the
|
||||
;; live `--ls-primary-background-color` via `read-bg-var`
|
||||
;; when computing `avatar-fallback-style`. Without this sub,
|
||||
;; the inline `style` hexes baked in at the previous render
|
||||
;; stay frozen across theme toggles — none of the other
|
||||
;; subscriptions in this component (`:ui/icon-hover-preview`,
|
||||
;; `model/sub-block`) tick on `:ui/theme` changes.
|
||||
_theme (state/sub :ui/theme)
|
||||
;; Get fresh entity using db/sub-block to make it reactive to property changes
|
||||
fresh-entity (when-let [db-id (:db/id node-entity)]
|
||||
(or (model/sub-block db-id) node-entity))
|
||||
entity (or fresh-entity node-entity)
|
||||
|
||||
@@ -1244,6 +1244,29 @@ Similar to re-frame subscriptions"
|
||||
(set-edit-content! edit-input-id content)
|
||||
(set-editor-last-pos! new-pos)))
|
||||
|
||||
(defn- apply-theme-to-dom!
|
||||
"Synchronously stamp `data-theme` + body classes onto the document
|
||||
so CSS variables re-resolve to the new theme *before* the state
|
||||
mutation below triggers React subscribers. Without this, subscribers
|
||||
that compute hex values from CSS vars at render time (e.g. avatar
|
||||
fallback colors via `colors/read-bg-var` → `getComputedStyle`)
|
||||
would re-render with the OLD theme's resolved vars because
|
||||
`theme.cljs`'s `use-effect!` only sets these attributes *after*
|
||||
the render commit. That effect remains as a safety net (it's
|
||||
idempotent — same setAttribute) and continues to handle the
|
||||
plugin-hook + custom-theme side effects."
|
||||
[mode]
|
||||
(when (exists? js/document)
|
||||
(let [^js doc js/document.documentElement
|
||||
^js cls (.-classList doc)
|
||||
^js cls-body (.-classList js/document.body)]
|
||||
(.setAttribute doc "data-theme" mode)
|
||||
(if (= mode "dark")
|
||||
(do (.add cls "dark")
|
||||
(doto cls-body (.remove "white-theme" "light-theme") (.add "dark-theme")))
|
||||
(do (.remove cls "dark")
|
||||
(doto cls-body (.remove "dark-theme") (.add "white-theme" "light-theme")))))))
|
||||
|
||||
(defn set-theme-mode!
|
||||
([mode] (set-theme-mode! mode (:ui/system-theme? @state)))
|
||||
([mode system-theme?]
|
||||
@@ -1253,6 +1276,7 @@ Similar to re-frame subscriptions"
|
||||
(util/set-theme-dark)))
|
||||
(when (mobile-util/native-platform?)
|
||||
(mobile-util/set-native-interface-style! mode system-theme?))
|
||||
(apply-theme-to-dom! mode)
|
||||
(set-state! :ui/theme mode)
|
||||
(storage/set :ui/theme mode)))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user