diff --git a/bun.lock b/bun.lock index 9b74091..7b617a7 100644 --- a/bun.lock +++ b/bun.lock @@ -25,25 +25,26 @@ "diff-match-patch": "^1.0.5", "dompurify": "^3.4.5", "elysia": "^1.4.28", - "fflate": "^0.8.2", - "katex": "^0.16.45", + "fflate": "^0.8.3", + "katex": "^0.16.47", "markdown-it": "^14.1.1", + "markdown-it-mark": "^4.0.0", "sanitize-html": "^2.17.4", "sharp": "^0.34.5", }, "devDependencies": { - "@biomejs/biome": "^2.4.14", - "@tailwindcss/cli": "^4.2.4", + "@biomejs/biome": "^2.4.15", + "@tailwindcss/cli": "^4.3.0", "@tailwindcss/typography": "^0.5.19", - "@types/bun": "^1.3.13", + "@types/bun": "^1.3.14", "@types/d3": "^7.4.3", "@types/diff-match-patch": "^1.0.36", "@types/markdown-it": "^14.1.2", "@types/sanitize-html": "^2.16.1", - "@typescript/native-preview": "^7.0.0-dev.20260507.1", + "@typescript/native-preview": "^7.0.0-dev.20260521.1", "htmx.org": "^2.0.10", - "knip": "^6.12.1", - "tailwindcss": "^4.2.4", + "knip": "^6.14.1", + "tailwindcss": "^4.3.0", }, }, }, @@ -586,6 +587,8 @@ "markdown-it": ["markdown-it@14.1.1", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA=="], + "markdown-it-mark": ["markdown-it-mark@4.0.0", "", {}, "sha512-YLhzaOsU9THO/cal0lUjfMjrqSMPjjyjChYM7oyj4DnyaXEzA8gnW6cVJeyCrCVeyesrY2PlEdUYJSPFYL4Nkg=="], + "mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], "memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="], diff --git a/package.json b/package.json index f0d2a99..f874101 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "fflate": "^0.8.3", "katex": "^0.16.47", "markdown-it": "^14.1.1", + "markdown-it-mark": "^4.0.0", "sanitize-html": "^2.17.4", "sharp": "^0.34.5" }, diff --git a/public/editor/preview.ts b/public/editor/preview.ts index 3c9d8d1..70476e5 100644 --- a/public/editor/preview.ts +++ b/public/editor/preview.ts @@ -1,10 +1,12 @@ import DOMPurify from "dompurify"; import MarkdownIt from "markdown-it"; +import markPlugin from "markdown-it-mark"; import { katexPlugin } from "../../src/lib/markdown/katex-plugin.ts"; import { wikilinkPlugin } from "../../src/lib/markdown/wikilink-plugin.ts"; const md = new MarkdownIt({ html: false, linkify: true }); md.use(wikilinkPlugin); +md.use(markPlugin); md.use(katexPlugin, { throwOnError: false }); // Matches the server-side allowlist closely. The preview is for the author's diff --git a/public/style.css b/public/style.css index 1f58f4a..8e7a056 100644 --- a/public/style.css +++ b/public/style.css @@ -6,3 +6,11 @@ .katex { line-height: 1.2; } + +/* ==highlight== markup */ +mark { + background-color: var(--accent-soft); + color: inherit; + padding: 0.1em 0.2em; + border-radius: 2px; +} diff --git a/public/tsconfig.json b/public/tsconfig.json index c0e494a..3db5b7b 100644 --- a/public/tsconfig.json +++ b/public/tsconfig.json @@ -3,6 +3,6 @@ "compilerOptions": { "lib": ["ESNext", "DOM", "DOM.Iterable"] }, - "include": ["./**/*.ts"], + "include": ["./**/*.ts", "../src/types.d.ts"], "exclude": [] } diff --git a/src/lib/markdown.ts b/src/lib/markdown.ts index 594bfdb..5644b7a 100644 --- a/src/lib/markdown.ts +++ b/src/lib/markdown.ts @@ -1,4 +1,5 @@ import MarkdownIt from "markdown-it"; +import markPlugin from "markdown-it-mark"; import { headingAnchorPlugin } from "./markdown/heading-anchor-plugin.ts"; import { type KatexPluginEnv, katexPlugin } from "./markdown/katex-plugin.ts"; import { sanitizeMarkdownHtml } from "./markdown/sanitize.ts"; @@ -59,6 +60,7 @@ function youtubePlugin(mdi: MarkdownIt): void { md.use(wikilinkPlugin); md.use(headingAnchorPlugin); +md.use(markPlugin); md.use(vizPlugin); md.use(katexPlugin, { throwOnError: false }); md.use(youtubePlugin); diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 0000000..f04e0d7 --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,6 @@ +declare module "markdown-it-mark" { + import type MarkdownIt from "markdown-it"; + + const plugin: MarkdownIt.PluginSimple; + export default plugin; +} diff --git a/tests/lib/markdown.test.ts b/tests/lib/markdown.test.ts index f5a013b..cd538b3 100644 --- a/tests/lib/markdown.test.ts +++ b/tests/lib/markdown.test.ts @@ -204,6 +204,29 @@ describe("wikilinks", () => { }); }); +describe("strikethrough", () => { + test("renders strikethrough", () => { + const { html } = renderMarkdown("~~deleted~~"); + expect(html).toContain(""); + expect(html).toContain("deleted"); + }); +}); + +describe("highlights", () => { + test("renders highlight markup", () => { + const { html } = renderMarkdown("This is ==highlighted== text."); + expect(html).toContain(""); + expect(html).toContain("highlighted"); + }); + + test("highlight does not collide with other inline", () => { + const { html } = renderMarkdown("**bold** and ==highlight== and `code`"); + expect(html).toContain(""); + expect(html).toContain(""); + expect(html).toContain(""); + }); +}); + describe("heading anchors", () => { test("attaches id to rendered headings", () => { const { html } = renderMarkdown("# Hello World\n\n## Another One");