okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
2ecf203
main
1package tui 2 3import ( 4"albedo/cli/internal/daemon" 5"errors" 6 7 tea"charm.land/bubbletea/v2" 8) 9 10// pagesDoc is a page with rows in two badges, one with detail, and actions 11// that cover a text, a secret, a choice and a confirmed chord. 12func pagesDoc ()* PageDocument { 13text := []daemon.FormField {{Name :"text" ,Label :"text" ,Type :"text" ,Required :true }} 14return & PageDocument { 15Title :"work" , 16Summary :"2 open · 2 resolved" , 17Empty :"no work items yet" , 18Rows : []PageRow { 19 {ID :"12" ,Text :"fix the webhook retry" ,Badge :"open" ,Tone :ToneWarning }, 20 {ID :"13" ,Text :"ship the picker" ,Badge :"open" ,Tone :ToneActive }, 21 {ID :"7" ,Text :"stale binary" ,Badge :"resolved" ,Tone :ToneMuted }, 22 {ID :"3" ,Text :"ruff not on PATH" ,Badge :"resolved" ,Tone :ToneMuted , 23Detail :"ruff is missing from PATH; the binary lives in pre-commit's env.\n\nsuggestion: document the canonical invocation" }, 24 }, 25Actions : []PageAction { 26 {ID :"add" ,Key :"ctrl+o" ,Label :"add" ,Fields :text }, 27 {ID :"edit" ,Key :"ctrl+e" ,Label :"edit" ,Row :true ,Fields :text }, 28 {ID :"delete" ,Key :"ctrl+d" ,Label :"delete" ,Row :true ,Confirm :true ,Confirmation :"Delete this item?" }, 29 {ID :"toggle" ,Key :"ctrl+t" ,Label :"done" ,Row :true ,Fields : []daemon.FormField {{Name :"done" ,Label :"done" ,Type :"boolean" }}}, 30 {ID :"secret" ,Key :"ctrl+g" ,Label :"new secret" ,Row :true ,Fields : []daemon.FormField {{Name :"secret" ,Label :"replacement" ,Type :"secret" ,Required :true }}}, 31 }, 32 } 33} 34 35func pagesModel (width ,height int ,doc * PageDocument )PageViewModel { 36m := NewPageViewModel (nil ,"s" ,"/work" ) 37m .SetSize (width ,height ) 38m .setDoc (doc ) 39m .Busy = false 40return m 41} 42 43// pagesChord is a ctrl chord press, the way actions are reached. 44func pagesChord (letter rune ) tea.KeyPressMsg { 45return tea.KeyPressMsg {Code :letter ,Mod :tea .ModCtrl } 46} 47 48func pagesShot (keys ... tea.Msg )func (width ,height int )string { 49return func (width ,height int )string { 50m := pagesModel (width ,height ,pagesDoc ()) 51for _ ,key := range keys { 52m ,_ = m .Update (key ) 53 } 54return m .View () 55 } 56} 57 58func init () { 59down := tea.KeyPressMsg {Code :tea .KeyDown } 60registerShots ("pages" , 61shotState {"list" ,pagesShot ()}, 62shotState {"filtering" ,pagesShot (shotTyped ("ruff" )... )}, 63shotState {"no-match" ,pagesShot (shotTyped ("zzz" )... )}, 64shotState {"row-detail" ,pagesShot (down ,down ,down )}, 65shotState {"confirm" ,pagesShot (pagesChord ('d' ))}, 66shotState {"text-prompt" ,pagesShot (pagesChord ('o' ))}, 67shotState {"secret-prompt" ,pagesShot (down ,down ,down ,pagesChord ('g' ), tea.KeyPressMsg {Code :'s' ,Text :"s" })}, 68shotState {"choice-prompt" ,pagesShot (down ,pagesChord ('t' ))}, 69shotState {"actions-menu" ,pagesShot (pagesChord ('a' ))}, 70shotState {"busy" ,func (width ,height int )string { 71m := pagesModel (width ,height ,pagesDoc ()) 72m .Busy = true 73return m .View () 74 }}, 75shotState {"notice" ,func (width ,height int )string { 76m := pagesModel (width ,height ,pagesDoc ()) 77m .Notice = "added: write the release notes" 78return m .View () 79 }}, 80shotState {"error" ,func (width ,height int )string { 81m := pagesModel (width ,height ,pagesDoc ()) 82m .Error = "daemon refused the change" 83return m .View () 84 }}, 85shotState {"empty" ,func (width ,height int )string { 86doc := pagesDoc () 87doc .Rows = nil 88return pagesModel (width ,height ,doc ).View () 89 }}, 90shotState {"loading" ,func (width ,height int )string { 91m := NewPageViewModel (nil ,"s" ,"/work" ) 92m .SetSize (width ,height ) 93return m .View () 94 }}, 95shotState {"load-failed" ,func (width ,height int )string { 96m := NewPageViewModel (nil ,"s" ,"/work" ) 97m .SetSize (width ,height ) 98m ,_ = m .Update (pageLoadedMsg {Gen :m .Generation ,Err :errors .New ("daemon connection unavailable" )}) 99return m .View () 100 }}, 101 ) 102}