From 603dbf71a6fe3d0dd2afcfe88f201735eee81b30 Mon Sep 17 00:00:00 2001 From: Lumither Tao Date: Sat, 27 Apr 2024 12:03:08 +0800 Subject: [PATCH] feat(blog) add CMS, render blog posts list - use GitHub repo as cms, read idx.json - blog posts list --- .env | 2 ++ app/blog/BlogPostCard.tsx | 33 +++++++++++++++++++++++++++++++++ app/blog/fetch_posts.ts | 19 +++++++++++++++++++ app/blog/layout.tsx | 15 +++++++++++++++ app/blog/page.tsx | 23 +++++++++++++++++++++-- app/public/type/Result.ts | 7 +++++++ tsconfig.json | 1 + 7 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 .env create mode 100644 app/blog/BlogPostCard.tsx create mode 100644 app/blog/fetch_posts.ts create mode 100644 app/blog/layout.tsx create mode 100644 app/public/type/Result.ts diff --git a/.env b/.env new file mode 100644 index 0000000..dfc11f3 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +BLOG_ENDPOINT=https://raw.githubusercontents.com/lumither/blog-posts/master +; use mirror diff --git a/app/blog/BlogPostCard.tsx b/app/blog/BlogPostCard.tsx new file mode 100644 index 0000000..393a7ea --- /dev/null +++ b/app/blog/BlogPostCard.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import Link from 'next/link'; +import { Card, CardBody, CardHeader } from '@nextui-org/card'; +import { Divider } from '@nextui-org/react'; + +type Props = { + post: JSON +} + +function BlogPostCard({ post }: Props) { + const name = (post as any)['name']; + const { title, desc } = (post as any)['meta'] as { title: string, desc: string }; + return ( + +
+ {/*todo: to be update*/ } + {/**/} + + +

{ title }

+
+ + + { desc } + +
+ {/**/} +
+ ); + +} + +export default BlogPostCard; diff --git a/app/blog/fetch_posts.ts b/app/blog/fetch_posts.ts new file mode 100644 index 0000000..af53549 --- /dev/null +++ b/app/blog/fetch_posts.ts @@ -0,0 +1,19 @@ +import { Result } from '@/app/public/type/Result'; + +export default async function fetch_posts(url: string): Promise> { + const response = await fetch(`${ url }/posts/idx.json`); + if (!response.ok) { + return { + ok: false, + error: new Error(response.statusText) + }; + } + const res = await response.json(); + const posts = res['idx'].filter((posts: { type: string }) => posts.type === 'md'); + return { + ok: true, + value: posts + }; +} + + diff --git a/app/blog/layout.tsx b/app/blog/layout.tsx new file mode 100644 index 0000000..7600370 --- /dev/null +++ b/app/blog/layout.tsx @@ -0,0 +1,15 @@ +import React from 'react'; + +function Layout({ + children +}: { + children: React.ReactNode; +}) { + return ( +
+ { children } +
+ ); +} + +export default Layout; diff --git a/app/blog/page.tsx b/app/blog/page.tsx index 0f4291a..a9962fa 100644 --- a/app/blog/page.tsx +++ b/app/blog/page.tsx @@ -1,8 +1,27 @@ import React from 'react'; +import fetch_posts from '@/app/blog/fetch_posts'; +import BlogPostCard from '@/app/blog/BlogPostCard'; + +async function Blog() { + + const res = await fetch_posts(process.env.BLOG_ENDPOINT!); + if (!res.ok) { + console.log(res.error); + return; + } + const posts = res.value; + // console.log(posts); -function Blog() { return ( -
+ + // blog list + ); } diff --git a/app/public/type/Result.ts b/app/public/type/Result.ts new file mode 100644 index 0000000..e9c21ba --- /dev/null +++ b/app/public/type/Result.ts @@ -0,0 +1,7 @@ +export type Result = { + ok: true; + value: T; +} | { + ok: false; + error: E; +}; diff --git a/tsconfig.json b/tsconfig.json index e7ff90f..a69d60e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "allowJs": true, "skipLibCheck": true, "strict": true, + "target": "ESNext", "noEmit": true, "esModuleInterop": true, "module": "esnext",