1 gal Rosemary
2025-04-05 bb24cd13c7fafbd42d3980c45351a58a76dabb18
fix(css): styles issues with popover, overflow, and scroll overflow (#1907)

* fix(style): fix toc overflow & scrolling overflow

* fix(style): fix explorer scrolling overflow

* fix(style): fix backlinks overflow & scrolling overflow

* fix(style): resolve popover overflow issue causing incomplete display

* chore: rename function to enhance readability

* fix(popover): make the backlink's id unique & use translate() instead of translateY()
5 files modified
49 ■■■■ changed files
quartz/components/scripts/popover.inline.ts 36 ●●●● patch | view | raw | blame | history
quartz/components/styles/backlinks.scss 2 ●●●●● patch | view | raw | blame | history
quartz/components/styles/explorer.scss 1 ●●●● patch | view | raw | blame | history
quartz/components/styles/popover.scss 8 ●●●● patch | view | raw | blame | history
quartz/components/styles/toc.scss 2 ●●●●● patch | view | raw | blame | history
quartz/components/scripts/popover.inline.ts
@@ -1,33 +1,40 @@
import { computePosition, flip, inline, shift } from "@floating-ui/dom"
import { normalizeRelativeURLs } from "../../util/path"
import { fetchCanonical } from "./util"
import { randomIdNonSecure } from "../../util/random"
const p = new DOMParser()
async function mouseEnterHandler(
  this: HTMLAnchorElement,
  { clientX, clientY }: { clientX: number; clientY: number },
) {
  clearActivePopover()
  const link = this
  link.id = `backlink-${randomIdNonSecure()}`
  if (link.dataset.noPopover === "true") {
    return
  }
  async function setPosition(popoverElement: HTMLElement) {
    const { x, y } = await computePosition(link, popoverElement, {
      strategy: "fixed",
      middleware: [inline({ x: clientX, y: clientY }), shift(), flip()],
    })
    Object.assign(popoverElement.style, {
      left: `${x}px`,
      top: `${y}px`,
      transform: `translate(${x}px, ${y}px)`,
    })
  }
  const hasAlreadyBeenFetched = () =>
    [...link.children].some((child) => child.classList.contains("popover"))
  const prevPopoverElement = document.getElementById(`popover-${link.id.split("-")[1]}`)
  const hasAlreadyBeenFetched = () => !!prevPopoverElement
  // dont refetch if there's already a popover
  if (hasAlreadyBeenFetched()) {
    return setPosition(link.lastChild as HTMLElement)
    setPosition(prevPopoverElement as HTMLElement)
    prevPopoverElement?.classList.add("active-popover")
    return
  }
  const thisUrl = new URL(document.location.href)
@@ -94,7 +101,9 @@
  }
  setPosition(popoverElement)
  link.appendChild(popoverElement)
  popoverElement.id = `popover-${link.id.split("-")[1]}`
  popoverElement?.classList.add("active-popover")
  document.body.appendChild(popoverElement)
  if (hash !== "") {
    const targetAnchor = hash.startsWith("#popover") ? hash : `#popover-${hash.slice(1)}`
@@ -106,10 +115,23 @@
  }
}
function clearActivePopover() {
  const allPopoverElements = document.querySelectorAll(".popover")
  if (allPopoverElements) {
    allPopoverElements.forEach((popoverElement) =>
      popoverElement.classList.remove("active-popover"),
    )
  }
}
document.addEventListener("nav", () => {
  const links = [...document.getElementsByClassName("internal")] as HTMLAnchorElement[]
  for (const link of links) {
    link.addEventListener("mouseleave", clearActivePopover)
    link.addEventListener("mouseenter", mouseEnterHandler)
    window.addCleanup(() => link.removeEventListener("mouseenter", mouseEnterHandler))
    window.addCleanup(() => {
      link.removeEventListener("mouseenter", mouseEnterHandler)
      link.removeEventListener("mouseleave", clearActivePopover)
    })
  }
})
quartz/components/styles/backlinks.scss
@@ -12,6 +12,8 @@
    list-style: none;
    padding: 0;
    margin: 0.5rem 0;
    height: 6rem;
    overscroll-behavior: contain;
    & > li {
      & > a {
quartz/components/styles/explorer.scss
@@ -118,6 +118,7 @@
    list-style: none;
    margin: 0;
    padding: 0;
    overscroll-behavior: contain;
    & li > a {
      color: var(--dark);
quartz/components/styles/popover.scss
@@ -16,9 +16,12 @@
.popover {
  z-index: 999;
  position: absolute;
  position: fixed;
  overflow: visible;
  padding: 1rem;
  left: 0;
  top: 0;
  will-change: transform;
  & > .popover-inner {
    position: relative;
@@ -35,6 +38,7 @@
    border-radius: 5px;
    box-shadow: 6px 6px 36px 0 rgba(0, 0, 0, 0.25);
    overflow: auto;
    overscroll-behavior: contain;
    white-space: normal;
    user-select: none;
    cursor: default;
@@ -77,7 +81,7 @@
  }
}
a:hover .popover,
.active-popover,
.popover:hover {
  animation: dropin 0.3s ease;
  animation-fill-mode: forwards;
quartz/components/styles/toc.scss
@@ -50,6 +50,8 @@
  position: relative;
  margin: 0.5rem 0;
  padding: 0;
  height: 5rem;
  overscroll-behavior: contain;
  list-style: none;
  & > li > a {