feat(Giscus): persist discussions via commentId

- require frontmatter commentId when giscus uses mapping "specific" so each page keeps its discussion
- clear prior giscus embeds on SPA navigation before reinjecting and skip when term is missing
- keep layout.ts wrapping Comments with a commentId guard
This commit is contained in:
2kwonhee 2025-09-18 00:54:58 +09:00
parent 7bcab60f3e
commit 545d65e7da
2 changed files with 24 additions and 1 deletions

View File

@ -35,6 +35,15 @@ export default ((opts: Options) => {
return <></> return <></>
} }
const mapping = opts.options.mapping ?? "url"
const commentId = fileData.frontmatter?.commentId as string | undefined
if (mapping === "specific" && !commentId) {
const identifier = fileData.filePath ?? fileData.slug ?? "unknown"
console.warn(`[Quartz] Missing commentId for page ${identifier}, skipping giscus mounting.`)
return <></>
}
return ( return (
<div <div
class={classNames(displayClass, "giscus")} class={classNames(displayClass, "giscus")}
@ -42,7 +51,8 @@ export default ((opts: Options) => {
data-repo-id={opts.options.repoId} data-repo-id={opts.options.repoId}
data-category={opts.options.category} data-category={opts.options.category}
data-category-id={opts.options.categoryId} data-category-id={opts.options.categoryId}
data-mapping={opts.options.mapping ?? "url"} data-mapping={mapping}
data-term={mapping === "specific" ? commentId : undefined}
data-strict={boolToStringBool(opts.options.strict ?? true)} data-strict={boolToStringBool(opts.options.strict ?? true)}
data-reactions-enabled={boolToStringBool(opts.options.reactionsEnabled ?? true)} data-reactions-enabled={boolToStringBool(opts.options.reactionsEnabled ?? true)}
data-input-position={opts.options.inputPosition ?? "bottom"} data-input-position={opts.options.inputPosition ?? "bottom"}

View File

@ -56,6 +56,7 @@ type GiscusElement = Omit<HTMLElement, "dataset"> & {
reactionsEnabled: string reactionsEnabled: string
inputPosition: "top" | "bottom" inputPosition: "top" | "bottom"
lang: string lang: string
term?: string
} }
} }
@ -65,6 +66,15 @@ document.addEventListener("nav", () => {
return return
} }
giscusContainer
.querySelectorAll("iframe.giscus-frame, script[src*='giscus.app']")
.forEach((node) => node.remove())
if (giscusContainer.dataset.mapping === "specific" && !giscusContainer.dataset.term) {
console.warn("[Giscus] mapping='specific' but data-term is missing; skipping widget injection.")
return
}
const giscusScript = document.createElement("script") const giscusScript = document.createElement("script")
giscusScript.src = "https://giscus.app/client.js" giscusScript.src = "https://giscus.app/client.js"
giscusScript.async = true giscusScript.async = true
@ -76,6 +86,9 @@ document.addEventListener("nav", () => {
giscusScript.setAttribute("data-category", giscusContainer.dataset.category) giscusScript.setAttribute("data-category", giscusContainer.dataset.category)
giscusScript.setAttribute("data-category-id", giscusContainer.dataset.categoryId) giscusScript.setAttribute("data-category-id", giscusContainer.dataset.categoryId)
giscusScript.setAttribute("data-mapping", giscusContainer.dataset.mapping) giscusScript.setAttribute("data-mapping", giscusContainer.dataset.mapping)
if (giscusContainer.dataset.term) {
giscusScript.setAttribute("data-term", giscusContainer.dataset.term)
}
giscusScript.setAttribute("data-strict", giscusContainer.dataset.strict) giscusScript.setAttribute("data-strict", giscusContainer.dataset.strict)
giscusScript.setAttribute("data-reactions-enabled", giscusContainer.dataset.reactionsEnabled) giscusScript.setAttribute("data-reactions-enabled", giscusContainer.dataset.reactionsEnabled)
giscusScript.setAttribute("data-input-position", giscusContainer.dataset.inputPosition) giscusScript.setAttribute("data-input-position", giscusContainer.dataset.inputPosition)