Skip to content

Instantly share code, notes, and snippets.

@KillyMXI
Last active November 1, 2024 17:50
Show Gist options
  • Save KillyMXI/cbef8edff6dd55d9e6ea4df66567e9b1 to your computer and use it in GitHub Desktop.
Save KillyMXI/cbef8edff6dd55d9e6ea4df66567e9b1 to your computer and use it in GitHub Desktop.
Obsidian list threading and highlight in live preview and source view

Obsidian live-preview list threading and highlight

Obsidian forum thread: https://forum.obsidian.md/t/plugin-for-bullet-threading/37317/22

Add these CSS files in Appearance settings.

Changelog:

  • 2024-08-15

    • separate versions for mouse hover and active line (keyboard focus)
      • can be enabled simultaneously without conflicts
    • works in live preview and source view
    • configurable with Style Settings plugin
    • threading snippets now have priority for wrapped text by default, can be toggled to priority for images
    • default styles adjusted to keep hover and active line threading distinguishable while using same color palette
    • threading line offsets are fixed to match latest Obsidian styles
  • 2023-10-02

    • highlight snippet
      • halved the alpha, making highlight more subtle
      • made 6th color a bit more distinct from 5th
    • threading snippet
      • removed accidental dependency on another CSS snippet
      • adjusted offsets to better match indentation lines with the default font size
      • using --list-indent variable to hopefully make the snippet more compatible with styles that alter it
      • providing height calculations that prioritize wrapped text over images (or any other oversized inline content with default vertical alignment) - requires manual edits in 3 places to switch

Support me if you'd like me to publish Obsidian things more often:

https://github.com/sponsors/KillyMXI

/* @settings
name: Live preview list highlight - active line
id: live-preview-list-highlight-active
settings:
-
id: colors-section
title: Colors
type: heading
level: 2
collapsed: false
-
id: list-highlight-active-alpha
title: Alpha
description: The alpha (transparency) of all highlights
type: variable-number-slider
default: 0.05
min: 0.0
max: 1.0
step: 0.05
-
id: style-settings-bug-note
title: Note
description: "Style Settings seems to be [bugged](https://github.com/mgmeyers/obsidian-style-settings/issues/168). You may not see the actual colors here before interacting with each color picker."
type: info-text
markdown: true
-
id: list-highlight-active-color-1
title: Color 1
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(23, 100%, 45%)'
-
id: list-highlight-active-color-2
title: Color 2
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(46, 100%, 45%)'
-
id: list-highlight-active-color-3
title: Color 3
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(70, 100%, 45%)'
-
id: list-highlight-active-color-4
title: Color 4
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(105, 100%, 45%)'
-
id: list-highlight-active-color-5
title: Color 5
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(187, 100%, 45%)'
-
id: list-highlight-active-color-6
title: Color 6
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(223, 100%, 45%)'
*/
.HyperMD-list-line-1.cm-active,
.HyperMD-list-line-1:not(:has(~ .HyperMD-list-line-1 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-2, .HyperMD-list-line-3, .HyperMD-list-line-4, .HyperMD-list-line-5, .HyperMD-list-line-6).cm-active) {
background-color: hsl(var(--list-highlight-active-color-1, 23, 100%, 45%), var(--list-highlight-active-alpha, 0.05));
}
.HyperMD-list-line-2.cm-active,
.HyperMD-list-line-2:not(:has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-3, .HyperMD-list-line-4, .HyperMD-list-line-5, .HyperMD-list-line-6).cm-active) {
background-color: hsl(var(--list-highlight-active-color-2, 46, 100%, 45%), var(--list-highlight-active-alpha, 0.05));
}
.HyperMD-list-line-3.cm-active,
.HyperMD-list-line-3:not(:has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-4, .HyperMD-list-line-5, .HyperMD-list-line-6).cm-active) {
background-color: hsl(var(--list-highlight-active-color-3, 70, 100%, 45%), var(--list-highlight-active-alpha, 0.05));
}
.HyperMD-list-line-4.cm-active,
.HyperMD-list-line-4:not(:has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-5, .HyperMD-list-line-6).cm-active) {
background-color: hsl(var(--list-highlight-active-color-4, 105, 100%, 45%), var(--list-highlight-active-alpha, 0.05));
}
.HyperMD-list-line-5.cm-active,
.HyperMD-list-line-5:not(:has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6).cm-active) {
background-color: hsl(var(--list-highlight-active-color-5, 187, 100%, 45%), var(--list-highlight-active-alpha, 0.05));
}
.HyperMD-list-line-6.cm-active {
background-color: hsl(var(--list-highlight-active-color-6, 223, 100%, 45%), var(--list-highlight-active-alpha, 0.05));
}
/* @settings
name: Live preview list highlight - on hover
id: live-preview-list-highlight-hover
settings:
-
id: colors-section
title: Colors
type: heading
level: 2
collapsed: false
-
id: list-highlight-hover-alpha
title: Alpha
description: The alpha (transparency) of all highlights
type: variable-number-slider
default: 0.05
min: 0.0
max: 1.0
step: 0.05
-
id: style-settings-bug-note
title: Note
description: "Style Settings seems to be [bugged](https://github.com/mgmeyers/obsidian-style-settings/issues/168). You may not see the actual colors here before interacting with each color picker."
type: info-text
markdown: true
-
id: list-highlight-hover-color-1
title: Color 1
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(23, 100%, 45%)'
-
id: list-highlight-hover-color-2
title: Color 2
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(46, 100%, 45%)'
-
id: list-highlight-hover-color-3
title: Color 3
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(70, 100%, 45%)'
-
id: list-highlight-hover-color-4
title: Color 4
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(105, 100%, 45%)'
-
id: list-highlight-hover-color-5
title: Color 5
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(187, 100%, 45%)'
-
id: list-highlight-hover-color-6
title: Color 6
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(223, 100%, 45%)'
*/
.HyperMD-list-line-1:hover,
.HyperMD-list-line-1:not(:has(~ .HyperMD-list-line-1 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-2, .HyperMD-list-line-3, .HyperMD-list-line-4, .HyperMD-list-line-5, .HyperMD-list-line-6):hover) {
background-color: hsl(var(--list-highlight-hover-color-1, 23, 100%, 45%), var(--list-highlight-hover-alpha, 0.05));
}
.HyperMD-list-line-2:hover,
.HyperMD-list-line-2:not(:has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-3, .HyperMD-list-line-4, .HyperMD-list-line-5, .HyperMD-list-line-6):hover) {
background-color: hsl(var(--list-highlight-hover-color-2, 46, 100%, 45%), var(--list-highlight-hover-alpha, 0.05));
}
.HyperMD-list-line-3:hover,
.HyperMD-list-line-3:not(:has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-4, .HyperMD-list-line-5, .HyperMD-list-line-6):hover) {
background-color: hsl(var(--list-highlight-hover-color-3, 70, 100%, 45%), var(--list-highlight-hover-alpha, 0.05));
}
.HyperMD-list-line-4:hover,
.HyperMD-list-line-4:not(:has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-5, .HyperMD-list-line-6):hover) {
background-color: hsl(var(--list-highlight-hover-color-4, 105, 100%, 45%), var(--list-highlight-hover-alpha, 0.05));
}
.HyperMD-list-line-5:hover,
.HyperMD-list-line-5:not(:has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6):hover) {
background-color: hsl(var(--list-highlight-hover-color-5, 187, 100%, 45%), var(--list-highlight-hover-alpha, 0.05));
}
.HyperMD-list-line-6:hover {
background-color: hsl(var(--list-highlight-hover-color-6, 223, 100%, 45%), var(--list-highlight-hover-alpha, 0.05));
}
/* @settings
name: Live preview list threading - active line
id: live-preview-list-threading-active
settings:
-
id: list-threading-active-elbow-location
title: Threading line elbow location
description: Where the threading line elbow is located
type: class-select
allowEmpty: false
default: list-threading-active-elbow-top
options:
-
label: "Top (priority for wrapped text)"
value: list-threading-active-elbow-top
-
label: "Bottom (priority for images)"
value: list-threading-active-elbow-bottom
-
id: list-threading-active-width
title: Threading line width
description: The width of the threading line
type: variable-number
default: 3
format: px
-
id: list-threading-active-offset-extra
title: Thread line extra offset
description: Extra offset for threading line
type: variable-number
default: 2
format: px
-
id: colors-section
title: Colors
type: heading
level: 2
collapsed: false
-
id: list-threading-active-alpha
title: Alpha
description: The alpha (transparency) of all threading lines
type: variable-number-slider
default: 0.2
min: 0.0
max: 1.0
step: 0.05
-
id: style-settings-bug-note
title: Note
description: "Style Settings seems to be [bugged](https://github.com/mgmeyers/obsidian-style-settings/issues/168). You may not see the actual colors here before interacting with each color picker."
type: info-text
markdown: true
-
id: list-threading-active-color-1
title: Color 1
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(23, 100%, 45%)'
-
id: list-threading-active-color-2
title: Color 2
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(46, 100%, 45%)'
-
id: list-threading-active-color-3
title: Color 3
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(70, 100%, 45%)'
-
id: list-threading-active-color-4
title: Color 4
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(105, 100%, 45%)'
-
id: list-threading-active-color-5
title: Color 5
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(187, 100%, 45%)'
*/
.markdown-source-view .HyperMD-list-line {
/* Unitless zero in variables is evil */
--list-padding-inline-start-fix: 0px; /*calc(1px * var(--list-indent-source));*/
}
.markdown-source-view.is-live-preview .HyperMD-list-line {
--list-padding-inline-start-fix: var(--list-indent-editing);
}
.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),
.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),
.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)) > .cm-hmd-list-indent {
&::before {
--list-threading-active-color: hsl(var(--list-threading-active-color-1, 23, 100%, 45%), var(--list-threading-active-alpha, 0.2));
--list-threading-active-offset: calc(var(--list-threading-active-offset-extra, 2px) + var(--list-padding-inline-start-fix));
}
}
.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),
.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),
.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)) > .cm-hmd-list-indent {
&::before {
--list-threading-active-color: hsl(var(--list-threading-active-color-2, 46, 100%, 45%), var(--list-threading-active-alpha, 0.2));
--list-threading-active-offset: calc(var(--list-threading-active-offset-extra, 2px) + var(--list-padding-inline-start-fix) + 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),
.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),
.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)) > .cm-hmd-list-indent {
&::before {
--list-threading-active-color: hsl(var(--list-threading-active-color-3, 70, 100%, 45%), var(--list-threading-active-alpha, 0.2));
--list-threading-active-offset: calc(var(--list-threading-active-offset-extra, 2px) + var(--list-padding-inline-start-fix) + 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),
.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),
.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)) > .cm-hmd-list-indent {
&::before {
--list-threading-active-color: hsl(var(--list-threading-active-color-4, 105, 100%, 45%), var(--list-threading-active-alpha, 0.2));
--list-threading-active-offset: calc(var(--list-threading-active-offset-extra, 2px) + var(--list-padding-inline-start-fix) + 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),
.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),
.HyperMD-list-line-6:not(:has(~ .HyperMD-list-line-6 ~ .HyperMD-list-line.cm-active)):is(.cm-active) > .cm-hmd-list-indent {
&::before {
--list-threading-active-color: hsl(var(--list-threading-active-color-5, 187, 100%, 45%), var(--list-threading-active-alpha, 0.2));
--list-threading-active-offset: calc(var(--list-threading-active-offset-extra, 2px) + var(--list-padding-inline-start-fix) + 4 * var(--list-indent));
}
}
/* tails */
.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),
.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),
.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),
.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),
.HyperMD-list-line-5:not(:has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line.cm-active)):has(~ :is(.HyperMD-list-line-6).cm-active) {
&::before {
content: "";
position: absolute;
left: var(--list-threading-active-offset);
bottom: 0;
width: var(--list-threading-active-width, 3px);
background-color: var(--list-threading-active-color);
height: calc(100% - 0.75em);
}
.is-live-preview &:is(.HyperMD-task-line)::before {
max-height: calc(100% - 1.3em);
}
body.list-threading-active-elbow-bottom &::before {
height: 0.8em;
}
body.list-threading-active-elbow-bottom .is-live-preview &:is(.HyperMD-task-line)::before {
max-height: 0.275em;
}
}
/* in-between lines */
.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),
.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),
.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),
.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),
.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-active-offset);
top: 0;
height: 100%;
width: var(--list-threading-active-width, 3px);
background-color: var(--list-threading-active-color);
}
}
/* elbows */
.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)),
.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)),
.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)),
.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)),
.HyperMD-list-line-6:not(:has(~ .HyperMD-list-line-6 ~ .HyperMD-list-line.cm-active)):is(.cm-active) {
& > .cm-hmd-list-indent::before {
content: "";
position: absolute;
left: var(--list-threading-active-offset);
width: calc(var(--list-indent) - var(--list-threading-active-width, 3px));
top: 0;
border-bottom-left-radius: var(--radius-m);
border-bottom: var(--list-threading-active-width, 3px) solid var(--list-threading-active-color);
border-left: var(--list-threading-active-width, 3px) solid var(--list-threading-active-color);
height: calc(0.775em);
}
body.list-threading-active-elbow-bottom & > .cm-hmd-list-indent::before {
height: calc(100% - 0.825em - var(--list-threading-active-width, 3px) / 2);
}
.is-live-preview &:is(.HyperMD-task-line) > .cm-hmd-list-indent::before {
max-width: calc(var(--list-indent) - 0.35em - var(--list-threading-active-offset-extra, 2px));
}
}
/* @settings
name: Live preview list threading - on hover
id: live-preview-list-threading-hover
settings:
-
id: list-threading-hover-elbow-location
title: Threading line elbow location
description: Where the threading line elbow is located
type: class-select
allowEmpty: false
default: list-threading-hover-elbow-top
options:
-
label: "Top (priority for wrapped text)"
value: list-threading-hover-elbow-top
-
label: "Bottom (priority for images)"
value: list-threading-hover-elbow-bottom
-
id: list-threading-hover-width
title: Threading line width
description: The width of the threading line
type: variable-number
default: 1
format: px
-
id: list-threading-hover-offset-extra
title: Thread line extra offset
description: Extra offset for threading line
type: variable-number
default: 4
format: px
-
id: colors-section
title: Colors
type: heading
level: 2
collapsed: false
-
id: list-threading-hover-alpha
title: Alpha
description: The alpha (transparency) of all threading lines
type: variable-number-slider
default: 0.4
min: 0.0
max: 1.0
step: 0.05
-
id: style-settings-bug-note
title: Note
description: "Style Settings seems to be [bugged](https://github.com/mgmeyers/obsidian-style-settings/issues/168). You may not see the actual colors here before interacting with each color picker."
type: info-text
markdown: true
-
id: list-threading-hover-color-1
title: Color 1
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(23, 100%, 45%)'
-
id: list-threading-hover-color-2
title: Color 2
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(46, 100%, 45%)'
-
id: list-threading-hover-color-3
title: Color 3
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(70, 100%, 45%)'
-
id: list-threading-hover-color-4
title: Color 4
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(105, 100%, 45%)'
-
id: list-threading-hover-color-5
title: Color 5
type: variable-color
opacity: false
format: hsl-values
default: 'hsl(187, 100%, 45%)'
*/
.markdown-source-view .HyperMD-list-line {
/* Unitless zero in variables is evil */
--list-padding-inline-start-fix: 0px; /*calc(1px * var(--list-indent-source));*/
}
.markdown-source-view.is-live-preview .HyperMD-list-line {
--list-padding-inline-start-fix: var(--list-indent-editing);
}
.HyperMD-list-line-1:not(:has(~ .HyperMD-list-line-1 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5, .HyperMD-list-line-4, .HyperMD-list-line-3, .HyperMD-list-line-2):hover),
.HyperMD-list-line-1:not(:has(~ .HyperMD-list-line-1 ~ .HyperMD-list-line:hover)) ~ .HyperMD-list-line:has(~ .HyperMD-list-line-2:hover, ~ .HyperMD-list-line-2 ~ :is(.HyperMD-list-line-3, .HyperMD-list-line-4, .HyperMD-list-line-5, .HyperMD-list-line-6):hover),
.HyperMD-list-line-2:not(:has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line:hover)):is(:hover, :has(~ :is(.HyperMD-list-line-3, .HyperMD-list-line-4, .HyperMD-list-line-5, .HyperMD-list-line-6):hover)) > .cm-hmd-list-indent {
&::after {
--list-threading-hover-color: hsl(var(--list-threading-hover-color-1, 23, 100%, 45%), var(--list-threading-hover-alpha, 0.4));
--list-threading-hover-offset: calc(var(--list-threading-hover-offset-extra, 4px) + var(--list-padding-inline-start-fix));
}
}
.HyperMD-list-line-2:not(:has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5, .HyperMD-list-line-4, .HyperMD-list-line-3):hover),
.HyperMD-list-line-2:not(:has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line:hover)) ~ .HyperMD-list-line:has(~ .HyperMD-list-line-3:hover, ~ .HyperMD-list-line-3 ~ :is(.HyperMD-list-line-4, .HyperMD-list-line-5, .HyperMD-list-line-6):hover),
.HyperMD-list-line-3:not(:has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line:hover)):is(:hover, :has(~ :is(.HyperMD-list-line-4, .HyperMD-list-line-5, .HyperMD-list-line-6):hover)) > .cm-hmd-list-indent {
&::after {
--list-threading-hover-color: hsl(var(--list-threading-hover-color-2, 46, 100%, 45%), var(--list-threading-hover-alpha, 0.4));
--list-threading-hover-offset: calc(var(--list-threading-hover-offset-extra, 4px) + var(--list-padding-inline-start-fix) + var(--list-indent));
}
}
.HyperMD-list-line-3:not(:has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5, .HyperMD-list-line-4):hover),
.HyperMD-list-line-3:not(:has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line:hover)) ~ .HyperMD-list-line:has(~ .HyperMD-list-line-4:hover, ~ .HyperMD-list-line-4 ~ :is(.HyperMD-list-line-5, .HyperMD-list-line-6):hover),
.HyperMD-list-line-4:not(:has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line:hover)):is(:hover, :has(~ :is(.HyperMD-list-line-5, .HyperMD-list-line-6):hover)) > .cm-hmd-list-indent {
&::after {
--list-threading-hover-color: hsl(var(--list-threading-hover-color-3, 70, 100%, 45%), var(--list-threading-hover-alpha, 0.4));
--list-threading-hover-offset: calc(var(--list-threading-hover-offset-extra, 4px) + var(--list-padding-inline-start-fix) + 2 * var(--list-indent));
}
}
.HyperMD-list-line-4:not(:has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5):hover),
.HyperMD-list-line-4:not(:has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line:hover)) ~ .HyperMD-list-line:has(~ .HyperMD-list-line-5:hover, ~ .HyperMD-list-line-5 ~ :is(.HyperMD-list-line-6):hover),
.HyperMD-list-line-5:not(:has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line:hover)):is(:hover, :has(~ :is(.HyperMD-list-line-6):hover)) > .cm-hmd-list-indent {
&::after {
--list-threading-hover-color: hsl(var(--list-threading-hover-color-4, 105, 100%, 45%), var(--list-threading-hover-alpha, 0.4));
--list-threading-hover-offset: calc(var(--list-threading-hover-offset-extra, 4px) + var(--list-padding-inline-start-fix) + 3 * var(--list-indent));
}
}
.HyperMD-list-line-5:not(:has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6):hover),
.HyperMD-list-line-5:not(:has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line:hover)) ~ .HyperMD-list-line:has(~ .HyperMD-list-line-6:hover),
.HyperMD-list-line-6:not(:has(~ .HyperMD-list-line-6 ~ .HyperMD-list-line:hover)):is(:hover) > .cm-hmd-list-indent {
&::after {
--list-threading-hover-color: hsl(var(--list-threading-hover-color-5, 187, 100%, 45%), var(--list-threading-hover-alpha, 0.4));
--list-threading-hover-offset: calc(var(--list-threading-hover-offset-extra, 4px) + var(--list-padding-inline-start-fix) + 4 * var(--list-indent));
}
}
/* tails */
.HyperMD-list-line-1:not(:has(~ .HyperMD-list-line-1 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5, .HyperMD-list-line-4, .HyperMD-list-line-3, .HyperMD-list-line-2):hover),
.HyperMD-list-line-2:not(:has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5, .HyperMD-list-line-4, .HyperMD-list-line-3):hover),
.HyperMD-list-line-3:not(:has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5, .HyperMD-list-line-4):hover),
.HyperMD-list-line-4:not(:has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5):hover),
.HyperMD-list-line-5:not(:has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line:hover)):has(~ :is(.HyperMD-list-line-6):hover) {
&::after {
content: "";
position: absolute;
left: var(--list-threading-hover-offset);
bottom: 0;
width: var(--list-threading-hover-width, 1px);
background-color: var(--list-threading-hover-color);
height: calc(100% - 0.75em);
}
.is-live-preview &:is(.HyperMD-task-line)::after {
max-height: calc(100% - 1.3em);
}
body.list-threading-hover-elbow-bottom &::after {
height: 0.8em;
}
body.list-threading-hover-elbow-bottom .is-live-preview &:is(.HyperMD-task-line)::after {
max-height: 0.275em;
}
}
/* in-between lines */
.HyperMD-list-line-1:not(:has(~ .HyperMD-list-line-1 ~ .HyperMD-list-line:hover)) ~ .HyperMD-list-line:has(~ .HyperMD-list-line-2:hover, ~ .HyperMD-list-line-2 ~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5, .HyperMD-list-line-4, .HyperMD-list-line-3):hover),
.HyperMD-list-line-2:not(:has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line:hover)) ~ .HyperMD-list-line:has(~ .HyperMD-list-line-3:hover, ~ .HyperMD-list-line-3 ~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5, .HyperMD-list-line-4):hover),
.HyperMD-list-line-3:not(:has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line:hover)) ~ .HyperMD-list-line:has(~ .HyperMD-list-line-4:hover, ~ .HyperMD-list-line-4 ~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5):hover),
.HyperMD-list-line-4:not(:has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line:hover)) ~ .HyperMD-list-line:has(~ .HyperMD-list-line-5:hover, ~ .HyperMD-list-line-5 ~ :is(.HyperMD-list-line-6):hover),
.HyperMD-list-line-5:not(:has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line:hover)) ~ .HyperMD-list-line:has(~ .HyperMD-list-line-6:hover) {
&::after {
content: "";
position: absolute;
left: var(--list-threading-hover-offset);
top: 0;
height: 100%;
width: var(--list-threading-hover-width, 1px);
background-color: var(--list-threading-hover-color);
}
}
/* elbows */
.HyperMD-list-line-2:not(:has(~ .HyperMD-list-line-2 ~ .HyperMD-list-line:hover)):is(:hover, :has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5, .HyperMD-list-line-4, .HyperMD-list-line-3):hover)),
.HyperMD-list-line-3:not(:has(~ .HyperMD-list-line-3 ~ .HyperMD-list-line:hover)):is(:hover, :has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5, .HyperMD-list-line-4):hover)),
.HyperMD-list-line-4:not(:has(~ .HyperMD-list-line-4 ~ .HyperMD-list-line:hover)):is(:hover, :has(~ :is(.HyperMD-list-line-6, .HyperMD-list-line-5):hover)),
.HyperMD-list-line-5:not(:has(~ .HyperMD-list-line-5 ~ .HyperMD-list-line:hover)):is(:hover, :has(~ :is(.HyperMD-list-line-6):hover)),
.HyperMD-list-line-6:not(:has(~ .HyperMD-list-line-6 ~ .HyperMD-list-line:hover)):is(:hover) {
& > .cm-hmd-list-indent::after {
content: "";
position: absolute;
left: var(--list-threading-hover-offset);
width: calc(var(--list-indent) - var(--list-threading-hover-width, 1px));
top: 0;
border-bottom-left-radius: var(--radius-m);
border-bottom: var(--list-threading-hover-width, 1px) solid var(--list-threading-hover-color);
border-left: var(--list-threading-hover-width, 1px) solid var(--list-threading-hover-color);
height: calc(0.775em);
}
body.list-threading-hover-elbow-bottom & > .cm-hmd-list-indent::after {
height: calc(100% - 0.825em - var(--list-threading-hover-width, 1px) / 2);
}
.is-live-preview &:is(.HyperMD-task-line) > .cm-hmd-list-indent::after {
max-width: calc(var(--list-indent) - 0.35em - var(--list-threading-hover-offset-extra, 4px));
}
}
@lasseeboe
Copy link

