diff options
Diffstat (limited to 'vhosts/blog/nuldoc-src/components')
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/global_footer.ts | 12 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/global_header.ts | 42 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/page_layout.ts | 78 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/post_page_entry.ts | 48 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/slide_page_entry.ts | 45 | ||||
| -rw-r--r-- | vhosts/blog/nuldoc-src/components/utils.ts | 30 |
6 files changed, 255 insertions, 0 deletions
diff --git a/vhosts/blog/nuldoc-src/components/global_footer.ts b/vhosts/blog/nuldoc-src/components/global_footer.ts new file mode 100644 index 00000000..4c9d2457 --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/global_footer.ts @@ -0,0 +1,12 @@ +import { Config } from "../config.ts"; +import { el, Element, text } from "../dom.ts"; + +export function globalFooter(config: Config): Element { + return el( + "footer", + [["class", "footer"]], + text( + `© ${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 new file mode 100644 index 00000000..a5130612 --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/global_header.ts @@ -0,0 +1,42 @@ +import { Config } from "../config.ts"; +import { el, Element, text } from "../dom.ts"; + +export function globalHeader(config: Config): Element { + return el( + "header", + [["class", "header"]], + el( + "nav", + [["class", "nav"]], + el( + "ul", + [], + el( + "li", + [], + el("a", [["href", "/"]], text(config.blog.siteName)), + ), + el( + "li", + [], + el("a", [["href", "/about/"]], text("About")), + ), + el( + "li", + [], + el("a", [["href", "/posts/"]], text("Posts")), + ), + el( + "li", + [], + el("a", [["href", "/slides/"]], text("Slides")), + ), + el( + "li", + [], + el("a", [["href", "/tags/"]], text("Tags")), + ), + ), + ), + ); +} diff --git a/vhosts/blog/nuldoc-src/components/page_layout.ts b/vhosts/blog/nuldoc-src/components/page_layout.ts new file mode 100644 index 00000000..50ed45de --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/page_layout.ts @@ -0,0 +1,78 @@ +import { Config } from "../config.ts"; +import { el, Element, text } from "../dom.ts"; +import { stylesheetLinkElement } from "./utils.ts"; + +type Params = { + metaCopyrightYear: number; + metaDescription: string; + metaKeywords: string[]; + metaTitle: string; + requiresSyntaxHighlight: boolean; +}; + +export async function pageLayout( + { + metaCopyrightYear, + metaDescription, + metaKeywords, + metaTitle, + 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(","), + ]]), + ]), + linkElement("icon", "/favicon.svg", "image/svg+xml"), + el("title", [], text(metaTitle)), + await stylesheetLinkElement("/style.css", config), + ...( + requiresSyntaxHighlight + ? [await stylesheetLinkElement("/hl.css", config)] + : [] + ), + ); + return el( + "html", + [["lang", "ja-JP"]], + head, + body, + ); +} + +function metaElement(attrs: [string, string][]): Element { + return el("meta", attrs); +} + +function linkElement( + rel: string, + href: string, + type: string | null, +): Element { + const attrs: [string, string][] = [["rel", rel], ["href", href]]; + if (type !== null) { + attrs.push(["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 new file mode 100644 index 00000000..685c03a8 --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/post_page_entry.ts @@ -0,0 +1,48 @@ +import { el, Element, text } from "../dom.ts"; +import { + getPostCreatedDate, + getPostUpdatedDate, + PostPage, +} from "../pages/post.ts"; +import { dateToString } from "../revision.ts"; + +export function postPageEntry(post: PostPage): Element { + return el( + "article", + [["class", "post-entry"]], + el( + "a", + [["href", post.href]], + el( + "header", + [["class", "entry-header"]], + el("h2", [], text(post.title)), + ), + el( + "section", + [["class", "entry-content"]], + el("p", [], text(post.summary)), + ), + el( + "footer", + [["class", "entry-footer"]], + el( + "time", + [["datetime", dateToString(getPostCreatedDate(post))]], + text(dateToString(getPostCreatedDate(post))), + ), + text(" 投稿"), + ...(post.revisions.length > 1 + ? [ + text("、"), + el("time", [[ + "datetime", + dateToString(getPostUpdatedDate(post)), + ]], text(dateToString(getPostUpdatedDate(post)))), + text(" 更新"), + ] + : []), + ), + ), + ); +} diff --git a/vhosts/blog/nuldoc-src/components/slide_page_entry.ts b/vhosts/blog/nuldoc-src/components/slide_page_entry.ts new file mode 100644 index 00000000..4767ca2b --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/slide_page_entry.ts @@ -0,0 +1,45 @@ +import { el, Element, text } from "../dom.ts"; +import { getPostCreatedDate, getPostUpdatedDate } from "../pages/post.ts"; +import { SlidePage } from "../pages/slide.ts"; +import { dateToString } from "../revision.ts"; + +export function slidePageEntry(slide: SlidePage): Element { + return el( + "article", + [["class", "post-entry"]], + el( + "a", + [["href", slide.href]], + el( + "header", + [["class", "entry-header"]], + el("h2", [], text(`登壇: ${slide.event} (${slide.talkType})`)), + ), + el( + "section", + [["class", "entry-content"]], + el("p", [], text(slide.title)), + ), + el( + "footer", + [["class", "entry-footer"]], + el( + "time", + [["datetime", dateToString(getPostCreatedDate(slide))]], + text(dateToString(getPostCreatedDate(slide))), + ), + text(" 登壇"), + ...(slide.revisions.length > 1 + ? [ + text("、"), + el("time", [[ + "datetime", + dateToString(getPostUpdatedDate(slide)), + ]], text(dateToString(getPostUpdatedDate(slide)))), + text(" 更新"), + ] + : []), + ), + ), + ); +} diff --git a/vhosts/blog/nuldoc-src/components/utils.ts b/vhosts/blog/nuldoc-src/components/utils.ts new file mode 100644 index 00000000..f0de71f1 --- /dev/null +++ b/vhosts/blog/nuldoc-src/components/utils.ts @@ -0,0 +1,30 @@ +import { crypto, toHashString } from "std/crypto/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: [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( + filePath: string, +): Promise<string> { + const content = (await Deno.readFile(filePath)).buffer; + return toHashString(await crypto.subtle.digest("MD5", content), "hex"); +} |
