Skip to content

Support for multiple giscus elements on one page (mobile/desktop) #2061

@ViscousPot

Description

@ViscousPot

Is your feature request related to a problem? Please describe.
I wanted to have two giscus elements so I can have one position for mobile and one for desktop. To be clear I don't need or want multiple giscus elements on a page at once, just for mobile and desktop.

Describe the solution you'd like
It looks like the giscus script itself applies itself to any div's with class giscus, eventhough the code in quartz only applies to a the first div. I imagine this could be easily solved by removing the class giscus from any non-visible div's.

Describe alternatives you've considered
I have come up with a basic fix for comments.inline.ts but I doubt it's robust

const changeTheme = (e: CustomEventMap["themechange"]) => {
  const theme = e.detail.theme
  const iframe = document.querySelector("iframe.giscus-frame") as HTMLIFrameElement
  if (!iframe) {
    return
  }

  if (!iframe.contentWindow) {
    return
  }

  iframe.contentWindow.postMessage(
    {
      giscus: {
        setConfig: {
          theme: getThemeUrl(getThemeName(theme)),
        },
      },
    },
    "https://giscus.app",
  )
}

const getThemeName = (theme: string) => {
  if (theme !== "dark" && theme !== "light") {
    return theme
  }
  const giscusContainer = document.querySelector(".giscus") as GiscusElement
  if (!giscusContainer) {
    return theme
  }
  const darkGiscus = giscusContainer.dataset.darkTheme ?? "dark"
  const lightGiscus = giscusContainer.dataset.lightTheme ?? "light"
  return theme === "dark" ? darkGiscus : lightGiscus
}

const getThemeUrl = (theme: string) => {
  const giscusContainer = document.querySelector(".giscus") as GiscusElement
  if (!giscusContainer) {
    return `https://giscus.app/themes/${theme}.css`
  }
  return `${giscusContainer.dataset.themeUrl ?? "https://giscus.app/themes"}/${theme}.css`
}

type GiscusElement = Omit<HTMLElement, "dataset"> & {
  dataset: DOMStringMap & {
    repo: `${string}/${string}`
    repoId: string
    category: string
    categoryId: string
    themeUrl: string
    lightTheme: string
    darkTheme: string
    mapping: "url" | "title" | "og:title" | "specific" | "number" | "pathname"
    strict: string
    reactionsEnabled: string
    inputPosition: "top" | "bottom"
    lang: string
  }
}

document.addEventListener("nav", () => {
  const giscusContainers = Array.from(document.querySelectorAll(".giscus")) as GiscusElement[]

  for (const giscusContainer of giscusContainers) {
    if (getComputedStyle(giscusContainer).display === "none") {
      giscusContainer.classList.remove('giscus')
      continue;
    }

    const giscusScript = document.createElement("script")
    giscusScript.src = "https://giscus.app/client.js"
    giscusScript.async = true
    giscusScript.crossOrigin = "anonymous"
    giscusScript.setAttribute("data-loading", "lazy")
    giscusScript.setAttribute("data-emit-metadata", "0")
    giscusScript.setAttribute("data-repo", giscusContainer.dataset.repo)
    giscusScript.setAttribute("data-repo-id", giscusContainer.dataset.repoId)
    giscusScript.setAttribute("data-category", giscusContainer.dataset.category)
    giscusScript.setAttribute("data-category-id", giscusContainer.dataset.categoryId)
    giscusScript.setAttribute("data-mapping", giscusContainer.dataset.mapping)
    giscusScript.setAttribute("data-strict", giscusContainer.dataset.strict)
    giscusScript.setAttribute("data-reactions-enabled", giscusContainer.dataset.reactionsEnabled)
    giscusScript.setAttribute("data-input-position", giscusContainer.dataset.inputPosition)
    giscusScript.setAttribute("data-lang", giscusContainer.dataset.lang)

    const theme = document.documentElement.getAttribute("saved-theme")
    if (theme) {
      giscusScript.setAttribute("data-theme", getThemeUrl(getThemeName(theme)))
    }

    giscusContainer.appendChild(giscusScript)
  }

  document.addEventListener("themechange", changeTheme)
  window.addCleanup(() => document.removeEventListener("themechange", changeTheme))
})

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions