【Dataview View】圆点年历
以圆点形式显示一年中的每一天。如果开启了 核心插件中的“页面预览”,或者第三方插件中的“Hover Editor”,则可以在鼠标指向某一日时显示对应的笔记。
调用方法:
dv.view("Year", { dailyPath: "Daily/{{YYYY-MM-DD}}.md" })
- 第一个引号中是视图文件(下面两个文件)的保存路径
dailyPath
后面的引号内是日记文件的路径,其中双大括号内的内容会按照时间字符串进行解析YYYY
四位年份MM
两位月份DD
两位日期WW
两位周数(第几周)- 这么多大概够用了吧
view.js
/** 获取视图容器,并添加类 */
const dvContainer = function (className) {
const container = dv.container;
container.classList.add(className);
return container;
};
/** 将数字转换为两位数 */
const dbNum = (num) => String(num).padStart(2, '0');
/** 日期增强 */
class DateExtends extends Date {
YYYY;
MM;
DD;
HH;
mm;
ss;
/** 星期几(数字) */
ee;
/** 星期几(中文) */
EE;
/** 第几周(数字) */
ww;
/** 第几周(两位数字字符串) */
WW;
yearProgress;
constructor(date) {
super(date !== undefined ? date : new Date());
this.YYYY = String(this.getFullYear());
this.MM = dbNum(this.getMonth() + 1);
this.DD = dbNum(this.getDate());
this.HH = dbNum(this.getHours());
this.mm = dbNum(this.getMinutes());
this.ss = dbNum(this.getSeconds());
this.ee = this.getDay();
this.EE = ['日', '一', '二', '三', '四', '五', '六'][this.ee];
const yearStart = new Date(this.getFullYear(), 0, 1);
const yearEnd = new Date(this.getFullYear() + 1, 0, 1);
this.yearProgress = (this.getTime() - yearStart.getTime()) / (yearEnd.getTime() - yearStart.getTime());
this.ww = Math.ceil(((new Date(this.getFullYear(), this.getMonth(), this.getDate() + 4 - (this.ee || 7)).getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
this.WW = dbNum(this.ww);
}
/** 格式化日期 */
format(format) {
const reg = /YYYY|MM|DD|HH|mm|ss|ee|EE|WW/g;
return format.replace(reg, (key) => {
return String(this[key]);
});
}
/** 获取当天的开始时间 */
getDayStart() {
return new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0).getTime();
}
/** 是否是闰年 */
isLeapYear() {
return (this.getFullYear() % 4 === 0 && this.getFullYear() % 100 !== 0) || this.getFullYear() % 400 === 0;
}
}
/** 获取当前时间 */
const now = new DateExtends();
/**
* Obsidian 圆点年历
* @author: 稻米鼠
* @description: 以圆点形式显示一年中的每一天
* @created: 2024-10-21 13:54:35
* @updated: 2024-10-21 13:54:35
* @version: 0.0.1
*/
const container = dvContainer('year-container');
const year = now.getFullYear();
container.innerHTML += `<h2>Days in ${year}</h2>`;
for (let i = 1; i <= 366; i++) {
const date = new DateExtends(new Date(year, 0, i));
/** 如果是闰年,跳过 */
if (i === 366 && !date.isLeapYear()) {
break;
}
const path = input.dailyPath.replace(/\{\{(.*?)\}\}/g, (m, s) => date.format(s));
const isPast = date.MM < now.MM || (date.MM === now.MM && date.DD < now.DD);
const isToday = date.MM === now.MM && date.DD === now.DD;
container.innerHTML += `<a class="internal-link year-day-item" data-status="${isPast ? 'past' : isToday ? 'today' : 'future'}" href="${path}" target="_blank" rel="noopener">${i}</a>`;
}
view.css
.year-container {
--gap-width: calc(var(--circle-size) / 3);
--main-color: #303134;
--border-color: rgba(255, 255, 255, 0.1);
--red-color: 154, 59, 59;
--blue-color: 42, 70, 107;
--green-color: 76, 90, 73;
--yellow-color: 134, 108, 72;
--orange-color: 170, 91, 55;
--pink-color: 167, 85, 112;
--paper-color: 255, 255, 255;
--circle-size: 2.4rem;
/* 定义容器名称,用来媒体查询 */
container-type: inline-size;
container-name: year-container;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: var(--gap-width);
background-color: var(--main-color);
padding: 0 var(--gap-width) calc(var(--gap-width) * 2);
}
.year-container > h2 {
width: 100%;
text-align: center;
color: rgb(var(--paper-color));
font-size: 1.6rem;
font-weight: bold;
}
.year-container > .year-day-item {
display: block;
width: var(--circle-size);
height: var(--circle-size);
background-color: var(--main-color);
border: 1px solid var(--border-color);
border-radius: calc(var(--circle-size) / 2);
text-align: center;
font-size: 1rem;
line-height: var(--circle-size);
color: rgba(var(--paper-color), 0.3);
margin-bottom: var(--gap-width);
text-decoration: none;
}
.year-container > .year-day-item:hover {
text-decoration: none;
}
.year-container > .year-day-item[data-status="past"],
.year-container > .year-day-item[data-status="today"] {
border: none;
box-shadow: inset 3px 3px 8px rgba(0, 0, 0, 0.3);
}
.year-container > .year-day-item[data-status="past"] {
color: var(--main-color);
background-color: rgba(var(--paper-color), 0.9);
}
.year-container > .year-day-item[data-status="today"] {
color: rgba(255, 255, 255, 0.8);
background-color: rgb(var(--red-color));
}
/** 在小屏幕下消除容器两侧内部,扩大显示面积
* Note: 容器查询似乎只能对其内部元素起作用
*/
.markdown-reading-view {
/* 定义容器名称,用来媒体查询 */
container-type: inline-size;
container-name: daily-reading-container;
}
@container daily-reading-container (max-width: 48rem) {
.markdown-reading-view .markdown-preview-view {
padding-left: 0;
padding-right: 0;
}
}
.view-content > .markdown-source-view.mod-cm6 > .cm-editor {
/* 定义容器名称,用来媒体查询 */
container-type: inline-size;
container-name: daily-editor-container;
}
@container daily-editor-container (max-width: 48rem) {
.view-content > .markdown-source-view.mod-cm6 > .cm-editor .cm-scroller {
padding-left: 0;
padding-right: 0;
}
}
效果演示
非完整效果