mirror of
https://github.com/mrusme/neonmodem.git
synced 2025-01-03 14:56:41 -05:00
Implemented Theme, refactored UI style
This commit is contained in:
parent
61ed9fde70
commit
54e8f53b77
102
config/config.go
102
config/config.go
@ -5,6 +5,7 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
@ -24,11 +25,46 @@ type SystemConfig struct {
|
||||
Config map[string]interface{}
|
||||
}
|
||||
|
||||
type ThemeItemConfig struct {
|
||||
Foreground lipgloss.AdaptiveColor
|
||||
Background lipgloss.AdaptiveColor
|
||||
Border struct {
|
||||
Foreground lipgloss.AdaptiveColor
|
||||
Background lipgloss.AdaptiveColor
|
||||
Border lipgloss.Border
|
||||
Sides []bool
|
||||
}
|
||||
Padding []int
|
||||
Margin []int
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Debug bool
|
||||
Log string
|
||||
|
||||
Systems []SystemConfig
|
||||
|
||||
Theme struct {
|
||||
DialogBox struct {
|
||||
Window ThemeItemConfig
|
||||
Titlebar ThemeItemConfig
|
||||
Bottombar ThemeItemConfig
|
||||
}
|
||||
|
||||
PostsList struct {
|
||||
List ThemeItemConfig
|
||||
Item ThemeItemConfig
|
||||
}
|
||||
|
||||
Post struct {
|
||||
Author ThemeItemConfig
|
||||
Subject ThemeItemConfig
|
||||
}
|
||||
|
||||
Reply struct {
|
||||
Author ThemeItemConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Load() (Config, error) {
|
||||
@ -48,6 +84,72 @@ func Load() (Config, error) {
|
||||
viper.SetDefault("Debug", "true")
|
||||
viper.SetDefault("Log", path.Join(cacheDir, "gobbs.log"))
|
||||
|
||||
// PostsList List
|
||||
viper.SetDefault("Theme.PostsList.List.Margin",
|
||||
[]int{0, 0, 0, 0})
|
||||
viper.SetDefault("Theme.PostsList.List.Padding",
|
||||
[]int{1, 1, 1, 1})
|
||||
viper.SetDefault("Theme.PostsList.List.Border.Border",
|
||||
lipgloss.RoundedBorder())
|
||||
viper.SetDefault("Theme.PostsList.List.Border.Sides",
|
||||
[]bool{true, true, true, true},
|
||||
)
|
||||
viper.SetDefault("Theme.PostsList.List.Border.Foreground",
|
||||
lipgloss.AdaptiveColor{Light: "#333333", Dark: "#cccccc"})
|
||||
|
||||
// DialogBox Window
|
||||
viper.SetDefault("Theme.DialogBox.Window.Margin",
|
||||
[]int{0, 0, 0, 0})
|
||||
viper.SetDefault("Theme.DialogBox.Window.Padding",
|
||||
[]int{0, 0, 0, 0})
|
||||
viper.SetDefault("Theme.DialogBox.Window.Border.Border",
|
||||
lipgloss.ThickBorder())
|
||||
viper.SetDefault("Theme.DialogBox.Window.Border.Sides",
|
||||
[]bool{false, true, true, true},
|
||||
)
|
||||
viper.SetDefault("Theme.DialogBox.Window.Border.Foreground",
|
||||
lipgloss.AdaptiveColor{Light: "#333333", Dark: "#cccccc"})
|
||||
|
||||
// DialogBox Titlebar
|
||||
viper.SetDefault("Theme.DialogBox.Titlebar.Margin",
|
||||
[]int{0, 0, 1, 0})
|
||||
viper.SetDefault("Theme.DialogBox.Titlebar.Padding",
|
||||
[]int{0, 1, 0, 1})
|
||||
viper.SetDefault("Theme.DialogBox.Titlebar.Foreground",
|
||||
lipgloss.AdaptiveColor{Light: "#ffffff", Dark: "#000000"})
|
||||
viper.SetDefault("Theme.DialogBox.Titlebar.Background",
|
||||
lipgloss.AdaptiveColor{Light: "#333333", Dark: "#cccccc"})
|
||||
|
||||
// DialogBox Bottombar
|
||||
viper.SetDefault("Theme.DialogBox.Bottombar.Margin",
|
||||
[]int{1, 0, 0, 0})
|
||||
viper.SetDefault("Theme.DialogBox.Bottombar.Padding",
|
||||
[]int{0, 1, 0, 1})
|
||||
viper.SetDefault("Theme.DialogBox.Bottombar.Foreground",
|
||||
lipgloss.AdaptiveColor{Light: "#aaaaaa", Dark: "#999999"})
|
||||
|
||||
// Post Author
|
||||
viper.SetDefault("Theme.Post.Author.Padding",
|
||||
[]int{0, 1, 0, 1})
|
||||
viper.SetDefault("Theme.Post.Author.Foreground",
|
||||
lipgloss.AdaptiveColor{Light: "#F25D94", Dark: "#F25D94"})
|
||||
|
||||
// Post Subject
|
||||
viper.SetDefault("Theme.Post.Subject.Padding",
|
||||
[]int{0, 1, 0, 1})
|
||||
viper.SetDefault("Theme.Post.Subject.Foreground",
|
||||
lipgloss.AdaptiveColor{Light: "#FFFFFF", Dark: "#FFFFFF"})
|
||||
viper.SetDefault("Theme.Post.Subject.Background",
|
||||
lipgloss.AdaptiveColor{Light: "#F25D94", Dark: "#F25D94"})
|
||||
|
||||
// Reply Author
|
||||
viper.SetDefault("Theme.Reply.Author.Padding",
|
||||
[]int{0, 1, 0, 1})
|
||||
viper.SetDefault("Theme.Reply.Author.Foreground",
|
||||
lipgloss.AdaptiveColor{Light: "#000000", Dark: "#00000"})
|
||||
viper.SetDefault("Theme.Reply.Author.Foreground",
|
||||
lipgloss.AdaptiveColor{Light: "#874BFD", Dark: "#874BFD"})
|
||||
|
||||
viper.SetConfigName("gobbs")
|
||||
viper.SetConfigType("toml")
|
||||
viper.AddConfigPath(cfgDir)
|
||||
|
@ -41,10 +41,9 @@ func (post Post) Title() string {
|
||||
|
||||
func (post Post) Description() string {
|
||||
return fmt.Sprintf(
|
||||
"[%s] %s in %s on %s",
|
||||
post.ID,
|
||||
post.Author.Name,
|
||||
"in %s by %s on %s",
|
||||
post.Forum.Name,
|
||||
post.CreatedAt.Format("Jan 2 2006"),
|
||||
post.Author.Name,
|
||||
post.CreatedAt.Format("02 Jan 06 15:04 MST"),
|
||||
)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package ctx
|
||||
import (
|
||||
"github.com/mrusme/gobbs/config"
|
||||
"github.com/mrusme/gobbs/system"
|
||||
"github.com/mrusme/gobbs/ui/theme"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@ -13,6 +14,7 @@ type Ctx struct {
|
||||
Systems []*system.System
|
||||
Loading bool
|
||||
Logger *zap.SugaredLogger
|
||||
Theme *theme.Theme
|
||||
}
|
||||
|
||||
func New(
|
||||
@ -25,6 +27,7 @@ func New(
|
||||
Config: cfg,
|
||||
Loading: false,
|
||||
Logger: logger,
|
||||
Theme: theme.New(cfg),
|
||||
}
|
||||
}
|
||||
|
||||
|
114
ui/theme/theme.go
Normal file
114
ui/theme/theme.go
Normal file
@ -0,0 +1,114 @@
|
||||
package theme
|
||||
|
||||
import (
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/mrusme/gobbs/config"
|
||||
)
|
||||
|
||||
type Theme struct {
|
||||
DialogBox struct {
|
||||
Window lipgloss.Style
|
||||
Titlebar lipgloss.Style
|
||||
Bottombar lipgloss.Style
|
||||
}
|
||||
|
||||
PostsList struct {
|
||||
List lipgloss.Style
|
||||
Item lipgloss.Style
|
||||
}
|
||||
|
||||
Post struct {
|
||||
Author lipgloss.Style
|
||||
Subject lipgloss.Style
|
||||
}
|
||||
|
||||
Reply struct {
|
||||
Author lipgloss.Style
|
||||
}
|
||||
}
|
||||
|
||||
func New(cfg *config.Config) (*Theme) {
|
||||
t := new(Theme)
|
||||
// viewportStyle = lipgloss.NewStyle().
|
||||
// Margin(0, 0, 0, 0).
|
||||
// Padding(0, 0).
|
||||
// BorderTop(false).
|
||||
// BorderLeft(false).
|
||||
// BorderRight(false).
|
||||
// BorderBottom(false)
|
||||
//
|
||||
|
||||
t.PostsList.List = lipgloss.NewStyle().
|
||||
Margin(cfg.Theme.PostsList.List.Margin...).
|
||||
Padding(cfg.Theme.PostsList.List.Padding...).
|
||||
Border(cfg.Theme.PostsList.List.Border.Border, cfg.Theme.PostsList.List.Border.Sides...).
|
||||
BorderForeground(cfg.Theme.PostsList.List.Border.Foreground).
|
||||
BorderBackground(cfg.Theme.PostsList.List.Border.Background).
|
||||
Foreground(cfg.Theme.PostsList.List.Foreground).
|
||||
Background(cfg.Theme.PostsList.List.Background)
|
||||
|
||||
t.PostsList.Item = lipgloss.NewStyle().
|
||||
Margin(cfg.Theme.PostsList.Item.Margin...).
|
||||
Padding(cfg.Theme.PostsList.Item.Padding...).
|
||||
Border(cfg.Theme.PostsList.Item.Border.Border, cfg.Theme.PostsList.Item.Border.Sides...).
|
||||
BorderForeground(cfg.Theme.PostsList.Item.Border.Foreground).
|
||||
BorderBackground(cfg.Theme.PostsList.Item.Border.Background).
|
||||
Foreground(cfg.Theme.PostsList.Item.Foreground).
|
||||
Background(cfg.Theme.PostsList.Item.Background)
|
||||
|
||||
t.DialogBox.Window = lipgloss.NewStyle().
|
||||
Margin(cfg.Theme.DialogBox.Window.Margin...).
|
||||
Padding(cfg.Theme.DialogBox.Window.Padding...).
|
||||
Border(cfg.Theme.DialogBox.Window.Border.Border, cfg.Theme.DialogBox.Window.Border.Sides...).
|
||||
BorderForeground(cfg.Theme.DialogBox.Window.Border.Foreground).
|
||||
BorderBackground(cfg.Theme.DialogBox.Window.Border.Background).
|
||||
Foreground(cfg.Theme.DialogBox.Window.Foreground).
|
||||
Background(cfg.Theme.DialogBox.Window.Background)
|
||||
|
||||
t.DialogBox.Titlebar = lipgloss.NewStyle().
|
||||
Margin(cfg.Theme.DialogBox.Titlebar.Margin...).
|
||||
Padding(cfg.Theme.DialogBox.Titlebar.Padding...).
|
||||
Border(cfg.Theme.DialogBox.Titlebar.Border.Border, cfg.Theme.DialogBox.Titlebar.Border.Sides...).
|
||||
BorderForeground(cfg.Theme.DialogBox.Titlebar.Border.Foreground).
|
||||
BorderBackground(cfg.Theme.DialogBox.Titlebar.Border.Background).
|
||||
Foreground(cfg.Theme.DialogBox.Titlebar.Foreground).
|
||||
Background(cfg.Theme.DialogBox.Titlebar.Background)
|
||||
|
||||
t.DialogBox.Bottombar = lipgloss.NewStyle().
|
||||
Margin(cfg.Theme.DialogBox.Bottombar.Margin...).
|
||||
Padding(cfg.Theme.DialogBox.Bottombar.Padding...).
|
||||
Border(cfg.Theme.DialogBox.Bottombar.Border.Border, cfg.Theme.DialogBox.Bottombar.Border.Sides...).
|
||||
BorderForeground(cfg.Theme.DialogBox.Bottombar.Border.Foreground).
|
||||
BorderBackground(cfg.Theme.DialogBox.Bottombar.Border.Background).
|
||||
Foreground(cfg.Theme.DialogBox.Bottombar.Foreground).
|
||||
Background(cfg.Theme.DialogBox.Bottombar.Background)
|
||||
|
||||
t.Post.Author = lipgloss.NewStyle().
|
||||
Margin(cfg.Theme.Post.Author.Margin...).
|
||||
Padding(cfg.Theme.Post.Author.Padding...).
|
||||
Border(cfg.Theme.Post.Author.Border.Border, cfg.Theme.Post.Author.Border.Sides...).
|
||||
BorderForeground(cfg.Theme.Post.Author.Border.Foreground).
|
||||
BorderBackground(cfg.Theme.Post.Author.Border.Background).
|
||||
Foreground(cfg.Theme.Post.Author.Foreground).
|
||||
Background(cfg.Theme.Post.Author.Background)
|
||||
|
||||
t.Post.Subject = lipgloss.NewStyle().
|
||||
Margin(cfg.Theme.Post.Subject.Margin...).
|
||||
Padding(cfg.Theme.Post.Subject.Padding...).
|
||||
Border(cfg.Theme.Post.Subject.Border.Border, cfg.Theme.Post.Subject.Border.Sides...).
|
||||
BorderForeground(cfg.Theme.Post.Subject.Border.Foreground).
|
||||
BorderBackground(cfg.Theme.Post.Subject.Border.Background).
|
||||
Foreground(cfg.Theme.Post.Subject.Foreground).
|
||||
Background(cfg.Theme.Post.Subject.Background)
|
||||
|
||||
t.Reply.Author = lipgloss.NewStyle().
|
||||
Margin(cfg.Theme.Reply.Author.Margin...).
|
||||
Padding(cfg.Theme.Reply.Author.Padding...).
|
||||
Border(cfg.Theme.Reply.Author.Border.Border, cfg.Theme.Reply.Author.Border.Sides...).
|
||||
BorderForeground(cfg.Theme.Reply.Author.Border.Foreground).
|
||||
BorderBackground(cfg.Theme.Reply.Author.Border.Background).
|
||||
Foreground(cfg.Theme.Reply.Author.Foreground).
|
||||
Background(cfg.Theme.Reply.Author.Background)
|
||||
|
||||
return t
|
||||
}
|
@ -18,71 +18,13 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ViewBorderColor = lipgloss.AdaptiveColor{
|
||||
Light: "#b0c4de",
|
||||
Dark: "#b0c4de",
|
||||
}
|
||||
|
||||
DialogBorderColor = lipgloss.AdaptiveColor{
|
||||
Light: "#b0c4de",
|
||||
Dark: "#b0c4de",
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
listStyle = lipgloss.NewStyle().
|
||||
Margin(0, 0, 0, 0).
|
||||
Padding(1, 1).
|
||||
Border(lipgloss.DoubleBorder()).
|
||||
BorderForeground(ViewBorderColor).
|
||||
BorderTop(true).
|
||||
BorderLeft(true).
|
||||
BorderRight(true).
|
||||
BorderBottom(true)
|
||||
|
||||
viewportStyle = lipgloss.NewStyle().
|
||||
Margin(0, 0, 0, 0).
|
||||
Padding(0, 0).
|
||||
BorderTop(false).
|
||||
BorderLeft(false).
|
||||
BorderRight(false).
|
||||
BorderBottom(false)
|
||||
|
||||
dialogBoxStyle = lipgloss.NewStyle().
|
||||
Border(lipgloss.ThickBorder()).
|
||||
BorderForeground(DialogBorderColor).
|
||||
Padding(0, 0).
|
||||
Margin(0, 0, 0, 0).
|
||||
BorderTop(false).
|
||||
BorderLeft(true).
|
||||
BorderRight(true).
|
||||
BorderBottom(true)
|
||||
|
||||
dialogBoxTitlebarStyle = lipgloss.NewStyle().
|
||||
Align(lipgloss.Center).
|
||||
Background(lipgloss.Color("#87cefa")).
|
||||
Foreground(lipgloss.Color("#000000")).
|
||||
Padding(0, 1).
|
||||
Margin(0, 0, 1, 0)
|
||||
|
||||
dialogBoxBottombarStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#999999")).
|
||||
Padding(0, 1).
|
||||
Margin(1, 0, 0, 0)
|
||||
|
||||
postAuthorStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#F25D94")).
|
||||
Padding(0, 1)
|
||||
|
||||
postSubjectStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#FFFFFF")).
|
||||
Background(lipgloss.Color("#F25D94")).
|
||||
Padding(0, 1)
|
||||
|
||||
replyAuthorStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#000000")).
|
||||
Background(lipgloss.Color("#874BFD")).
|
||||
Padding(0, 1)
|
||||
Margin(0, 0, 0, 0).
|
||||
Padding(0, 0).
|
||||
BorderTop(false).
|
||||
BorderLeft(false).
|
||||
BorderRight(false).
|
||||
BorderBottom(false)
|
||||
)
|
||||
|
||||
type KeyMap struct {
|
||||
@ -130,7 +72,8 @@ func NewModel(c *ctx.Ctx) Model {
|
||||
}
|
||||
|
||||
m.list = list.New(m.items, list.NewDefaultDelegate(), 0, 0)
|
||||
m.list.Title = "Posts"
|
||||
m.list.SetShowTitle(false)
|
||||
m.list.SetShowStatusBar(false)
|
||||
m.ctx = c
|
||||
m.a, _ = aggregator.New(m.ctx)
|
||||
|
||||
@ -167,8 +110,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
viewportWidth := m.ctx.Content[0] - 9
|
||||
viewportHeight := m.ctx.Content[1] - 10
|
||||
|
||||
listStyle.Width(listWidth)
|
||||
listStyle.Height(listHeight)
|
||||
m.ctx.Theme.PostsList.List.Width(listWidth)
|
||||
m.ctx.Theme.PostsList.List.Height(listHeight)
|
||||
m.list.SetSize(
|
||||
listWidth-2,
|
||||
listHeight-2,
|
||||
@ -196,12 +139,12 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmd tea.Cmd
|
||||
|
||||
if m.viewportOpen == false {
|
||||
// listStyle.BorderForeground(lipgloss.Color("#FFFFFF"))
|
||||
// m.ctx.Theme.PostsList.List.BorderForeground(lipgloss.Color("#FFFFFF"))
|
||||
// viewportStyle.BorderForeground(lipgloss.Color("#874BFD"))
|
||||
m.list, cmd = m.list.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
} else if m.viewportOpen == true {
|
||||
// listStyle.BorderForeground(lipgloss.Color("#874BFD"))
|
||||
// m.ctx.Theme.PostsList.List.BorderForeground(lipgloss.Color("#874BFD"))
|
||||
// viewportStyle.BorderForeground(lipgloss.Color("#FFFFFF"))
|
||||
m.viewport, cmd = m.viewport.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
@ -215,15 +158,16 @@ func (m Model) View() string {
|
||||
|
||||
view.WriteString(lipgloss.JoinHorizontal(
|
||||
lipgloss.Top,
|
||||
listStyle.Render(m.list.View()),
|
||||
m.ctx.Theme.PostsList.List.Render(m.list.View()),
|
||||
))
|
||||
|
||||
if m.viewportOpen {
|
||||
titlebar := dialogBoxTitlebarStyle.
|
||||
titlebar := m.ctx.Theme.DialogBox.Titlebar.
|
||||
Align(lipgloss.Center).
|
||||
Width(m.viewport.Width + 4).
|
||||
Render("Post")
|
||||
|
||||
bottombar := dialogBoxBottombarStyle.
|
||||
bottombar := m.ctx.Theme.DialogBox.Bottombar.
|
||||
Width(m.viewport.Width + 4).
|
||||
Render("r reply · esc close")
|
||||
|
||||
@ -234,7 +178,9 @@ func (m Model) View() string {
|
||||
bottombar,
|
||||
)
|
||||
|
||||
return helpers.PlaceOverlay(3, 2, dialogBoxStyle.Render(ui), view.String(), true)
|
||||
return helpers.PlaceOverlay(3, 2,
|
||||
m.ctx.Theme.DialogBox.Window.Render(ui),
|
||||
view.String(), true)
|
||||
}
|
||||
|
||||
return view.String()
|
||||
@ -288,10 +234,10 @@ func (m *Model) renderViewport(p *post.Post) string {
|
||||
}
|
||||
out += fmt.Sprintf(
|
||||
" %s\n %s\n%s",
|
||||
postAuthorStyle.Render(
|
||||
m.ctx.Theme.Post.Author.Render(
|
||||
fmt.Sprintf("%s %s:", p.Author.Name, adj),
|
||||
),
|
||||
postSubjectStyle.Render(p.Subject),
|
||||
m.ctx.Theme.Post.Subject.Render(p.Subject),
|
||||
body,
|
||||
)
|
||||
|
||||
@ -331,7 +277,7 @@ func (m *Model) renderReplies(
|
||||
}
|
||||
out += fmt.Sprintf(
|
||||
"\n\n %s %s\n%s",
|
||||
replyAuthorStyle.Render(
|
||||
m.ctx.Theme.Reply.Author.Render(
|
||||
author,
|
||||
),
|
||||
lipgloss.NewStyle().Foreground(lipgloss.Color("#874BFD")).Render(
|
||||
|
Loading…
Reference in New Issue
Block a user