// 自定义参数
const Path = '📖 书山学海/📝 读书笔记'; // 读书笔记文件夹路径
const showYear = null; // 仅需显示相应年度的读书笔记,如需显示全部,则将showYear改为null
const selected = 1; // 切换主题颜色:0-常规 1-莫兰迪
const showDesc = true; // 是否需要逆序显示
// 遍历Path文件夹下所有读书笔记
const weReadFiles = dv
.pages()
.file.where(b => b.path.includes(Path) && b.path.endsWith(b.name + '.md'));
// 按年、月划分阅读记录
const readYearsMonths = new Map();
// 色彩管理 - 集中定义所有颜色
const colorManager = {
// 基础颜色
yellow: 'var(--color-yellow-rgb)',
green: 'var(--color-green-rgb)',
red: 'var(--color-red-rgb)',
blue: 'var(--color-blue-rgb)',
cyan: 'var(--color-cyan-rgb)',
purple: 'var(--color-purple-rgb)',
orange: 'var(--color-orange-rgb)',
pink: 'var(--color-pink-rgb)',
teal: 'var(--color-teal-rgb)',
yellowgreen: 'var(--color-yellowgreen-rgb)',
turquoise: 'var(--color-turquoise-rgb)',
// 莫兰迪色系
pomelo: '255,111,94', // 红西柚
pulp: '235, 89, 94', // 红橙
daffodil: '224,159,71', // 黄水仙
jade: '70,164,115', // 翡翠
seasky: '125,201,231', // 海洋天蓝
plum: '141,191,139', // 青梅
swanlake: '60, 167, 171', // 天鹅湖蓝
pelorous: '59,176,186', // 冷青
honor: '229,140,197', // 荣耀
love: '241,138,161', // 火烈鸟
autumn: '233, 191, 102', // 秋天
};
// 主题颜色配置
const themes = [
// 常规配色
[colorManager.yellow, colorManager.green, colorManager.blue],
// 莫兰迪配色
[colorManager.pomelo, colorManager.daffodil, colorManager.swanlake],
];
// 阅读进度颜色
const progressColors = [
// 常规配色
[
colorManager.turquoise,
colorManager.orange,
colorManager.teal,
colorManager.red,
colorManager.pink, // 已读完状态颜色
],
// 莫兰迪配色
[
colorManager.seasky,
colorManager.plum,
colorManager.autumn,
colorManager.love,
colorManager.pulp, // 已读完状态颜色
],
];
// 选择当前主题颜色
const themeColor = themes[selected];
const currentProgressColors = progressColors[selected];
// 预先编译正则表达式 - 用于解析日期
const dateRegex = /(\d{4})-(\d{1,2})-(\d{1,2})/;
// 彩虹猫进度条样式模板
const progressBarTemplate =
"
";
/**
* 创建标签徽章
* @param {string} icon - 图标类名
* @param {string} color - 颜色RGB值
* @param {string} title - 标签文本
* @returns {string} 徽章HTML
*/
function createBadge(icon, color, title) {
return `
${title}
`;
}
/**
* 生成书籍信息HTML
* @param {string} name - 书籍链接名
* @param {Object} bookInfo - 书籍元数据
* @param {string} progressBar - 进度条HTML
* @param {number} readPercent - 阅读百分比
* @param {Array} themeColor - 主题颜色
* @param {string} progressColor - 进度颜色
* @returns {string} 书籍信息HTML
*/
function generateBookInfo(name, bookInfo, progressBar, readPercent, themeColor, progressColor) {
// 处理作者信息,如果过长则截断
const authorText = bookInfo.author != null
? bookInfo.author.length > 8
? bookInfo.author.substring(0, 8) + '...'
: bookInfo.author
: '-';
// 创建各类信息徽章
const author = createBadge('book-user-icon', themeColor[0], '作者:' + authorText);
const readDate = createBadge('read-date-icon', themeColor[1], '阅读日期:' + bookInfo.lastReadDate);
const readTime = createBadge('read-time-icon', themeColor[2], '阅读时长:' + bookInfo.readingTime);
// 阅读进度徽章选项
const progressOptions = [
['book-icon', progressColor, '阅读进度:' + readPercent + '%'],
['book-checked-icon', currentProgressColors[4], '已读完']
];
// 根据是否读完选择不同的进度徽章
const progressBadge = createBadge(...(readPercent !== 100 ? progressOptions[0] : progressOptions[1]));
// 拼接所有信息
return name + author + readDate + readTime + progressBadge + progressBar;
}
// 收集并处理所有读书笔记文件
const weReadInfoArray = weReadFiles.values
// 按最后阅读日期降序排序
.sort((a, b) => new Date(b.frontmatter.lastReadDate) - new Date(a.frontmatter.lastReadDate))
.map(file => {
const bookInfo = file.frontmatter;
const lastReadDateMatch = dateRegex.exec(bookInfo.lastReadDate);
// 如果日期格式不匹配,跳过此条目
if (!lastReadDateMatch) return null;
const [, yearStr, monthStr] = lastReadDateMatch;
const year = Number(yearStr);
const month = Number(monthStr);
// 计算阅读进度百分比
const readPercent = bookInfo.readingStatus === '读完'
? 100
: bookInfo.progress === -1
? 0
: parseFloat(bookInfo.progress);
// 生成进度条HTML
const progressBar = progressBarTemplate.replace(
'{progress}',
readPercent == 100 ? '100' : readPercent
);
// 根据进度选择颜色
const progressColor = currentProgressColors[
Math.min(Math.floor(readPercent / 25), currentProgressColors.length - 1)
];
// 如果需要显示指定年份或显示全部,则记录年月信息
if (showYear == null || year == showYear) {
const existingMonths = readYearsMonths.get(year) || new Set();
existingMonths.add(month);
readYearsMonths.set(year, existingMonths);
}
// 返回处理后的书籍信息
return {
year,
month,
lastReadDate: bookInfo.lastReadDate,
cover: ``,
info: generateBookInfo(
file.link,
bookInfo,
progressBar,
readPercent,
themeColor,
progressColor
)
};
})
.filter(Boolean); // 过滤掉无效条目
// 按年份排序(正序或逆序)
const sortedYears = Array.from(readYearsMonths.keys())
.sort(showDesc ? (a, b) => b - a : (a, b) => a - b);
// 生成最终的展示内容
for (const year of sortedYears) {
// 显示年份标题
dv.paragraph(`## ${year}年`);
// 获取并排序该年的月份
const monthsInYear = Array.from(readYearsMonths.get(year))
.sort(showDesc ? (a, b) => b - a : (a, b) => a - b);
// 遍历每个月份
for (const month of monthsInYear) {
// 显示月份标题
dv.paragraph(`### ${month}月`);
// 筛选该年月的书籍
const booksInMonth = weReadInfoArray.filter(book =>
book.year === year && book.month === month
);
// 如果有书籍,生成表格显示
if (booksInMonth.length > 0) {
dv.table(
['封面', '信息'],
booksInMonth.map(book => [book.cover, book.info])
);
}
}
}