Skip to content

Commit

Permalink
Merge branch 'pr/808'
Browse files Browse the repository at this point in the history
  • Loading branch information
cumany committed Jul 1, 2024
2 parents b78a6d0 + 5e5ee71 commit 568f03b
Show file tree
Hide file tree
Showing 5 changed files with 739 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
uid: 20240629182937
title: 快速复制标题链接和内联代码
tags: [Obsidian]
description:
author: Moy
type: tutorial
draft: false
editable: false
modified: 20240630162130
aliases: []
create_date: 2024-06-29T18:29
modified_date: 2024-06-30T15:57
publish: true
---

# 快速复制标题链接和内联代码

在使用 OB 的时候,有时候会想复制指向某个标题的引用链接。

想要的结果是:`[[笔记名称#标题|标题]]`

这样的链接可以**直接跳转到这个标题所在的位置**,并且**只显示标题文本**,避免链接过长。

是否显示笔记名称的长度区别:

![](https://cdn.pkmer.cn/images/202407012053309.png!pkmer)

我一直的做法是先双击 `[[` 后选择一个笔记,选完之后再输入 `#` 选择页面里的一个标题,最后修改显示文本。

这样太麻烦了(尤其是有时候想要复制的页面就直接开着!),所以我写了一个 TP 脚本来**快速复制指向标题的链接**

> [!info] Copy Block Link 插件
> 这个插件也可以实现相同的功能,甚至支持复制指向块的链接。
> 但因为缺少自定义功能,默认的链接文本太长(如上图的第二行),所以还是选择自己写脚本了。
## TP 脚本

```markdown
<%*
// 2024.06.05 增加了对行内代码 inline code 的兼容

function getInlineCode(str, cursor){
let start = str.lastIndexOf('`', cursor - 1);
let end = str.indexOf('`', cursor);

if (start === -1 || end === -1) {
return null;
}

return str.substring(start + 1, end);
}

