Jacky Zhao
2025-03-09 1cd8e7f0d510b97dfc2c3314c36d957383162a8f
feat: support non-singleton table of contents
4 files modified
30 ■■■■ changed files
quartz/components/TableOfContents.tsx 7 ●●●●● patch | view | raw | blame | history
quartz/components/scripts/toc.inline.ts 13 ●●●● patch | view | raw | blame | history
quartz/components/styles/legacyToc.scss 2 ●●● patch | view | raw | blame | history
quartz/components/styles/toc.scss 8 ●●●● patch | view | raw | blame | history
quartz/components/TableOfContents.tsx
@@ -29,8 +29,7 @@
    <div class={classNames(displayClass, "toc")}>
      <button
        type="button"
        id="toc"
        class={fileData.collapseToc ? "collapsed" : ""}
        class={fileData.collapseToc ? "collapsed toc-header" : "toc-header"}
        aria-controls="toc-content"
        aria-expanded={!fileData.collapseToc}
      >
@@ -50,7 +49,7 @@
          <polyline points="6 9 12 15 18 9"></polyline>
        </svg>
      </button>
      <div id="toc-content" class={fileData.collapseToc ? "collapsed" : ""}>
      <div class={fileData.collapseToc ? "collapsed toc-content" : "toc-content"}>
        <OverflowList id="toc-ul">
          {fileData.toc.map((tocEntry) => (
            <li key={tocEntry.slug} class={`depth-${tocEntry.depth}`}>
@@ -72,7 +71,7 @@
    return null
  }
  return (
    <details id="toc" open={!fileData.collapseToc}>
    <details class="toc" open={!fileData.collapseToc}>
      <summary>
        <h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
      </summary>
quartz/components/scripts/toc.inline.ts
@@ -25,16 +25,15 @@
}
function setupToc() {
  const toc = document.getElementById("toc")
  if (toc) {
    const content = toc.nextElementSibling as HTMLElement | undefined
    if (!content) return
    toc.addEventListener("click", toggleToc)
    window.addCleanup(() => toc.removeEventListener("click", toggleToc))
  for (const toc of document.querySelectorAll(".toc")) {
    const button = toc.querySelector(".toc-header")
    const content = toc.querySelector(".toc-content")
    if (!button || !content) return
    button.addEventListener("click", toggleToc)
    window.addCleanup(() => button.removeEventListener("click", toggleToc))
  }
}
window.addEventListener("resize", setupToc)
document.addEventListener("nav", () => {
  setupToc()
quartz/components/styles/legacyToc.scss
@@ -1,4 +1,4 @@
details#toc {
details.toc {
  & summary {
    cursor: pointer;
quartz/components/styles/toc.scss
@@ -6,18 +6,18 @@
  overflow-y: hidden;
  flex: 0 1 auto;
  &:has(button#toc.collapsed) {
  &:has(button.toc-header.collapsed) {
    flex: 0 1 1.2rem;
  }
}
@media all and not ($mobile) {
  .toc {
  .toc-header {
    display: flex;
  }
}
button#toc {
button.toc-header {
  background-color: transparent;
  border: none;
  text-align: left;
@@ -44,7 +44,7 @@
  }
}
#toc-content {
.toc-content {
  list-style: none;
  position: relative;