From ccadada9ce9ea48ce967426b3c234cd30677a03e Mon Sep 17 00:00:00 2001 From: liyunze <50455574+liyunze-coding@users.noreply.github.com> Date: Thu, 3 Sep 2026 09:06:44 +0800 Subject: [PATCH] added LaTeX support --- package-lock.json | 37 +++++++++- package.json | 2 + src/lib/components/MarkdownEditor.svelte | 33 ++++++++- src/lib/markdown.spec.ts | 17 ++++- src/lib/markdown.ts | 12 ++- src/lib/server/api.ts | 34 +++------ src/markdown-it-texmath.d.ts | 22 ++++++ src/routes/layout.css | 2 + src/routes/post/note/+page.svelte | 94 ++++++++++++------------ src/routes/post/question/+page.svelte | 90 ++++++++++++----------- 10 files changed, 225 insertions(+), 118 deletions(-) create mode 100644 src/markdown-it-texmath.d.ts diff --git a/package-lock.json b/package-lock.json index 1e8c4b7..9d6e9fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,16 @@ { "name": "dsec-notebook", - "version": "0.0.1", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dsec-notebook", - "version": "0.0.1", + "version": "1.0.0", "dependencies": { + "katex": "^0.18.5", "markdown-it": "^15.0.1", + "markdown-it-texmath": "^1.0.0", "resend": "^6.25.0" }, "devDependencies": { @@ -6455,6 +6457,31 @@ "node": ">=0.10.0" } }, + "node_modules/katex": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.18.5.tgz", + "integrity": "sha512-1FU5H3RjGJVj6GT9fMjf2uMIXmPQp232aXS3UEeQzf0dxefHg/CKMvNB3DuOC46LFG/E5PNxrE8dOwB782FDGg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^15.0.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -6823,6 +6850,12 @@ "markdown-it": "bin/markdown-it.mjs" } }, + "node_modules/markdown-it-texmath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-texmath/-/markdown-it-texmath-1.0.0.tgz", + "integrity": "sha512-4hhkiX8/gus+6e53PLCUmUrsa6ZWGgJW2XCW6O0ASvZUiezIK900ZicinTDtG3kAO2kon7oUA/ReWmpW2FByxg==", + "license": "MIT" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", diff --git a/package.json b/package.json index a397aad..add4e04 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,9 @@ "lint:fix": "oxlint --fix" }, "dependencies": { + "katex": "^0.18.5", "markdown-it": "^15.0.1", + "markdown-it-texmath": "^1.0.0", "resend": "^6.25.0" }, "devDependencies": { diff --git a/src/lib/components/MarkdownEditor.svelte b/src/lib/components/MarkdownEditor.svelte index 66564ad..43b2d33 100644 --- a/src/lib/components/MarkdownEditor.svelte +++ b/src/lib/components/MarkdownEditor.svelte @@ -108,6 +108,20 @@ }); } + function insertMathBlock() { + const { start, end, text } = selection(); + const formula = text || "x^2 + y^2 = z^2"; + applyEdit((value) => { + const insertion = `$$\n${formula}\n$$`; + const next = value.slice(0, start) + insertion + value.slice(end); + return { + value: next, + start: start + 3, + end: start + 3 + formula.length, + }; + }); + } + function insertText(text: string) { applyEdit((value, start, end) => { const next = value.slice(0, start) + text + value.slice(end); @@ -210,6 +224,22 @@ + + +
+ + {#if !useCustomUnit} + + {/if} - {#if useCustomUnit} - - {/if} + + + {#if useCustomUnit} + + {/if} +
diff --git a/src/routes/post/question/+page.svelte b/src/routes/post/question/+page.svelte index f64a6b7..16cb831 100644 --- a/src/routes/post/question/+page.svelte +++ b/src/routes/post/question/+page.svelte @@ -38,8 +38,9 @@ error = "Title and content are required"; return; } - if (!selectedTopicId) { - error = "Please select a topic"; + const hasUnit = useCustomUnit ? !!customUnit.trim() : !!selectedUnitId; + if (!selectedTopicId && !hasUnit) { + error = "Please select a topic or a unit"; return; } @@ -51,7 +52,7 @@ loading = true; try { - let unitId = selectedUnitId; + let unitId = useCustomUnit ? "" : selectedUnitId; let unitCode = units.find((unit) => unit._id === unitId)?.code ?? ""; if (useCustomUnit && customUnit.trim()) { unitCode = customUnit.trim().toUpperCase(); @@ -77,7 +78,7 @@ unitId, })) as string; - goto(postPath(unitCode, id)); + goto(unitCode ? postPath(unitCode, id) : `/questions/${id}`); } catch (err: any) { error = err.message ?? "Failed to post question"; } finally { @@ -118,49 +119,52 @@ /> -
-
- - -
- -
- - {#if !useCustomUnit} - + + {#each topics as topic} + {/each} - {/if} +
- +
+ + {#if !useCustomUnit} + + {/if} - {#if useCustomUnit} - - {/if} + + + {#if useCustomUnit} + + {/if} +