add config to components

This commit is contained in:
Jacky Zhao 2023-06-11 23:46:38 -07:00
parent 352075ae81
commit 2bfe90b7e6
13 changed files with 53 additions and 26 deletions

View File

@ -56,9 +56,9 @@ const config: QuartzConfig = {
], ],
emitters: [ emitters: [
Plugin.ContentPage({ Plugin.ContentPage({
head: Component.Head, head: Component.Head(),
header: [Component.PageTitle, Component.Spacer, Component.Darkmode], header: [Component.PageTitle(), Component.Spacer(), Component.Darkmode()],
body: [Component.ArticleTitle, Component.ReadingTime, Component.TableOfContents, Component.Content] body: [Component.ArticleTitle(), Component.ReadingTime(), Component.TableOfContents(), Component.Content()]
}) })
] ]
}, },

View File

@ -1,6 +1,6 @@
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 title = fileData.frontmatter?.title
const displayTitle = fileData.slug === "index" ? undefined : title const displayTitle = fileData.slug === "index" ? undefined : title
if (displayTitle) { if (displayTitle) {
@ -9,3 +9,5 @@ export default function ArticleTitle({ fileData }: QuartzComponentProps) {
return null return null
} }
} }
export default (() => ArticleTitle) satisfies QuartzComponentConstructor

View File

@ -1,8 +1,8 @@
import clipboardScript from './scripts/clipboard.inline' import clipboardScript from './scripts/clipboard.inline'
import clipboardStyle from './styles/clipboard.scss' 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> return <article>
{children} {children}
</article> </article>
@ -10,3 +10,6 @@ export default function Body({ children }: QuartzComponentProps) {
Body.afterDOMLoaded = clipboardScript Body.afterDOMLoaded = clipboardScript
Body.css = clipboardStyle Body.css = clipboardStyle
export default (() => Body) satisfies QuartzComponentConstructor

View File

@ -1,9 +1,11 @@
import { QuartzComponentProps } from "./types" import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
import { Fragment, jsx, jsxs } from 'preact/jsx-runtime' import { Fragment, jsx, jsxs } from 'preact/jsx-runtime'
import { toJsxRuntime } from "hast-util-to-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) // @ts-ignore (preact makes it angry)
const content = toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: 'html' }) const content = toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: 'html' })
return content return content
} }
export default (() => Content) satisfies QuartzComponentConstructor

View File

