Skip to content

Commit 59237f4

Browse files
authored
feat: UI improvements for session list (#8)
## Summary - Add git branch icon (nerd font) before branch name - Add blue left border indicator for selected items - Improve visual hierarchy: title uses terminal default color, selected items use blue - Display session prompt (truncated with ellipsis) below title - Make directory path and prompt text subtle (gray) - Fix bug where prompt wasn't saved when recycling sessions ## Test plan - [x] Run TUI and verify selected item has blue left border - [x] Verify git branch shows icon prefix - [x] Verify prompt displays below session name - [x] Create session with prompt, recycle it, create new session - verify prompt updates
1 parent 614b4ec commit 59237f4

3 files changed

Lines changed: 51 additions & 24 deletions

File tree

internal/hive/service.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ func (s *Service) CreateSession(ctx context.Context, opts CreateOptions) (*sessi
9090

9191
sess = recyclable
9292
sess.Name = opts.Name
93+
sess.Prompt = opts.Prompt
9394
sess.State = session.StateActive
9495
sess.UpdatedAt = time.Now()
9596
} else {

internal/tui/delegate.go

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import (
1111
"github.com/hay-kot/hive/pkg/kv"
1212
)
1313

14+
// maxPromptDisplayLen is the maximum number of runes to display for a session prompt.
15+
const maxPromptDisplayLen = 60
16+
1417
// SessionItem wraps a session for the list component.
1518
type SessionItem struct {
1619
Session session.Session
@@ -54,7 +57,7 @@ func NewSessionDelegate() SessionDelegate {
5457

5558
// Height returns the height of each item.
5659
func (d SessionDelegate) Height() int {
57-
return 4
60+
return 5
5861
}
5962

6063
// Spacing returns the spacing between items.
@@ -77,10 +80,7 @@ func (d SessionDelegate) Render(w io.Writer, m list.Model, index int, item list.
7780
s := sessionItem.Session
7881
isSelected := index == m.Index()
7982

80-
// Build the title line: ID Name
81-
title := fmt.Sprintf("%-8s %s", s.ID, s.Name)
82-
83-
// Build the description line: State | Path
83+
// Build the title line: Name [state]
8484
var stateStyle lipgloss.Style
8585
switch s.State {
8686
case session.StateActive:
@@ -91,26 +91,42 @@ func (d SessionDelegate) Render(w io.Writer, m list.Model, index int, item list.
9191
stateStyle = d.Styles.Normal
9292
}
9393

94-
state := stateStyle.Render(string(s.State))
95-
desc := fmt.Sprintf("%s %s", state, s.Path)
94+
stateTag := stateStyle.Render(fmt.Sprintf("[%s]", s.State))
95+
title := fmt.Sprintf("%s %s", s.Name, stateTag)
96+
97+
// Build the description line: Path
98+
path := pathStyle.Render(s.Path)
99+
100+
// Build prompt line (truncated with ellipsis)
101+
prompt := s.Prompt
102+
if prompt == "" {
103+
prompt = "(no prompt)"
104+
}
105+
promptRunes := []rune(prompt)
106+
if len(promptRunes) > maxPromptDisplayLen {
107+
prompt = string(promptRunes[:maxPromptDisplayLen-3]) + "..."
108+
}
109+
promptLine := promptStyle.Render(prompt)
96110

97111
// Build git status line
98112
gitLine := d.renderGitStatus(s.Path)
99113

100-
// Apply selection styling
114+
// Apply selection styling with left border
101115
var titleStyle lipgloss.Style
116+
var border string
102117
if isSelected {
103118
titleStyle = d.Styles.Selected
104-
title = "> " + title
119+
border = selectedBorderStyle.Render("┃") + " "
105120
} else {
106121
titleStyle = d.Styles.Normal
107-
title = " " + title
122+
border = " "
108123
}
109124

110-
// Write to output
111-
_, _ = fmt.Fprintf(w, "%s\n", titleStyle.Render(title))
112-
_, _ = fmt.Fprintf(w, " %s\n", desc)
113-
_, _ = fmt.Fprintf(w, " %s", gitLine)
125+
// Write to output with left border
126+
_, _ = fmt.Fprintf(w, "%s%s\n", border, titleStyle.Render(title))
127+
_, _ = fmt.Fprintf(w, "%s%s\n", border, promptLine)
128+
_, _ = fmt.Fprintf(w, "%s%s\n", border, path)
129+
_, _ = fmt.Fprintf(w, "%s%s", border, gitLine)
114130
}
115131

116132
// renderGitStatus returns the formatted git status line for a session path.
@@ -128,8 +144,8 @@ func (d SessionDelegate) renderGitStatus(path string) string {
128144
return gitLoadingStyle.Render("Git: unavailable")
129145
}
130146

131-
// Format: branch +N -N • clean/uncommitted changes
132-
branch := gitBranchStyle.Render(status.Branch)
147+
// Format: branch +N -N • clean/uncommitted changes
148+
branch := gitBranchStyle.Render("\ue725 " + status.Branch)
133149

134150
// Diff stats with colored additions (green) and deletions (red)
135151
additions := gitAdditionsStyle.Render(fmt.Sprintf(" +%d", status.Additions))

internal/tui/styles.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@ var (
1111
colorGreen = lipgloss.Color("#9ece6a") // green
1212
colorYellow = lipgloss.Color("#e0af68") // yellow
1313
colorBlue = lipgloss.Color("#7aa2f7") // blue
14-
/* colorPurple = lipgloss.Color("#bb9af7") // purple */
15-
/* colorCyan = lipgloss.Color("#7dcfff") // cyan */
16-
colorGray = lipgloss.Color("#565f89") // comment
17-
colorWhite = lipgloss.Color("#c0caf5") // foreground
14+
colorGray = lipgloss.Color("#565f89") // comment
15+
colorWhite = lipgloss.Color("#c0caf5") // foreground
1816
)
1917

2018
// Styles used for rendering the TUI (lipgloss v1 for bubbles compatibility).
@@ -32,14 +30,26 @@ var (
3230
recycledStyle = lipgloss.NewStyle().
3331
Foreground(colorYellow)
3432

35-
// Selected item style.
33+
// Selected item style (matches border color).
3634
selectedStyle = lipgloss.NewStyle().
37-
Foreground(colorWhite).
35+
Foreground(colorBlue).
3836
Bold(true)
3937

40-
// Normal item style.
41-
normalStyle = lipgloss.NewStyle().
38+
// Normal item style (no color, uses terminal default).
39+
normalStyle = lipgloss.NewStyle()
40+
41+
// Path style for subtle directory text.
42+
pathStyle = lipgloss.NewStyle().
4243
Foreground(colorGray)
44+
45+
// Prompt style for session prompt text.
46+
promptStyle = lipgloss.NewStyle().
47+
Foreground(colorGray).
48+
Italic(true)
49+
50+
// Selected border style for left accent bar.
51+
selectedBorderStyle = lipgloss.NewStyle().
52+
Foreground(colorBlue)
4353
)
4454

4555
// Banner ASCII art for the header.

0 commit comments

Comments
 (0)