Summarize weekly reports using dataviewjs and perfectly adapt to Calander

I tried using dataviewjs to aggregate my journal by week into the weekly journal generated by the Calander plug-in, and I succeeded, pretty much!

Using this as a weekly diary template, you can click on the calander plugin to automatically summarize your weekly diary to the weekly diary page.

// Weekly 模板 - 展示本周 Dairy 目录下的笔记(基于文件名日期)

// 获取当前文件名(格式应为 2025-W11 这样的周标识)
const weekTitle = dv.current().file.name;

// 解析周标识,获取年份和周数
const match = weekTitle.match(/(\d{4})-W(\d{1,2})/);
if (!match) {
    dv.el("div", "❌ 错误:文件名格式应为 YYYY-WXX(如 2025-W11)", {
        cls: "error-message",
        attr: { style: "color: #e74c3c; padding: 10px; border-left: 3px solid #e74c3c; background-color: #fadbd8;" }
    });
    return;
}

const year = parseInt(match[1]);
const week = parseInt(match[2]);

// 计算本周的开始日期和结束日期
function getDateOfWeek(weekNum, year) {
    const jan4 = new Date(year, 0, 4);
    const jan4Day = jan4.getDay() || 7;
    const firstMonday = new Date(year, 0, 4 - jan4Day + 1);
    const targetMonday = new Date(firstMonday);
    targetMonday.setDate(firstMonday.getDate() + (weekNum - 1) * 7);
    
    const targetSunday = new Date(targetMonday);
    targetSunday.setDate(targetMonday.getDate() + 6);
    
    return {
        start: targetMonday,
        end: targetSunday
    };
}

const weekDates = getDateOfWeek(week, year);
const weekStart = weekDates.start;
const weekEnd = weekDates.end;

// 格式化日期为 YYYY-MM-DD
function formatDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
}

// 生成本周的日期范围(YYYY-MM-DD 格式)
const dateRange = [];
const currentDate = new Date(weekStart);
while (currentDate <= weekEnd) {
    dateRange.push(formatDate(currentDate));
    currentDate.setDate(currentDate.getDate() + 1);
}

// 输出周信息 - 使用自定义样式的标题
dv.el("h1", `🗓️ 第 ${week} 周总结`, {
    attr: { 
        style: "color: #3498db; border-bottom: 2px solid #3498db; padding-bottom: 8px; margin-bottom: 20px;" 
    }
});

dv.el("div", `📅 ${formatDate(weekStart)} 至 ${formatDate(weekEnd)}`, {
    attr: { 
        style: "font-size: 1.2em; color: #7f8c8d; margin-bottom: 20px;" 
    }
});

// 获取 Dairy 目录下本周的所有文件(基于文件名匹配)
const dairyNotes = dv.pages('"Dairy"')
    .filter(page => {
        const filenameMatch = page.file.name.match(/^(\d{4}-\d{2}-\d{2})/);
        if (!filenameMatch) return false;
        
        const dateStr = filenameMatch[1];
        return dateRange.includes(dateStr);
    })
    .sort(page => page.file.name);

