Skip to content

feat(web): auto-detect dark theme from OS preference#2963

Merged
elijah-potter merged 1 commit intomasterfrom
unknown repository
Mar 20, 2026
Merged

feat(web): auto-detect dark theme from OS preference#2963
elijah-potter merged 1 commit intomasterfrom
unknown repository

Conversation

@ghost
Copy link
Copy Markdown

@ghost ghost commented Mar 18, 2026

Summary

Automatically enables dark theme on writewithharper.com for users whose OS prefers dark mode, using the prefers-color-scheme CSS media feature.

The site already has full dark mode CSS support via Tailwind dark: classes, but there was no mechanism to apply the .dark class to the document. This adds an inline script in app.html that:

  1. Checks localStorage for a previously stored theme preference
  2. Falls back to window.matchMedia('(prefers-color-scheme: dark)')
  3. Adds the .dark class to <html> before SvelteKit renders, preventing FOUC

This is intentionally minimal and non-breaking. The existing manual theme toggle (if any) continues to work since stored preferences take priority over OS detection.

Test plan

  • Visit writewithharper.com with OS set to dark mode: site renders in dark theme
  • Visit with OS set to light mode: site renders in light theme (unchanged behavior)
  • Set localStorage.setItem('theme', 'dark'): dark theme persists regardless of OS setting
  • Clear localStorage: falls back to OS preference

Closes #1452

Add an inline script in app.html that checks prefers-color-scheme
and applies the .dark class to <html> before the page renders,
preventing a flash of unstyled content (FOUC).

The script also respects a previously stored theme preference in
localStorage, allowing future theme toggle implementations to
persist the user's choice.

Closes #1452

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@elijah-potter elijah-potter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@elijah-potter elijah-potter added this pull request to the merge queue Mar 20, 2026
Merged via the queue into Automattic:master with commit 64e143d Mar 20, 2026
11 checks passed
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Apr 9, 2026
⚠️ **CAUTION: this is a major update, indicating a breaking change!** ⚠️

