cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists ๐Ÿƒ
charm leaflet readability golang

build: reorganize main

+249 -205
+225
cmd/cli/commands.go
··· 1 + package main 2 + 3 + import ( 4 + "fmt" 5 + "strings" 6 + 7 + "github.com/spf13/cobra" 8 + "github.com/stormlightlabs/noteleaf/cmd/handlers" 9 + "github.com/stormlightlabs/noteleaf/internal/ui" 10 + ) 11 + 12 + func rootCmd() *cobra.Command { 13 + return &cobra.Command{ 14 + Use: "noteleaf", 15 + Long: ui.Colossal.ColoredInViewport(), 16 + Short: "A TaskWarrior-inspired CLI with notes, media queues and reading lists", 17 + Run: func(cmd *cobra.Command, args []string) { 18 + if len(args) == 0 { 19 + cmd.Help() 20 + } else { 21 + output := strings.Join(args, " ") 22 + fmt.Println(output) 23 + } 24 + }, 25 + } 26 + } 27 + 28 + func todoCmd() *cobra.Command { 29 + root := &cobra.Command{ 30 + Use: "todo", 31 + Short: "task management", 32 + } 33 + 34 + root.AddCommand(&cobra.Command{ 35 + Use: "add [description]", 36 + Short: "Add a new task", 37 + Args: cobra.MinimumNArgs(1), 38 + RunE: func(cmd *cobra.Command, args []string) error { 39 + description := args[0] 40 + fmt.Printf("Adding task: %s\n", description) 41 + // TODO: Implement task creation 42 + return nil 43 + }, 44 + }) 45 + 46 + root.AddCommand(&cobra.Command{ 47 + Use: "list", 48 + Short: "List tasks", 49 + Aliases: []string{"ls"}, 50 + RunE: func(cmd *cobra.Command, args []string) error { 51 + fmt.Println("Listing tasks...") 52 + // TODO: Implement task listing 53 + return nil 54 + }, 55 + }) 56 + 57 + root.AddCommand(&cobra.Command{ 58 + Use: "done [task-id]", 59 + Short: "Mark task as completed", 60 + Args: cobra.ExactArgs(1), 61 + RunE: func(cmd *cobra.Command, args []string) error { 62 + taskID := args[0] 63 + fmt.Printf("Marking task %s as done\n", taskID) 64 + // TODO: Implement task completion 65 + return nil 66 + }, 67 + }) 68 + 69 + return root 70 + } 71 + 72 + func movieCmd() *cobra.Command { 73 + root := &cobra.Command{ 74 + Use: "movie", 75 + Short: "Manage movie watch queue", 76 + } 77 + 78 + root.AddCommand(&cobra.Command{ 79 + Use: "add [title]", 80 + Short: "Add movie to watch queue", 81 + Args: cobra.MinimumNArgs(1), 82 + RunE: func(cmd *cobra.Command, args []string) error { 83 + title := args[0] 84 + fmt.Printf("Adding movie: %s\n", title) 85 + // TODO: Implement movie addition 86 + return nil 87 + }, 88 + }) 89 + 90 + root.AddCommand(&cobra.Command{ 91 + Use: "list", 92 + Short: "List movies in queue", 93 + RunE: func(cmd *cobra.Command, args []string) error { 94 + fmt.Println("Listing movies...") 95 + // TODO: Implement movie listing 96 + return nil 97 + }, 98 + }) 99 + 100 + return root 101 + } 102 + 103 + func tvCmd() *cobra.Command { 104 + root := &cobra.Command{ 105 + Use: "tv", 106 + Short: "Manage TV show watch queue", 107 + } 108 + 109 + root.AddCommand(&cobra.Command{ 110 + Use: "add [title]", 111 + Short: "Add TV show to watch queue", 112 + Args: cobra.MinimumNArgs(1), 113 + RunE: func(cmd *cobra.Command, args []string) error { 114 + title := args[0] 115 + fmt.Printf("Adding TV show: %s\n", title) 116 + // TODO: Implement TV show addition 117 + return nil 118 + }, 119 + }) 120 + 121 + root.AddCommand(&cobra.Command{ 122 + Use: "list", 123 + Short: "List TV shows in queue", 124 + RunE: func(cmd *cobra.Command, args []string) error { 125 + fmt.Println("Listing TV shows...") 126 + // TODO: Implement TV show listing 127 + return nil 128 + }, 129 + }) 130 + 131 + return root 132 + } 133 + 134 + func bookCmd() *cobra.Command { 135 + root := &cobra.Command{ 136 + Use: "book", 137 + Short: "Manage reading list", 138 + } 139 + 140 + root.AddCommand(&cobra.Command{ 141 + Use: "add [title]", 142 + Short: "Add book to reading list", 143 + Args: cobra.MinimumNArgs(1), 144 + RunE: func(cmd *cobra.Command, args []string) error { 145 + title := args[0] 146 + fmt.Printf("Adding book: %s\n", title) 147 + // TODO: Implement book addition 148 + return nil 149 + }, 150 + }) 151 + 152 + root.AddCommand(&cobra.Command{ 153 + Use: "list", 154 + Short: "List books in reading list", 155 + RunE: func(cmd *cobra.Command, args []string) error { 156 + fmt.Println("Listing books...") 157 + // TODO: Implement book listing 158 + return nil 159 + }, 160 + }) 161 + 162 + return root 163 + } 164 + 165 + func noteCmd() *cobra.Command { 166 + root := &cobra.Command{ 167 + Use: "note", 168 + Short: "Manage notes", 169 + } 170 + 171 + root.AddCommand(&cobra.Command{ 172 + Use: "create [title] [content...]", 173 + Short: "Create a new note", 174 + Aliases: []string{"new"}, 175 + RunE: func(cmd *cobra.Command, args []string) error { 176 + return handlers.Create(cmd.Context(), args) 177 + }, 178 + }) 179 + 180 + return root 181 + } 182 + 183 + func statusCmd() *cobra.Command { 184 + return &cobra.Command{ 185 + Use: "status", 186 + Short: "Show application status and configuration", 187 + RunE: func(cmd *cobra.Command, args []string) error { 188 + return handlers.Status(cmd.Context(), args) 189 + }, 190 + } 191 + } 192 + 193 + func resetCmd() *cobra.Command { 194 + return &cobra.Command{ 195 + Use: "reset", 196 + Short: "Reset the application (removes all data)", 197 + RunE: func(cmd *cobra.Command, args []string) error { 198 + return handlers.Reset(cmd.Context(), args) 199 + }, 200 + } 201 + } 202 + 203 + func setupCmd() *cobra.Command { 204 + return &cobra.Command{ 205 + Use: "setup", 206 + Short: "Initialize the application database and configuration", 207 + RunE: func(cmd *cobra.Command, args []string) error { 208 + return handlers.Setup(cmd.Context(), args) 209 + }, 210 + } 211 + } 212 + 213 + func confCmd() *cobra.Command { 214 + return &cobra.Command{ 215 + Use: "config [key] [value]", 216 + Short: "Manage configuration", 217 + Args: cobra.ExactArgs(2), 218 + RunE: func(cmd *cobra.Command, args []string) error { 219 + key, value := args[0], args[1] 220 + fmt.Printf("Setting config %s = %s\n", key, value) 221 + // TODO: Implement config management 222 + return nil 223 + }, 224 + } 225 + }
+15 -193
cmd/cli/main.go
··· 4 4 "context" 5 5 "fmt" 6 6 "os" 7 - "strings" 8 7 9 8 "github.com/charmbracelet/fang" 10 9 "github.com/spf13/cobra" 11 - "github.com/stormlightlabs/noteleaf/cmd/handlers" 12 10 "github.com/stormlightlabs/noteleaf/internal/store" 13 11 "github.com/stormlightlabs/noteleaf/internal/ui" 14 12 "github.com/stormlightlabs/noteleaf/internal/utils" ··· 27 25 return nil, fmt.Errorf("failed to initialize database: %w", err) 28 26 } 29 27 30 - config, err := store.LoadConfig() 31 - if err != nil { 28 + if config, err := store.LoadConfig(); err != nil { 32 29 return nil, fmt.Errorf("failed to load configuration: %w", err) 30 + } else { 31 + return &App{db: db, config: config}, nil 33 32 } 34 - 35 - return &App{ 36 - db: db, 37 - config: config, 38 - }, nil 39 33 } 40 34 41 35 // Close cleans up application resources ··· 56 50 } 57 51 defer app.Close() 58 52 59 - rootCmd := &cobra.Command{ 60 - Use: "noteleaf", 61 - Short: "A TaskWarrior-inspired CLI with media queues and reading lists", 62 - Run: func(cmd *cobra.Command, args []string) { 63 - if len(args) == 0 { 64 - fmt.Println(ui.Collosal.ColoredInViewport()) 65 - cmd.Help() 66 - return 67 - } 68 - 69 - output := strings.Join(args, " ") 70 - fmt.Println(output) 71 - }, 72 - } 73 - 74 - rootCmd.AddCommand(&cobra.Command{ 75 - Use: "setup", 76 - Short: "Initialize the application database and configuration", 77 - RunE: func(cmd *cobra.Command, args []string) error { 78 - return handlers.Setup(cmd.Context(), args) 79 - }, 80 - }) 81 - 82 - rootCmd.AddCommand(&cobra.Command{ 83 - Use: "reset", 84 - Short: "Reset the application (removes all data)", 85 - RunE: func(cmd *cobra.Command, args []string) error { 86 - return handlers.Reset(cmd.Context(), args) 87 - }, 88 - }) 89 - 90 - rootCmd.AddCommand(&cobra.Command{ 91 - Use: "status", 92 - Short: "Show application status and configuration", 93 - RunE: func(cmd *cobra.Command, args []string) error { 94 - return handlers.Status(cmd.Context(), args) 95 - }, 96 - }) 97 - 98 - rootCmd.AddCommand(&cobra.Command{ 99 - Use: "add [description]", 100 - Short: "Add a new task", 101 - Args: cobra.MinimumNArgs(1), 102 - RunE: func(cmd *cobra.Command, args []string) error { 103 - description := args[0] 104 - fmt.Printf("Adding task: %s\n", description) 105 - // TODO: Implement task creation 106 - return nil 107 - }, 108 - }) 109 - 110 - rootCmd.AddCommand(&cobra.Command{ 111 - Use: "list", 112 - Short: "List tasks", 113 - Aliases: []string{"ls"}, 114 - RunE: func(cmd *cobra.Command, args []string) error { 115 - fmt.Println("Listing tasks...") 116 - // TODO: Implement task listing 117 - return nil 118 - }, 119 - }) 120 - 121 - rootCmd.AddCommand(&cobra.Command{ 122 - Use: "done [task-id]", 123 - Short: "Mark task as completed", 124 - Args: cobra.ExactArgs(1), 125 - RunE: func(cmd *cobra.Command, args []string) error { 126 - taskID := args[0] 127 - fmt.Printf("Marking task %s as done\n", taskID) 128 - // TODO: Implement task completion 129 - return nil 130 - }, 131 - }) 132 - 133 - movieCmd := &cobra.Command{ 134 - Use: "movie", 135 - Short: "Manage movie watch queue", 136 - } 137 - 138 - movieCmd.AddCommand(&cobra.Command{ 139 - Use: "add [title]", 140 - Short: "Add movie to watch queue", 141 - Args: cobra.MinimumNArgs(1), 142 - RunE: func(cmd *cobra.Command, args []string) error { 143 - title := args[0] 144 - fmt.Printf("Adding movie: %s\n", title) 145 - // TODO: Implement movie addition 146 - return nil 147 - }, 148 - }) 149 - 150 - movieCmd.AddCommand(&cobra.Command{ 151 - Use: "list", 152 - Short: "List movies in queue", 153 - RunE: func(cmd *cobra.Command, args []string) error { 154 - fmt.Println("Listing movies...") 155 - // TODO: Implement movie listing 156 - return nil 157 - }, 158 - }) 159 - 160 - rootCmd.AddCommand(movieCmd) 161 - 162 - tvCmd := &cobra.Command{ 163 - Use: "tv", 164 - Short: "Manage TV show watch queue", 53 + root := rootCmd() 54 + commands := []func() *cobra.Command{ 55 + setupCmd, resetCmd, statusCmd, todoCmd, 56 + movieCmd, noteCmd, tvCmd, bookCmd, confCmd, 165 57 } 166 58 167 - tvCmd.AddCommand(&cobra.Command{ 168 - Use: "add [title]", 169 - Short: "Add TV show to watch queue", 170 - Args: cobra.MinimumNArgs(1), 171 - RunE: func(cmd *cobra.Command, args []string) error { 172 - title := args[0] 173 - fmt.Printf("Adding TV show: %s\n", title) 174 - // TODO: Implement TV show addition 175 - return nil 176 - }, 177 - }) 178 - 179 - tvCmd.AddCommand(&cobra.Command{ 180 - Use: "list", 181 - Short: "List TV shows in queue", 182 - RunE: func(cmd *cobra.Command, args []string) error { 183 - fmt.Println("Listing TV shows...") 184 - // TODO: Implement TV show listing 185 - return nil 186 - }, 187 - }) 188 - 189 - rootCmd.AddCommand(tvCmd) 190 - 191 - bookCmd := &cobra.Command{ 192 - Use: "book", 193 - Short: "Manage reading list", 59 + for _, cmdFunc := range commands { 60 + cmd := cmdFunc() 61 + root.AddCommand(cmd) 194 62 } 195 63 196 - bookCmd.AddCommand(&cobra.Command{ 197 - Use: "add [title]", 198 - Short: "Add book to reading list", 199 - Args: cobra.MinimumNArgs(1), 200 - RunE: func(cmd *cobra.Command, args []string) error { 201 - title := args[0] 202 - fmt.Printf("Adding book: %s\n", title) 203 - // TODO: Implement book addition 204 - return nil 205 - }, 206 - }) 207 - 208 - bookCmd.AddCommand(&cobra.Command{ 209 - Use: "list", 210 - Short: "List books in reading list", 211 - RunE: func(cmd *cobra.Command, args []string) error { 212 - fmt.Println("Listing books...") 213 - // TODO: Implement book listing 214 - return nil 215 - }, 216 - }) 217 - 218 - rootCmd.AddCommand(bookCmd) 219 - 220 - noteCmd := &cobra.Command{ 221 - Use: "note", 222 - Short: "Manage notes", 64 + options := []fang.Option{ 65 + fang.WithVersion("0.1.0"), 66 + fang.WithoutCompletions(), 67 + fang.WithColorSchemeFunc(ui.NoteleafColorScheme), 223 68 } 224 69 225 - noteCmd.AddCommand(&cobra.Command{ 226 - Use: "create [title] [content...]", 227 - Short: "Create a new note", 228 - Aliases: []string{"new"}, 229 - RunE: func(cmd *cobra.Command, args []string) error { 230 - return handlers.Create(cmd.Context(), args) 231 - }, 232 - }) 233 - 234 - rootCmd.AddCommand(noteCmd) 235 - 236 - rootCmd.AddCommand(&cobra.Command{ 237 - Use: "config [key] [value]", 238 - Short: "Manage configuration", 239 - Args: cobra.ExactArgs(2), 240 - RunE: func(cmd *cobra.Command, args []string) error { 241 - key, value := args[0], args[1] 242 - fmt.Printf("Setting config %s = %s\n", key, value) 243 - // TODO: Implement config management 244 - return nil 245 - }, 246 - }) 247 - 248 - if err := fang.Execute(context.Background(), rootCmd, fang.WithVersion("0.1.0")); err != nil { 70 + if err := fang.Execute(context.Background(), root, options...); err != nil { 249 71 os.Exit(1) 250 72 } 251 73 }
+1 -1
codecov.yml
··· 20 20 - "**/*_test.go" 21 21 - "**/testdata/**" 22 22 - "**/vendor/**" 23 - - "cmd/cli/main.go" # Main entry point typically has minimal logic to test 23 + - "cmd/cli/*.go"
+6 -9
internal/ui/logo.go
··· 12 12 type Logo int 13 13 14 14 const ( 15 - Collosal Logo = iota 15 + Colossal Logo = iota 16 16 Georgia 17 17 Alligator 18 18 ANSI 19 19 ANSIShadow 20 20 ) 21 21 22 - const collosal string = ` 22 + const colossal string = ` 23 23 888b 888 888 888 .d888 24 24 8888b 888 888 888 d88P" 25 25 88888b 888 888 888 888 ··· 62 62 63 63 func (l Logo) String() string { 64 64 switch l { 65 - case Collosal: 66 - return collosal 65 + case Colossal: 66 + return colossal 67 67 case Georgia: 68 68 return georgia 69 69 case Alligator: ··· 73 73 case ANSIShadow: 74 74 return ansiShadow 75 75 default: 76 - return collosal 76 + return colossal 77 77 } 78 78 } 79 79 ··· 130 130 vp := viewport.New(maxWidth+4, len(lines)) 131 131 vp.SetContent(coloredLogo) 132 132 133 - style := lipgloss.NewStyle(). 134 - Border(lipgloss.RoundedBorder()). 135 - BorderForeground(lipgloss.Color("#6b7280")). 136 - Padding(1) 133 + style := lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("#6b7280")).PaddingLeft(1) 137 134 138 135 if len(renderer) > 0 && renderer[0] != nil { 139 136 style = style.Renderer(renderer[0])
+2 -2
internal/ui/ui_test.go
··· 270 270 name string 271 271 contains string 272 272 }{ 273 - {Collosal, "Collosal", "888b 888"}, 273 + {Colossal, "Collosal", "888b 888"}, 274 274 {Georgia, "Georgia", "`7MN. `7MF'"}, 275 275 {Alligator, "Alligator", ":::: ::: ::::::::"}, 276 276 {ANSI, "ANSI", "โ–ˆโ–ˆโ–ˆ โ–ˆโ–ˆ"}, ··· 308 308 309 309 t.Run("Colored in Viewport", func(t *testing.T) { 310 310 withColor(t, func(r *lipgloss.Renderer) { 311 - logo := Collosal 311 + logo := Colossal 312 312 viewport := logo.ColoredInViewport(r) 313 313 t.Logf("viewport output:\n%s", viewport) 314 314