Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…uartz into v4
  • Loading branch information
Mara-Li authored Mar 15, 2024
2 parents e24364a + a25fd70 commit ce5207e
Show file tree
Hide file tree
Showing 13 changed files with 170 additions and 116 deletions.
2 changes: 2 additions & 0 deletions quartz/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ async function partialRebuildFromEntrypoint(
}
await rimraf([...destinationsToDelete]);

console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`));

toRemove.clear();
release();
clientRefresh();
Expand Down
22 changes: 14 additions & 8 deletions quartz/components/ContentMeta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>) => {
Expand All @@ -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))
Expand All @@ -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
6 changes: 4 additions & 2 deletions quartz/components/Head.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { i18n } from "../i18n";
import { FullSlug, joinSegments, pathToRoot, sluggify } from "../util/path";
import { FullSlug, joinSegments, pathToRoot } from "../util/path";
import { JSResourceToScriptElement } from "../util/resources";
import { googleFontHref } from "../util/theme";
import { getMetaImage } from "./scripts/util";
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types";

Expand All @@ -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" />
Expand Down
3 changes: 2 additions & 1 deletion quartz/components/renderPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down
1 change: 1 addition & 0 deletions quartz/components/scripts/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Data } from "vfile";

import { GlobalConfiguration } from "../../cfg";
import { sluggify } from "../../util/path";

Expand Down
14 changes: 14 additions & 0 deletions quartz/components/styles/contentMeta.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.content-meta {
margin-top: 0;
color: var(--gray);

&[show-comma="true"] {
> span:not(:last-child) {
margin-right: 8px;

&::after {
content: ",";
}
}
}
}
155 changes: 53 additions & 102 deletions quartz/plugins/emitters/componentResources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import DepGraph from "../../depgraph";
import styles from "../../styles/custom.scss";
import { BuildCtx } from "../../util/ctx";
import { FilePath, FullSlug, joinSegments } from "../../util/path";
import { StaticResources } from "../../util/resources";
import { googleFontHref, joinStyles } from "../../util/theme";
import { QuartzEmitterPlugin } from "../types";
import { write } from "./helpers";
Expand Down Expand Up @@ -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) {
Expand All @@ -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());
Expand Down Expand Up @@ -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;

const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g;

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(".");

googleFontsStyleSheet = googleFontsStyleSheet.replace(
url,
`/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),
}),
),
);
}
} 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;

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(".");

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),
}),
),
);
}
}

// 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,
Expand Down Expand Up @@ -304,4 +255,4 @@ export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<
return await Promise.all(promises);
},
};
};
};
17 changes: 17 additions & 0 deletions quartz/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Loading

0 comments on commit ce5207e

Please sign in to comment.