clone

fifteen puzzle games for the terminal, with daily puzzles, weekly ladders and xp, built on bubble tea

bug/architecture-test-trim-path
puzzletea / game / border.go
border.go 2.3K
1package game23import (4 "image/color"5 "strings"67 "charm.land/lipgloss/v2"8 "github.com/FelineStateMachine/puzzletea/theme"9)1011// GridBorderColors holds the color configuration for a grid border with12// crosshair and solved-state highlighting.13type GridBorderColors struct {14 BorderFG color.Color15 BackgroundBG color.Color16 CrosshairBG color.Color17 SolvedBorderFG color.Color18 SolvedBG color.Color19}2021func borderColors(colors GridBorderColors, solved bool, bg color.Color) (color.Color, color.Color) {22 fg := colors.BorderFG23 background := bg2425 if solved {26 fg = colors.SolvedBorderFG27 }2829 if background == nil {30 background = colors.BackgroundBG31 if solved {32 background = colors.SolvedBG33 }34 return fg, background35 }3637 // Tinted bridge/crosshair backgrounds need a contrast-aware foreground.38 return theme.TextOnBG(background), background39}4041// DefaultBorderColors returns border colors from the active theme.42func DefaultBorderColors() GridBorderColors {43 p := theme.Current()44 return GridBorderColors{45 BorderFG: p.Border,46 BackgroundBG: p.BG,47 CrosshairBG: p.Surface,48 SolvedBorderFG: p.SuccessBorder,49 SolvedBG: p.SuccessBG,50 }51}5253// BorderChar renders a single border character with optional crosshair highlighting.54func BorderChar(ch string, colors GridBorderColors, solved, highlight bool) string {55 bg := color.Color(nil)56 if highlight && !solved {57 bg = colors.CrosshairBG58 }59 fg, bg := borderColors(colors, solved, bg)60 return lipgloss.NewStyle().Foreground(fg).Background(bg).Render(ch)61}6263// HBorderRow builds a horizontal border row (top or bottom) with per-column64// crosshair highlighting. cellWidth is the visual width of each cell.65func HBorderRow(w, cursorX, cellWidth int, left, right string, colors GridBorderColors, solved bool) string {66 var parts []string67 parts = append(parts, BorderChar(left, colors, solved, false))68 segment := strings.Repeat("─", cellWidth)69 for x := range w {70 highlight := !solved && x == cursorX71 bg := color.Color(nil)72 if highlight {73 bg = colors.CrosshairBG74 }75 fg, bg := borderColors(colors, solved, bg)76 s := lipgloss.NewStyle().Foreground(fg).Background(bg)77 parts = append(parts, s.Render(segment))78 }79 parts = append(parts, BorderChar(right, colors, solved, false))80 return lipgloss.JoinHorizontal(lipgloss.Top, parts...)81}