diff --git a/src/editor/_code.scss b/src/editor/_code.scss new file mode 100644 index 0000000..0b1c9ff --- /dev/null +++ b/src/editor/_code.scss @@ -0,0 +1,22 @@ +body { + --code-background: var(--background-secondary); + --code-white-space: pre; + --code-size: 0.88em; + --code-normal: var(--text-normal); + --code-comment: var(--text-faint); + --code-function: var(--color-blue); + --code-important: var(--color-orange); + --code-keyword: var(--text-accent); + --code-operator: var(--text-muted); + --code-property: var(--color-cyan); + --code-punctuation: var(--text-muted); + --code-string: var(--color-orange); + --code-tag: var(--color-red); + --code-value: var(--color-purple); +} + +/* Obsidian has no code-block border or radius variable. */ +.markdown-rendered pre { + border: var(--border-width) solid var(--background-modifier-border); + border-radius: 6px; +} diff --git a/src/editor/_lists.scss b/src/editor/_lists.scss new file mode 100644 index 0000000..74f5fa9 --- /dev/null +++ b/src/editor/_lists.scss @@ -0,0 +1,20 @@ +body { + --list-indent: 2em; + --list-indent-editing: 0.75em; + --list-spacing: var(--size-2-1); + --list-marker-color: var(--text-muted); + --list-marker-color-hover: var(--text-accent); + --list-marker-color-collapsed: var(--text-accent); + --list-bullet-border: 1px solid var(--text-muted); + --list-bullet-radius: 50%; + --list-bullet-size: 5px; + --checkbox-radius: 4px; + --checkbox-size: 16px; + --checkbox-marker-color: var(--text-on-accent); + --checkbox-color: var(--interactive-accent); + --checkbox-color-hover: var(--interactive-accent-hover); + --checkbox-border-color: var(--text-faint); + --checkbox-border-color-hover: var(--text-muted); + --checklist-done-decoration: line-through; + --checklist-done-color: var(--text-faint); +} diff --git a/src/editor/_quotes.scss b/src/editor/_quotes.scss new file mode 100644 index 0000000..c1153d7 --- /dev/null +++ b/src/editor/_quotes.scss @@ -0,0 +1,9 @@ +body { + --blockquote-background-color: transparent; + --blockquote-border-thickness: 2px; + --blockquote-border-color: var(--text-accent); + --blockquote-font-style: normal; + --blockquote-color: var(--text-muted); + --hr-color: var(--background-modifier-border); + --hr-thickness: 1px; +} diff --git a/src/theme.scss b/src/theme.scss index d57e970..232187c 100644 --- a/src/theme.scss +++ b/src/theme.scss @@ -4,3 +4,6 @@ @use "foundations/typography"; @use "editor/headings"; @use "editor/inline"; +@use "editor/lists"; +@use "editor/quotes"; +@use "editor/code"; diff --git a/tests/editor-blocks.test.mjs b/tests/editor-blocks.test.mjs new file mode 100644 index 0000000..6bf5431 --- /dev/null +++ b/tests/editor-blocks.test.mjs @@ -0,0 +1,88 @@ +import assert from "node:assert/strict"; +import { readFile } from "node:fs/promises"; +import test from "node:test"; + +import postcss from "postcss"; + +import { declarationsFor } from "./helpers/css.mjs"; + +const css = await readFile(new URL("../theme.css", import.meta.url), "utf8"); +const body = declarationsFor(css, "body"); + +function assertDeclarations(expected) { + for (const [property, value] of Object.entries(expected)) { + assert.equal(body.get(property), value, property); + } +} + +test("defines list and task variables", () => { + assertDeclarations({ + "--list-indent": "2em", + "--list-indent-editing": "0.75em", + "--list-spacing": "var(--size-2-1)", + "--list-marker-color": "var(--text-muted)", + "--list-marker-color-hover": "var(--text-accent)", + "--list-marker-color-collapsed": "var(--text-accent)", + "--list-bullet-border": "1px solid var(--text-muted)", + "--list-bullet-radius": "50%", + "--list-bullet-size": "5px", + "--checkbox-radius": "4px", + "--checkbox-size": "16px", + "--checkbox-marker-color": "var(--text-on-accent)", + "--checkbox-color": "var(--interactive-accent)", + "--checkbox-color-hover": "var(--interactive-accent-hover)", + "--checkbox-border-color": "var(--text-faint)", + "--checkbox-border-color-hover": "var(--text-muted)", + "--checklist-done-decoration": "line-through", + "--checklist-done-color": "var(--text-faint)", + }); +}); + +test("defines quote and horizontal rule variables", () => { + assertDeclarations({ + "--blockquote-background-color": "transparent", + "--blockquote-border-thickness": "2px", + "--blockquote-border-color": "var(--text-accent)", + "--blockquote-font-style": "normal", + "--blockquote-color": "var(--text-muted)", + "--hr-color": "var(--background-modifier-border)", + "--hr-thickness": "1px", + }); +}); + +test("defines semantic code variables", () => { + assertDeclarations({ + "--code-background": "var(--background-secondary)", + "--code-white-space": "pre", + "--code-size": "0.88em", + "--code-normal": "var(--text-normal)", + "--code-comment": "var(--text-faint)", + "--code-function": "var(--color-blue)", + "--code-important": "var(--color-orange)", + "--code-keyword": "var(--text-accent)", + "--code-operator": "var(--text-muted)", + "--code-property": "var(--color-cyan)", + "--code-punctuation": "var(--text-muted)", + "--code-string": "var(--color-orange)", + "--code-tag": "var(--color-red)", + "--code-value": "var(--color-purple)", + }); +}); + +test("adds the single code block selector with direct border declarations", () => { + const rules = []; + + postcss.parse(css).walkRules((rule) => { + if (rule.selector === ".markdown-rendered pre") rules.push(rule); + }); + + assert.equal(rules.length, 1); + const declarations = rules[0].nodes.filter((node) => node.type === "decl"); + assert.deepEqual( + declarations.map(({ prop, value }) => [prop, value]), + [ + ["border", "var(--border-width) solid var(--background-modifier-border)"], + ["border-radius", "6px"], + ], + ); +}); diff --git a/theme.css b/theme.css index 27f4afa..51d0a76 100644 --- a/theme.css +++ b/theme.css @@ -109,3 +109,57 @@ body { --link-external-decoration: none; --link-external-decoration-hover: underline; } + +body { + --list-indent: 2em; + --list-indent-editing: 0.75em; + --list-spacing: var(--size-2-1); + --list-marker-color: var(--text-muted); + --list-marker-color-hover: var(--text-accent); + --list-marker-color-collapsed: var(--text-accent); + --list-bullet-border: 1px solid var(--text-muted); + --list-bullet-radius: 50%; + --list-bullet-size: 5px; + --checkbox-radius: 4px; + --checkbox-size: 16px; + --checkbox-marker-color: var(--text-on-accent); + --checkbox-color: var(--interactive-accent); + --checkbox-color-hover: var(--interactive-accent-hover); + --checkbox-border-color: var(--text-faint); + --checkbox-border-color-hover: var(--text-muted); + --checklist-done-decoration: line-through; + --checklist-done-color: var(--text-faint); +} + +body { + --blockquote-background-color: transparent; + --blockquote-border-thickness: 2px; + --blockquote-border-color: var(--text-accent); + --blockquote-font-style: normal; + --blockquote-color: var(--text-muted); + --hr-color: var(--background-modifier-border); + --hr-thickness: 1px; +} + +body { + --code-background: var(--background-secondary); + --code-white-space: pre; + --code-size: 0.88em; + --code-normal: var(--text-normal); + --code-comment: var(--text-faint); + --code-function: var(--color-blue); + --code-important: var(--color-orange); + --code-keyword: var(--text-accent); + --code-operator: var(--text-muted); + --code-property: var(--color-cyan); + --code-punctuation: var(--text-muted); + --code-string: var(--color-orange); + --code-tag: var(--color-red); + --code-value: var(--color-purple); +} + +/* Obsidian has no code-block border or radius variable. */ +.markdown-rendered pre { + border: var(--border-width) solid var(--background-modifier-border); + border-radius: 6px; +}