diff --git a/docs/features/OxHugo compatibility.md b/docs/features/OxHugo compatibility.md index 7801f0c2..b25167f8 100644 --- a/docs/features/OxHugo compatibility.md +++ b/docs/features/OxHugo compatibility.md @@ -3,7 +3,7 @@ tags: - plugin/transformer --- -[org-roam](https://www.orgroam.com/) is a plain-text(`org`) personal knowledge management system for [emacs](https://en.wikipedia.org/wiki/Emacs). [ox-hugo](https://github.com/kaushalmodi/ox-hugo) is org exporter backend that exports `org-mode` files to [Hugo](https://gohugo.io/) compatible Markdown. +[org-roam](https://www.orgroam.com/) is a plain-text personal knowledge management system for [emacs](https://en.wikipedia.org/wiki/Emacs). [ox-hugo](https://github.com/kaushalmodi/ox-hugo) is org exporter backend that exports `org-mode` files to [Hugo](https://gohugo.io/) compatible Markdown. Because the Markdown generated by ox-hugo is not pure Markdown but Hugo specific, we need to transform it to fit into Quartz. This is done by `Plugin.OxHugoFlavouredMarkdown`. Even though this [[making plugins|plugin]] was written with `ox-hugo` in mind, it should work for any Hugo specific Markdown. diff --git a/docs/features/upcoming features.md b/docs/features/upcoming features.md index fbfdbc94..76adda00 100644 --- a/docs/features/upcoming features.md +++ b/docs/features/upcoming features.md @@ -4,15 +4,14 @@ draft: true ## high priority backlog +- static dead link detection - block links: https://help.obsidian.md/Linking+notes+and+files/Internal+links#Link+to+a+block+in+a+note - note/header/block transcludes: https://help.obsidian.md/Linking+notes+and+files/Embedding+files -- static dead link detection - docker support ## misc backlog - breadcrumbs component -- filetree component - cursor chat extension - https://giscus.app/ extension - sidenotes? https://github.com/capnfabs/paperesque diff --git a/quartz.config.ts b/quartz.config.ts index 31d5bcfe..f677a18f 100644 --- a/quartz.config.ts +++ b/quartz.config.ts @@ -69,6 +69,7 @@ const config: QuartzConfig = { }), Plugin.Assets(), Plugin.Static(), + Plugin.NotFoundPage(), ], }, } diff --git a/quartz/components/index.ts b/quartz/components/index.ts index a83f078b..10a43acb 100644 --- a/quartz/components/index.ts +++ b/quartz/components/index.ts @@ -1,7 +1,8 @@ -import ArticleTitle from "./ArticleTitle" import Content from "./pages/Content" import TagContent from "./pages/TagContent" import FolderContent from "./pages/FolderContent" +import NotFound from "./pages/404" +import ArticleTitle from "./ArticleTitle" import Darkmode from "./Darkmode" import Head from "./Head" import PageTitle from "./PageTitle" @@ -36,4 +37,5 @@ export { DesktopOnly, MobileOnly, RecentNotes, + NotFound, } diff --git a/quartz/components/pages/404.tsx b/quartz/components/pages/404.tsx new file mode 100644 index 00000000..c276f568 --- /dev/null +++ b/quartz/components/pages/404.tsx @@ -0,0 +1,12 @@ +import { QuartzComponentConstructor } from "../types" + +function NotFound() { + return ( +
+

404

+

Either this page is private or doesn't exist.

+
+ ) +} + +export default (() => NotFound) satisfies QuartzComponentConstructor diff --git a/quartz/plugins/emitters/404.tsx b/quartz/plugins/emitters/404.tsx new file mode 100644 index 00000000..785c873d --- /dev/null +++ b/quartz/plugins/emitters/404.tsx @@ -0,0 +1,56 @@ +import { QuartzEmitterPlugin } from "../types" +import { QuartzComponentProps } from "../../components/types" +import BodyConstructor from "../../components/Body" +import { pageResources, renderPage } from "../../components/renderPage" +import { FullPageLayout } from "../../cfg" +import { FilePath, FullSlug } from "../../util/path" +import { sharedPageComponents } from "../../../quartz.layout" +import { NotFound } from "../../components" +import { defaultProcessedContent } from "../vfile" + +export const NotFoundPage: QuartzEmitterPlugin = () => { + const opts: FullPageLayout = { + ...sharedPageComponents, + pageBody: NotFound(), + beforeBody: [], + left: [], + right: [], + } + + const { head: Head, pageBody, footer: Footer } = opts + const Body = BodyConstructor() + + return { + name: "404Page", + getQuartzComponents() { + return [Head, Body, pageBody, Footer] + }, + async emit(ctx, _content, resources, emit): Promise { + const cfg = ctx.cfg.configuration + const slug = "404" as FullSlug + const externalResources = pageResources(slug, resources) + const [tree, vfile] = defaultProcessedContent({ + slug, + text: "Not Found", + description: "Not Found", + frontmatter: { title: "Not Found", tags: [] }, + }) + const componentData: QuartzComponentProps = { + fileData: vfile.data, + externalResources, + cfg, + children: [], + tree, + allFiles: [], + } + + return [ + await emit({ + content: renderPage(slug, componentData, opts, externalResources), + slug, + ext: ".html", + }), + ] + }, + } +} diff --git a/quartz/plugins/emitters/index.ts b/quartz/plugins/emitters/index.ts index da95d490..99a2c54d 100644 --- a/quartz/plugins/emitters/index.ts +++ b/quartz/plugins/emitters/index.ts @@ -6,3 +6,4 @@ export { AliasRedirects } from "./aliases" export { Assets } from "./assets" export { Static } from "./static" export { ComponentResources } from "./componentResources" +export { NotFoundPage } from "./404"