"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import { ArrowRight, Slash } from "lucide-react"; import { Fragment, useCallback, useMemo, useState } from "react"; import { ControllerRenderProps, useForm } from "react-hook-form"; import { Controller } from "react-hook-form"; import { z } from "zod"; import { AspectRatio } from "@/components/ui/aspect-ratio"; import { Badge } from "@/components/ui/badge"; import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbSeparator, } from "@/components/ui/breadcrumb"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Checkbox } from "@/components/ui/checkbox"; import { Field, FieldError, FieldGroup, FieldLabel, } from "@/components/ui/field"; import { Input } from "@/components/ui/input"; import { cn } from "@/lib/utils"; interface BreadcrumbItem { label: string; link: string; } interface Post { categoryKey: string; category: string; title: string; summary: string; link: string; cta: string; thumbnail: string; } interface Category { label: string; value: string; } interface FilterFormProps { categories: Array; onCategoryChange: (selectedCategories: string[]) => void; } interface BlogsResultProps { posts: Array; categories: Array; } interface BreadcrumbBlogProps { breadcrumb: Array; } const POSTS_PER_PAGE = 6; const BREADCRUMB: Array = [ { label: "منابع", link: "#", }, { label: "گزارش‌ها", link: "#", }, ]; const CATEGORIES: Array = [ { label: "همه", value: "all", }, { label: "بهره‌وری", value: "productivity", }, { label: "دسترس‌پذیری", value: "accessibility", }, { label: "کارایی", value: "performance", }, ]; const PRIMARY_POST: Post = { categoryKey: "all", category: "ویژه: نوآوری", title: "چگونه هوش مصنوعی توسعه فرانت‌اند را متحول می‌کند", summary: "ببینید ابزارهایی مثل GitHub Copilot، مولدهای طراحی هوش مصنوعی و دستیارهای کدنویسی چگونه ساخت UI و تحویل قابلیت‌ها را برای توسعه‌دهندگان تغییر می‌دهند.", link: "#", cta: "کشف آینده", thumbnail: "/block-media/shadcnblocks/block/placeholder-1.svg", }; const POSTS: Array = [ { categoryKey: "productivity", category: "بهره‌وری", title: "۵ افزونه ویرایشگر کد که ساعت‌ها وقت شما را ذخیره می‌کند", summary: "افزونه‌های ضروری برای افزایش بهره‌وری کدنویسی و ساده‌تر کردن گردش کار.", link: "#", cta: "ویرایشگر را تقویت کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-2.svg", }, { categoryKey: "productivity", category: "بهره‌وری", title: "مدیریت زمان برای توسعه‌دهندگان: چه چیزی واقعاً جواب می‌دهد", summary: "استراتژی‌های اثبات‌شده برای جلوگیری از فرسودگی و مدیریت وظایف بدون استرس.", link: "#", cta: "زمان را مدیریت کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-3.svg", }, { categoryKey: "productivity", category: "بهره‌وری", title: "خودکارسازی گردش کار با اجرای خودکار وظایفها", summary: "از Gulp، اسکریپت‌های npm و GitHub Actions برای خودکار کردن کارهای تکراری توسعه استفاده کنید.", link: "#", cta: "همین حالا خودکار کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-4.svg", }, { categoryKey: "productivity", category: "بهره‌وری", title: "روتین‌های روزانه مؤثر برای توسعه‌دهندگان", summary: "روتین‌هایی که توسعه‌دهندگان برتر برای ماندن پرانرژی، خلاق و متمرکز دنبال می‌کنند.", link: "#", cta: "جریان کاری خود را بیابید", thumbnail: "/block-media/shadcnblocks/block/placeholder-5.svg", }, { categoryKey: "productivity", category: "بهره‌وری", title: "تسلط بر کنترل نسخه با این میانبرها", summary: "گردش کار version control را با aliasها و نکات قدرتمند Git تسریع کنید.", link: "#", cta: "Git را سریع‌تر کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-6.svg", }, { categoryKey: "productivity", category: "بهره‌وری", title: "کاهش تعویض زمینه در کار توسعه", summary: "حواس‌پرتی را کم کنید و با تمرکز عمیق روی کد پیش بروید.", link: "#", cta: "متمرکز بمانید", thumbnail: "/block-media/shadcnblocks/block/placeholder-1.svg", }, { categoryKey: "productivity", category: "بهره‌وری", title: "راه‌اندازی دورکاری: ابزارهای محیط بدون حواس‌پرتی", summary: "فضا و استک نرم‌افزاری را برای حداکثر بهره‌وری در کار از خانه تنظیم کنید.", link: "#", cta: "محیط کار را ارتقا دهید", thumbnail: "/block-media/shadcnblocks/block/placeholder-2.svg", }, { categoryKey: "productivity", category: "بهره‌وری", title: "پومودورو برای برنامه‌نویسان: واقعاً مؤثر است؟", summary: "بررسی عملی تکنیک پومودورو و اثربخشی آن در توسعه نرم‌افزار.", link: "#", cta: "روش را امتحان کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-3.svg", }, { categoryKey: "accessibility", category: "دسترس‌پذیری", title: "چرا دسترس‌پذیری باید بخشی از نسخه اولیه محصول شما باشد", summary: "فراگیر کردن محصول از روز اول، قابلیت استفاده و دسترسی را بهبود می‌دهد.", link: "#", cta: "دلیلش را بدانید", thumbnail: "/block-media/shadcnblocks/block/placeholder-4.svg", }, { categoryKey: "accessibility", category: "دسترس‌پذیری", title: "استفاده درست از نقش‌های برچسب دسترس‌پذیری در وب‌اپ", summary: "چگونه با نقش‌ها و landmarkهای ARIA پشتیبانی screen reader را تقویت کنید.", link: "#", cta: "معناشناسی را بهبود دهید", thumbnail: "/block-media/shadcnblocks/block/placeholder-5.svg", }, { categoryKey: "accessibility", category: "دسترس‌پذیری", title: "نکات کنتراست رنگ برای خوانایی بهتر", summary: "ترکیب‌های رنگی دسترس‌پذیر مطابق استاندارد WCAG را بیاموزید.", link: "#", cta: "رنگ‌ها را اصلاح کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-6.svg", }, { categoryKey: "accessibility", category: "دسترس‌پذیری", title: "ناوبری با کیبورد: تجربه‌ای که نادیده گرفته می‌شود", summary: "وب‌سایت را کاملاً با کیبورد قابل استفاده کنید برای دسترس‌پذیری و سرعت.", link: "#", cta: "ناوبری را تست کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-1.svg", }, { categoryKey: "accessibility", category: "دسترس‌پذیری", title: "فرم‌های دسترس‌پذیر: برچسب، خطا و بازخورد", summary: "با دستورالعمل‌های واضح برای screen reader و کاربران، فرم‌ها را قابل فهم‌تر کنید.", link: "#", cta: "فرم‌ها را اصلاح کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-2.svg", }, { categoryKey: "accessibility", category: "دسترس‌پذیری", title: "تست با صفحه‌خوان: راهنمای مبتدی", summary: "چگونه با screen readerهای رایج سایت را تست کنید و به چه چیزهایی گوش دهید.", link: "#", cta: "تست را شروع کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-3.svg", }, { categoryKey: "accessibility", category: "دسترس‌پذیری", title: "تفکر طراحی فراگیر در توسعه رابط کاربری", summary: "رابط‌هایی طراحی کنید که از ابتدا همه توانایی‌ها را در نظر بگیرند.", link: "#", cta: "برای همه طراحی کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-4.svg", }, { categoryKey: "accessibility", category: "دسترس‌پذیری", title: "ممیزی دسترس‌پذیری: ابزارها و چک‌لیست‌ها", summary: "ممیزی کامل با Axe، Lighthouse و چک‌لیست‌های دستی انجام دهید.", link: "#", cta: "ممیزی کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-5.svg", }, { categoryKey: "performance", category: "کارایی", title: "بارگذاری هوشمند تصاویر با استاندارد وب مدرن", summary: "زمان بارگذاری را با lazy-loading بومی و استراتژی‌های جایگزین بهبود دهید.", link: "#", cta: "تصاویر را بهینه کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-6.svg", }, { categoryKey: "performance", category: "کارایی", title: "فشرده‌سازی برنامه‌نویسی وب بدون خراب کردن اپ", summary: "بهترین روش‌های minify و tree-shaking برای bundleهای سریع‌تر.", link: "#", cta: "کد را کوچک کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-1.svg", }, { categoryKey: "performance", category: "کارایی", title: "شاخص‌های عملکرد وب توضیح داده شد: جابجایی چیدمان، زمان بارگذاری اصلی، تأخیر اولین تعامل", summary: "اندازه‌گیری و بهبود Core Web Vitals برای تجربه کاربری بهتر.", link: "#", cta: "شاخص‌ها را بهبود دهید", thumbnail: "/block-media/shadcnblocks/block/placeholder-2.svg", }, { categoryKey: "performance", category: "کارایی", title: "رندر سمت سرور در برابر کلاینت: کدام سریع‌تر است؟", summary: "SSR و CSR را مقایسه کنید و بدانید هر کدام چه زمانی برای کارایی بهتر مناسب‌اند.", link: "#", cta: "گزینه‌ها را بررسی کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-3.svg", }, { categoryKey: "performance", category: "کارایی", title: "بهینه‌سازی فونت برای بارگذاری سریع‌تر", summary: "فونت را بدون مسدود کردن رندر یا جابجایی layout بارگذاری کنید.", link: "#", cta: "فونت‌ها را سریع کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-4.svg", }, { categoryKey: "performance", category: "کارایی", title: "کاهش حجم بسته با تقسیم هوشمند بار", summary: "با import پویا و chunking مبتنی بر مسیر، زمان بار اولیه را کم کنید.", link: "#", cta: "تقسیم‌بندی کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-5.svg", }, { categoryKey: "performance", category: "کارایی", title: "استراتژی‌های کش برای وب‌اپ‌های مدرن", summary: "از کش HTTP، service worker و CDN برای سرعت و پشتیبانی آفلاین بهره ببرید.", link: "#", cta: "هوشمندانه کش کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-6.svg", }, { categoryKey: "performance", category: "کارایی", title: "تحلیل گلوگاه‌های کارایی با ابزار تحلیل مرورگر", summary: "با تب Performance در DevTools مشکلات زمان اجرا را پیدا و رفع کنید.", link: "#", cta: "همین حالا تحلیل کنید", thumbnail: "/block-media/shadcnblocks/block/placeholder-1.svg", }, ]; const FilterFormSchema = z.object({ items: z.array(z.string()).refine((value) => value.length > 0, { message: "حداقل یک دسته باید انتخاب شود.", }), }); const FilterForm = ({ categories, onCategoryChange }: FilterFormProps) => { const form = useForm>({ resolver: zodResolver(FilterFormSchema), defaultValues: { items: [CATEGORIES[0].value], }, }); const handleCheckboxChange = useCallback( ( checked: boolean | string, categoryValue: string, field: ControllerRenderProps, "items">, ) => { let updatedValues = checked ? [...field.value, categoryValue] : field.value.filter((value: string) => value !== categoryValue); // If no categories are checked, add "all" if (updatedValues.length === 0) { form.setValue("items", ["all"]); onCategoryChange(["all"]); return; } // Remove "all" if specific category is checked if (updatedValues.includes("all")) { updatedValues = updatedValues.filter((v: string) => v !== "all"); } // Avoid unnecessary updates if (JSON.stringify(field.value) !== JSON.stringify(updatedValues)) { form.setValue("items", updatedValues); onCategoryChange(updatedValues); } }, [form, onCategoryChange], ); return (
( {categories.map((category) => { const isChecked = field.value?.includes(category.value); const inputId = `category-${category.value}`; return ( {category.label} handleCheckboxChange(checked, category.value, field) } /> ); })} )} /> ); }; const ResourcesResult = ({ posts, categories }: BlogsResultProps) => { const [visibleCount, setVisibleCount] = useState(POSTS_PER_PAGE); const [selectedCategories, setSelectedCategories] = useState([ CATEGORIES[0].value, ]); const handleCategoryChange = useCallback((selected: string[]) => { setSelectedCategories(selected); setVisibleCount(POSTS_PER_PAGE); }, []); const handleLoadMore = useCallback(() => { setVisibleCount((prev) => prev + POSTS_PER_PAGE); }, []); const filteredPosts = useMemo(() => { return posts.filter( (post) => selectedCategories.includes(post.categoryKey) || selectedCategories.includes("all"), ); }, [posts, selectedCategories]); const postsToDisplay = filteredPosts.length > 0 ? filteredPosts : posts; const hasMore = visibleCount < postsToDisplay.length; return (
{postsToDisplay.slice(0, visibleCount).map((post) => ( ))}
{hasMore && ( )}
); }; const BreadcrumbBlog = ({ breadcrumb }: BreadcrumbBlogProps) => { return ( {breadcrumb.map((item, i) => { return ( {item.label} {i < breadcrumb.length - 1 ? ( ) : null} ); })} ); }; const EmailFormSchema = z.object({ email: z .string() .min(1, "ایمیل الزامی است") .email("آدرس ایمیل نامعتبر است"), }); const EmailForm = () => { const form = useForm>({ resolver: zodResolver(EmailFormSchema), defaultValues: { email: "", }, }); function onSubmit(values: z.infer) { console.log(values); } return (
( ایمیل
{fieldState.invalid && ( )}
)} /> ); }; const ResourcesCard = ({ category, title, thumbnail, summary, link, cta, }: Post) => { return (
{category}
{title}

{title}

{summary}

{cta}
); }; interface Resources1Props { className?: string; } const Resources1 = ({ className }: Resources1Props) => { return (

مرور گزارش‌ها

بهترین گزارش، گزارشی است که خواننده را با محتوای جذاب و پژوهش‌محور، در قالبی روشن و قابل‌درک، درگیر نگه می‌دارد.

همه گزارش‌ها

); }; export { Resources1 };