mirror of
https://github.com/jackyzha0/quartz.git
synced 2026-03-24 23:15:46 -05:00
Merge branch 'v4' of https://github.com/jackyzha0/quartz
This commit is contained in:
commit
95da75f003
@ -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(),
|
||||
|
||||
@ -309,6 +309,8 @@ async function partialRebuildFromEntrypoint(
|
||||
}
|
||||
await rimraf([...destinationsToDelete])
|
||||
|
||||
console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`))
|
||||
|
||||
toRemove.clear()
|
||||
release()
|
||||
clientRefresh()
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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" />
|
||||
|
||||
@ -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} />
|
||||
|
||||
14
quartz/components/styles/contentMeta.scss
Normal file
14
quartz/components/styles/contentMeta.scss
Normal 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: ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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,71 +141,29 @@ 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 {
|
||||
} 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
|
||||
@ -228,7 +180,7 @@ export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<
|
||||
|
||||
googleFontsStyleSheet = googleFontsStyleSheet.replace(
|
||||
url,
|
||||
`/static/fonts/${filename}.ttf`,
|
||||
`https://${cfg.baseUrl}/static/fonts/${filename}.ttf`,
|
||||
)
|
||||
|
||||
promises.push(
|
||||
@ -250,12 +202,11 @@ export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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++
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +90,7 @@ declare module "vfile" {
|
||||
description: string
|
||||
publish: boolean
|
||||
draft: boolean
|
||||
lang: string
|
||||
enableToc: string
|
||||
cssclasses: string[]
|
||||
}>
|
||||
|
||||
@ -22,6 +22,7 @@ export interface Theme {
|
||||
}
|
||||
cdnCaching: boolean
|
||||
colors: Colors
|
||||
fontOrigin: "googleFonts" | "local"
|
||||
}
|
||||
|
||||
export type ThemeKey = keyof Colors
|
||||
|
||||
Loading…
Reference in New Issue
Block a user