// 检查是否有笔记
if (dairyNotes.length === 0) {
    dv.el("div", "📝 本周没有日记记录", {
        cls: "empty-notes",
        attr: { 
            style: "text-align: center; padding: 20px; color: #95a5a6; font-style: italic; border: 1px dashed #bdc3c7; border-radius: 5px;" 
        }
    });
} else {
    // 显示统计信息
    dv.el("div", `📊 本周共有 ${dairyNotes.length} 条日记记录`, {
        cls: "stats",
        attr: { 
            style: "background-color: #e8f4f8; padding: 10px 15px; border-radius: 5px; margin-bottom: 20px; font-weight: bold; color: #2980b9;" 
        }
    });
    
    // 按日期处理每个笔记
    for (const note of dairyNotes) {
        // 从文件名提取日期
        const dateStr = note.file.name.match(/^(\d{4}-\d{2}-\d{2})/)[1];
        const date = new Date(dateStr);
        const dayNames = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
        const dayName = dayNames[date.getDay()];
        
        // 显示日期作为二级标题
        const headerContainer = dv.el("div", "", {
            cls: "date-header",
            attr: { 
                style: "margin-top: 30px; margin-bottom: 10px; background-color: #f5f5f5; border-radius: 5px; padding: 8px 15px; display: flex; align-items: center;" 
            }
        });
        
        // 添加日期图标
        dv.el("span", "📆", { 
            attr: { style: "margin-right: 10px; font-size: 1.2em;" },
            container: headerContainer 
        });
        
        // 添加日期链接
        const linkSpan = dv.el("span", "", { container: headerContainer });
        dv.el("a", dateStr, { 
            attr: { 
                href: note.file.path,
                style: "font-size: 1.2em; font-weight: bold; color: #16a085; text-decoration: none;"
            },
            container: linkSpan 
        });
        
        // 添加星期几
        dv.el("span", ` ${dayName}`, { 
            attr: { style: "margin-left: 10px; color: #7f8c8d;" },
            container: headerContainer 
        });
        
        // 加载笔记内容
        const content = await dv.io.load(note.file.path);
        
        // 移除 YAML 前置元数据(如果有)
        let cleanContent = content;
        if (content.startsWith('---')) {
            const endOfYaml = content.indexOf('---', 3);
            if (endOfYaml > 0) {
                cleanContent = content.substring(endOfYaml + 3).trim();
            }
        }
        
        // 显示笔记内容,带样式的卡片
        dv.el("div", cleanContent, {
            cls: "note-content",
            attr: { 
                style: "padding: 15px; background-color: #ffffff; border-left: 3px solid #2ecc71; border-radius: 0 5px 5px 0; margin-bottom: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);" 
            }
        });
        
        // 添加分隔线
        dv.el("div", "", {
            cls: "separator",
            attr: { style: "height: 1px; background: linear-gradient(to right, transparent, #e0e0e0, transparent); margin: 25px 0;" }
        });
    }
}

1 Like

Pretty funny how in my country Chinese characters in movies are made to pronounce ‘r’ with ‘l’ (no offence), but you guys, seem to to do the exact opposite (‘l’ → ‘r’). Interesting…

This would also make more it more interesting for international users in English.
Can you confirm this is what is intended:

// Weekly Template - Display notes from the "Daily" folder for the current week (based on filenames)

// Get the current file name (should follow the format "2025-W11" for weekly identification)
const weekTitle = dv.current().file.name;

// Parse the weekly identifier to extract the year and week number
const match = weekTitle.match(/(\d{4})-W(\d{1,2})/);
if (!match) {
    dv.el("div", "❌ Error: Filename format should be YYYY-WXX (e.g., 2025-W11)", {
        cls: "error-message",
        attr: { style: "color: #e74c3c; padding: 10px; border-left: 3px solid #e74c3c; background-color: #fadbd8;" }
    });
    return;
}

const year = parseInt(match[1]);
const week = parseInt(match[2]);

// Calculate the start and end dates of the given week
function getDateOfWeek(weekNum, year) {
    const jan4 = new Date(year, 0, 4);
    const jan4Day = jan4.getDay() || 7;
    const firstMonday = new Date(year, 0, 4 - jan4Day + 1);
    const targetMonday = new Date(firstMonday);
    targetMonday.setDate(firstMonday.getDate() + (weekNum - 1) * 7);

    const targetSunday = new Date(targetMonday);
    targetSunday.setDate(targetMonday.getDate() + 6);

    return {
        start: targetMonday,
        end: targetSunday
    };
}

const weekDates = getDateOfWeek(week, year);
const weekStart = weekDates.start;
const weekEnd = weekDates.end;

// Format date as YYYY-MM-DD
function formatDate(date) {
    return date.toISOString().split('T')[0];
}

// Generate the list of dates for the week
const dateRange = [];
const currentDate = new Date(weekStart);
while (currentDate <= weekEnd) {
    dateRange.push(formatDate(currentDate));
    currentDate.setDate(currentDate.getDate() + 1);
}

// Display weekly summary title
dv.el("h1", `🗓️ Week ${week} Summary`, {
    attr: { style: "color: #3498db; border-bottom: 2px solid #3498db; padding-bottom: 8px; margin-bottom: 20px;" }
});

dv.el("div", `📅 ${formatDate(weekStart)} to ${formatDate(weekEnd)}`, {
    attr: { style: "font-size: 1.2em; color: #7f8c8d; margin-bottom: 20px;" }
});

