pub struct Theme {Show 44 fields
pub appearance: Appearance,
pub bg: Hsla,
pub surface: Hsla,
pub surface_raised: Hsla,
pub surface_card: Hsla,
pub surface_dialog: Hsla,
pub surface_overlay: Hsla,
pub element_hover: Hsla,
pub element_active: Hsla,
pub border: Hsla,
pub border_strong: Hsla,
pub text: Hsla,
pub text_muted: Hsla,
pub text_faint: Hsla,
pub text_dim: Hsla,
pub solid: Hsla,
pub on_solid: Hsla,
pub accent: Hsla,
pub accent_strong: Hsla,
pub on_accent: Hsla,
pub danger: Hsla,
pub danger_muted: Hsla,
pub warning: Hsla,
pub warning_muted: Hsla,
pub success: Hsla,
pub busy: Hsla,
pub success_muted: Hsla,
pub surface_raised_hover: Hsla,
pub band: Hsla,
pub input_bg: Hsla,
pub selection: Hsla,
pub cursor: Hsla,
pub caret: Hsla,
pub danger_strong: Hsla,
pub code_text: Hsla,
pub code_wash: Hsla,
pub syntax: SyntaxPalette,
pub diff_add: Hsla,
pub diff_del: Hsla,
pub diff_hunk_bg: Hsla,
pub font_sans: SharedString,
pub font_mono: SharedString,
pub font_sans_fallback: SharedString,
pub font_mono_fallback: SharedString,
}Expand description
The app theme. Two concrete instances — Theme::dark and Theme::light.
Fields§
§appearance: AppearanceWhich appearance these tokens were built for.
bg: HslaMain content panel. Dark: the deepest plane (#060606). Light: pure white — long-form content reads best on an unbroken white field.
surface: HslaShell / sidebar surface. Dark: one step up from bg. Light: one step
down (grey) — chrome recedes from the content plane in both, which is
the direction a naive invert gets backwards.
surface_raised: HslaRaised surface: opaque pills and chips that sit proud of the panel.
Dark: lighter than surface. Light: white, separated by border +
shadow rather than by lightness.
surface_card: HslaInline card resting on the main panel (auth gate, empty-state cards).
surface_dialog: HslaModal dialog, floating over a Theme::scrim.
surface_overlay: HslaPopover, menu and command-palette surface — the highest plane.
element_hover: HslaHover wash for interactive rows/buttons.
element_active: HslaActive/selected wash.
border: HslaHairline border.
border_strong: HslaStronger border for focused/raised edges.
text: HslaPrimary text. ~17.5:1 on its own background in both appearances.
text_muted: HslaMuted text: timestamps, secondary labels. ~7.5–8:1.
text_faint: HslaFaint text: placeholders, disabled. ~4.5:1 — AA for body copy.
text_dim: HslaOne notch below text_muted — the diff file-path tone. It exists as its
own token rather than being folded into text_muted because the dark
value was sampled (#989898) and folding it would shift that label, which
is a palette change dressed up as a refactor.
solid: HslaThe maximum-contrast solid fill: near-white on dark, near-black on light. This is the primary button plate.
on_solid: HslaLabel/icon color on top of Self::solid — its inverse.
accent: HslaAccent — the emphasis weight for text and icons.
Neutral by default, and deliberately. A component library that ships a hue puts that hue in every app that installs it, and bezel had an indigo running through spinners, pagination, date selection and list markers before anyone chose it. The default is now the same lightness with the chroma at zero.
This is the token to brand:
let mut theme = Theme::for_appearance(appearance);
theme.accent = my_brand_accent(appearance);See set_palette, which is what
makes an override survive an appearance switch.
accent_strong: HslaStronger accent for fills that carry Self::on_accent text. Neutral by
default, it is the maximum-contrast plate — a mid grey would not carry a
label the way the indigo it replaced did.
on_accent: HslaLabel color on top of Self::accent_strong.
danger: HslaDanger — red (errors, stop button).
danger_muted: HslaSofter danger for secondary/inline error copy.
warning: HslaWarning — amber (offline notices, awaiting-input).
warning_muted: HslaSofter warning for secondary copy.
success: HslaSuccess / online — emerald.
busy: HslaWorking / streaming indicator — pink.
success_muted: HslaSofter success for text on a success-tinted chip.
surface_raised_hover: HslaHover tone for an opaque raised pill. Hover must brighten the plate in dark mode, never swap it for a translucent wash (that made pills go see-through — user-reported); in light mode it darkens instead, same idea.
band: HslaRecessed band behind a palette/picker header or footer strip. Translucent so the glass still reads through.
input_bg: HslaThe composer pill and other input plates.
Its own token because “lifted” inverts between appearances. On dark, a faint white wash over near-black reads as raised. The literal light translation — a faint black wash on white — reads as recessed, a dent rather than a plate, which is why the prompt looked like bare text on a smudge. Light mode lifts the way light UIs actually do: pure white, with the border and shadow carrying the elevation.
selection: HslaText-selection highlight in the composer and inputs.
cursor: HslaTerminal block cursor.
caret: HslaText caret, and the focus ring that shares its weight.
The body text colour, because that is what a caret is: the next glyph, before you type it. It was a sampled blue once — carried over from the app this library was extracted from, derived from nothing here — which is why a caret in a plain paragraph arrived tinted.
danger_strong: HslaDestructive-action button fill (danger plate, carries Self::on_accent).
code_text: HslaInline-code text. Neutral: code is already set apart by the mono face and its wash, and a hue on top reads as a link rather than as code.
code_wash: HslaInline-code wash behind Self::code_text.
syntax: SyntaxPaletteShared paint-only syntax palette.
diff_add: HslaDiff: added lines.
diff_del: HslaDiff: deleted lines.
diff_hunk_bg: HslaDiff: hunk-header wash (bluish grey).
font_sans: SharedStringUI font family — the name the text system resolves, not the bytes. Point it at your own family once you have registered that font with the text system; a family nothing registered falls through to the fallback below.
font_mono: SharedStringMonospace family for code/terminal.
font_sans_fallback: SharedStringExplicit system fallbacks, for callers that want to skip the lookup.
font_mono_fallback: SharedStringImplementations§
Source§impl Theme
impl Theme
Sourcepub fn branded(brand: &Brand, appearance: Appearance) -> Self
pub fn branded(brand: &Brand, appearance: Appearance) -> Self
The shipped palette for an appearance, rotated onto a brand. What
Theme::install builds, without installing it — for previewing the
appearance you are not currently painting.
Source§impl Theme
impl Theme
Sourcepub fn glass(&self) -> Hsla
pub fn glass(&self) -> Hsla
The frost tint painted over the blurred window background (macOS glass),
at Brand::glass’s alpha. Dark: darker than
surface, matched to the reference vibrancy scrim hsl(0 0% 3%).
Light: a near-white frost. Opaque, this IS the surface tone.
Sourcepub fn window_bg(&self) -> Hsla
pub fn window_bg(&self) -> Hsla
The app’s root fill: the frost where glass is on, the opaque panel
where it is not. What a root element paints instead of
Self::bg, so a window that opens blurred is not
then covered over by the paint that made the blur pointless.
Sourcepub fn is_glass(&self) -> bool
pub fn is_glass(&self) -> bool
Whether this appearance paints translucent chrome over the blurred desktop. Glass-only recipes — backdrop blurs, translucent popover tints, per-glyph edge fades — must gate on this rather than reading the brand’s alpha, because an opaque appearance can still be asked for one.
Sourcepub fn glass_hover(&self) -> Hsla
pub fn glass_hover(&self) -> Hsla
Hover wash for chrome that sits ON GLASS (sidebar rows, tabs, titlebar
buttons). One recipe, both appearances: the 11% wash,
tone-flipped by the palette convention (soft-white on dark, soft-black
on light).
Hover and selection share the SAME fill (selection adds only the ring). Light previously ran heavy white washes here (hover 0.55, selection 0.92) after a black-hover-next-to-white-selection mismatch report; now hover and selection are both the tone-flipped wash, so they lift the same way again. Light’s alpha sits under dark’s: dark’s 11% at the light tone read too dark over the bright frost (user report).
Sourcepub fn glass_overlay(&self) -> Hsla
pub fn glass_overlay(&self) -> Hsla
The translucent tint floating cards paint over their backdrop blur
(see bezel::material). Dark: the reference
.glass-surface menu tint verbatim — oklch(0.33 0 0 / 34%). The
previous surface_overlay at 65% was tuned back when the tint had to
approximate the composited recipe without a real blur; kept over the
blur it buried the backdrop’s colour and menus read as flat grey slabs
next to the hue-inheriting chrome (user report). At 34% the blurred
backdrop carries the card and the mid-grey only lifts it off the
plane. Light: heavier — a translucent white tint left menu text
ghosting over whatever sat behind the popover, so light coverage
steps up to keep rows on a known background.
Sourcepub fn input_glass_bg(&self) -> Hsla
pub fn input_glass_bg(&self) -> Hsla
The composer pill / question panel fill. Light’s input_bg is opaque
white (the elevation ladder on an opaque page) — over glass it read as
a solid slab in front of the frosted blur, so it thins to a
translucent tint there (0.6 and then 0.45 both still read too bright
over the 0.80 frost — lowered on user request). Dark’s 3% white wash
is already glass-native.
Sourcepub fn card_glass_bg(&self) -> Hsla
pub fn card_glass_bg(&self) -> Hsla
Section-card fill (settings cards and similar in-panel cards). The
opaque surface tone read as a harsh solid slab floating on the
frosted blur (user report), so glass thins it to a translucent tint;
opaque platforms keep the true card tone.
Sourcepub fn window_background_appearance(&self) -> WindowBackgroundAppearance
pub fn window_background_appearance(&self) -> WindowBackgroundAppearance
How the platform should composite the window behind our paint. The mode falls out of the alpha: frost under 1.0 wants the blurred desktop, opaque wants opaque compositing (subpixel-friendly, no vibrancy cost for a blur nothing shows).
This is a method rather than a constant because it has to be re-applied after
every theme swap: gpui’s macOS backend tears the NSVisualEffectView
out of the hierarchy whenever the value is anything but Blurred, and
the re-apply in appearance::apply is what restores vibrancy when the
user switches back to dark. See zed’s crates/zed/src/main.rs, which
runs the same loop on every settings change.
Source§impl Theme
impl Theme
Sourcepub fn install(appearance: Appearance, cx: &mut App)
pub fn install(appearance: Appearance, cx: &mut App)
Install the palette for appearance as the gpui global and point the
context-free paint helpers at it. The only way the appearance should
change — setting the global directly leaves
current_appearance stale.
Which palette that is comes from set_palette, so an app with its own
colours keeps them across a light/dark switch.
Sourcepub fn install_custom(theme: Theme, cx: &mut App)
pub fn install_custom(theme: Theme, cx: &mut App)
Install a palette the caller built: brand colours, one retuned token, or
a wholesale replacement. Theme is a plain struct with public fields, so
the usual shape is Theme::light() with a few fields overwritten.
Use this rather than cx.set_global(theme). The context-free paint
helpers (ink, hairline, wash, …) read current_appearance
and not the global, so a palette installed around this one leaves them
painting for whatever appearance was last installed — light washes over a
dark palette, and nothing to point at.
One-shot: appearance::apply rebuilds the palette whenever the
appearance changes, so what is installed here is replaced on a light/dark
switch. For colours that survive that, register a builder with
set_palette instead.
Source§impl Theme
impl Theme
Sourcepub const GLASS_ALPHA: f32
pub const GLASS_ALPHA: f32
The frost alpha Brand::glass starts from.
Matched by eye to a reference Electron app’s dark glass: its scrim is
0.76 over hsl(0 0% 3%), but sits on the under-window vibrancy
MATERIAL, which pre-darkens the blur; a bare backdrop blur has no such
layer, so ours runs heavier to land on the same perceived tone.
Opaque off macOS: Linux and Windows get no compositor-blur guarantee, and a merely transparent window would show raw desktop through the sidebar. An app that knows its compositor sets the brand field anyway.
Sourcepub const HEADER_HEIGHT: f32 = 44.0
pub const HEADER_HEIGHT: f32 = 44.0
Main-panel header height (the reference h-11) — in-card headers (changes pane).
Sourcepub const TITLEBAR_HEIGHT: f32 = 38.0
pub const TITLEBAR_HEIGHT: f32 = 38.0
The unified window titlebar (traffic lights + cluster + tabs). Content
rides Self::TITLEBAR_TOP_PAD lower than center so the air above
matches the perceived gap to the inset card below (border + card body).
Sourcepub const TITLEBAR_TOP_PAD: f32 = 2.0
pub const TITLEBAR_TOP_PAD: f32 = 2.0
Downward shift of titlebar content within the bar.
Sourcepub const TRAFFIC_LIGHT_INSET: f32
pub const TRAFFIC_LIGHT_INSET: f32
Leading room the macOS traffic lights need where AppKit puts them —
zed’s TRAFFIC_LIGHT_PADDING on the macOS 26 SDK (71.0 before it), and
the same 78 ../desktop measured for its Tauri window. An app that
moves the lights with TitlebarOptions::traffic_light_position owns
this number too.
Sourcepub const STATUS_STRIP_HEIGHT: f32 = 24.0
pub const STATUS_STRIP_HEIGHT: f32 = 24.0
Reserved status strip under the content outlet (the reference h-6) — the
WorkingIndicator row; reserving it keeps the composer from shifting.
Sourcepub const TRANSCRIPT_FADE_BAND: f32 = 24.0
pub const TRANSCRIPT_FADE_BAND: f32 = 24.0
Height of the gradient that fades the transcript into the panel background at its bottom edge. The transcript’s last row must pad itself past this band so settled content (message text, the hover-revealed timestamp) never sits inside the fade when scrolled to the bottom.
Sourcepub const BASE_RADIUS: f32 = 8.0
pub const BASE_RADIUS: f32 = 8.0
Button, text field and select-trigger radius — the crate’s most-used
corner after the derived ones, and unnamed until the concentric pass
separated the eight sites that chose 8.0 from the ones that only
arrived at it as 12 − 4.
Every other corner is a ratio of this one, so
Brand::radius moves the whole set together.
pub const SPACE_SM: f32 = 8.0
pub const SPACE_MD: f32 = 12.0
pub const SPACE_LG: f32 = 16.0
Sourcepub fn bubble_radius() -> f32
pub fn bubble_radius() -> f32
Message bubble corner radius.
Sourcepub fn surface_radius() -> f32
pub fn surface_radius() -> f32
Floating-surface corner radius — popovers, menus, the command palette, group boxes.
A glass surface paints this on its border and hands the same number
to bezel::ui::material’s backdrop blur. The two must agree: a blur cut
to a different radius frosts square corners outside a round border, and
it shows only on glass and only at the corners. So the radius is named
once and read at both ends, rather than written twice sixty lines apart
— which is how three independent 12.0s came to exist here.
Sourcepub fn panel_radius() -> f32
pub fn panel_radius() -> f32
Panel / card corner radius.
Button, text field and select-trigger radius.
Sourcepub fn control_radius() -> f32
pub fn control_radius() -> f32
Small control radius (chips, tags, steppers) — a size down from
Self::button_radius, for things that sit inside a control rather
than being one.
Sourcepub const fn inset_radius(outer: f32, inset: f32) -> f32
pub const fn inset_radius(outer: f32, inset: f32) -> f32
The concentric child of a surface: a row inset by inset inside a
container of radius outer keeps its corners parallel to the
container’s, rather than looking pasted onto it.
This is SwiftUI’s ContainerRelativeShape rule done as arithmetic. gpui
has no container shape to inherit at paint time, so the relationship is
stated where the child is defined instead of resolved at runtime —
which means a container that changes its padding carries its rows with
it, and the derived value never becomes a constant of its own.
Source§impl Theme
impl Theme
Sourcepub fn dark() -> Self
pub fn dark() -> Self
Build the dark theme. The surface tones are sampled straight from the
reference screenshots of the original app (docs/reference): main panel
#060606, shell/sidebar #0d0d0d.
Sourcepub fn light() -> Self
pub fn light() -> Self
Build the light theme.
Neutrals are the same oklch scale read from the other end, but the roles are reassigned rather than mirrored (see the module docs): content plane white, chrome grey, raised surfaces white-plus-shadow. Text tones are picked to reproduce the dark theme’s contrast ratios, and accents drop from the 400 to the 600 step at identical hue so they clear WCAG AA on white instead of glowing.
Sourcepub fn for_appearance(appearance: Appearance) -> Self
pub fn for_appearance(appearance: Appearance) -> Self
Build the theme for an appearance.
Trait Implementations§
impl Global for Theme
Auto Trait Implementations§
impl Freeze for Theme
impl RefUnwindSafe for Theme
impl Send for Theme
impl Sync for Theme
impl Unpin for Theme
impl UnsafeUnpin for Theme
impl UnwindSafe for Theme
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> ReadGlobal for Twhere
T: Global,
impl<T> ReadGlobal for Twhere
T: Global,
Source§impl<R, P> ReadPrimitive<R> for P
impl<R, P> ReadPrimitive<R> for P
Source§fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
ReadEndian::read_from_little_endian().