Introduction

View todos in a calendar, either vertically or horizontally

Inspired by dot plot.

const todoArr = FileAttachment('./data/todotxt.json').json();
todoArr[0]
new TodoTxtItem(todoArr[0][1])
const todos = todoArr.map(([date, text]) => {
    const t = new TodoTxtItem(text);
    t.edited = date;
    return t;
})
function isInvalidDate(date) {
    return isNaN(date.getTime());
}

function extractDateField(sp, tag) {
    const dateStr = sp.find(s => s.startsWith(`${tag}:`));
    let date = dateStr ? new Date(dateStr.substring(tag.length + 1)) : null;
    if (date !== null && isInvalidDate(date)) {
        date = null;
    }
    return date;
}

const data = todos
    .sort((a, b) => a.date - b.date)
    .map(t => {
        const sp = t.text.split(' ');
        const {text, date, priority, edited} = t;
        
        const due = extractDateField(sp, 'due');
        const threshold = extractDateField(sp, 't');

        // const lastdate = Math.max(...[due, date, threshold, new Date(edited)]);
        const lastdate = Math.max(...[due, date, threshold]);

        let combined = '';
        combined += `${t.priority ? `(${t.priority}) ` : ''}`;
        combined += `${(t.contexts || []).map(c => `@${c} `).join('')}`;
        combined += `${(t.projects|| []).map(p => `+${p} `).join('')}`;
        combined += `${text}`;
    
        return {
            ...t,
            due, threshold, lastdate,
            original: text,
            text: combined,
        };
    })
    .filter(t => t.date > startDate)
    .filter(t => showCompleted ? true : !t.complete)
    // .filter(t => showThreshold ? true : t.treshold > new Date())
    .map((t, index) => {
        return {...t, index}
    })
    // .slice(0, 5)