Skip to content

Feat/brand theme - #8

Merged
sam0uly merged 7 commits into
mainfrom
feat/brand-theme
Jul 27, 2026
Merged

Feat/brand theme#8
sam0uly merged 7 commits into
mainfrom
feat/brand-theme

Conversation

@sam0uly

@sam0uly sam0uly commented Jul 27, 2026

Copy link
Copy Markdown
Owner

This PR replaces the default terminal colors throughout spin with a consistent orange and warm-gray brand palette that adapts to the user's terminal background at startup.

The colors are pre-resolved once at startup using lipgloss.LightDark plus lipgloss.HasDarkBackground instead of tracking BackgroundColorMsg at runtime. This eliminates hasDarkBg fields, style regeneration, and message handling that was previously spread across models.

What changed:

  • New internal/theme/ package (160 lines) containing the full brand palette, pre-resolved semantic tokens, Huh theme, fang color scheme, list styles, and convenience helpers

  • All huh.NewForm calls replaced with theme.NewForm() so prompt forms inherit the brand palette automatically

  • main.go uses theme.FangColorScheme for branded --help output

  • cmd/new_tui.go and cmd/hooks_tui.go use pre-resolved colors for all custom styles and view backgrounds instead of tracking isDark per model or using the compat package

  • cmd/print.go and cmd/hook_output.go use theme.Accent and theme.TextDimmed for headers and body text

  • Footer keybinding hints now match the same accent/muted color scheme as Huh help text

The semantic tokens (Accent, Text, TextMuted, TextDimmed, StatusError, StatusSuccess, StatusInfo) resolve adaptively at startup so the same binary looks correct on both light and dark terminals.

sam0uly added 7 commits July 27, 2026 01:05
Central color source for the orange/warm-gray brand palette. Semantic
tokens (Accent, Text, Status*) are pre-resolved at startup for the
terminal's dark/light background using lipgloss.LightDark.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-free
Apply the orange/warm-gray color scheme to fang's --help rendering
via FangColorScheme.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-free
Apply theme.Accent for headers and theme.TextDimmed for table borders
and hint text.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-free
Apply theme.Accent for hook step headers and theme.TextDimmed for
hook body text.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-free
Replace direct huh.NewForm calls with theme.NewForm() so all six
prompt forms inherit the orange/warm-gray brand palette.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-free
Apply adaptive orange/warm-gray colors to the interactive scaffolding
form and status panel. Pre-resolve adaptive colors at startup instead
of tracking BackgroundColorMsg at runtime.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-free
Apply adaptive orange/warm-gray colors to the hook list, delegate
styles, and view background. Remove manual hasDarkBg tracking in
favor of pre-resolved adaptive colors at startup.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-free
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a shared runtime-aware theme package and applies it to HUH forms, project and hook TUIs, hook output, printed output, and Fang command rendering. Existing prompt behavior and command flow remain unchanged.

Changes

Shared theme integration

Layer / File(s) Summary
Shared theme foundation
internal/theme/theme.go
Defines runtime-aware colors plus reusable HUH, spinner, Fang, and list styling helpers.
Themed interactive prompts
cmd/new_prompts.go
Routes project setup prompts through the shared themed form constructor without changing prompt options or cancellation behavior.
Project TUI theme wiring
cmd/new_tui.go
Applies shared colors and form themes to project titles, status sections, footers, boundaries, error frames, and alternate-screen backgrounds.
Hook interface theming
cmd/hook_output.go, cmd/hooks_tui.go
Applies shared theme colors and list styles to hook output, completion messages, panes, boundaries, and modal actions.
CLI output theme wiring
cmd/print.go, main.go
Uses shared theme colors for printed output and configures Fang with the shared color scheme.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • N1xev/spin#6: Introduces the hooks TUI code whose output and interface styling are updated here.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title matches the main change: introducing a shared brand/theme system across the CLI UI.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/brand-theme

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
cmd/new_tui.go (1)

93-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse theme.NewForm here.

This duplicates the wrapper already centralized in internal/theme.NewForm, allowing this form to diverge from the other themed prompts over time.

Proposed refactor
-	m.form = huh.NewForm(huh.NewGroup(fields...)).
-		WithTheme(huh.ThemeFunc(func(_ bool) *huh.Styles { return theme.Theme() })).
+	m.form = theme.NewForm(huh.NewGroup(fields...)).
 		WithWidth(min(m.width/2, 60)).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/new_tui.go` around lines 93 - 95, Update the form construction in the new
TUI setup to use the centralized theme.NewForm wrapper instead of directly
calling huh.NewForm with WithTheme. Preserve the existing fields and width
configuration while removing the duplicated theme setup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/theme/theme.go`:
- Around line 15-16: Remove the import-time lipgloss.HasDarkBackground call that
initializes isDark/ld in the theme package. Thread the runtime dark-mode value
through Theme and NewForm, use Huh’s isDark callback argument when constructing
the form theme, and handle tea.BackgroundColorMsg in the Bubble Tea loop if
background changes must update the UI.

