Changes
5 changed files (+116/-24)
-
-
@@ -54,6 +54,7 @@ const pageBuilder = new DefaultThemeBuilder({copyright: "© 2024 Shota FUJI", faviconSvg: ["Assets", "logo.svg"], faviconPng: ["Assets", "logo-64x64.png"], siteLogo: ["Assets", "logo.svg"], }); const documentTree = await treeBuilder.build({
-
-
-
@@ -54,8 +54,8 @@ - [x] Document sorting- [ ] Search functionality - [ ] Creation / Update date - [ ] Tags - [ ] Config for site logo - [ ] Tool's logo - [x] Config for site logo - [x] Tool's logo - [ ] Proper styling - [ ] Switch to drawer menu when side navigation cannot fit - [ ] CLI for opinionated build
-
-
-
@@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0/** @jsx h */ import { extname } from "../../deps/deno.land/std/path/mod.ts"; import { h, renderSSR } from "../../deps/deno.land/x/nano_jsx/mod.ts"; import type { BuildParameters, PageBuilder } from "../interface.ts";
-
@@ -27,6 +28,13 @@ function isJSONCanvas(x: Document): x is Document<JSONCanvasDocument> {return x.content.kind === "json_canvas"; } export interface Assets { globalCss: readonly string[]; faviconSvg?: readonly string[]; faviconPng?: readonly string[]; siteLogo?: readonly string[]; } interface InnerBuildParameters { item: DocumentDirectory | Document;
-
@@ -37,6 +45,8 @@pathPrefix?: readonly string[]; buildParameters: Omit<BuildParameters, "documentTree">; assets: Assets; } export interface DefaultThemeBuilderConstructorParameters {
-
@@ -56,20 +66,27 @@ /*** Path to the PNG file to use as a favicon from the root directory (FileSystem Reader). */ faviconPng?: readonly string[]; /** * Path to the website's logo or icon image from the root directory (FileSystem Reader). */ siteLogo?: readonly string[]; } export class DefaultThemeBuilder implements PageBuilder { #copyright: string; #faviconSvg?: readonly string[]; #faviconPng?: readonly string[]; #siteLogo?: readonly string[]; constructor( { copyright, faviconSvg, faviconPng }: { copyright, faviconSvg, faviconPng, siteLogo }: DefaultThemeBuilderConstructorParameters, ) { this.#copyright = copyright; this.#faviconPng = faviconPng; this.#faviconSvg = faviconSvg; this.#siteLogo = siteLogo; } async build(
-
@@ -79,25 +96,42 @@ const styles = css.serialize(Html.styles, ); const assets: Assets = { globalCss: ["assets", "global.css"], }; await fileSystemWriter.write( ["assets", "global.css"], assets.globalCss, new TextEncoder().encode(styles), ); if (this.#faviconSvg) { assets.faviconSvg = ["favicon.svg"]; await fileSystemWriter.write( ["favicon.svg"], assets.faviconSvg, await (fileSystemReader.readFile(this.#faviconSvg)), ); } if (this.#faviconPng) { assets.faviconPng = ["favicon.png"]; await fileSystemWriter.write( ["favicon.png"], assets.faviconPng, await (fileSystemReader.readFile(this.#faviconPng)), ); } if (this.#siteLogo) { const ext = extname(this.#siteLogo[this.#siteLogo.length - 1]); assets.siteLogo = ["assets", `logo.${ext}`]; await fileSystemWriter.write( assets.siteLogo, await (fileSystemReader.readFile(this.#siteLogo)), ); } await Promise.all(documentTree.nodes.map((item) => this.#build({ item,
-
@@ -105,12 +139,13 @@ tree: documentTree,parentLanguage: documentTree.defaultLanguage, pathPrefix: [], buildParameters: { fileSystemWriter, fileSystemReader }, assets, }) )); } async #build( { item, tree, parentLanguage, pathPrefix = [], buildParameters }: { item, tree, parentLanguage, pathPrefix = [], buildParameters, assets }: InnerBuildParameters, ): Promise<void> { const { fileSystemWriter } = buildParameters;
-
@@ -126,8 +161,7 @@ tree={tree}document={item} language={item.metadata.language || parentLanguage} copyright={this.#copyright} hasFaviconSvg={!!this.#faviconSvg} hasFaviconPng={!!this.#faviconPng} assets={assets} /> </PathResolverProvider> ),
-
@@ -153,6 +187,7 @@ tree,parentLanguage: item.metadata.language || parentLanguage, pathPrefix: [...pathPrefix, item.metadata.name], buildParameters, assets, }) )); }
-
-
-
@@ -23,6 +23,7 @@ import * as css from "../css.ts";import { globalStyles } from "./global_styles.ts"; import { mapTocItem, tocMut } from "../hast/hast_util_toc_mut.ts"; import type { Assets } from "../builder.tsx"; import * as DocumentTreeUI from "./organisms/document_tree.tsx"; import * as Footer from "./organisms/footer.tsx";
-
@@ -78,7 +79,7 @@ content: ObsidianMarkdownDocument;} function ObsidianMarkdownBody( { content, document, tree, copyright }: ObsidianMarkdownBodyProps, { content, document, tree, copyright, assets }: ObsidianMarkdownBodyProps, ) { const hast = toHast(content.content);
-
@@ -98,6 +99,7 @@ currentPath={document.path}/> } footer={<Footer.View copyright={copyright} />} logoImage={assets.siteLogo} > <h1>{document.metadata.title}</h1> {contentNodes}
-
@@ -110,7 +112,7 @@ content: JSONCanvasDocument;} function JSONCanvasBody( { content, document, copyright, tree }: JSONCanvasBodyProps, { content, document, copyright, tree, assets }: JSONCanvasBodyProps, ) { return ( <SiteLayout.View
-
@@ -121,6 +123,7 @@ currentPath={document.path}/> } footer={<Footer.View copyright={copyright} />} logoImage={assets.siteLogo} > <h1>{document.metadata.title}</h1> <JSONCanvasRenderer.View data={content.content} />
-
@@ -140,12 +143,11 @@ language: string;copyright: string; hasFaviconSvg?: boolean; hasFaviconPng?: boolean; assets: Assets; } export function View( { hasFaviconPng, hasFaviconSvg, ...props }: ViewProps, { assets, ...props }: ViewProps, ) { const { document, language } = props;
-
@@ -161,25 +163,37 @@ <linkrel="stylesheet" href={path.resolve(["assets", "global.css"])} /> {hasFaviconSvg && ( {assets.faviconSvg && ( <link rel="icon" type="image/svg+xml" href={path.resolve(["favicon.svg"])} href={path.resolve(assets.faviconSvg)} /> )} {hasFaviconPng && ( {assets.faviconPng && ( <link rel="icon" type="image/png" href={path.resolve(["favicon.png"])} href={path.resolve(assets.faviconPng)} /> )} </head> <body> {document.content.kind === "json_canvas" ? <JSONCanvasBody content={document.content} {...props} /> : <ObsidianMarkdownBody content={document.content} {...props} />} ? ( <JSONCanvasBody content={document.content} assets={assets} {...props} /> ) : ( <ObsidianMarkdownBody content={document.content} assets={assets} {...props} /> )} </body> </html> );
-
-
-
@@ -6,12 +6,15 @@ /** @jsx h */import { h } from "../../../../deps/deno.land/x/nano_jsx/mod.ts"; import { usePathResolver } from "../../contexts/path_resolver.tsx"; import { css } from "../../css.ts"; const enum C { Layout = "t-sl--root", NavBg = "t-sl--navbg", HeaderBg = "t-sl--headbg", Header = "t-sl--head", Logo = "t-sl--lg", Nav = "t-sl--nav", NavInner = "t-sl--nav-i", FooterBg = "t-sl--fbg",
-
@@ -23,6 +26,8 @@ }export const styles = css` .${C.Layout} { --_ends-shadow-color: hsl(0deg 0% 0% / 0.03); display: grid; grid-template-columns: minmax(100vw, 1fr); min-height: 100vh;
-
@@ -36,10 +41,17 @@ .${C.Layout} > * > :first-child {margin-block-start: 0; } .${C.NavBg} { .${C.HeaderBg}, .${C.Header} { padding: calc(var(--baseline) * 0.5rem) 16px; } .${C.HeaderBg} { position: sticky; top: calc(var(--baseline) * -1rem); grid-row: 1; grid-column: 1 / -1; margin-block-end: calc(var(--baseline) * 2rem); border-block-end: 1px solid var(--_ends-shadow-color); background-color: var(--color-bg-accent); }
-
@@ -48,6 +60,17 @@ .${C.Header} {grid-row: 1; grid-column: 1; margin-block-end: calc(var(--baseline) * 2rem); display: flex; position: sticky; top: calc(var(--baseline) * -0.5rem); } .${C.Logo} { position: relative; padding: 4px; border-radius: 4px; box-shadow: none; } .${C.Nav} {
-
@@ -78,6 +101,7 @@ .${C.FooterBg} {grid-row: 999; grid-column: 1 / -1; margin-block-start: calc(var(--baseline) * 2rem); border-block-start: 1px solid var(--_ends-shadow-color); background-color: var(--color-bg-accent); }
-
@@ -129,12 +153,30 @@aside?: JSX.ElementChildrenAttribute["children"]; footer: JSX.ElementChildrenAttribute["children"]; logoImage?: readonly string[]; logoSize?: number; } export function View({ children, nav, aside, footer }: ViewProps) { export function View( { children, nav, aside, footer, logoImage, logoSize = 32 }: ViewProps, ) { const path = usePathResolver(); return ( <div className={C.Layout}> <div className={C.NavBg} /> <div className={C.HeaderBg} /> {logoImage && ( <header className={C.Header}> <img className={C.Logo} src={path.resolve(logoImage)} width={logoSize} height={logoSize} /> </header> )} <nav className={C.Nav}> <div className={C.NavInner}>{nav}</div> </nav>
-