Skip to content

Fix dark-mode search UI after Roam rewrote find-or-create (Craft, Things) - #57

Open
nickhuo wants to merge 1 commit into
rcvd:masterfrom
nickhuo:fix/craft-dark-search-ui
Open

Fix dark-mode search UI after Roam rewrote find-or-create (Craft, Things)#57
nickhuo wants to merge 1 commit into
rcvd:masterfrom
nickhuo:fix/craft-dark-search-ui

Conversation

@nickhuo

@nickhuo nickhuo commented Jul 30, 2026

Copy link
Copy Markdown

Problem

Roam rewrote the find-or-create component, and the theme's selectors stopped matching. In dark mode Roam's light-mode defaults show through:

Symptom Where
Selected result row painted #e1e8ed under light text — effectively unreadable topbar dropdown and modal
Keyboard-hint footer painted #ebeceb both
Modal chrome, filter chips and search input stay white new centered search modal
Block-result snippet text at 1.20:1 contrast both

Reported for Craft; Things has the same gaps. Quattro is partly protected because it fills more variables.

What changed in Roam

  • Result rows: .rm-menu-itemli.bp3-menu-item
  • Selection: an inline background-color style → the .bp3-active class
  • A second surface was added: the centered .rm-find-or-create-modal (with Semantic / + Filter / Best match chips) alongside the existing topbar .rm-find-or-create-popover. The two use different list containers.rm-find-or-create__menu vs .rm-find-or-create-modal-body__list
  • Row internals are now .rm-find-or-create-row__{title,ref-count,label,snippet,breadcrumb-segment}

So system.css:2081-2125 — the whole find-or-create block — no longer matched anything.

Root cause detail

Two independent mechanisms, both worth noting because they recur:

1. Selector drift, plus a specificity loss. Even where a generic rule still matches, Roam out-specifies the theme. Collected from the live page:

rgb(225, 232, 237)  <<  .rm-find-or-create-popover .rm-find-or-create__menu > li.bp3-menu-item.bp3-active   [Roam]   (0,4,1)
var(--bc-menu__item--active)  <<  .bp3-menu-item.bp3-active                                                 [theme]  (0,2,0)

system.css is injected at runtime so it loses on specificity, not order. The retargeted rules therefore mirror Roam's selector shape and keep !important. Same for the modal: .rm-modal-portal--find-or-create > .bp3-overlay > .bp3-dialog-container > .bp3-dialog is (0,4,0) versus the theme's .rm-modal-dialog at (0,1,0).

2. Empty variables are silent dark-mode bugs. --x: ; is invalid at computed-value time, so the declaration is dropped and Roam's light default wins. Invisible in light mode, a contrast bug in dark. grep -n ": ;" *-dark.css finds more of these.

Testing

Verified in Craft/Thing dark: selected row, hover, footer, hint chips, modal surface, chips, snippet contrast, and that the green New page: label survives selection. Light mode checked for non-regression.

Before:
Pasted Graphic 2
Pasted Graphic 3

After:
image
image

Roam rewrote the find-or-create component: result rows moved from
.rm-menu-item to li.bp3-menu-item, selection moved from an inline
background-color style to the .bp3-active class, and a new centered
modal (.rm-find-or-create-modal) was added alongside the topbar
dropdown (.rm-find-or-create-popover). The theme's selectors stopped
matching, so Roam's light-mode defaults showed through in dark mode:
the selected row painted #e1e8ed under light text, the keyboard-hint
footer painted #ebeceb, the modal chrome / filter chips / search input
stayed white, and block-result snippet text sat at 1.20:1 contrast.

Retarget the dead selectors onto the current DOM, keeping the old ones
comma-joined so older Roam builds still work. Roam's rules out-specify
the theme (0,4,1 vs 0,2,0), so the selected-row rules mirror Roam's
selector shape and keep !important. Scope with
:is(.rm-find-or-create-popover, .rm-find-or-create-modal) and
:is(.rm-find-or-create__menu, .rm-find-or-create-modal-body__list) to
cover both surfaces without changing specificity.

Also fill variables left empty, which is the same class of bug: an
empty value is invalid at computed-value time, so the declaration is
dropped and Roam's default wins.

- --bc-find-or-create__menu-item--hover (empty in both modes)
- --co-filter__{command-text,helper-text,icon--filtered} (empty)
- --*-block-search__menu-item--active (empty in Craft; corrupt in
  things-dark, where --bt- read var(--cl-.) and --co- read transparent)

New variables for DOM that was never themed: __footer,
__footer-hotkey, __chip, __snippet and __snippet--selected. Every new
rule uses var(--x, <existing var>) fallbacks so the five themes that
do not define them degrade to a sane value rather than an invalid
declaration.

--bc-find-or-create__wrapper-large gets a real background in dark
only: the focused topbar wrapper is flex: 0 1 600px and therefore
matches :not([style*="flex: 0 1 200px"]), so a light-mode value would
put a 600px band across the topbar.

src/index.ts regenerated via npm run add_css.
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.

1 participant