feat: wip tui application

This commit is contained in:
l.weber 2025-12-06 11:01:11 +01:00
parent a161b86c9a
commit 5d7e9d79c4
7 changed files with 286 additions and 0 deletions

47
tui/app.go Normal file
View file

@ -0,0 +1,47 @@
package tui
import (
"strings"
tea "github.com/charmbracelet/bubbletea"
)
type (
AppModel struct{
Size Size
Header HeaderModel
Screen tea.Model
}
)
func NewApp() AppModel {
return AppModel{
Header: NewHeader(),
Screen: NewHomeScreen(),
}
}
func (m AppModel) Init() tea.Cmd {
return nil
}
func (m AppModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd, headerCmd, screenCmd tea.Cmd
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.Size = NewSizeFromWindow(msg)
}
m.Header, headerCmd = m.Header.Update(msg)
m.Screen, screenCmd = m.Screen.Update(msg)
return m, tea.Batch(cmd, headerCmd, screenCmd)
}
func (m AppModel) View() string {
return strings.Join([]string{
m.Header.View(),
m.Screen.View(),
}, "\n")
}

7
tui/args.go Normal file
View file

@ -0,0 +1,7 @@
package tui
type (
Args struct{
}
)

114
tui/header.go Normal file
View file

@ -0,0 +1,114 @@
package tui
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
type (
HeaderModel struct{
Tabs []HeaderTabModel
Width int
}
HeaderTabModel struct{
Current bool
Name string
Unread int
}
)
func NewHeader() HeaderModel {
return HeaderModel{
Tabs: []HeaderTabModel {
NewHeaderTab("Home", 10, true),
NewHeaderTab("Notifications", 3, false),
NewHeaderTab("Lists", 5, false),
NewHeaderTab("Private", 0, false),
},
}
}
func NewHeaderTab(name string, unread int, current bool) HeaderTabModel {
return HeaderTabModel{ Name: name, Unread: unread, Current: current }
}
var (
activeTabBorder = lipgloss.Border{
Top: "─",
Bottom: " ",
Left: "│",
Right: "│",
TopLeft: "╭",
TopRight: "╮",
BottomLeft: "┘",
BottomRight: "└",
}
tabBorder = lipgloss.Border{
Top: "─",
Bottom: "─",
Left: "│",
Right: "│",
TopLeft: "╭",
TopRight: "╮",
BottomLeft: "┴",
BottomRight: "┴",
}
headerTabStyle = lipgloss.NewStyle().
Border(tabBorder, true)
activeHeaderTabStyle = headerTabStyle.
Border(activeTabBorder, true)
)
func (m HeaderModel) Init() tea.Cmd {
return nil
}
func (m HeaderModel) Update(msg tea.Msg) (HeaderModel, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case Size:
m.Width = msg.Width
}
return m, cmd
}
func (m HeaderModel) View() string {
header := lipgloss.NewStyle().
Padding(1, 0).
Align(lipgloss.Center).
Width(m.Width)
renderedTabs := make([]string, len(m.Tabs))
for i, tab := range m.Tabs {
renderedTabs[i] = tab.View()
}
return header.Render(renderedTabs...)
}
func (m HeaderTabModel) Init() tea.Cmd {
return nil
}
func (m HeaderTabModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
return m, cmd
}
func (m HeaderTabModel) View() string {
content := lipgloss.JoinHorizontal(lipgloss.Center, m.Name, fmt.Sprintf("(%d)", m.Unread))
if m.Current {
return lipgloss.NewStyle().Underline(true).Render(content)
}
return content
}

53
tui/home.go Normal file
View file

@ -0,0 +1,53 @@
package tui
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
type (
HomeScreenModel struct{
Size Size
}
)
func NewHomeScreen() HomeScreenModel {
return HomeScreenModel{}
}
func (m HomeScreenModel) Init() tea.Cmd {
return nil
}
func (m HomeScreenModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl-c":
cmd = tea.Quit
}
case Size:
m.Size = msg
}
return m, cmd
}
func (m HomeScreenModel) View() string {
header := lipgloss.NewStyle().
Align(lipgloss.Center).
Width(m.Size.Width).
SetString(fmt.Sprintf("Home\n%s", "@example@mastodon.social"))
window := lipgloss.NewStyle().
Width(m.Size.Width).
Height(m.Size.Height)
return window.Render(
header.Render(),
)
}

15
tui/size.go Normal file
View file

@ -0,0 +1,15 @@
package tui
import tea "github.com/charmbracelet/bubbletea"
type Size struct{
Width, Height int
}
func NewSize(width, height int) Size {
return Size { Width: width, Height: height }
}
func NewSizeFromWindow(size tea.WindowSizeMsg) Size {
return Size { Width: size.Width, Height: size.Height }
}

10
tui/start.go Normal file
View file

@ -0,0 +1,10 @@
package tui
import tea "github.com/charmbracelet/bubbletea"
func Start(args Args) error {
app := NewApp()
program := tea.NewProgram(app, tea.WithAltScreen())
_, err := program.Run()
return err
}