a567b2ce73
Card-by-card walkthrough of entries untouched for 30+ days. Prevents write-mostly decay by bringing old entries back to attention. - S from list triggers stumble, loads entries where modified_at < 30d - Single-card view with markdown body, glyph, tags, age indicator - Actions: n skip, d dismiss, ! pin, p promote, m absorb, esc exit - Progress indicator: stumble [3/12] - After promote/absorb from stumble, returns to deck (not list) - "All caught up" screen when deck exhausted - DB: add ModifiedBefore to ListParams, modified_at sort column
109 lines
2.6 KiB
Go
109 lines
2.6 KiB
Go
package tui
|
|
|
|
import "strings"
|
|
|
|
func renderHelp(width, height int) string {
|
|
sections := []struct {
|
|
title string
|
|
binds [][2]string
|
|
}{
|
|
{"Focus", [][2]string{
|
|
{"tab", "toggle capture ↔ list"},
|
|
{"esc", "back / clear filter / to capture"},
|
|
{"a", "focus capture bar"},
|
|
{"h", "focus tag rail (from list)"},
|
|
{"l", "focus detail (split view)"},
|
|
{"ctrl+b", "toggle tag rail"},
|
|
}},
|
|
{"Capture Bar", [][2]string{
|
|
{"enter", "submit (or browse if empty)"},
|
|
{"?…", "search (type ?query)"},
|
|
{"-", "todo prefix"},
|
|
{"@", "event prefix"},
|
|
{"!", "reminder prefix"},
|
|
}},
|
|
{"Navigation", [][2]string{
|
|
{"j/k ↑/↓", "move cursor"},
|
|
{"g/G home/end", "top / bottom"},
|
|
{"pgup/pgdn", "page up / down"},
|
|
{"enter", "view detail"},
|
|
}},
|
|
{"Views", [][2]string{
|
|
{"1", "stream view"},
|
|
{"2", "cards view"},
|
|
{"s", "cycle sort (cards)"},
|
|
{"i", "cycle intent (cards)"},
|
|
}},
|
|
{"Actions", [][2]string{
|
|
{"d", "delete (with confirm)"},
|
|
{"x", "toggle todo completion"},
|
|
{"!", "toggle pin"},
|
|
{"#", "filter by tag"},
|
|
{"m", "absorb (merge into target)"},
|
|
{"p", "promote to card"},
|
|
{"S", "stumble (resurface stale entries)"},
|
|
}},
|
|
{"Detail View", [][2]string{
|
|
{"p", "promote to card"},
|
|
{"D", "demote to fluid"},
|
|
{"c", "copy to clipboard"},
|
|
{"e", "edit in $EDITOR"},
|
|
{"!", "toggle pin"},
|
|
{"r", "run checklist"},
|
|
{"f", "fill template"},
|
|
}},
|
|
{"Stumble", [][2]string{
|
|
{"n / →", "skip to next"},
|
|
{"d", "dismiss (soft delete)"},
|
|
{"!", "pin"},
|
|
{"p", "promote to card"},
|
|
{"m", "absorb"},
|
|
{"esc", "exit"},
|
|
}},
|
|
{"Run Mode", [][2]string{
|
|
{"j/k", "move between steps"},
|
|
{"space", "toggle step"},
|
|
{"r", "reset all steps"},
|
|
{"esc", "save + exit"},
|
|
}},
|
|
{"Fill Mode", [][2]string{
|
|
{"tab", "next slot"},
|
|
{"shift+tab", "prev slot"},
|
|
{"enter", "copy resolved"},
|
|
{"esc", "cancel"},
|
|
}},
|
|
{"Split View", [][2]string{
|
|
{"l", "focus detail pane"},
|
|
{"h", "focus list pane"},
|
|
{"esc", "close detail / back"},
|
|
}},
|
|
{"Global", [][2]string{
|
|
{"?", "toggle help"},
|
|
{"q / ctrl+c", "quit"},
|
|
}},
|
|
}
|
|
|
|
var b strings.Builder
|
|
b.WriteString(detailHeaderStyle.Render("keybindings"))
|
|
b.WriteString("\n\n")
|
|
|
|
for _, s := range sections {
|
|
b.WriteString(titleStyle.Render(s.title))
|
|
b.WriteString("\n")
|
|
for _, bind := range s.binds {
|
|
key := helpKeyStyle.Render(bind[0])
|
|
desc := helpDescStyle.Render(bind[1])
|
|
b.WriteString(" " + key + " " + desc + "\n")
|
|
}
|
|
b.WriteString("\n")
|
|
}
|
|
|
|
b.WriteString(helpStyle.Render("press ? or esc to close"))
|
|
|
|
lines := strings.Split(b.String(), "\n")
|
|
if len(lines) > height {
|
|
lines = lines[:height]
|
|
}
|
|
return strings.Join(lines, "\n")
|
|
}
|