Very nice! Is it possible to make the threading stick on cursor position instead of mouse position?

@KillyMXI
Copy link
Author

KillyMXI commented Oct 12, 2023

@lasseeboe good question.
And the answer is Yes!

Find and replace with your code editor of choice all :hover with .cm-active, and it seems to work nicely!

( Ctrl+H hotkey is typically used for the replace operation in many editors, please don't try to replace them one by one manually. I hope this is trivial enough, so I don't have to make a separate copy. )

@neuromaancer
Copy link

neuromaancer commented Oct 21, 2023

Hi This is excellent! Thank you very much! However, I have an issue, it works fine if I use the mouse, but I am a Vim user, so I actually use vim motion with vim obsidian plugin. I think this snippet won't allow me to do the same thing with vim cursor. Especially in Vim normal mode.

@pulkitgoyal56
Copy link

pulkitgoyal56 commented Oct 21, 2023

@lasseeboe good question. And the answer is Yes!

Find and replace with your code editor of choice all :hover with .cm-active, and it seems to work nicely!

( Ctrl+H hotkey is typically used for the replace operation in many editors, please don't try to replace them one by one manually. I hope this is trivial enough, so I don't have to make a separate copy. )

I use the Vim plugin as well and it works perfectly with this change.

I actually use both the mouse hover version and the cursor version together.

