feat(theme): add Glass design language - #3130
Conversation
Drop `transparent: true` (it makes behind-window vibrancy render near-opaque over the desktop) and switch the material to `popover`; keep `visualEffectState: active` so the menubar popup stays translucent while unfocused. Sync `nativeTheme.themeSource` with the color mode via a new SET_NATIVE_THEME IPC so dark Glass gets a dark material instead of light text on a light frost. Clear the Primer `[data-color-mode]` wrapper's opaque background so the material shows through the whole window. Also removes the Increase contrast setting, which forced Glass to a solid surface and whose useAppearance/theme wiring is intertwined with the changes above.
Under translucency: row action buttons become bare icons (no hover band or button fill) with the row text fading out under them on hover so it never collides; the scrollbar track goes transparent; and the glass tints are lowered a step so more of the material shows through.
…witch applyWindowVibrancy only cleared the window background when disabling, so switching Classic (which paints an opaque backdrop) to Glass left that backdrop in place and blocked the vibrancy material from sampling the desktop. Clear it on enable too; `#00000000` works without a transparent window because the vibrancy view provides the translucency. Adds regression tests for both toggle sides.
Handle the setNativeTheme IPC rejection (log via rendererLogError) instead of leaving an unhandled promise, matching the setWindowVibrancy call, and note that the sync is intentionally not macOS-gated. Adds coverage for the Glass-clamped path (Glass + DARK_DIMMED still syncs 'dark').
setchy
left a comment
There was a problem hiding this comment.
Marking while I have time to review.
| const mockAppearanceSettings: AppearanceSettingsState = { | ||
| designLanguage: DesignLanguage.CLASSIC, | ||
| theme: Theme.SYSTEM, | ||
| increaseContrast: false, |
There was a problem hiding this comment.
this was used to control an accessibility feature of the GitHub primer themes
There was a problem hiding this comment.
was your thoughts to control this from the macOS Accessibility increase contrast setting directly?
There was a problem hiding this comment.
Whoops, no, I just meant to remove it from Glass, but forgot to add it back in Classic. Re-adding.
There was a problem hiding this comment.
@afonsojramos - increaseContrast is missing from our mockAppearanceSettings
There was a problem hiding this comment.
It’s back already?? increaseContrast was restored in bba2ca8 along with the Classic-only checkbox and the new prefers-contrast: more wiring, so mockAppearanceSettings has it at state-mocks.ts:30
|
Super sharp enhancement, @afonsojramos. I love that we're able to keep the design components as Primer and apply new theme/style overrides. Nice work. Left a few inline comments for my own curiosity |
…and the OS Restore the Increase contrast setting (shown for Classic only) and additionally honour the OS "Increase contrast" accessibility preference via `prefers-contrast: more`. Either one selects Primer's `*_high_contrast` schemes for Classic; Glass takes its solid fallback instead, and that same preference now also withholds Glass's vibrancy.
The inert zoom/interval/volume/shortcut value displays are self-explanatory from
`pointer-events-none` and `tabIndex={-1}`, so the repeated comment was just noise.
|
|
Was doing more manual testing this morning - the notification type icon colors appear broken [always black] |
Yup, fairly certain - try toggling the theme - looks like several items loose their styling when set to Screen.Recording.2026-08-04.at.5.05.37.PM.mov |









Summary
After simmering for 2 days @setchy 👀
Adds a second design language, Glass, next to the existing look (now Classic), selectable under Settings → Appearance. Under Glass the whole window becomes one continuous translucent material: the sidebar dissolves into icons floating on the glass, controls (buttons, selects, checkboxes, radios, count pills) render as stepped translucent tiles, notification and repo rows float as rounded cards with glass hover states, and tooltips/popovers come out frosted. Classic is pixel-unchanged: everything Glass lives behind
[data-theme='glass']plus a.gitify-translucentgate, so there is no risk to the default experience.Design decisions
popovervibrancy material, wired over IPC and ordered so switching designs at runtime never flashes black; the material also follows the app's light/dark mode vianativeThemesync. Other platforms fall back to CSSbackdrop-filter.data-color-modeboundary, so components stay stock Primer and the entire language lives inApp.css.Validation
tsc, lint and format clean.New concepts
Theme tokens that re-resolve per language (Tailwind
@theme inline)The radius/shadow/tint utilities are backed by plain CSS variables (
--gitify-*) that each design language re-points under its own[data-theme]scope. Declaring them with@theme inline(instead of@theme) makes Tailwind re-resolve the utilities against the active scope rather than freezing them at:root.This is why one component tree can serve two languages with no JS branching: the swap is a single attribute on the root. Reach for it when a whole token layer swaps at once; for one-off per-component tweaks, a direct class is simpler.
Note: I now fully prefer this theme 👀