Skip to content

المكونات

تطبيقات FORGE الأمامية مبنية على shadcn/ui، التي توفر primitives قابلة للوصول وغير منسقة مدعومة بـ Radix UI ومُنسّقة بـ Tailwind CSS. فوق هذه الـ primitives، يُولّد FORGE عدة مكونات عالية المستوى مُصمّمة للوحة التحكم وتطبيق الويب.

معمارية المكونات

┌─────────────────────────────────────────────────┐
│              مكونات التطبيق                      │
│  (الصفحات، التخطيطات، مكونات خاصة بالميزات)      │
├─────────────────────────────────────────────────┤
│           مكونات FORGE المخصصة                   │
│  (DataTable, RichTextEditor, LanguageSwitcher,  │
│   ConfirmDialog, TranslationsInput, إلخ.)        │
├─────────────────────────────────────────────────┤
│             shadcn/ui Primitives                 │
│  (Button, Input, Dialog, Select, Table, Tabs,   │
│   Card, Badge, Skeleton, Tooltip, إلخ.)          │
├─────────────────────────────────────────────────┤
│              Radix UI + Tailwind CSS             │
│      (مكونات headless قابلة للوصول)              │
└─────────────────────────────────────────────────┘

DataTable

DataTable هو المكون الرئيسي لعرض قوائم الموارد في لوحة التحكم الإدارية. يغلف TanStack Table مع الفرز والتصفية وتبديل رؤية الأعمدة والترقيم وتحديد الصفوف.

الخصائص

الخاصيةالنوعالوصف
columnsColumnDef<TData, TValue>[]تعريفات أعمدة TanStack Table
dataTData[]مصفوفة صفوف البيانات
searchKeystring (اختياري)مفتاح العمود لتفعيل تصفية البحث النصي
searchPlaceholderstring (اختياري)نص placeholder لحقل البحث

الاستخدام

tsx
import { DataTable } from "@/components/ui/data-table";
import { getColumns } from "./columns";
import type { User } from "@/lib/types";

// Define columns in a separate file (columns.tsx)
export function getColumns({
  onDelete,
  canEdit,
  canDelete,
}: {
  onDelete: (user: User) => void;
  canEdit: boolean;
  canDelete: boolean;
}): ColumnDef<User>[] {
  return [
    {
      accessorKey: "name",
      header: ({ column }) => (
        <DataTableColumnHeader column={column} title="الاسم" />
      ),
    },
    {
      accessorKey: "email",
      header: "البريد الإلكتروني",
    },
    {
      accessorKey: "is_active",
      header: "الحالة",
      cell: ({ row }) => (
        <Badge variant={row.original.is_active ? "default" : "secondary"}>
          {row.original.is_active ? "نشط" : "غير نشط"}
        </Badge>
      ),
    },
    {
      id: "actions",
      cell: ({ row }) => (
        <DataTableRowActions
          row={row}
          onEdit={canEdit ? `/users/${row.original.id}/edit` : undefined}
          onDelete={canDelete ? () => onDelete(row.original) : undefined}
        />
      ),
    },
  ];
}

// Usage in page component
<DataTable
  columns={columns}
  data={users}
  searchKey="name"
  searchPlaceholder="تصفية المستخدمين..."
/>

المكونات الفرعية المدمجة

DataTable يتضمن عدة مكونات فرعية تعمل معاً:

  • DataTableColumnHeader -- رؤوس أعمدة قابلة للفرز مع عناصر تحكم تصاعدي/تنازلي/إخفاء
  • DataTableRowActions -- قائمة منسدلة مع إجراءات تعديل وعرض وحذف
  • DataTablePagination -- تنقل الصفحات مع صفوف لكل صفحة قابلة للتعديل (10، 20، 30، 40، 50)
  • رؤية الأعمدة -- قائمة منسدلة لإظهار/إخفاء الأعمدة

نصيحة

تعريفات الأعمدة تُحفظ في ملف columns.tsx منفصل باصطلاح. هذا يُبقي مكونات الصفحة مركزة على جلب البيانات والإجراءات بينما منطق عرض الأعمدة يبقى معزولاً وقابلاً للاختبار.

ConfirmDialog

حوار تأكيد يُستخدم قبل الإجراءات التدميرية مثل الحذف. مبني على AlertDialog من Radix UI.

الخصائص

الخاصيةالنوعالوصف
openbooleanيتحكم برؤية الحوار
onOpenChange(open: boolean) => voidيُستدعى عند تغير الرؤية
titlestringعنوان الحوار
descriptionstringنص وصفي
confirmTextstringنص زر التأكيد
variant"default" | "destructive"متغير نمط الزر
isLoadingbooleanيعرض spinner تحميل على زر التأكيد
onConfirm() => voidيُستدعى عندما يؤكد المستخدم الإجراء

الاستخدام

tsx
import { ConfirmDialog } from "@/components/ui/confirm-dialog";

const [deleteTarget, setDeleteTarget] = useState<User | null>(null);
const [isDeleting, setIsDeleting] = useState(false);

