Skip to content

Commit

Permalink
pager config (#247)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock authored Nov 28, 2023
1 parent 6300bb8 commit ac92804
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 23 deletions.
5 changes: 1 addition & 4 deletions docs/.observablehq/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,5 @@ export default {
]
},
{name: "Contributing", path: "/contributing"}
],
toc: {
show: true
}
]
};
6 changes: 4 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface TableOfContents {
export interface Config {
title?: string;
pages: (Page | Section)[]; // TODO rename to sidebar?
pager: boolean; // defaults to true
toc: TableOfContents;
}

Expand Down Expand Up @@ -56,11 +57,12 @@ async function readPages(root: string): Promise<Page[]> {
}

export async function normalizeConfig(spec: any, root: string): Promise<Config> {
let {title, pages = await readPages(root), toc = true} = spec;
let {title, pages = await readPages(root), pager = true, toc = true} = spec;
if (title !== undefined) title = String(title);
pages = Array.from(pages, normalizePageOrSection);
pager = Boolean(pager);
toc = normalizeToc(toc);
return {title, pages, toc};
return {title, pages, pager, toc};
}

function normalizePageOrSection(spec: any): Page | Section {
Expand Down
8 changes: 4 additions & 4 deletions src/pager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ export type PageLink =
| {prev: Page; next: undefined}; // last page

// Pager links in the footer are computed once for a given navigation.
const pagers = new WeakMap<Config["pages"], Map<string, PageLink>>();
const linkCache = new WeakMap<Config["pages"], Map<string, PageLink>>();

export function pager(path: string, options: Pick<Config, "pages" | "title"> = {pages: []}): PageLink | undefined {
export function findLink(path: string, options: Pick<Config, "pages" | "title"> = {pages: []}): PageLink | undefined {
const {pages, title} = options;
let links = pagers.get(pages);
let links = linkCache.get(pages);
if (!links) {
links = new Map<string, PageLink>();
let prev: Page | undefined;
Expand All @@ -24,7 +24,7 @@ export function pager(path: string, options: Pick<Config, "pages" | "title"> = {
prev = page;
}
if (links.size === 1) links.clear(); // no links if only one page
pagers.set(pages, links);
linkCache.set(pages, links);
}
return links.get(path);
}
Expand Down
16 changes: 7 additions & 9 deletions src/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {type Html, html} from "./html.js";
import {type ImportResolver, createImportResolver} from "./javascript/imports.js";
import {type FileReference, type ImportReference} from "./javascript.js";
import {type CellPiece, type ParseResult, parseMarkdown} from "./markdown.js";
import {type PageLink, pager} from "./pager.js";
import {type PageLink, findLink} from "./pager.js";
import {relativeUrl} from "./url.js";

export interface Render {
Expand Down Expand Up @@ -49,11 +49,9 @@ type RenderInternalOptions =
| {preview?: false} // serverless
| {preview: true}; // preview

function render(
parseResult: ParseResult,
{root, path, pages, title, toc, preview, resolver}: RenderOptions & RenderInternalOptions
): string {
toc = mergeToc(parseResult.data?.toc, toc);
function render(parseResult: ParseResult, options: RenderOptions & RenderInternalOptions): string {
const {root, path, pages, title, preview, resolver} = options;
const toc = mergeToc(parseResult.data?.toc, options.toc);
const headers = toc.show ? findHeaders(parseResult) : [];
return String(html`<!DOCTYPE html>
<meta charset="utf-8">${path === "/404" ? html`\n<base href="/">` : ""}
Expand Down Expand Up @@ -83,7 +81,7 @@ ${pages.length > 0 ? renderSidebar(title, pages, path) : ""}
${headers.length > 0 ? renderToc(headers, toc.label) : ""}<div id="observablehq-center">
<main id="observablehq-main" class="observablehq">
${html.unsafe(parseResult.html)}</main>
${renderFooter(path, {pages, title})}
${renderFooter(path, options)}
</div>
`);
}
Expand Down Expand Up @@ -174,8 +172,8 @@ function renderImportPreloads(parseResult: ParseResult, path: string, resolver:
return html`${Array.from(preloads, (href) => html`\n<link rel="modulepreload" href="${href}">`)}`;
}

function renderFooter(path: string, options?: Pick<Config, "pages" | "title">): Html {
const link = pager(path, options);
function renderFooter(path: string, options: Pick<Config, "pages" | "pager" | "title">): Html {
const link = options.pager ? findLink(path, options) : null;
return html`<footer id="observablehq-footer">${link ? renderPager(path, link) : ""}
<div>© ${new Date().getUTCFullYear()} Observable, Inc.</div>
</footer>`;
Expand Down
15 changes: 13 additions & 2 deletions test/config-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ describe("readConfig(root)", () => {
{path: "/sub/two", name: "Two"}
],
title: undefined,
toc: {label: "On this page", show: true}
toc: {label: "On this page", show: true},
pager: true
});
});
it("returns the default config if no config file is found", async () => {
assert.deepStrictEqual(await readConfig("test/input/build/simple"), {
pages: [{name: "Build test case", path: "/simple"}],
title: undefined,
toc: {label: "Contents", show: true}
toc: {label: "Contents", show: true},
pager: true
});
});
});
Expand Down Expand Up @@ -72,6 +74,15 @@ describe("normalizeConfig(spec, root)", () => {
assert.deepStrictEqual((await config({pages: [], toc: true}, root)).toc, {label: "Contents", show: true});
assert.deepStrictEqual((await config({pages: [], toc: false}, root)).toc, {label: "Contents", show: false});
});
it("coerces pager", async () => {
assert.strictEqual((await config({pages: [], pager: 0}, root)).pager, false);
assert.strictEqual((await config({pages: [], pager: 1}, root)).pager, true);
assert.strictEqual((await config({pages: [], pager: ""}, root)).pager, false);
assert.strictEqual((await config({pages: [], pager: "0"}, root)).pager, true);
});
it("populates default pager", async () => {
assert.strictEqual((await config({pages: []}, root)).pager, true);
});
});

describe("mergeToc(spec, toc)", () => {
Expand Down
4 changes: 2 additions & 2 deletions test/pager-test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from "node:assert";
import {pager} from "../src/pager.js";
import {findLink as pager} from "../src/pager.js";

describe("pager(path, options)", () => {
describe("findLink(path, options)", () => {
it("returns the previous and next links for three pages", () => {
const config = {
pages: [
Expand Down

0 comments on commit ac92804

Please sign in to comment.