package tui import ( "fmt" "strings" "github.com/lerko/nib/internal/db" ) type tagRailModel struct { tags []db.TagCount cursor int offset int height int width int activeTag string } func newTagRailModel() tagRailModel { return tagRailModel{} } func (r *tagRailModel) setTags(tags []db.TagCount) { r.tags = tags if r.cursor >= len(tags) { r.cursor = max(0, len(tags)-1) } } func (r *tagRailModel) setSize(width, height int) { r.width = width r.height = height } func (r tagRailModel) selectedTag() string { if len(r.tags) == 0 || r.cursor >= len(r.tags) { return "" } return r.tags[r.cursor].Tag } func (r tagRailModel) update(key string) tagRailModel { switch key { case "up", "k": if r.cursor > 0 { r.cursor-- if r.cursor < r.offset { r.offset = r.cursor } } case "down", "j": if r.cursor < len(r.tags)-1 { r.cursor++ visible := r.visibleCount() if r.cursor >= r.offset+visible { r.offset = r.cursor - visible + 1 } } } return r } func (r tagRailModel) visibleCount() int { v := r.height - 2 if v <= 0 { return 10 } return v } func (r tagRailModel) view(focused bool) string { w := r.width if w <= 0 { return "" } var b strings.Builder headerStyle := railHeaderStyle if focused { headerStyle = headerStyle.Foreground(highlight) } b.WriteString(headerStyle.Render("tags")) b.WriteString("\n") b.WriteString(separatorStyle.Render(strings.Repeat("─", w))) b.WriteString("\n") if len(r.tags) == 0 { b.WriteString(hintDescStyle.Render(" no tags")) return b.String() } visible := r.visibleCount() end := min(r.offset+visible, len(r.tags)) countW := 0 for _, tc := range r.tags { cw := len(fmt.Sprintf("%d", tc.Count)) if cw > countW { countW = cw } } nameW := w - countW - 3 if nameW < 4 { nameW = 4 } for i := r.offset; i < end; i++ { tc := r.tags[i] name := "#" + tc.Tag if len(name) > nameW { name = name[:nameW-1] + "…" } count := fmt.Sprintf("%*d", countW, tc.Count) gap := w - len(name) - len(count) - 1 if gap < 1 { gap = 1 } var line string if i == r.cursor && focused { line = selectedItemStyle.Render(" " + name + strings.Repeat(" ", gap) + railCountStyle.Render(count)) } else if tc.Tag == r.activeTag { line = " " + railActiveTagStyle.Render(name) + strings.Repeat(" ", gap) + railCountStyle.Render(count) } else { line = " " + railTagStyle.Render(name) + strings.Repeat(" ", gap) + railCountStyle.Render(count) } b.WriteString(line) if i < end-1 { b.WriteString("\n") } } return b.String() }