بلاک‌ها · پشتیبانی و محتوا

بلاگِ ساده بدونِ عکس: ستونِ تاریخ کنارِ هر نوشته، برچسب، زمانِ خواندن و جست‌وجو؛ برای وبلاگِ شخصی و فنی.

۱. نصب کامپوننت‌ها

این بلاک از ۴ آیتم دیگ استفاده می‌کند: control-sizeiconspersiansearch-field

پکیج‌منیجر پیش‌فرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیج‌منیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/search-field.json
pnpm dlx digdesign@latest add https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/search-field.json
yarn dlx digdesign@latest add https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/search-field.json
bunx --bun digdesign@latest add https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/search-field.json

۲. کد صفحه

کد را در app/<route>/page.tsx بگذارید و متن‌ها، داده و هندلرها را با محصول خودتان عوض کنید.

blog-list.tsx
"use client"

import * as React from "react"

import { ChevronLeftIcon } from "@/components/icons"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { SearchField } from "@/components/ui/search-field"
import { formatJalali, toFaDigits, toSearchKey } from "@/lib/persian"

const POSTS = [
  { title: "قانونِ ۵۰/۳۰/۲۰ برای بودجه‌بندی ماهانه", excerpt: "روشی ساده که بدونِ اکسل هم کار می‌کند.", date: "2026-10-02", minutes: 5, tag: "مالی شخصی" },
  { title: "پشتِ صحنهٔ گزارشِ ماهانهٔ خودکار", excerpt: "از ایده تا انتشار در شش هفته.", date: "2026-09-27", minutes: 8, tag: "محصول" },
  { title: "فاکتورِ رسمی بدونِ دردسر", excerpt: "چه اطلاعاتی لازم است و کجا اشتباه می‌کنیم.", date: "2026-09-25", minutes: 5, tag: "کسب‌وکار" },
  { title: "کارمزدِ جدیدِ کارت‌به‌کارت از مهر", excerpt: "جدولِ کارمزدها و راه‌هایی که کمتر بپردازید.", date: "2026-09-12", minutes: 3, tag: "اخبار" },
  { title: "پس‌اندازِ اضطراری: چقدر کافی است؟", excerpt: "عددِ درست به سه چیز بستگی دارد.", date: "2026-08-30", minutes: 6, tag: "مالی شخصی" },
]

/**
 * بلاگِ ساده و متنی: بدونِ عکس، با ستونِ تاریخ کنارِ هر نوشته، برچسب، زمانِ خواندن و
 * جست‌وجو؛ برای وبلاگ‌های شخصی، تغییراتِ فنی و نوشته‌هایی که متن مهم‌تر از تصویر است.
 */
export default function BlogListBlock() {
  const [query, setQuery] = React.useState("")
  const visible = POSTS.filter((post) => toSearchKey(post.title + post.excerpt).includes(toSearchKey(query)))

  return (
    <ControlSizeProvider size="xl" asChild>
      <main className="mx-auto flex w-full max-w-3xl flex-col gap-10 px-4 py-16 sm:px-6">
        <header className="flex flex-col gap-6">
          <div className="flex flex-col gap-2">
            <h1 className="text-4xl font-black">نوشته‌ها</h1>
            <p className="text-muted-foreground">دربارهٔ پول، کار و ساختنِ آوند.</p>
          </div>
          <SearchField aria-label="جست‌وجو در نوشته‌ها" placeholder="جست‌وجو" value={query} onValueChange={setQuery} />
        </header>
        <ol className="flex flex-col divide-y divide-border">
          {visible.map((post) => (
            <li key={post.title}>
              <a href="#" className="group grid grid-cols-1 gap-2 py-6 sm:grid-cols-[8rem_minmax(0,1fr)_auto] sm:items-baseline sm:gap-6">
                <span className="text-sm text-muted-foreground tabular-nums">{formatJalali(new Date(post.date), "short")}</span>
                <span className="flex flex-col gap-1.5">
                  <span className="text-lg font-bold group-hover:underline">{post.title}</span>
                  <span className="leading-7 text-muted-foreground">{post.excerpt}</span>
                  <span className="text-xs text-muted-foreground">
                    {post.tag} · {toFaDigits(post.minutes)} دقیقه
                  </span>
                </span>
                <ChevronLeftIcon aria-hidden className="hidden size-5 text-muted-foreground transition-transform group-hover:-translate-x-1 sm:block ltr:rotate-180" />
              </a>
            </li>
          ))}
          {visible.length === 0 && <li className="py-10 text-center text-muted-foreground">نوشته‌ای با این واژه پیدا نشد.</li>}
        </ol>
      </main>
    </ControlSizeProvider>
  )
}