| | |
| | | ], |
| | | emitters: [ |
| | | Plugin.ContentPage({ |
| | | head: Component.Head, |
| | | header: [Component.PageTitle, Component.Spacer, Component.Darkmode], |
| | | body: [Component.ArticleTitle, Component.ReadingTime, Component.TableOfContents, Component.Content] |
| | | head: Component.Head(), |
| | | header: [Component.PageTitle(), Component.Spacer(), Component.Darkmode()], |
| | | body: [Component.ArticleTitle(), Component.ReadingTime(), Component.TableOfContents(), Component.Content()] |
| | | }) |
| | | ] |
| | | }, |
| | |
| | | import { QuartzComponentProps } from "./types" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | |
| | | export default function ArticleTitle({ fileData }: QuartzComponentProps) { |
| | | function ArticleTitle({ fileData }: QuartzComponentProps) { |
| | | const title = fileData.frontmatter?.title |
| | | const displayTitle = fileData.slug === "index" ? undefined : title |
| | | if (displayTitle) { |
| | |
| | | return null |
| | | } |
| | | } |
| | | |
| | | export default (() => ArticleTitle) satisfies QuartzComponentConstructor |
| | |
| | | import clipboardScript from './scripts/clipboard.inline' |
| | | import clipboardStyle from './styles/clipboard.scss' |
| | | import { QuartzComponentProps } from "./types" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | |
| | | export default function Body({ children }: QuartzComponentProps) { |
| | | function Body({ children }: QuartzComponentProps) { |
| | | return <article> |
| | | {children} |
| | | </article> |
| | |
| | | |
| | | Body.afterDOMLoaded = clipboardScript |
| | | Body.css = clipboardStyle |
| | | |
| | | export default (() => Body) satisfies QuartzComponentConstructor |
| | | |
| | |
| | | import { QuartzComponentProps } from "./types" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | import { Fragment, jsx, jsxs } from 'preact/jsx-runtime' |
| | | import { toJsxRuntime } from "hast-util-to-jsx-runtime" |
| | | |
| | | export default function Content({ tree }: QuartzComponentProps) { |
| | | function Content({ tree }: QuartzComponentProps) { |
| | | // @ts-ignore (preact makes it angry) |
| | | const content = toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: 'html' }) |
| | | return content |
| | | } |
| | | |
| | | export default (() => Content) satisfies QuartzComponentConstructor |
| | |
| | | // see: https://v8.dev/features/modules#defer |
| | | import darkmodeScript from "./scripts/darkmode.inline" |
| | | import styles from './styles/darkmode.scss' |
| | | import { QuartzComponentConstructor } from "./types" |
| | | |
| | | export default function Darkmode() { |
| | | function Darkmode() { |
| | | return <div class="darkmode"> |
| | | <input class="toggle" id="darkmode-toggle" type="checkbox" tabIndex={-1} /> |
| | | <label id="toggle-label-light" for="darkmode-toggle" tabIndex={-1}> |
| | |
| | | |
| | | Darkmode.beforeDOMLoaded = darkmodeScript |
| | | Darkmode.css = styles |
| | | |
| | | export default (() => Darkmode) satisfies QuartzComponentConstructor |
| | |
| | | import { resolveToRoot } from "../path" |
| | | import { QuartzComponentProps } from "./types" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | |
| | | export default function Head({ fileData, externalResources }: QuartzComponentProps) { |
| | | function Head({ fileData, externalResources }: QuartzComponentProps) { |
| | | const slug = fileData.slug! |
| | | const title = fileData.frontmatter?.title ?? "Untitled" |
| | | const description = fileData.description ?? "No description provided" |
| | |
| | | const baseDir = resolveToRoot(slug) |
| | | const iconPath = baseDir + "/static/icon.png" |
| | | const ogImagePath = baseDir + "/static/og-image.png" |
| | | |
| | | |
| | | return <head> |
| | | <title>{title}</title> |
| | | <meta charSet="utf-8" /> |
| | |
| | | {js.filter(resource => resource.loadTime === "beforeDOMReady").map(resource => <script key={resource.src} {...resource} spa-preserve />)} |
| | | </head> |
| | | } |
| | | |
| | | export default (() => Head) satisfies QuartzComponentConstructor |
| | |
| | | import { QuartzComponentProps } from "./types" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | |
| | | export default function Header({ children }: QuartzComponentProps) { |
| | | function Header({ children }: QuartzComponentProps) { |
| | | return <header> |
| | | {children} |
| | | </header> |
| | |
| | | flex: auto; |
| | | } |
| | | ` |
| | | |
| | | export default (() => Header) satisfies QuartzComponentConstructor |
| | |
| | | import { resolveToRoot } from "../path" |
| | | import { QuartzComponentProps } from "./types" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | |
| | | export default function({ cfg, fileData }: QuartzComponentProps) { |
| | | function PageTitle({ cfg, fileData }: QuartzComponentProps) { |
| | | const title = cfg.siteTitle |
| | | const slug = fileData.slug! |
| | | const baseDir = resolveToRoot(slug) |
| | | return <h1><a href={baseDir}>{title}</a></h1> |
| | | } |
| | | |
| | | export default (() => PageTitle) satisfies QuartzComponentConstructor |
| | |
| | | import { QuartzComponentProps } from "./types" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | import readingTime from "reading-time" |
| | | |
| | | export default function ReadingTime({ fileData }: QuartzComponentProps) { |
| | | function ReadingTime({ fileData }: QuartzComponentProps) { |
| | | const text = fileData.text |
| | | const isHomePage = fileData.slug === "index" |
| | | if (text && !isHomePage) { |
| | |
| | | opacity: 0.5; |
| | | } |
| | | ` |
| | | |
| | | export default (() => ReadingTime) satisfies QuartzComponentConstructor |
| | |
| | | export default function() { |
| | | import { QuartzComponentConstructor } from "./types" |
| | | |
| | | function Spacer() { |
| | | return <div class="spacer"></div> |
| | | } |
| | | |
| | | export default (() => Spacer) satisfies QuartzComponentConstructor |
| | |
| | | import { QuartzComponentProps } from "./types" |
| | | import { QuartzComponentConstructor, QuartzComponentProps } from "./types" |
| | | import style from "./styles/toc.scss" |
| | | |
| | | export default function TableOfContents({ fileData }: QuartzComponentProps) { |
| | | function TableOfContents({ fileData }: QuartzComponentProps) { |
| | | if (!fileData.toc) { |
| | | return null |
| | | } |
| | |
| | | } |
| | | |
| | | TableOfContents.css = style |
| | | |
| | | export default (() => TableOfContents) satisfies QuartzComponentConstructor |
| | |
| | | afterDOMLoaded?: string, |
| | | } |
| | | |
| | | export type QuartzComponentConstructor<Options extends object> = (opts: Options) => QuartzComponent |
| | | export type QuartzComponentConstructor<Options extends object | undefined = undefined> = (opts: Options) => QuartzComponent |
| | |
| | | import { GlobalConfiguration } from "../../cfg" |
| | | import { QuartzComponent } from "../../components/types" |
| | | import { resolveToRoot } from "../../path" |
| | | import Header from "../../components/Header" |
| | | import HeaderConstructor from "../../components/Header" |
| | | import { QuartzComponentProps } from "../../components/types" |
| | | import Body from "../../components/Body" |
| | | import BodyConstructor from "../../components/Body" |
| | | |
| | | interface Options { |
| | | head: QuartzComponent |
| | |
| | | throw new Error("ContentPage must be initialized with options specifiying the components to use") |
| | | } |
| | | |
| | | const { head: Head, header, body } = opts |
| | | const Header = HeaderConstructor() |
| | | const Body = BodyConstructor() |
| | | |
| | | return { |
| | | name: "ContentPage", |
| | | getQuartzComponents() { |
| | |
| | | async emit(cfg: GlobalConfiguration, content: ProcessedContent[], resources: StaticResources, emit: EmitCallback): Promise<string[]> { |
| | | const fps: string[] = [] |
| | | |
| | | const { head: Head, header, body } = opts |
| | | for (const [tree, file] of content) { |
| | | const baseDir = resolveToRoot(file.data.slug!) |
| | | const pageResources: StaticResources = { |