fix(tui): center all tabs, full-screen SFTP, muted inline keybindings
This commit is contained in:
+73
-29
@@ -7,6 +7,7 @@ import (
|
||||
"sync"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
|
||||
"git.tukangketik.id/swanadiva/hostkeeper/internal/models"
|
||||
"git.tukangketik.id/swanadiva/hostkeeper/pkg/storage"
|
||||
@@ -134,53 +135,96 @@ func (t *SnippetListTab) View() string {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
var b strings.Builder
|
||||
|
||||
b.WriteString(AppTitleStyle.Render("Command Snippets"))
|
||||
b.WriteString("\n\n")
|
||||
|
||||
switch t.state {
|
||||
case snippetListLoading:
|
||||
b.WriteString(SubtitleStyle.Render("Loading snippets..."))
|
||||
return b.String()
|
||||
case snippetListError:
|
||||
b.WriteString(ErrorStyle.Render(fmt.Sprintf("Error: %v", t.err)))
|
||||
b.WriteString("\n\n")
|
||||
b.WriteString(SubtitleStyle.Render("Press Esc to go back"))
|
||||
if t.state == snippetListLoading {
|
||||
return lipgloss.PlaceHorizontal(t.width, lipgloss.Center,
|
||||
SubtitleStyle.Render("Loading snippets..."))
|
||||
}
|
||||
if t.state == snippetListError {
|
||||
var b strings.Builder
|
||||
b.WriteString(lipgloss.PlaceHorizontal(t.width, lipgloss.Center,
|
||||
ErrorStyle.Render(fmt.Sprintf("Error: %v", t.err))))
|
||||
b.WriteString("\n")
|
||||
b.WriteString(lipgloss.PlaceHorizontal(t.width, lipgloss.Center,
|
||||
SubtitleStyle.Render("Press Esc to go back")))
|
||||
return b.String()
|
||||
}
|
||||
|
||||
type styledRow struct {
|
||||
text string
|
||||
plain string
|
||||
}
|
||||
var rows []styledRow
|
||||
|
||||
title := "Command Snippets"
|
||||
titlePlain := title
|
||||
|
||||
if t.err != nil {
|
||||
b.WriteString(ErrorStyle.Render(fmt.Sprintf("Error: %v", t.err)))
|
||||
b.WriteString("\n\n")
|
||||
errLine := fmt.Sprintf("Error: %v", t.err)
|
||||
rows = append(rows, styledRow{text: ErrorStyle.Render(errLine), plain: errLine})
|
||||
}
|
||||
|
||||
if len(t.snippets) == 0 {
|
||||
b.WriteString(SubtitleStyle.Render("No snippets stored."))
|
||||
b.WriteString("\n")
|
||||
b.WriteString(SubtitleStyle.Render("Press Ctrl+N to add a new snippet."))
|
||||
empty := "No snippets stored."
|
||||
hint := "Press Ctrl+N to add a new snippet."
|
||||
rows = append(rows, styledRow{text: SubtitleStyle.Render(empty), plain: empty})
|
||||
rows = append(rows, styledRow{text: SubtitleStyle.Render(hint), plain: hint})
|
||||
} else {
|
||||
for i, sn := range t.snippets {
|
||||
var line string
|
||||
desc := sn.Description
|
||||
if desc != "" {
|
||||
line = fmt.Sprintf(" %s — %s", sn.Name, desc)
|
||||
var plain string
|
||||
if sn.Description != "" {
|
||||
plain = fmt.Sprintf(" %s — %s", sn.Name, sn.Description)
|
||||
} else {
|
||||
line = fmt.Sprintf(" %s", sn.Name)
|
||||
plain = fmt.Sprintf(" %s", sn.Name)
|
||||
}
|
||||
|
||||
var styled string
|
||||
if i == t.selected {
|
||||
b.WriteString(SelectedStyle.Render(line))
|
||||
styled = lipgloss.NewStyle().
|
||||
Foreground(gbFg).
|
||||
Background(gbBgSel).
|
||||
Bold(true).
|
||||
Render("▸ " + strings.TrimLeft(plain, " "))
|
||||
} else {
|
||||
b.WriteString(HostNameStyle.Render(line))
|
||||
styled = lipgloss.NewStyle().Foreground(gbFg).Render(plain)
|
||||
}
|
||||
b.WriteString("\n")
|
||||
rows = append(rows, styledRow{text: styled, plain: plain})
|
||||
}
|
||||
}
|
||||
|
||||
b.WriteString("\n")
|
||||
b.WriteString(SubtitleStyle.Render("Ctrl+N:add Ctrl+E:edit D:delete Esc:back"))
|
||||
footerPlain := "Ctrl+N:add Ctrl+E:edit D:delete Esc:back Ctrl+Tab:switch Ctrl+Q:close"
|
||||
footer := styledRow{text: SubtitleStyle.Render(footerPlain), plain: footerPlain}
|
||||
|
||||
widestRow := lipgloss.Width(titlePlain)
|
||||
for _, r := range rows {
|
||||
if w := lipgloss.Width(r.plain); w > widestRow {
|
||||
widestRow = w
|
||||
}
|
||||
}
|
||||
if w := lipgloss.Width(footer.plain); w > widestRow {
|
||||
widestRow = w
|
||||
}
|
||||
|
||||
const sidePad = 6
|
||||
targetW := widestRow + sidePad*2
|
||||
rowShift := (targetW - widestRow) / 2
|
||||
|
||||
var inner strings.Builder
|
||||
|
||||
titleStyled := lipgloss.NewStyle().Bold(true).Foreground(gbYellow).Render(titlePlain)
|
||||
inner.WriteString(lipgloss.PlaceHorizontal(targetW, lipgloss.Center, titleStyled))
|
||||
inner.WriteString("\n\n")
|
||||
|
||||
shift := strings.Repeat(" ", rowShift)
|
||||
for _, r := range rows {
|
||||
line := lipgloss.PlaceHorizontal(targetW, lipgloss.Left, shift+r.text)
|
||||
inner.WriteString(line)
|
||||
inner.WriteString("\n")
|
||||
}
|
||||
inner.WriteString("\n")
|
||||
inner.WriteString(lipgloss.PlaceHorizontal(targetW, lipgloss.Center, footer.text))
|
||||
|
||||
box := BorderStyle.Render(inner.String())
|
||||
var b strings.Builder
|
||||
b.WriteString(lipgloss.PlaceHorizontal(t.width, lipgloss.Center, box))
|
||||
return b.String()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user