all repos — todo.txt-go @ main

style.go (view raw)

  1package main
  2
  3import (
  4	"fmt"
  5	"regexp"
  6
  7	todo "github.com/1set/todotxt"
  8	"github.com/charmbracelet/lipgloss"
  9
 10	catppuccin "github.com/catppuccin/go"
 11)
 12
 13var DATETIME_FORMAT = "02-01-2006 15:03"
 14var DATE_FORMAT = "02-01-2006"
 15
 16var Catppuccin catppuccin.Flavor = catppuccin.Mocha
 17
 18type Style struct {
 19	Task     TaskStyle
 20	Priority PriorityStyle
 21	Date     DateStyle
 22	Check    lipgloss.Style
 23	Context  lipgloss.Style
 24	Project  lipgloss.Style
 25	KeyValue lipgloss.Style
 26}
 27
 28type TaskStyle struct {
 29	Todo      lipgloss.Style
 30	Completed lipgloss.Style
 31}
 32
 33type PriorityStyle struct {
 34	A lipgloss.Style
 35	B lipgloss.Style
 36	C lipgloss.Style
 37}
 38
 39type DateStyle struct {
 40	done    lipgloss.Style
 41	today   lipgloss.Style
 42	overdue lipgloss.Style
 43	futur   lipgloss.Style
 44}
 45
 46func NewTextStyle() Style {
 47
 48	taskStyle := TaskStyle{
 49		Todo:      lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Text().Hex)),
 50		Completed: lipgloss.NewStyle().Strikethrough(true).Foreground(lipgloss.Color(Catppuccin.Overlay2().Hex)),
 51	}
 52
 53	priorityStyle := PriorityStyle{
 54		A: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Red().Hex)),
 55		B: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Peach().Hex)),
 56		C: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Green().Hex)),
 57	}
 58
 59	dateBaseStyle := lipgloss.NewStyle()
 60	dateStyle := DateStyle{
 61		done:    dateBaseStyle.Foreground(lipgloss.Color(Catppuccin.Overlay0().Hex)),
 62		today:   dateBaseStyle.Foreground(lipgloss.Color(Catppuccin.Crust().Hex)).Background(lipgloss.Color(Catppuccin.Blue().Hex)),
 63		overdue: dateBaseStyle.Foreground(lipgloss.Color(Catppuccin.Crust().Hex)).Background(lipgloss.Color(Catppuccin.Red().Hex)),
 64		futur:   dateBaseStyle.Foreground(lipgloss.Color(Catppuccin.Blue().Hex)),
 65	}
 66
 67	style := Style{
 68		Priority: priorityStyle,
 69		Task:     taskStyle,
 70		Date:     dateStyle,
 71		Check:    lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Blue().Hex)),
 72		Context:  lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Blue().Hex)),
 73		Project:  lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Mauve().Hex)),
 74		KeyValue: lipgloss.NewStyle().Foreground(lipgloss.Color(Catppuccin.Flamingo().Hex)),
 75	}
 76	return style
 77}
 78
 79func (s Style) getTaskStyle(task todo.Task, checked bool) string {
 80
 81	todoText := task.Original
 82
 83	checkedRegex := regexp.MustCompile(`^x (\d{4}-\d{2}-\d{2} )? ?`)
 84	priorityRegex := regexp.MustCompile(`^\([A-Z]\) `)
 85	contextRegex := regexp.MustCompile(`@\w+`)
 86	projectRegex := regexp.MustCompile(`\+\w+`)
 87	dueDateRegex := regexp.MustCompile(`due:\d{4}-\d{2}-\d{2}`)
 88	keyValueRegex := regexp.MustCompile(`\w+:.+`)
 89
 90	todoText = checkedRegex.ReplaceAllString(todoText, "")
 91	todoText = priorityRegex.ReplaceAllString(todoText, "")
 92	todoText = dueDateRegex.ReplaceAllString(todoText, "")
 93
 94	checkString := " "
 95	if checked {
 96		checkString = "✓"
 97	}
 98
 99	switch task.Completed {
100	case true:
101		dateString := s.Date.done.Render(task.CompletedDate.Local().Format(DATETIME_FORMAT))
102		return fmt.Sprintf("%s %s %s %s", s.Check.Render(checkString), s.getPriorityStyle(task.Priority), s.Task.Completed.Render(todoText), dateString)
103	default:
104		todoText = contextRegex.ReplaceAllStringFunc(todoText, func(match string) string {
105			return s.Context.Render(match)
106		})
107		todoText = projectRegex.ReplaceAllStringFunc(todoText, func(match string) string {
108			return s.Project.Render(match)
109		})
110		todoText = keyValueRegex.ReplaceAllStringFunc(todoText, func(match string) string {
111			return s.KeyValue.Render(match)
112		})
113		var dueDateString string
114		if task.HasDueDate() {
115			formatedDueDate := task.DueDate.Format(DATE_FORMAT)
116			switch {
117			case task.IsDueToday():
118				dueDateString = s.Date.today.Render(formatedDueDate)
119			case task.IsOverdue():
120				dueDateString = s.Date.overdue.Render(formatedDueDate)
121			default:
122				dueDateString = s.Date.futur.Render(formatedDueDate)
123			}
124		}
125		return fmt.Sprintf("%s %s %s %s", s.Check.Render(checkString), s.getPriorityStyle(task.Priority), s.Task.Todo.Render(todoText), dueDateString)
126	}
127}
128
129func (s Style) getPriorityStyle(priority string) string {
130	switch priority {
131	case "":
132		return " "
133	case "A":
134		return s.Priority.A.Render(priority)
135	case "B":
136		return s.Priority.B.Render(priority)
137	case "C":
138		return s.Priority.C.Render(priority)
139	default:
140		return priority
141	}
142}