From 8938c964094910777afe2c8c91b0d5beb6b8e205 Mon Sep 17 00:00:00 2001 From: Lumither Tao Date: Wed, 5 Feb 2025 13:57:20 -0800 Subject: [PATCH] feat(frontend) add `Activities.tsx` --- README.md | 40 +++-------- .../src/blog/cron/check_update/mod.rs | 22 +++--- .../src/blog/cron/check_update/utils.rs | 2 +- backend/api_server/src/blog/cron/mod.rs | 3 +- frontend/app/{ => (pages)}/about/layout.tsx | 6 ++ frontend/app/{ => (pages)}/about/me/page.tsx | 2 +- frontend/app/{ => (pages)}/about/page.tsx | 0 .../app/{ => (pages)}/about/website/page.tsx | 2 +- .../app/{ => (pages)}/blog/BlogPostCard.tsx | 0 frontend/app/{ => (pages)}/blog/Error.tsx | 0 .../app/{ => (pages)}/blog/Pagination.tsx | 2 +- frontend/app/{ => (pages)}/blog/PostList.tsx | 11 +-- frontend/app/{ => (pages)}/blog/api.ts | 0 frontend/app/{ => (pages)}/blog/layout.tsx | 6 ++ frontend/app/{ => (pages)}/blog/page.tsx | 6 +- .../blog/post/[id]/ButtonGoBack.tsx | 0 .../{ => (pages)}/blog/post/[id]/Footer.tsx | 34 +++++---- .../{ => (pages)}/blog/post/[id]/Headers.tsx | 46 ++++++------ .../blog/post/[id]/MinifyPostCard.tsx | 8 +-- .../app/(pages)/blog/post/[id]/PostCard.tsx | 55 +++++++++++++++ frontend/app/(pages)/blog/post/[id]/page.tsx | 70 +++++++++++++++++++ frontend/app/{ => (pages)}/friends/layout.tsx | 6 ++ frontend/app/{ => (pages)}/friends/page.tsx | 0 frontend/app/(pages)/layout.tsx | 30 ++++++++ .../{ => (pages)}/public/MarkdownRenderer.tsx | 0 .../app/{ => (pages)}/public/css/article.css | 0 .../{ => (pages)}/public/screenSizeTrigger.ts | 0 .../app/{ => (pages)}/public/type/Result.ts | 0 frontend/app/{ => (pages)}/search/page.tsx | 0 frontend/app/Activities.tsx | 43 ++++++++++++ frontend/app/blog/post/[id]/PostCard.tsx | 53 -------------- frontend/app/blog/post/[id]/page.tsx | 29 -------- frontend/app/entries.tsx | 56 +++++++++++++++ frontend/app/layout.tsx | 19 ++--- frontend/app/page.tsx | 47 ++++++++++++- frontend/app/public/MotionDiv.tsx | 5 -- frontend/components/Navbar.tsx | 57 +-------------- frontend/components/ThemeSwitcher.tsx | 2 +- frontend/package.json | 3 +- frontend/src/HomePageActivities/activity.tsx | 18 +++++ frontend/src/HomePageActivities/constants.ts | 1 + .../ghActivities/starRepo.tsx | 34 +++++++++ .../src/HomePageActivities/ghActivity.tsx | 32 +++++++++ frontend/src/constants.ts | 4 ++ 44 files changed, 501 insertions(+), 253 deletions(-) rename frontend/app/{ => (pages)}/about/layout.tsx (57%) rename frontend/app/{ => (pages)}/about/me/page.tsx (83%) rename frontend/app/{ => (pages)}/about/page.tsx (100%) rename frontend/app/{ => (pages)}/about/website/page.tsx (84%) rename frontend/app/{ => (pages)}/blog/BlogPostCard.tsx (100%) rename frontend/app/{ => (pages)}/blog/Error.tsx (100%) rename frontend/app/{ => (pages)}/blog/Pagination.tsx (92%) rename frontend/app/{ => (pages)}/blog/PostList.tsx (83%) rename frontend/app/{ => (pages)}/blog/api.ts (100%) rename frontend/app/{ => (pages)}/blog/layout.tsx (67%) rename frontend/app/{ => (pages)}/blog/page.tsx (77%) rename frontend/app/{ => (pages)}/blog/post/[id]/ButtonGoBack.tsx (100%) rename frontend/app/{ => (pages)}/blog/post/[id]/Footer.tsx (80%) rename frontend/app/{ => (pages)}/blog/post/[id]/Headers.tsx (64%) rename frontend/app/{ => (pages)}/blog/post/[id]/MinifyPostCard.tsx (84%) create mode 100644 frontend/app/(pages)/blog/post/[id]/PostCard.tsx create mode 100644 frontend/app/(pages)/blog/post/[id]/page.tsx rename frontend/app/{ => (pages)}/friends/layout.tsx (57%) rename frontend/app/{ => (pages)}/friends/page.tsx (100%) create mode 100644 frontend/app/(pages)/layout.tsx rename frontend/app/{ => (pages)}/public/MarkdownRenderer.tsx (100%) rename frontend/app/{ => (pages)}/public/css/article.css (100%) rename frontend/app/{ => (pages)}/public/screenSizeTrigger.ts (100%) rename frontend/app/{ => (pages)}/public/type/Result.ts (100%) rename frontend/app/{ => (pages)}/search/page.tsx (100%) create mode 100644 frontend/app/Activities.tsx delete mode 100644 frontend/app/blog/post/[id]/PostCard.tsx delete mode 100644 frontend/app/blog/post/[id]/page.tsx create mode 100644 frontend/app/entries.tsx delete mode 100644 frontend/app/public/MotionDiv.tsx create mode 100644 frontend/src/HomePageActivities/activity.tsx create mode 100644 frontend/src/HomePageActivities/constants.ts create mode 100644 frontend/src/HomePageActivities/ghActivities/starRepo.tsx create mode 100644 frontend/src/HomePageActivities/ghActivity.tsx create mode 100644 frontend/src/constants.ts diff --git a/README.md b/README.md index c8ea3a4..36ab327 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,16 @@ -# `Nocturne: personal website & CMS` +# `Nocturne: Personal Website` -This is the code repo of my personal website, and [here](https://github.com/Lumither/blog-posts/) is the link of the -content repo. +This is the code repo of my [personal website](https://lumither.com), +and [here](https://github.com/Lumither/blog-posts/) is the link to the +content (blog posts etc.) repo. Powered by Next.js and Rust, built with passion and love -

