obsidian-habit-mood-tracker
obsidian-habit-mood-tracker copied to clipboard
Code snippet for automatically handling multiple habits
Hi,
Thanks for this repo! It's a nice example which encouraged me to set up my own implementation.
In my setup, I have my daily notes stored in the "daily" folder in Obsidian, and the habit tracking part looks like this:
### Tracker
- [ ] habit 1
- [ ] habit 2
etc.
One thing that I wanted to modify compared to your example was to automatically pick up any new items added to the tracker without a code change. Here's how I did it:
const calendarDataTemplate = {
year: moment().year(),
colors: {
"x": ["#228B22", "#228B22", "#228B22", "#228B22", "#228B22"],
"-": ["#FF0000", "#FF0000", "#FF0000", "#FF0000", "#FF0000"],
">": ["#696969", "#696969", "#696969", "#696969", "#696969"]
},
intensityScaleStart: 1,
intensityScaleEnd: 5,
showCurrentDayBorder: true
}
// This above is mostly the same as in your example, but the enties part is omitted.
// I've added showCurrentDayBorder, as I think that's quite useful here.
// I'm going to use this calendarDataTemplate as a template below
// I broke things apart a bit, just to make things a bit more readable.
// So I'm loading my daily notes from the "daily" folder...
const pages = dv.pages('"daily"').file
// ...and filter it down for tasks in the tracker section, but not checking
// whether the tasks are completed - at this stage, I need even the non-complete ones
const trackerTasks = pages.tasks.where(p => String(p.section).includes("Tracker"))
// I'm going to store the calendar entries per habit in this:
const calendarEntriesPerHabit = {}
for (const task of trackerTasks.values) {
// If the habit in the current task is not yet in the entries,
// I'm adding it with an empty array
if (!(task.text in calendarEntriesPerHabit)) {
calendarEntriesPerHabit[task.text] = []
}
// If the task is not incomplete, I'm adding it to the earlier entries
if (task.status !== ' ') {
calendarEntriesPerHabit[task.text].push({
date: task.path.split("/").pop().replace(".md", ""),
color: task.status,
intensity: 5
})
}
}
// At this stage I should have a complete dict with all the occurrences per habit, ...
for (const habit in calendarEntriesPerHabit) {
// ...so all that's left is to put a header with a habit name...
dv.el('h3', habit)
// ...and to render the heatmap for the given habit, constructing
// the calendar data from the template + the entries
renderHeatmapCalendar(this.container, {
...calendarDataTemplate,
entries: calendarEntriesPerHabit[habit]
})
}
This nicely renders the habit heatmaps one by one without having to duplicate code.