Phase 5: TUI client (Bubbletea)
- cmd/tui/main.go: entry point with --server, --token, --version flags
- cmd/tui/config.go: config from ~/.config/dumpster/config.yaml or env vars
- cmd/tui/auth.go: login flow, session cookie management
- cmd/tui/api.go: HTTP client for servers, channels, messages, voice
- cmd/tui/model.go: root bubbletea model with state management
- cmd/tui/theme.go: Gruvbox dark lipgloss styles
- cmd/tui/servers.go: server bar with [D] style initials
- cmd/tui/channels.go: channel list with #text and 🔊 voice
- cmd/tui/chat.go: IRC-style message viewport with colored usernames
- cmd/tui/input.go: message input with > _ prompt
- cmd/tui/members.go: member list with ●/◐/○ status
- cmd/tui/ws.go: WebSocket client for real-time events
- cmd/tui/voice.go: voice state tracking and mute toggle
- cmd/tui/keys.go: vim-style keybindings (j/k, g/G, Tab, /, etc)
- cmd/tui/views.go: multi-pane layout rendering
- Makefile: added build-tui and run-tui targets
- go.mod/go.sum: added charmbracelet dependencies
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
package main
|
||||
|
||||
import "github.com/charmbracelet/lipgloss"
|
||||
|
||||
// Gruvbox dark palette
|
||||
var (
|
||||
bg = lipgloss.Color("#282828")
|
||||
bgS = lipgloss.Color("#3c3836")
|
||||
bgT = lipgloss.Color("#504945")
|
||||
fg = lipgloss.Color("#ebdbb2")
|
||||
fgS = lipgloss.Color("#d5c4a1")
|
||||
fgF = lipgloss.Color("#a89984")
|
||||
red = lipgloss.Color("#fb4934")
|
||||
grn = lipgloss.Color("#b8bb26")
|
||||
org = lipgloss.Color("#fe8019")
|
||||
aqua = lipgloss.Color("#8ec07c")
|
||||
yel = lipgloss.Color("#fabd2f")
|
||||
)
|
||||
|
||||
// Styles
|
||||
var (
|
||||
// Layout panes
|
||||
ServerBarStyle = lipgloss.NewStyle().
|
||||
Background(bgS).
|
||||
Foreground(fg).
|
||||
Padding(0, 1).
|
||||
Border(lipgloss.NormalBorder(), false, true, false, false).
|
||||
BorderForeground(bgT)
|
||||
|
||||
ChannelListStyle = lipgloss.NewStyle().
|
||||
Background(bgS).
|
||||
Foreground(fg).
|
||||
Padding(0, 1)
|
||||
|
||||
ChatPaneStyle = lipgloss.NewStyle().
|
||||
Background(bg).
|
||||
Foreground(fg).
|
||||
Padding(0, 1)
|
||||
|
||||
MemberListStyle = lipgloss.NewStyle().
|
||||
Background(bgS).
|
||||
Foreground(fg).
|
||||
Padding(0, 1)
|
||||
|
||||
InputPaneStyle = lipgloss.NewStyle().
|
||||
Background(bgS).
|
||||
Foreground(fg).
|
||||
Padding(0, 1)
|
||||
|
||||
// Focus indicators
|
||||
FocusedBorder = lipgloss.NewStyle().
|
||||
Border(lipgloss.NormalBorder(), false, false, true, false).
|
||||
BorderForeground(aqua)
|
||||
|
||||
UnfocusedBorder = lipgloss.NewStyle().
|
||||
Border(lipgloss.NormalBorder(), false, false, true, false).
|
||||
BorderForeground(bgT)
|
||||
|
||||
// Server list
|
||||
ServerActive = lipgloss.NewStyle().
|
||||
Background(aqua).
|
||||
Foreground(bg).
|
||||
Bold(true).
|
||||
Padding(0, 1).
|
||||
Align(lipgloss.Center)
|
||||
|
||||
ServerInactive = lipgloss.NewStyle().
|
||||
Background(bgS).
|
||||
Foreground(fgF).
|
||||
Padding(0, 1).
|
||||
Align(lipgloss.Center)
|
||||
|
||||
ServerHover = lipgloss.NewStyle().
|
||||
Background(bgT).
|
||||
Foreground(fg).
|
||||
Padding(0, 1).
|
||||
Align(lipgloss.Center)
|
||||
|
||||
// Channel list
|
||||
CategoryStyle = lipgloss.NewStyle().
|
||||
Foreground(fgF).
|
||||
Bold(true).
|
||||
PaddingTop(1)
|
||||
|
||||
ChannelActive = lipgloss.NewStyle().
|
||||
Foreground(fg).
|
||||
Bold(true).
|
||||
PaddingLeft(1)
|
||||
|
||||
ChannelInactive = lipgloss.NewStyle().
|
||||
Foreground(fgF).
|
||||
PaddingLeft(1)
|
||||
|
||||
ChannelHover = lipgloss.NewStyle().
|
||||
Foreground(fg).
|
||||
PaddingLeft(1)
|
||||
|
||||
VoiceChannelPrefix = lipgloss.NewStyle().Foreground(aqua)
|
||||
TextChannelPrefix = lipgloss.NewStyle().Foreground(fgF)
|
||||
|
||||
// Chat
|
||||
MessageStyle = lipgloss.NewStyle().
|
||||
Foreground(fg)
|
||||
|
||||
TimestampStyle = lipgloss.NewStyle().
|
||||
Foreground(fgF)
|
||||
|
||||
UsernameStyle = lipgloss.NewStyle().
|
||||
Bold(true)
|
||||
|
||||
MentionStyle = lipgloss.NewStyle().
|
||||
Foreground(aqua).
|
||||
Bold(true)
|
||||
|
||||
EditedTag = lipgloss.NewStyle().
|
||||
Foreground(fgF).
|
||||
Italic(true)
|
||||
|
||||
// Status indicators
|
||||
StatusOnline = lipgloss.NewStyle().Foreground(grn)
|
||||
StatusIdle = lipgloss.NewStyle().Foreground(yel)
|
||||
StatusOffline = lipgloss.NewStyle().Foreground(fgF)
|
||||
|
||||
// Voice
|
||||
VoiceStatusStyle = lipgloss.NewStyle().
|
||||
Background(lipgloss.Color("#1d2021")).
|
||||
Foreground(aqua).
|
||||
Padding(0, 1)
|
||||
|
||||
// Error/success
|
||||
ErrorStyle = lipgloss.NewStyle().
|
||||
Foreground(red).
|
||||
Bold(true)
|
||||
|
||||
SuccessStyle = lipgloss.NewStyle().
|
||||
Foreground(grn).
|
||||
Bold(true)
|
||||
|
||||
// Help
|
||||
HelpStyle = lipgloss.NewStyle().
|
||||
Foreground(fgF).
|
||||
Italic(true)
|
||||
|
||||
// Title
|
||||
TitleStyle = lipgloss.NewStyle().
|
||||
Foreground(aqua).
|
||||
Bold(true).
|
||||
Align(lipgloss.Center)
|
||||
)
|
||||
|
||||
// UsernameColor returns a deterministic color for a username based on its content.
|
||||
func UsernameColor(username string) lipgloss.Color {
|
||||
colors := []lipgloss.Color{red, grn, org, aqua, yel, lipgloss.Color("#d3869b"), lipgloss.Color("#83a598")}
|
||||
hash := 0
|
||||
for _, c := range username {
|
||||
hash += int(c)
|
||||
}
|
||||
return colors[hash%len(colors)]
|
||||
}
|
||||
Reference in New Issue
Block a user