Build Mac AppDocsMenu

Modules

Module: a dark-only (or light-only) product

The template's site and app both follow the reader's system appearance. The site's skins must be the app's skins: a marketing page readable in a skin the software has never worn is a page showing a product that does not exist. If your app forces one appearance, force the same one on the site.

The app

On every window the app creates (AppDelegate.makeWindow, makeSettingsWindow):

window.appearance = NSAppearance(named: .darkAqua)

Palette colours resolve against the drawing appearance, so they follow automatically. Previews only approximate this with .preferredColorScheme — AppKit controls take their look from the window, which a preview does not have.

The site

  1. site/app/globals.css: replace every light-dark(a, b) pair with its dark half, keep the plain :root fallback block equal to those dark values, and change color-scheme: light dark; to color-scheme: dark;.
  2. site/lib/palette.ts: make PALETTE.light equal to PALETTE.dark, or delete light and update site/lib/palette.test.ts to compare only dark.
  3. site/lib/palette.test.ts: change the expected declaration to color-scheme: dark;.
  4. site/app/layout.tsx: viewport.themeColor becomes one colour — a pair would wrap a near-black page in a pale browser toolbar on a light-mode Mac.
  5. site/app/globals.css launch badges: keep only the dark image.

Do not add a theme switch. A source project "disabled" its light theme by pinning color-scheme near the top of the stylesheet, while a [data-theme="light"] selector forty lines down had equal specificity and later source order. Driven by a localStorage entry with no control left on screen to undo it, it painted the wrong skin for every returning visitor — with every check green. The palette test refuses theme-attribute selectors for this reason.

What stays light regardless

  • Email (EMAIL in site/lib/palette.ts). Gmail re-colours dark mail by heuristic and turns light-on-dark into light-on-light. The palette test asserts the email colours stay light.
  • The favicon and app icon: drawn on somebody else's tab strip and Dock, whose colour is theirs.
  • The OG card is dark in both cases (see site/app/opengraph-image.tsx).

Verify

cd site && pnpm test (the palette weld and contrast checks), then mac/scripts/check-palette.sh — which still compares both columns, so keep the Swift pairs equal to the site's.

This page is docs/modules/theme.md in the repository, copied 2026-09-25.