دورهٔ آموزشی
پیشنمایش تمامصفحهصفحهٔ دوره: پخشکنندهٔ درسِ فعلی، مدرس با عکس و آمار، ستونِ پیشرفت و سرفصلها در آکاردئون با تیکِ انجامشده، درسِ فعلی و زمانِ هر درس.
۱. نصب کامپوننتها
این بلاک از ۷ آیتم دیگ استفاده میکند: accordionavatarbuttoncontrol-sizeiconspersianprogress
پکیجمنیجر پیشفرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیجمنیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/accordion.json https://docs.digdesign.ir/r/avatar.json https://docs.digdesign.ir/r/button.json 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/progress.jsonpnpm dlx digdesign@latest add https://docs.digdesign.ir/r/accordion.json https://docs.digdesign.ir/r/avatar.json https://docs.digdesign.ir/r/button.json 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/progress.jsonyarn dlx digdesign@latest add https://docs.digdesign.ir/r/accordion.json https://docs.digdesign.ir/r/avatar.json https://docs.digdesign.ir/r/button.json 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/progress.jsonbunx --bun digdesign@latest add https://docs.digdesign.ir/r/accordion.json https://docs.digdesign.ir/r/avatar.json https://docs.digdesign.ir/r/button.json 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/progress.json۲. کد صفحه
کد را در app/<route>/page.tsx بگذارید و متنها، داده و هندلرها را با محصول خودتان عوض کنید.
course.tsx
"use client"
import * as React from "react"
import { CheckIcon, ClockIcon, PlayIcon, UsersIcon } from "@/components/icons"
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
import { Avatar } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { Progress } from "@/components/ui/progress"
import { toFaDigits } from "@/lib/persian"
import { stockImages } from "@/lib/stock-images"
type Lesson = { title: string; minutes: number; done?: boolean; current?: boolean }
const CHAPTERS: { title: string; lessons: Lesson[] }[] = [
{
title: "فصلِ ۱: پایههای حسابداری",
lessons: [
{ title: "دارایی، بدهی و سرمایه به زبانِ ساده", minutes: 12, done: true },
{ title: "سند و دفترِ روزنامه", minutes: 18, done: true },
{ title: "تراز آزمایشی", minutes: 15, current: true },
],
},
{
title: "فصلِ ۲: گزارشهای مالی",
lessons: [
{ title: "سود و زیان", minutes: 20 },
{ title: "ترازنامه", minutes: 16 },
{ title: "جریانِ نقد", minutes: 22 },
],
},
{ title: "فصلِ ۳: مالیات و بیمه", lessons: [{ title: "اظهارنامهٔ فصلی", minutes: 25 }, { title: "لیستِ بیمه", minutes: 14 }] },
]
/**
* دورهٔ آموزشی: پخشکنندهٔ درسِ فعلی (عکسِ کاور با دکمهٔ پخش)، عنوان، مدرس با عکس و آمار؛
* ستونِ کنار با پیشرفت و سرفصلها در آکاردئون (انجامشده تیک، فعلی برجسته، زمانِ هر درس).
*/
export default function CourseBlock() {
const lessons = CHAPTERS.flatMap((chapter) => chapter.lessons)
const done = lessons.filter((lesson) => lesson.done).length
const current = lessons.find((lesson) => lesson.current)!
return (
<ControlSizeProvider size="xl" asChild>
<main className="mx-auto grid grid-cols-1 w-full max-w-6xl items-start gap-8 p-4 sm:p-6 lg:grid-cols-[minmax(0,1fr)_22rem]">
<div className="flex flex-col gap-6">
<div className="relative overflow-hidden rounded-xl bg-inverse">
{/* eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ */}
<img src={stockImages.coverCalculator.src} alt="" className="aspect-video w-full object-cover" />
<div className="absolute inset-0 flex items-center justify-center bg-[color-mix(in_oklab,var(--dig-graphite-950)_35%,transparent)]">
<Button aria-label={`پخشِ درسِ «${current.title}»`} className="bg-[var(--dig-white)] text-[var(--dig-graphite-900)] hover:bg-[var(--dig-neutral-200)]">
<PlayIcon />
پخشِ درس
</Button>
</div>
</div>
<div className="flex flex-col gap-3">
<span className="text-sm font-semibold text-brand-secondary">درسِ فعلی</span>
<h1 className="text-2xl font-bold">{current.title}</h1>
<p className="leading-8 text-muted-foreground">تراز آزمایشی را میسازیم و یاد میگیریم با آن خطاهای ثبتِ سند را قبل از بستنِ دوره پیدا کنیم.</p>
</div>
<div className="flex flex-wrap items-center justify-between gap-4 rounded-xl bg-subtle p-4">
<div className="flex items-center gap-3">
<Avatar size="lg" alt="نگار احمدی" src={stockImages.personWoman3.src} />
<span className="flex flex-col">
<span className="font-semibold">نگار احمدی</span>
<span className="text-sm text-muted-foreground">حسابدارِ رسمی، ۱۲ سال تدریس</span>
</span>
</div>
<ul className="flex gap-5 text-sm text-muted-foreground">
<li className="flex items-center gap-1.5">
<UsersIcon aria-hidden className="size-4" />
۳٬۴۰۰ دانشجو
</li>
<li className="flex items-center gap-1.5">
<ClockIcon aria-hidden className="size-4" />
{toFaDigits(Math.round(lessons.reduce((sum, lesson) => sum + lesson.minutes, 0) / 60))} ساعت
</li>
</ul>
</div>
</div>
<aside className="flex flex-col gap-5 rounded-xl border border-border bg-card p-5 lg:sticky lg:top-6">
<div className="flex flex-col gap-2">
<div className="flex items-baseline justify-between">
<span className="font-bold">پیشرفتِ تو</span>
<span className="text-sm text-muted-foreground tabular-nums">
{toFaDigits(done)} از {toFaDigits(lessons.length)} درس
</span>
</div>
<Progress value={(done / lessons.length) * 100} aria-label="پیشرفتِ دوره" />
</div>
<Accordion type="multiple" defaultValue={[CHAPTERS[0].title]}>
{CHAPTERS.map((chapter) => (
<AccordionItem key={chapter.title} value={chapter.title}>
<AccordionTrigger className="text-sm">{chapter.title}</AccordionTrigger>
<AccordionContent>
<ol className="flex flex-col gap-1">
{chapter.lessons.map((lesson) => (
<li key={lesson.title}>
<a
href="#"
aria-current={lesson.current ? "step" : undefined}
className={`flex items-center gap-3 rounded-lg p-2.5 text-sm ${lesson.current ? "bg-primary-subtle font-semibold" : "hover:bg-subtle"}`}
>
<span
aria-hidden
className={`flex size-6 shrink-0 items-center justify-center rounded-full [&>svg]:size-3 ${lesson.done ? "bg-success text-[var(--dig-white)]" : lesson.current ? "bg-foreground text-background" : "border border-input"}`}
>
{lesson.done ? <CheckIcon /> : lesson.current ? <PlayIcon /> : null}
</span>
<span className="flex-1">{lesson.title}</span>
<span className="text-xs text-muted-foreground tabular-nums">{toFaDigits(lesson.minutes)} دقیقه</span>
</a>
</li>
))}
</ol>
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</aside>
</main>
</ControlSizeProvider>
)
}