分享一种好看的月历做法
起因是最近在做 Obsidian 里的年度笔记。
想要在笔记里展示各个月份,方便点进每个月的月度笔记。
一开始直接写的链接,像是这样:
上半年:[[2024年1月|1月]] [[2024年2月|2月]] [[2024年3月|3月]] [[2024年4月|4月]] [[2024年5月|5月]] [[2024年6月|6月]]
下半年:[[2024年7月|7月]] [[2024年8月|8月]] [[2024年9月|9月]] [[2024年10月|10月]] [[2024年11月|11月]] [[2024年21月|12月]]
有两个问题:
- 写起来麻烦,要自己一个个写
- 丑
所以稍微折腾了一下,用 Dataview 做了个更好看的月历,效果如图:
这是按钮(其实是链接)实际交互起来的演示:
每个月份笔记本质上都是个链接,所以可以直接显示悬浮预览/浮动编辑窗,或是右键用不同方式打开:
依赖插件 Dataview
这个东西用了 Dataview 插件,并且需要开启 Dataview 插件里的 JS 代码功能(Enable Javascript Queries)
不会有人用 OB 不装 DV 吧
制作方法
其实非常简单,大概是两个步骤:
- 粘贴下面的 Dataview js 代码片段,并根据自己的笔记情况修改几个参数
- 添加 css 样式
Dataview js 代码
```dataviewjs
// 0. 从当前文件获取年份,或者直接填写变量
let year = dv.current().year || 2024
// 1. 这里是你的月份笔记的基础路径
const baseFolder = `PeriodicNote/Monthly/${year}年`
// 当前月份的前缀和后缀
let prefix = ""
let suffix = ""
let content = ""
for (let i=0; i < 12; i++) {
let monthNum = i+1
let monthName = `${monthNum}月`
let cssClasses = "internal-link monthly-btn ready"
if (monthNum == dv.func.dateformat(dv.date('now'), "M")) {
monthName = `${prefix}${monthName}${suffix}`
cssClasses += " current-month"
}
// 2. 这里是你的月份笔记的路径
const monthlyNote = `${baseFolder}/${year}年${monthNum}月/${year}年${monthNum}月`
let isExist = app.vault.getAbstractFileByPath(monthlyNote+".md")
if (!isExist) {
cssClasses += " not-exist"
}
content += `<a class="${cssClasses}" href="${monthlyNote}">${monthName}</a>`
if (i % 3 === 2) {
// content += " <br>"
dv.el("div", `<div class="breadcrumbs-wrapper"> ${content} </div>`);
content = ""
}
}
```
粘贴这一段之后,你应该就能看到基本的视图了。
丑丑的,缩成一团。
但是别担心,之后我们会用 css 来美化它。
首先要解决的问题是:这些链接都还是无效的。
你需要修改几个地方让它们能指向实际的月度笔记路径。
年份
// 0. 从当前文件获取年份,或者直接填写变量
你有两种办法指定年份,其一是在当前笔记添加一个 year
属性,并填写当前的年份。
其二是直接写在代码里,修改 ||
后面的数字即可:
// 0. 从当前文件获取年份,或者直接填写变量
let year = dv.current().year || 2066
两种办法的区别是:前者可以直接复制这个代码片段到任何笔记里,自动读取笔记的年份属性(比如每年的年度笔记都可以用这份代码);而后者则需要自己手动修改代码里的年份变量。
文件夹
// 1. 这里是你的月份笔记的基础路径
在这个位置把 baseFolder
修改成你的月份笔记的基础路径,其中 ${year}
代表你在属性里填写的年份。
比如文件夹如果是 月度笔记/2024年/
就写成:
// 1. 这里是你的月份笔记的基础路径
const baseFolder = `月度笔记/${year}年`
文件名
// 2. 这里是你的月份笔记的路径
这个位置则是修改你实际的月度笔记完整路径,其中 ${year}
和 ${monthNum}
会被替换成实际的年份和月份,然后 ${baseFolder}
就是上面填写的那个基础路径。
比如完整路径如果是 月度笔记/2024年/1月.md
,这里就写成:
// 2. 这里是你的月份笔记的路径
const monthlyNote = `${baseFolder}/${monthNum}月`
这样改完之后,每个笔记应该都能正确工作了。
你可以点击按钮打开某个笔记,或者鼠标停在上面来查看悬浮预览。
题外话:关于用到的函数
写到的时候用到了几个函数,这里也简单介绍一下。
dv.func.dateformat()
可以获得指定格式的日期(但是用 momentJS
或者 datetime
也 OK);配合 dv.date('now')
可以获得当前的时间。
所以结合起来,dv.func.dateformat(dv.date('now', "M")
就可以获得当前的月份,并进行对比。
dvjs 函数介绍:Functions - Dataview
顺便,如果想在 DV 外部调用 dataview 函数(比如做测试),可以用
app.plugins.plugins["dataview"].api.func
获取函数。
对于 Templater 插件也可以类似地用app.plugins.plugins["templater-obsidian"].templater.current_functions_object
获取到 TP 的各种函数。
另外还用到了 OB 原生的函数 app.vault.getAbstractFileByFile()
用来判断文件是否存在,并根据结果来分配 css 变量。
CSS 样式
接下来是美化时间!
粘贴以下 CSS 片段到你的 css snippets 内:
/* 月历按钮美化.css */
/* 整体布局 */
.breadcrumbs-wrapper {
display: flex;
justify-content: space-around;
margin-bottom: 25px;
height: 48px;
}
/* 每月按钮做的样式 */
.ready.monthly-btn {
display: inline-block;
padding: 0.18rem 1.8rem;
/*font-size: 16px;*/
font-weight: 500;
color: var(--text-normal);
border: 3px solid var(--color-accent);
cursor: pointer;
position: relative;
background-color: transparent;
text-decoration: none;
overflow: hidden;
z-index: 1;
font-family: inherit;
/*固定按钮大小并居中文本*/
width: 6em;
text-align: center;
transition: color .3s;
}
/* 当前月份的按钮的特殊样式 */
.ready.monthly-btn.current-month {
color: var(--text-accent-hover) !important;
}
/* 尚未创建按钮的特殊样式 */
.ready.monthly-btn.not-exist {
color: var(--text-muted) !important;
}
/* 浮动的效果 */
.ready.monthly-btn::before {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: var(--color-accent);
transform: translateX(-100%);
z-index: -1;
transition: all .3s;
}
.ready.monthly-btn:hover {
color: var(--background-primary) !important;
}
.ready.monthly-btn:hover::before {
transform: translateX(0);
}
CSS 片段
如果你不知道啥是 css 片段,参考文档:PKMer_Obsidian 的 CSS 代码片段
如果你不喜欢这个样式,也可以去类似 零代码 - 精美CSS样式库 这样的网站找到自己喜欢的样式,然后替换上面的 CSS 片段。
例如找到一个想要的按钮,复制它的 css 片段:
然后将片段里的 button
都替换成 .ready.monthly-btn
就可以了!
特别说明
这段代码的最初灵感——以及排列的样式——都来自木一 Benature 的示例库!
(日记里的前后按钮)
木一大佬的示例库让我学到了炒鸡多,感兴趣的话也可以前去查看:
Benature/obsidian-sample-vault
讨论
若阁下有独到的见解或新颖的想法,诚邀您在文章下方留言,与大家共同探讨。
反馈交流
其他渠道
版权声明
版权声明:所有 PKMer 文章如果需要转载,请附上原文出处链接。