feat: enhance blog and dashboard UI components

- Update blog post dates in English and Chinese content
- Refactor blog layout with header section and container
- Simplify blog page and post layouts
- Improve blog card and grid styling
- Add initial dashboard page with sidebar and breadcrumbs
- Adjust header section subtitle color
This commit is contained in:
javayhu 2025-03-05 22:45:51 +08:00
parent 71eaefefbf
commit 58401624c0
10 changed files with 39 additions and 31 deletions

View File

@ -2,7 +2,7 @@
title: What is MkSaaS? title: What is MkSaaS?
description: MkSaaS is the best boilerplate for building AI SaaS websites. description: MkSaaS is the best boilerplate for building AI SaaS websites.
image: /images/blog/mksaas-og.png image: /images/blog/mksaas-og.png
date: 2024-11-24T12:00:00.000Z date: 2024-11-26T12:00:00.000Z
published: true published: true
categories: [news, guide] categories: [news, guide]
author: mksaas author: mksaas

View File

@ -2,7 +2,7 @@
title: MkSaaS 是什么? title: MkSaaS 是什么?
description: MkSaaS 是构建 AI SaaS 网站的最佳样板。 description: MkSaaS 是构建 AI SaaS 网站的最佳样板。
image: /images/blog/mksaas-og.png image: /images/blog/mksaas-og.png
date: 2024-11-24T12:00:00.000Z date: 2024-11-26T12:00:00.000Z
published: true published: true
categories: [news, guide] categories: [news, guide]
author: mksaas author: mksaas

View File

@ -1,5 +1,25 @@
import Container from '@/components/container';
import { HeaderSection } from '@/components/shared/header-section';
import { PropsWithChildren } from 'react'; import { PropsWithChildren } from 'react';
export default function BlogLayout({ children }: PropsWithChildren) { export default async function BlogListLayout({
return children; children,
} }: { children: React.ReactNode }) {
return (
<div className="mb-16">
<div className="mt-8 w-full flex flex-col items-center justify-center gap-8">
<HeaderSection
titleAs="h2"
title="MkSaaS Blog"
subtitle="Read our latest blog posts about MkSaaS"
/>
{/* <BlogCategoryFilter /> */}
</div>
<Container className="mt-8 px-4">
{children}
</Container>
</div>
);
}

View File

@ -36,20 +36,6 @@ export default async function BlogPage({ params }: BlogPageProps) {
); );
return ( return (
<Container className="py-8 md:py-12"> <BlogGrid posts={sortedPosts} />
<div className="">
<div className="flex flex-col items-start gap-4 md:flex-row md:justify-between md:gap-8">
<div className="flex-1 space-y-4">
<h1 className="inline-block text-4xl font-bold tracking-tight lg:text-5xl">
Blog
</h1>
<p className="text-xl text-muted-foreground">
Latest news and updates from our team
</p>
</div>
</div>
<BlogGrid posts={sortedPosts} />
</div>
</Container>
); );
} }

View File

@ -1,10 +1,9 @@
import Container from '@/components/container'; import Container from '@/components/container';
import { Separator } from '@/components/ui/separator';
import { PropsWithChildren } from 'react'; import { PropsWithChildren } from 'react';
export default function BlogPostLayout({ children }: PropsWithChildren) { export default function BlogPostLayout({ children }: PropsWithChildren) {
return ( return (
<Container className="py-8 md:py-12"> <Container className="py-8 px-4">
<div className="mx-auto"> <div className="mx-auto">
{children} {children}
</div> </div>

View File

@ -92,9 +92,9 @@ export default async function BlogPostPage(props: NextPageProps) {
return ( return (
<div className="flex flex-col gap-8"> <div className="flex flex-col gap-8">
{/* Content section */} {/* content section */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Left column */} {/* left column (blog post content) */}
<div className="lg:col-span-2 flex flex-col"> <div className="lg:col-span-2 flex flex-col">
{/* Basic information */} {/* Basic information */}
<div className="space-y-8"> <div className="space-y-8">
@ -129,7 +129,7 @@ export default async function BlogPostPage(props: NextPageProps) {
</div> </div>
</div> </div>
{/* Right column (sidebar) */} {/* right column (sidebar) */}
<div> <div>
<div className="space-y-4 lg:sticky lg:top-24"> <div className="space-y-4 lg:sticky lg:top-24">
{/* author info */} {/* author info */}
@ -184,6 +184,9 @@ export default async function BlogPostPage(props: NextPageProps) {
</div> </div>
</div> </div>
</div> </div>
{/* newsletter */}
{/* TODO: add newsletter */}
</div> </div>
); );
} }

View File

@ -71,9 +71,9 @@ export default function BlogCard({ post }: BlogCardProps) {
</h3> </h3>
{/* Post excerpt, hidden for now */} {/* Post excerpt, hidden for now */}
<div className="hidden"> <div className="">
{post.description && ( {post.description && (
<p className="mt-2 line-clamp-3 text-sm text-gray-500 dark:text-gray-400"> <p className="mt-2 line-clamp-2 text-sm text-gray-500 dark:text-gray-400">
<Link href={postUrl}>{post.description}</Link> <Link href={postUrl}>{post.description}</Link>
</p> </p>
)} )}
@ -83,7 +83,7 @@ export default function BlogCard({ post }: BlogCardProps) {
{/* Author and date */} {/* Author and date */}
<div className="mt-auto pt-4 flex items-center justify-between space-x-4 text-muted-foreground"> <div className="mt-auto pt-4 flex items-center justify-between space-x-4 text-muted-foreground">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="relative h-5 w-5 flex-shrink-0"> <div className="relative h-8 w-8 flex-shrink-0">
{post?.author?.avatar && ( {post?.author?.avatar && (
<Image <Image
src={post?.author?.avatar} src={post?.author?.avatar}

View File

@ -11,7 +11,7 @@ export default function BlogGrid({ posts }: BlogGridProps) {
return ( return (
<div> <div>
{posts?.length > 0 && ( {posts?.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-12">
{posts.map((post) => ( {posts.map((post) => (
<BlogCard key={post.slug} post={post} /> <BlogCard key={post.slug} post={post} />
))} ))}
@ -25,7 +25,7 @@ export function BlogGridSkeleton({
count = POSTS_PER_PAGE, count = POSTS_PER_PAGE,
}: { count?: number }) { }: { count?: number }) {
return ( return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-12">
{[...Array(count)].map((_, index) => ( {[...Array(count)].map((_, index) => (
<BlogCardSkeleton key={index} /> <BlogCardSkeleton key={index} />
))} ))}

View File

@ -45,7 +45,7 @@ export function HeaderSection({
</TitleComponent> </TitleComponent>
) : null} ) : null}
{subtitle ? ( {subtitle ? (
<SubtitleComponent className="text-balance text-lg text-foreground/80"> <SubtitleComponent className="text-balance text-lg text-muted-foreground">
{subtitle} {subtitle}
</SubtitleComponent> </SubtitleComponent>
) : null} ) : null}