## 概要
[[Obsidian]]の[[Live Preview]]でも[[Logseq]]の[[Bullet Threading]]みたいな表示をしたい。

*[pengx17/logseq\-plugin\-bullet\-threading](https://github.com/pengx17/logseq-plugin-bullet-threading)より引用*
## ソリューション
[[CSS]]の設定だけで実現できます。
以下のページに[[Reading view]]において実現可能な[[CSS]]のソースコードが共有されているので、それを少し改造します。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://forum.obsidian.md/uploads/default/optimized/3X/a/b/abf9faf124ba8edea7e6e644ec69d669b49baa30_2_32x32.png" />
<span class="link-card-v2-site-name">Obsidian Forum</span>
</div>
<div class="link-card-v2-title">
Plugin for Bullet Threading
</div>
<div class="link-card-v2-content">
Here it is:
</div>
<img class="link-card-v2-image" src="https://forum.obsidian.md/uploads/default/original/3X/1/e/1eeeef2f4b8dd2052a41e008b237da935f4634d0.gif" />
<a href="https://forum.obsidian.md/t/plugin-for-bullet-threading/37317/21"></a>
</div>
ベースにしたソースコードは以下です。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" />
<span class="link-card-v2-site-name">Gist</span>
</div>
<div class="link-card-v2-title">
Obsidian list threading and highlight in live preview and source view
</div>
<div class="link-card-v2-content">
Obsidian list threading and highlight in live preview and source view - README.md
</div>
<img class="link-card-v2-image" src="https://github.githubassets.com/assets/gist-og-image-54fd7dc0713e.png" />
<a href="https://gist.github.com/KillyMXI/cbef8edff6dd55d9e6ea4df66567e9b1"></a>
</div>
`.HyperMD-list-line:hover` をすべて `.HyperMD-list-line.cm-active` に変更します。これで、マウスなどでホバーした行の代わりに、カーソルがアクティブな行が対象になります。
> [!hint]
> `:hover`と`.cm-active`の両方を指定すれば、マウスでもキーボードでも[[Bullet Threading]]を実現可能になると思いますが、確認はしていません。
### 実現イメージ
![[2024-01-27-23-15-41.webp|frame]]
### ソースコード
前提として `--list-indent` が正しく設定されている必要があります。
```css
.theme-light {
--list-indent: 1.2rem;
}
```
私のテーマ (改造した自作テーマ) の場合は以下のように設定しました。
```css
/* ---------------------------------------------------------------- */
/* L字線全体に対するスタイル */
/* --list-threading-colorは線の色に関する設定 */
/* --list-threading-offsetは横位置の調整. 大きいほど右に移動する */
/* ---------------------------------------------------------------- */
.HyperMD-list-line-1:not( :has(~ .HyperMD-list-line-1 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6,
.HyperMD-list-line-5,
.HyperMD-list-line-4,
.HyperMD-list-line-3,
.HyperMD-list-line-2).cm-active)::after,
.HyperMD-list-line-1:not( :has(~ .HyperMD-list-line-1 ~ .HyperMD-list-line.cm-active))~.HyperMD-list-line:has(~ .HyperMD-list-line-2.cm-active,
~ .HyperMD-list-line-2 ~ :is(.HyperMD-list-line-3,
.HyperMD-list-line-4,
.HyperMD-list-line-5,
.HyperMD-list-line-6).cm-active)::before,
.HyperMD-list-line-2:not( :has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line.cm-active)):is(.cm-active,
:has(~ :is(.HyperMD-list-line-3,
.HyperMD-list-line-4,
.HyperMD-list-line-5,
.HyperMD-list-line-6).cm-active))::before {
--list-threading-color: hsl(23, 100%, 45%, 0.5);
--list-threading-offset: calc(7px + 0.15em);
}
.HyperMD-list-line-2:not( :has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6,
.HyperMD-list-line-5,
.HyperMD-list-line-4,
.HyperMD-list-line-3).cm-active)::after,
.HyperMD-list-line-2:not( :has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line.cm-active))~.HyperMD-list-line:has(~ .HyperMD-list-line-3.cm-active,
~ .HyperMD-list-line-3 ~ :is(.HyperMD-list-line-4,
.HyperMD-list-line-5,
.HyperMD-list-line-6).cm-active)::before,
.HyperMD-list-line-3:not( :has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line.cm-active)):is(.cm-active,
:has(~ :is(.HyperMD-list-line-4,
.HyperMD-list-line-5,
.HyperMD-list-line-6).cm-active))::before {
--list-threading-color: hsl(23, 100%, 45%, 0.5);
--list-threading-offset: calc(6px + 0.15em + var(--list-indent));
}
.HyperMD-list-line-3:not( :has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6,
.HyperMD-list-line-5,
.HyperMD-list-line-4).cm-active)::after,
.HyperMD-list-line-3:not( :has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line.cm-active))~.HyperMD-list-line:has(~ .HyperMD-list-line-4.cm-active,
~ .HyperMD-list-line-4 ~ :is(.HyperMD-list-line-5, .HyperMD-list-line-6).cm-active)::before,
.HyperMD-list-line-4:not( :has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line.cm-active)):is(.cm-active,
:has(~ :is(.HyperMD-list-line-5, .HyperMD-list-line-6).cm-active))::before {
--list-threading-color: hsl(23, 100%, 45%, 0.5);
--list-threading-offset: calc(5px + 0.15em + 2 * var(--list-indent));
}
.HyperMD-list-line-4:not( :has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5).cm-active)::after,
.HyperMD-list-line-4:not( :has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line.cm-active))~.HyperMD-list-line:has(~ .HyperMD-list-line-5.cm-active,
~ .HyperMD-list-line-5 ~ :is(.HyperMD-list-line-6).cm-active)::before,
.HyperMD-list-line-5:not( :has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line.cm-active)):is(.cm-active, :has(~ :is(.HyperMD-list-line-6).cm-active))::before {
--list-threading-color: hsl(23, 100%, 45%, 0.5);
--list-threading-offset: calc(4px + 0.15em + 3 * var(--list-indent));
}
.HyperMD-list-line-5:not( :has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6).cm-active)::after,
.HyperMD-list-line-5:not( :has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line.cm-active))~.HyperMD-list-line:has(~ .HyperMD-list-line-6.cm-active)::before,
.HyperMD-list-line-6:not( :has(~ .HyperMD-list-line-6 ~ .HyperMD-list-line.cm-active)):is(.cm-active)::before {
--list-threading-color: hsl(23, 100%, 45%, 0.5);
--list-threading-offset: calc(2px + 0.15em + 4 * var(--list-indent));
}
/* ---------------------------------------------------------------- */
/* L字線と点の上接合部に対するスタイル */
/* heightが大きいほど線が点の上に突き抜ける */
/* ---------------------------------------------------------------- */
.HyperMD-list-line-1:not( :has(~ .HyperMD-list-line-1 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6,
.HyperMD-list-line-5,
.HyperMD-list-line-4,
.HyperMD-list-line-3,
.HyperMD-list-line-2).cm-active)::after,
.HyperMD-list-line-2:not( :has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6,
.HyperMD-list-line-5,
.HyperMD-list-line-4,
.HyperMD-list-line-3).cm-active)::after,
.HyperMD-list-line-3:not( :has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6,
.HyperMD-list-line-5,
.HyperMD-list-line-4).cm-active)::after,
.HyperMD-list-line-4:not( :has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5).cm-active)::after,
.HyperMD-list-line-5:not( :has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6).cm-active)::after {
content: "";
position: absolute;
left: var(--list-threading-offset);
bottom: 0;
height: calc(100% - 1.1em);
width: var(--size-2-1);
background-color: var(--list-threading-color);
}
.HyperMD-list-line.HyperMD-task-line::after {
max-height: calc(100% - 1.3em);
}
/* ---------------------------------------------------------------- */
/* L字線の上接合部と右接合部を結ぶ線のスタイル */
/* ---------------------------------------------------------------- */
.HyperMD-list-line-1:not( :has(~ .HyperMD-list-line-1 ~ .HyperMD-list-line.cm-active))~.HyperMD-list-line:has(~ .HyperMD-list-line-2.cm-active,
~ .HyperMD-list-line-2 ~ :is(.HyperMD-list-line-6,
.HyperMD-list-line-5,
.HyperMD-list-line-4,
.HyperMD-list-line-3).cm-active)::before,
.HyperMD-list-line-2:not( :has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line.cm-active))~.HyperMD-list-line:has(~ .HyperMD-list-line-3.cm-active,
~ .HyperMD-list-line-3 ~ :is(.HyperMD-list-line-6,
.HyperMD-list-line-5,
.HyperMD-list-line-4).cm-active)::before,
.HyperMD-list-line-3:not( :has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line.cm-active))~.HyperMD-list-line:has(~ .HyperMD-list-line-4.cm-active,
~ .HyperMD-list-line-4 ~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5).cm-active)::before,
.HyperMD-list-line-4:not( :has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line.cm-active))~.HyperMD-list-line:has(~ .HyperMD-list-line-5.cm-active,
~ .HyperMD-list-line-5 ~ :is(.HyperMD-list-line-6).cm-active)::before,
.HyperMD-list-line-5:not( :has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line.cm-active))~.HyperMD-list-line:has(~ .HyperMD-list-line-6.cm-active)::before {
content: "";
position: absolute;
left: var(--list-threading-offset);
top: 0;
height: 100%;
width: var(--size-2-1);
background-color: var(--list-threading-color);
}
/* ---------------------------------------------------------------- */
/* L字線の右接合部と点を結ぶ線のスタイル */
/* --list-indentが大きいと線が点に食い込んでいく(右にいく) */
/* ---------------------------------------------------------------- */
.HyperMD-list-line-2:not( :has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line.cm-active)):is(.cm-active,
:has(~ :is(.HyperMD-list-line-6,
.HyperMD-list-line-5,
.HyperMD-list-line-4,
.HyperMD-list-line-3).cm-active))::before,
.HyperMD-list-line-3:not( :has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line.cm-active)):is(.cm-active,
:has(~ :is(.HyperMD-list-line-6,
.HyperMD-list-line-5,
.HyperMD-list-line-4).cm-active))::before,
.HyperMD-list-line-4:not( :has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line.cm-active)):is(.cm-active,
:has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5).cm-active))::before,
.HyperMD-list-line-5:not( :has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line.cm-active)):is(.cm-active, :has(~ :is(.HyperMD-list-line-6).cm-active))::before,
.HyperMD-list-line-6:not( :has(~ .HyperMD-list-line-6 ~ .HyperMD-list-line.cm-active)):is(.cm-active)::before {
content: "";
position: absolute;
left: var(--list-threading-offset);
width: calc(var(--list-indent) - 0.4em);
top: 0;
height: calc(0.75em);
border-bottom-left-radius: var(--radius-m);
border-bottom: var(--size-2-1) solid var(--list-threading-color);
border-left: var(--size-2-1) solid var(--list-threading-color);
}
.HyperMD-list-line.HyperMD-task-line::before {
max-width: calc(var(--list-indent) - 0.65em);
}
```