That setup also mostly works. Although there are cases where it doesn't work perfectly. Like having the cursor and mouse on different items at the same sublist level, the vertical line is not proper. Maybe @KillyMXI, would you suggest any modifications to make it work better in that setup? (It'd also be very nice if these two could be made visually more different, like maybe dotted lines for one and solid lines for the other, but I suppose that requires more changes. Any comments there?)

@KillyMXI
Copy link
Author

Oh gosh.
I was thinking how to make a combined version that would follow either the keyboard cursor or mouse, giving priority to mouse.
Making separate threading for keyboard and mouse might be possible, will try to pull it off without compromises.
Quick answer: With a compromise of losing tails, it is certainly possible - one copy will use ::before, the other copy will use ::after pseudo-element.

Dotted lines may not work very well - each thread is composed of small fragments - there are going to be a lot of visual artifacts.
When there are two threads, I would rather assign each one a constant color regardless of depth. Assuming low alpha, two distinct enough hues may blend well enough to see how they overlap.
Other tools to distinguish them are line offset and thickness.

@KillyMXI
Copy link
Author

KillyMXI commented Aug 15, 2024

Timely nudge...
I was able to focus on the improved version, long overdue.

@pulkitgoyal56 I was able to keep two full versions of threading completely apart from each other, so it is now possible to enjoy it both for active line (kb cursor) and mouse hover.
By default, they are distinguished by width and opacity. But colors are also adjustable.