---

Nitpick comments:
In `@cmd/new_tui.go`:
- Around line 93-95: Update the form construction in the new TUI setup to use
the centralized theme.NewForm wrapper instead of directly calling huh.NewForm
with WithTheme. Preserve the existing fields and width configuration while
removing the duplicated theme setup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 560500f4-60b3-49dd-bc18-e7c522f2c874

📥 Commits

Reviewing files that changed from the base of the PR and between ef7a96c and 2b0fab0.

📒 Files selected for processing (7)
  • cmd/hook_output.go
  • cmd/hooks_tui.go
  • cmd/new_prompts.go
  • cmd/new_tui.go
  • cmd/print.go
  • internal/theme/theme.go
  • main.go

Comment thread internal/theme/theme.go
Comment on lines +15 to +16
isDark = lipgloss.HasDarkBackground(os.Stdin, os.Stdout)
ld = lipgloss.LightDark(isDark)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate import-time background probes and theme callbacks that ignore runtime mode.
rg -n --glob '*.go' \
  'HasDarkBackground\(|ThemeFunc\(func\(_ bool\)|RequestBackgroundColor|BackgroundColorMsg' .

Repository: N1xev/spin

Length of output: 446


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the theme implementation and the TUI caller for runtime background handling.
printf '\n== internal/theme/theme.go ==\n'
sed -n '1,220p' internal/theme/theme.go

printf '\n== cmd/new_tui.go ==\n'
sed -n '1,160p' cmd/new_tui.go

printf '\n== search for background-color handling ==\n'
rg -n --glob '*.go' 'BackgroundColorMsg|RequestBackgroundColor|SetColorProfile|HasDarkBackground|WithTheme\(huh.ThemeFunc|Theme\(\)' .

Repository: N1xev/spin

Length of output: 10957


🌐 Web query:

lipgloss HasDarkBackground terminal.go query stdin stdout wait behavior Huh ThemeFunc isDark runtime argument

💡 Result:

In Charmbracelet libraries, detection and handling of terminal background colors are managed via specific functions in Lip Gloss and Huh. Lip Gloss HasDarkBackground The HasDarkBackground function in Lip Gloss (charm.land/lipgloss) detects whether a terminal has a light or dark background [1][2][3]. Standalone Usage: When not using Bubble Tea, you can perform manual detection by passing input and output files [1][4][5]: hasDarkBG:= lipgloss.HasDarkBackground(os.Stdin, os.Stdout) Detection Behavior: This function returns a boolean. By default, it returns true if an error is encountered during the detection process [1][2]. Bubble Tea Integration: In a Bubble Tea application, you should instead listen for tea.BackgroundColorMsg in your Update function and use the msg.IsDark method [1][6]. Thread Safety/Caching: The renderer maintains cached background detection states. Thread-safe functions like SetHasDarkBackground(b bool) exist primarily for testing purposes to override automatic detection [3]. Huh ThemeFunc and isDark In Huh (github.com/charmbracelet/huh), theme handling has been updated in v2.0.0 [7][8][9]. ThemeFunc Signature: Custom themes now use the ThemeFunc signature, which accepts a boolean argument to indicate whether the background is dark [10][7][9]: type ThemeFunc func(isDark bool) Styles Built-in Themes: All built-in themes (e.g., ThemeCharm, ThemeDracula) now require this bool parameter [8][9]. You typically pass the result of a detection function to these themes [9]: isDark:= lipgloss.HasDarkBackground form:= huh.NewForm(...).WithTheme(huh.ThemeCharm(isDark)) Summary of Behavior The core pattern across both libraries is to determine the terminal background state as a boolean (isDark) and pass this state explicitly into layout or styling functions (like lipgloss.LightDark or huh.Theme functions) to ensure the UI adapts correctly to the user's environment [5][6][9].

Citations:


Avoid import-time terminal background detection
HasDarkBackground(os.Stdin, os.Stdout) runs during package init and can block or emit terminal-query bytes before the UI starts. Thread isDark into Theme/NewForm instead, and handle tea.BackgroundColorMsg in the Bubble Tea loop if the TUI needs to react to background changes. NewForm also ignores Huh’s isDark callback arg, so the form theme is fixed at import time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/theme/theme.go` around lines 15 - 16, Remove the import-time
lipgloss.HasDarkBackground call that initializes isDark/ld in the theme package.
Thread the runtime dark-mode value through Theme and NewForm, use Huh’s isDark
callback argument when constructing the form theme, and handle
tea.BackgroundColorMsg in the Bubble Tea loop if background changes must update
the UI.

@sam0uly
sam0uly merged commit d337e41 into main Jul 27, 2026
3 checks passed
@sam0uly
sam0uly deleted the feat/brand-theme branch July 27, 2026 02:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant