feat(tui): add cards view, mode switching, promote picker, and card detail
Stream/cards toggle with 1/2 keys. Cards view with intent filtering (tab cycles grab/read/fill/all), sort cycling (s key), pinned-first ordering, and affordance badges. Promote picker (p key) with card type selection and auto-detection from body content. Detail view renders card_data per type: checklist steps, template slots, decision fields, link URLs. Extracts generateCardData to internal/carddata for reuse across cmd and tui packages.
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"github.com/lerko/nib/internal/carddata"
|
||||
"github.com/lerko/nib/internal/db"
|
||||
"github.com/lerko/nib/internal/display"
|
||||
)
|
||||
|
||||
type promoteOption struct {
|
||||
cardType db.CardType
|
||||
label string
|
||||
group string
|
||||
}
|
||||
|
||||
var promoteOptions = []promoteOption{
|
||||
{db.CardSnippet, "snippet", "grab"},
|
||||
{db.CardNote, "note", "read"},
|
||||
{db.CardLink, "link", "read"},
|
||||
{db.CardDecision, "decision", "read"},
|
||||
{db.CardTemplate, "template", "fill"},
|
||||
{db.CardChecklist, "checklist", "fill"},
|
||||
}
|
||||
|
||||
type promoteModel struct {
|
||||
cursor int
|
||||
entityID string
|
||||
body string
|
||||
suggested *db.CardType
|
||||
}
|
||||
|
||||
func newPromoteModel(entityID, body string) promoteModel {
|
||||
return promoteModel{
|
||||
entityID: entityID,
|
||||
body: body,
|
||||
suggested: carddata.DetectCardType(body),
|
||||
}
|
||||
}
|
||||
|
||||
func (p promoteModel) selectedType() db.CardType {
|
||||
return promoteOptions[p.cursor].cardType
|
||||
}
|
||||
|
||||
func (p promoteModel) update(key string) promoteModel {
|
||||
switch key {
|
||||
case "up", "k":
|
||||
if p.cursor > 0 {
|
||||
p.cursor--
|
||||
}
|
||||
case "down", "j":
|
||||
if p.cursor < len(promoteOptions)-1 {
|
||||
p.cursor++
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p promoteModel) view(width int) string {
|
||||
var b string
|
||||
b += titleStyle.Render("promote to card") + "\n\n"
|
||||
|
||||
currentGroup := ""
|
||||
for i, opt := range promoteOptions {
|
||||
if opt.group != currentGroup {
|
||||
currentGroup = opt.group
|
||||
b += dateHeaderStyle.Render("── "+currentGroup+" ──") + "\n"
|
||||
}
|
||||
|
||||
glyph := display.DisplayGlyph(db.GlyphNote, &opt.cardType)
|
||||
label := glyph + " " + opt.label
|
||||
|
||||
if p.suggested != nil && *p.suggested == opt.cardType {
|
||||
label += " " + affordanceStyle.Render("*")
|
||||
}
|
||||
|
||||
if i == p.cursor {
|
||||
b += selectedItemStyle.Render(" "+label) + "\n"
|
||||
} else {
|
||||
b += listItemStyle.Render(label) + "\n"
|
||||
}
|
||||
}
|
||||
|
||||
b += "\n" + helpStyle.Render("enter:select esc:cancel")
|
||||
return b
|
||||
}
|
||||
Reference in New Issue
Block a user