From 3a810213a5eb86c976135ed38c062a1b42e1ecfd Mon Sep 17 00:00:00 2001 From: hayao Date: Thu, 9 Jan 2025 18:35:09 +0900 Subject: [PATCH] refactor: Add PostData class --- src/components/layouts/blog/PostPreview.tsx | 42 +++---- .../layouts/blog/PostPreviewList.tsx | 2 +- src/lib/blog/categories.ts | 4 +- src/lib/blog/fromurl.tsx | 5 +- src/lib/markdown/post.ts | 111 +++++++++++++----- src/lib/markdown/postlist.ts | 23 +--- src/lib/projects/index.tsx | 4 +- 7 files changed, 111 insertions(+), 80 deletions(-) diff --git a/src/components/layouts/blog/PostPreview.tsx b/src/components/layouts/blog/PostPreview.tsx index fcea31a..af82b2a 100644 --- a/src/components/layouts/blog/PostPreview.tsx +++ b/src/components/layouts/blog/PostPreview.tsx @@ -3,15 +3,15 @@ import { motion, Variants } from "framer-motion"; import { Link } from "@/components/elements/Link"; -import { PostData } from "@/lib/markdown/post"; +import { StaticPostData } from "@/lib/markdown/post"; import * as utils from "@/lib/utils"; -const PostPreview = ({ posts }: { posts: PostData }) => { - if (!posts.meta.title || !posts.meta.date) { +const PostPreview = ({ posts: post }: { posts: StaticPostData }) => { + if (!post.meta.title || !post.meta.date) { return <>; } - const postDate = new Date(posts.meta.date); + const postDate = new Date(post.meta.date); const animate: Variants = { offscreen: { @@ -27,9 +27,7 @@ const PostPreview = ({ posts }: { posts: PostData }) => { }, }; - const contentString = posts.content.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, "").slice(0, 100) + "..."; - - const fullURL = "/blog/posts/" + posts.url; + const fullURL = "/blog/posts/" + post.url; return ( {
- {(posts.meta.categories ? posts.meta.categories : ["その他"]) - .filter((c) => { - return c !== "ブログ"; - }) - .map((c) => { - return c ? c : "その他"; - }) - .map((s) => { - return ( -
- {s} -
- ); - })} + {post.categories.map((s) => ( +
+ {s} +
+ ))}

@@ -64,11 +53,14 @@ const PostPreview = ({ posts }: { posts: PostData }) => {

+ {/* タイトル */} - {posts.meta.title} + {post.meta.title} -
- {posts.meta.tags?.map((s) => { + + {/* タグ一覧 */} +
+ {post.meta.tags?.map((s) => { return ( #{s} @@ -80,7 +72,7 @@ const PostPreview = ({ posts }: { posts: PostData }) => {
- {contentString} + {post.summary}
diff --git a/src/components/layouts/blog/PostPreviewList.tsx b/src/components/layouts/blog/PostPreviewList.tsx index 18655b6..f985011 100644 --- a/src/components/layouts/blog/PostPreviewList.tsx +++ b/src/components/layouts/blog/PostPreviewList.tsx @@ -13,7 +13,7 @@ export function PostList({ posts }: PostListProps) { return (
{posts.map((f) => { - return ; + return ; })}
); diff --git a/src/lib/blog/categories.ts b/src/lib/blog/categories.ts index 826b066..627555c 100644 --- a/src/lib/blog/categories.ts +++ b/src/lib/blog/categories.ts @@ -10,8 +10,8 @@ export type Category = { export const getAllCategories = () => fetchedBlogPostList.getAllCategories(); export const findCategoryInfo = (category: string): Category | null => { - const catingo = getCategoryInfo(); - const matched = catingo.filter((c) => c.url === category || c.jp === category); + const catinfo = getCategoryInfo(); + const matched = catinfo.filter((c) => c.url === category || c.jp === category); if (matched.length === 0) { return null; diff --git a/src/lib/blog/fromurl.tsx b/src/lib/blog/fromurl.tsx index d4d62d9..ab34764 100644 --- a/src/lib/blog/fromurl.tsx +++ b/src/lib/blog/fromurl.tsx @@ -4,7 +4,7 @@ import { ReactNode } from "react"; import Markdown from "@/components/elements/Markdown"; import { findMarkdownFromURL } from "../markdown/fromurl"; -import { getPostDataFromFile, PostData } from "../markdown/post"; +import { PostData } from "../markdown/post"; type FoundPost = { post?: PostData; @@ -16,8 +16,7 @@ export function findPostFromUrl(url: string): FoundPost { const targetFile = findMarkdownFromURL(path.join(process.cwd(), "posts"), url); if (targetFile) { - const post = getPostDataFromFile(targetFile); - //console.log(post); + const post = PostData.getFromFile(targetFile); return { post: post, diff --git a/src/lib/markdown/post.ts b/src/lib/markdown/post.ts index 1ea42f1..2f1cc3a 100644 --- a/src/lib/markdown/post.ts +++ b/src/lib/markdown/post.ts @@ -6,36 +6,91 @@ import { PostMeta } from "@/lib/markdown/type"; import { BLOG_URL_FORMAT } from "../blog/config"; import { formatURL, mdPathToURL, URLFormat } from "./url"; -export function getPostDataFromFile(file: string, urlFormat: URLFormat = BLOG_URL_FORMAT): PostData { - const fileContent = fs.readFileSync(file, "utf-8"); - const parsed = matter(fileContent); - const meta: PostMeta = {}; - - Object.keys(parsed.data).forEach((key) => { - if (key === "date") { - meta[key] = new Date(parsed.data[key]).toISOString(); - } else if (key === "categories") { - meta[key] = parsed.data[key].filter((c: string) => c !== "ブログ"); - } else { - meta[key] = parsed.data[key]; - } - }); - - //console.log(meta); - - const data = { - file: file, - url: formatURL(mdPathToURL(file), urlFormat), - meta: meta, - content: parsed.content, - }; - - return data; -} - -export interface PostData { +export interface StaticPostData { file: string; url: string; meta: PostMeta; content: string; + summary: string; + categories: string[]; +} + +export class PostData { + #file: string; + #url: string; + #meta: PostMeta; + #content: string; + + get file() { + return this.#file; + } + get url() { + return this.#url; + } + get meta() { + return this.#meta; + } + get content() { + return this.#content; + } + + get summary() { + return this.#content.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, "").slice(0, 100) + "..."; + } + + get categories() { + return this.#meta.categories + ? this.#meta.categories + : ["その他"] + .filter((c) => { + return c !== "ブログ"; + }) + .map((c) => { + return c ? c : "その他"; + }); + } + + constructor(file: string, url: string, meta: PostMeta, content: string) { + this.#file = file; + this.#url = url; + this.#meta = meta; + this.#content = content; + } + + contentSplited(chars: number) { + return new PostData(this.#file, this.#url, this.#meta, this.#content.slice(0, chars)); + } + + getStaticData(): StaticPostData { + return { + file: this.#file, + url: this.#url, + meta: this.#meta, + content: this.#content, + summary: this.summary, + categories: this.categories, + }; + } + + static getFromFile(file: string, urlFormat: URLFormat = BLOG_URL_FORMAT): PostData { + const fileContent = fs.readFileSync(file, "utf-8"); + const parsed = matter(fileContent); + const meta: PostMeta = {}; + + Object.keys(parsed.data).forEach((key) => { + if (key === "date") { + meta[key] = new Date(parsed.data[key]).toISOString(); + } else if (key === "categories") { + meta[key] = parsed.data[key].filter((c: string) => c !== "ブログ"); + } else { + meta[key] = parsed.data[key]; + } + }); + + return new PostData(file, formatURL(mdPathToURL(file), urlFormat), meta, parsed.content); + } + + static getFromStaticData(data: StaticPostData, urlFormat: URLFormat = BLOG_URL_FORMAT): PostData { + return new PostData(data.file, formatURL(data.url, urlFormat), data.meta, data.content); + } } diff --git a/src/lib/markdown/postlist.ts b/src/lib/markdown/postlist.ts index 6c152fc..b0486e0 100644 --- a/src/lib/markdown/postlist.ts +++ b/src/lib/markdown/postlist.ts @@ -1,7 +1,7 @@ import fs from "fs"; import path from "path"; -import { getPostDataFromFile, PostData } from "./post"; +import { PostData } from "./post"; import { URLFormat } from "./url"; const getMdFilesInDir = (dir: string): string[] => { @@ -28,12 +28,7 @@ export class PostList { this.posts = []; } - fetch( - dir: string, - format: URLFormat, - //includeDraft: boolean | undefined = undefined, - //includeHidden: boolean | undefined = undefined, - ) { + fetch(dir: string, format: URLFormat) { if (this.fetched) return this; const files = getMdFilesInDir(dir); @@ -41,9 +36,7 @@ export class PostList { //console.log(files); const posts = files - .map((file) => { - return getPostDataFromFile(file, format); - }) + .map((file) => PostData.getFromFile(file, format)) .filter((p) => { if (p.meta.publish == undefined) return true; if (p.meta.publish == true) return true; @@ -169,15 +162,7 @@ export class PostList { } getContentSplitedPosts(perChars: number) { - return PostList.fromPostDatas( - this.posts.map((p) => { - const content = p.content.slice(0, perChars); - return { - ...p, - content: content, - }; - }), - ); + return PostList.fromPostDatas(this.posts.map((p) => p.contentSplited(perChars))); } getAllCategories() { diff --git a/src/lib/projects/index.tsx b/src/lib/projects/index.tsx index b238bcc..5288819 100644 --- a/src/lib/projects/index.tsx +++ b/src/lib/projects/index.tsx @@ -3,7 +3,7 @@ import path from "path"; import Markdown from "@/components/elements/Markdown"; import { findMarkdownFromURL } from "../markdown/fromurl"; -import { getPostDataFromFile } from "../markdown/post"; +import { PostData } from "../markdown/post"; import { PostList } from "../markdown/postlist"; export const projectsDir = path.join(process.cwd(), "src", "app", "(hayao)", "something", "files"); @@ -19,7 +19,7 @@ export const getProjectFromURL = (url: string) => { // console.log(mdFile); if (mdFile) { - const projPost = getPostDataFromFile(mdFile, { + const projPost = PostData.getFromFile(mdFile, { cutHead: process.cwd().split(path.sep).length + 5, }); // TODO: basepathがあってるか確認する