From 198f9e79a763e3afb8c98c982db5b2b178d6d364 Mon Sep 17 00:00:00 2001 From: Amir Pourmand Date: Wed, 10 Sep 2025 00:30:57 +0330 Subject: [PATCH 1/3] feat(contentPage): add dead link detection for missing pages This update introduces functionality to identify and mark links to non-existent pages as "dead links" within the content page emitter. The implementation utilizes the `unist-util-visit` library to traverse the document tree and modify link elements accordingly. Links that do not correspond to existing slugs are converted to spans with a "dead-link" class for better user feedback. --- quartz/plugins/emitters/contentPage.tsx | 45 ++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/quartz/plugins/emitters/contentPage.tsx b/quartz/plugins/emitters/contentPage.tsx index c3410ecc3..dfac4a7ec 100644 --- a/quartz/plugins/emitters/contentPage.tsx +++ b/quartz/plugins/emitters/contentPage.tsx @@ -5,15 +5,18 @@ import HeaderConstructor from "../../components/Header" import BodyConstructor from "../../components/Body" import { pageResources, renderPage } from "../../components/renderPage" import { FullPageLayout } from "../../cfg" -import { pathToRoot } from "../../util/path" +import { pathToRoot, resolveRelative } from "../../util/path" import { defaultContentPageLayout, sharedPageComponents } from "../../../quartz.layout" import { Content } from "../../components" import { styleText } from "util" import { write } from "./helpers" import { BuildCtx } from "../../util/ctx" import { Node } from "unist" +import { Root } from "hast" import { StaticResources } from "../../util/resources" import { QuartzPluginData } from "../vfile" +import { visit } from "unist-util-visit" +import { RelativeURL } from "../../util/path" async function processContent( ctx: BuildCtx, @@ -25,6 +28,46 @@ async function processContent( ) { const slug = fileData.slug! const cfg = ctx.cfg.configuration + + /** Until the end of visit(), this code snippet is from + * https://github.com/jackyzha0/quartz/issues/454#issuecomment-2408792538 + * by auctumnus + * + * It removes all the links that would lead to missing pages, ie. + * + * [[Missing link]] when Missing link.md does not exist. + */ + const allSlugs = allFiles.map((f) => (f.slug ? resolveRelative(slug, f.slug) : "")) + + visit(tree as Root, "element", (elem) => { + if (elem.tagName === "a" && elem.properties.href) { + const href = elem.properties.href.toString() + + if (href.startsWith("#")) { + return + } + + if (!allSlugs.includes(href as RelativeURL)) { + if (elem.properties.className === undefined) { + elem.properties.className = "dead-link" + } else if (Array.isArray(elem.properties.className)) { + if (elem.properties.className.includes("external")) { + return + } + elem.properties.className.push("dead-link") + } else if (typeof elem.properties.className === "string") { + if (elem.properties.className.includes("external")) { + return + } + elem.properties.className += " dead-link" + } else { + return + } + elem.tagName = "span" + } + } + }) + const externalResources = pageResources(pathToRoot(slug), resources) const componentData: QuartzComponentProps = { ctx, From bca21f4f2bd18d8b5d9c9ce630d4d44eb00fc09d Mon Sep 17 00:00:00 2001 From: Amir Pourmand Date: Wed, 10 Sep 2025 00:41:19 +0330 Subject: [PATCH 2/3] feat(styles): add custom styling for dead links This commit introduces a new CSS class `.dead-link` to style links that point to missing pages. The styling includes a distinct color, background, and cursor to enhance user feedback when encountering dead links. --- quartz/styles/custom.scss | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/quartz/styles/custom.scss b/quartz/styles/custom.scss index b0c09dcb9..f408788b7 100644 --- a/quartz/styles/custom.scss +++ b/quartz/styles/custom.scss @@ -1,3 +1,15 @@ @use "./base.scss"; // put your custom CSS here! +// Dead link styling - links to missing pages +.dead-link { + font-weight: 600; + text-decoration: none; + transition: color 0.2s ease; + color: #d97706; + background-color: var(--lightgray); + padding: 0 0.1rem; + border-radius: 5px; + line-height: 1.4rem; + cursor: default; +} \ No newline at end of file From 10f2e2eff63f0dfe7c2180a2115759d281047714 Mon Sep 17 00:00:00 2001 From: Amir Pourmand Date: Wed, 10 Sep 2025 00:45:02 +0330 Subject: [PATCH 3/3] refactor(contentPage): remove outdated comments regarding dead link detection This commit cleans up the code in the content page emitter by removing unnecessary comments that referenced an external issue. The functionality for dead link detection remains intact, ensuring clarity and maintainability of the code. --- quartz/plugins/emitters/contentPage.tsx | 16 ++++------------ quartz/styles/custom.scss | 2 +- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/quartz/plugins/emitters/contentPage.tsx b/quartz/plugins/emitters/contentPage.tsx index dfac4a7ec..e0b3f6728 100644 --- a/quartz/plugins/emitters/contentPage.tsx +++ b/quartz/plugins/emitters/contentPage.tsx @@ -28,25 +28,17 @@ async function processContent( ) { const slug = fileData.slug! const cfg = ctx.cfg.configuration - - /** Until the end of visit(), this code snippet is from - * https://github.com/jackyzha0/quartz/issues/454#issuecomment-2408792538 - * by auctumnus - * - * It removes all the links that would lead to missing pages, ie. - * - * [[Missing link]] when Missing link.md does not exist. - */ + const allSlugs = allFiles.map((f) => (f.slug ? resolveRelative(slug, f.slug) : "")) - + visit(tree as Root, "element", (elem) => { if (elem.tagName === "a" && elem.properties.href) { const href = elem.properties.href.toString() - + if (href.startsWith("#")) { return } - + if (!allSlugs.includes(href as RelativeURL)) { if (elem.properties.className === undefined) { elem.properties.className = "dead-link" diff --git a/quartz/styles/custom.scss b/quartz/styles/custom.scss index f408788b7..752b145f4 100644 --- a/quartz/styles/custom.scss +++ b/quartz/styles/custom.scss @@ -12,4 +12,4 @@ border-radius: 5px; line-height: 1.4rem; cursor: default; -} \ No newline at end of file +}