two-threading-lines

@X012C
Copy link

X012C commented Aug 19, 2024

image
I am new to obsidian. I loaded the CSS in the default theme but it didn't take effect. I don't know which step I missed. I hope to get help.

@justanotherjurastudent
Copy link

justanotherjurastudent commented Aug 19, 2024

image I am new to obsidian. I loaded the CSS in the default theme but it didn't take effect. I don't know which step I missed. I hope to get help.

@X012C You have to save the CSS code in a CSS file under the .obsidian > snippets folder and then activate the snippet in the Obsidian settings under appearance. Have you done this steps?

@X012C
Copy link

X012C commented Aug 19, 2024

image I am new to obsidian. I loaded the CSS in the default theme but it didn't take effect. I don't know which step I missed. I hope to get help.

@X012C You have to save the CSS code in a CSS file under the .obsidian > snippets folder and then activate the snippet in the Obsidian settings under appearance. Have you done this steps?

image
I should be done.

@KillyMXI
Copy link
Author

image I am new to obsidian. I loaded the CSS in the default theme but it didn't take effect. I don't know which step I missed. I hope to get help.

@X012C the issue is that this is intended to work with markdown lists, and you're showing just intended text instead of a list.

Refer to https://help.obsidian.md/Editing+and+formatting/Basic+formatting+syntax#Lists.

