Adapt theme colors to light and dark terminals#149
Open
skarim wants to merge 2 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR makes the submit, view, and modify interactive TUIs readable on both light and dark terminal backgrounds. Previously colors were hardcoded ANSI indices tuned only for dark terminals (e.g. ANSI white was invisible on light backgrounds, accents were low-contrast). It introduces a centralized, background-aware palette of lipgloss.AdaptiveColor roles and migrates every hardcoded color across shared/, submitview/, and modifyview/ to it.
Changes:
- New
internal/tui/shared/theme.godefines a semantic, GitHub Primer-inspired palette (text/muted/faint, border, accent, PR-state, badge, button, switch) usinglipgloss.AdaptiveColor, plusApplyThemeOverride()honoringGH_STACK_THEME=auto|light|dark, wired via the root command'sPersistentPreRun. - Replaces hardcoded ANSI colors with palette roles everywhere; status icons now render at use-time so adaptive colors resolve against the detected background, and the markdown preview picks glamour's light/dark style from
lipgloss.HasDarkBackground(). - Adds tests (
theme_test.go) verifying the palette differs by background and thatGH_STACK_THEMEis honored, plus README and CLI docs.
Show a summary per file
| File | Description |
|---|---|
internal/tui/shared/theme.go |
New adaptive palette + ApplyThemeOverride() for GH_STACK_THEME. |
internal/tui/shared/theme_test.go |
Tests palette background-awareness and theme override. |
internal/tui/shared/styles.go |
Migrates branch/PR/diff/connector/header styles to palette; icons rendered at use-time. |
internal/tui/shared/render.go |
StatusIcon renders glyph+style at use-time instead of pre-rendered icons. |
internal/tui/shared/header.go |
Disabled-shortcut style uses ColorTextFaint. |
internal/tui/submitview/styles.go |
State fg/bg, chrome, switch, segment styles moved to palette; Color() returns TerminalColor. |
internal/tui/submitview/screen.go |
Branch circle/name/checkbox + left panel border use palette. |
internal/tui/submitview/editor.go |
Field/desc box borders use palette accent/border. |
internal/tui/submitview/render.go |
Chrome + "new PRs" highlight use palette. |
internal/tui/submitview/preview.go |
Selects light/dark glamour style from detected background. |
internal/tui/submitview/help.go |
Help overlay styles use palette. |
internal/tui/modifyview/styles.go |
Action/connector/status/help/transient styles use palette. |
internal/tui/modifyview/model.go |
Pending-summary icon uses ColorYellow. |
cmd/root.go |
PersistentPreRun applies the theme override before any render. |
README.md, docs/.../cli.md |
Document GH_STACK_THEME and auto-adaptation behavior. |
Review details
- Files reviewed: 16/16 changed files
- Comments generated: 0
- Review effort level: Medium
The submit, view, and modify TUIs were tuned for dark terminals. On light or solarized-light backgrounds the result was hard to read and inverted: primary text used ANSI white (invisible on white), dim chrome used light grays (too faint), and accents used bright cyan (low contrast) — so "active" things looked lighter than "disabled" ones. Introduce a centralized, background-aware color palette and migrate all three TUIs to it: - internal/tui/shared/theme.go: a semantic palette of lipgloss.AdaptiveColor values (primary/muted/faint text, chrome/border, accent, PR-state colors, badge backgrounds, row shade, button, switch). lipgloss resolves the light/dark variant per render from the terminal background, which Bubble Tea detects at startup; terminals that don't report it fall back to dark, preserving the original look. - Replace every hardcoded ANSI color in shared/, submitview/, and modifyview/ with palette roles. The four pre-rendered status icons now render at use-time so their adaptive colors resolve correctly. The submit markdown preview picks glamour's light or dark style from the detected background. - GH_STACK_THEME=auto|light|dark forces the palette for terminals that mis-detect (some SSH/tmux setups); wired via the root command's PersistentPreRun before any render. Documented in the README and CLI docs. Neutral text/chrome use truecolor hex (GitHub Primer-inspired) for predictability across themes, including solarized which repurposes ANSI 8-15; lipgloss downsamples on terminals without truecolor. Tests verify the palette resolves differently for light vs dark and that GH_STACK_THEME is honored.
d9ed2c3 to
6a41f54
Compare
Background detection and the GH_STACK_THEME override (added for the TUIs)
only affected the interactive screens. Plain command output -- status
messages and interactive prompts -- went through the mgutz/ansi library
with fixed ANSI palette names (green/red/yellow/cyan/...), so it never
adapted to the terminal background and could read poorly on light or
solarized themes.
Unify everything on the same adaptive palette so all colors react to the
detected background and to GH_STACK_THEME.
- Extract internal/theme, a foundational package with no internal
dependencies, that owns:
- the background-aware lipgloss.AdaptiveColor palette (moved out of
internal/tui/shared),
- ApplyOverride(), the GH_STACK_THEME=auto|light|dark logic, and
- non-TUI colorizers (Success/Error/Warning/Blue/Magenta/Cyan/Gray/
Bold) plus FgSeqs(), which returns the raw start/reset escapes used
to color the user's echoed prompt input.
- internal/tui/shared/theme.go now re-exports the palette, so the TUI code
keeps referring to shared.ColorX unchanged.
- internal/config/config.go wires the Config.Color* funcs to the theme
colorizers and drops mgutz/ansi (now an indirect dependency only).
- cmd/utils.go colors the prompt icon and echoed input via theme.
- cmd/root.go calls theme.ApplyOverride() in PersistentPreRun.
Detection adds no cost: because the command package imports Bubble Tea,
its init() already triggers (and caches) the terminal background query for
every command, so the non-TUI colorizers just read the cached value.
Terminals that don't answer the query fall back to the dark palette;
GH_STACK_THEME=light|dark forces it. Colors are truecolor on capable
terminals and downsample to the nearest ANSI color elsewhere.
Tests: internal/theme covers palette adaptiveness, ApplyOverride, the
colorizers, and FgSeqs; a new internal/config test verifies the wired-up
Config.Color* funcs adapt to the background when color is enabled.
Docs: README and the CLI reference note that GH_STACK_THEME now controls
all colored output, not just the interactive screens.
No behavior change beyond colors.
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
gh-stack's colors — both the interactive TUIs (
submit,view,modify) and plain command output (status messages, prompts) — were tuned for dark terminals. On light or solarized backgrounds they read poorly: TUI text used ANSI white (invisible on white) with inverted emphasis, and command output used fixed ANSI palette colors that never adapted.This PR introduces one background-aware color palette and uses it everywhere:
internal/theme: a foundational package holding the adaptivelipgloss.AdaptiveColorpalette (semantic roles: text/muted/faint, chrome, accent, PR-state colors, …), theGH_STACK_THEMEoverride, and colorizers for plain output. lipgloss resolves the light/dark variant per render from the detected terminal background; terminals that don't report it fall back to dark, preserving the original look.submit/view/modify): every hardcoded ANSI color becomes a palette role; pre-rendered status icons render at use-time, and the submit markdown preview picks glamour's light/dark style.configand the prompt helpers dropmgutz/ansiand color via the shared palette, so success/error/warning messages and prompts adapt too.GH_STACK_THEME=auto|light|darkforces the palette for terminals that mis-detect (some SSH/tmux setups). Detection is free — Bubble Tea's startup background query (already run for every command) is cached.Neutral colors use truecolor hex (GitHub Primer-inspired) for consistency across themes including solarized, which repurposes ANSI 8–15; lipgloss downsamples on terminals without truecolor. Tests cover the palette's light/dark resolution, the
GH_STACK_THEMEoverride, and that command output colors adapt.Stack created with GitHub Stacks CLI • Give Feedback 💬