From d2578abeec4e5f766b4dc13b7f9d1f7086952378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20LUDWIG?= Date: Tue, 1 Aug 2023 18:59:45 +0200 Subject: [PATCH] fix: loader improvements --- app/blog/[slug]/loading.tsx | 11 +++ app/blog/[slug]/page.tsx | 120 +--------------------------- app/blog/loading.tsx | 11 +++ app/blog/page.tsx | 2 +- app/loading.tsx | 2 +- blog/BlogPost.tsx | 35 ++++++++ blog/BlogPostContent.tsx | 111 +++++++++++++++++++++++++ blog/blog.ts | 32 ++++---- components/Loader/Loader.module.css | 39 --------- components/Loader/Loader.tsx | 33 -------- components/design/Loader.tsx | 28 +++++++ 11 files changed, 217 insertions(+), 207 deletions(-) create mode 100644 app/blog/[slug]/loading.tsx create mode 100644 app/blog/loading.tsx create mode 100644 blog/BlogPost.tsx create mode 100644 blog/BlogPostContent.tsx delete mode 100644 components/Loader/Loader.module.css delete mode 100644 components/Loader/Loader.tsx create mode 100644 components/design/Loader.tsx diff --git a/app/blog/[slug]/loading.tsx b/app/blog/[slug]/loading.tsx new file mode 100644 index 0000000..663fff6 --- /dev/null +++ b/app/blog/[slug]/loading.tsx @@ -0,0 +1,11 @@ +import { Loader } from '@/components/design/Loader' + +const Loading = (): JSX.Element => { + return ( +
+ +
+ ) +} + +export default Loading diff --git a/app/blog/[slug]/page.tsx b/app/blog/[slug]/page.tsx index 4fb28cb..bd4d133 100644 --- a/app/blog/[slug]/page.tsx +++ b/app/blog/[slug]/page.tsx @@ -1,46 +1,10 @@ import type { Metadata } from 'next' import { notFound } from 'next/navigation' -import { cookies } from 'next/headers' -import Link from 'next/link' -import Image from 'next/image' -import { MDXRemote } from 'next-mdx-remote/rsc' -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faLink } from '@fortawesome/free-solid-svg-icons' -import date from 'date-and-time' -import { nodeTypes } from '@mdx-js/mdx' -import rehypeRaw from 'rehype-raw' -import remarkGfm from 'remark-gfm' -import rehypeSlug from 'rehype-slug' -import remarkMath from 'remark-math' -import rehypeKatex from 'rehype-katex' -import { getHighlighter } from 'shiki' import 'katex/dist/katex.min.css' -import { remarkSyntaxHighlightingPlugin } from '@/blog/remarkSyntaxHighlightingPlugin' import { getBlogPostBySlug } from '@/blog/blog' -import { BlogPostComments } from '@/blog/BlogPostComments' -import { getTheme } from '@/theme/theme.server' - -const Heading = ( - props: React.DetailedHTMLProps< - React.HTMLAttributes, - HTMLHeadingElement - > -): JSX.Element => { - const { children, id = '' } = props - return ( -

- - - - {children} -

- ) -} +import { BlogPost } from '@/blog/BlogPost' interface BlogPostPageProps { params: { @@ -52,7 +16,7 @@ export const generateMetadata = async ( props: BlogPostPageProps ): Promise => { const blogPost = await getBlogPostBySlug(props.params.slug) - if (blogPost == null || !blogPost.frontmatter.isPublished) { + if (blogPost == null) { return notFound() } const title = `${blogPost.frontmatter.title} | Théo LUDWIG` @@ -74,85 +38,7 @@ export const generateMetadata = async ( const BlogPostPage = async (props: BlogPostPageProps): Promise => { const { params } = props - const blogPost = await getBlogPostBySlug(params.slug) - if (blogPost == null || !blogPost.frontmatter.isPublished) { - return notFound() - } - - const cookiesStore = cookies() - const theme = getTheme() - - const highlighter = await getHighlighter({ - theme: `${theme}-plus` - }) - - return ( -
-
-

{blogPost.frontmatter.title}

-

- {date.format( - new Date(blogPost.frontmatter.publishedOn), - 'DD/MM/YYYY' - )} -

-
-
-
- { - const { src = '', alt = 'Blog Image' } = properties - const source = src.replace('../../public/', '/') - return ( - - {alt} - - ) - }, - a: (props) => { - const { href = '' } = props - if (href.startsWith('#')) { - return - } - return ( - - ) - } - }} - /> - -
-
-
- ) + return } export default BlogPostPage diff --git a/app/blog/loading.tsx b/app/blog/loading.tsx new file mode 100644 index 0000000..663fff6 --- /dev/null +++ b/app/blog/loading.tsx @@ -0,0 +1,11 @@ +import { Loader } from '@/components/design/Loader' + +const Loading = (): JSX.Element => { + return ( +
+ +
+ ) +} + +export default Loading diff --git a/app/blog/page.tsx b/app/blog/page.tsx index d767114..b503ef0 100644 --- a/app/blog/page.tsx +++ b/app/blog/page.tsx @@ -2,7 +2,7 @@ import { Suspense } from 'react' import type { Metadata } from 'next' import { BlogPosts } from '@/blog/BlogPosts' -import { Loader } from '@/components/Loader/Loader' +import { Loader } from '@/components/design/Loader' const title = 'Blog | Théo LUDWIG' const description = diff --git a/app/loading.tsx b/app/loading.tsx index ec8f4ff..663fff6 100644 --- a/app/loading.tsx +++ b/app/loading.tsx @@ -1,4 +1,4 @@ -import { Loader } from '@/components/Loader/Loader' +import { Loader } from '@/components/design/Loader' const Loading = (): JSX.Element => { return ( diff --git a/blog/BlogPost.tsx b/blog/BlogPost.tsx new file mode 100644 index 0000000..7e50bf2 --- /dev/null +++ b/blog/BlogPost.tsx @@ -0,0 +1,35 @@ +import { notFound } from 'next/navigation' +import date from 'date-and-time' + +import 'katex/dist/katex.min.css' + +import { getBlogPostBySlug } from '@/blog/blog' +import { BlogPostContent } from '@/blog/BlogPostContent' + +export interface BlogPostProps { + slug: string +} + +export const BlogPost = async (props: BlogPostProps): Promise => { + const { slug } = props + + const blogPost = await getBlogPostBySlug(slug) + if (blogPost == null) { + return notFound() + } + + return ( +
+
+

{blogPost.frontmatter.title}

+

+ {date.format( + new Date(blogPost.frontmatter.publishedOn), + 'DD/MM/YYYY' + )} +

+
+ +
+ ) +} diff --git a/blog/BlogPostContent.tsx b/blog/BlogPostContent.tsx new file mode 100644 index 0000000..ebe4126 --- /dev/null +++ b/blog/BlogPostContent.tsx @@ -0,0 +1,111 @@ +import Image from 'next/image' +import Link from 'next/link' +import { cookies } from 'next/headers' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faLink } from '@fortawesome/free-solid-svg-icons' +import { MDXRemote } from 'next-mdx-remote/rsc' +import { nodeTypes } from '@mdx-js/mdx' +import rehypeRaw from 'rehype-raw' +import remarkGfm from 'remark-gfm' +import rehypeSlug from 'rehype-slug' +import remarkMath from 'remark-math' +import rehypeKatex from 'rehype-katex' +import { getHighlighter } from 'shiki' + +import 'katex/dist/katex.min.css' + +import { getTheme } from '@/theme/theme.server' +import { remarkSyntaxHighlightingPlugin } from '@/blog/remarkSyntaxHighlightingPlugin' +import { BlogPostComments } from '@/blog/BlogPostComments' + +const Heading = ( + props: React.DetailedHTMLProps< + React.HTMLAttributes, + HTMLHeadingElement + > +): JSX.Element => { + const { children, id = '' } = props + return ( +

+ + + + {children} +

+ ) +} + +export interface BlogPostContentProps { + content: string +} + +export const BlogPostContent = async ( + props: BlogPostContentProps +): Promise => { + const { content } = props + + const cookiesStore = cookies() + const theme = getTheme() + + const highlighter = await getHighlighter({ + theme: `${theme}-plus` + }) + + return ( +
+ +
+ ) +} diff --git a/blog/blog.ts b/blog/blog.ts index ee984ad..ca591f9 100644 --- a/blog/blog.ts +++ b/blog/blog.ts @@ -4,7 +4,7 @@ import path from 'node:path' import { cache } from 'react' import matter from 'gray-matter' -export const POSTS_PATH = path.join(process.cwd(), 'blog', 'posts') +export const BLOG_POSTS_PATH = path.join(process.cwd(), 'blog', 'posts') export interface FrontMatter { title: string @@ -13,21 +13,21 @@ export interface FrontMatter { publishedOn: string } -export interface Post { +export interface BlogPost { frontmatter: FrontMatter slug: string content: string } -export const getBlogPosts = cache(async (): Promise => { - const posts = await fs.promises.readdir(POSTS_PATH) - const postsWithTime = await Promise.all( - posts.map(async (postFilename) => { - const [slug, extension] = postFilename.split('.') +export const getBlogPosts = cache(async (): Promise => { + const blogPosts = await fs.promises.readdir(BLOG_POSTS_PATH) + const blogPostsWithTime = await Promise.all( + blogPosts.map(async (blogPostFilename) => { + const [slug, extension] = blogPostFilename.split('.') if (slug == null || extension == null) { - throw new Error('Invalid postFilename.') + throw new Error('Invalid blog post filename.') } - const blogPostPath = path.join(POSTS_PATH, `${slug}.${extension}`) + const blogPostPath = path.join(BLOG_POSTS_PATH, `${slug}.${extension}`) const blogPostContent = await fs.promises.readFile(blogPostPath, { encoding: 'utf8' }) @@ -44,22 +44,22 @@ export const getBlogPosts = cache(async (): Promise => { } }) ) - const postsWithTimeSorted = postsWithTime + const blogPostsSortedByPublicationDate = blogPostsWithTime .filter((post) => { return post.frontmatter.isPublished }) .sort((a, b) => { return b.time - a.time }) - return postsWithTimeSorted + return blogPostsSortedByPublicationDate }) export const getBlogPostBySlug = cache( - async (slug: string): Promise => { - const posts = await getBlogPosts() - const post = posts.find((post) => { - return post.slug === slug + async (slug: string): Promise => { + const blogPosts = await getBlogPosts() + const blogPost = blogPosts.find((blogPost) => { + return blogPost.slug === slug && blogPost.frontmatter.isPublished }) - return post + return blogPost } ) diff --git a/components/Loader/Loader.module.css b/components/Loader/Loader.module.css deleted file mode 100644 index f75b8b0..0000000 --- a/components/Loader/Loader.module.css +++ /dev/null @@ -1,39 +0,0 @@ -@keyframes progressSpinnerRotate { - 100% { - transform: rotate(360deg); - } -} -@keyframes progressSpinnerDash { - 0% { - stroke-dasharray: 1, 200; - stroke-dashoffset: 0; - } - 50% { - stroke-dasharray: 89, 200; - stroke-dashoffset: -35px; - } - 100% { - stroke-dasharray: 89, 200; - stroke-dashoffset: -124px; - } -} - -.progressSpinnerSvg { - animation: progressSpinnerRotate 2s linear infinite; - height: 100%; - transform-origin: center center; - width: 100%; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - margin: auto; -} -.progressSpinnerCircle { - stroke-dasharray: 89, 200; - stroke-dashoffset: 0; - stroke: #ffd800; - animation: progressSpinnerDash 1.5s ease-in-out infinite; - stroke-linecap: round; -} diff --git a/components/Loader/Loader.tsx b/components/Loader/Loader.tsx deleted file mode 100644 index 89fd87f..0000000 --- a/components/Loader/Loader.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import styles from './Loader.module.css' - -export interface LoaderProps { - width?: number - height?: number - className?: string -} - -export const Loader = (props: LoaderProps): JSX.Element => { - const { width = 50, height = 50, className } = props - - return ( -
-
- - - -
-
- ) -} diff --git a/components/design/Loader.tsx b/components/design/Loader.tsx new file mode 100644 index 0000000..fec06cd --- /dev/null +++ b/components/design/Loader.tsx @@ -0,0 +1,28 @@ +import classNames from 'clsx' + +export interface LoaderProps { + width?: number + height?: number + className?: string +} + +export const Loader = (props: LoaderProps): JSX.Element => { + const { width = 50, height = 50, className } = props + + return ( +
+ Loading... +
+ ) +}