// Retrieve notes from the "Daily" folder that match this week's date range
const dailyNotes = dv.pages('"Daily"')
    .filter(page => {
        const filenameMatch = page.file.name.match(/^(\d{4}-\d{2}-\d{2})/);
        if (!filenameMatch) return false;

        const dateStr = filenameMatch[1];
        return dateRange.includes(dateStr);
    })
    .sort(page => page.file.name);

// Display notes or message if no notes are found
if (dailyNotes.length === 0) {
    dv.el("div", "📝 No daily entries for this week", {
        cls: "empty-notes",
        attr: { style: "text-align: center; padding: 20px; color: #95a5a6; font-style: italic; border: 1px dashed #bdc3c7; border-radius: 5px;" }
    });
} else {
    dv.el("div", `📊 Total ${dailyNotes.length} daily entries this week`, {
        cls: "stats",
        attr: { style: "background-color: #e8f4f8; padding: 10px 15px; border-radius: 5px; margin-bottom: 20px; font-weight: bold; color: #2980b9;" }
    });

    // Display each note
    for (const note of dailyNotes) {
        const dateStr = note.file.name.match(/^(\d{4}-\d{2}-\d{2})/)[1];
        const date = new Date(dateStr);
        const dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
        const dayName = dayNames[date.getDay()];

        const headerContainer = dv.el("div", "", {
            cls: "date-header",
            attr: { style: "margin-top: 30px; margin-bottom: 10px; background-color: #f5f5f5; border-radius: 5px; padding: 8px 15px; display: flex; align-items: center;" }
        });

        dv.el("span", "📆", { attr: { style: "margin-right: 10px; font-size: 1.2em;" }, container: headerContainer });
        const linkSpan = dv.el("span", "", { container: headerContainer });
        dv.el("a", dateStr, {
            attr: { href: note.file.path, style: "font-size: 1.2em; font-weight: bold; color: #16a085; text-decoration: none;" },
            container: linkSpan
        });

        dv.el("span", ` ${dayName}`, { attr: { style: "margin-left: 10px; color: #7f8c8d;" }, container: headerContainer });

        const content = await dv.io.load(note.file.path);
        let cleanContent = content.startsWith('---') ? content.split('---').slice(2).join('---').trim() : content;

        dv.el("div", cleanContent, {
            cls: "note-content",
            attr: { style: "padding: 15px; background-color: #ffffff; border-left: 3px solid #2ecc71; border-radius: 0 5px 5px 0; margin-bottom: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);" }
        });

        dv.el("div", "", {
            cls: "separator",
            attr: { style: "height: 1px; background: linear-gradient(to right, transparent, #e0e0e0, transparent); margin: 25px 0;" }
        });
    }
}

:smile: I thought about this pronunciation, may it be a dialect from Guangdong? To be honest, I don’t quite understand what the pronunciation changes you mentioned are. Can you give me a movie clip to refer to? I really want to know what Chinese pronunciation you guys hear, because I have only received one pronunciation (Mandarin pronunciation) education since I was young.

I have confirmed that the only difference is that I am using the Dairy folder, while you are using the Daily folder. After changing the folder name, everything can be displayed normally. This is a small matter, everyone using the code just needs to change it to their own folder name.

Thank you for your help with the English version!

off-topic

I can’t now. It is not English anyway. Basically dubbing in movies is used to portray a person’s inability to speak the language correctly. So a French character in a British movie can be added an accent typical of French speakers (e.g. thiszis in English but the dubbing will not use these words, correct) to convey a sense of foreign-ness.
The linguistic feature in question is the non-rhotic ‘r’. Compare the Scottish and English differences in pronounciation.
R-L changes are seen in multiple languages. In fact, Japanese when taking a foreign word with ‘L’ into its vocabulary, will convert ‘L’ to ‘R’ (model > moderu, etc.).

Well, I had to make a guess, since we are dealing with calendars and not products made of milk. :slight_smile:

I’m laughing so hard; I can’t believe I’m writing my diary in a ‘dairy’. Who knows why I mistook ‘dairy’ for ‘daily’? Thank you, hahaha! My English teacher: Don’t say you are my student when you go out

1 Like