diff --git a/packages/gem-book/src/element/elements/main.ts b/packages/gem-book/src/element/elements/main.ts index 830d5fee..104e8bd8 100644 --- a/packages/gem-book/src/element/elements/main.ts +++ b/packages/gem-book/src/element/elements/main.ts @@ -69,8 +69,27 @@ export class Main extends GemElement { // homepage/footer 等内置元素渲染在 main 前面,不能使用自定义渲染器 static instance?: Main; + static detailsStateCache = new Map(); + static parseMarkdown(mdBody: string) { - return [...parser.parseFromString(parse(mdBody, { renderer: Main.instance?.renderer }), 'text/html').body.children]; + const elements = [ + ...parser.parseFromString( + parse(mdBody, { + renderer: Main.instance?.renderer, + }), + 'text/html', + ).body.children, + ]; + elements.forEach((detailsEle) => { + if (detailsEle instanceof HTMLDetailsElement) { + const html = locationStore.path + detailsEle.innerHTML; + detailsEle.open = !!Main.detailsStateCache.get(html); + detailsEle.addEventListener('toggle', () => { + Main.detailsStateCache.set(html, detailsEle.open); + }); + } + }); + return elements; } static unsafeRenderHTML(s: string, style = '') { diff --git a/packages/gem-book/src/element/elements/plugin.ts b/packages/gem-book/src/element/elements/plugin.ts index 1e965928..29ee40d5 100644 --- a/packages/gem-book/src/element/elements/plugin.ts +++ b/packages/gem-book/src/element/elements/plugin.ts @@ -57,16 +57,17 @@ export class GemBookPluginElement extends GemElement { return bookStore.getCurrentLink?.(); } - static caches?: Map; + static caches = new Map>(); cacheState(getDeps: () => string[]) { if (!this.state) throw new Error('Only cache state'); const cons = this.constructor as typeof GemBookPluginElement; - const caches = cons.caches || (cons.caches = new Map()); + const cache = cons.caches.get(cons) || new Map(); + cons.caches.set(cons, cache); this.memo( () => { - Object.assign(this.state!, caches.get(getDeps().join())); - return () => caches.set(getDeps().join(), this.state); + Object.assign(this.state!, cache.get(getDeps().join())); + return () => cache.set(getDeps().join(), this.state); }, () => getDeps(), ); diff --git a/packages/gem-book/src/element/elements/pre.ts b/packages/gem-book/src/element/elements/pre.ts index caa55478..b378154f 100644 --- a/packages/gem-book/src/element/elements/pre.ts +++ b/packages/gem-book/src/element/elements/pre.ts @@ -349,45 +349,57 @@ export class Pre extends GemElement { } }; - mounted() { - this.effect(async () => { - if (!this.getBoundingClientRect().width) return; - if (this.status === 'hidden') return; - if (!this.codeRef.element) return; - await import(/* @vite-ignore */ /* webpackIgnore: true */ prismjs); - const { Prism } = window as any; - if (this.codelang && !Prism.languages[this.codelang]) { - const lang = langAliases[this.codelang] || this.codelang; - const langDeps = ([] as string[]).concat(langDependencies[lang] || []); - try { - await Promise.all( - langDeps.map((langDep) => { - if (!Prism.languages[langDep]) { - return import( - /* @vite-ignore */ /* webpackIgnore: true */ `${prismjs}/components/prism-${langDep}.min.js` - ); - } - }), - ); - await import(/* @vite-ignore */ /* webpackIgnore: true */ `${prismjs}/components/prism-${lang}.min.js`); - } catch { - // - } + #updateHtml = async () => { + if (this.status === 'hidden') return; + if (!this.codeRef.element) return; + await import(/* @vite-ignore */ /* webpackIgnore: true */ prismjs); + const { Prism } = window as any; + if (this.codelang && !Prism.languages[this.codelang]) { + const lang = langAliases[this.codelang] || this.codelang; + const langDeps = ([] as string[]).concat(langDependencies[lang] || []); + try { + await Promise.all( + langDeps.map((langDep) => { + if (!Prism.languages[langDep]) { + return import( + /* @vite-ignore */ /* webpackIgnore: true */ `${prismjs}/components/prism-${langDep}.min.js` + ); + } + }), + ); + await import(/* @vite-ignore */ /* webpackIgnore: true */ `${prismjs}/components/prism-${lang}.min.js`); + } catch { + // } - const content = Prism.languages[this.codelang] - ? Prism.highlight(this.textContent || '', Prism.languages[this.codelang], this.codelang) - : this.innerHTML; - const { parts, lineNumbersParts } = this.#getParts(content); - this.codeRef.element.innerHTML = parts.reduce( - (p, c, i) => - p + - ` @@ ${lineNumbersParts[i - 1].at(-1)! + 1}-${ - lineNumbersParts[i].at(0)! - 1 - } @@` + - c, - ); - this.#setOffset(); + } + const content = Prism.languages[this.codelang] + ? Prism.highlight(this.textContent || '', Prism.languages[this.codelang], this.codelang) + : this.innerHTML; + const { parts, lineNumbersParts } = this.#getParts(content); + this.codeRef.element.innerHTML = parts.reduce( + (p, c, i) => + p + + ` @@ ${lineNumbersParts[i - 1].at(-1)! + 1}-${ + lineNumbersParts[i].at(0)! - 1 + } @@` + + c, + ); + this.#setOffset(); + }; + + mounted() { + const io = new IntersectionObserver((entries) => { + entries.forEach(({ intersectionRatio }) => { + if (intersectionRatio === 0) return; + io.disconnect(); + this.effect( + () => this.#updateHtml(), + () => [this.textContent, this.codelang], + ); + }); }); + io.observe(this); + return () => io.disconnect(); } render() {