分享一种好看的月历做法

分享一种好看的月历做法

起因是最近在做 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月]]

有两个问题:

  1. 写起来麻烦,要自己一个个写

所以稍微折腾了一下,用 Dataview 做了个更好看的月历,效果如图:

分享一种好看的月历做法--

这是按钮(其实是链接)实际交互起来的演示:

分享一种好看的月历做法--

每个月份笔记本质上都是个链接,所以可以直接显示悬浮预览/浮动编辑窗,或是右键用不同方式打开:

分享一种好看的月历做法--

依赖插件 Dataview

这个东西用了 Dataview 插件,并且需要开启 Dataview 插件里的 JS 代码功能(Enable Javascript Queries)
不会有人用 OB 不装 DV 吧

制作方法

其实非常简单,大概是两个步骤:

  1. 粘贴下面的 Dataview js 代码片段,并根据自己的笔记情况修改几个参数
  2. 添加 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 = ""
  }
}

```

粘贴这一段之后,你应该就能看到基本的视图了。

分享一种好看的月历做法--Dataview js 代码

丑丑的,缩成一团。

但是别担心,之后我们会用 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 片段:

分享一种好看的月历做法--CSS 样式

然后将片段里的 button 都替换成 .ready.monthly-btn 就可以了!

特别说明

这段代码的最初灵感——以及排列的样式——都来自木一 Benature 的示例库!

分享一种好看的月历做法--特别说明

(日记里的前后按钮)

木一大佬的示例库让我学到了炒鸡多,感兴趣的话也可以前去查看:

Benature/obsidian-sample-vault

讨论

若阁下有独到的见解或新颖的想法,诚邀您在文章下方留言,与大家共同探讨。



反馈交流

其他渠道

版权声明