feat: improve blog localization and error handling
- Add new localization keys for "all" and "noPostsFound" in English and Chinese - Update blog components to use localized translations - Add optional chaining for category properties to prevent rendering errors - Improve mobile and desktop category list components with translations
This commit is contained in:
parent
4657e5b691
commit
2f4b8e23fe
@ -63,6 +63,8 @@
|
||||
"subtitle": "Latest news and updates from our team",
|
||||
"publisher": "Publisher",
|
||||
"categories": "Categories",
|
||||
"tableOfContents": "Table of Contents"
|
||||
"tableOfContents": "Table of Contents",
|
||||
"all": "All",
|
||||
"noPostsFound": "No posts found"
|
||||
}
|
||||
}
|
@ -63,6 +63,8 @@
|
||||
"subtitle": "来自我们的团队最新新闻和更新",
|
||||
"publisher": "发布者",
|
||||
"categories": "分类",
|
||||
"tableOfContents": "目录"
|
||||
"tableOfContents": "目录",
|
||||
"all": "全部",
|
||||
"noPostsFound": "没有找到文章"
|
||||
}
|
||||
}
|
@ -38,10 +38,10 @@ export default function BlogCard({ post }: BlogCardProps) {
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{post.categories.map((category, index) => (
|
||||
<span
|
||||
key={`${category.slug}-${index}`}
|
||||
key={`${category?.slug}-${index}`}
|
||||
className="text-xs font-medium text-white bg-black bg-opacity-50 px-2 py-1 rounded-md"
|
||||
>
|
||||
{category.name}
|
||||
{category?.name}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@ export function BlogCategoryListDesktop({
|
||||
categoryList,
|
||||
}: BlogCategoryListDesktopProps) {
|
||||
const { slug } = useParams() as { slug?: string };
|
||||
const t = useTranslations("BlogPage.categories");
|
||||
const t = useTranslations("BlogPage");
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -54,6 +54,7 @@ export function BlogCategoryListDesktop({
|
||||
)}
|
||||
aria-label={`Toggle blog category of ${category.name}`}
|
||||
>
|
||||
{/* TODO: fix as any */}
|
||||
<Link href={`/blog/category/${category.slug}` as any}>
|
||||
<h2>{category.name}</h2>
|
||||
</Link>
|
||||
|
@ -6,6 +6,7 @@ import { useParams } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { Drawer } from "vaul";
|
||||
import FilterItemMobile from "@/components/shared/filter-item-mobile";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export type BlogCategoryListMobileProps = {
|
||||
categoryList: Category[];
|
||||
@ -14,11 +15,12 @@ export type BlogCategoryListMobileProps = {
|
||||
export function BlogCategoryListMobile({
|
||||
categoryList,
|
||||
}: BlogCategoryListMobileProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const { slug } = useParams() as { slug?: string };
|
||||
const selectedCategory = categoryList.find(
|
||||
(category) => category.slug === slug,
|
||||
);
|
||||
const [open, setOpen] = useState(false);
|
||||
const t = useTranslations("BlogPage");
|
||||
|
||||
const closeDrawer = () => {
|
||||
setOpen(false);
|
||||
@ -33,10 +35,10 @@ export function BlogCategoryListMobile({
|
||||
<div className="flex items-center justify-between w-full gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<LayoutListIcon className="size-5" />
|
||||
<span className="text-sm">Category</span>
|
||||
<span className="text-sm">{t("categories")}</span>
|
||||
</div>
|
||||
<span className="text-sm">
|
||||
{selectedCategory?.name ? `${selectedCategory?.name}` : "All"}
|
||||
{selectedCategory?.name ? `${selectedCategory?.name}` : t("all")}
|
||||
</span>
|
||||
</div>
|
||||
</Drawer.Trigger>
|
||||
@ -46,14 +48,14 @@ export function BlogCategoryListMobile({
|
||||
/>
|
||||
<Drawer.Portal>
|
||||
<Drawer.Content className="fixed inset-x-0 bottom-0 z-50 mt-24 overflow-hidden rounded-t-[10px] border bg-background">
|
||||
<Drawer.Title className="sr-only">Category</Drawer.Title>
|
||||
<Drawer.Title className="sr-only">{t("categories")}</Drawer.Title>
|
||||
<div className="sticky top-0 z-20 flex w-full items-center justify-center bg-inherit">
|
||||
<div className="my-3 h-1.5 w-16 rounded-full bg-muted-foreground/20" />
|
||||
</div>
|
||||
|
||||
<ul className="mb-14 w-full p-3 text-muted-foreground">
|
||||
<FilterItemMobile
|
||||
title="All"
|
||||
title={t("all")}
|
||||
href="/blog"
|
||||
active={!slug}
|
||||
clickAction={closeDrawer}
|
||||
|
@ -30,7 +30,7 @@ export function BlogPost({ post }: BlogPostProps): React.JSX.Element {
|
||||
<div className="space-y-8">
|
||||
<div className="flex flex-row items-center justify-between gap-4 text-base text-muted-foreground">
|
||||
<span className="flex flex-row items-center gap-2">
|
||||
{post.categories.map((c) => c.name).join(', ')}
|
||||
{post.categories.map((c) => c?.name).join(', ')}
|
||||
</span>
|
||||
<span className="flex flex-row items-center gap-2">
|
||||
<time dateTime={post.date}>
|
||||
|
@ -36,7 +36,7 @@ export function BlogPosts(): React.JSX.Element {
|
||||
className="md:duration-2000 flex h-full flex-col space-y-4 text-clip border-dashed py-6 md:rounded-2xl md:px-6 md:shadow md:transition-shadow md:hover:shadow-xl dark:md:bg-accent/40 dark:md:hover:bg-accent"
|
||||
>
|
||||
<div className="flex flex-row items-center justify-between text-muted-foreground">
|
||||
<span className="text-sm">{post.categories.map((c) => c.name).join(', ')}</span>
|
||||
<span className="text-sm">{post.categories.map((c) => c?.name).join(', ')}</span>
|
||||
<time
|
||||
className="text-sm"
|
||||
dateTime={post.date}
|
||||
|
@ -1,8 +1,12 @@
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export default function EmptyGrid() {
|
||||
const t = useTranslations("BlogPage");
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="my-8 h-32 w-full flex items-center justify-center">
|
||||
<p className="font-medium text-muted-foreground">Nothing found.</p>
|
||||
<p className="font-medium text-muted-foreground">{t("noPostsFound")}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user