This commit is contained in:
semanticdata 2024-02-08 15:25:55 -06:00
commit 31e2c63053
9 changed files with 136 additions and 15 deletions

View File

@ -34,6 +34,7 @@ This part of the configuration concerns anything that can affect the whole site.
- `ignorePatterns`: a list of [glob](<https://en.wikipedia.org/wiki/Glob_(programming)>) patterns that Quartz should ignore and not search through when looking for files inside the `content` folder. See [[private pages]] for more details.
- `defaultDateType`: whether to use created, modified, or published as the default date to display on pages and page listings.
- `theme`: configure how the site looks.
- `cdnCaching`: Whether to use Google CDN to cache the fonts (generally will be faster). Disable this if you want Quartz to be self-contained. Default to `true`
- `typography`: what fonts to use. Any font available on [Google Fonts](https://fonts.google.com/) works here.
- `header`: Font to use for headers
- `code`: Font for inline and block quotes.

View File

@ -14,6 +14,7 @@ const config: QuartzConfig = {
ignorePatterns: ["private", "templates"],
defaultDateType: "modified",
theme: {
cdnCaching: true,
typography: {
header: "Bitter", // Schibsted Grotesk
body: "Poppins", // Source Sans Pro, Poppins

View File

@ -30,8 +30,12 @@ export default (() => {
<link rel="icon" href={iconPath} />
<meta name="description" content={description} />
<meta name="generator" content="Quartz" />
{cfg.theme.cdnCaching && (
<>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
</>
)}
{css.map((href) => (
<link key={href} href={href} rel="stylesheet" type="text/css" spa-preserve />
))}

View File

@ -209,8 +209,7 @@ export function renderPage(
</div>
)
const lang = componentData.frontmatter?.lang ?? cfg.locale.split("-")[0]
const lang = componentData.frontmatter?.lang ?? cfg.locale?.split("-")[0] ?? "en"
const doc = (
<html lang="en">
<Head {...componentData} />

View File

@ -6,6 +6,7 @@ import de from "./locales/de-DE"
import nl from "./locales/nl-NL"
import ro from "./locales/ro-RO"
import es from "./locales/es-ES"
import uk from "./locales/uk-UA"
export const TRANSLATIONS = {
"en-US": en,
@ -14,8 +15,11 @@ export const TRANSLATIONS = {
"de-DE": de,
"nl-NL": nl,
"ro-RO": ro,
"ro-MD": ro,
"es-ES": es,
"uk-UA": uk,
} as const
export const i18n = (locale: ValidLocale): Translation => TRANSLATIONS[locale ?? "en-US"]
export const defaultTranslation = "en-US"
export const i18n = (locale: ValidLocale): Translation => TRANSLATIONS[locale ?? defaultTranslation]
export type ValidLocale = keyof typeof TRANSLATIONS

View File

@ -0,0 +1,65 @@
import { Translation } from "./definition"
export default {
propertyDefaults: {
title: "Без назви",
description: "Опис не надано",
},
components: {
backlinks: {
title: "Зворотні посилання",
noBacklinksFound: "Зворотних посилань не знайдено",
},
themeToggle: {
lightMode: "Світлий режим",
darkMode: "Темний режим",
},
explorer: {
title: "Провідник",
},
footer: {
createdWith: "Створено за допомогою",
},
graph: {
title: "Вигляд графа",
},
recentNotes: {
title: "Останні нотатки",
seeRemainingMore: ({ remaining }) => `Переглянути ще ${remaining}`,
},
transcludes: {
transcludeOf: ({ targetSlug }) => `Видобуто з ${targetSlug}`,
linkToOriginal: "Посилання на оригінал",
},
search: {
title: "Пошук",
searchBarPlaceholder: "Шукати щось",
},
tableOfContents: {
title: "Зміст",
},
},
pages: {
rss: {
recentNotes: "Останні нотатки",
lastFewNotes: ({ count }) => `Останні нотатки: ${count}`,
},
error: {
title: "Не знайдено",
notFound: "Ця сторінка або приватна, або не існує.",
},
folderContent: {
folder: "Папка",
itemsUnderFolder: ({ count }) =>
count === 1 ? "У цій папці 1 елемент" : `Елементів у цій папці: ${count}.`,
},
tagContent: {
tag: "Тег",
tagIndex: "Індекс тегу",
itemsUnderTag: ({ count }) =>
count === 1 ? "1 елемент з цим тегом" : `Елементів з цим тегом: ${count}.`,
showingFirst: ({ count }) => `Показ перших ${count} тегів.`,
totalTags: ({ count }) => `Всього знайдено тегів: ${count}.`,
},
},
} as const satisfies Translation

View File

@ -1,4 +1,4 @@
import { FilePath, FullSlug } from "../../util/path"
import { FilePath, FullSlug, joinSegments } from "../../util/path"
import { QuartzEmitterPlugin } from "../types"
// @ts-ignore
@ -119,7 +119,7 @@ function addGlobalPageResources(
} else if (cfg.analytics?.provider === "umami") {
componentResources.afterDOMLoaded.push(`
const umamiScript = document.createElement("script")
umamiScript.src = cfg.analytics.host ?? "https://analytics.umami.is/script.js"
umamiScript.src = ${cfg.analytics.host} ?? "https://analytics.umami.is/script.js"
umamiScript.setAttribute("data-website-id", "${cfg.analytics.websiteId}")
umamiScript.async = true
@ -172,27 +172,72 @@ export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<
return []
},
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)
// 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
if (fontOrigin === "googleFonts") {
resources.css.push(googleFontHref(ctx.cfg.configuration.theme))
} else if (fontOrigin === "local") {
let googleFontsStyleSheet = ""
if (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, `/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("fonts", filename) as FullSlug,
ext: `.${ext}`,
content: Buffer.from(buf),
}),
),
)
}
}
}
addGlobalPageResources(ctx, resources, componentResources)
const stylesheet = joinStyles(ctx.cfg.configuration.theme, ...componentResources.css, styles)
const stylesheet = joinStyles(
ctx.cfg.configuration.theme,
...componentResources.css,
googleFontsStyleSheet,
styles,
)
const [prescript, postscript] = await Promise.all([
joinScripts(componentResources.beforeDOMLoaded),
joinScripts(componentResources.afterDOMLoaded),
])
const fps = await Promise.all([
promises.push(
write({
ctx,
slug: "index" as FullSlug,
@ -223,8 +268,9 @@ export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<
ext: ".js",
content: postscript,
}),
])
return fps
)
return await Promise.all(promises)
},
}
}

View File

@ -7,7 +7,7 @@ type WriteOptions = {
ctx: BuildCtx
slug: FullSlug
ext: `.${string}` | ""
content: string
content: string | Buffer
}
export const write = async ({ ctx, slug, ext, content }: WriteOptions): Promise<FilePath> => {

View File

@ -15,6 +15,7 @@ export interface Theme {
body: string
code: string
}
cdnCaching: boolean
colors: {
lightMode: ColorScheme
darkMode: ColorScheme