feat: enhance date formatting in changelog
Build & Push Docker Image / build (push) Has been cancelled

- Added support for Latin digit formatting in release dates to improve readability.
- Updated the ChangelogVersionCard component to ensure proper text direction for dates.
This commit is contained in:
ar.badiei
2026-07-12 02:08:11 +03:30
parent 6cb9e2aac5
commit f0c290786e
5 changed files with 49 additions and 15 deletions
+6 -1
View File
@@ -31,7 +31,12 @@ export async function generateMetadata({
params,
}: BlogPostPageProps): Promise<Metadata> {
const { slug } = await params;
const post = await getPostBySlug(slug);
let post;
try {
post = await getPostBySlug(slug);
} catch {
return { title: "پست یافت نشد" };
}
if (!post) return { title: "پست یافت نشد" };
const titleRaw = post.title?.rendered ?? "پست";
const title = stripHtml(titleRaw);
+3 -3
View File
@@ -28,7 +28,7 @@ export function BlogPostCard({
if (variant === "related") {
return (
<Link href={`/blog/${encodeURIComponent(post.slug)}`} className="block h-full min-w-0">
<Link href={`/blog/${post.slug}`} className="block h-full min-w-0">
<Card className="h-full overflow-hidden transition-all rounded-md duration-300 hover:shadow-md flex flex-col p-0 gap-0">
<CardContent className="p-3 sm:p-4 grid grid-cols-3 gap-3 sm:gap-4 min-w-0">
{thumbnailUrl ? (
@@ -76,7 +76,7 @@ export function BlogPostCard({
if (variant === "tiny") {
return (
<Link href={`/blog/${encodeURIComponent(post.slug)}`} className="block h-full">
<Link href={`/blog/${post.slug}`} className="block h-full">
<Card className="h-full overflow-hidden transition-all rounded-md duration-300 hover:shadow-md flex flex-col p-2">
<CardContent className="p-2 grid grid-cols-3 gap-4">
{thumbnailUrl ? (
@@ -123,7 +123,7 @@ export function BlogPostCard({
}
return (
<Link href={`/blog/${encodeURIComponent(post.slug)}`} className="block h-full">
<Link href={`/blog/${post.slug}`} className="block h-full">
<Card className="h-full overflow-hidden transition-all duration-300 hover:-translate-y-1 hover:shadow-lg pt-0 gap-1">
{thumbnailUrl ? (
<div className="relative aspect-video w-full overflow-hidden bg-muted">
+2 -2
View File
@@ -27,7 +27,7 @@ function PostCard({
const date = post.date ? formatDateShamsi(post.date) : null;
const authorName = post._embedded?.author?.[0]?.name ?? null;
const thumbnailUrl = getFeaturedImageUrl(post, size === "large" ? "medium_large" : "medium");
const href = `/blog/${encodeURIComponent(post.slug)}`;
const href = `/blog/${post.slug}`;
return (
<Link
@@ -81,7 +81,7 @@ function PostCardRow({ post }: { post: WpPost }) {
const date = post.date ? formatDateShamsi(post.date) : null;
const authorName = post._embedded?.author?.[0]?.name ?? null;
const thumbnailUrl = getFeaturedImageUrl(post, "medium");
const href = `/blog/${encodeURIComponent(post.slug)}`;
const href = `/blog/${post.slug}`;
return (
<Link
+1
Submodule lastest-project added at f7a163c4aa
+37 -9
View File
@@ -136,18 +136,46 @@ export async function getPosts(
return { posts, total, totalPages };
}
export async function getPostBySlug(slug: string): Promise<WpPost | null> {
const decodedSlug = decodeURIComponent(slug);
const params = new URLSearchParams({ slug: decodedSlug, _embed: "1" });
const url = `${WP_API_BASE}/posts?${params.toString()}`;
const res = await fetchWithTimeout(url);
/** وردپرس گاهی slug را به‌صورت percent-encoded ذخیره می‌کند؛ مسیر ممکن است چندبار encode شده باشد. */
export function normalizeBlogSlug(slug: string): string[] {
const variants: string[] = [];
const seen = new Set<string>();
let current = slug.trim();
if (!res.ok) {
throw new Error(`WP API error: ${res.status} ${res.statusText}`);
for (let i = 0; i < 4 && current; i++) {
if (!seen.has(current)) {
seen.add(current);
variants.push(current);
}
try {
const decoded = decodeURIComponent(current);
if (decoded === current) break;
current = decoded;
} catch {
break;
}
}
const posts: WpPost[] = await res.json();
return posts.length > 0 ? posts[0] : null;
return variants;
}
export async function getPostBySlug(slug: string): Promise<WpPost | null> {
const slugVariants = normalizeBlogSlug(slug);
for (const slugVariant of slugVariants) {
const params = new URLSearchParams({ slug: slugVariant, _embed: "1" });
const url = `${WP_API_BASE}/posts?${params.toString()}`;
const res = await fetchWithTimeout(url);
if (!res.ok) {
throw new Error(`WP API error: ${res.status} ${res.statusText}`);
}
const posts: WpPost[] = await res.json();
if (posts.length > 0) return posts[0];
}
return null;
}
export async function getRelatedPosts(