Changes
7 changed files (+139/-4)
-
-
-
@@ -50,7 +50,11 @@ const contentParser = oneof(new JSONCanvasParser(), new ObsidianMarkdownParser(), ); const pageBuilder = new DefaultThemeBuilder("© 2024 Shota FUJI"); const pageBuilder = new DefaultThemeBuilder({ copyright: "© 2024 Shota FUJI", faviconSvg: ["Assets", "logo.svg"], faviconPng: ["Assets", "logo-64x64.png"], }); const documentTree = await treeBuilder.build({ fileSystemReader,
-
-
-
@@ -107,4 +107,8 @@ };return root; } async readFile(path: readonly string[]): Promise<Uint8Array> { return await Deno.readFile(this.#resolve(path)); } }
-
-
-
@@ -9,4 +9,11 @@ /*** Returns the topmost directory this FileSystem Reader can operate on. */ getRootDirectory(): Promise<RootDirectoryReader>; /** * Directly read file contents at given path. * Throws if path does not exist or found directory. * You should traverse from `getRootDirectory()` for most cases. */ readFile(path: readonly string[]): Promise<Uint8Array>; }
-
-
-
@@ -14,6 +14,8 @@ path: string | readonly string[];content: string | Uint8Array; } const SEP = "/"; type InternalTree = Map<string, Uint8Array | InternalTree>; /**
-
@@ -31,7 +33,7 @@ const encoder = new TextEncoder();for (const file of files) { const path = typeof file.path === "string" ? file.path.split("/") ? file.path.split(SEP) : file.path; const content = typeof file.content === "string" ? encoder.encode(file.content)
-
@@ -117,6 +119,56 @@return readers; } async #getAtRecur( path: readonly string[], parent: DirectoryReader | RootDirectoryReader, ): Promise<FileReader | DirectoryReader> { switch (path.length) { case 0: throw new Error("MemoryFsReader: path cannot be empty"); case 1: { const [name] = path; for (const child of await parent.read()) { if (child.name === name) { return child; } } const parentPath = parent.type === "root" ? [] : parent.path; throw new Error( `MemoryFsReader: file or directory not found at ${ [...parentPath, name].join(SEP) }`, ); } default: { const [name, ...rest] = path; for (const child of await parent.read()) { if (child.name === name) { if (child.type === "file") { throw new Error( `MemoryFsReader: ${child.path.join(SEP)} is directory`, ); } return this.#getAtRecur(rest, child); } } const parentPath = parent.type === "root" ? [] : parent.path; throw new Error( `MemoryFsReader: file or directory not found at ${ [...parentPath, name].join(SEP) }`, ); } } } getRootDirectory(): Promise<RootDirectoryReader> { const root: RootDirectoryReader = { type: "root",
-
@@ -124,5 +176,14 @@ read: () => Promise.resolve(this.#mapToReaders(this.#tree, root)),}; return Promise.resolve(root); } async readFile(path: readonly string[]): Promise<Uint8Array> { const file = await this.#getAtRecur(path, await this.getRootDirectory()); if (file.type === "directory") { throw new Error(`MemoryFsReader: ${path.join(SEP)} is directory`); } return file.read(); } }
-
-
-
@@ -39,11 +39,37 @@buildParameters: Omit<BuildParameters, "documentTree">; } export interface DefaultThemeBuilderConstructorParameters { /** * Copyright text to display at website footer. * The page buidler does not add/subtract to the text: do not forget to * include "Copyright" or "©". */ copyright: string; /** * Path to the SVG file to use as a favicon from the root directory (FileSystem Reader). */ faviconSvg?: readonly string[]; /** * Path to the PNG file to use as a favicon from the root directory (FileSystem Reader). */ faviconPng?: readonly string[]; } export class DefaultThemeBuilder implements PageBuilder { #copyright: string; #faviconSvg?: readonly string[]; #faviconPng?: readonly string[]; constructor(copyright: string) { constructor( { copyright, faviconSvg, faviconPng }: DefaultThemeBuilderConstructorParameters, ) { this.#copyright = copyright; this.#faviconPng = faviconPng; this.#faviconSvg = faviconSvg; } async build(
-
@@ -58,6 +84,20 @@ ["assets", "global.css"],new TextEncoder().encode(styles), ); if (this.#faviconSvg) { await fileSystemWriter.write( ["favicon.svg"], await (fileSystemReader.readFile(this.#faviconSvg)), ); } if (this.#faviconPng) { await fileSystemWriter.write( ["favicon.png"], await (fileSystemReader.readFile(this.#faviconPng)), ); } await Promise.all(documentTree.nodes.map((item) => this.#build({ item,
-
@@ -86,6 +126,8 @@ tree={tree}document={item} language={item.metadata.language || parentLanguage} copyright={this.#copyright} hasFaviconSvg={!!this.#faviconSvg} hasFaviconPng={!!this.#faviconPng} /> </PathResolverProvider> ),
-
-
-
@@ -139,10 +139,13 @@language: string; copyright: string; hasFaviconSvg?: boolean; hasFaviconPng?: boolean; } export function View( props: ViewProps, { hasFaviconPng, hasFaviconSvg, ...props }: ViewProps, ) { const { document, language } = props;
-
@@ -158,6 +161,20 @@ <linkrel="stylesheet" href={path.resolve(["assets", "global.css"])} /> {hasFaviconSvg && ( <link rel="icon" type="image/svg+xml" href={path.resolve(["favicon.svg"])} /> )} {hasFaviconPng && ( <link rel="icon" type="image/png" href={path.resolve(["favicon.png"])} /> )} </head> <body> {document.content.kind === "json_canvas"
-