From 57315c52be96d2a2c013f0cfb0de5429980e301a Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 2 Nov 2025 17:49:34 +0900 Subject: refactor(blog): rename directory, services/{blog => nuldoc}/ --- .../nuldoc/nuldoc-src/components/GlobalFooter.tsx | 9 ++ .../nuldoc/nuldoc-src/components/GlobalHeader.tsx | 27 ++++++ .../nuldoc/nuldoc-src/components/PageLayout.tsx | 63 +++++++++++++ .../nuldoc/nuldoc-src/components/Pagination.tsx | 104 +++++++++++++++++++++ .../nuldoc/nuldoc-src/components/PostPageEntry.tsx | 46 +++++++++ .../nuldoc-src/components/SlidePageEntry.tsx | 46 +++++++++ .../nuldoc/nuldoc-src/components/StaticScript.tsx | 18 ++++ .../nuldoc-src/components/StaticStylesheet.tsx | 11 +++ .../nuldoc-src/components/TableOfContents.tsx | 33 +++++++ services/nuldoc/nuldoc-src/components/TagList.tsx | 18 ++++ services/nuldoc/nuldoc-src/components/utils.ts | 8 ++ 11 files changed, 383 insertions(+) create mode 100644 services/nuldoc/nuldoc-src/components/GlobalFooter.tsx create mode 100644 services/nuldoc/nuldoc-src/components/GlobalHeader.tsx create mode 100644 services/nuldoc/nuldoc-src/components/PageLayout.tsx create mode 100644 services/nuldoc/nuldoc-src/components/Pagination.tsx create mode 100644 services/nuldoc/nuldoc-src/components/PostPageEntry.tsx create mode 100644 services/nuldoc/nuldoc-src/components/SlidePageEntry.tsx create mode 100644 services/nuldoc/nuldoc-src/components/StaticScript.tsx create mode 100644 services/nuldoc/nuldoc-src/components/StaticStylesheet.tsx create mode 100644 services/nuldoc/nuldoc-src/components/TableOfContents.tsx create mode 100644 services/nuldoc/nuldoc-src/components/TagList.tsx create mode 100644 services/nuldoc/nuldoc-src/components/utils.ts (limited to 'services/nuldoc/nuldoc-src/components') diff --git a/services/nuldoc/nuldoc-src/components/GlobalFooter.tsx b/services/nuldoc/nuldoc-src/components/GlobalFooter.tsx new file mode 100644 index 0000000..757bece --- /dev/null +++ b/services/nuldoc/nuldoc-src/components/GlobalFooter.tsx @@ -0,0 +1,9 @@ +import { Config } from "../config.ts"; + +export default function GlobalFooter({ config }: { config: Config }) { + return ( + + ); +} diff --git a/services/nuldoc/nuldoc-src/components/GlobalHeader.tsx b/services/nuldoc/nuldoc-src/components/GlobalHeader.tsx new file mode 100644 index 0000000..c0fa7e8 --- /dev/null +++ b/services/nuldoc/nuldoc-src/components/GlobalHeader.tsx @@ -0,0 +1,27 @@ +import { Config } from "../config.ts"; + +export default function GlobalHeader({ config }: { config: Config }) { + return ( +
+
+ {config.blog.siteName} +
+ +
+ ); +} diff --git a/services/nuldoc/nuldoc-src/components/PageLayout.tsx b/services/nuldoc/nuldoc-src/components/PageLayout.tsx new file mode 100644 index 0000000..78a5cde --- /dev/null +++ b/services/nuldoc/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 ( + + + + + + + + {metaKeywords && metaKeywords.length !== 0 && + } + + + + + + {/* https://b.hatena.ne.jp/help/entry/nocomment */} + + {metaAtomFeedHref && + ( + + )} + + {metaTitle} + + + {children} + + ); +} diff --git a/services/nuldoc/nuldoc-src/components/Pagination.tsx b/services/nuldoc/nuldoc-src/components/Pagination.tsx new file mode 100644 index 0000000..84752c5 --- /dev/null +++ b/services/nuldoc/nuldoc-src/components/Pagination.tsx @@ -0,0 +1,104 @@ +type Props = { + currentPage: number; + totalPages: number; + basePath: string; +}; + +export default function Pagination( + { currentPage, totalPages, basePath }: Props, +) { + if (totalPages <= 1) { + return
; + } + + const pages = generatePageNumbers(currentPage, totalPages); + + return ( + + ); +} + +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.tsx b/services/nuldoc/nuldoc-src/components/PostPageEntry.tsx new file mode 100644 index 0000000..23ca88a --- /dev/null +++ b/services/nuldoc/nuldoc-src/components/PostPageEntry.tsx @@ -0,0 +1,46 @@ +import { + getPostPublishedDate, + getPostUpdatedDate, + postHasAnyUpdates, + PostPage, +} from "../generators/post.ts"; +import { dateToString } from "../revision.ts"; +import { Config } from "../config.ts"; +import TagList from "./TagList.tsx"; + +type Props = { post: PostPage; config: Config }; + +export default function PostPageEntry({ post, config }: Props) { + return ( + + ); +} diff --git a/services/nuldoc/nuldoc-src/components/SlidePageEntry.tsx b/services/nuldoc/nuldoc-src/components/SlidePageEntry.tsx new file mode 100644 index 0000000..2401765 --- /dev/null +++ b/services/nuldoc/nuldoc-src/components/SlidePageEntry.tsx @@ -0,0 +1,46 @@ +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 TagList from "./TagList.tsx"; + +type Props = { slide: SlidePage; config: Config }; + +export default function SlidePageEntry({ slide, config }: Props) { + return ( + + ); +} diff --git a/services/nuldoc/nuldoc-src/components/StaticScript.tsx b/services/nuldoc/nuldoc-src/components/StaticScript.tsx new file mode 100644 index 0000000..0e3ab19 --- /dev/null +++ b/services/nuldoc/nuldoc-src/components/StaticScript.tsx @@ -0,0 +1,18 @@ +import { join } from "@std/path"; +import { Config } from "../config.ts"; +import { calculateFileHash } from "./utils.ts"; + +export default async function StaticScript( + { fileName, type, defer, config }: { + fileName: string; + type?: string; + defer?: "true"; + config: Config; + }, +) { + const filePath = join(Deno.cwd(), config.locations.staticDir, fileName); + const hash = await calculateFileHash(filePath); + return ( + + ); +} diff --git a/services/nuldoc/nuldoc-src/components/StaticStylesheet.tsx b/services/nuldoc/nuldoc-src/components/StaticStylesheet.tsx new file mode 100644 index 0000000..52b695e --- /dev/null +++ b/services/nuldoc/nuldoc-src/components/StaticStylesheet.tsx @@ -0,0 +1,11 @@ +import { join } from "@std/path"; +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 ; +} diff --git a/services/nuldoc/nuldoc-src/components/TableOfContents.tsx b/services/nuldoc/nuldoc-src/components/TableOfContents.tsx new file mode 100644 index 0000000..29907d0 --- /dev/null +++ b/services/nuldoc/nuldoc-src/components/TableOfContents.tsx @@ -0,0 +1,33 @@ +import { TocEntry, TocRoot } from "../djot/document.ts"; + +type Props = { + toc: TocRoot; +}; + +export default function TableOfContents({ toc }: Props) { + return ( + + ); +} + +function TocEntryComponent({ entry }: { entry: TocEntry }) { + return ( +
  • + {entry.text} + {entry.children.length > 0 && ( +
      + {entry.children.map((child, index) => ( + + ))} +
    + )} +
  • + ); +} diff --git a/services/nuldoc/nuldoc-src/components/TagList.tsx b/services/nuldoc/nuldoc-src/components/TagList.tsx new file mode 100644 index 0000000..86ee70b --- /dev/null +++ b/services/nuldoc/nuldoc-src/components/TagList.tsx @@ -0,0 +1,18 @@ +import { Config, getTagLabel } from "../config.ts"; + +type Props = { + tags: string[]; + config: Config; +}; + +export default function TagList({ tags, config }: Props) { + return ( +
      + {tags.map((slug) => ( +
    • + {getTagLabel(config, slug)} +
    • + ))} +
    + ); +} diff --git a/services/nuldoc/nuldoc-src/components/utils.ts b/services/nuldoc/nuldoc-src/components/utils.ts new file mode 100644 index 0000000..14059b5 --- /dev/null +++ b/services/nuldoc/nuldoc-src/components/utils.ts @@ -0,0 +1,8 @@ +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.2.3-70-g09d2