بلاک‌ها · حساب کاربری

تنظیمات با ستونِ بخش‌ها

پیش‌نمایش تمام‌صفحه

تنظیمات با فهرستِ بخش‌ها در کنار و محتوای بخش در ستونِ اصلی؛ ردیف‌های تیتر و توضیح کنارِ کنترل (عکس، نام، ظاهر با سگمنت، سوییچ) و ذخیره در پایان.

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

این بلاک از ۹ آیتم دیگ استفاده می‌کند: avatarbuttoncontrol-sizeiconslabelswitchtext-fieldtoasttoggle-group

پکیج‌منیجر پیش‌فرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیج‌منیجر Bun
npx digdesign@latest add 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/label.json https://docs.digdesign.ir/r/switch.json https://docs.digdesign.ir/r/text-field.json https://docs.digdesign.ir/r/toast.json https://docs.digdesign.ir/r/toggle-group.json
pnpm dlx digdesign@latest add 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/label.json https://docs.digdesign.ir/r/switch.json https://docs.digdesign.ir/r/text-field.json https://docs.digdesign.ir/r/toast.json https://docs.digdesign.ir/r/toggle-group.json
yarn dlx digdesign@latest add 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/label.json https://docs.digdesign.ir/r/switch.json https://docs.digdesign.ir/r/text-field.json https://docs.digdesign.ir/r/toast.json https://docs.digdesign.ir/r/toggle-group.json
bunx --bun digdesign@latest add 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/label.json https://docs.digdesign.ir/r/switch.json https://docs.digdesign.ir/r/text-field.json https://docs.digdesign.ir/r/toast.json https://docs.digdesign.ir/r/toggle-group.json

۲. کد صفحه

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

settings-sidebar.tsx
"use client"

import * as React from "react"

import { BellIcon, CreditCardIcon, GlobeIcon, ShieldCheckIcon, UserIcon } from "@/components/icons"
import { Avatar } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { Label } from "@/components/ui/label"
import { Switch } from "@/components/ui/switch"
import { TextField } from "@/components/ui/text-field"
import { toast } from "@/components/ui/toast"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
import { stockImages } from "@/lib/stock-images"

const SECTIONS = [
  { value: "account", label: "حساب", icon: <UserIcon /> },
  { value: "notifications", label: "اعلان‌ها", icon: <BellIcon /> },
  { value: "security", label: "امنیت", icon: <ShieldCheckIcon /> },
  { value: "billing", label: "پرداخت", icon: <CreditCardIcon /> },
  { value: "language", label: "زبان و منطقه", icon: <GlobeIcon /> },
]

/**
 * تنظیمات با ستونِ بخش‌ها: فهرستِ بخش‌ها در کنار (فعال روی کارتِ سفید با سایه، روی سطحِ
 * muted) و محتوای همان بخش در ستونِ اصلی؛ هر بخش ردیف‌های تیتر/توضیح در یک سو و کنترل
 * در سوی دیگر دارد و «ذخیره» در پایانِ همان بخش.
 */
export default function SettingsSidebarBlock() {
  const [section, setSection] = React.useState("account")
  const [theme, setTheme] = React.useState("system")
  const [weekly, setWeekly] = React.useState(true)

  return (
    <ControlSizeProvider size="xl" asChild>
      <main className="mx-auto flex w-full max-w-5xl flex-col gap-8 p-4 sm:p-6">
        <h1 className="text-2xl font-bold">تنظیمات</h1>
        <div className="grid grid-cols-1 items-start gap-8 md:grid-cols-[15rem_minmax(0,1fr)]">
          <nav aria-label="بخش‌های تنظیمات" className="flex gap-1 overflow-x-auto rounded-xl bg-muted p-1.5 md:flex-col">
            {SECTIONS.map((item) => (
              <Button
                key={item.value}
                variant="ghost"
                aria-current={item.value === section ? "page" : undefined}
                onClick={() => setSection(item.value)}
                className={`shrink-0 justify-start gap-3 font-normal ${item.value === section ? "bg-card font-semibold shadow-control hover:bg-card" : "hover:bg-card"}`}
              >
                <span aria-hidden className="text-muted-foreground [&>svg]:size-5">
                  {item.icon}
                </span>
                {item.label}
              </Button>
            ))}
          </nav>

          <section aria-label={SECTIONS.find((item) => item.value === section)?.label} className="flex flex-col divide-y divide-border rounded-xl border border-border bg-card">
            <div className="flex flex-wrap items-center gap-4 p-6">
              <Avatar size="lg" alt="" src={stockImages.personWoman1.src} className="size-16" />
              <div className="flex flex-1 flex-col">
                <span className="font-semibold">عکسِ پروفایل</span>
                <span className="text-sm text-muted-foreground">مربعی، حداقل ۴۰۰ پیکسل</span>
              </div>
              <Button variant="outline">تغییر</Button>
            </div>
            <div className="grid grid-cols-1 gap-4 p-6 sm:grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)] sm:items-start">
              <div className="flex flex-col gap-1">
                <span className="font-semibold">نام و ایمیل</span>
                <span className="text-sm text-muted-foreground">در فاکتورها و پیام‌ها دیده می‌شود.</span>
              </div>
              <div className="flex flex-col gap-4">
                <TextField label="نام" defaultValue="مهسا کریمی" />
                <TextField label="ایمیل" type="email" dir="ltr" defaultValue="mahsa@avand.example" />
              </div>
            </div>
            <div className="grid grid-cols-1 gap-4 p-6 sm:grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)] sm:items-center">
              <div className="flex flex-col gap-1">
                <span id="ss-theme" className="font-semibold">
                  ظاهر
                </span>
                <span className="text-sm text-muted-foreground">روشن، تاریک یا مثلِ دستگاه.</span>
              </div>
              <ToggleGroup type="single" variant="segmented" value={theme} onValueChange={(value) => value && setTheme(value as string)} aria-labelledby="ss-theme" className="w-full">
                <ToggleGroupItem value="light" className="flex-1">
                  روشن
                </ToggleGroupItem>
                <ToggleGroupItem value="dark" className="flex-1">
                  تاریک
                </ToggleGroupItem>
                <ToggleGroupItem value="system" className="flex-1">
                  دستگاه
                </ToggleGroupItem>
              </ToggleGroup>
            </div>
            <div className="flex items-center justify-between gap-4 p-6">
              <div className="flex flex-col gap-1">
                <Label htmlFor="ss-weekly" className="font-semibold">
                  خلاصهٔ هفتگی
                </Label>
                <span className="text-sm text-muted-foreground">هر شنبه گزارشِ کوتاهِ هفتهٔ قبل.</span>
              </div>
              <Switch id="ss-weekly" checked={weekly} onCheckedChange={setWeekly} />
            </div>
            <div className="flex justify-end gap-3 p-6">
              <Button variant="outline">انصراف</Button>
              <Button onClick={() => toast.success("تنظیمات ذخیره شد.")}>ذخیره</Button>
            </div>
          </section>
        </div>
      </main>
    </ControlSizeProvider>
  )
}