1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
package models
import "time"
type AtomSource string
const (
SourceTrello AtomSource = "trello"
SourceTodoist AtomSource = "todoist"
SourceObsidian AtomSource = "obsidian"
SourceMeal AtomSource = "plantoeat"
)
type AtomType string
const (
TypeTask AtomType = "task"
TypeNote AtomType = "note"
TypeMeal AtomType = "meal"
)
// Atom represents a unified unit of work or information
type Atom struct {
ID string
Title string
Description string
Source AtomSource
Type AtomType
// Metadata
URL string
DueDate *time.Time
CreatedAt time.Time
Priority int // Normalized: 1 (Low) to 4 (Urgent)
// UI Helpers (to be populated by mappers)
SourceIcon string // e.g., "trello-icon.svg" or emoji
ColorClass string // e.g., "border-blue-500"
// Original Data (for write operations)
Raw interface{}
}
// TaskToAtom converts a Todoist Task to an Atom
func TaskToAtom(t Task) Atom {
// Todoist priority: 1 (normal) to 4 (urgent)
// Keep as-is since it already matches our 1-4 scale
priority := t.Priority
if priority < 1 {
priority = 1
}
if priority > 4 {
priority = 4
}
return Atom{
ID: t.ID,
Title: t.Content,
Description: t.Description,
Source: SourceTodoist,
Type: TypeTask,
URL: t.URL,
DueDate: t.DueDate,
CreatedAt: t.CreatedAt,
Priority: priority,
SourceIcon: "✓", // Checkmark emoji for tasks
ColorClass: "border-red-500",
Raw: t,
}
}
// CardToAtom converts a Trello Card to an Atom
func CardToAtom(c Card) Atom {
// Trello doesn't have explicit priority, default to medium (2)
// Can be enhanced later with label-based priority detection
priority := 2
return Atom{
ID: c.ID,
Title: c.Name,
Description: c.ListName, // Use list name as description
Source: SourceTrello,
Type: TypeTask,
URL: c.URL,
DueDate: c.DueDate,
CreatedAt: time.Time{}, // Trello ID contains timestamp, can be parsed later
Priority: priority,
SourceIcon: "📋", // Clipboard emoji for boards
ColorClass: "border-blue-500",
Raw: c,
}
}
// NoteToAtom converts an Obsidian Note to an Atom
func NoteToAtom(n Note) Atom {
// Notes don't have priority, default to low (1)
priority := 1
return Atom{
ID: n.Path, // Use path as unique ID
Title: n.Title,
Description: n.Content,
Source: SourceObsidian,
Type: TypeNote,
URL: "", // Obsidian notes don't have URLs
DueDate: nil, // Notes typically don't have due dates
CreatedAt: n.Modified, // Use modified time as created time
Priority: priority,
SourceIcon: "📝", // Memo emoji for notes
ColorClass: "border-purple-500",
Raw: n,
}
}
// MealToAtom converts a PlanToEat Meal to an Atom
func MealToAtom(m Meal) Atom {
// Meals don't have priority, default to low (1)
priority := 1
return Atom{
ID: m.ID,
Title: m.RecipeName,
Description: m.MealType, // breakfast, lunch, dinner
Source: SourceMeal,
Type: TypeMeal,
URL: m.RecipeURL,
DueDate: &m.Date, // Meal date is effectively the "due date"
CreatedAt: time.Time{},
Priority: priority,
SourceIcon: "🍽️", // Fork and knife emoji for meals
ColorClass: "border-green-500",
Raw: m,
}
}
|