While Obsidian makes indented text to behave somewhat similar to lists (with indentation guides and folding), I don't think it is good to use.

@X012C
Copy link

X012C commented Aug 19, 2024

image I am new to obsidian. I loaded the CSS in the default theme but it didn't take effect. I don't know which step I missed. I hope to get help.

@X012C the issue is that this is intended to work with markdown lists, and you're showing just intended text instead of a list.

Refer to https://help.obsidian.md/Editing+and+formatting/Basic+formatting+syntax#Lists.

While Obsidian makes indented text to behave somewhat similar to lists (with indentation guides and folding), I don't think it is good to use.

I use a translation tool, so there may be some discrepancies in communication. I tried to use the style of md lists in the address you provided, but it didn't work?
image

@KillyMXI
Copy link
Author

@X012C according to your screenshot, active list items highlight is working as expected.

If you need list threading - you have to use different CSS file. There are 4 of them in this Gist.

Use the "Download ZIP" button on the top right of this page to get all files at once.

@X012C
Copy link

X012C commented Aug 20, 2024

@X012C according to your screenshot, active list items highlight is working as expected.

If you need list threading - you have to use different CSS file. There are 4 of them in this Gist.

Use the "Download ZIP" button on the top right of this page to get all files at once.

It worked successfully, thanks for your help.

