mirror of
https://gitlab.com/MisterBiggs/brain-quartz.git
synced 2025-09-12 00:35:07 +00:00
.github
content
docs
quartz
cli
components
i18n
plugins
processors
static
styles
util
clone.ts
ctx.ts
emoji.ts
emojimap.json
escape.ts
fileTrie.test.ts
fileTrie.ts
glob.ts
jsx.tsx
lang.ts
log.ts
og.tsx
path.test.ts
path.ts
perf.ts
random.ts
resources.tsx
sourcemap.ts
theme.ts
trace.ts
bootstrap-cli.mjs
bootstrap-worker.mjs
build.ts
cfg.ts
worker.ts
.gitattributes
.gitignore
.node-version
.npmrc
.prettierignore
.prettierrc
CODE_OF_CONDUCT.md
Dockerfile
LICENSE.txt
README.md
globals.d.ts
index.d.ts
package-lock.json
package.json
quartz.config.ts
quartz.layout.ts
tsconfig.json
* fix(explorer): vertically center the Explorer toggle under mobile view * Added a separate title font configuration * Added googleSubFontHref function * Applied --titleFont to PageTitle * Made googleFontHref return array of URLs * Dealing with empty and undefined title * Minor update * Dealing with empty and undefined title * Refined font inclusion logic * Adopted the googleFontHref + googleFontSubsetHref method * Adaptively include font subset for PageTitle * Restored default config * Minor changes on configuration docs * Formatted source code
168 lines
4.7 KiB
TypeScript
168 lines
4.7 KiB
TypeScript
export interface ColorScheme {
|
|
light: string
|
|
lightgray: string
|
|
gray: string
|
|
darkgray: string
|
|
dark: string
|
|
secondary: string
|
|
tertiary: string
|
|
highlight: string
|
|
textHighlight: string
|
|
}
|
|
|
|
interface Colors {
|
|
lightMode: ColorScheme
|
|
darkMode: ColorScheme
|
|
}
|
|
|
|
export type FontSpecification =
|
|
| string
|
|
| {
|
|
name: string
|
|
weights?: number[]
|
|
includeItalic?: boolean
|
|
}
|
|
|
|
export interface Theme {
|
|
typography: {
|
|
title?: FontSpecification
|
|
header: FontSpecification
|
|
body: FontSpecification
|
|
code: FontSpecification
|
|
}
|
|
cdnCaching: boolean
|
|
colors: Colors
|
|
fontOrigin: "googleFonts" | "local"
|
|
}
|
|
|
|
export type ThemeKey = keyof Colors
|
|
|
|
const DEFAULT_SANS_SERIF =
|
|
'system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"'
|
|
const DEFAULT_MONO = "ui-monospace, SFMono-Regular, SF Mono, Menlo, monospace"
|
|
|
|
export function getFontSpecificationName(spec: FontSpecification): string {
|
|
if (typeof spec === "string") {
|
|
return spec
|
|
}
|
|
|
|
return spec.name
|
|
}
|
|
|
|
function formatFontSpecification(
|
|
type: "title" | "header" | "body" | "code",
|
|
spec: FontSpecification,
|
|
) {
|
|
if (typeof spec === "string") {
|
|
spec = { name: spec }
|
|
}
|
|
|
|
const defaultIncludeWeights = type === "header" ? [400, 700] : [400, 600]
|
|
const defaultIncludeItalic = type === "body"
|
|
const weights = spec.weights ?? defaultIncludeWeights
|
|
const italic = spec.includeItalic ?? defaultIncludeItalic
|
|
|
|
const features: string[] = []
|
|
if (italic) {
|
|
features.push("ital")
|
|
}
|
|
|
|
if (weights.length > 1) {
|
|
const weightSpec = italic
|
|
? weights
|
|
.flatMap((w) => [`0,${w}`, `1,${w}`])
|
|
.sort()
|
|
.join(";")
|
|
: weights.join(";")
|
|
|
|
features.push(`wght@${weightSpec}`)
|
|
}
|
|
|
|
if (features.length > 0) {
|
|
return `${spec.name}:${features.join(",")}`
|
|
}
|
|
|
|
return spec.name
|
|
}
|
|
|
|
export function googleFontHref(theme: Theme) {
|
|
const { header, body, code } = theme.typography
|
|
const headerFont = formatFontSpecification("header", header)
|
|
const bodyFont = formatFontSpecification("body", body)
|
|
const codeFont = formatFontSpecification("code", code)
|
|
|
|
return `https://fonts.googleapis.com/css2?family=${headerFont}&family=${bodyFont}&family=${codeFont}&display=swap`
|
|
}
|
|
|
|
export function googleFontSubsetHref(theme: Theme, text: string) {
|
|
const title = theme.typography.title || theme.typography.header
|
|
const titleFont = formatFontSpecification("title", title)
|
|
|
|
return `https://fonts.googleapis.com/css2?family=${titleFont}&text=${encodeURIComponent(text)}&display=swap`
|
|
}
|
|
|
|
export interface GoogleFontFile {
|
|
url: string
|
|
filename: string
|
|
extension: string
|
|
}
|
|
|
|
export async function processGoogleFonts(
|
|
stylesheet: string,
|
|
baseUrl: string,
|
|
): Promise<{
|
|
processedStylesheet: string
|
|
fontFiles: GoogleFontFile[]
|
|
}> {
|
|
const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g
|
|
const fontFiles: GoogleFontFile[] = []
|
|
let processedStylesheet = stylesheet
|
|
|
|
let match
|
|
while ((match = fontSourceRegex.exec(stylesheet)) !== null) {
|
|
const url = match[1]
|
|
const [filename, extension] = url.split("/").pop()!.split(".")
|
|
const staticUrl = `https://${baseUrl}/static/fonts/${filename}.${extension}`
|
|
|
|
processedStylesheet = processedStylesheet.replace(url, staticUrl)
|
|
fontFiles.push({ url, filename, extension })
|
|
}
|
|
|
|
return { processedStylesheet, fontFiles }
|
|
}
|
|
|
|
export function joinStyles(theme: Theme, ...stylesheet: string[]) {
|
|
return `
|
|
${stylesheet.join("\n\n")}
|
|
|
|
:root {
|
|
--light: ${theme.colors.lightMode.light};
|
|
--lightgray: ${theme.colors.lightMode.lightgray};
|
|
--gray: ${theme.colors.lightMode.gray};
|
|
--darkgray: ${theme.colors.lightMode.darkgray};
|
|
--dark: ${theme.colors.lightMode.dark};
|
|
--secondary: ${theme.colors.lightMode.secondary};
|
|
--tertiary: ${theme.colors.lightMode.tertiary};
|
|
--highlight: ${theme.colors.lightMode.highlight};
|
|
--textHighlight: ${theme.colors.lightMode.textHighlight};
|
|
|
|
--titleFont: "${getFontSpecificationName(theme.typography.title || theme.typography.header)}", ${DEFAULT_SANS_SERIF};
|
|
--headerFont: "${getFontSpecificationName(theme.typography.header)}", ${DEFAULT_SANS_SERIF};
|
|
--bodyFont: "${getFontSpecificationName(theme.typography.body)}", ${DEFAULT_SANS_SERIF};
|
|
--codeFont: "${getFontSpecificationName(theme.typography.code)}", ${DEFAULT_MONO};
|
|
}
|
|
|
|
:root[saved-theme="dark"] {
|
|
--light: ${theme.colors.darkMode.light};
|
|
--lightgray: ${theme.colors.darkMode.lightgray};
|
|
--gray: ${theme.colors.darkMode.gray};
|
|
--darkgray: ${theme.colors.darkMode.darkgray};
|
|
--dark: ${theme.colors.darkMode.dark};
|
|
--secondary: ${theme.colors.darkMode.secondary};
|
|
--tertiary: ${theme.colors.darkMode.tertiary};
|
|
--highlight: ${theme.colors.darkMode.highlight};
|
|
--textHighlight: ${theme.colors.darkMode.textHighlight};
|
|
}
|
|
`
|
|
}
|