From 6dedddc545e2f1930bdc2256784eb1551bd4231d Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 1 Feb 2026 00:49:15 +0900 Subject: feat(nuldoc): rewrite nuldoc in Ruby --- .../nuldoc-src/components/AboutGlobalHeader.ts | 15 ---- .../nuldoc-src/components/BlogGlobalHeader.ts | 28 ------- .../nuldoc-src/components/DefaultGlobalHeader.ts | 15 ---- .../nuldoc/nuldoc-src/components/GlobalFooter.ts | 9 --- .../nuldoc/nuldoc-src/components/PageLayout.ts | 76 ------------------ .../nuldoc/nuldoc-src/components/Pagination.ts | 93 ---------------------- .../nuldoc/nuldoc-src/components/PostPageEntry.ts | 55 ------------- .../nuldoc/nuldoc-src/components/SlidePageEntry.ts | 55 ------------- .../nuldoc-src/components/SlidesGlobalHeader.ts | 27 ------- .../nuldoc/nuldoc-src/components/StaticScript.ts | 26 ------ .../nuldoc-src/components/StaticStylesheet.ts | 21 ----- .../nuldoc-src/components/TableOfContents.ts | 30 ------- services/nuldoc/nuldoc-src/components/TagList.ts | 19 ----- services/nuldoc/nuldoc-src/components/utils.ts | 8 -- 14 files changed, 477 deletions(-) delete mode 100644 services/nuldoc/nuldoc-src/components/AboutGlobalHeader.ts delete mode 100644 services/nuldoc/nuldoc-src/components/BlogGlobalHeader.ts delete mode 100644 services/nuldoc/nuldoc-src/components/DefaultGlobalHeader.ts delete mode 100644 services/nuldoc/nuldoc-src/components/GlobalFooter.ts delete mode 100644 services/nuldoc/nuldoc-src/components/PageLayout.ts delete mode 100644 services/nuldoc/nuldoc-src/components/Pagination.ts delete mode 100644 services/nuldoc/nuldoc-src/components/PostPageEntry.ts delete mode 100644 services/nuldoc/nuldoc-src/components/SlidePageEntry.ts delete mode 100644 services/nuldoc/nuldoc-src/components/SlidesGlobalHeader.ts delete mode 100644 services/nuldoc/nuldoc-src/components/StaticScript.ts delete mode 100644 services/nuldoc/nuldoc-src/components/StaticStylesheet.ts delete mode 100644 services/nuldoc/nuldoc-src/components/TableOfContents.ts delete mode 100644 services/nuldoc/nuldoc-src/components/TagList.ts delete mode 100644 services/nuldoc/nuldoc-src/components/utils.ts (limited to 'services/nuldoc/nuldoc-src/components') diff --git a/services/nuldoc/nuldoc-src/components/AboutGlobalHeader.ts b/services/nuldoc/nuldoc-src/components/AboutGlobalHeader.ts deleted file mode 100644 index df437931..00000000 --- a/services/nuldoc/nuldoc-src/components/AboutGlobalHeader.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Config } from "../config.ts"; -import { a, div, Element, header } from "../dom.ts"; - -export default function GlobalHeader({ config }: { config: Config }): Element { - return header( - { class: "header" }, - div( - { class: "site-logo" }, - a( - { href: `https://${config.sites.default.fqdn}/` }, - "nsfisis.dev", - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/BlogGlobalHeader.ts b/services/nuldoc/nuldoc-src/components/BlogGlobalHeader.ts deleted file mode 100644 index ae0fc13a..00000000 --- a/services/nuldoc/nuldoc-src/components/BlogGlobalHeader.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Config } from "../config.ts"; -import { a, div, Element, header, li, nav, ul } from "../dom.ts"; - -export default function GlobalHeader({ config }: { config: Config }): Element { - return header( - { class: "header" }, - div( - { class: "site-logo" }, - a( - { href: `https://${config.sites.default.fqdn}/` }, - "nsfisis.dev", - ), - ), - div({ class: "site-name" }, config.sites.blog.siteName), - nav( - { class: "nav" }, - ul( - {}, - li( - {}, - a({ href: `https://${config.sites.about.fqdn}/` }, "About"), - ), - li({}, a({ href: "/posts/" }, "Posts")), - li({}, a({ href: "/tags/" }, "Tags")), - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/DefaultGlobalHeader.ts b/services/nuldoc/nuldoc-src/components/DefaultGlobalHeader.ts deleted file mode 100644 index df437931..00000000 --- a/services/nuldoc/nuldoc-src/components/DefaultGlobalHeader.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Config } from "../config.ts"; -import { a, div, Element, header } from "../dom.ts"; - -export default function GlobalHeader({ config }: { config: Config }): Element { - return header( - { class: "header" }, - div( - { class: "site-logo" }, - a( - { href: `https://${config.sites.default.fqdn}/` }, - "nsfisis.dev", - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/GlobalFooter.ts b/services/nuldoc/nuldoc-src/components/GlobalFooter.ts deleted file mode 100644 index 313a01c5..00000000 --- a/services/nuldoc/nuldoc-src/components/GlobalFooter.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Config } from "../config.ts"; -import { Element, footer } from "../dom.ts"; - -export default function GlobalFooter({ config }: { config: Config }): Element { - return footer( - { class: "footer" }, - `© ${config.site.copyrightYear} ${config.site.author}`, - ); -} diff --git a/services/nuldoc/nuldoc-src/components/PageLayout.ts b/services/nuldoc/nuldoc-src/components/PageLayout.ts deleted file mode 100644 index f970c0b6..00000000 --- a/services/nuldoc/nuldoc-src/components/PageLayout.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Config } from "../config.ts"; -import { elem, Element, link, meta, Node } from "../dom.ts"; -import StaticStylesheet from "./StaticStylesheet.ts"; - -type Props = { - metaCopyrightYear: number; - metaDescription: string; - metaKeywords?: string[]; - metaTitle: string; - metaAtomFeedHref?: string; - requiresSyntaxHighlight?: boolean; - site: "default" | "about" | "blog" | "slides"; - config: Config; - children: Node; -}; - -export default async function PageLayout( - { - metaCopyrightYear, - metaDescription, - metaKeywords, - metaTitle, - metaAtomFeedHref, - requiresSyntaxHighlight: _, - site, - config, - children, - }: Props, -): Promise { - return elem( - "html", - { lang: "ja-JP" }, - elem( - "head", - {}, - meta({ charset: "UTF-8" }), - meta({ - name: "viewport", - content: "width=device-width, initial-scale=1.0", - }), - meta({ name: "author", content: config.site.author }), - meta({ - name: "copyright", - content: `© ${metaCopyrightYear} ${config.site.author}`, - }), - meta({ name: "description", content: metaDescription }), - metaKeywords && metaKeywords.length !== 0 - ? meta({ name: "keywords", content: metaKeywords.join(",") }) - : null, - 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.sites[site].siteName, - }), - meta({ property: "og:locale", content: "ja_JP" }), - meta({ name: "Hatena::Bookmark", content: "nocomment" }), - metaAtomFeedHref - ? link({ - rel: "alternate", - href: metaAtomFeedHref, - type: "application/atom+xml", - }) - : null, - link({ - rel: "icon", - href: "/favicon.svg", - type: "image/svg+xml", - }), - elem("title", {}, metaTitle), - await StaticStylesheet({ fileName: "/style.css", config }), - ), - children, - ); -} diff --git a/services/nuldoc/nuldoc-src/components/Pagination.ts b/services/nuldoc/nuldoc-src/components/Pagination.ts deleted file mode 100644 index d9203165..00000000 --- a/services/nuldoc/nuldoc-src/components/Pagination.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { a, div, Element, nav, span } from "../dom.ts"; - -type Props = { - currentPage: number; - totalPages: number; - basePath: string; -}; - -export default function Pagination( - { currentPage, totalPages, basePath }: Props, -): Element { - if (totalPages <= 1) { - return div({}); - } - - const pages = generatePageNumbers(currentPage, totalPages); - - return nav( - { class: "pagination" }, - div( - { class: "pagination-prev" }, - currentPage > 1 - ? a({ href: pageUrlAt(basePath, currentPage - 1) }, "前へ") - : null, - ), - ...pages.map((page) => { - if (page === "...") { - return div({ class: "pagination-elipsis" }, "…"); - } else if (page === currentPage) { - return div( - { class: "pagination-page pagination-page-current" }, - span({}, String(page)), - ); - } else { - return div( - { class: "pagination-page" }, - a({ href: pageUrlAt(basePath, page) }, String(page)), - ); - } - }), - div( - { class: "pagination-next" }, - currentPage < totalPages - ? a({ href: pageUrlAt(basePath, currentPage + 1) }, "次へ") - : null, - ), - ); -} - -type PageItem = number | "..."; - -/** - * Generates page numbers for pagination display. - * - * - Always show the first page - * - Always show the last page - * - Always show the current page - * - Always show the page before and after the current page - * - If there's only one page gap between displayed pages, fill it - * - If there are two or more pages gap between displayed pages, show ellipsis - */ -function generatePageNumbers( - currentPage: number, - totalPages: number, -): PageItem[] { - const pages = new Set(); - pages.add(1); - pages.add(Math.max(1, currentPage - 1)); - pages.add(currentPage); - pages.add(Math.min(totalPages, currentPage + 1)); - pages.add(totalPages); - - const sorted = Array.from(pages).sort((a, b) => a - b); - - const result: PageItem[] = []; - for (let i = 0; i < sorted.length; i++) { - if (i > 0) { - const gap = sorted[i] - sorted[i - 1]; - if (gap === 2) { - result.push(sorted[i - 1] + 1); - } else if (gap > 2) { - result.push("..."); - } - } - result.push(sorted[i]); - } - - return result; -} - -function pageUrlAt(basePath: string, page: number): string { - return page === 1 ? basePath : `${basePath}${page}/`; -} diff --git a/services/nuldoc/nuldoc-src/components/PostPageEntry.ts b/services/nuldoc/nuldoc-src/components/PostPageEntry.ts deleted file mode 100644 index 482a3a8e..00000000 --- a/services/nuldoc/nuldoc-src/components/PostPageEntry.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - getPostPublishedDate, - getPostUpdatedDate, - postHasAnyUpdates, - PostPage, -} from "../generators/post.ts"; -import { dateToString } from "../revision.ts"; -import { Config } from "../config.ts"; -import { - a, - article, - elem, - Element, - footer, - h2, - header, - p, - section, -} from "../dom.ts"; -import TagList from "./TagList.ts"; - -type Props = { post: PostPage; config: Config }; - -export default function PostPageEntry({ post, config }: Props): Element { - return article( - { class: "post-entry" }, - a( - { href: post.href }, - header({ class: "entry-header" }, h2({}, post.title)), - section( - { class: "entry-content" }, - p({}, post.description), - ), - footer( - { class: "entry-footer" }, - elem( - "time", - { datetime: dateToString(getPostPublishedDate(post)) }, - dateToString(getPostPublishedDate(post)), - ), - " 投稿", - postHasAnyUpdates(post) ? "、" : null, - postHasAnyUpdates(post) - ? elem( - "time", - { datetime: dateToString(getPostUpdatedDate(post)) }, - dateToString(getPostUpdatedDate(post)), - ) - : null, - postHasAnyUpdates(post) ? " 更新" : null, - post.tags.length !== 0 ? TagList({ tags: post.tags, config }) : null, - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/SlidePageEntry.ts b/services/nuldoc/nuldoc-src/components/SlidePageEntry.ts deleted file mode 100644 index b48ab4e5..00000000 --- a/services/nuldoc/nuldoc-src/components/SlidePageEntry.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - getPostPublishedDate, - getPostUpdatedDate, - postHasAnyUpdates, -} from "../generators/post.ts"; -import { SlidePage } from "../generators/slide.ts"; -import { dateToString } from "../revision.ts"; -import { Config } from "../config.ts"; -import { - a, - article, - elem, - Element, - footer, - h2, - header, - p, - section, -} from "../dom.ts"; -import TagList from "./TagList.ts"; - -type Props = { slide: SlidePage; config: Config }; - -export default function SlidePageEntry({ slide, config }: Props): Element { - return article( - { class: "post-entry" }, - a( - { href: slide.href }, - header( - { class: "entry-header" }, - h2({}, slide.title), - ), - section({ class: "entry-content" }, p({}, slide.description)), - footer( - { class: "entry-footer" }, - elem( - "time", - { datetime: dateToString(getPostPublishedDate(slide)) }, - dateToString(getPostPublishedDate(slide)), - ), - " 登壇", - postHasAnyUpdates(slide) ? "、" : null, - postHasAnyUpdates(slide) - ? elem( - "time", - { datetime: dateToString(getPostUpdatedDate(slide)) }, - dateToString(getPostUpdatedDate(slide)), - ) - : null, - postHasAnyUpdates(slide) ? " 更新" : null, - slide.tags.length !== 0 ? TagList({ tags: slide.tags, config }) : null, - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/SlidesGlobalHeader.ts b/services/nuldoc/nuldoc-src/components/SlidesGlobalHeader.ts deleted file mode 100644 index 666ca0e3..00000000 --- a/services/nuldoc/nuldoc-src/components/SlidesGlobalHeader.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Config } from "../config.ts"; -import { a, div, Element, header, li, nav, ul } from "../dom.ts"; - -export default function GlobalHeader({ config }: { config: Config }): Element { - return header( - { class: "header" }, - div( - { class: "site-logo" }, - a( - { href: `https://${config.sites.default.fqdn}/` }, - "nsfisis.dev", - ), - ), - nav( - { class: "nav" }, - ul( - {}, - li( - {}, - a({ href: `https://${config.sites.about.fqdn}/` }, "About"), - ), - li({}, a({ href: "/slides/" }, "Slides")), - li({}, a({ href: "/tags/" }, "Tags")), - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/StaticScript.ts b/services/nuldoc/nuldoc-src/components/StaticScript.ts deleted file mode 100644 index 1a3431a3..00000000 --- a/services/nuldoc/nuldoc-src/components/StaticScript.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { join } from "@std/path"; -import { Config } from "../config.ts"; -import { Element, script } from "../dom.ts"; -import { calculateFileHash } from "./utils.ts"; - -export default async function StaticScript( - { site, fileName, type, defer, config }: { - site?: string; - fileName: string; - type?: string; - defer?: "true"; - config: Config; - }, -): Promise { - const filePath = join( - Deno.cwd(), - config.locations.staticDir, - site || "_all", - fileName, - ); - const hash = await calculateFileHash(filePath); - const attrs: Record = { src: `${fileName}?h=${hash}` }; - if (type) attrs.type = type; - if (defer) attrs.defer = defer; - return script(attrs); -} diff --git a/services/nuldoc/nuldoc-src/components/StaticStylesheet.ts b/services/nuldoc/nuldoc-src/components/StaticStylesheet.ts deleted file mode 100644 index f2adb473..00000000 --- a/services/nuldoc/nuldoc-src/components/StaticStylesheet.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { join } from "@std/path"; -import { Config } from "../config.ts"; -import { Element, link } from "../dom.ts"; -import { calculateFileHash } from "./utils.ts"; - -export default async function StaticStylesheet( - { site, fileName, config }: { - site?: string; - fileName: string; - config: Config; - }, -): Promise { - const filePath = join( - Deno.cwd(), - config.locations.staticDir, - site || "_all", - fileName, - ); - const hash = await calculateFileHash(filePath); - return link({ rel: "stylesheet", href: `${fileName}?h=${hash}` }); -} diff --git a/services/nuldoc/nuldoc-src/components/TableOfContents.ts b/services/nuldoc/nuldoc-src/components/TableOfContents.ts deleted file mode 100644 index 1eb79e98..00000000 --- a/services/nuldoc/nuldoc-src/components/TableOfContents.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { TocEntry, TocRoot } from "../markdown/document.ts"; -import { a, Element, h2, li, nav, ul } from "../dom.ts"; - -type Props = { - toc: TocRoot; -}; - -export default function TableOfContents({ toc }: Props): Element { - return nav( - { class: "toc" }, - h2({}, "目次"), - ul( - {}, - ...toc.entries.map((entry) => TocEntryComponent({ entry })), - ), - ); -} - -function TocEntryComponent({ entry }: { entry: TocEntry }): Element { - return li( - {}, - a({ href: `#${entry.id}` }, entry.text), - entry.children.length > 0 - ? ul( - {}, - ...entry.children.map((child) => TocEntryComponent({ entry: child })), - ) - : null, - ); -} diff --git a/services/nuldoc/nuldoc-src/components/TagList.ts b/services/nuldoc/nuldoc-src/components/TagList.ts deleted file mode 100644 index ed3fc1a1..00000000 --- a/services/nuldoc/nuldoc-src/components/TagList.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Config, getTagLabel } from "../config.ts"; -import { Element, li, span, text, ul } from "../dom.ts"; - -type Props = { - tags: string[]; - config: Config; -}; - -export default function TagList({ tags, config }: Props): Element { - return ul( - { class: "entry-tags" }, - ...tags.map((slug) => - li( - { class: "tag" }, - span({ class: "tag-inner" }, text(getTagLabel(config, slug))), - ) - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/utils.ts b/services/nuldoc/nuldoc-src/components/utils.ts deleted file mode 100644 index 14059b5b..00000000 --- a/services/nuldoc/nuldoc-src/components/utils.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Hash } from "checksum/mod.ts"; - -export async function calculateFileHash( - filePath: string, -): Promise { - const content = await Deno.readFile(filePath); - return new Hash("md5").digest(content).hex(); -} -- cgit v1.3-1-g0d28