diff --git a/app/blog/[slug]/page.tsx b/app/blog/[slug]/page.tsx index d030858..bca79ea 100644 --- a/app/blog/[slug]/page.tsx +++ b/app/blog/[slug]/page.tsx @@ -97,7 +97,7 @@ export default async function BlogPostPage({ params }: BlogPostPageProps) { className="text-muted-foreground hover:text-foreground text-sm inline-flex items-center gap-1 transition-colors" > - بلاگ + دانشنامه

- بلاگ + دانشنامه

مقالات و مطالب فیپ در زمینه یکپارچه‌سازی، اتوماسیون و بهره‌وری سازمانی. diff --git a/app/page.tsx b/app/page.tsx index 05292d0..2117cb7 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,14 +1,33 @@ import ContentSection from "@/components/content-1"; import Features from "@/components/features-12"; +import { FeaturedPostsGrid } from "@/components/featured-posts-grid"; +import { getPosts } from "@/lib/wp-api"; +import { HeroHeader } from "@/components/header"; import HeroSection from "@/components/hero-section"; -import Image from "next/image"; -export default function Home() { +const FEATURED_CATEGORY_ID = 3; +const FEATURED_POSTS_COUNT = 4; + +export default async function Home() { + let featuredPosts: Awaited>["posts"] = []; + try { + const result = await getPosts({ + categoryId: FEATURED_CATEGORY_ID, + perPage: FEATURED_POSTS_COUNT, + orderby: "date", + order: "desc", + }); + featuredPosts = result.posts; + } catch { + // بدون پست هم صفحه رندر می‌شود + } + return ( <> + ); } diff --git a/components/featured-posts-grid.tsx b/components/featured-posts-grid.tsx new file mode 100644 index 0000000..1adbfb2 --- /dev/null +++ b/components/featured-posts-grid.tsx @@ -0,0 +1,176 @@ +"use client"; + +import Link from "next/link"; +import Image from "next/image"; +import { ChevronLeft, ImageIcon } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { getFeaturedImageUrl, type WpPost } from "@/lib/wp-api"; +import { formatDateShamsi } from "@/lib/format-date"; +import { cn } from "@/lib/utils"; + +function stripHtml(html: string): string { + return html.replace(/<[^>]*>/g, "").trim(); +} + +/** کارت با تصویر به‌صورت پس‌زمینه و عنوان + توضیح در پایین با overlay */ +function PostCard({ + post, + size = "default", +}: { + post: WpPost; + size?: "large" | "default"; +}) { + const excerpt = + stripHtml(post.excerpt.rendered) || + stripHtml(post.content.rendered).slice(0, size === "large" ? 280 : 120); + 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)}`; + + return ( + + {/* پس‌زمینه: تصویر تمام کارت */} + {thumbnailUrl ? ( + + ) : ( +

+ +
+ )} + {/* گرادیان شفاف و متن در پایین */} +
+
+

+

+ {excerpt} +

+

+ + ); +} + +/** کارت ردیفی: تصویر کنار عنوان، بدون توضیح */ +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)}`; + + return ( + + {/* نیمه عنوان + نویسنده */} +
+

+

+ + ); +} + +const DEFAULT_TITLE = "از دانشنامه"; +const DEFAULT_CAPTION = + "از داده تا بینش؛ یادداشت‌ها و تجربه‌هایی که مسیر شما را روشن‌تر می‌کنند."; +const DEFAULT_CTA_LABEL = "مشاهده همه مقالات"; +const DEFAULT_CTA_HREF = "/blog"; + +interface FeaturedPostsGridProps { + posts: WpPost[]; + /** عنوان بخش */ + title?: string; + /** کپشن زیر عنوان */ + caption?: string; + /** متن دکمه CTA */ + ctaLabel?: string; + /** لینک CTA (پیش‌فرض: /blog) */ + ctaHref?: string; +} + +export function FeaturedPostsGrid({ + posts, + title = DEFAULT_TITLE, + caption = DEFAULT_CAPTION, + ctaLabel = DEFAULT_CTA_LABEL, + ctaHref = DEFAULT_CTA_HREF, +}: FeaturedPostsGridProps) { + if (!posts.length) return null; + + const [first, second, third, fourth] = posts; + + return ( +
+
+
+

+ {title} +

+

+ {caption} +

+
+
+ {/* کارت بزرگ: در RTL سمت چپ، در LTR سمت راست */} + {first && ( +
+ +
+ )} + {/* سه کارت کوچک: یک بالا، دو پایین */} +
+ {second && ( +
+ +
+ )} + {third && ( +
+ +
+ )} +
+
+
+

+ مطالب بیشتر در دانشنامه +

+ +
+
+
+ ); +} diff --git a/components/footer.tsx b/components/footer.tsx index 7a6c44a..99e591b 100644 --- a/components/footer.tsx +++ b/components/footer.tsx @@ -7,7 +7,7 @@ const links = [ href: "/about", }, { - title: "بلاگ", + title: "دانشنامه", href: "/blog", }, { diff --git a/components/header.tsx b/components/header.tsx index 90c8987..781ce18 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -10,7 +10,7 @@ import { ThemeToggle } from '@/components/theme-toggle' const menuItems = [ { name: 'صفحه اصلی', href: '/' }, - { name: 'بلاگ', href: '/blog' }, + { name: 'دانشنامه', href: '/blog' }, { name: 'راه حل‌ها', href: '/solutions' }, // { name: 'قیمت‌گذاری', href: '/pricing' }, { name: 'درباره ما', href: '/about' }, diff --git a/lib/wp-api.ts b/lib/wp-api.ts index 287e0b6..38f2dd7 100644 --- a/lib/wp-api.ts +++ b/lib/wp-api.ts @@ -71,6 +71,9 @@ export interface GetPostsOptions { perPage?: number; search?: string; categoryId?: number; + /** ترتیب بر اساس: date, modified, title, ... در وردپرس. برای اولویت دستی (menu_order) پلاگین/فیلتر در وردپرس لازم است. */ + orderby?: string; + order?: "asc" | "desc"; } async function fetchWithTimeout( @@ -96,12 +99,14 @@ async function fetchWithTimeout( export async function getPosts( options: GetPostsOptions = {} ): Promise { - const { page = 1, perPage = 9, search, categoryId } = options; + const { page = 1, perPage = 9, search, categoryId, orderby, order } = options; const params = new URLSearchParams(); params.set("page", String(page)); params.set("per_page", String(perPage)); if (search?.trim()) params.set("search", search.trim()); if (categoryId) params.set("categories", String(categoryId)); + if (orderby) params.set("orderby", orderby); + if (order) params.set("order", order); params.set("_embed", "1"); const url = `${WP_API_BASE}/posts?${params.toString()}`;