Source of truth for visual consistency. Extracted from
internal/ui/styles/styles.go,AGENTS.md, and page Views.
Default: neon (see styles.go:ApplyTheme).
| Token | Value | Usage |
|---|---|---|
ColorPrimary |
#BF40FF neon purple |
Title, focused border, selection ▸ |
ColorBg |
#000000 |
Background |
ColorCardBg |
#1E1B2E |
Card/box background |
ColorSuccess |
#10B981 green |
Synced, Mining, running border |
ColorWarning |
#F59E0B orange |
Syncing, Stopped |
ColorError |
#EF4444 |
Errors / Rejected >0 |
ColorAccent |
#06B6D4 cyan |
Threads, accent |
ColorSecondary |
muted purple | Secondary highlights |
ColorBorder |
muted gray | Box border (inactive) |
ColorText |
white | Primary text |
ColorMuted |
gray | Labels, footer hints |
Width |
80 |
Outer box width (ThemedBoxStyle) |
InputWidth |
60 |
components.Input width (ti.SetWidth(56)) |
Styles: TitleStyle (Primary Bold), MutedStyle, TextStyle, Success/Warning/Error/AccentStyle, BoxStyle (RoundedBorder), ThemedBoxStyle, InputStyle/Focused/Disabled, HeaderStyle.
- Centering: All pages center via
lipgloss.Place(width, height, lipgloss.Center, lipgloss.Center, content)–width/heightfromtea.WindowSizeMsg(m.width/m.height), fallback80×24. Miner fixed to centered (was left-aligned). - Box:
ThemedBoxStyle().Width(Width).Padding(2,4)– inner content72wide. When mining,BorderForeground(ColorSuccess)elseColorBorder. - Header/Footer: No global top bar. Daemon shown once inside page (
Mining via …footer in miner). Footer:AccentStyle(k) + MutedStyle(label)joined by•, single line, responsive truncation.
Rows built as []string then strings.Join(rows, "\n") inside box.
- Label:
MutedStyle.Render("Label: ") - Value: per Option C (status-driven) – see §6.
- Truncation:
truncatePlain(addr, 56)+…for long hashes/addresses.
- Input:
components.NewInput(label, placeholder, false)–labelrendered above input (label+"\n"+input).InputStylevsFocusedInputStyle(Primary border). Do not doMuted("Label: ")+input.View()inline – breaks border. Miner usesNewInput("Address", "dero1…", false)+rows=append(rows, input.View()). - Keys:
key.NewBinding(key.WithKeys("s"))etc. Footer showsS Start • ←/→ Threads • A Edit Address • C Copy • / Commands • Esc Back– responsive: dropC Copythen abbreviateEdit Address→Edit,Commands→Cmdwhenlipgloss.Width(joined) > availWidth.
type Model struct { page Page; width, height int; wallet ...; miner pages.MinerModel ... }
func (m Model) View() tea.View {
var content string
switch m.page { case PageMiner: content = m.miner.View() ... }
// palette overlay, debug, then return tea.NewView(content)
}Each pages/*.go follows New / Init / Update(msg tea.Msg) / View() string; Update handles tea.WindowSizeMsg and tea.KeyPressMsg; View returns centered box.
- Default threads:
maxThreads-2(min 1) –internal/ui/pages/miner.go:NewMiner(). - Visual (single): Spinner only on
Status:line viarenderStatus()→SuccessStyle(spinner+" Mining")wherespinner = [⠋…⠏][frame%10]tick 180ms (SpinnerTickMsg). Title staticMiner. Green border whenRunning. - Value colors (C):
Status: Stopped→Warningorange;Status: ∴ Mining→SuccessgreenThreads: 30/32→Accentcyan (always)Hashrate:→Successif>0elseMutedMinis/Blocks:→Successif>0elseMutedRejected:→Errorred if>0elseMutedTotal Hashes, Height, Difficulty, Uptime→Textwhite (orMutedwhen 0)
- Address:
Addresslabel viacomponents.Input(label "Address"),Viewshowsinput.View()wheneditingAddresselserenderAddress()truncated.a/eedit,entersave (validaterpc.NewAddress,config.SetLastMiningAddress),esccancel,ccopy. Threads←/→disabled whenRunning. - Daemon: Shown once as footer
Mining via <host>(fromm.miner.DaemonHostfallbackOpts.DaemonAddress), not in top bar. - Footer: Single line,
availWidth = m.width-8(fallback 80), dropC Copyfirst, then abbreviate,lipgloss.Widthcheck.
go vet ./.../go test ./...- Manual:
/minercentered like/send//daemon,Status: ∴ Miningspinner only, values colored per C, footer 1 line at 80 and 60 cols, address textbox clean.