- GitHub Avatar -

+> [!NOTE] +> This system is not production ready, and contains bugs, (security risk potentially). +> But have fun on it =) -*will add more here in the future - -## Nav: - - - -## Todos: - -### Backend - -- [ ] Add: log system -- [ ] Add: search api -- [ ] Add: tag filter (api) -- [ ] Abandon: UUID mechanism -- [ ] Fix: db connection issue - -### Frontend - -- [ ] Page: Home -- [ ] Page: About -- [ ] Page: Tags -- [ ] Page: Archive -- [ ] Page: Search -- [ ] Add: Right sidebar +# Todos +- [ ] the todo list lol +- [ ] and much more... diff --git a/backend/api_server/src/blog/cron/check_update/mod.rs b/backend/api_server/src/blog/cron/check_update/mod.rs index 9568ae2..2d531e3 100644 --- a/backend/api_server/src/blog/cron/check_update/mod.rs +++ b/backend/api_server/src/blog/cron/check_update/mod.rs @@ -1,4 +1,5 @@ use std::env; +use std::error::Error; use std::fs::remove_dir_all; use std::path::{Path, PathBuf}; @@ -89,24 +90,22 @@ pub fn task(db_connection: &Pool) { for update in updates { if [Delta::Deleted, Delta::Untracked].contains(&update.status) { if let Some(path) = &update.old_path { - if drop_index( + match drop_index( &get_md_file_basename( path.file_name().unwrap().to_str().unwrap(), ), db_connection, - ) - .is_ok() - { - info!( + ) { + Ok(_) => info!( "blog content git({}) file `{}` is detected as deleted/untracked, index dropped", &git_url, &path.display() - ); - } else { - error!( - "blog content git({}) file `{}` is detected as deleted/untracked, failed to drop index", + ), + Err(e) => error!( + "blog content git({}) file `{}` is detected as deleted/untracked, failed to drop index: {}", &git_url, - &path.display() + &path.display(), + e ) } } @@ -114,7 +113,8 @@ pub fn task(db_connection: &Pool) { if path.components().any(|comp| comp.as_os_str() == "posts") && path.extension().is_some_and(|ext| ext == "md") { - update_md.push(path.to_path_buf()); + // update_md.push(path.to_path_buf()); + update_md.push(dbg!(path.to_path_buf())); } } } diff --git a/backend/api_server/src/blog/cron/check_update/utils.rs b/backend/api_server/src/blog/cron/check_update/utils.rs index d0da864..c20d98a 100644 --- a/backend/api_server/src/blog/cron/check_update/utils.rs +++ b/backend/api_server/src/blog/cron/check_update/utils.rs @@ -38,7 +38,7 @@ pub fn search_md(entry: PathBuf) -> Vec { pub fn index_files(files: &[PathBuf], db_conn: &Pool) { let rt = Runtime::new().unwrap(); rt.block_on(async { - let files_clone = files.to_owned(); + let files_clone = dbg!(files).to_owned(); let handlers = files_clone .into_iter() .map(|file: PathBuf| { diff --git a/backend/api_server/src/blog/cron/mod.rs b/backend/api_server/src/blog/cron/mod.rs index 686fb26..1cb8398 100644 --- a/backend/api_server/src/blog/cron/mod.rs +++ b/backend/api_server/src/blog/cron/mod.rs @@ -7,7 +7,8 @@ pub mod check_update; pub fn get_tasks(db_connection: Pool) -> Vec> { let db_conn_clone = db_connection.clone(); vec![ - BasicTask::new(move || check_update::task(&db_conn_clone), "0/15 * * * * *") + // BasicTask::new(move || check_update::task(&db_conn_clone), "0/15 * * * * *") + BasicTask::new(move || check_update::task(&db_conn_clone), "* * * * * *") .unwrap() .to_task(), ] diff --git a/frontend/app/about/layout.tsx b/frontend/app/(pages)/about/layout.tsx similarity index 57% rename from frontend/app/about/layout.tsx rename to frontend/app/(pages)/about/layout.tsx index ccc425b..e84ea45 100644 --- a/frontend/app/about/layout.tsx +++ b/frontend/app/(pages)/about/layout.tsx @@ -1,4 +1,10 @@ import React from 'react'; +import { Metadata } from 'next'; +import { SITE_CONFIG } from '@/src/constants'; + +export const metadata: Metadata = { + title: `About - ${ SITE_CONFIG.name }` +}; function Layout({ children diff --git a/frontend/app/about/me/page.tsx b/frontend/app/(pages)/about/me/page.tsx similarity index 83% rename from frontend/app/about/me/page.tsx rename to frontend/app/(pages)/about/me/page.tsx index 86cccf5..03821e9 100644 --- a/frontend/app/about/me/page.tsx +++ b/frontend/app/(pages)/about/me/page.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import MarkdownRenderer from '@/app/public/MarkdownRenderer'; +import MarkdownRenderer from '@/app/(pages)/public/MarkdownRenderer'; import { fetchText } from '@/app/fetch'; const Me = async () => { diff --git a/frontend/app/about/page.tsx b/frontend/app/(pages)/about/page.tsx similarity index 100% rename from frontend/app/about/page.tsx rename to frontend/app/(pages)/about/page.tsx diff --git a/frontend/app/about/website/page.tsx b/frontend/app/(pages)/about/website/page.tsx similarity index 84% rename from frontend/app/about/website/page.tsx rename to frontend/app/(pages)/about/website/page.tsx index 0fc5d5a..0d112cb 100644 --- a/frontend/app/about/website/page.tsx +++ b/frontend/app/(pages)/about/website/page.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import MarkdownRenderer from '@/app/public/MarkdownRenderer'; +import MarkdownRenderer from '@/app/(pages)/public/MarkdownRenderer'; import { fetchText } from '@/app/fetch'; const Website = async () => { diff --git a/frontend/app/blog/BlogPostCard.tsx b/frontend/app/(pages)/blog/BlogPostCard.tsx similarity index 100% rename from frontend/app/blog/BlogPostCard.tsx rename to frontend/app/(pages)/blog/BlogPostCard.tsx diff --git a/frontend/app/blog/Error.tsx b/frontend/app/(pages)/blog/Error.tsx similarity index 100% rename from frontend/app/blog/Error.tsx rename to frontend/app/(pages)/blog/Error.tsx diff --git a/frontend/app/blog/Pagination.tsx b/frontend/app/(pages)/blog/Pagination.tsx similarity index 92% rename from frontend/app/blog/Pagination.tsx rename to frontend/app/(pages)/blog/Pagination.tsx index c3b8033..3d381ab 100644 --- a/frontend/app/blog/Pagination.tsx +++ b/frontend/app/(pages)/blog/Pagination.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { Pagination as NextUIPagination } from '@nextui-org/react'; import { useRouter, useSearchParams } from 'next/navigation'; -import { useScreenSizeTrigger } from '@/app/public/screenSizeTrigger'; +import { useScreenSizeTrigger } from '@/app/(pages)/public/screenSizeTrigger'; const Pagination = ({ total }: { total: number, diff --git a/frontend/app/blog/PostList.tsx b/frontend/app/(pages)/blog/PostList.tsx similarity index 83% rename from frontend/app/blog/PostList.tsx rename to frontend/app/(pages)/blog/PostList.tsx index 591c6ea..c815d5c 100644 --- a/frontend/app/blog/PostList.tsx +++ b/frontend/app/(pages)/blog/PostList.tsx @@ -1,11 +1,12 @@ 'use server'; import React from 'react'; -import { fetchNocturneApi } from '@/app/blog/api'; -import { MotionDiv } from '@/app/public/MotionDiv'; -import BlogPostCard from '@/app/blog/BlogPostCard'; +import { fetchNocturneApi } from '@/app/(pages)/blog/api'; +import BlogPostCard from '@/app/(pages)/blog/BlogPostCard'; import { Card, CardBody } from '@nextui-org/card'; +import * as motion from 'motion/react-client'; + const PostList = async ({ page }: { page: number }) => { try { const res = await fetchNocturneApi(`/blog/get_post_list?page=${ page }`); @@ -16,13 +17,13 @@ const PostList = async ({ page }: { page: number }) => {
    { posts.map((post: JSON, key: number) => (
  • - - +
  • ) ) }