This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [Automattic/harper/harper-ls](https://github.com/Automattic/harper) | major | `v1.12.0` → `v2.0.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>Automattic/harper (Automattic/harper/harper-ls)</summary>

### [`v2.0.0`](https://github.com/Automattic/harper/releases/tag/v2.0.0)

[Compare Source](Automattic/harper@v1.12.0...v2.0.0)

#### What's Changed

Hey all! We're finally releasing Harper 2.0. Why?

It isn't because we have any new groundbreaking features in this release, because we don't let major versioning stop us from pushing those out as soon as they're ready. It's because we have some breaking changes.

The biggest one only applies to you if you consume `harper.js`. From now on, instead of importing your binary from the main Harper module, you'll import it from one of four specialized modules.

Previously, you'd import the Harper WebAssembly binary with:

```javascript
import { LocalLinter, binary } from "harper.js";
```

As of Harper 2.0, you'll import it like this:

```javascript
import { LocalLinter } from "harper.js";
import { binary } from "harper.js/binary"; 
```

It's that simple! Thanks to this change, you'll find that your applications are more conducive to tree-shaking and therefore might even be a bit smaller!

In addition to that large breaking change, we also have a bunch of smaller improvements rolling out. I won't go through them one by one, but you're free to read through any of the linked pull requests below.

- refactor(core): use `Option::get_or_insert_with` by [@&#8203;86xsk](https://github.com/86xsk) in [#&#8203;2977](Automattic/harper#2977)
- test(linting): add comprehensive test cases for were/where lint rule by [@&#8203;estefafdez](https://github.com/estefafdez) in [#&#8203;2984](Automattic/harper#2984)
- feat: means a lot for→means a lot to by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;2982](Automattic/harper#2982)
- feat: add subcommand to generate shell completions by [@&#8203;deckstose](https://github.com/deckstose) in [#&#8203;2978](Automattic/harper#2978)
- refactor(core): extract indefinite article logic into its own module by [@&#8203;mvanhorn](https://github.com/mvanhorn) in [#&#8203;2980](Automattic/harper#2980)
- feat(web): auto-detect dark theme from OS preference in [#&#8203;2963](Automattic/harper#2963)
- build(deps): bump tar from 0.4.44 to 0.4.45 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2986](Automattic/harper#2986)
- feat: as evident by -> as evidenced by by [@&#8203;mvanhorn](https://github.com/mvanhorn) in [#&#8203;2985](Automattic/harper#2985)
- fix(core): `SplitWords` allowing uncommon merges by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;2874](Automattic/harper#2874)
- feat: add lint rule for flaunt/flout mix-up in [#&#8203;2962](Automattic/harper#2962)
- test: add regression tests for need\_to\_noun false positives ([#&#8203;2320](Automattic/harper#2320)) by [@&#8203;majiayu000](https://github.com/majiayu000) in [#&#8203;3014](Automattic/harper#3014)
- fix: case-insensitive same-form check in SimplePastToPastParticiple by [@&#8203;saschabuehrle](https://github.com/saschabuehrle) in [#&#8203;3012](Automattic/harper#3012)
- build(deps): bump pulldown-cmark from 0.13.1 to 0.13.3 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3002](Automattic/harper#3002)
- build(deps): bump tree-sitter-rust from 0.24.0 to 0.24.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3003](Automattic/harper#3003)
- build(deps): bump zip from 8.1.0 to 8.3.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3000](Automattic/harper#3000)
- build(deps): bump cached from 0.56.0 to 0.59.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3001](Automattic/harper#3001)
- chore(harper.js): update `raw-web` example to `1.12.0` by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;3015](Automattic/harper#3015)
- feat: "a" & "an" both OK for "URL" by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;2981](Automattic/harper#2981)
- feat: except of→except for / exception of by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;2997](Automattic/harper#2997)
- build(deps): bump rustls-webpki from 0.103.8 to 0.103.10 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2991](Automattic/harper#2991)
- feat: aspire for → aspire to by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3004](Automattic/harper#3004)
- docs: added link to agent policy by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;3016](Automattic/harper#3016)
- fix(lint-framework): reconnect popup host after DOM replacement by [@&#8203;k4sperski](https://github.com/k4sperski) in [#&#8203;2998](Automattic/harper#2998)
- fix(harper-cli): return exit code 0 when no lints are found by [@&#8203;Ryujiyasu](https://github.com/Ryujiyasu) in [#&#8203;2836](Automattic/harper#2836)
- chore: dictionary curation 2026-03-19 by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;2968](Automattic/harper#2968)
- Added native Neovim LSP config to docs by [@&#8203;RobertCrummett](https://github.com/RobertCrummett) in [#&#8203;2987](Automattic/harper#2987)
- fix: don't flag "more orange than red" etc. by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;2928](Automattic/harper#2928)
- perf(core): cache `WordSet` in `ModalVerb` by [@&#8203;86xsk](https://github.com/86xsk) in [#&#8203;3017](Automattic/harper#3017)
- feat: flag "use to" when "used to" is intended in [#&#8203;2975](Automattic/harper#2975)
- feat: flag nonstandard "verse" used as a verb (from "versus") in [#&#8203;2973](Automattic/harper#2973)
- feat: flag "date back from" as blend of "date from" and "date back to" in [#&#8203;2976](Automattic/harper#2976)
- feat(core): allow users to include dictionaries in Weirpacks by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;2922](Automattic/harper#2922)
- feat: try out one's luck→try one's luck by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;2916](Automattic/harper#2916)
- fix(chrome-ext): reverse the toggle button to it appears "on" by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;3026](Automattic/harper#3026)
- chore: dictionary curation by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3023](Automattic/harper#3023)
- Improve embedded form support in iframes by [@&#8203;k4sperski](https://github.com/k4sperski) in [#&#8203;3010](Automattic/harper#3010)
- refactor: compact token/lint content & char comparison by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;2957](Automattic/harper#2957)
- feat: expression to match pronoun-be, word pair or contraction by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;2944](Automattic/harper#2944)
- fix(chrome-ext): persist lint rule changes from settings page by [@&#8203;queelius](https://github.com/queelius) in [#&#8203;3028](Automattic/harper#3028)
- feat: in 1 day from now→in one day/one day from now by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3049](Automattic/harper#3049)
- build(deps): bump tree-sitter-ink-lbz from 0.0.1 to 0.0.5 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3064](Automattic/harper#3064)
- build(deps): bump ordered-float from 5.1.0 to 5.3.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3063](Automattic/harper#3063)
- build(deps): bump zip from 8.3.1 to 8.4.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3065](Automattic/harper#3065)
- feat: support Quarto qmd files as markdown by [@&#8203;itamarst](https://github.com/itamarst) in [#&#8203;3053](Automattic/harper#3053)
- feat: thrive off (of)→thrive on by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3055](Automattic/harper#3055)
- perf(core): optimizations in `LintGroup` by [@&#8203;86xsk](https://github.com/86xsk) in [#&#8203;3052](Automattic/harper#3052)
- feat: worth while/worth-while → worthwhile by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3056](Automattic/harper#3056)
- refactor(core)!: `Lrc<[char]>` instead of `Lrc<Vec<char>>` by [@&#8203;86xsk](https://github.com/86xsk) in [#&#8203;3060](Automattic/harper#3060)
- chore: dictionary curation by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3041](Automattic/harper#3041)
- build(deps): bump tree-sitter-rust from 0.24.1 to 0.24.2 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3061](Automattic/harper#3061)
- fix(obsidian): OOM error by reducing WASM bundle size by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;3050](Automattic/harper#3050)
- build(deps): bump tree-sitter-scala from 0.24.0 to 0.25.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3062](Automattic/harper#3062)
- fix(lint): add 'side' to ignore list for effect/affect rule (fix issue [#&#8203;2958](Automattic/harper#2958)) by [@&#8203;estefafdez](https://github.com/estefafdez) in [#&#8203;2983](Automattic/harper#2983)
- perf(spell): skip redundant lowercase DFA search in FstDictionary by [@&#8203;k4sperski](https://github.com/k4sperski) in [#&#8203;3025](Automattic/harper#3025)
- refactor!: take argument by value instead of mut ref by [@&#8203;86xsk](https://github.com/86xsk) in [#&#8203;3051](Automattic/harper#3051)
- feat: Sneaked vs snuck by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;2209](Automattic/harper#2209)
- feat: skeleton for new `ExprLinter` modules by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3024](Automattic/harper#3024)
- feat: web scrapping → web scraping by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3059](Automattic/harper#3059)
- fix: add key stroke→keystroke to key stoke→keystroke by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3067](Automattic/harper#3067)
- perf(core): avoid conversion between string and char array by [@&#8203;86xsk](https://github.com/86xsk) in [#&#8203;3074](Automattic/harper#3074)
- fix: don't flag "each of whom" by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3078](Automattic/harper#3078)
- docs(web): add link to [@&#8203;KraXen72](https://github.com/KraXen72)'s work by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;3079](Automattic/harper#3079)
- feat: at all cost → at all costs by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3082](Automattic/harper#3082)
- fix(core): address recent false positives and negatives by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;3090](Automattic/harper#3090)
- feat: add styling for user-defined monospace fonts by [@&#8203;stanley-910](https://github.com/stanley-910) in [#&#8203;3105](Automattic/harper#3105)
- feat: I am bias/you are prejudice→biased/prejudiced by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3058](Automattic/harper#3058)
- fix: don't flag "to" before "only" in ToTwoToo by [@&#8203;joaquinhuigomez](https://github.com/joaquinhuigomez) in [#&#8203;3093](Automattic/harper#3093)
- feat: ppl→people by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3116](Automattic/harper#3116)
- feat/obsidian web lint styling by [@&#8203;stanley-910](https://github.com/stanley-910) in [#&#8203;3104](Automattic/harper#3104)
- fix(lint-framework): preserve cursor position when dismissing suggestion popup by [@&#8203;draphy](https://github.com/draphy) in [#&#8203;3112](Automattic/harper#3112)
- build(deps): bump uuid from 1.22.0 to 1.23.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3117](Automattic/harper#3117)
- fix: skip PronounVerbAgreement for hyphenated compounds by [@&#8203;mvanhorn](https://github.com/mvanhorn) in [#&#8203;3095](Automattic/harper#3095)
- fix(harper-tex): mask additional LaTeX math environments by [@&#8203;jurajkl](https://github.com/jurajkl) in [#&#8203;3103](Automattic/harper#3103)
- feat: look forward for→look forward to by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3109](Automattic/harper#3109)
- build(deps): bump tempfile from 3.20.0 to 3.27.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3118](Automattic/harper#3118)
- build(deps): bump indexmap from 2.13.0 to 2.13.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3121](Automattic/harper#3121)
- build(deps): bump tracing-subscriber from 0.3.22 to 0.3.23 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3120](Automattic/harper#3120)
- build(deps): bump zip from 8.4.0 to 8.5.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;3119](Automattic/harper#3119)
- fix(core): exclude prepositions and conjunctions from QuiteQuiet pattern by [@&#8203;draphy](https://github.com/draphy) in [#&#8203;3127](Automattic/harper#3127)
- feat: arrive to → arrive at/in by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3125](Automattic/harper#3125)
- feat(core): create `UseEllipsisCharacter` rule by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;3099](Automattic/harper#3099)
- Fix indentation handling in harper-tex by [@&#8203;jurajkl](https://github.com/jurajkl) in [#&#8203;3106](Automattic/harper#3106)
- feat: will ran → will run / ran by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;2268](Automattic/harper#2268)
- feat: in the best of times→at the best of times by [@&#8203;hippietrail](https://github.com/hippietrail) in [#&#8203;3133](Automattic/harper#3133)
- feat: render configuration structurally by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;3123](Automattic/harper#3123)
- fix(chrome-ext): issues with Google Docs by [@&#8203;elijah-potter](https://github.com/elijah-potter) in [#&#8203;3141](Automattic/harper#3141)

#### New Contributors

- [@&#8203;estefafdez](https://github.com/estefafdez) made their first contribution in [#&#8203;2984](Automattic/harper#2984)
- [@&#8203;deckstose](https://github.com/deckstose) made their first contribution in [#&#8203;2978](Automattic/harper#2978)
- [@&#8203;mvanhorn](https://github.com/mvanhorn) made their first contribution in [#&#8203;2980](Automattic/harper#2980)
- [@&#8203;majiayu000](https://github.com/majiayu000) made their first contribution in [#&#8203;3014](Automattic/harper#3014)
- [@&#8203;saschabuehrle](https://github.com/saschabuehrle) made their first contribution in [#&#8203;3012](Automattic/harper#3012)
- [@&#8203;k4sperski](https://github.com/k4sperski) made their first contribution in [#&#8203;2998](Automattic/harper#2998)
- [@&#8203;Ryujiyasu](https://github.com/Ryujiyasu) made their first contribution in [#&#8203;2836](Automattic/harper#2836)
- [@&#8203;RobertCrummett](https://github.com/RobertCrummett) made their first contribution in [#&#8203;2987](Automattic/harper#2987)
- [@&#8203;queelius](https://github.com/queelius) made their first contribution in [#&#8203;3028](Automattic/harper#3028)
- [@&#8203;itamarst](https://github.com/itamarst) made their first contribution in [#&#8203;3053](Automattic/harper#3053)
- [@&#8203;joaquinhuigomez](https://github.com/joaquinhuigomez) made their first contribution in [#&#8203;3093](Automattic/harper#3093)
- [@&#8203;jurajkl](https://github.com/jurajkl) made their first contribution in [#&#8203;3103](Automattic/harper#3103)

**Full Changelog**: <Automattic/harper@v1.12.0...v2.0.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDkuMyIsInVwZGF0ZWRJblZlciI6IjQzLjEwOS4zIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6bWFqb3IiXX0=-->
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.

Enable dark theme automatically for writewithharper.com

1 participant