o/w/d select OPEN/WIP/DONE in the status menu, with the hotkeys shown inline. Co-authored-by: Cursor <cursoragent@cursor.com>
97 lines
2.0 KiB
Go
97 lines
2.0 KiB
Go
package views
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
|
|
"task/internal/ticket"
|
|
)
|
|
|
|
// StatusMenu renders a status picker overlay.
|
|
type StatusMenu struct {
|
|
Cursor int
|
|
Width int
|
|
Styles StatusMenuStyles
|
|
}
|
|
|
|
// StatusMenuStyles holds styles for the status picker.
|
|
type StatusMenuStyles struct {
|
|
Box lipgloss.Style
|
|
Title lipgloss.Style
|
|
Selected lipgloss.Style
|
|
Normal lipgloss.Style
|
|
}
|
|
|
|
// NewStatusMenu creates a menu with the given status pre-selected.
|
|
func NewStatusMenu(current ticket.Status, width int, styles StatusMenuStyles) StatusMenu {
|
|
return StatusMenu{
|
|
Cursor: current.Index(),
|
|
Width: width,
|
|
Styles: styles,
|
|
}
|
|
}
|
|
|
|
// MoveDown moves the selection down.
|
|
func (m *StatusMenu) MoveDown() {
|
|
if m.Cursor < len(ticket.AllStatuses)-1 {
|
|
m.Cursor++
|
|
}
|
|
}
|
|
|
|
// MoveUp moves the selection up.
|
|
func (m *StatusMenu) MoveUp() {
|
|
if m.Cursor > 0 {
|
|
m.Cursor--
|
|
}
|
|
}
|
|
|
|
// JumpToShortcut moves the cursor to the status whose label starts with r.
|
|
func (m *StatusMenu) JumpToShortcut(r rune) bool {
|
|
r = unicode.ToLower(r)
|
|
for i, st := range ticket.AllStatuses {
|
|
if st.Shortcut() == r {
|
|
m.Cursor = i
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Selected returns the currently highlighted status.
|
|
func (m StatusMenu) Selected() ticket.Status {
|
|
if m.Cursor < 0 || m.Cursor >= len(ticket.AllStatuses) {
|
|
return ticket.StatusTodo
|
|
}
|
|
return ticket.AllStatuses[m.Cursor]
|
|
}
|
|
|
|
// View renders the status menu.
|
|
func (m StatusMenu) View() string {
|
|
var lines []string
|
|
lines = append(lines, m.Styles.Title.Render("Set status"))
|
|
for i, st := range ticket.AllStatuses {
|
|
entry := fmt.Sprintf("%c %s", st.Shortcut(), st.Label())
|
|
if i == m.Cursor {
|
|
lines = append(lines, m.Styles.Selected.Render("▸ "+entry))
|
|
} else {
|
|
lines = append(lines, m.Styles.Normal.Render(" "+entry))
|
|
}
|
|
}
|
|
body := strings.Join(lines, "\n")
|
|
w := m.Width
|
|
if w < 20 {
|
|
w = 20
|
|
}
|
|
return m.Styles.Box.Width(min(40, w-2)).Render(body)
|
|
}
|
|
|
|
func min(a, b int) int {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|