ui: wire automata background, add clock + session specifier + form card
- Automata.Frame() rendered as base layer, form card overlaid via ANSI cursor positioning with dark background for readability - Clock widget showing datetime (Mon Jan 02 15:04:05) in top bar - Session type label (x11/wayland) shown above switcher selection
This commit is contained in:
@@ -438,6 +438,9 @@ var (
|
|||||||
infoCol = lipgloss.Color("3") // yellow
|
infoCol = lipgloss.Color("3") // yellow
|
||||||
greenCol = lipgloss.Color("2") // green
|
greenCol = lipgloss.Color("2") // green
|
||||||
|
|
||||||
|
cardBg = lipgloss.Color("0") // black card background
|
||||||
|
cardPad = 2
|
||||||
|
|
||||||
avatarStyle = lipgloss.NewStyle().Foreground(accent)
|
avatarStyle = lipgloss.NewStyle().Foreground(accent)
|
||||||
|
|
||||||
fieldBox = lipgloss.NewStyle().
|
fieldBox = lipgloss.NewStyle().
|
||||||
@@ -481,6 +484,14 @@ func (m *Model) View() string {
|
|||||||
content := m.renderLayout()
|
content := m.renderLayout()
|
||||||
|
|
||||||
if m.width > 0 && m.height > 0 {
|
if m.width > 0 && m.height > 0 {
|
||||||
|
if m.automata != nil {
|
||||||
|
bg := m.automata.Frame()
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString(bg)
|
||||||
|
sb.WriteString("\x1b[H") // cursor home before overlaying
|
||||||
|
sb.WriteString(overlayCenter(m.width, m.height, content))
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center,
|
return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center,
|
||||||
content,
|
content,
|
||||||
)
|
)
|
||||||
@@ -488,17 +499,49 @@ func (m *Model) View() string {
|
|||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func overlayCenter(w, h int, content string) string {
|
||||||
|
lines := strings.Split(content, "\n")
|
||||||
|
cw := 0
|
||||||
|
for _, l := range lines {
|
||||||
|
if lw := lipgloss.Width(l); lw > cw {
|
||||||
|
cw = lw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cx := (w - cw) / 2
|
||||||
|
cy := (h - len(lines)) / 2
|
||||||
|
if cx < 0 {
|
||||||
|
cx = 0
|
||||||
|
}
|
||||||
|
if cy < 0 {
|
||||||
|
cy = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb strings.Builder
|
||||||
|
for i, line := range lines {
|
||||||
|
sb.WriteString(fmt.Sprintf("\x1b[%d;%dH", cy+i+1, cx+1))
|
||||||
|
sb.WriteString(line)
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Model) renderLayout() string {
|
func (m *Model) renderLayout() string {
|
||||||
// top bar: power hints
|
clock := m.renderClock()
|
||||||
top := m.renderPowerHints()
|
|
||||||
|
// top bar: power hints on left, clock on right
|
||||||
|
var topParts []string
|
||||||
|
topParts = append(topParts, m.renderPowerHints())
|
||||||
|
if clock != "" {
|
||||||
|
topParts = append(topParts, clock)
|
||||||
|
}
|
||||||
|
top := strings.Join(topParts, " ")
|
||||||
|
|
||||||
// avatar + form side by side
|
// avatar + form side by side
|
||||||
avatar := m.renderAvatar()
|
avatar := m.renderAvatar()
|
||||||
form := m.renderForm()
|
form := m.renderForm()
|
||||||
mid := lipgloss.JoinHorizontal(lipgloss.Top, avatar, " ", form)
|
mid := lipgloss.JoinHorizontal(lipgloss.Top, avatar, " ", form)
|
||||||
|
|
||||||
// DE switcher below
|
// DE switcher with specifier label
|
||||||
sw := m.renderSwitcherDots()
|
sw := m.renderSwitcher()
|
||||||
|
|
||||||
// caps lock
|
// caps lock
|
||||||
caps := m.renderCapsLock()
|
caps := m.renderCapsLock()
|
||||||
@@ -536,7 +579,10 @@ func (m *Model) renderLayout() string {
|
|||||||
joined = pad + joined
|
joined = pad + joined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return joined
|
return lipgloss.NewStyle().
|
||||||
|
Background(cardBg).
|
||||||
|
Padding(cardPad, cardPad+2).
|
||||||
|
Render(joined)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) renderPowerHints() string {
|
func (m *Model) renderPowerHints() string {
|
||||||
@@ -594,7 +640,12 @@ func (m *Model) renderForm() string {
|
|||||||
return lipgloss.JoinVertical(lipgloss.Left, userField, "", passField)
|
return lipgloss.JoinVertical(lipgloss.Left, userField, "", passField)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) renderSwitcherDots() string {
|
func (m *Model) renderClock() string {
|
||||||
|
now := time.Now()
|
||||||
|
return powerHint.Render(now.Format("Mon Jan 02 15:04:05"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Model) renderSwitcher() string {
|
||||||
if len(m.envs) == 0 {
|
if len(m.envs) == 0 {
|
||||||
return swNeighbour.Align(lipgloss.Center).Render("no desktop environments found")
|
return swNeighbour.Align(lipgloss.Center).Render("no desktop environments found")
|
||||||
}
|
}
|
||||||
@@ -604,6 +655,9 @@ func (m *Model) renderSwitcherDots() string {
|
|||||||
|
|
||||||
var parts []string
|
var parts []string
|
||||||
|
|
||||||
|
// session specifier (like "x11", "wayland")
|
||||||
|
spec := swDot.Render(m.envs[m.selIdx].Kind + " ")
|
||||||
|
|
||||||
if cfg.ShowMovers && m.selIdx > 0 {
|
if cfg.ShowMovers && m.selIdx > 0 {
|
||||||
parts = append(parts, swMover.Render(cfg.LeftMover+" "))
|
parts = append(parts, swMover.Render(cfg.LeftMover+" "))
|
||||||
}
|
}
|
||||||
@@ -636,7 +690,7 @@ func (m *Model) renderSwitcherDots() string {
|
|||||||
}
|
}
|
||||||
dotLine := strings.Join(dots, " ")
|
dotLine := strings.Join(dots, " ")
|
||||||
|
|
||||||
return lipgloss.JoinVertical(lipgloss.Center, swLine, dotLine)
|
return lipgloss.JoinVertical(lipgloss.Center, spec, swLine, dotLine)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) renderCapsLock() string {
|
func (m *Model) renderCapsLock() string {
|
||||||
|
|||||||
Reference in New Issue
Block a user