<ConfirmDialog
  open={!!deleteTarget}
  onOpenChange={(open) => !open && setDeleteTarget(null)}
  title="حذف المستخدم"
  description="هل أنت متأكد؟ لا يمكن التراجع عن هذا الإجراء."
  confirmText="حذف"
  variant="destructive"
  isLoading={isDeleting}
  onConfirm={handleDelete}
/>

RichTextEditor

محرر نص غني مبني على TinyMCE يُستخدم لتحرير صفحات المحتوى في لوحة التحكم الإدارية. يدعم محتوى RTL وإدراج الصور وينتج HTML نظيف.

الخصائص

الخاصيةالنوعالوصف
valuestringسلسلة محتوى HTML
onChange(value: string) => voidيُستدعى بـ HTML المُحدّث عند التغيير
placeholderstring (اختياري)نص placeholder
disabledbooleanيُعطّل التحرير
heightnumberارتفاع المحرر بالبكسل (الافتراضي: 300)
classNamestring (اختياري)فئات CSS إضافية

الاستخدام

tsx
import { RichTextEditor } from "@/components/ui/rich-text-editor";

<RichTextEditor
  value={content.details}
  onChange={(html) => setContent({ ...content, details: html })}
  height={400}
  placeholder="اكتب محتواك هنا..."
/>

المحرر يُعدّل اتجاه نصه تلقائياً بناءً على سياق اللغة الحالي، مما يضمن عرض اللغات RTL مثل العربية بشكل صحيح داخل المحرر.

TranslationsInput

واجهة بتبويبات لتحرير الحقول القابلة للترجمة عبر لغات متعددة. كل تبويب يتوافق مع لغة نشطة ويعرض حقول إدخال للخصائص القابلة للترجمة.

الخصائص

الخاصيةالنوعالوصف
valueTranslationsكائن مُفتّح بكود اللغة
onChange(translations: Translations) => voidيُستدعى عند أي تغيير حقل
fields("display_name" | "description")[]أي الحقول تُعرض
disabledbooleanيُعطّل جميع المدخلات

الاستخدام

tsx
import { TranslationsInput } from "@/components/ui/translations-input";

<TranslationsInput
  value={role.translations || {}}
  onChange={(translations) =>
    setRole({ ...role, translations })
  }
  fields={["display_name", "description"]}
/>

هذا يعرض شريط تبويبات بتبويب لكل لغة نشطة (مثل "English"، "العربية")، وتحت كل تبويب، حقول إدخال للخصائص القابلة للترجمة المُحددة.

ContentTranslationsInput

نسخة متخصصة من TranslationsInput لصفحات المحتوى. تتضمن حقولاً لـ title و summary و details (نص غني) و button_text وبيانات SEO الوصفية -- الكل لكل لغة.

الاستخدام

tsx
import { ContentTranslationsInput } from "@/components/ui/content-translations-input";

<ContentTranslationsInput
  value={content.translations || {}}
  onChange={(translations) =>
    setContent({ ...content, translations })
  }
/>

كل تبويب لغة يعرض:

┌─────────────────────────────────────────┐
│ [English]  [العربية]                     │
├─────────────────────────────────────────┤
│ العنوان:    [________________________]   │
│ الملخص:    [________________________]   │
│ التفاصيل:  ┌────────────────────────┐   │
│            │   محرر نص غني         │   │
│            └────────────────────────┘   │
│ نص الزر:   [_______________________]   │
│                                          │
│ -- حقول SEO --                           │
│ عنوان SEO: [________________________]   │
│ وصف SEO:  [________________________]   │
│ الكلمات المفتاحية: [________________]   │
└─────────────────────────────────────────┘

PermissionSelector

واجهة checkbox تسلسلية لتعيين الصلاحيات للأدوار. الصلاحيات مُجمّعة حسب main_group و group، تعرض بنية شجرية تسمح بتحديد صلاحيات فردية أو مجموعات كاملة.

الاستخدام

tsx
import { PermissionSelector } from "@/components/ui/permission-selector";

<PermissionSelector
  permissions={allPermissions}
  selected={selectedPermissionIds}
  onChange={setSelectedPermissionIds}
/>

المكون يعرض الصلاحيات في شجرة:

[x] المستخدمون (تحديد الكل)
    [x] عرض المستخدمين
    [x] إنشاء المستخدمين
    [x] تعديل المستخدمين
    [ ] حذف المستخدمين

[x] المحتويات (تحديد الكل)
    [x] عرض المحتويات
    [x] إنشاء المحتويات
    [x] تعديل المحتويات
    [x] حذف المحتويات

النقر على رأس مجموعة يُبدّل جميع الصلاحيات داخل تلك المجموعة.

LanguageSwitcher

قائمة منسدلة تعرض اللغات المتاحة وتسمح للمستخدم بتبديل اللغة النشطة. عند اختيار لغة، يُحدّث cookies (locale و direction)، يُحدّث خصائص dir و lang لعنصر <html>، ويُحدّث الصفحة.

