feat: UI legend
This commit is contained in:
107
internal/ui/legend/legend.go
Normal file
107
internal/ui/legend/legend.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package legend
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"playback/internal/ui"
|
||||
)
|
||||
|
||||
// Model represents the legend component
|
||||
type Model struct {
|
||||
Width int
|
||||
}
|
||||
|
||||
// New creates a new legend model
|
||||
func New() Model {
|
||||
return Model{}
|
||||
}
|
||||
|
||||
// SetWidth sets the legend width
|
||||
func (m *Model) SetWidth(width int) {
|
||||
m.Width = width
|
||||
}
|
||||
|
||||
// View renders the key legend
|
||||
func (m Model) View() string {
|
||||
if m.Width < 30 {
|
||||
return "" // Too narrow to show legend
|
||||
}
|
||||
|
||||
// Group keybindings by category
|
||||
groups := []struct {
|
||||
title string
|
||||
entries []keyEntry
|
||||
}{
|
||||
{
|
||||
title: "Playback",
|
||||
entries: []keyEntry{
|
||||
{key: "space", desc: "play/pause"},
|
||||
{key: "q", desc: "quit"},
|
||||
{key: "?", desc: "help"},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Seeking",
|
||||
entries: []keyEntry{
|
||||
{key: "h/←", desc: "seek -5s"},
|
||||
{key: "l/→", desc: "seek +5s"},
|
||||
{key: "H", desc: "seek -30s"},
|
||||
{key: "L", desc: "seek +30s"},
|
||||
{key: "g/G", desc: "start/end"},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Nav",
|
||||
entries: []keyEntry{
|
||||
{key: "j/↓", desc: "next cue"},
|
||||
{key: "k/↑", desc: "prev cue"},
|
||||
{key: "ctrl+d/u", desc: "jump 5 cues"},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Edit",
|
||||
entries: []keyEntry{
|
||||
{key: "i", desc: "edit transcript"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Build legend rows
|
||||
var rows []string
|
||||
for _, group := range groups {
|
||||
rows = append(rows, renderGroup(group.title, group.entries))
|
||||
}
|
||||
|
||||
return lipgloss.JoinHorizontal(
|
||||
lipgloss.Left,
|
||||
lipgloss.NewStyle().Width(m.Width).Render(strings.Join(rows, " │ ")),
|
||||
)
|
||||
}
|
||||
|
||||
type keyEntry struct {
|
||||
key string
|
||||
desc string
|
||||
}
|
||||
|
||||
func renderGroup(title string, entries []keyEntry) string {
|
||||
var keyParts []string
|
||||
var descParts []string
|
||||
|
||||
for _, e := range entries {
|
||||
keyParts = append(keyParts, ui.HelpKeyStyle.Render(e.key))
|
||||
descParts = append(descParts, ui.HelpDescStyle.Render(e.desc))
|
||||
}
|
||||
|
||||
keyStr := strings.Join(keyParts, " ")
|
||||
descStr := strings.Join(descParts, " ")
|
||||
|
||||
return lipgloss.JoinHorizontal(
|
||||
lipgloss.Left,
|
||||
ui.BaseStyle.Render(title+":"),
|
||||
" ",
|
||||
keyStr,
|
||||
" ",
|
||||
descStr,
|
||||
)
|
||||
}
|
||||
@@ -96,6 +96,11 @@ var (
|
||||
HelpDescStyle = lipgloss.NewStyle().
|
||||
Foreground(ColorMuted)
|
||||
|
||||
// Legend styles
|
||||
LegendGroupStyle = lipgloss.NewStyle().
|
||||
Foreground(ColorMuted).
|
||||
PaddingLeft(2)
|
||||
|
||||
// Error styles
|
||||
ErrorStyle = lipgloss.NewStyle().
|
||||
Foreground(ColorError).
|
||||
|
||||
Reference in New Issue
Block a user