diff --git a/frontend/app/blog/api.ts b/frontend/app/(pages)/blog/api.ts similarity index 100% rename from frontend/app/blog/api.ts rename to frontend/app/(pages)/blog/api.ts diff --git a/frontend/app/blog/layout.tsx b/frontend/app/(pages)/blog/layout.tsx similarity index 67% rename from frontend/app/blog/layout.tsx rename to frontend/app/(pages)/blog/layout.tsx index 2c3ea28..7a16d98 100644 --- a/frontend/app/blog/layout.tsx +++ b/frontend/app/(pages)/blog/layout.tsx @@ -1,4 +1,10 @@ import React from 'react'; +import { Metadata } from 'next'; +import { SITE_CONFIG } from '@/src/constants'; + +export const metadata: Metadata = { + title: `Blog - ${ SITE_CONFIG.name }` +}; function Layout({ children diff --git a/frontend/app/blog/page.tsx b/frontend/app/(pages)/blog/page.tsx similarity index 77% rename from frontend/app/blog/page.tsx rename to frontend/app/(pages)/blog/page.tsx index 6690937..f6b4939 100644 --- a/frontend/app/blog/page.tsx +++ b/frontend/app/(pages)/blog/page.tsx @@ -1,6 +1,6 @@ -import PostList from '@/app/blog/PostList'; -import Pagination from '@/app/blog/Pagination'; -import { fetchNocturneApi } from '@/app/blog/api'; +import PostList from '@/app/(pages)/blog/PostList'; +import Pagination from '@/app/(pages)/blog/Pagination'; +import { fetchNocturneApi } from '@/app/(pages)/blog/api'; async function Blog({ searchParams diff --git a/frontend/app/blog/post/[id]/ButtonGoBack.tsx b/frontend/app/(pages)/blog/post/[id]/ButtonGoBack.tsx similarity index 100% rename from frontend/app/blog/post/[id]/ButtonGoBack.tsx rename to frontend/app/(pages)/blog/post/[id]/ButtonGoBack.tsx diff --git a/frontend/app/blog/post/[id]/Footer.tsx b/frontend/app/(pages)/blog/post/[id]/Footer.tsx similarity index 80% rename from frontend/app/blog/post/[id]/Footer.tsx rename to frontend/app/(pages)/blog/post/[id]/Footer.tsx index 6802851..e0ac2b5 100644 --- a/frontend/app/blog/post/[id]/Footer.tsx +++ b/frontend/app/(pages)/blog/post/[id]/Footer.tsx @@ -1,24 +1,32 @@ import React from 'react'; -import MinifyPostCard from '@/app/blog/post/[id]/MinifyPostCard'; +import MinifyPostCard from '@/app/(pages)/blog/post/[id]/MinifyPostCard'; import Link from 'next/link'; import { FaCreativeCommons } from 'react-icons/fa6'; type Props = { - post: any + // post: any + post_id: string; + adjacent_posts: any + perm_link: string | undefined; + author: string | undefined; + author_link: string | undefined; + first_update: string; + last_update: string | undefined; + cc: string | undefined; + title: string; } const Footer = (props: Props) => { - const { post } = props; + const { adjacent_posts, perm_link, post_id, first_update, last_update, title } = props; - const adjacent_posts = post['adj']; - const prev_post = adjacent_posts['prev']; - const next_post = adjacent_posts['next']; - const link = post['meta']['link'] ?? `https://lumither.com/blog/post/${ post['meta']['id'] }`; - const author = post['meta']['author'] ?? 'Tao'; - const author_link = post['meta']['author_link'] ?? '/about'; - const post_date = new Date(post['first_update']); - const update_date: Date | undefined = post['last_update'] ? new Date(post['last_update']) : undefined; - const cc = post['meta']['cc'] ?? 'by-nc-sa'; + const prev_post = adjacent_posts.prev; + const next_post = adjacent_posts.next; + const link = perm_link ?? `https://lumither.com/blog/post/${ post_id }`; + const author = props.author ?? 'Tao'; + const author_link = props.author_link ?? '/about/me'; + const post_date = new Date(first_update); + const update_date: Date | undefined = last_update ? new Date(last_update) : undefined; + const cc = props.cc ?? 'by-nc-sa'; return ( @@ -35,7 +43,7 @@ const Footer = (props: Props) => {
-

{ post['meta']['title'] }

+

{ title }

{ link }

diff --git a/frontend/app/blog/post/[id]/Headers.tsx b/frontend/app/(pages)/blog/post/[id]/Headers.tsx similarity index 64% rename from frontend/app/blog/post/[id]/Headers.tsx rename to frontend/app/(pages)/blog/post/[id]/Headers.tsx index 62e9090..7c83e51 100644 --- a/frontend/app/blog/post/[id]/Headers.tsx +++ b/frontend/app/(pages)/blog/post/[id]/Headers.tsx @@ -3,57 +3,57 @@ import Image from 'next/image'; import { Chip } from '@nextui-org/react'; import { MdCalendarMonth } from 'react-icons/md'; +// type Props = { +// post: any +// }; + type Props = { - post: any -}; + title: string; + subtitle: string; + summary: string | undefined; + category: string; + tags: string[]; + first_update: string; + header_img: string | undefined; +} -const Headers = (props: Props) => { - let post = props.post; - let title = post['title']; - let sub_title = post['sub_title']; - // let summary = (post as any)['summary']; - let category = post['category']; - let tags = post['tags']; - // let last_update = new Date((post as any)['last_update']); - let first_update = new Date(post['first_update']); - // let post_id = (post as any)['post_id']; - let header_img = post['meta']['header_img'] as string | null; +const Headers = (post: Props) => { return ( <> - { header_img &&
+ { post.header_img &&
{ {
}
-
+
{ category } -

{ title }

-

{ sub_title }

+ variant={ `solid` }>{ post.category } +

{ post.title }

+

{ post.subtitle }

    { - tags.map((tag: string, key: any) => ( + post.tags.map((tag: string, key: any) => (
  • { tag }
  • @@ -64,7 +64,7 @@ const Headers = (props: Props) => {

    - { first_update.toLocaleString('default', { + { (new Date(post.first_update)).toLocaleString('default', { month: `long`, day: `numeric`, year: `numeric` diff --git a/frontend/app/blog/post/[id]/MinifyPostCard.tsx b/frontend/app/(pages)/blog/post/[id]/MinifyPostCard.tsx similarity index 84% rename from frontend/app/blog/post/[id]/MinifyPostCard.tsx rename to frontend/app/(pages)/blog/post/[id]/MinifyPostCard.tsx index 20f6925..ac9212f 100644 --- a/frontend/app/blog/post/[id]/MinifyPostCard.tsx +++ b/frontend/app/(pages)/blog/post/[id]/MinifyPostCard.tsx @@ -43,10 +43,10 @@ const MinifyPostCard = (props: Props) => { } { !img_url &&

    -
    -

    { post['title'] }

    -
    -

    { post['sub_title'] }

    +
    +

    { post['title'] }

    +
    +

    { post['sub_title'] }

    } diff --git a/frontend/app/(pages)/blog/post/[id]/PostCard.tsx b/frontend/app/(pages)/blog/post/[id]/PostCard.tsx new file mode 100644 index 0000000..27b0253 --- /dev/null +++ b/frontend/app/(pages)/blog/post/[id]/PostCard.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { Card, CardBody } from '@nextui-org/card'; +import Headers from '@/app/(pages)/blog/post/[id]/Headers'; +import Footer from '@/app/(pages)/blog/post/[id]/Footer'; +import MarkdownRenderer from '@/app/(pages)/public/MarkdownRenderer'; + +type Props = { + post: any +} + +async function PostCard(props: Props) { + let post = props.post; + return ( +
    + + + {/* card headers */ } + + + {/* card body */ } + +
    + + { post.content } + +
    +
    + + + {/* card footer */ } +
    + + +
    + ); +} + +export default PostCard; diff --git a/frontend/app/(pages)/blog/post/[id]/page.tsx b/frontend/app/(pages)/blog/post/[id]/page.tsx new file mode 100644 index 0000000..6c2e938 --- /dev/null +++ b/frontend/app/(pages)/blog/post/[id]/page.tsx @@ -0,0 +1,70 @@ +import React, { cache } from 'react'; +import PostCard from '@/app/(pages)/blog/post/[id]/PostCard'; +import ButtonGoBack from '@/app/(pages)/blog/post/[id]/ButtonGoBack'; +import * as motion from 'motion/react-client'; +import { fetchNocturneApi } from '@/app/(pages)/blog/api'; +import { Metadata } from 'next'; +import { SITE_CONFIG } from '@/src/constants'; + +const fetchPost = cache(async (id: string) => { + const res = await fetchNocturneApi(`/blog/get_post/${ id }`); + // throw Error('Not Found'); + return await res.json(); +}); + +export async function generateMetadata( + { params }: { params: Promise<{ id: string }> }) + : Promise { + try { + const title = (await fetchPost((await params).id)).title as string; + return { + title: `${ title } - ${ SITE_CONFIG.name }` + }; + } catch (e) { + return { + title: 'Unexpected Error' + }; + } +} + +async function BlogReader({ + params +}: { + params: Promise<{ id: string }> +}) { + try { + let post = await fetchPost((await params).id); + + return ( + +
    + +
    +
    + +
    +
    + ); + } catch (e: any) { + return ( +
    +
    +

    + { 'Unexpected Error:' } +

    +

    + { e.message } +

    +
    +
    + ); + } + +} + +export default BlogReader; diff --git a/frontend/app/friends/layout.tsx b/frontend/app/(pages)/friends/layout.tsx similarity index 57% rename from frontend/app/friends/layout.tsx rename to frontend/app/(pages)/friends/layout.tsx index 37dad5b..c6e9396 100644 --- a/frontend/app/friends/layout.tsx +++ b/frontend/app/(pages)/friends/layout.tsx @@ -1,4 +1,10 @@ import React from 'react'; +import { Metadata } from 'next'; +import { SITE_CONFIG } from '@/src/constants'; + +export const metadata: Metadata = { + title: `Friends - ${ SITE_CONFIG.name }` +}; function Layout({ children diff --git a/frontend/app/friends/page.tsx b/frontend/app/(pages)/friends/page.tsx similarity index 100% rename from frontend/app/friends/page.tsx rename to frontend/app/(pages)/friends/page.tsx diff --git a/frontend/app/(pages)/layout.tsx b/frontend/app/(pages)/layout.tsx new file mode 100644 index 0000000..61f980a --- /dev/null +++ b/frontend/app/(pages)/layout.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import Navbar from '@/components/Navbar'; +import Footer from '@/components/Footer'; + +import * as motion from 'motion/react-client'; + +function Layout({ + children +}: { + children: React.ReactNode; +}) { + return ( +
    + + +
    + { children } +
    +
    +
    +
    + ) + ; +} + +export default Layout; diff --git a/frontend/app/public/MarkdownRenderer.tsx b/frontend/app/(pages)/public/MarkdownRenderer.tsx similarity index 100% rename from frontend/app/public/MarkdownRenderer.tsx rename to frontend/app/(pages)/public/MarkdownRenderer.tsx diff --git a/frontend/app/public/css/article.css b/frontend/app/(pages)/public/css/article.css similarity index 100% rename from frontend/app/public/css/article.css rename to frontend/app/(pages)/public/css/article.css diff --git a/frontend/app/public/screenSizeTrigger.ts b/frontend/app/(pages)/public/screenSizeTrigger.ts similarity index 100% rename from frontend/app/public/screenSizeTrigger.ts rename to frontend/app/(pages)/public/screenSizeTrigger.ts diff --git a/frontend/app/public/type/Result.ts b/frontend/app/(pages)/public/type/Result.ts similarity index 100% rename from frontend/app/public/type/Result.ts rename to frontend/app/(pages)/public/type/Result.ts diff --git a/frontend/app/search/page.tsx b/frontend/app/(pages)/search/page.tsx similarity index 100% rename from frontend/app/search/page.tsx rename to frontend/app/(pages)/search/page.tsx diff --git a/frontend/app/Activities.tsx b/frontend/app/Activities.tsx new file mode 100644 index 0000000..2d5294d --- /dev/null +++ b/frontend/app/Activities.tsx @@ -0,0 +1,43 @@ +import React, { useEffect, useState } from 'react'; +import { Activity } from '@/src/HomePageActivities/activity'; +import { getGhActivities } from '@/src/HomePageActivities/ghActivity'; +import * as motion from 'motion/react-client'; + +const Activities = () => { + + const [ activities, setActivities ] = useState(null); + + useEffect(() => { + getGhActivities().then(data => setActivities(data)); + }, []); + + if (!activities) { + return ( +
    +

    loading

    +
    + ); + } else { + return ( +
    +
      + { activities.map((activity, key) => ( + +
    • + { activity.toElement() } +
    • +
      + )) } +
    +
    + ); + } + +}; + +export default Activities; \ No newline at end of file diff --git a/frontend/app/blog/post/[id]/PostCard.tsx b/frontend/app/blog/post/[id]/PostCard.tsx deleted file mode 100644 index 958979f..0000000 --- a/frontend/app/blog/post/[id]/PostCard.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React from 'react'; -import { Card, CardBody } from '@nextui-org/card'; -import Headers from '@/app/blog/post/[id]/Headers'; -import Footer from '@/app/blog/post/[id]/Footer'; -import { fetchNocturneApi } from '@/app/blog/api'; -import MarkdownRenderer from '@/app/public/MarkdownRenderer'; - -type Props = { - id: string -} - -async function PostCard(props: Props) { - - - try { - const res = await fetchNocturneApi(`/blog/get_post/${ props.id }`); - const ret: any = await res.json(); - return ( -
    - - - {/* card headers */ } - - - {/* card body */ } - -
    - - { ret['content'] } - -
    -
    - - - {/* card footer */ } -
    - - -
    - ); - } catch (e: any) { - return
    - - - Fatal: { e.toString() } - - -
    ; - } - -} - -export default PostCard; diff --git a/frontend/app/blog/post/[id]/page.tsx b/frontend/app/blog/post/[id]/page.tsx deleted file mode 100644 index c29364d..0000000 --- a/frontend/app/blog/post/[id]/page.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import PostCard from '@/app/blog/post/[id]/PostCard'; -import { MotionDiv } from '@/app/public/MotionDiv'; -import ButtonGoBack from '@/app/blog/post/[id]/ButtonGoBack'; - -async function BlogReader({ - params -}: { - params: Promise<{ id: string }> -}) { - - return ( - -
    - -
    -
    - -
    -
    - ); -} - -export default BlogReader; diff --git a/frontend/app/entries.tsx b/frontend/app/entries.tsx new file mode 100644 index 0000000..adcf6a3 --- /dev/null +++ b/frontend/app/entries.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { + IoFlask, + IoHome, + IoInformationCircle, + IoLink, + IoLogoGithub, + IoMail, + IoPencil, + IoSearch +} from 'react-icons/io5'; + +export const entries: { display_name: string; href: string; icon: React.ReactNode }[] = [ + { + icon: , + display_name: 'Home', + href: '/' + }, + { + icon: , + display_name: 'About', + href: '/about' + }, + { + icon: , + display_name: 'Blog', + href: '/blog' + }, + { + icon: , + display_name: 'Friends', + href: '/friends' + }, + { + icon: , + display_name: 'Search', + href: '/search' + }, { + icon: , + display_name: 'Lab', + href: 'https://lab.lmt.moe' + } +]; + +export const connections: { label: string, href: string, icon: React.ReactNode }[] = [ + { + label: 'Github', + href: 'https://github.com/Lumither', + icon: + }, + { + label: 'email', + href: 'mailto:lumither@outlook.com', + icon: + } +]; diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index 1c4b3c9..04bb4b9 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -2,13 +2,14 @@ import type { Metadata } from 'next'; import './globals.css'; import React from 'react'; import { ThemeProvider as NextThemesProvider } from 'next-themes'; -import Navbar from '@/components/Navbar'; -import Footer from '@/components/Footer'; - +import { SITE_CONFIG } from '@/src/constants'; export const metadata: Metadata = { - title: 'Lumitherの酒馆', - description: '一间位于时间夹缝中的酒馆,静候下一位旅者的到来...' + openGraph: { + siteName: SITE_CONFIG.name + }, + title: SITE_CONFIG.name, + description: SITE_CONFIG.desc }; export default function RootLayout({ @@ -20,13 +21,7 @@ export default function RootLayout({ -
    - -
    - { children } -
    -
    -
    + { children }
    diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index e9f70cd..bcd8567 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -1,10 +1,51 @@ -import ConstructionPlaceHolder from '@/components/ConstructionPlaceHolder'; +'use client'; + import React from 'react'; +import { useScreenSizeTrigger } from '@/app/(pages)/public/screenSizeTrigger'; +import { Button } from '@nextui-org/react'; +import { entries } from '@/app/entries'; +import Link from 'next/link'; +import { useLocalStorage } from 'react-use'; export default function Home() { + + const isMobile = useScreenSizeTrigger('lg'); + + const [ test, setTest, removeTest ] = useLocalStorage('test', 'test_value'); + console.log(test); + // setTest('test value 2'); + // console.log(test); + // removeTest(); + // console.log(test); + return ( -
    - +
    +
      + { + entries.map((meta, key) => ( +
    • + +
    • + )) + } +
    +
    +
    +
    ); } diff --git a/frontend/app/public/MotionDiv.tsx b/frontend/app/public/MotionDiv.tsx deleted file mode 100644 index 224a656..0000000 --- a/frontend/app/public/MotionDiv.tsx +++ /dev/null @@ -1,5 +0,0 @@ -'use client'; - -import { motion } from 'framer-motion'; - -export const MotionDiv = motion.div; diff --git a/frontend/components/Navbar.tsx b/frontend/components/Navbar.tsx index ea0238c..ab48da5 100644 --- a/frontend/components/Navbar.tsx +++ b/frontend/components/Navbar.tsx @@ -3,65 +3,12 @@ import React, { useEffect, useState } from 'react'; import { Button } from '@nextui-org/react'; import Image from 'next/image'; -import { - IoFlask, - IoHome, - IoInformationCircle, - IoLink, - IoLogoGithub, - IoMail, - IoPencil, - IoSearch -} from 'react-icons/io5'; import Link from 'next/link'; import ThemeSwitcher from '@/components/ThemeSwitcher'; import { usePathname } from 'next/navigation'; -import { useScreenSizeTrigger } from '@/app/public/screenSizeTrigger'; +import { useScreenSizeTrigger } from '@/app/(pages)/public/screenSizeTrigger'; +import { connections, entries } from '@/app/entries'; -const entries: { display_name: string; href: string; icon: React.ReactNode }[] = [ - { - icon: , - display_name: 'Home', - href: '/' - }, - { - icon: , - display_name: 'About', - href: '/about' - }, - { - icon: , - display_name: 'Blog', - href: '/blog' - }, - { - icon: , - display_name: 'Friends', - href: '/friends' - }, - { - icon: , - display_name: 'Search', - href: '/search' - }, { - icon: , - display_name: 'Lab', - href: 'https://lab.lmt.moe' - } -]; - -const connections: { label: string, href: string, icon: React.ReactNode }[] = [ - { - label: 'Github', - href: 'https://github.com/Lumither', - icon: - }, - { - label: 'email', - href: 'mailto:lumither@outlook.com', - icon: - } -]; function Navbar() { diff --git a/frontend/components/ThemeSwitcher.tsx b/frontend/components/ThemeSwitcher.tsx index 0dbc95f..891867a 100644 --- a/frontend/components/ThemeSwitcher.tsx +++ b/frontend/components/ThemeSwitcher.tsx @@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react'; import { useTheme } from 'next-themes'; import { Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger } from '@nextui-org/react'; import { MdOutlineDarkMode, MdOutlineDesktopWindows, MdOutlineLightMode } from 'react-icons/md'; -import { useScreenSizeTrigger } from '@/app/public/screenSizeTrigger'; +import { useScreenSizeTrigger } from '@/app/(pages)/public/screenSizeTrigger'; const switcherElements = new Map( [ diff --git a/frontend/package.json b/frontend/package.json index 92be224..6497820 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,8 +11,8 @@ "dependencies": { "@nextui-org/react": "^2.4.6", "@types/react-syntax-highlighter": "^15.5.13", - "framer-motion": "^11.3.24", "lxgw-wenkai-webfont": "^1.7.0", + "motion": "^12.3.1", "next": "^15.0.3", "next-themes": "^0.3.0", "react": "^18.3.1", @@ -20,6 +20,7 @@ "react-icons": "^5.2.1", "react-markdown": "^9.0.1", "react-syntax-highlighter": "^15.5.0", + "react-use": "^17.6.0", "rehype-raw": "^7.0.0", "rehype-sanitize": "^6.0.0", "remark-frontmatter": "^5.0.0", diff --git a/frontend/src/HomePageActivities/activity.tsx b/frontend/src/HomePageActivities/activity.tsx new file mode 100644 index 0000000..d7f5ea4 --- /dev/null +++ b/frontend/src/HomePageActivities/activity.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + + +export abstract class Activity { + protected constructor( + readonly time: Date + ) { + } + + abstract toElement(): React.ReactElement; + +} + +export abstract class GhActivity extends Activity { + protected constructor(time: Date) { + super(time); + } +} diff --git a/frontend/src/HomePageActivities/constants.ts b/frontend/src/HomePageActivities/constants.ts new file mode 100644 index 0000000..b75cc9c --- /dev/null +++ b/frontend/src/HomePageActivities/constants.ts @@ -0,0 +1 @@ +export const GH_USER_NAME = 'Lumither'; diff --git a/frontend/src/HomePageActivities/ghActivities/starRepo.tsx b/frontend/src/HomePageActivities/ghActivities/starRepo.tsx new file mode 100644 index 0000000..8cacb89 --- /dev/null +++ b/frontend/src/HomePageActivities/ghActivities/starRepo.tsx @@ -0,0 +1,34 @@ +import { GhActivity } from '@/src/HomePageActivities/activity'; +import { Card, CardBody } from '@nextui-org/card'; +import Link from 'next/link'; + +export class StarRepo extends GhActivity { + constructor( + readonly repoName: string, + readonly repoUrl: string, + time: Date + ) { + super(time); + } + + toElement() { + return ( + //
    + // { `${ GH_USER_NAME } started ${ this.repoName } at ${ this.time }` } + //
    + + +

    { `Stared GitHub repository '${ this.repoName }'` }

    +
    +
    + + ); + } +} diff --git a/frontend/src/HomePageActivities/ghActivity.tsx b/frontend/src/HomePageActivities/ghActivity.tsx new file mode 100644 index 0000000..689a6ad --- /dev/null +++ b/frontend/src/HomePageActivities/ghActivity.tsx @@ -0,0 +1,32 @@ +import { GhActivity } from '@/src/HomePageActivities/activity'; +import { match } from 'ts-pattern'; +import { StarRepo } from '@/src/HomePageActivities/ghActivities/starRepo'; +import { GH_USER_NAME } from '@/src/HomePageActivities/constants'; + + +export const getGhActivities: () => Promise = async () => { + const data = await fetch(`https://api.github.com/users/${ GH_USER_NAME }/events`, { + headers: { + 'Accept': 'application/vnd.github+json', + 'X-GitHub-Api-Version': '2022-11-28' + } + }); + return data + .json() + .then((ret: any): GhActivity[] => ( + ret + .map((res: any) => ( + match(res) + .returnType() + // star repo + .with( + { type: 'WatchEvent', payload: { action: 'started' } } + , () => ( + new StarRepo(res.repo.name, res.repo.url, res.created_at) + )) + // to be continued + .otherwise(() => undefined)) + ) + .filter((res: GhActivity | undefined) => res !== undefined) + )); +}; \ No newline at end of file diff --git a/frontend/src/constants.ts b/frontend/src/constants.ts new file mode 100644 index 0000000..37ff01d --- /dev/null +++ b/frontend/src/constants.ts @@ -0,0 +1,4 @@ +export const SITE_CONFIG = { + name: 'Atelier Lumiaethor', + desc: '' +}; \ No newline at end of file