Skip to content

feat: add AppearanceProvider to decouple externalImages from theme - #27197

Merged
jakehwll merged 5 commits into
mainfrom
jakehwll/appearance-context
Jul 27, 2026
Merged

feat: add AppearanceProvider to decouple externalImages from theme#27197
jakehwll merged 5 commits into
mainfrom
jakehwll/appearance-context

Conversation

@jakehwll

@jakehwll jakehwll commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

🤖 This PR was modified by Coder Agents on behalf of Jake Howell.

What

Introduces an AppearanceProvider / useAppearance context that publishes user appearance values derived from the active site theme, and migrates the current consumers of theme.externalImages (Avatar, ExternalImage, IconsPage) to read from it.

Why

Today, per-user appearance concerns like externalImages are smuggled onto the Emotion theme object, which forces components to pull in useTheme purely to reach a single appearance value. That couples "how something looks for this user" to "how the styling engine happens to be wired", and means every new user-appearance value has to be bolted onto the theme.

This context gives user appearance a home of its own, decoupled from Emotion. Components ask for what they actually need (const { externalImages } = useAppearance()) instead of reaching through the theme.

Scope: user appearance, not admin appearance

To be explicit, this provider is about user-level appearance — the per-user, theme-derived rendering concerns. It is deliberately not the deployment-level AppearanceConfig (application name/logo, service banners, support/docs links) that admins configure; that is a separate concern with its own data source and shouldn't be folded in here.

Future scope

externalImages is the first value to move here, not the only one. Appearance is deliberately modelled as an open interface so future user appearance state can live in one place without touching every consumer or overloading the theme again. Likely candidates are other per-user, theme-derived values, e.g.:

  • Terminal font / other typography preferences currently surfaced via user appearance settings.
  • Theme mode and other theme-derived rendering styles that follow the same "read one value off the theme" pattern as externalImages.
  • Accessibility-oriented rendering preferences (e.g. reduced motion) as they're added.

Centralising these behind a single provider keeps consumers stable as the surface grows and avoids re-litigating the useTheme coupling each time (laziness now, less maintenance later).

Changes

  • Add site/src/theme/appearance.tsx (AppearanceProvider, useAppearance), defaulting externalImages to forDarkThemes to match DEFAULT_THEME.
  • Wrap children with AppearanceProvider in ThemeOverride and in the Storybook preview decorator.
  • Migrate Avatar, ExternalImage, and IconsPage off theme.externalImages and onto useAppearance.

Notes

  • Kept as a draft pending the go-ahead to open for review.
  • No behavioural change intended; this is a plumbing/refactor step.

@jakehwll jakehwll changed the title feat: <AppearanceContext /> feat: add appearance context to decouple externalImages from theme Jul 13, 2026
@jakehwll jakehwll changed the title feat: add appearance context to decouple externalImages from theme feat: add <AppearanceSettings /> to decouple externalImages from theme Jul 13, 2026
@jakehwll
jakehwll marked this pull request as ready for review July 13, 2026 17:18
jakehwll

This comment was marked as outdated.

@jakehwll
jakehwll marked this pull request as draft July 13, 2026 17:21
@jakehwll jakehwll changed the title feat: add <AppearanceSettings /> to decouple externalImages from theme feat: add <AppearanceSettings /> to decouple externalImages from theme Jul 13, 2026
jakehwll added 2 commits July 14, 2026 03:23
Addresses review nits on the appearance context:
- Make `useAppearance` throw when used outside an `AppearanceProvider`
  instead of silently defaulting, so a missing provider surfaces loudly.
  Every render path (`ThemeOverride`, `AppProviders`, Storybook preview)
  already wraps the provider.
- Document that this is the client-side, *user* appearance surface, distinct
  from `appearanceSettings` (user query) and the deployment `AppearanceConfig`.
- Soften the provider provenance note so it doesn't drift as more mounts appear.
jakehwll

This comment was marked as outdated.

@jakehwll
jakehwll requested a review from jeremyruppel July 14, 2026 14:10
@jakehwll
jakehwll marked this pull request as ready for review July 14, 2026 14:10
@github-actions github-actions Bot added the stale This issue is like stale bread. label Jul 27, 2026
@jakehwll jakehwll changed the title feat: add <AppearanceSettings /> to decouple externalImages from theme feat: add AppearanceProvider to decouple externalImages from theme Jul 27, 2026
@jakehwll
jakehwll enabled auto-merge (squash) July 27, 2026 08:47
@jakehwll
jakehwll merged commit 88c7304 into main Jul 27, 2026
32 checks passed
@jakehwll
jakehwll deleted the jakehwll/appearance-context branch July 27, 2026 08:54
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

stale This issue is like stale bread.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants