This commit is contained in:
giancarlo
2024-03-24 02:23:22 +08:00
parent 648d77b430
commit bce3479368
589 changed files with 37067 additions and 9596 deletions

View File

@@ -0,0 +1,33 @@
import Image from 'next/image';
import { cn } from '@kit/ui/utils';
type Props = {
title: string;
src: string;
preloadImage?: boolean;
className?: string;
};
export const CoverImage: React.FC<Props> = ({
title,
src,
preloadImage,
className,
}) => {
return (
<Image
className={cn(
'duration-250 block rounded-xl object-cover' +
' transition-all hover:opacity-90',
{
className,
},
)}
src={src}
priority={preloadImage}
alt={`Cover Image for ${title}`}
fill
/>
);
};

View File

@@ -0,0 +1,11 @@
import { format, parseISO } from 'date-fns';
type Props = {
dateString: string;
};
export const DateFormatter = ({ dateString }: Props) => {
const date = parseISO(dateString);
return <time dateTime={dateString}>{format(date, 'PP')}</time>;
};

View File

@@ -0,0 +1,9 @@
import React from 'react';
export function DraftPostBadge({ children }: React.PropsWithChildren) {
return (
<span className="dark:text-dark-800 rounded-md bg-yellow-200 px-4 py-2 font-semibold">
{children}
</span>
);
}

View File

@@ -0,0 +1,56 @@
import type { Post } from 'contentlayer/generated';
import { CoverImage } from '~/(marketing)/blog/components/cover-image';
import { DateFormatter } from '~/(marketing)/blog/components/date-formatter';
import { Heading } from '@kit/ui/heading';
import { If } from '@kit/ui/if';
const PostHeader: React.FC<{
post: Post;
}> = ({ post }) => {
const { title, date, readingTime, description, image } = post;
// NB: change this to display the post's image
const displayImage = true;
const preloadImage = true;
return (
<div className={'flex flex-col space-y-4'}>
<div className={'flex flex-col space-y-4'}>
<Heading level={1}>{title}</Heading>
<Heading level={3}>
<span className={'font-normal text-muted-foreground'}>
{description}
</span>
</Heading>
</div>
<div className="flex">
<div className="flex flex-row items-center space-x-2 text-sm text-gray-600 dark:text-gray-400">
<div>
<DateFormatter dateString={date} />
</div>
<span>·</span>
<span>{readingTime} minutes reading</span>
</div>
</div>
<If condition={displayImage && image}>
{(imageUrl) => (
<div className="relative mx-auto h-[378px] w-full justify-center">
<CoverImage
preloadImage={preloadImage}
className="rounded-md"
title={title}
src={imageUrl}
/>
</div>
)}
</If>
</div>
);
};
export default PostHeader;

View File

@@ -0,0 +1,70 @@
import Link from 'next/link';
import type { Post } from 'contentlayer/generated';
import { CoverImage } from '~/(marketing)/blog/components/cover-image';
import { DateFormatter } from '~/(marketing)/blog/components/date-formatter';
import { If } from '@kit/ui/if';
type Props = {
post: Post;
preloadImage?: boolean;
imageHeight?: string | number;
};
const DEFAULT_IMAGE_HEIGHT = 250;
function PostPreview({
post,
preloadImage,
imageHeight,
}: React.PropsWithChildren<Props>) {
const { title, image, date, readingTime, description } = post;
const height = imageHeight ?? DEFAULT_IMAGE_HEIGHT;
return (
<div className="rounded-xl transition-shadow duration-500 dark:text-gray-800">
<If condition={image}>
{(imageUrl) => (
<div className="relative mb-2 w-full" style={{ height }}>
<Link href={post.url}>
<CoverImage
preloadImage={preloadImage}
title={title}
src={imageUrl}
/>
</Link>
</div>
)}
</If>
<div className={'px-1'}>
<div className="flex flex-col space-y-1 px-1 py-2">
<h3 className="px-1 text-2xl font-bold leading-snug dark:text-white">
<Link href={post.url} className="hover:underline">
{title}
</Link>
</h3>
</div>
<div className="mb-2 flex flex-row items-center space-x-2 px-1 text-sm">
<div className="text-gray-600 dark:text-gray-300">
<DateFormatter dateString={date} />
</div>
<span className="text-gray-600 dark:text-gray-300">·</span>
<span className="text-gray-600 dark:text-gray-300">
{readingTime} mins reading
</span>
</div>
<p className="mb-4 px-1 text-sm leading-relaxed dark:text-gray-300">
{description}
</p>
</div>
</div>
);
}
export default PostPreview;

View File

@@ -0,0 +1,24 @@
import React from 'react';
import type { Post as PostType } from 'contentlayer/generated';
import { Mdx } from '@kit/ui/mdx';
import PostHeader from './post-header';
export const Post: React.FC<{
post: PostType;
content: string;
}> = ({ post, content }) => {
return (
<div className={'mx-auto my-8 max-w-2xl'}>
<PostHeader post={post} />
<article className={'mx-auto flex justify-center'}>
<Mdx code={content} />
</article>
</div>
);
};
export default Post;