This commit is contained in:
semanticdata 2024-03-11 08:53:58 -05:00
commit 95da75f003
11 changed files with 111 additions and 111 deletions

View File

@ -19,6 +19,7 @@ const config: QuartzConfig = {
ignorePatterns: ["private", "templates"],
defaultDateType: "modified",
theme: {
fontOrigin: "googleFonts",
cdnCaching: true,
typography: {
header: "Bitter", // Schibsted Grotesk
@ -63,7 +64,7 @@ const config: QuartzConfig = {
filters: [Plugin.RemoveDrafts()],
emitters: [
Plugin.AliasRedirects(),
Plugin.ComponentResources({ fontOrigin: "googleFonts" }),
Plugin.ComponentResources(),
Plugin.ContentPage(),
Plugin.FolderPage(),
Plugin.TagPage(),

View File

@ -309,6 +309,8 @@ async function partialRebuildFromEntrypoint(
}
await rimraf([...destinationsToDelete])
console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`))
toRemove.clear()
release()
clientRefresh()

View File

@ -3,16 +3,20 @@ import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
import readingTime from "reading-time"
import { classNames } from "../util/lang"
import { i18n } from "../i18n"
import { JSX } from "preact"
import style from "./styles/contentMeta.scss"
interface ContentMetaOptions {
/**
* Whether to display reading time
*/
showReadingTime: boolean
showComma: boolean
}
const defaultOptions: ContentMetaOptions = {
showReadingTime: true,
showComma: true,
}
export default ((opts?: Partial<ContentMetaOptions>) => {
@ -23,7 +27,7 @@ export default ((opts?: Partial<ContentMetaOptions>) => {
const text = fileData.text
if (text) {
const segments: string[] = []
const segments: (string | JSX.Element)[] = []
if (fileData.dates) {
segments.push(formatDate(getDate(cfg, fileData)!, cfg.locale))
@ -38,17 +42,19 @@ export default ((opts?: Partial<ContentMetaOptions>) => {
segments.push(displayedTime)
}
return <p class={classNames(displayClass, "content-meta")}>{segments.join(", ")}</p>
const segmentsElements = segments.map((segment) => <span>{segment}</span>)
return (
<p show-comma={options.showComma} class={classNames(displayClass, "content-meta")}>
{segmentsElements}
</p>
)
} else {
return null
}
}
ContentMetadata.css = `
.content-meta {
margin-top: 0;
color: var(--gray);
}
`
ContentMetadata.css = style
return ContentMetadata
}) satisfies QuartzComponentConstructor

View File

@ -1,6 +1,7 @@
import { i18n } from "../i18n"
import { FullSlug, joinSegments, pathToRoot } from "../util/path"
import { JSResourceToScriptElement } from "../util/resources"
import { googleFontHref } from "../util/theme"
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
export default (() => {
@ -21,10 +22,11 @@ export default (() => {
<head>
<title>{title}</title>
<meta charSet="utf-8" />
{cfg.theme.cdnCaching && (
{cfg.theme.cdnCaching && cfg.theme.fontOrigin === "googleFonts" && (
<>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link rel="stylesheet" href={googleFontHref(cfg.theme)} />
</>
)}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

View File

@ -118,11 +118,12 @@ export function renderPage(
// skip until we find the blockref that matches
if (el.properties?.id === blockRef) {
startIdx = i
startDepth = Number(el.tagName.substring(1))
startDepth = depth
}
} else if (depth <= startDepth) {
// looking for new header that is same level or higher
endIdx = i
break
}
}
@ -209,7 +210,7 @@ export function renderPage(
</div>
)
const lang = componentData.frontmatter?.lang ?? cfg.locale?.split("-")[0] ?? "en"
const lang = componentData.fileData.frontmatter?.lang ?? cfg.locale?.split("-")[0] ?? "en"
const doc = (
<html lang="en">
<Head {...componentData} />

View File

@ -0,0 +1,14 @@
.content-meta {
margin-top: 0;
color: var(--gray);
&[show-comma="true"] {
> span:not(:last-child) {
margin-right: 8px;
&::after {
content: ",";
}
}
}
}

View File

@ -8,7 +8,6 @@ import popoverScript from "../../components/scripts/popover.inline"
import styles from "../../styles/custom.scss"
import popoverStyle from "../../components/styles/popover.scss"
import { BuildCtx } from "../../util/ctx"
import { StaticResources } from "../../util/resources"
import { QuartzComponent } from "../../components/types"
import { googleFontHref, joinStyles } from "../../util/theme"
import { Features, transform } from "lightningcss"
@ -69,13 +68,8 @@ async function joinScripts(scripts: string[]): Promise<string> {
return res.code
}
function addGlobalPageResources(
ctx: BuildCtx,
staticResources: StaticResources,
componentResources: ComponentResources,
) {
function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentResources) {
const cfg = ctx.cfg.configuration
const reloadScript = ctx.argv.serve
// popovers
if (cfg.enablePopovers) {
@ -85,12 +79,12 @@ function addGlobalPageResources(
if (cfg.analytics?.provider === "google") {
const tagId = cfg.analytics.tagId
staticResources.js.push({
src: `https://www.googletagmanager.com/gtag/js?id=${tagId}`,
contentType: "external",
loadTime: "afterDOMReady",
})
componentResources.afterDOMLoaded.push(`
const gtagScript = document.createElement("script")
gtagScript.src = "https://www.googletagmanager.com/gtag/js?id=${tagId}"
gtagScript.async = true
document.head.appendChild(gtagScript)
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag("js", new Date());
@ -147,115 +141,72 @@ function addGlobalPageResources(
document.dispatchEvent(event)
`)
}
let wsUrl = `ws://localhost:${ctx.argv.wsPort}`
if (ctx.argv.remoteDevHost) {
wsUrl = `wss://${ctx.argv.remoteDevHost}:${ctx.argv.wsPort}`
}
if (reloadScript) {
staticResources.js.push({
loadTime: "afterDOMReady",
contentType: "inline",
script: `
const socket = new WebSocket('${wsUrl}')
// reload(true) ensures resources like images and scripts are fetched again in firefox
socket.addEventListener('message', () => document.location.reload(true))
`,
})
}
}
interface Options {
fontOrigin: "googleFonts" | "local"
}
const defaultOptions: Options = {
fontOrigin: "googleFonts",
}
export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<Options>) => {
const { fontOrigin } = { ...defaultOptions, ...opts }
// This emitter should not update the `resources` parameter. If it does, partial
// rebuilds may not work as expected.
export const ComponentResources: QuartzEmitterPlugin = () => {
return {
name: "ComponentResources",
getQuartzComponents() {
return []
},
async getDependencyGraph(ctx, content, _resources) {
// This emitter adds static resources to the `resources` parameter. One
// important resource this emitter adds is the code to start a websocket
// connection and listen to rebuild messages, which triggers a page reload.
// The resources parameter with the reload logic is later used by the
// ContentPage emitter while creating the final html page. In order for
// the reload logic to be included, and so for partial rebuilds to work,
// we need to run this emitter for all markdown files.
const graph = new DepGraph<FilePath>()
for (const [_tree, file] of content) {
const sourcePath = file.data.filePath!
const slug = file.data.slug!
graph.addEdge(sourcePath, joinSegments(ctx.argv.output, slug + ".html") as FilePath)
}
return graph
async getDependencyGraph(_ctx, _content, _resources) {
return new DepGraph<FilePath>()
},
async emit(ctx, _content, resources): Promise<FilePath[]> {
async emit(ctx, _content, _resources): Promise<FilePath[]> {
const promises: Promise<FilePath>[] = []
const cfg = ctx.cfg.configuration
// component specific scripts and styles
const componentResources = getComponentResources(ctx)
let googleFontsStyleSheet = ""
if (fontOrigin === "local") {
if (cfg.theme.fontOrigin === "local") {
// let the user do it themselves in css
} else if (fontOrigin === "googleFonts") {
if (cfg.theme.cdnCaching) {
resources.css.push(googleFontHref(cfg.theme))
} else {
let match
} else if (cfg.theme.fontOrigin === "googleFonts" && !cfg.theme.cdnCaching) {
// when cdnCaching is true, we link to google fonts in Head.tsx
let match
const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g
const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g
googleFontsStyleSheet = await (
await fetch(googleFontHref(ctx.cfg.configuration.theme))
).text()
googleFontsStyleSheet = await (
await fetch(googleFontHref(ctx.cfg.configuration.theme))
).text()
while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) {
// match[0] is the `url(path)`, match[1] is the `path`
const url = match[1]
// the static name of this file.
const [filename, ext] = url.split("/").pop()!.split(".")
while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) {
// match[0] is the `url(path)`, match[1] is the `path`
const url = match[1]
// the static name of this file.
const [filename, ext] = url.split("/").pop()!.split(".")
googleFontsStyleSheet = googleFontsStyleSheet.replace(
url,
`/static/fonts/${filename}.ttf`,
)
googleFontsStyleSheet = googleFontsStyleSheet.replace(
url,
`https://${cfg.baseUrl}/static/fonts/${filename}.ttf`,
)
promises.push(
fetch(url)
.then((res) => {
if (!res.ok) {
throw new Error(`Failed to fetch font`)
}
return res.arrayBuffer()
})
.then((buf) =>
write({
ctx,
slug: joinSegments("static", "fonts", filename) as FullSlug,
ext: `.${ext}`,
content: Buffer.from(buf),
}),
),
)
}
promises.push(
fetch(url)
.then((res) => {
if (!res.ok) {
throw new Error(`Failed to fetch font`)
}
return res.arrayBuffer()
})
.then((buf) =>
write({
ctx,
slug: joinSegments("static", "fonts", filename) as FullSlug,
ext: `.${ext}`,
content: Buffer.from(buf),
}),
),
)
}
}
// important that this goes *after* component scripts
// as the "nav" event gets triggered here and we should make sure
// that everyone else had the chance to register a listener for it
addGlobalPageResources(ctx, resources, componentResources)
addGlobalPageResources(ctx, componentResources)
const stylesheet = joinStyles(
ctx.cfg.configuration.theme,

View File

@ -18,6 +18,23 @@ export function getStaticResourcesFromPlugins(ctx: BuildCtx) {
}
}
// if serving locally, listen for rebuilds and reload the page
if (ctx.argv.serve) {
const wsUrl = ctx.argv.remoteDevHost
? `wss://${ctx.argv.remoteDevHost}:${ctx.argv.wsPort}`
: `ws://localhost:${ctx.argv.wsPort}`
staticResources.js.push({
loadTime: "afterDOMReady",
contentType: "inline",
script: `
const socket = new WebSocket('${wsUrl}')
// reload(true) ensures resources like images and scripts are fetched again in firefox
socket.addEventListener('message', () => document.location.reload(true))
`,
})
}
return staticResources
}

View File

@ -42,21 +42,25 @@ export const Description: QuartzTransformerPlugin<Partial<Options> | undefined>
const finalDesc: string[] = []
const len = opts.descriptionLength
let sentenceIdx = 0
let currentDescriptionLength = 0
if (sentences[0] !== undefined && sentences[0].length >= len) {
const firstSentence = sentences[0].split(" ")
while (finalDesc.length < len) {
while (currentDescriptionLength < len) {
const sentence = firstSentence[sentenceIdx]
if (!sentence) break
finalDesc.push(sentence)
currentDescriptionLength += sentence.length
sentenceIdx++
}
finalDesc.push("...")
} else {
while (finalDesc.length < len) {
while (currentDescriptionLength < len) {
const sentence = sentences[sentenceIdx]
if (!sentence) break
finalDesc.push(sentence.endsWith(".") ? sentence : sentence + ".")
const currentSentence = sentence.endsWith(".") ? sentence : sentence + "."
finalDesc.push(currentSentence)
currentDescriptionLength += currentSentence.length
sentenceIdx++
}
}

View File

@ -90,6 +90,7 @@ declare module "vfile" {
description: string
publish: boolean
draft: boolean
lang: string
enableToc: string
cssclasses: string[]
}>

View File

@ -22,6 +22,7 @@ export interface Theme {
}
cdnCaching: boolean
colors: Colors
fontOrigin: "googleFonts" | "local"
}
export type ThemeKey = keyof Colors