From cc7950267089648e4329531105fe5f8ba011b1b4 Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Tue, 25 Jul 2023 23:37:24 -0700 Subject: [PATCH] make layouts simpler to think about --- content/advanced/making plugins.md | 12 +-- content/configuration.md | 4 +- content/features/upcoming features.md | 2 - quartz.config.ts | 135 ++++++++---------------- quartz.layout.ts | 39 +++++++ quartz/plugins/emitters/contentPage.tsx | 17 +-- quartz/plugins/emitters/folderPage.tsx | 15 ++- quartz/plugins/emitters/tagPage.tsx | 15 ++- 8 files changed, 117 insertions(+), 122 deletions(-) create mode 100644 quartz.layout.ts diff --git a/content/advanced/making plugins.md b/content/advanced/making plugins.md index 661b51623..a73069e6d 100644 --- a/content/advanced/making plugins.md +++ b/content/advanced/making plugins.md @@ -4,17 +4,9 @@ title: Making your own plugins This part of the documentation will assume you have some basic coding knowledge and will include code snippets that describe the interface of what Quartz plugins should look like. -## Transformers +![[quartz-transform-pipeline.png]] -```ts -export type QuartzTransformerPluginInstance = { - name: string - textTransform?: (src: string | Buffer) => string | Buffer - markdownPlugins?: () => PluggableList - htmlPlugins?: () => PluggableList - externalResources?: () => Partial -} -``` +## Transformers ## Filters diff --git a/content/configuration.md b/content/configuration.md index 9f103f4a2..1545d66b7 100644 --- a/content/configuration.md +++ b/content/configuration.md @@ -75,8 +75,10 @@ transformers: [ ] ``` +If you'd like to make your own plugins, read the guide on [[making plugins]] for more information. + ### Layout -Certain emitters may also output [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML) files. To make sure that +Certain emitters may also output [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML) files. To enable easy customization, these emitters allow you to fully rearrange the layout of the page. ### Components diff --git a/content/features/upcoming features.md b/content/features/upcoming features.md index 6d36de85a..370e2cd49 100644 --- a/content/features/upcoming features.md +++ b/content/features/upcoming features.md @@ -6,8 +6,6 @@ draft: true - images in same folder are broken on shortest path mode - watch mode for config/source code -- publish metadata https://help.obsidian.md/Editing+and+formatting/Metadata#Metadata+for+Obsidian+Publish -- metadata aliases: https://help.obsidian.md/Editing+and+formatting/Metadata#Predefined+metadata - 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 diff --git a/quartz.config.ts b/quartz.config.ts index 211fa9370..83b59e692 100644 --- a/quartz.config.ts +++ b/quartz.config.ts @@ -1,83 +1,46 @@ -import { GlobalConfiguration, PageLayout, QuartzConfig } from "./quartz/cfg" -import * as Component from "./quartz/components" +import { QuartzConfig } from "./quartz/cfg" import * as Plugin from "./quartz/plugins" -const generalConfiguration: GlobalConfiguration = { - pageTitle: "🪴 Quartz 4.0", - enableSPA: true, - enablePopovers: true, - analytics: { - provider: "plausible", - }, - baseUrl: "quartz.jzhao.xyz", - ignorePatterns: ["private", "templates"], - theme: { - typography: { - header: "Schibsted Grotesk", - body: "Source Sans Pro", - code: "IBM Plex Mono", - }, - colors: { - lightMode: { - light: "#faf8f8", - lightgray: "#e5e5e5", - gray: "#b8b8b8", - darkgray: "#4e4e4e", - dark: "#2b2b2b", - secondary: "#284b63", - tertiary: "#84a59d", - highlight: "rgba(143, 159, 169, 0.15)", - }, - darkMode: { - light: "#161618", - lightgray: "#393639", - gray: "#646464", - darkgray: "#d4d4d4", - dark: "#ebebec", - secondary: "#7b97aa", - tertiary: "#84a59d", - highlight: "rgba(143, 159, 169, 0.15)", - }, - }, - }, -} - -const sharedPageComponents = { - head: Component.Head(), - header: [], - footer: Component.Footer({ - links: { - GitHub: "https://github.com/jackyzha0/quartz", - "Discord Community": "https://discord.gg/cRFFHYye7t", - }, - }), -} - -const contentPageLayout: PageLayout = { - beforeBody: [Component.ArticleTitle(), Component.ReadingTime(), Component.TagList()], - left: [ - Component.PageTitle(), - Component.MobileOnly(Component.Spacer()), - Component.Search(), - Component.Darkmode(), - Component.DesktopOnly(Component.TableOfContents()), - ], - right: [Component.Graph(), Component.Backlinks()], -} - -const listPageLayout: PageLayout = { - beforeBody: [Component.ArticleTitle()], - left: [ - Component.PageTitle(), - Component.MobileOnly(Component.Spacer()), - Component.Search(), - Component.Darkmode(), - ], - right: [], -} - const config: QuartzConfig = { - configuration: generalConfiguration, + configuration: { + pageTitle: "🪴 Quartz 4.0", + enableSPA: true, + enablePopovers: true, + analytics: { + provider: "plausible", + }, + baseUrl: "quartz.jzhao.xyz", + ignorePatterns: ["private", "templates"], + theme: { + typography: { + header: "Schibsted Grotesk", + body: "Source Sans Pro", + code: "IBM Plex Mono", + }, + colors: { + lightMode: { + light: "#faf8f8", + lightgray: "#e5e5e5", + gray: "#b8b8b8", + darkgray: "#4e4e4e", + dark: "#2b2b2b", + secondary: "#284b63", + tertiary: "#84a59d", + highlight: "rgba(143, 159, 169, 0.15)", + }, + darkMode: { + light: "#161618", + lightgray: "#393639", + gray: "#646464", + darkgray: "#d4d4d4", + dark: "#ebebec", + secondary: "#7b97aa", + tertiary: "#84a59d", + highlight: "rgba(143, 159, 169, 0.15)", + }, + }, + }, + }, plugins: { transformers: [ Plugin.FrontMatter(), @@ -96,21 +59,9 @@ const config: QuartzConfig = { emitters: [ Plugin.AliasRedirects(), Plugin.ComponentResources({ fontOrigin: "googleFonts" }), - Plugin.ContentPage({ - ...sharedPageComponents, - ...contentPageLayout, - pageBody: Component.Content(), - }), - Plugin.FolderPage({ - ...sharedPageComponents, - ...listPageLayout, - pageBody: Component.FolderContent(), - }), - Plugin.TagPage({ - ...sharedPageComponents, - ...listPageLayout, - pageBody: Component.TagContent(), - }), + Plugin.ContentPage(), + Plugin.FolderPage(), + Plugin.TagPage(), Plugin.ContentIndex({ enableSiteMap: true, enableRSS: true, diff --git a/quartz.layout.ts b/quartz.layout.ts new file mode 100644 index 000000000..f47b22496 --- /dev/null +++ b/quartz.layout.ts @@ -0,0 +1,39 @@ +import { PageLayout } from "./quartz/cfg" +import * as Component from "./quartz/components" + +// components shared across all pages +export const sharedPageComponents = { + head: Component.Head(), + header: [], + footer: Component.Footer({ + links: { + GitHub: "https://github.com/jackyzha0/quartz", + "Discord Community": "https://discord.gg/cRFFHYye7t", + }, + }), +} + +// components for pages that display a single page (e.g. a single note) +export const defaultContentPageLayout: PageLayout = { + beforeBody: [Component.ArticleTitle(), Component.ReadingTime(), Component.TagList()], + left: [ + Component.PageTitle(), + Component.MobileOnly(Component.Spacer()), + Component.Search(), + Component.Darkmode(), + Component.DesktopOnly(Component.TableOfContents()), + ], + right: [Component.Graph(), Component.Backlinks()], +} + +// components for pages that display lists of pages (e.g. tags or folders) +export const defaultListPageLayout: PageLayout = { + beforeBody: [Component.ArticleTitle()], + left: [ + Component.PageTitle(), + Component.MobileOnly(Component.Spacer()), + Component.Search(), + Component.Darkmode(), + ], + right: [], +} diff --git a/quartz/plugins/emitters/contentPage.tsx b/quartz/plugins/emitters/contentPage.tsx index 97198da62..25432532b 100644 --- a/quartz/plugins/emitters/contentPage.tsx +++ b/quartz/plugins/emitters/contentPage.tsx @@ -5,22 +5,25 @@ import BodyConstructor from "../../components/Body" import { pageResources, renderPage } from "../../components/renderPage" import { FullPageLayout } from "../../cfg" import { FilePath, canonicalizeServer } from "../../path" +import { defaultContentPageLayout, sharedPageComponents } from "../../../quartz.layout" +import { Content } from "../../components" -export const ContentPage: QuartzEmitterPlugin = (opts) => { - if (!opts) { - throw new Error( - "ContentPage must be initialized with options specifiying the components to use", - ) +export const ContentPage: QuartzEmitterPlugin> = (userOpts) => { + const opts: FullPageLayout = { + ...sharedPageComponents, + ...defaultContentPageLayout, + pageBody: Content(), + ...userOpts, } - const { head: Head, header, beforeBody, pageBody: Content, left, right, footer: Footer } = opts + const { head: Head, header, beforeBody, pageBody, left, right, footer: Footer } = opts const Header = HeaderConstructor() const Body = BodyConstructor() return { name: "ContentPage", getQuartzComponents() { - return [Head, Header, Body, ...header, ...beforeBody, Content, ...left, ...right, Footer] + return [Head, Header, Body, ...header, ...beforeBody, pageBody, ...left, ...right, Footer] }, async emit(ctx, content, resources, emit): Promise { const cfg = ctx.cfg.configuration diff --git a/quartz/plugins/emitters/folderPage.tsx b/quartz/plugins/emitters/folderPage.tsx index 8c6ae020a..5de2e923b 100644 --- a/quartz/plugins/emitters/folderPage.tsx +++ b/quartz/plugins/emitters/folderPage.tsx @@ -7,20 +7,25 @@ import { ProcessedContent, defaultProcessedContent } from "../vfile" import { FullPageLayout } from "../../cfg" import path from "path" import { CanonicalSlug, FilePath, ServerSlug, canonicalizeServer, joinSegments } from "../../path" +import { defaultListPageLayout, sharedPageComponents } from "../../../quartz.layout" +import { FolderContent } from "../../components" -export const FolderPage: QuartzEmitterPlugin = (opts) => { - if (!opts) { - throw new Error("ErrorPage must be initialized with options specifiying the components to use") +export const FolderPage: QuartzEmitterPlugin = (userOpts) => { + const opts: FullPageLayout = { + ...sharedPageComponents, + ...defaultListPageLayout, + pageBody: FolderContent(), + ...userOpts, } - const { head: Head, header, beforeBody, pageBody: Content, left, right, footer: Footer } = opts + const { head: Head, header, beforeBody, pageBody, left, right, footer: Footer } = opts const Header = HeaderConstructor() const Body = BodyConstructor() return { name: "FolderPage", getQuartzComponents() { - return [Head, Header, Body, ...header, ...beforeBody, Content, ...left, ...right, Footer] + return [Head, Header, Body, ...header, ...beforeBody, pageBody, ...left, ...right, Footer] }, async emit(ctx, content, resources, emit): Promise { const fps: FilePath[] = [] diff --git a/quartz/plugins/emitters/tagPage.tsx b/quartz/plugins/emitters/tagPage.tsx index 2154851b4..ae231d6e0 100644 --- a/quartz/plugins/emitters/tagPage.tsx +++ b/quartz/plugins/emitters/tagPage.tsx @@ -12,20 +12,25 @@ import { getAllSegmentPrefixes, joinSegments, } from "../../path" +import { defaultListPageLayout, sharedPageComponents } from "../../../quartz.layout" +import { TagContent } from "../../components" -export const TagPage: QuartzEmitterPlugin = (opts) => { - if (!opts) { - throw new Error("TagPage must be initialized with options specifiying the components to use") +export const TagPage: QuartzEmitterPlugin = (userOpts) => { + const opts: FullPageLayout = { + ...sharedPageComponents, + ...defaultListPageLayout, + pageBody: TagContent(), + ...userOpts, } - const { head: Head, header, beforeBody, pageBody: Content, left, right, footer: Footer } = opts + const { head: Head, header, beforeBody, pageBody, left, right, footer: Footer } = opts const Header = HeaderConstructor() const Body = BodyConstructor() return { name: "TagPage", getQuartzComponents() { - return [Head, Header, Body, ...header, ...beforeBody, Content, ...left, ...right, Footer] + return [Head, Header, Body, ...header, ...beforeBody, pageBody, ...left, ...right, Footer] }, async emit(ctx, content, resources, emit): Promise { const fps: FilePath[] = []