DESIGN SYSTEM · v1

نظام التصميم

مرجع حيّ لجميع المكوّنات الأساسية في نور. يستخدمه المساهمون لمعرفة ما هو متاح، وكيفية استدعائه، وكيف يبدو في الإنتاج.

الألوان والطباعة

نظام الألوان مبنيّ على إيفوري + التيركوازي العميق + الرملي الدافئ. تستخدم الواجهة Cairo و Tajawal للنص، و Amiri للعناوين والاقتباسات.

وضع النهار

ivory-100
#FAF7F2
teal
#0E5C5C
sand-500
#C9A875
ink
#2A2A2A
accent-rose
#B85450

وضع الليل (Midnight)

midnight.bg
#0E1318
midnight.surface
#161B22
midnight.teal
#3FA6A6
midnight.text
#E6E8EA
midnight.rose
#E08E8B

font-amiri (عناوين)

لكُلّ شيءٍ سببٌ ونتيجة

font-tajawal (نص)

هذا نصٌ تجريبيّ بخطّ تجوّل يُستعمل في المتن.

font-cairo (واجهة)

أزرار وعناصر التحكّم تستخدم Cairo

Button

يدعم أربعة متغيّرات (primary، secondary، ghost، danger) وثلاثة أحجام (sm، md، lg) وحالة تحميل.

Variants
<Button variant="primary">حفظ</Button>
<Button variant="secondary">إلغاء</Button>
<Button variant="ghost">تخطّي</Button>
<Button variant="danger">حذف</Button>
Sizes
<Button size="sm">صغير</Button>
<Button size="md">متوسط</Button>
<Button size="lg">كبير</Button>
With icons
import { Plus, Sparkles } from "lucide-react";

<Button><Plus className="w-4 h-4" />جديد</Button>
<Button variant="secondary"><Sparkles className="w-4 h-4" />تدقيق</Button>
Loading + disabled
<Button loading={true}>جارٍ الحفظ</Button>
<Button disabled>غير متاح</Button>

Card

حاوية أساسية بإطار خفيف وظلّ ناعم. مكوّنات فرعية: CardHeader، CardBody، CardTitle.

عنوان البطاقة

محتوى البطاقة هنا — نصّ، نموذج، أو أي عنصر يستحقّ التأطير.

<Card>
  <CardHeader>
    <CardTitle>عنوان البطاقة</CardTitle>
  </CardHeader>
  <CardBody>
    محتوى البطاقة هنا — نصّ، نموذج، أو أي عنصر آخر.
  </CardBody>
</Card>
With card-hover utility

حُم على هذه البطاقة

سترتفع قليلًا مع ظلّ أعمق.

<Card className="card-hover cursor-pointer">
  <CardBody>...</CardBody>
</Card>

Input / Textarea

حقول إدخال نموذجية بإطار رمليّ خفيف وحلقة تركيز تيركوازية.

Input
<Input placeholder="ابحث في المصادر..." />
<Input type="email" placeholder="example@domain.com" dir="ltr" />
Textarea
<Textarea placeholder="اكتب ملاحظاتك..." rows={4} />

Badge

شارات صغيرة لإبراز حالة أو وسم. خمسة متغيّرات: default, teal, sand, rose, ochre.

افتراضيجديدرمليعاجلمميّز
<Badge>افتراضي</Badge>
<Badge variant="teal">جديد</Badge>
<Badge variant="sand">رملي</Badge>
<Badge variant="rose">عاجل</Badge>
<Badge variant="ochre">مميّز</Badge>

Toast

إشعارات قصيرة تظهر أسفل اليسار. تستدعى بشكل أمري عبر hook useToast(). الـ Toaster مثبّت في الـ layout الجذري.

import { useToast } from "@/lib/use-toast";

const toast = useToast();
toast.success("تم الحفظ", "حُفظت المسودة بنجاح");
toast.error("فشلت العملية", "تأكّد من اتصالك بالشبكة");
toast.info("معلومة", "هذه نسخة تجريبية");

Confirm Dialog

تأكيد بسيط (نعم/لا) باستدعاء أمري ينتظر قرار المستخدم. يُستخدم بدلًا من window.confirm().

آخر نتيجة: —
import { confirm } from "@/components/ui/confirm-dialog";

const ok = await confirm({
  title: "حذف المسودة؟",
  description: "لا يمكن التراجع.",
  confirmLabel: "حذف",
  variant: "destructive",
});
if (ok) deleteDraft();

Prompt Dialog

حقل إدخال نصّي أمري. يدعم نوع الحقل (text/url/email) واتجاه الكتابة. يُستخدم بدلًا من window.prompt().

آخر نتيجة: —
import { promptText } from "@/components/ui/confirm-dialog";

// نصّ عربي عادي
const name = await promptText({
  title: "ما اسمك؟",
  placeholder: "مثلًا: محمد العتيبي",
});

// رابط (LTR)
const url = await promptText({
  title: "إدراج رابط",
  inputType: "url",
  inputDir: "ltr",
  defaultValue: "https://",
});

Skeleton

عناصر تحميل بنبضة هادئة. أربعة مستويات: Skeleton الأساسي، CardSkeleton، ListItemSkeleton، TextSkeleton.

Base + composed
<Skeleton className="h-6 w-40" />
<Skeleton className="h-4 w-full" />
<Skeleton className="h-10 w-32 rounded-lg" />
Presets
<CardSkeleton />
<ListItemSkeleton />
<TextSkeleton lines={4} />

Empty State

رسالة وسطية تُعرض عندما لا توجد بيانات. يدعم أيقونة، عنوانًا، وصفًا، وزرّ إجراء.

Default

لا توجد مصادر بعد

ابدأ بحفظ المصادر من مكتبة البحث وستظهر هنا تلقائيًا.

<EmptyState
  icon={<BookMarked className="w-8 h-8" />}
  title="لا توجد مصادر بعد"
  description="ابدأ بحفظ المصادر من مكتبة البحث."
  action={<Button><Search className="w-4 h-4" />ابدأ البحث</Button>}
/>
Compact

لا توجد مسودات

ابدأ بكتابة مسودة جديدة.

<EmptyState
  variant="compact"
  icon={<FileText className="w-6 h-6" />}
  title="لا توجد مسودات"
  description="ابدأ بكتابة مسودة جديدة."
/>

للمساهمين الجدد

كل المكوّنات أعلاه مُصدَّرة من @/components/ui. الاستدعاءات الأمريّة (toast، confirm، promptText) تتطلّب أن يكون المضيف مثبَّتًا في app/layout.tsx — وهو كذلك بالفعل.