@ -3,8 +3,9 @@
// see: https://v8.dev/features/modules#defer // see: https://v8.dev/features/modules#defer
import darkmodeScript from "./scripts/darkmode.inline" import darkmodeScript from "./scripts/darkmode.inline"
import styles from './styles/darkmode.scss' import styles from './styles/darkmode.scss'
import { QuartzComponentConstructor } from "./types"
export default function Darkmode() { function Darkmode() {
return <div class="darkmode"> return <div class="darkmode">
<input class="toggle" id="darkmode-toggle" type="checkbox" tabIndex={-1} /> <input class="toggle" id="darkmode-toggle" type="checkbox" tabIndex={-1} />
<label id="toggle-label-light" for="darkmode-toggle" tabIndex={-1}> <label id="toggle-label-light" for="darkmode-toggle" tabIndex={-1}>
@ -48,3 +49,5 @@ export default function Darkmode() {
Darkmode.beforeDOMLoaded = darkmodeScript Darkmode.beforeDOMLoaded = darkmodeScript
Darkmode.css = styles Darkmode.css = styles
export default (() => Darkmode) satisfies QuartzComponentConstructor

View File

@ -1,7 +1,7 @@
import { resolveToRoot } from "../path" 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 slug = fileData.slug!
const title = fileData.frontmatter?.title ?? "Untitled" const title = fileData.frontmatter?.title ?? "Untitled"
const description = fileData.description ?? "No description provided" const description = fileData.description ?? "No description provided"
@ -28,3 +28,5 @@ export default function Head({ fileData, externalResources }: QuartzComponentPro
{js.filter(resource => resource.loadTime === "beforeDOMReady").map(resource => <script key={resource.src} {...resource} spa-preserve />)} {js.filter(resource => resource.loadTime === "beforeDOMReady").map(resource => <script key={resource.src} {...resource} spa-preserve />)}
</head> </head>
} }
export default (() => Head) satisfies QuartzComponentConstructor

View File

@ -1,6 +1,6 @@
import { QuartzComponentProps } from "./types" import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
export default function Header({ children }: QuartzComponentProps) { function Header({ children }: QuartzComponentProps) {
return <header> return <header>
{children} {children}
</header> </header>
@ -21,3 +21,5 @@ header > h1 {
flex: auto; flex: auto;
} }
` `
export default (() => Header) satisfies QuartzComponentConstructor

View File

@ -1,9 +1,11 @@
import { resolveToRoot } from "../path" 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 title = cfg.siteTitle
const slug = fileData.slug! const slug = fileData.slug!
const baseDir = resolveToRoot(slug) const baseDir = resolveToRoot(slug)
return <h1><a href={baseDir}>{title}</a></h1> return <h1><a href={baseDir}>{title}</a></h1>
} }
export default (() => PageTitle) satisfies QuartzComponentConstructor

View File

@ -1,7 +1,7 @@
import { QuartzComponentProps } from "./types" import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
import readingTime from "reading-time" import readingTime from "reading-time"
export default function ReadingTime({ fileData }: QuartzComponentProps) { function ReadingTime({ fileData }: QuartzComponentProps) {
const text = fileData.text const text = fileData.text
const isHomePage = fileData.slug === "index" const isHomePage = fileData.slug === "index"
if (text && !isHomePage) { if (text && !isHomePage) {
@ -18,3 +18,5 @@ ReadingTime.css = `
opacity: 0.5; opacity: 0.5;
} }
` `
export default (() => ReadingTime) satisfies QuartzComponentConstructor

View File

@ -1,3 +1,7 @@
export default function() { import { QuartzComponentConstructor } from "./types"
function Spacer() {
return <div class="spacer"></div> return <div class="spacer"></div>
} }
export default (() => Spacer) satisfies QuartzComponentConstructor

View File

@ -1,7 +1,7 @@
import { QuartzComponentProps } from "./types" import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
import style from "./styles/toc.scss" import style from "./styles/toc.scss"
export default function TableOfContents({ fileData }: QuartzComponentProps) { function TableOfContents({ fileData }: QuartzComponentProps) {
if (!fileData.toc) { if (!fileData.toc) {
return null return null
} }
@ -17,3 +17,5 @@ export default function TableOfContents({ fileData }: QuartzComponentProps) {
} }
TableOfContents.css = style TableOfContents.css = style
export default (() => TableOfContents) satisfies QuartzComponentConstructor

View File

@ -18,4 +18,4 @@ export type QuartzComponent = ComponentType<QuartzComponentProps> & {
afterDOMLoaded?: string, afterDOMLoaded?: string,
} }
export type QuartzComponentConstructor<Options extends object> = (opts: Options) => QuartzComponent export type QuartzComponentConstructor<Options extends object | undefined = undefined> = (opts: Options) => QuartzComponent

View File

@ -5,9 +5,9 @@ import { render } from "preact-render-to-string"
import { GlobalConfiguration } from "../../cfg" import { GlobalConfiguration } from "../../cfg"
import { QuartzComponent } from "../../components/types" import { QuartzComponent } from "../../components/types"
import { resolveToRoot } from "../../path" import { resolveToRoot } from "../../path"
import Header from "../../components/Header" import HeaderConstructor from "../../components/Header"
import { QuartzComponentProps } from "../../components/types" import { QuartzComponentProps } from "../../components/types"
import Body from "../../components/Body" import BodyConstructor from "../../components/Body"
interface Options { interface Options {
head: QuartzComponent head: QuartzComponent
@ -20,6 +20,10 @@ export const ContentPage: QuartzEmitterPlugin<Options> = (opts) => {
throw new Error("ContentPage must be initialized with options specifiying the components to use") 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 { return {
name: "ContentPage", name: "ContentPage",
getQuartzComponents() { getQuartzComponents() {
@ -28,7 +32,6 @@ export const ContentPage: QuartzEmitterPlugin<Options> = (opts) => {
async emit(cfg: GlobalConfiguration, content: ProcessedContent[], resources: StaticResources, emit: EmitCallback): Promise<string[]> { async emit(cfg: GlobalConfiguration, content: ProcessedContent[], resources: StaticResources, emit: EmitCallback): Promise<string[]> {
const fps: string[] = [] const fps: string[] = []
const { head: Head, header, body } = opts
for (const [tree, file] of content) { for (const [tree, file] of content) {
const baseDir = resolveToRoot(file.data.slug!) const baseDir = resolveToRoot(file.data.slug!)
const pageResources: StaticResources = { const pageResources: StaticResources = {