feat: add AppearanceProvider to decouple externalImages from theme - #27197
Merged
Conversation
<AppearanceContext /><AppearanceSettings /> to decouple externalImages from theme
jakehwll
marked this pull request as ready for review
July 13, 2026 17:18
jakehwll
marked this pull request as draft
July 13, 2026 17:21
<AppearanceSettings /> to decouple externalImages from theme<AppearanceSettings /> to decouple externalImages from theme
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
marked this pull request as ready for review
July 14, 2026 14:10
jeremyruppel
approved these changes
Jul 16, 2026
<AppearanceSettings /> to decouple externalImages from themeAppearanceProvider to decouple externalImages from theme
jakehwll
enabled auto-merge (squash)
July 27, 2026 08:47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Introduces an
AppearanceProvider/useAppearancecontext that publishes user appearance values derived from the active site theme, and migrates the current consumers oftheme.externalImages(Avatar,ExternalImage,IconsPage) to read from it.Why
Today, per-user appearance concerns like
externalImagesare smuggled onto the Emotion theme object, which forces components to pull inuseThemepurely 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
externalImagesis the first value to move here, not the only one.Appearanceis 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.:externalImages.Centralising these behind a single provider keeps consumers stable as the surface grows and avoids re-litigating the
useThemecoupling each time (laziness now, less maintenance later).Changes
site/src/theme/appearance.tsx(AppearanceProvider,useAppearance), defaultingexternalImagestoforDarkThemesto matchDEFAULT_THEME.AppearanceProviderinThemeOverrideand in the Storybook preview decorator.Avatar,ExternalImage, andIconsPageofftheme.externalImagesand ontouseAppearance.Notes