الاستخدام

tsx
import { LanguageSwitcher } from "@/components/ui/language-switcher";

// In header component
<LanguageSwitcher />

المكون يُخفي نفسه تلقائياً عندما تكون لغة واحدة فقط متاحة. يعرض الاسم الأصلي لكل لغة (مثل "English"، "العربية") ويُميّز الاختيار النشط.

نصيحة

LanguageSwitcher موجود في كلا التطبيقين (admin/components/ui/ و web/components/)، كل منها مُصمّم لتخطيط تطبيقه. كلاهما يستخدم نفس hook useI18n من I18n provider.

حالات التحميل والـ Skeletons

يستخدم FORGE مكون Skeleton من shadcn/ui لعناصر placeholder للتحميل في جميع أنحاء لوحة التحكم الإدارية:

tsx
import { Skeleton } from "@/components/ui/skeleton";

function UserListSkeleton() {
  return (
    <div className="space-y-4">
      <Skeleton className="h-10 w-[250px]" />
      <div className="space-y-2">
        {Array.from({ length: 5 }).map((_, i) => (
          <Skeleton key={i} className="h-16 w-full" />
        ))}
      </div>
    </div>
  );
}

استخدم skeletons في صفحات القوائم أثناء تحميل البيانات:

tsx
if (isLoading) return <UserListSkeleton />;
return <DataTable columns={columns} data={users} />;

إشعارات Toast

يستخدم FORGE Sonner لإشعارات toast. غلاف DirectionAwareToaster يُوضع الإشعارات بناءً على اتجاه النص الحالي:

tsx
import { toast } from "sonner";

// Success notification
toast.success("تم إنشاء المستخدم بنجاح");

// Error notification
toast.error("فشل في إنشاء المستخدم");

// Custom with description
toast.success("تم حفظ الإعدادات", {
  description: "تغييراتك ستصبح سارية فوراً.",
});

DirectionAwareToaster

غلاف حول Toaster من Sonner يُكيّف الموضع لتخطيطات RTL:

tsx
import { DirectionAwareToaster } from "@/components/ui/direction-aware-toaster";

// In root layout
<DirectionAwareToaster />

في وضع LTR، تظهر الإشعارات في الزاوية السفلية اليمنى. في وضع RTL، تظهر في الزاوية السفلية اليسرى.

sidebar الإدارة هو مكون تنقل متجاوب مع الميزات التالية:

  • قابل للطي -- يُبدّل بين العرض الكامل (مع العناوين) ووضع الأيقونات فقط على سطح المكتب
  • overlay للجوال -- ينزلق من اليسار على الجوال مع backdrop overlay
  • عناصر محمية بالصلاحيات -- عناصر التنقل تُعرض فقط إذا كان للمستخدم الصلاحية المطلوبة
  • قوائم فرعية قابلة للطي -- العناصر الرئيسية تتوسع لتكشف الروابط الفرعية
  • حالة نشطة -- المسار الحالي مُميّز بصرياً
tsx
import { Sidebar } from "@/components/layout/sidebar";

// Used in dashboard layout
<div className="flex h-screen">
  <Sidebar />
  <div className="flex flex-1 flex-col overflow-hidden">
    <Header />
    <main className="flex-1 overflow-y-auto p-6">
      {children}
    </main>
  </div>
</div>

ThemeToggle

زر يُبدّل بين السمات الفاتحة والداكنة. يستخدم next-themes تحت الغطاء مع اكتشاف تفضيل النظام:

tsx
// In admin header
<ThemeToggle />

shadcn/ui Primitives

الـ primitives التالية من shadcn/ui مُضمّنة في كلا التطبيقين:

المكونالوصف
Buttonمتغيرات primary، secondary، outline، ghost، destructive
Inputإدخال نصي مع دعم label وحالة الخطأ
Textareaإدخال نص متعدد الأسطر
Selectاختيار منسدل
Checkboxcheckbox مع label
Switchمفتاح تبديل
Dialogحوار modal
DropdownMenuقائمة سياق / منسدلة
Tableprimitives جدول البيانات (Header، Body، Row، Cell)
Tabsلوحات محتوى بتبويبات
Cardبطاقة حاوية مع header ومحتوى و footer
Badgeشارات حالة وعناوين
Skeletonرسوم placeholder للتحميل
Tooltiptooltip عند التمرير
Separatorفاصل مرئي
Labelعنوان حقل النموذج
Accordionأقسام محتوى قابلة للتوسيع
Avatarصورة رمزية للمستخدم مع صورة و fallback
Collapsibleقسم قابل للتوسيع/الطي

نصيحة

جميع مكونات shadcn/ui تُولّد كـ source code في components/ui/، وليست مُثبّتة كـ package. هذا يعني أنه يمكنك تخصيص أي مكون مباشرة بدون ejecting أو تجاوز الأنماط.

ما التالي

Released under the MIT License.