@dianedef
Copy link

dianedef commented Aug 21, 2024

This is splendid, and great for focus. Thanks a ton!
Edit 1 : Oh and BTW, it would be amazing to have all of these snippets into a plugin where we could maybe toggle hover, colors, and stuff... If you feel like it one day:)
Edit 2 : Oh you can configure stuff with the plugin Style Settings! Great =D

@muhirwa45
Copy link

Great job 👍
How I can i change color of bullet threading as one color (such light blue) instead of different color in editing, preview and reading mode?. Thank you

@socalledtheraven
Copy link

This is awesome! Is there any way to toggle it (or modify the css, if need be) so that the hover effect always shows? Thanks so much!

@KillyMXI
Copy link
Author

@socalledtheraven I don't understand the question. Please elaborate.

@socalledtheraven
Copy link

this is what it looks like when I hover a particular bullet:
image
and this is what it looks like when I don't:
image
What I'd like to do is make it so that the first view applies to all bullets, whether or not I'm hovering over them.

@KillyMXI
Copy link
Author

@socalledtheraven So you need something like a tree view.
I saw someone else did it, but it might have some bugs, and I can't remember where I saw it - probably in Obsidian Discord.
I thought about whether I should recreate it and work around some limitations, but it seems insignificant for me.
I care about what helps to narrow down the focus, not disperse it.
It might look ok as a replacement of current indentation lines, with appropriately low contrast.
I will keep it in mind just as a challenge. But, as a not very practical feature, I don't expect to attempt it soon.

@justanotherjurastudent
Copy link

justanotherjurastudent commented Oct 12, 2024

(reply to original question by via-lactea7, now deleted)

@KillyMXI 스크린샷 2024-10-12 10 51 41

Is there any specific code I should modify to move the highlighted part in the image downwards to align with the dot?

[RESPONSE REDACTED OUT BY KillyMXI]

@via-lactea7
Copy link

@justanotherjurastudent Thx for the advice!

@KillyMXI
Copy link
Author

@via-lactea7 why you deleted most of your comments? I'm recovering the discussion from email notifications.

When it comes to vertical adjustment for the bullet point location - there is some guesswork, and I adjusted it to Latin script and default theme with whatever font it uses.

You won't need to touch the top value.
You will need to adjust (increase) height (and possibly width) of elbow and adjust (decrease) height of tail - by adding/subtracting some value in formulas.
Pay attention that there are two different heights depending on the setting body.list-threading-hover-elbow-bottom.

Thanks for the question. I noted this issue, and I think I can add Style Settings variables to adjust this with ease. Will do this later (hopefully soon).

Advice by justanotherjurastudent was misguided. I'm deleting some comments to prevent further confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment