more UI and change default local user permissions

This commit is contained in:
2026-03-19 22:22:24 +00:00
parent a997b184f5
commit a79666f5a6
4 changed files with 198 additions and 37 deletions

129
tui.go
View File

@@ -12,7 +12,9 @@ import (
type tuiTheme struct {
outer lipgloss.Style
headerBar lipgloss.Style
badge lipgloss.Style
chrome lipgloss.Style
title lipgloss.Style
subtitle lipgloss.Style
sectionTitle lipgloss.Style
@@ -20,10 +22,15 @@ type tuiTheme struct {
muted lipgloss.Style
footer lipgloss.Style
panel lipgloss.Style
panelAccent lipgloss.Style
row lipgloss.Style
rowSelected lipgloss.Style
rowNumber lipgloss.Style
rowNumberOn lipgloss.Style
rowKey lipgloss.Style
rowKeySelected lipgloss.Style
rowTitle lipgloss.Style
rowTitleOn lipgloss.Style
rowHint lipgloss.Style
rowHintActive lipgloss.Style
statusInfo lipgloss.Style
@@ -34,35 +41,44 @@ type tuiTheme struct {
}
func newTUITheme() tuiTheme {
border := lipgloss.Color("#4B5D6B")
text := lipgloss.Color("#E9E1D4")
muted := lipgloss.Color("#9E9385")
accent := lipgloss.Color("#D97745")
accentSoft := lipgloss.Color("#F4D8BD")
panel := lipgloss.Color("#192126")
panelAlt := lipgloss.Color("#232E36")
info := lipgloss.Color("#7FB0C2")
warn := lipgloss.Color("#D7A55A")
success := lipgloss.Color("#8AAC83")
border := lipgloss.Color("#5A6772")
borderSoft := lipgloss.Color("#31414A")
text := lipgloss.Color("#ECE4D8")
muted := lipgloss.Color("#A49788")
accent := lipgloss.Color("#D9733F")
accentSoft := lipgloss.Color("#F2D2B5")
panel := lipgloss.Color("#161C20")
panelAlt := lipgloss.Color("#212A30")
panelLift := lipgloss.Color("#2B363D")
info := lipgloss.Color("#86B7C6")
warn := lipgloss.Color("#D8AB63")
success := lipgloss.Color("#91B57F")
return tuiTheme{
outer: lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(border).
Padding(1, 2),
headerBar: lipgloss.NewStyle().
Foreground(borderSoft),
chrome: lipgloss.NewStyle().
Foreground(muted),
badge: lipgloss.NewStyle().
Foreground(panel).
Background(accentSoft).
Bold(true).
Padding(0, 1),
subtitle: lipgloss.NewStyle().
Foreground(muted),
title: lipgloss.NewStyle().
Foreground(text).
Bold(true),
subtitle: lipgloss.NewStyle().
Foreground(muted),
sectionTitle: lipgloss.NewStyle().
Foreground(accentSoft).
Bold(true).
Border(lipgloss.NormalBorder(), false, false, true, false).
BorderForeground(borderSoft).
PaddingBottom(0).
MarginBottom(1),
body: lipgloss.NewStyle().
Foreground(text),
@@ -71,26 +87,50 @@ func newTUITheme() tuiTheme {
footer: lipgloss.NewStyle().
Foreground(muted).
Border(lipgloss.NormalBorder(), true, false, false, false).
BorderForeground(border).
PaddingTop(1),
BorderForeground(borderSoft).
PaddingTop(1).
MarginTop(1),
panel: lipgloss.NewStyle().
Border(lipgloss.NormalBorder(), false, false, false, true).
BorderForeground(border).
PaddingLeft(1),
row: lipgloss.NewStyle().
BorderForeground(borderSoft).
PaddingLeft(1).
MarginBottom(1),
panelAccent: lipgloss.NewStyle().
Border(lipgloss.ThickBorder(), false, false, false, true).
BorderForeground(panelAlt).
PaddingLeft(1),
BorderForeground(accent).
PaddingLeft(1).
MarginBottom(1),
row: lipgloss.NewStyle().
Border(lipgloss.NormalBorder(), false, false, false, true).
BorderForeground(panelLift).
Padding(0, 1).
MarginBottom(1),
rowSelected: lipgloss.NewStyle().
Border(lipgloss.ThickBorder(), false, false, false, true).
BorderForeground(accent).
Background(panel).
PaddingLeft(1),
Padding(0, 1).
MarginBottom(1),
rowNumber: lipgloss.NewStyle().
Foreground(muted),
rowNumberOn: lipgloss.NewStyle().
Foreground(accentSoft).
Bold(true),
rowKey: lipgloss.NewStyle().
Foreground(accent).
Bold(true),
Bold(true).
Background(panelAlt).
Padding(0, 1),
rowKeySelected: lipgloss.NewStyle().
Foreground(accentSoft).
Background(panelLift).
Bold(true).
Padding(0, 1),
rowTitle: lipgloss.NewStyle().
Foreground(text).
Bold(true),
rowTitleOn: lipgloss.NewStyle().
Foreground(text).
Bold(true),
rowHint: lipgloss.NewStyle().
Foreground(muted),
@@ -111,7 +151,8 @@ func newTUITheme() tuiTheme {
inputBox: lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(border).
Padding(0, 1),
Padding(0, 1).
Background(panelAlt),
}
}
@@ -144,10 +185,11 @@ func (t tuiTheme) renderFrame(width int, title, subtitle, body, footer string) s
placeWidth = frameWidth
}
sections := []string{
t.badge.Render("SAMBA CONFIGER"),
t.title.Width(contentWidth).Render(title),
}
headerLeft := lipgloss.JoinHorizontal(lipgloss.Top, t.badge.Render("SAMBA CONFIGER"), " ", t.chrome.Render("share editor"))
headerRule := t.headerBar.Render(strings.Repeat("─", max(0, contentWidth-lipgloss.Width(headerLeft)-1)))
header := lipgloss.JoinHorizontal(lipgloss.Center, headerLeft, " ", headerRule)
sections := []string{header, t.title.Width(contentWidth).Render(title)}
if subtitle != "" {
sections = append(sections, t.subtitle.Width(contentWidth).Render(subtitle))
}
@@ -172,7 +214,7 @@ func (t tuiTheme) renderSection(width int, title string, lines []string) string
rendered = append(rendered, t.sectionTitle.Width(contentWidth).Render(title))
}
for _, line := range lines {
rendered = append(rendered, t.panel.Width(contentWidth).Render(t.body.Width(contentWidth-2).Render(line)))
rendered = append(rendered, t.panel.Width(contentWidth).Render(t.body.Width(max(1, contentWidth-2)).Render(line)))
}
return strings.Join(rendered, "\n")
}
@@ -190,6 +232,13 @@ func (t tuiTheme) renderMessage(width int, kind, text string) string {
)
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
type menuOption struct {
Key string
Value string
@@ -260,17 +309,29 @@ func (m menuModel) View() string {
for i, option := range m.options {
rowStyle := m.theme.row
keyStyle := m.theme.rowKey
titleStyle := m.theme.rowTitle
hintStyle := m.theme.rowHint
prefix := m.theme.muted.Render(fmt.Sprintf("%02d", i+1))
numberStyle := m.theme.rowNumber
prefix := numberStyle.Render(fmt.Sprintf("%02d", i+1))
if i == m.cursor {
rowStyle = m.theme.rowSelected
keyStyle = m.theme.rowKeySelected
titleStyle = m.theme.rowTitleOn
hintStyle = m.theme.rowHintActive
prefix = keyStyle.Render(">>")
numberStyle = m.theme.rowNumberOn
prefix = numberStyle.Render(">>")
}
label := fmt.Sprintf("%s %s %s", prefix, keyStyle.Render("["+option.Key+"]"), option.Label)
rowLines := []string{label}
top := lipgloss.JoinHorizontal(
lipgloss.Center,
prefix,
" ",
keyStyle.Render(strings.ToUpper(option.Key)),
" ",
titleStyle.Render(option.Label),
)
rowLines := []string{top}
if option.Description != "" {
rowLines = append(rowLines, hintStyle.Render(option.Description))
}
@@ -360,10 +421,8 @@ func (m textPromptModel) View() string {
width := clampFrameWidth(m.width)
contentWidth := innerWidth(width)
lines := []string{
m.theme.inputLabel.Width(contentWidth).Render(m.label),
m.theme.inputBox.Width(contentWidth).Render(m.input.View()),
}
lines := []string{m.theme.inputLabel.Width(contentWidth).Render(m.label)}
lines = append(lines, m.theme.panelAccent.Width(contentWidth).Render(m.theme.inputBox.Width(max(8, contentWidth-2)).Render(m.input.View())))
if m.defaultValue != "" {
lines = append(lines, m.theme.muted.Width(contentWidth).Render("Enter keeps: "+m.defaultValue))
}