mirror of
https://github.com/HananoshikaYomaru/openfreebooks.git
synced 2026-11-13 13:05:51 +00:00
Enhance math curriculum content and improve rendering: Update contributing guidelines for math widget integration and clarify KaTeX usage. Add interactive demo technology choices to SKILL.md for better guidance on chapter interactions. Introduce new visual elements in coordinate geometry chapters, including an empty Cartesian plane SVG and detailed proofs for distance, midpoint, and slope formulas. Revise Pythagorean theorem content to include geometric proofs and applications, enhancing clarity and educational value.
This commit is contained in:
parent
f74867fe4c
commit
2ca490ff81
17 changed files with 1571 additions and 201 deletions
|
|
@ -6,6 +6,14 @@ export type RenderLatexOptions = {
|
|||
displayMode?: boolean;
|
||||
};
|
||||
|
||||
export type RenderMathInContainerOptions = {
|
||||
force?: boolean;
|
||||
};
|
||||
|
||||
export type RenderBookMathOptions = {
|
||||
force?: boolean;
|
||||
};
|
||||
|
||||
const DELIMITERS = [
|
||||
{ left: "$$", right: "$$", display: true },
|
||||
{ left: "\\(", right: "\\)", display: false },
|
||||
|
|
@ -20,7 +28,7 @@ const AUTO_RENDER_OPTIONS = {
|
|||
|
||||
/** Prose and question blocks that may contain \\( … \\) or \\[ … \\] delimiters. */
|
||||
const AUTO_RENDER_TARGETS =
|
||||
".book-prose, .book-callout, .book-formula, .book-question__prompt, .book-question__solution, .math-widget__caption";
|
||||
".book-prose, .book-callout, .book-formula, .book-question__prompt, .book-question__solution, .math-widget";
|
||||
|
||||
/**
|
||||
* Render a LaTeX string to HTML for use with Solid `innerHTML` (widgets, dynamic labels).
|
||||
|
|
@ -36,16 +44,26 @@ export function renderLatex(latex: string, options: RenderLatexOptions = {}) {
|
|||
/**
|
||||
* Auto-render delimiter-based math inside a single element (idempotent per element).
|
||||
*/
|
||||
export function renderMathInContainer(el: HTMLElement) {
|
||||
if (el.dataset.katexRendered === "true") return;
|
||||
export function renderMathInContainer(
|
||||
el: HTMLElement,
|
||||
options: RenderMathInContainerOptions = {}
|
||||
) {
|
||||
if (options.force) {
|
||||
delete el.dataset.katexRendered;
|
||||
} else if (el.dataset.katexRendered === "true") {
|
||||
return;
|
||||
}
|
||||
renderMathInElement(el, AUTO_RENDER_OPTIONS);
|
||||
el.dataset.katexRendered = "true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan chapter / book content for math delimiters. Skips `.math-widget` trees (widgets use renderLatex).
|
||||
* Scan chapter / book content for math delimiters in prose and widget trees.
|
||||
*/
|
||||
export function renderBookMath(root: ParentNode = document) {
|
||||
export function renderBookMath(
|
||||
root: ParentNode = document,
|
||||
options: RenderBookMathOptions = {}
|
||||
) {
|
||||
const article =
|
||||
root instanceof Document
|
||||
? root.querySelector<HTMLElement>("[data-pagefind-body]")
|
||||
|
|
@ -56,7 +74,64 @@ export function renderBookMath(root: ParentNode = document) {
|
|||
const scope: ParentNode = article ?? root;
|
||||
|
||||
scope.querySelectorAll<HTMLElement>(AUTO_RENDER_TARGETS).forEach((el) => {
|
||||
if (el.closest(".math-widget")) return;
|
||||
renderMathInContainer(el);
|
||||
renderMathInContainer(el, { force: options.force });
|
||||
});
|
||||
}
|
||||
|
||||
function nodeInsideKatex(node: Node) {
|
||||
const element =
|
||||
node instanceof Element ? node : node.parentElement;
|
||||
return Boolean(element?.closest(".katex"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Observe dynamic DOM updates (including Solid widget updates) and auto-render math delimiters.
|
||||
* Returns a disposer function.
|
||||
*/
|
||||
export function observeMathAutoRender(root: ParentNode = document) {
|
||||
const observedNode =
|
||||
root instanceof Document
|
||||
? root.documentElement
|
||||
: root instanceof HTMLElement
|
||||
? root
|
||||
: null;
|
||||
|
||||
if (!observedNode) {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
let scheduled = false;
|
||||
let rendering = false;
|
||||
|
||||
const scheduleRender = () => {
|
||||
if (scheduled) return;
|
||||
scheduled = true;
|
||||
requestAnimationFrame(() => {
|
||||
scheduled = false;
|
||||
rendering = true;
|
||||
renderBookMath(root, { force: true });
|
||||
rendering = false;
|
||||
});
|
||||
};
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
if (rendering) return;
|
||||
const hasExternalChange = mutations.some((mutation) => {
|
||||
if (nodeInsideKatex(mutation.target)) return false;
|
||||
if (mutation.type === "characterData") return true;
|
||||
if (mutation.addedNodes.length === 0 && mutation.removedNodes.length === 0) return false;
|
||||
const addedInsideKatex = Array.from(mutation.addedNodes).every(nodeInsideKatex);
|
||||
const removedInsideKatex = Array.from(mutation.removedNodes).every(nodeInsideKatex);
|
||||
return !(addedInsideKatex && removedInsideKatex);
|
||||
});
|
||||
if (hasExternalChange) scheduleRender();
|
||||
});
|
||||
|
||||
observer.observe(observedNode, {
|
||||
subtree: true,
|
||||
childList: true,
|
||||
characterData: true,
|
||||
});
|
||||
|
||||
return () => observer.disconnect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,12 @@
|
|||
/** @deprecated Import from `./katex` instead. Kept for existing paths. */
|
||||
export { renderBookMath, renderLatex, renderMathInContainer } from "./katex";
|
||||
export type { RenderLatexOptions } from "./katex";
|
||||
export {
|
||||
observeMathAutoRender,
|
||||
renderBookMath,
|
||||
renderLatex,
|
||||
renderMathInContainer,
|
||||
} from "./katex";
|
||||
export type {
|
||||
RenderBookMathOptions,
|
||||
RenderLatexOptions,
|
||||
RenderMathInContainerOptions,
|
||||
} from "./katex";
|
||||
|
|
|
|||
|
|
@ -61,9 +61,16 @@ function localizeChapterLastModified() {
|
|||
}
|
||||
}
|
||||
|
||||
let stopMathObserver: (() => void) | null = null;
|
||||
|
||||
function scheduleBookMath() {
|
||||
void import("./lib/katex").then(({ renderBookMath }) => {
|
||||
requestAnimationFrame(() => renderBookMath());
|
||||
void import("./lib/katex").then(({ observeMathAutoRender, renderBookMath }) => {
|
||||
requestAnimationFrame(() => {
|
||||
renderBookMath(document, { force: true });
|
||||
if (!stopMathObserver) {
|
||||
stopMathObserver = observeMathAutoRender(document);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue