Skip to content

Commit

Permalink
googlefonts configuration option (**experimental and temporary**)
Browse files Browse the repository at this point in the history
ref. #423
  • Loading branch information
Fil committed Aug 20, 2024
1 parent 8c341eb commit 01039d4
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 8 deletions.
8 changes: 8 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,11 @@ The set of replacements for straight double and single quotes used when the [**t
## linkify <a href="https://github.com/observablehq/framework/releases/tag/v1.7.0" class="observablehq-version-badge" data-version="^1.7.0" title="Added in 1.7.0"></a>

If true (the default), automatically convert URL-like text to links in Markdown.

<!--
## googlefonts <a href="https://github.com/observablehq/framework/pull/1588" class="observablehq-version-badge" data-version="prerelease" title="Added in #1588"></a>
The URL of a Google Fonts resource. This is a **temporary** configuration element, which will be superseded when fonts are self-hosted (see [#423](https://github.com/observablehq/framework/issues/423)).
-->
4 changes: 2 additions & 2 deletions src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export async function build(
{config}: BuildOptions,
effects: BuildEffects = new FileBuildEffects(config.output, join(config.root, ".observablehq", "cache"))
): Promise<void> {
const {root, loaders, normalizePath} = config;
const {root, loaders, normalizePath, googlefonts} = config;
Telemetry.record({event: "build", step: "start"});

// Make sure all files are readable before starting to write output files.
Expand Down Expand Up @@ -79,7 +79,7 @@ export async function build(
effects.logger.log(faint("(skipped)"));
continue;
}
const resolvers = await getResolvers(page, {root, path: sourceFile, normalizePath, loaders});
const resolvers = await getResolvers(page, {root, path: sourceFile, normalizePath, loaders, googlefonts});
const elapsed = Math.floor(performance.now() - start);
for (const f of resolvers.assets) files.add(resolvePath(sourceFile, f));
for (const f of resolvers.files) files.add(resolvePath(sourceFile, f));
Expand Down
9 changes: 9 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export interface Config {
head: PageFragmentFunction | string | null; // defaults to null
header: PageFragmentFunction | string | null; // defaults to null
footer: PageFragmentFunction | string | null; // defaults to “Built with Observable on [date].”
googlefonts: string | null; // defaults to Source Pro URL
toc: TableOfContents;
style: null | Style; // defaults to {theme: ["light", "dark"]}
search: SearchConfig | null; // default to null
Expand All @@ -105,6 +106,7 @@ export interface ConfigSpec {
head?: unknown;
header?: unknown;
footer?: unknown;
googlefonts?: unknown;
interpreters?: unknown;
title?: unknown;
pages?: unknown;
Expand Down Expand Up @@ -239,6 +241,12 @@ export function normalizeConfig(spec: ConfigSpec = {}, defaultRoot?: string, wat
const head = pageFragment(spec.head === undefined ? "" : spec.head);
const header = pageFragment(spec.header === undefined ? "" : spec.header);
const footer = pageFragment(spec.footer === undefined ? defaultFooter() : spec.footer);
const googlefonts =
spec.googlefonts === undefined
? "https://fonts.googleapis.com/css2?family=Source+Serif+Pro:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700&display=swap"
: spec.googlefonts === null
? null
: String(spec.googlefonts);
const search = spec.search == null || spec.search === false ? null : normalizeSearch(spec.search as any);
const interpreters = normalizeInterpreters(spec.interpreters as any);
const config: Config = {
Expand All @@ -253,6 +261,7 @@ export function normalizeConfig(spec: ConfigSpec = {}, defaultRoot?: string, wat
head,
header,
footer,
googlefonts,
toc,
style,
search,
Expand Down
8 changes: 4 additions & 4 deletions src/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ function handleWatch(socket: WebSocket, req: IncomingMessage, configPromise: Pro

async function watcher(event: WatchEventType, force = false) {
if (!path || !config) throw new Error("not initialized");
const {root, loaders, normalizePath} = config;
const {root, loaders, normalizePath, googlefonts} = config;
switch (event) {
case "rename": {
markdownWatcher?.close();
Expand Down Expand Up @@ -336,7 +336,7 @@ function handleWatch(socket: WebSocket, req: IncomingMessage, configPromise: Pro
clearTimeout(emptyTimeout);
emptyTimeout = null;
}
const resolvers = await getResolvers(page, {root, path, loaders, normalizePath});
const resolvers = await getResolvers(page, {root, path, loaders, normalizePath, googlefonts});
if (hash === resolvers.hash) break;
const previousHash = hash!;
const previousHtml = html!;
Expand Down Expand Up @@ -373,10 +373,10 @@ function handleWatch(socket: WebSocket, req: IncomingMessage, configPromise: Pro
if (path.endsWith("/")) path += "index";
path = join(dirname(path), basename(path, ".html") + ".md");
config = await configPromise;
const {root, loaders, normalizePath} = config;
const {root, loaders, normalizePath, googlefonts} = config;
const source = await readFile(join(root, path), "utf8");
const page = parseMarkdown(source, {path, ...config});
const resolvers = await getResolvers(page, {root, path, loaders, normalizePath});
const resolvers = await getResolvers(page, {root, path, loaders, normalizePath, googlefonts});
if (resolvers.hash !== initialHash) return void send({type: "reload"});
hash = resolvers.hash;
html = getHtml(page, resolvers);
Expand Down
5 changes: 3 additions & 2 deletions src/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface ResolversConfig {
path: string;
normalizePath: (path: string) => string;
loaders: LoaderResolver;
googlefonts: string | null;
}

const defaultImports = [
Expand Down Expand Up @@ -83,7 +84,7 @@ export const builtins = new Map<string, string>([
*/
export async function getResolvers(
page: MarkdownPage,
{root, path, normalizePath, loaders}: ResolversConfig
{root, path, normalizePath, loaders, googlefonts}: ResolversConfig
): Promise<Resolvers> {
const hash = createHash("sha256").update(page.body).update(JSON.stringify(page.data));
const assets = new Set<string>();
Expand All @@ -107,7 +108,7 @@ export async function getResolvers(

// Add stylesheets. TODO Instead of hard-coding Source Serif Pro, parse the
// page’s stylesheet to look for external imports.
stylesheets.add("https://fonts.googleapis.com/css2?family=Source+Serif+Pro:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700&display=swap"); // prettier-ignore
if (googlefonts) stylesheets.add(googlefonts);
if (page.style) stylesheets.add(page.style);

// Collect directly-attached files, local imports, and static imports.
Expand Down
4 changes: 4 additions & 0 deletions test/config-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ describe("readConfig(undefined, root)", () => {
header: "",
footer:
'Built with <a href="https://observablehq.com/" target="_blank">Observable</a> on <a title="2024-01-10T16:00:00">Jan 10, 2024</a>.',
googlefonts:
"https://fonts.googleapis.com/css2?family=Source+Serif+Pro:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700&display=swap",
search: null,
watchPath: resolve("test/input/build/config/observablehq.config.js")
});
Expand All @@ -62,6 +64,8 @@ describe("readConfig(undefined, root)", () => {
header: "",
footer:
'Built with <a href="https://observablehq.com/" target="_blank">Observable</a> on <a title="2024-01-10T16:00:00">Jan 10, 2024</a>.',
googlefonts:
"https://fonts.googleapis.com/css2?family=Source+Serif+Pro:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700&display=swap",
search: null,
watchPath: undefined
});
Expand Down

0 comments on commit 01039d4

Please sign in to comment.