diff --git a/content/advanced/making plugins.md b/content/advanced/making plugins.md index 661b5162..a73069e6 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 9f103f4a..1545d66b 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 6d36de85..370e2cd4 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 211fa937..83b59e69 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 00000000..f47b2249 --- /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 97198da6..25432532 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 8c6ae020..5de2e923 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 2154851b..ae231d6e 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[] = []