async function linkHeading() {
const curView = app.workspace.activeLeaf.view;
const curFile = curView.file;
const curEditor = curView.editor;
const curLine = curEditor.getLine(curEditor.getCursor().line);

if (!curLine.startsWith('#') || !curLine.includes('# ')) {
if (!curLine.includes("`")) {
new Notice("当前光标处没有标题");
return;
} else {
const curCh = curEditor.getCursor().ch;
let inlineCode = getInlineCode(curLine, curCh)
if (inlineCode) {
navigator.clipboard.writeText(inlineCode)
new Notice("Inline Code Copied!");
return;
}
}
}

let selectedHeading = curLine.replace(/#+ /, "#")
const filename = curFile.name;
let linkAlias = selectedHeading.replace(/# ?/, "")

let headingReferenceLink = `[[${filename}${selectedHeading}|${linkAlias}]]`

navigator.clipboard.writeText(headingReferenceLink)
new Notice("Heading Copied!");
}

await linkHeading();
%>
```

## 使用方法

在光标位于标题的时候,执行这个 TP 脚本即可复制链接。

为了更省事儿,我用 **Commander** 插件将这个命令加进了右键菜单:

![](https://cdn.pkmer.cn/images/202407012053310.png!pkmer)

这样可以直接右键点击标题并复制:

![](https://cdn.pkmer.cn/images/202407012053311.gif!pkmer)

## 拓展用法:复制内联代码 ✨

在 OB 内我们有时候会写像是 `print("Hello world")` 这样的内联代码。

但想要复制的时候,还得小心翼翼选中两个 \` 符号中间的文本内容,很麻烦。

所以,干脆给这个脚本额外加了一个功能——

如果对内联代码执行,就会**只复制代码本身内容**

这样在需要复制 Inline code 的时候就很方便。
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
---
uid: 20240629212603
title: 分享一种好看的月历做法
tags: [Obsidian]
description: 如何在 Obsidian 里做一个好看又实用的月份显示(适用于年度笔记)。
author: Moy
type: practice
draft: false
editable: false
modified: 20240701210544

---

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

起因是最近在做 Obsidian 里的**年度笔记**

想要在笔记里展示各个月份,方便点进每个月的**月度笔记**

一开始直接写的链接,像是这样:

```markdown
上半年:[[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. 写起来麻烦,要自己一个个写
2.

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

![](https://cdn.pkmer.cn/images/202407012053614.png!pkmer)

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

![](https://cdn.pkmer.cn/images/202407012053615.gif!pkmer)

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

![](https://cdn.pkmer.cn/images/202407012053616.png!pkmer)

> [!info] 依赖插件 Dataview
> 这个东西用了 Dataview 插件,并且需要开启 Dataview 插件里的 JS 代码功能(Enable Javascript Queries)
> ~~不会有人用 OB 不装 DV 吧~~
## 制作方法

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

1. 粘贴下面的 Dataview js 代码片段,并根据自己的笔记情况修改几个参数
2. 添加 css 样式

### Dataview js 代码

````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 = ""
}
}
```
````

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

![](https://cdn.pkmer.cn/images/202407012053617.png!pkmer)

丑丑的,缩成一团。

但是别担心,之后我们会用 css 来美化它。

首先要解决的问题是:这些链接都还是无效的。

你需要修改几个地方让它们能指向实际的月度笔记路径。

#### 年份

> `// 0. 从当前文件获取年份,或者直接填写变量`
你有两种办法指定年份,其一是在当前笔记添加一个 `year` 属性,并填写当前的年份。

![](https://cdn.pkmer.cn/images/202407012053618.png!pkmer)

其二是直接写在代码里,修改 `||` 后面的数字即可:

```js
// 0. 从当前文件获取年份,或者直接填写变量
let year = dv.current().year || 2066
```

两种办法的区别是:前者可以直接复制这个代码片段到任何笔记里,自动读取笔记的年份属性(比如每年的年度笔记都可以用这份代码);而后者则需要自己手动修改代码里的年份变量。

#### 文件夹

> `// 1. 这里是你的月份笔记的基础路径`
在这个位置把 `baseFolder` 修改成你的月份笔记的基础路径,其中 `${year}` 代表你在属性里填写的年份。

比如文件夹如果是 `月度笔记/2024年/` 就写成:

```js
// 1. 这里是你的月份笔记的基础路径
const baseFolder = `月度笔记/${year}`
```

### 文件名

> `// 2. 这里是你的月份笔记的路径`
这个位置则是修改你实际的月度笔记完整路径,其中 `${year}``${monthNum}` 会被替换成实际的年份和月份,然后 `${baseFolder}` 就是上面填写的那个基础路径。

比如完整路径如果是 `月度笔记/2024年/1月.md`,这里就写成:

```js
// 2. 这里是你的月份笔记的路径
const monthlyNote = `${baseFolder}/${monthNum}`

```

这样改完之后,每个笔记应该都能正确工作了。

你可以点击按钮打开某个笔记,或者鼠标停在上面来查看悬浮预览。

### 题外话:关于用到的函数

写到的时候用到了几个函数,这里也简单介绍一下。

`dv.func.dateformat()` 可以获得指定格式的日期(但是用 `momentJS` 或者 `datetime` 也 OK);配合 `dv.date('now')` 可以获得当前的时间。

所以结合起来,`dv.func.dateformat(dv.date('now', "M")` 就可以获得当前的月份,并进行对比。

dvjs 函数介绍:[Functions - Dataview](https://blacksmithgu.github.io/obsidian-dataview/reference/functions/#datetext-format)
> 顺便,如果想在 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
/* 月历按钮美化.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);
}


```

> [!info] CSS 片段
> 如果你不知道啥是 css 片段,参考文档:[PKMer_Obsidian 的 CSS 代码片段]( https://pkmer.cn/show/20230329145845 )
如果你不喜欢这个样式,也可以去类似 [零代码 - 精美CSS样式库](https://www.lingdaima.com/css/#/) 这样的网站找到自己喜欢的样式,然后替换上面的 CSS 片段。

例如找到一个想要的按钮,复制它的 css 片段:

![](https://cdn.pkmer.cn/images/202407012053619.png!pkmer)

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

## 特别说明

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

![](https://cdn.pkmer.cn/images/202407012053620.png!pkmer)

(日记里的前后按钮)

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

[Benature/obsidian-sample-vault](https://github.com/Benature/obsidian-sample-vault)
Loading

0 comments on commit 568f03b

Please sign in to comment.