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

feat(ui): update styles for article, task, and publication views to use new, consistent lipgloss color palette

+146 -92
+8 -8
internal/handlers/articles.go
··· 112 func (h *ArticleHandler) Add(ctx context.Context, url string) error { 113 existing, err := h.repos.Articles.GetByURL(ctx, url) 114 if err == nil { 115 - ui.Warningln("Article already exists: %s (ID: %d)", ui.TitleColorStyle.Render(existing.Title), existing.ID) 116 return nil 117 } 118 ··· 153 154 ui.Infoln("Article saved successfully!") 155 ui.Infoln("ID: %d", id) 156 - ui.Infoln("Title: %s", ui.TitleColorStyle.Render(article.Title)) 157 if article.Author != "" { 158 - ui.Infoln("Author: %s", ui.HeaderColorStyle.Render(article.Author)) 159 } 160 if article.Date != "" { 161 ui.Infoln("Date: %s", article.Date) ··· 187 ui.Infoln("Found %d article(s):\n", len(articles)) 188 for _, article := range articles { 189 ui.Infoln("ID: %d", article.ID) 190 - ui.Infoln("Title: %s", ui.TitleColorStyle.Render(article.Title)) 191 if article.Author != "" { 192 - ui.Infoln("Author: %s", ui.HeaderColorStyle.Render(article.Author)) 193 } 194 if article.Date != "" { 195 ui.Infoln("Date: %s", article.Date) ··· 208 return fmt.Errorf("failed to get article: %w", err) 209 } 210 211 - ui.Infoln("Title: %s", ui.TitleColorStyle.Render(article.Title)) 212 if article.Author != "" { 213 - ui.Infoln("Author: %s", ui.HeaderColorStyle.Render(article.Author)) 214 } 215 if article.Date != "" { 216 ui.Infoln("Date: %s", article.Date) ··· 302 if err != nil { 303 return fmt.Errorf("failed to get storage directory: %w", err) 304 } 305 - ui.Headerln("%s %s", ui.HeaderColorStyle.Render("Storage directory:"), dir) 306 307 return nil 308 }
··· 112 func (h *ArticleHandler) Add(ctx context.Context, url string) error { 113 existing, err := h.repos.Articles.GetByURL(ctx, url) 114 if err == nil { 115 + ui.Warningln("Article already exists: %s (ID: %d)", ui.TableTitleStyle.Render(existing.Title), existing.ID) 116 return nil 117 } 118 ··· 153 154 ui.Infoln("Article saved successfully!") 155 ui.Infoln("ID: %d", id) 156 + ui.Infoln("Title: %s", ui.TableTitleStyle.Render(article.Title)) 157 if article.Author != "" { 158 + ui.Infoln("Author: %s", ui.TableHeaderStyle.Render(article.Author)) 159 } 160 if article.Date != "" { 161 ui.Infoln("Date: %s", article.Date) ··· 187 ui.Infoln("Found %d article(s):\n", len(articles)) 188 for _, article := range articles { 189 ui.Infoln("ID: %d", article.ID) 190 + ui.Infoln("Title: %s", ui.TableTitleStyle.Render(article.Title)) 191 if article.Author != "" { 192 + ui.Infoln("Author: %s", ui.TableHeaderStyle.Render(article.Author)) 193 } 194 if article.Date != "" { 195 ui.Infoln("Date: %s", article.Date) ··· 208 return fmt.Errorf("failed to get article: %w", err) 209 } 210 211 + ui.Infoln("Title: %s", ui.TableTitleStyle.Render(article.Title)) 212 if article.Author != "" { 213 + ui.Infoln("Author: %s", ui.TableHeaderStyle.Render(article.Author)) 214 } 215 if article.Date != "" { 216 ui.Infoln("Date: %s", article.Date) ··· 302 if err != nil { 303 return fmt.Errorf("failed to get storage directory: %w", err) 304 } 305 + ui.Headerln("%s %s", ui.TableHeaderStyle.Render("Storage directory:"), dir) 306 307 return nil 308 }
+36 -4
internal/ui/common.go
··· 1 - // TODO: create variants of colored output without icons 2 - // TODO: refactor existing (relevant) calls to old styles 3 - // TODO: k v wrappers 4 package ui 5 6 import ( ··· 9 "github.com/charmbracelet/lipgloss" 10 ) 11 12 func newStyle() lipgloss.Style { return lipgloss.NewStyle() } 13 func newPStyle(v, h int) lipgloss.Style { return lipgloss.NewStyle().Padding(v, h) } 14 func newBoldStyle() lipgloss.Style { return newStyle().Bold(true) } 15 func newPBoldStyle(v, h int) lipgloss.Style { return newPStyle(v, h).Bold(true) } 16 func newEmStyle() lipgloss.Style { return newStyle().Italic(true) } 17 18 func success(msg string) string { return SuccessStyle.Render("โœ“ " + msg) } 19 func errorMsg(msg string) string { return ErrorStyle.Render("โœ— " + msg) } 20 func warning(msg string) string { return WarningStyle.Render("โš  " + msg) } ··· 25 func box(content string) string { return BoxStyle.Render(content) } 26 func errorBox(content string) string { return ErrorBoxStyle.Render(content) } 27 func text(content string) string { return TextStyle.Render(content) } 28 func header(content string) string { return HeaderStyle.Render(content) } 29 30 // Success prints a formatted success message 31 func Success(format string, a ...any) { ··· 121 func Plain(format string, a ...any) { fmt.Print(text(fmt.Sprintf(format, a...))) } 122 func Plainln(format string, a ...any) { fmt.Println(text(fmt.Sprintf(format, a...))) } 123 func Header(format string, a ...any) { fmt.Print(header(fmt.Sprintf(format, a...))) } 124 - func Headerln(format string, a ...any) { fmt.Print(header(fmt.Sprintf(format, a...))) }
··· 1 package ui 2 3 import ( ··· 6 "github.com/charmbracelet/lipgloss" 7 ) 8 9 + // Style constructor helpers 10 func newStyle() lipgloss.Style { return lipgloss.NewStyle() } 11 func newPStyle(v, h int) lipgloss.Style { return lipgloss.NewStyle().Padding(v, h) } 12 func newBoldStyle() lipgloss.Style { return newStyle().Bold(true) } 13 func newPBoldStyle(v, h int) lipgloss.Style { return newPStyle(v, h).Bold(true) } 14 func newEmStyle() lipgloss.Style { return newStyle().Italic(true) } 15 16 + // Rendering helpers (private, used by public API) 17 func success(msg string) string { return SuccessStyle.Render("โœ“ " + msg) } 18 func errorMsg(msg string) string { return ErrorStyle.Render("โœ— " + msg) } 19 func warning(msg string) string { return WarningStyle.Render("โš  " + msg) } ··· 24 func box(content string) string { return BoxStyle.Render(content) } 25 func errorBox(content string) string { return ErrorBoxStyle.Render(content) } 26 func text(content string) string { return TextStyle.Render(content) } 27 + func muted(content string) string { return MutedStyle.Render(content) } 28 + func accent(content string) string { return AccentStyle.Render(content) } 29 func header(content string) string { return HeaderStyle.Render(content) } 30 + func primary(content string) string { return PrimaryStyle.Render(content) } 31 32 // Success prints a formatted success message 33 func Success(format string, a ...any) { ··· 123 func Plain(format string, a ...any) { fmt.Print(text(fmt.Sprintf(format, a...))) } 124 func Plainln(format string, a ...any) { fmt.Println(text(fmt.Sprintf(format, a...))) } 125 func Header(format string, a ...any) { fmt.Print(header(fmt.Sprintf(format, a...))) } 126 + func Headerln(format string, a ...any) { fmt.Println(header(fmt.Sprintf(format, a...))) } 127 + 128 + // Muted prints muted/secondary text 129 + func Muted(format string, a ...any) { 130 + fmt.Print(muted(fmt.Sprintf(format, a...))) 131 + } 132 + 133 + // Mutedln prints muted/secondary text with a newline 134 + func Mutedln(format string, a ...any) { 135 + fmt.Println(muted(fmt.Sprintf(format, a...))) 136 + } 137 + 138 + // Accent prints accent-colored text 139 + func Accent(format string, a ...any) { 140 + fmt.Print(accent(fmt.Sprintf(format, a...))) 141 + } 142 + 143 + // Accentln prints accent-colored text with a newline 144 + func Accentln(format string, a ...any) { 145 + fmt.Println(accent(fmt.Sprintf(format, a...))) 146 + } 147 + 148 + // Primary prints primary-colored text 149 + func Primary(format string, a ...any) { 150 + fmt.Print(primary(fmt.Sprintf(format, a...))) 151 + } 152 + 153 + // Primaryln prints primary-colored text with a newline 154 + func Primaryln(format string, a ...any) { 155 + fmt.Println(primary(fmt.Sprintf(format, a...))) 156 + }
+3 -4
internal/ui/data_list.go
··· 11 "github.com/charmbracelet/bubbles/key" 12 "github.com/charmbracelet/bubbles/viewport" 13 tea "github.com/charmbracelet/bubbletea" 14 - "github.com/charmbracelet/lipgloss" 15 "github.com/stormlightlabs/noteleaf/internal/models" 16 ) 17 ··· 315 func (m dataListModel) View() string { 316 var s strings.Builder 317 318 - style := lipgloss.NewStyle().Foreground(lipgloss.Color(Squid.Hex())) 319 320 if m.showingHelp { 321 return m.help.View(m.keys) ··· 328 return s.String() 329 } 330 331 - s.WriteString(TitleColorStyle.Render(m.opts.Title)) 332 if m.totalCount > 0 { 333 s.WriteString(fmt.Sprintf(" (%d total)", m.totalCount)) 334 } ··· 434 } 435 436 if selected { 437 - return SelectedColorStyle.Render(line) 438 } 439 return line 440 }
··· 11 "github.com/charmbracelet/bubbles/key" 12 "github.com/charmbracelet/bubbles/viewport" 13 tea "github.com/charmbracelet/bubbletea" 14 "github.com/stormlightlabs/noteleaf/internal/models" 15 ) 16 ··· 314 func (m dataListModel) View() string { 315 var s strings.Builder 316 317 + style := MutedStyle 318 319 if m.showingHelp { 320 return m.help.View(m.keys) ··· 327 return s.String() 328 } 329 330 + s.WriteString(TableTitleStyle.Render(m.opts.Title)) 331 if m.totalCount > 0 { 332 s.WriteString(fmt.Sprintf(" (%d total)", m.totalCount)) 333 } ··· 433 } 434 435 if selected { 436 + return TableSelectedStyle.Render(line) 437 } 438 return line 439 }
+5 -6
internal/ui/data_table.go
··· 10 "github.com/charmbracelet/bubbles/help" 11 "github.com/charmbracelet/bubbles/key" 12 tea "github.com/charmbracelet/bubbletea" 13 - "github.com/charmbracelet/lipgloss" 14 "github.com/stormlightlabs/noteleaf/internal/models" 15 ) 16 ··· 258 func (m dataTableModel) View() string { 259 var s strings.Builder 260 261 - style := lipgloss.NewStyle().Foreground(lipgloss.Color(Squid.Hex())) 262 263 if m.showingHelp { 264 return m.help.View(m.keys) ··· 271 return s.String() 272 } 273 274 - s.WriteString(TitleColorStyle.Render(m.opts.Title)) 275 if m.totalCount > 0 { 276 s.WriteString(fmt.Sprintf(" (%d total)", m.totalCount)) 277 } ··· 300 headerParts[i] = fmt.Sprintf(format, field.Title) 301 } 302 headerLine := fmt.Sprintf(" %s", strings.Join(headerParts, " ")) 303 - s.WriteString(HeaderColorStyle.Render(headerLine)) 304 s.WriteString("\n") 305 306 totalWidth := 3 + len(strings.Join(headerParts, " ")) 307 - s.WriteString(HeaderColorStyle.Render(strings.Repeat("โ”€", totalWidth))) 308 s.WriteString("\n") 309 310 for i, record := range m.records { ··· 335 line := fmt.Sprintf("%s%s", prefix, strings.Join(rowParts, " ")) 336 337 if i == m.selected { 338 - s.WriteString(SelectedColorStyle.Render(line)) 339 } else { 340 s.WriteString(style.Render(line)) 341 }
··· 10 "github.com/charmbracelet/bubbles/help" 11 "github.com/charmbracelet/bubbles/key" 12 tea "github.com/charmbracelet/bubbletea" 13 "github.com/stormlightlabs/noteleaf/internal/models" 14 ) 15 ··· 257 func (m dataTableModel) View() string { 258 var s strings.Builder 259 260 + style := MutedStyle 261 262 if m.showingHelp { 263 return m.help.View(m.keys) ··· 270 return s.String() 271 } 272 273 + s.WriteString(TableTitleStyle.Render(m.opts.Title)) 274 if m.totalCount > 0 { 275 s.WriteString(fmt.Sprintf(" (%d total)", m.totalCount)) 276 } ··· 299 headerParts[i] = fmt.Sprintf(format, field.Title) 300 } 301 headerLine := fmt.Sprintf(" %s", strings.Join(headerParts, " ")) 302 + s.WriteString(TableHeaderStyle.Render(headerLine)) 303 s.WriteString("\n") 304 305 totalWidth := 3 + len(strings.Join(headerParts, " ")) 306 + s.WriteString(TableHeaderStyle.Render(strings.Repeat("โ”€", totalWidth))) 307 s.WriteString("\n") 308 309 for i, record := range m.records { ··· 334 line := fmt.Sprintf("%s%s", prefix, strings.Join(rowParts, " ")) 335 336 if i == m.selected { 337 + s.WriteString(TableSelectedStyle.Render(line)) 338 } else { 339 s.WriteString(style.Render(line)) 340 }
+72 -36
internal/ui/palette.go
··· 53 } 54 55 var ( 56 - ColorPrimary = Thunder.Hex() // Blue 57 - ColorAccent = Cumin.Hex() // Yellow/Gold 58 - ColorError = Paprika.Hex() // Red/Pink 59 - ColorText = Salt.Hex() // Light text 60 - ColorBG = Pepper.Hex() // Dark background 61 62 - PrimaryStyle = newStyle().Foreground(lipgloss.Color(ColorPrimary)) 63 - AccentStyle = newStyle().Foreground(lipgloss.Color(ColorAccent)) 64 - ErrorStyle = newStyle().Foreground(lipgloss.Color(ColorError)) 65 - TextStyle = newStyle().Foreground(lipgloss.Color(ColorText)) 66 - TitleStyle = newPBoldStyle(0, 1).Foreground(lipgloss.Color(ColorAccent)) 67 - SubtitleStyle = newEmStyle().Foreground(lipgloss.Color(ColorPrimary)) 68 - SuccessStyle = newBoldStyle().Foreground(lipgloss.Color(ColorPrimary)) 69 - WarningStyle = newBoldStyle().Foreground(lipgloss.Color(ColorAccent)) 70 - InfoStyle = newStyle().Foreground(lipgloss.Color(ColorText)) 71 - BoxStyle = newPStyle(1, 2).Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color(ColorPrimary)) 72 - ErrorBoxStyle = newPStyle(1, 2).Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color(ColorError)) 73 - ListItemStyle = newStyle().Foreground(lipgloss.Color(ColorText)).PaddingLeft(2) 74 - SelectedItemStyle = newBoldStyle().Foreground(lipgloss.Color(ColorAccent)).PaddingLeft(2) 75 - HeaderStyle = newPBoldStyle(0, 1).Foreground(lipgloss.Color(ColorPrimary)) 76 - CellStyle = newPStyle(0, 1).Foreground(lipgloss.Color(ColorText)) 77 78 - TaskTitleStyle = newBoldStyle().Foreground(lipgloss.Color(Salt.Hex())) 79 - TaskIDStyle = newStyle().Foreground(lipgloss.Color(Squid.Hex())).Width(8) 80 81 - StatusPending = newStyle().Foreground(lipgloss.Color(Citron.Hex())) 82 - StatusCompleted = newStyle().Foreground(lipgloss.Color(Julep.Hex())) 83 84 - PriorityHigh = newBoldStyle().Foreground(lipgloss.Color(Cherry.Hex())) 85 - PriorityMedium = newStyle().Foreground(lipgloss.Color(Citron.Hex())) 86 - PriorityLow = newStyle().Foreground(lipgloss.Color(Squid.Hex())) 87 88 - MovieStyle = newBoldStyle().Foreground(lipgloss.Color(Coral.Hex())) 89 - TVStyle = newBoldStyle().Foreground(lipgloss.Color(Violet.Hex())) 90 - BookStyle = newBoldStyle().Foreground(lipgloss.Color(Guac.Hex())) 91 - MusicStyle = newBoldStyle().Foreground(lipgloss.Color(Lichen.Hex())) 92 93 - TableStyle = newStyle().BorderStyle(lipgloss.NormalBorder()).BorderForeground(lipgloss.Color(Smoke.Hex())) 94 - SelectedStyle = newBoldStyle().Foreground(lipgloss.Color(Salt.Hex())).Background(lipgloss.Color(Squid.Hex())) 95 - TitleColorStyle = newBoldStyle().Foreground(lipgloss.Color("212")) 96 - SelectedColorStyle = newBoldStyle().Foreground(lipgloss.Color("0")).Background(lipgloss.Color("212")) 97 - HeaderColorStyle = newBoldStyle().Foreground(lipgloss.Color("240")) 98 )
··· 53 } 54 55 var ( 56 + // Background colors (dark mode, Iceberg-inspired) 57 + ColorBGBase = Pepper.Hex() // #201F26 - Darkest base 58 + ColorBGSecondary = BBQ.Hex() // #2d2c35 - Secondary background 59 + ColorBGTertiary = Charcoal.Hex() // #3A3943 - Tertiary/elevated 60 + ColorBGInput = Iron.Hex() // #4D4C57 - Input fields/focus 61 62 + // Text colors (light to dark hierarchy) 63 + ColorTextPrimary = Salt.Hex() // #F1EFEF - Primary text (brightest) 64 + ColorTextSecondary = Smoke.Hex() // #BFBCC8 - Secondary text 65 + ColorTextMuted = Squid.Hex() // #858392 - Muted/comments 66 + ColorTextDimmed = Oyster.Hex() // #605F6B - Dimmed text 67 68 + // Semantic colors (Iceberg-inspired: cool blues/purples with warm accents) 69 + ColorPrimary = Malibu.Hex() // #00A4FF - Blue (primary accent) 70 + ColorSuccess = Julep.Hex() // #00FFB2 - Green (success/positive) 71 + ColorError = Sriracha.Hex() // #EB4268 - Red (errors) 72 + ColorWarning = Tang.Hex() // #FF985A - Orange (warnings) 73 + ColorInfo = Violet.Hex() // #C259FF - Purple (info) 74 + ColorAccent = Lichen.Hex() // #5CDFEA - Teal (secondary accent) 75 76 + // Base styles 77 + PrimaryStyle = newStyle().Foreground(lipgloss.Color(ColorPrimary)) 78 + SuccessStyle = newBoldStyle().Foreground(lipgloss.Color(ColorSuccess)) 79 + ErrorStyle = newBoldStyle().Foreground(lipgloss.Color(ColorError)) 80 + WarningStyle = newBoldStyle().Foreground(lipgloss.Color(ColorWarning)) 81 + InfoStyle = newStyle().Foreground(lipgloss.Color(ColorTextSecondary)) 82 + AccentStyle = newStyle().Foreground(lipgloss.Color(ColorAccent)) 83 + TextStyle = newStyle().Foreground(lipgloss.Color(ColorTextPrimary)) 84 + MutedStyle = newStyle().Foreground(lipgloss.Color(ColorTextMuted)) 85 + TitleStyle = newPBoldStyle(0, 1).Foreground(lipgloss.Color(ColorPrimary)) 86 + SubtitleStyle = newEmStyle().Foreground(lipgloss.Color(ColorAccent)) 87 88 + // Layout styles 89 + BoxStyle = newPStyle(1, 2).Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color(ColorPrimary)) 90 + ErrorBoxStyle = newPStyle(1, 2).Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color(ColorError)) 91 + HeaderStyle = newPBoldStyle(0, 1).Foreground(lipgloss.Color(ColorPrimary)) 92 + CellStyle = newPStyle(0, 1).Foreground(lipgloss.Color(ColorTextPrimary)) 93 94 + // List styles 95 + ListItemStyle = newStyle().Foreground(lipgloss.Color(ColorTextPrimary)).PaddingLeft(2) 96 + SelectedItemStyle = newBoldStyle().Foreground(lipgloss.Color(ColorPrimary)).PaddingLeft(2) 97 + 98 + // Table/data view styles (replacing ANSI code references) 99 + TableStyle = newStyle().BorderStyle(lipgloss.NormalBorder()).BorderForeground(lipgloss.Color(ColorTextMuted)) 100 + TableHeaderStyle = newBoldStyle().Foreground(lipgloss.Color(ColorAccent)) 101 + TableTitleStyle = newBoldStyle().Foreground(lipgloss.Color(ColorPrimary)) 102 + TableSelectedStyle = newBoldStyle().Foreground(lipgloss.Color(ColorTextPrimary)).Background(lipgloss.Color(ColorBGInput)) 103 104 + // Task-specific styles 105 + TaskTitleStyle = newBoldStyle().Foreground(lipgloss.Color(ColorTextPrimary)) 106 + TaskIDStyle = newStyle().Foreground(lipgloss.Color(ColorTextMuted)).Width(8) 107 + 108 + // Status styles (Iceberg-inspired: muted โ†’ blue โ†’ red โ†’ green) 109 + StatusTodo = newStyle().Foreground(lipgloss.Color(ColorTextMuted)) // Gray (muted) 110 + StatusInProgress = newStyle().Foreground(lipgloss.Color(ColorPrimary)) // Blue (active) 111 + StatusBlocked = newStyle().Foreground(lipgloss.Color(ColorError)) // Red (blocked) 112 + StatusDone = newStyle().Foreground(lipgloss.Color(ColorSuccess)) // Green (success) 113 + StatusPending = newStyle().Foreground(lipgloss.Color(ColorWarning)) // Orange (pending) 114 + StatusCompleted = newStyle().Foreground(lipgloss.Color(ColorSuccess)) // Green (completed) 115 + StatusAbandoned = newStyle().Foreground(lipgloss.Color(ColorTextDimmed)) // Dimmed gray (abandoned) 116 + StatusDeleted = newStyle().Foreground(lipgloss.Color(Cherry.Hex())) // Dark red (deleted) 117 + 118 + // Priority styles (Iceberg-inspired: red โ†’ orange โ†’ gray) 119 + PriorityHigh = newBoldStyle().Foreground(lipgloss.Color(Cherry.Hex())) // #FF388B - Bright red 120 + PriorityMedium = newStyle().Foreground(lipgloss.Color(Tang.Hex())) // #FF985A - Orange 121 + PriorityLow = newStyle().Foreground(lipgloss.Color(ColorAccent)) // Teal (low) 122 + PriorityNone = newStyle().Foreground(lipgloss.Color(ColorTextMuted)) // Gray (no priority) 123 + PriorityLegacy = newStyle().Foreground(lipgloss.Color(Urchin.Hex())) // #C337E0 - Magenta (legacy) 124 + 125 + // Content type styles (distinctive colors for different media) 126 + MovieStyle = newBoldStyle().Foreground(lipgloss.Color(Coral.Hex())) // #FF577D - Pink/coral 127 + TVStyle = newBoldStyle().Foreground(lipgloss.Color(Violet.Hex())) // #C259FF - Purple 128 + BookStyle = newBoldStyle().Foreground(lipgloss.Color(Guac.Hex())) // #12C78F - Green 129 + MusicStyle = newBoldStyle().Foreground(lipgloss.Color(Lichen.Hex())) // #5CDFEA - Teal 130 + 131 + // Diff styles 132 + AdditionStyle = newStyle().Foreground(lipgloss.Color(Pickle.Hex())) // #00A475 - Green 133 + DeletionStyle = newStyle().Foreground(lipgloss.Color(Pom.Hex())) // #AB2454 - Red 134 )
+2 -2
internal/ui/publication_view.go
··· 162 status = "draft" 163 } 164 165 - title := TitleColorStyle.Render(fmt.Sprintf("%s (%s)", m.note.Title, status)) 166 content := m.viewport.View() 167 - help := lipgloss.NewStyle().Foreground(lipgloss.Color(Squid.Hex())).Render(m.help.View(m.keys)) 168 169 if !m.ready { 170 return "\n Initializing..."
··· 162 status = "draft" 163 } 164 165 + title := TableTitleStyle.Render(fmt.Sprintf("%s (%s)", m.note.Title, status)) 166 content := m.viewport.View() 167 + help := MutedStyle.Render(m.help.View(m.keys)) 168 169 if !m.ready { 170 return "\n Initializing..."
+4 -4
internal/ui/task_edit.go
··· 350 351 var content strings.Builder 352 353 - title := TitleColorStyle.Render("Edit Task") 354 content.WriteString(title + "\n\n") 355 356 for i, field := range m.fields { 357 fieldStyle := lipgloss.NewStyle() 358 if i == m.currentField && m.mode == fieldNavigation { 359 - fieldStyle = SelectedColorStyle 360 } 361 362 switch field { ··· 427 for i, status := range statusOptions { 428 style := lipgloss.NewStyle() 429 if i == m.statusIndex { 430 - style = SelectedColorStyle 431 } 432 433 line := fmt.Sprintf("%s %s", FormatStatusIndicator(status), status) ··· 460 for i, priority := range options { 461 style := lipgloss.NewStyle() 462 if i == m.priorityIndex { 463 - style = SelectedColorStyle 464 } 465 466 var line string
··· 350 351 var content strings.Builder 352 353 + title := TableTitleStyle.Render("Edit Task") 354 content.WriteString(title + "\n\n") 355 356 for i, field := range m.fields { 357 fieldStyle := lipgloss.NewStyle() 358 if i == m.currentField && m.mode == fieldNavigation { 359 + fieldStyle = TableSelectedStyle 360 } 361 362 switch field { ··· 427 for i, status := range statusOptions { 428 style := lipgloss.NewStyle() 429 if i == m.statusIndex { 430 + style = TableSelectedStyle 431 } 432 433 line := fmt.Sprintf("%s %s", FormatStatusIndicator(status), status) ··· 460 for i, priority := range options { 461 style := lipgloss.NewStyle() 462 if i == m.priorityIndex { 463 + style = TableSelectedStyle 464 } 465 466 var line string
+14 -26
internal/ui/task_information.go
··· 44 PriorityNonePattern = "โ˜†โ˜†โ˜†" 45 ) 46 47 var ( 48 - // Gray 49 - TodoStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) 50 - // Blue 51 - InProgressStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("12")) 52 - // Red 53 - BlockedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("9")) 54 - // Green 55 - DoneStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("10")) 56 - // Dark Gray 57 - AbandonedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) 58 - // Light Gray 59 - PendingStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("7")) 60 - // Green 61 - CompletedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("10")) 62 - // Dark Red 63 - DeletedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("1")) 64 - // Bright Red - highest urgency 65 - PriorityHighStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("196")) 66 - // Yellow - medium urgency 67 - PriorityMediumStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("11")) 68 - // Cyan - low urgency 69 - PriorityLowStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) 70 - // Gray - no priority 71 - PriorityNoneStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) 72 - // For legacy A-Z and numeric priorities 73 - PriorityLegacyStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("13")) // Magenta 74 ) 75 76 // GetStatusSymbol returns the unicode symbol for a given status
··· 44 PriorityNonePattern = "โ˜†โ˜†โ˜†" 45 ) 46 47 + // Type aliases for status and priority styles (now defined in palette.go) 48 var ( 49 + TodoStyle = StatusTodo 50 + InProgressStyle = StatusInProgress 51 + BlockedStyle = StatusBlocked 52 + DoneStyle = StatusDone 53 + AbandonedStyle = StatusAbandoned 54 + PendingStyle = StatusPending 55 + CompletedStyle = StatusCompleted 56 + DeletedStyle = StatusDeleted 57 + PriorityHighStyle = PriorityHigh 58 + PriorityMediumStyle = PriorityMedium 59 + PriorityLowStyle = PriorityLow 60 + PriorityNoneStyle = PriorityNone 61 + PriorityLegacyStyle = PriorityLegacy 62 ) 63 64 // GetStatusSymbol returns the unicode symbol for a given status
+2 -2
internal/ui/task_view.go
··· 157 return m.help.View(m.keys) 158 } 159 160 - title := TitleColorStyle.Render(fmt.Sprintf("Task %d", m.task.ID)) 161 content := m.viewport.View() 162 - help := lipgloss.NewStyle().Foreground(lipgloss.Color(Squid.Hex())).Render(m.help.View(m.keys)) 163 164 return lipgloss.JoinVertical(lipgloss.Left, title, "", content, "", help) 165 }
··· 157 return m.help.View(m.keys) 158 } 159 160 + title := TableTitleStyle.Render(fmt.Sprintf("Task %d", m.task.ID)) 161 content := m.viewport.View() 162 + help := MutedStyle.Render(m.help.View(m.keys)) 163 164 return lipgloss.JoinVertical(lipgloss.Left, title, "", content, "", help) 165 }