diff --git a/actionsList.go b/actionsList.go new file mode 100644 index 0000000..430021c --- /dev/null +++ b/actionsList.go @@ -0,0 +1,85 @@ +package main + +import ( + "fmt" + "gemini_site/gemlog" + + tea "github.com/charmbracelet/bubbletea" +) + +type Action string + +const ( + Write Action = "write" + Read Action = "read" + Edit Action = "edit" + Delete Action = "delete" +) + +var actions = []Action{Write, Read, Edit, Delete} + +type ActionListPageModel struct { + cursor int +} + +func initialActionListPageModel() ActionListPageModel { + return ActionListPageModel{ + cursor: 0, + } +} + +func (m ActionListPageModel) InitActionListPage() tea.Cmd { + return nil +} + +func (m ActionListPageModel) Update(msg tea.Msg, ctx *context) (ActionListPageModel, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "up", "k": + if m.cursor > 0 { + m.cursor-- + } + case "down", "j": + if m.cursor < len(actions)-1 { + m.cursor++ + } + case "enter", " ": + action := actions[m.cursor] + switch action { + case Write: + return m, gemlog.WritePostCMD(ctx.config) + case Read: + switchPageCmd := func() tea.Msg { + return SwitchPages{Page: EntryList} + } + loadGemLogsCmd := gemlog.LoadGemlogCMD(ctx.config) + return m, tea.Batch(switchPageCmd, loadGemLogsCmd) + // case Edit: + // m.ui.page = EntryList + // m.ui.entryListPage.cursor = 0 + // m.ui.entryListPage.actionToTake = Edit + // return m, gemlog.LoadGemlogCMD(ctx.config) + // case Delete: + // m.ui.page = EntryList + // m.ui.entryListPage.cursor = 0 + // m.ui.entryListPage.actionToTake = Delete + // return m, gemlog.LoadGemlogCMD(m.context.config) + } + } + } + + return m, nil +} + +func (m ActionListPageModel) View() string { + s := "Welcome to gemlog cli!\n\nWhat post action would you like to take?\n\n" + for i, action := range actions { + cursor := " " + if m.cursor == i { + cursor = ">" + } + s += fmt.Sprintf("%s %s\n", cursor, action) + } + return s +} diff --git a/entryList.go b/entryList.go new file mode 100644 index 0000000..af9e8c3 --- /dev/null +++ b/entryList.go @@ -0,0 +1,80 @@ +package main + +import ( + "fmt" + "gemini_site/gemlog" + + tea "github.com/charmbracelet/bubbletea" +) + +type EntryListPageModel struct { + entries []gemlog.GemlogListEntry + actionToTake Action + cursor int +} + +func InitialEntryListPageModel() EntryListPageModel { + return EntryListPageModel{ + cursor: 0, + actionToTake: Read, + } +} + +func (m EntryListPageModel) InitEntryListPage() tea.Cmd { + return nil +} + +func (m EntryListPageModel) Update(msg tea.Msg, ctx *context) (EntryListPageModel, tea.Cmd) { + switch msg := msg.(type) { + case gemlog.GemLogsLoaded: + m.entries = msg.Logs + return m, nil + case tea.KeyMsg: + switch msg.String() { + case "up", "k": + if m.cursor > 0 { + m.cursor-- + } + case "down", "j": + if m.cursor < len(actions)-1 { + m.cursor++ + } + // case "enter", " ": + + // action := actions[m.cursor] + // switch action { + // case Write: + // return m, gemlog.WritePostCMD(ctx.config) + // case Read: + // m.ui.page = EntryList + // m.ui.entryListPage.cursor = 0 + // m.ui.entryListPage.actionToTake = Read + // return m, gemlog.LoadGemlogCMD(ctx.config) + // case Edit: + // m.ui.page = EntryList + // m.ui.entryListPage.cursor = 0 + // m.ui.entryListPage.actionToTake = Edit + // return m, gemlog.LoadGemlogCMD(ctx.config) + // case Delete: + // m.ui.page = EntryList + // m.ui.entryListPage.cursor = 0 + // m.ui.entryListPage.actionToTake = Delete + // return m, gemlog.LoadGemlogCMD(m.context.config) + // } + } + } + + return m, nil +} + +func (m EntryListPageModel) View() string { + s := fmt.Sprintf("Which entry would you like to %s\n\n", m.actionToTake) + for i, entry := range m.entries { + cursor := " " + if m.cursor == i { + cursor = ">" + } + s += fmt.Sprintf("%s %s : %s\n", cursor, entry.Date, entry.Slug) + } + return s +} diff --git a/gemlog/db.go b/gemlog/db.go index cc14979..e5f123f 100644 --- a/gemlog/db.go +++ b/gemlog/db.go @@ -17,7 +17,6 @@ func genBasicAuthHeader(user, password string) string { } func listGemLogs(config *Config) ([]GemlogListEntry, error) { - slog.Info("Listing gemlogs from couchdb") url := fmt.Sprintf("%s:%d/gemlog/_design/gemlog-cli/_view/list", config.CouchDB.Host, config.CouchDB.Port) req, err := http.NewRequest("GET", url, nil) if err != nil { diff --git a/gemlog/list.go b/gemlog/list.go index 17af8cf..ce51dfc 100644 --- a/gemlog/list.go +++ b/gemlog/list.go @@ -1,18 +1,15 @@ package gemlog import ( - "log/slog" - tea "github.com/charmbracelet/bubbletea" ) func LoadGemlogCMD(config *Config) tea.Cmd { return func() tea.Msg { logs, err := listGemLogs(config) - slog.Info("Loaded gemlogs", "count", len(logs)) if err != nil { return ErrorMsg{err} } - return GemLogsLoaded{logs} + return GemLogsLoaded{Logs: logs} } } diff --git a/main.go b/main.go index 0f0c5f1..6b2d5e8 100644 --- a/main.go +++ b/main.go @@ -9,41 +9,23 @@ import ( tea "github.com/charmbracelet/bubbletea" ) -type Action string - -const ( - Write Action = "write" - Read Action = "read" - Edit Action = "edit" - Delete Action = "delete" -) - -var actions = []Action{Write, Read, Edit, Delete} - -func TODOCmd() tea.Msg { - return gemlog.Notification("This action has not been implemented yet. Try another.") -} - type Page string const ( ActionList Page = "actionList" EntryList Page = "entryList" - Entry Page = "entry" + // Entry Page = "entry" ) -type entryListPageModel struct { - entries []gemlog.GemlogListEntry - action Action -} +type SwitchPages struct{ Page Page } type uiState struct { notification string - cursor int errorTxt string - page Page - entryListPage entryListPageModel + page Page + entryListPage EntryListPageModel + actionListPage ActionListPageModel } type context struct { @@ -59,9 +41,11 @@ func initialModel(config *gemlog.Config) model { return model{ ui: uiState{ page: ActionList, - entryListPage: entryListPageModel{ - entries: []gemlog.GemlogListEntry{}, - }, + // entryListPage: entryListPageModel{ + // cursor: 0, + // entries: []gemlog.GemlogListEntry{}, + // }, + actionListPage: initialActionListPageModel(), }, context: &context{ config: config, @@ -70,47 +54,37 @@ func initialModel(config *gemlog.Config) model { } func (m model) Init() tea.Cmd { - return tea.SetWindowTitle("Gemlog CLI") + cmds := make([]tea.Cmd, 0) + cmds = append(cmds, tea.SetWindowTitle("Gemlog CLI")) + // TODO: add init commands from other pages + return tea.Batch(cmds...) } func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + cmds := make([]tea.Cmd, 0) switch msg := msg.(type) { + case SwitchPages: + m.ui.page = msg.Page case gemlog.ErrorMsg: m.ui.errorTxt = fmt.Sprintf("%s\n\n", fmt.Errorf("%s", msg)) case gemlog.Notification: m.ui.notification = fmt.Sprintf("%s\n\n", string(msg)) - case gemlog.GemLogsLoaded: - m.ui.entryListPage.entries = msg.Logs - m.ui.cursor = 0 case tea.KeyMsg: switch msg.String() { case "ctrl+c", "q": return m, tea.Quit - case "up", "k": - if m.ui.cursor > 0 { - m.ui.cursor-- - } - case "down", "j": - if m.ui.cursor < len(actions)-1 { - m.ui.cursor++ - } - case "enter", " ": - action := actions[m.ui.cursor] - switch action { - case Write: - return m, gemlog.WritePostCMD(m.context.config) - case Read: - m.ui.page = EntryList - return m, gemlog.LoadGemlogCMD(m.context.config) - case Edit: - return m, TODOCmd - case Delete: - return m, TODOCmd - } } } - return m, nil + actionListM, cmd := m.ui.actionListPage.Update(msg, m.context) + m.ui.actionListPage = actionListM + cmds = append(cmds, cmd) + + entryListM, cmd := m.ui.entryListPage.Update(msg, m.context) + m.ui.entryListPage = entryListM + cmds = append(cmds, cmd) + + return m, tea.Batch(cmds...) } func (m model) View() string { @@ -120,30 +94,12 @@ func (m model) View() string { s := "" if m.ui.notification != "" { s += m.ui.notification - } else { - s += "Welcome to gemlog cli!\n\nWhat post action would you like to take?\n\n" } if m.ui.page == ActionList { - for i, action := range actions { - cursor := " " - if m.ui.cursor == i { - cursor = ">" - } - s += fmt.Sprintf("%s %s\n", cursor, action) - } - } - - if m.ui.page == EntryList { - slog.Info("rendering entry list", "count", len(m.ui.entryListPage.entries)) - for i, entry := range m.ui.entryListPage.entries { - slog.Info("entry", "value", entry) - cursor := " " - if m.ui.cursor == i { - cursor = ">" - } - s += fmt.Sprintf("%s %s : %s\n", cursor, entry.Date, entry.Slug) - } + s += m.ui.actionListPage.View() + } else if m.ui.page == EntryList { + s += m.ui.entryListPage.View() } s += "\nPress q to quit.\n" @@ -160,13 +116,15 @@ func main() { defer f.Close() slog.Info("Starting gemlog cli") config, err := gemlog.LoadConfig() - // gemlog.CheckDBConnection(config) if err != nil { fmt.Printf("Error loading config: %v", err) os.Exit(1) } - - // TODO: check if we can reach db before starting program + err = gemlog.CheckDBConnection(config) + if err != nil { + fmt.Printf("Error checking db connection: %v", err) + os.Exit(1) + } p := tea.NewProgram(initialModel(config)) if _, err := p.Run(); err != nil { fmt.Printf("Alas, there's been an error: %v", err)