diff --git a/bun.lock b/bun.lock index 6f5a710..bb6a4c4 100644 --- a/bun.lock +++ b/bun.lock @@ -6,7 +6,7 @@ "dependencies": { "@biomejs/biome": "^1.9.4", "@endeavorance/emdy": "^1.0.0", - "marked": "^15.0.12", + "rehype-callouts": "^2.1.0", "rehype-raw": "^7.0.0", "rehype-slug": "^6.0.0", "rehype-stringify": "^10.0.1", @@ -90,10 +90,14 @@ "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], + "hast-util-from-html": ["hast-util-from-html@2.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.1.0", "hast-util-from-parse5": "^8.0.0", "parse5": "^7.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw=="], + "hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="], "hast-util-heading-rank": ["hast-util-heading-rank@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA=="], + "hast-util-is-element": ["hast-util-is-element@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g=="], + "hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="], "hast-util-raw": ["hast-util-raw@9.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-from-parse5": "^8.0.0", "hast-util-to-parse5": "^8.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "parse5": "^7.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw=="], @@ -116,8 +120,6 @@ "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], - "marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], - "mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="], "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="], @@ -204,6 +206,8 @@ "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], + "rehype-callouts": ["rehype-callouts@2.1.0", "", { "dependencies": { "@types/hast": "^3.0.4", "hast-util-from-html": "^2.0.3", "hast-util-is-element": "^3.0.0", "hastscript": "^9.0.1", "unist-util-visit": "^5.0.0" } }, "sha512-Als/wlYpXg2Rs0p/yofrkSH6IQzn1xh6cvBC5BHy5JVT3lGlzUvVT8wOyVqCEgf8Eun6cQ3f47rLLoaiyLkP0w=="], + "rehype-raw": ["rehype-raw@7.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", "vfile": "^6.0.0" } }, "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww=="], "rehype-slug": ["rehype-slug@6.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "github-slugger": "^2.0.0", "hast-util-heading-rank": "^3.0.0", "hast-util-to-string": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A=="], diff --git a/demo/another.md b/demo/another.md index a0dad4d..2792cae 100644 --- a/demo/another.md +++ b/demo/another.md @@ -8,3 +8,12 @@ It has a list! - See? - Fancy! + +How about a callout? + +> [!info] This is an info callout +> Here's some more info +> etc + +> [!warning]- This is collapsible +> And how! diff --git a/package.json b/package.json index c891984..4083909 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "module": "index.ts", "type": "module", "private": true, - "version": "0.1.0", + "version": "0.2.0", "devDependencies": { "@types/bun": "latest" }, @@ -13,6 +13,7 @@ "dependencies": { "@biomejs/biome": "^1.9.4", "@endeavorance/emdy": "^1.0.0", + "rehype-callouts": "^2.1.0", "rehype-raw": "^7.0.0", "rehype-slug": "^6.0.0", "rehype-stringify": "^10.0.1", diff --git a/src/defaults/default-style.css b/src/defaults/default-style.css index ef7d9b3..c7e2f9c 100644 --- a/src/defaults/default-style.css +++ b/src/defaults/default-style.css @@ -113,3 +113,248 @@ th { background: var(--color-bg); font-weight: 500; } + +/* Callout styles, from https://raw.githubusercontent.com/lin-stephanie/rehype-callouts/refs/heads/main/src/themes/obsidian/index.css */ + +[data-callout="note"] { + --rc-color-light: var(--callout-note-color-light, rgb(8, 109, 221)); + --rc-color-dark: var(--callout-note-color-dark, rgb(2, 122, 255)); +} + +[data-callout="abstract"] { + --rc-color-light: var(--callout-abstract-color-light, rgb(0, 191, 188)); + --rc-color-dark: var(--callout-abstract-color-dark, rgb(83, 223, 221)); +} + +[data-callout="summary"] { + --rc-color-light: var(--callout-summary-color-light, rgb(0, 191, 188)); + --rc-color-dark: var(--callout-summary-color-dark, rgb(83, 223, 221)); +} + +[data-callout="tldr"] { + --rc-color-light: var(--callout-tldr-color-light, rgb(0, 191, 188)); + --rc-color-dark: var(--callout-tldr-color-dark, rgb(83, 223, 221)); +} + +[data-callout="info"] { + --rc-color-light: var(--callout-info-color-light, rgb(8, 109, 221)); + --rc-color-dark: var(--callout-info-color-dark, rgb(2, 122, 255)); +} + +[data-callout="todo"] { + --rc-color-light: var(--callout-todo-color-light, rgb(8, 109, 221)); + --rc-color-dark: var(--callout-todo-color-dark, rgb(2, 122, 255)); +} + +[data-callout="tip"] { + --rc-color-light: var(--callout-tip-color-light, rgb(0, 191, 188)); + --rc-color-dark: var(--callout-tip-color-dark, rgb(83, 223, 221)); +} + +[data-callout="hint"] { + --rc-color-light: var(--callout-hint-color-light, rgb(0, 191, 188)); + --rc-color-dark: var(--callout-hint-color-dark, rgb(83, 223, 221)); +} + +[data-callout="important"] { + --rc-color-light: var(--callout-important-color-light, rgb(0, 191, 188)); + --rc-color-dark: var(--callout-important-color-dark, rgb(83, 223, 221)); +} + +[data-callout="success"] { + --rc-color-light: var(--callout-success-color-light, rgb(8, 185, 78)); + --rc-color-dark: var(--callout-success-color-dark, rgb(68, 207, 110)); +} + +[data-callout="check"] { + --rc-color-light: var(--callout-check-color-light, rgb(8, 185, 78)); + --rc-color-dark: var(--callout-check-color-dark, rgb(68, 207, 110)); +} + +[data-callout="done"] { + --rc-color-light: var(--callout-done-color-light, rgb(8, 185, 78)); + --rc-color-dark: var(--callout-done-color-dark, rgb(68, 207, 110)); +} + +[data-callout="question"] { + --rc-color-light: var(--callout-question-color-light, rgb(236, 117, 0)); + --rc-color-dark: var(--callout-question-color-dark, rgb(233, 151, 63)); +} + +[data-callout="help"] { + --rc-color-light: var(--callout-help-color-light, rgb(236, 117, 0)); + --rc-color-dark: var(--callout-help-color-dark, rgb(233, 151, 63)); +} + +[data-callout="faq"] { + --rc-color-light: var(--callout-faq-color-light, rgb(236, 117, 0)); + --rc-color-dark: var(--callout-faq-color-dark, rgb(233, 151, 63)); +} + +[data-callout="warning"] { + --rc-color-light: var(--callout-warning-color-light, rgb(236, 117, 0)); + --rc-color-dark: var(--callout-warning-color-dark, rgb(233, 151, 63)); +} + +[data-callout="attention"] { + --rc-color-light: var(--callout-attention-color-light, rgb(236, 117, 0)); + --rc-color-dark: var(--callout-attention-color-dark, rgb(233, 151, 63)); +} + +[data-callout="caution"] { + --rc-color-light: var(--callout-caution-color-light, rgb(236, 117, 0)); + --rc-color-dark: var(--callout-caution-color-dark, rgb(233, 151, 63)); +} + +[data-callout="failure"] { + --rc-color-light: var(--callout-failure-color-light, rgb(233, 49, 71)); + --rc-color-dark: var(--callout-failure-color-dark, rgb(251, 70, 76)); +} + +[data-callout="missing"] { + --rc-color-light: var(--callout-missing-color-light, rgb(233, 49, 71)); + --rc-color-dark: var(--callout-missing-color-dark, rgb(251, 70, 76)); +} + +[data-callout="fail"] { + --rc-color-light: var(--callout-fail-color-light, rgb(233, 49, 71)); + --rc-color-dark: var(--callout-fail-color-dark, rgb(251, 70, 76)); +} + +[data-callout="danger"] { + --rc-color-light: var(--callout-danger-color-light, rgb(233, 49, 71)); + --rc-color-dark: var(--callout-danger-color-dark, rgb(251, 70, 76)); +} + +[data-callout="error"] { + --rc-color-light: var(--callout-error-color-light, rgb(233, 49, 71)); + --rc-color-dark: var(--callout-error-color-dark, rgb(251, 70, 76)); +} + +[data-callout="bug"] { + --rc-color-light: var(--callout-bug-color-light, rgb(233, 49, 71)); + --rc-color-dark: var(--callout-bug-color-dark, rgb(251, 70, 76)); +} + +[data-callout="example"] { + --rc-color-light: var(--callout-example-color-light, rgb(120, 82, 238)); + --rc-color-dark: var(--callout-example-color-dark, rgb(168, 130, 255)); +} + +[data-callout="quote"] { + --rc-color-light: var(--callout-quote-color-light, rgb(158, 158, 158)); + --rc-color-dark: var(--callout-quote-color-dark, rgb(158, 158, 158)); +} + +[data-callout="cite"] { + --rc-color-light: var(--callout-cite-color-light, rgb(158, 158, 158)); + --rc-color-dark: var(--callout-cite-color-dark, rgb(158, 158, 158)); +} + +.callout { + --rc-color-default: #888; + + overflow: hidden; + + width: 100%; + padding: 12px 12px 12px 24px; + border-radius: 4px; + margin: 1em 0; + + line-height: 1.3; + + mix-blend-mode: darken; + background-color: rgb( + from var(--rc-color-light, var(--rc-color-default)) r g b / + 0.1 + ); +} + +.dark .callout { + mix-blend-mode: lighten; + background-color: rgb( + from var(--rc-color-dark, var(--rc-color-default)) r g b / + 0.1 + ); +} + +.callout-title { + display: flex; + align-items: flex-start; + gap: 4px; + + color: var(--rc-color-light, var(--rc-color-default)); + font-size: inherit; +} + +.dark .callout-title { + color: var(--rc-color-dark, var(--rc-color-default)); +} + +.callout-title::-webkit-details-marker { + display: none; +} + +.callout-title-icon { + display: flex; + flex: 0 0 auto; + align-items: center; +} + +.callout-title-text { + color: inherit; + font-weight: 600; +} + +.callout-content { + overflow-x: auto; + padding: 0; + background-color: transparent; +} + +.callout[data-collapsible="true"] .callout-title { + cursor: pointer; +} + +.callout[data-collapsible="true"] .callout-fold-icon { + display: flex; + align-items: center; + padding-inline-end: 8px; +} + +.callout[data-collapsible="true"] > .callout-title .callout-fold-icon svg { + transform: rotate(-90deg); + transition: transform 100ms ease-in-out; +} + +.callout[data-collapsible="true"][open] + > .callout-title + .callout-fold-icon + svg { + transform: none; +} + +.callout-title-icon::after, +.callout-fold-icon::after { + content: "\200B"; +} + +.callout-title-icon svg, +.callout-fold-icon svg { + width: 18px; + height: 18px; +} + +@media (prefers-color-scheme: dark) { + .callout { + mix-blend-mode: lighten; + background-color: rgb( + from var(--rc-color-dark, var(--rc-color-default)) r g b / + 0.1 + ); + } + + .callout-title { + color: var(--rc-color-dark, var(--rc-color-default)); + } +} diff --git a/src/markdown.ts b/src/markdown.ts index 1fdbe98..e03dd76 100644 --- a/src/markdown.ts +++ b/src/markdown.ts @@ -5,6 +5,7 @@ import remarkParse from "remark-parse"; import remarkRehype from "remark-rehype"; import rehypeSlug from "rehype-slug"; import { unified } from "unified"; +import rehypeCallouts from "rehype-callouts"; export async function parseMarkdown(markdown: string): Promise { const file = await unified() @@ -13,6 +14,7 @@ export async function parseMarkdown(markdown: string): Promise { .use(remarkRehype, { allowDangerousHtml: true }) .use(rehypeRaw) .use(rehypeSlug) + .use(rehypeCallouts) .use(rehypeStringify) .process(markdown);