diff options
Diffstat (limited to 'vhosts/blog/nuldoc-src/components')
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/GlobalFooter.tsx | 9 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/GlobalHeader.tsx | 27 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/PageLayout.tsx | 63 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/PostPageEntry.tsx | 39 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/SlidePageEntry.tsx | 39 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/StaticScript.tsx | 17 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/StaticStylesheet.tsx | 11 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/global_footer.ts | 10 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/global_header.ts | 26 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/page_layout.ts | 82 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/post_page_entry.ts | 50 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/slide_page_entry.ts | 50 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/utils.ts | 24 |
13 files changed, 206 insertions, 241 deletions
diff --git a/vhosts/blog/nuldoc-src/components/GlobalFooter.tsx b/vhosts/blog/nuldoc-src/components/GlobalFooter.tsx new file mode 100644 index 00000000..757beced --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/GlobalFooter.tsx @@ -0,0 +1,9 @@ +import { Config } from "../config.ts"; + +export default function GlobalFooter({ config }: { config: Config }) { + return ( + <footer className="footer"> + {`© ${config.blog.siteCopyrightYear} ${config.blog.author}`} + </footer> + ); +} diff --git a/vhosts/blog/nuldoc-src/components/GlobalHeader.tsx b/vhosts/blog/nuldoc-src/components/GlobalHeader.tsx new file mode 100644 index 00000000..c0fa7e8b --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/GlobalHeader.tsx @@ -0,0 +1,27 @@ +import { Config } from "../config.ts"; + +export default function GlobalHeader({ config }: { config: Config }) { + return ( + <header className="header"> + <div className="site-logo"> + <a href="/">{config.blog.siteName}</a> + </div> + <nav className="nav"> + <ul> + <li> + <a href="/about/">About</a> + </li> + <li> + <a href="/posts/">Posts</a> + </li> + <li> + <a href="/slides/">Slides</a> + </li> + <li> + <a href="/tags/">Tags</a> + </li> + </ul> + </nav> + </header> + ); +} diff --git a/vhosts/blog/nuldoc-src/components/PageLayout.tsx b/vhosts/blog/nuldoc-src/components/PageLayout.tsx new file mode 100644 index 00000000..c7145e0a --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/PageLayout.tsx @@ -0,0 +1,63 @@ +import { Config } from "../config.ts"; +import { JSXNode } from "myjsx/jsx-runtime"; +import StaticStylesheet from "./StaticStylesheet.tsx"; + +type Props = { + metaCopyrightYear: number; + metaDescription: string; + metaKeywords?: string[]; + metaTitle: string; + metaAtomFeedHref?: string; + requiresSyntaxHighlight?: boolean; + config: Config; + children: JSXNode; +}; + +export default function PageLayout( + { + metaCopyrightYear, + metaDescription, + metaKeywords, + metaTitle, + metaAtomFeedHref, + requiresSyntaxHighlight, + config, + children, + }: Props, +) { + return ( + <html lang="ja-JP"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta name="author" content={config.blog.author} /> + <meta + name="copyright" + content={`© ${metaCopyrightYear} ${config.blog.author}`} + /> + <meta name="description" content={metaDescription} /> + {metaKeywords && metaKeywords.length !== 0 && + <meta name="keywords" content={metaKeywords.join(",")} />} + <meta property="og:type" content="article" /> + <meta property="og:title" content={metaTitle} /> + <meta property="og:description" content={metaDescription} /> + <meta property="og:site_name" content={config.blog.siteName} /> + <meta property="og:locale" content="ja_JP" /> + {metaAtomFeedHref && + ( + <link + rel="alternate" + href={metaAtomFeedHref} + type="application/atom+xml" + /> + )} + <link rel="icon" href="/favicon.svg" type="image/svg+xml" /> + <title>{metaTitle}</title> + <StaticStylesheet fileName="/style.css" config={config} /> + {requiresSyntaxHighlight && + <StaticStylesheet fileName="/hl.css" config={config} />} + </head> + {children} + </html> + ); +} diff --git a/vhosts/blog/nuldoc-src/components/PostPageEntry.tsx b/vhosts/blog/nuldoc-src/components/PostPageEntry.tsx new file mode 100644 index 00000000..2708b009 --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/PostPageEntry.tsx @@ -0,0 +1,39 @@ +import { + getPostPublishedDate, + getPostUpdatedDate, + postHasAnyUpdates, + PostPage, +} from "../generators/post.ts"; +import { dateToString } from "../revision.ts"; + +export default function PostPageEntry({ post }: { post: PostPage }) { + return ( + <article className="post-entry"> + <a href={post.href}> + <header className="entry-header"> + <h2>{post.title}</h2> + </header> + <section className="entry-content"> + <p>{post.description}</p> + </section> + <footer className="entry-footer"> + <time datetime={dateToString(getPostPublishedDate(post))}> + {dateToString(getPostPublishedDate(post))} + </time> + {" 投稿"} + { + // TODO(jsx): support Fragment and merge them. + postHasAnyUpdates(post) && "、" + } + {postHasAnyUpdates(post) && + ( + <time datetime={dateToString(getPostUpdatedDate(post))}> + {dateToString(getPostUpdatedDate(post))} + </time> + )} + {postHasAnyUpdates(post) && " 更新"} + </footer> + </a> + </article> + ); +} diff --git a/vhosts/blog/nuldoc-src/components/SlidePageEntry.tsx b/vhosts/blog/nuldoc-src/components/SlidePageEntry.tsx new file mode 100644 index 00000000..d2cf9a17 --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/SlidePageEntry.tsx @@ -0,0 +1,39 @@ +import { + getPostPublishedDate, + getPostUpdatedDate, + postHasAnyUpdates, +} from "../generators/post.ts"; +import { SlidePage } from "../generators/slide.ts"; +import { dateToString } from "../revision.ts"; + +export default function SlidePageEntry({ slide }: { slide: SlidePage }) { + return ( + <article className="post-entry"> + <a href={slide.href}> + <header className="entry-header"> + <h2>{slide.description}</h2> + </header> + <section className="entry-content"> + <p>{slide.title}</p> + </section> + <footer className="entry-footer"> + <time datetime={dateToString(getPostPublishedDate(slide))}> + {dateToString(getPostPublishedDate(slide))} + </time> + {" 登壇"} + { + // TODO(jsx): support Fragment and merge them. + postHasAnyUpdates(slide) && "、" + } + {postHasAnyUpdates(slide) && + ( + <time datetime={dateToString(getPostUpdatedDate(slide))}> + {dateToString(getPostUpdatedDate(slide))} + </time> + )} + {postHasAnyUpdates(slide) && " 更新"} + </footer> + </a> + </article> + ); +} diff --git a/vhosts/blog/nuldoc-src/components/StaticScript.tsx b/vhosts/blog/nuldoc-src/components/StaticScript.tsx new file mode 100644 index 00000000..eb26ada7 --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/StaticScript.tsx @@ -0,0 +1,17 @@ +import { join } from "std/path/mod.ts"; +import { Config } from "../config.ts"; +import { calculateFileHash } from "./utils.ts"; + +export default async function StaticScript( + { fileName, type, config }: { + fileName: string; + type?: string; + config: Config; + }, +) { + const filePath = join(Deno.cwd(), config.locations.staticDir, fileName); + const hash = await calculateFileHash(filePath); + return ( + <script src={`${fileName}?h=${hash}`} {...(type ? { type } : {})}></script> + ); +} diff --git a/vhosts/blog/nuldoc-src/components/StaticStylesheet.tsx b/vhosts/blog/nuldoc-src/components/StaticStylesheet.tsx new file mode 100644 index 00000000..5c2c2a0f --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/StaticStylesheet.tsx @@ -0,0 +1,11 @@ +import { join } from "std/path/mod.ts"; +import { Config } from "../config.ts"; +import { calculateFileHash } from "./utils.ts"; + +export default async function StaticStylesheet( + { fileName, config }: { fileName: string; config: Config }, +) { + const filePath = join(Deno.cwd(), config.locations.staticDir, fileName); + const hash = await calculateFileHash(filePath); + return <link rel="stylesheet" href={`${fileName}?h=${hash}`} />; +} diff --git a/vhosts/blog/nuldoc-src/components/global_footer.ts b/vhosts/blog/nuldoc-src/components/global_footer.ts deleted file mode 100644 index 7fdc8797..00000000 --- a/vhosts/blog/nuldoc-src/components/global_footer.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Config } from "../config.ts"; -import { el, Element } from "../dom.ts"; - -export function globalFooter(config: Config): Element { - return el( - "footer", - { className: "footer" }, - `© ${config.blog.siteCopyrightYear} ${config.blog.author}`, - ); -} diff --git a/vhosts/blog/nuldoc-src/components/global_header.ts b/vhosts/blog/nuldoc-src/components/global_header.ts deleted file mode 100644 index 166c48ff..00000000 --- a/vhosts/blog/nuldoc-src/components/global_header.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Config } from "../config.ts"; -import { el, Element } from "../dom.ts"; - -export function globalHeader(config: Config): Element { - return el( - "header", - { className: "header" }, - el( - "div", - { className: "site-logo" }, - el("a", { href: "/" }, config.blog.siteName), - ), - el( - "nav", - { className: "nav" }, - el( - "ul", - {}, - el("li", {}, el("a", { href: "/about/" }, "About")), - el("li", {}, el("a", { href: "/posts/" }, "Posts")), - el("li", {}, el("a", { href: "/slides/" }, "Slides")), - el("li", {}, el("a", { href: "/tags/" }, "Tags")), - ), - ), - ); -} diff --git a/vhosts/blog/nuldoc-src/components/page_layout.ts b/vhosts/blog/nuldoc-src/components/page_layout.ts deleted file mode 100644 index a6b75d01..00000000 --- a/vhosts/blog/nuldoc-src/components/page_layout.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Config } from "../config.ts"; -import { el, Element } from "../dom.ts"; -import { stylesheetLinkElement } from "./utils.ts"; - -type Params = { - metaCopyrightYear: number; - metaDescription: string; - metaKeywords: string[]; - metaTitle: string; - metaAtomFeedHref?: string; - requiresSyntaxHighlight: boolean; -}; - -export async function pageLayout( - { - metaCopyrightYear, - metaDescription, - metaKeywords, - metaTitle, - metaAtomFeedHref, - requiresSyntaxHighlight, - }: Params, - body: Element, - config: Config, -): Promise<Element> { - const head = el( - "head", - {}, - metaElement({ charset: "UTF-8" }), - metaElement({ - name: "viewport", - content: "width=device-width, initial-scale=1.0", - }), - metaElement({ name: "author", content: config.blog.author }), - metaElement({ - name: "copyright", - content: `© ${metaCopyrightYear} ${config.blog.author}`, - }), - metaElement({ name: "description", content: metaDescription }), - ...(metaKeywords.length === 0 ? [] : [ - metaElement({ name: "keywords", content: metaKeywords.join(",") }), - ]), - metaElement({ property: "og:type", content: "article" }), - metaElement({ property: "og:title", content: metaTitle }), - metaElement({ property: "og:description", content: metaDescription }), - metaElement({ property: "og:site_name", content: config.blog.siteName }), - metaElement({ property: "og:locale", content: "ja_JP" }), - ...(metaAtomFeedHref - ? [linkElement("alternate", metaAtomFeedHref, "application/atom+xml")] - : []), - linkElement("icon", "/favicon.svg", "image/svg+xml"), - el("title", {}, metaTitle), - await stylesheetLinkElement("/style.css", config), - ...( - requiresSyntaxHighlight - ? [await stylesheetLinkElement("/hl.css", config)] - : [] - ), - ); - return el( - "html", - { lang: "ja-JP" }, - head, - body, - ); -} - -function metaElement(attrs: Record<string, string>): Element { - return el("meta", attrs); -} - -function linkElement( - rel: string, - href: string, - type: string | null, -): Element { - const attrs: Record<string, string> = { rel: rel, href: href }; - if (type !== null) { - attrs.type = type; - } - return el("link", attrs); -} diff --git a/vhosts/blog/nuldoc-src/components/post_page_entry.ts b/vhosts/blog/nuldoc-src/components/post_page_entry.ts deleted file mode 100644 index bd82eb95..00000000 --- a/vhosts/blog/nuldoc-src/components/post_page_entry.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { el, Element } from "../dom.ts"; -import { - getPostPublishedDate, - getPostUpdatedDate, - postHasAnyUpdates, - PostPage, -} from "../pages/post.ts"; -import { dateToString } from "../revision.ts"; - -export function postPageEntry(post: PostPage): Element { - return el( - "article", - { className: "post-entry" }, - el( - "a", - { href: post.href }, - el( - "header", - { className: "entry-header" }, - el("h2", {}, post.title), - ), - el( - "section", - { className: "entry-content" }, - el("p", {}, post.description), - ), - el( - "footer", - { className: "entry-footer" }, - el( - "time", - { datetime: dateToString(getPostPublishedDate(post)) }, - dateToString(getPostPublishedDate(post)), - ), - " 投稿", - ...(postHasAnyUpdates(post) - ? [ - "、", - el( - "time", - { "datetime": dateToString(getPostUpdatedDate(post)) }, - dateToString(getPostUpdatedDate(post)), - ), - " 更新", - ] - : []), - ), - ), - ); -} diff --git a/vhosts/blog/nuldoc-src/components/slide_page_entry.ts b/vhosts/blog/nuldoc-src/components/slide_page_entry.ts deleted file mode 100644 index e64a4022..00000000 --- a/vhosts/blog/nuldoc-src/components/slide_page_entry.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { el, Element } from "../dom.ts"; -import { - getPostPublishedDate, - getPostUpdatedDate, - postHasAnyUpdates, -} from "../pages/post.ts"; -import { SlidePage } from "../pages/slide.ts"; -import { dateToString } from "../revision.ts"; - -export function slidePageEntry(slide: SlidePage): Element { - return el( - "article", - { className: "post-entry" }, - el( - "a", - { href: slide.href }, - el( - "header", - { className: "entry-header" }, - el("h2", {}, slide.description), - ), - el( - "section", - { className: "entry-content" }, - el("p", {}, slide.title), - ), - el( - "footer", - { className: "entry-footer" }, - el( - "time", - { datetime: dateToString(getPostPublishedDate(slide)) }, - dateToString(getPostPublishedDate(slide)), - ), - " 登壇", - ...(postHasAnyUpdates(slide) - ? [ - "、", - el( - "time", - { "datetime": dateToString(getPostUpdatedDate(slide)) }, - dateToString(getPostUpdatedDate(slide)), - ), - " 更新", - ] - : []), - ), - ), - ); -} diff --git a/vhosts/blog/nuldoc-src/components/utils.ts b/vhosts/blog/nuldoc-src/components/utils.ts index ce693100..14059b5b 100644 --- a/vhosts/blog/nuldoc-src/components/utils.ts +++ b/vhosts/blog/nuldoc-src/components/utils.ts @@ -1,28 +1,6 @@ import { Hash } from "checksum/mod.ts"; -import { join } from "std/path/mod.ts"; -import { Config } from "../config.ts"; -import { el, Element } from "../dom.ts"; -export async function stylesheetLinkElement( - fileName: string, - config: Config, -): Promise<Element> { - const filePath = join(Deno.cwd(), config.locations.staticDir, fileName); - const hash = await calculateFileHash(filePath); - return el("link", { rel: "stylesheet", href: `${fileName}?h=${hash}` }); -} - -export async function staticScriptElement( - fileName: string, - attrs: Record<string, string>, - config: Config, -): Promise<Element> { - const filePath = join(Deno.cwd(), config.locations.staticDir, fileName); - const hash = await calculateFileHash(filePath); - return el("script", { src: `${fileName}?h=${hash}`, ...attrs }); -} - -async function calculateFileHash( +export async function calculateFileHash( filePath: string, ): Promise<string> { const content = await Deno.readFile(filePath); |
