إنتقل إلى المحتوى الرئيسي

الصفحات (Pages)

كيف تعمل الصفحات في بنية Orb - التوجيه، ربط السمات، الفتحات، والتنقل.

ذو صلة:


نظرة عامة

في Orb، الصفحة (Page) هي مسار يجمع السمات لعرض واجهة المستخدم. التركيبة الأساسية هي:

Orbital = Entity + Traits + Pages

بينما تحدد الكيانات البيانات والسمات السلوك، تحدد الصفحات أين يتفاعل المستخدمون مع النظام. الصفحات مدفوعة بالسمات - لا تحتوي على واجهة مستخدم مباشرة، بل تشير إلى سمات تملأ تأثيرات render-ui الخاصة بها الصفحة.


تعريف الصفحة (Page)

تُعرَّف الصفحة (Page) في برنامج .orb بالبنية التالية:

{
"اسم": "TaskListPage",
"مسار": "/tasks",
"نوع_العرض": "list",
"الكيان_الأساسي": "Task",
"سمات": [
{
"مرجع": "TaskBrowser",
"كيان_مرتبط": "Task"
},
{
"مرجع": "FilterPanel",
"كيان_مرتبط": "Task"
}
]
}

خصائص الصفحة

الخاصيةمطلوبةالوصف
nameنعممعرِّف بصيغة PascalCase (مثال: TaskListPage)
pathنعممسار URL يبدأ بـ /
viewTypeلاتلميح دلالي: list، detail، create، edit، dashboard، custom
primaryEntityلاالكيان الأساسي الذي تعمل عليه هذه الصفحة
traitsنعممصفوفة مراجع السمات التي تقود الواجهة
isInitialلاما إذا كانت هذه صفحة نقطة الدخول

المسارات وأنماط المسارات

مسارات الصفحات تحدد مسارات URL لتطبيقك.

قواعد المسارات

  • يجب أن تبدأ بـ /
  • الأحرف الصالحة: حروف، أرقام، شرطات، شرطات سفلية، نقطتان، شرطات مائلة
  • يجب أن تكون فريدة عبر جميع الصفحات في البرنامج

المسارات الثابتة

مسارات بسيطة بدون أجزاء ديناميكية:

{ "path": "/tasks" }
{ "path": "/dashboard" }
{ "path": "/settings/profile" }

الأجزاء الديناميكية

استخدم صيغة النقطتين للمعاملات الديناميكية:

{ "path": "/tasks/:id" }
{ "path": "/users/:userId/tasks/:taskId" }
{ "path": "/projects/:projectId/members/:memberId" }

تُستخرج الأجزاء الديناميكية وتكون متاحة في:

  • حمولات الأحداث (@payload.id)
  • تأثيرات التنقل
  • عمليات البحث عن الكيانات

أمثلة المسارات

المسارالوصف
/tasksصفحة قائمة المهام
/tasks/:idتفاصيل مهمة واحدة
/tasks/createإنشاء مهمة جديدة
/tasks/:id/editتعديل مهمة موجودة
/users/:id/profileملف المستخدم
/dashboardعرض لوحة المعلومات

أنواع العرض (View Types)

أنواع العرض هي تلميحات دلالية حول غرض الصفحة:

النوعالغرضالأنماط النموذجية
listعرض مجموعة كياناتentity-table، entity-cards، entity-list
detailعرض كيان واحدentity-detail، stats
createإنشاء كيان جديدform
editتعديل كيان موجودform
dashboardنظرة عامة بأقسام متعددةdashboard-grid، stats
customتخطيط مخصصأي أنماط

مهم: أنواع العرض لا تقيّد الواجهة. العرض الفعلي يُتحكم به عبر تأثيرات render-ui في السمات. أنواع العرض هي بيانات وصفية لأجل:

  • التوثيق
  • تلميحات توليد الكود
  • بناء هيكل الواجهة

ربط الصفحة بالسمة

الصفحات تشير إلى السمات التي توفر سلوكها وواجهتها.

مراجع السمات

{
"صفحات": [
{
"اسم": "TaskListPage",
"مسار": "/tasks",
"سمات": [
{
"مرجع": "TaskBrowser",
"كيان_مرتبط": "Task"
},
{
"مرجع": "QuickActions",
"كيان_مرتبط": "Task",
"تكوين": {
"showCreate": true
}
}
]
}
]
}

بنية PageTraitRef

الخاصيةمطلوبةالوصف
refنعماسم السمة أو مسارها (مثال: "TaskBrowser"، "Std.traits.CRUD")
linkedEntityلاالكيان الذي تعمل عليه هذه السمة
configلاإعدادات خاصة بالسمة

سمات متعددة لكل صفحة

يمكن للصفحة أن تحتوي على سمات متعددة، كل منها تساهم بواجهة في فتحات مختلفة:

{
"اسم": "DashboardPage",
"مسار": "/dashboard",
"سمات": [
{
"مرجع": "StatsSummary",
"كيان_مرتبط": "Analytics"
},
{
"مرجع": "RecentActivity",
"كيان_مرتبط": "Activity"
},
{
"مرجع": "QuickActions",
"كيان_مرتبط": "Task"
}
]
}

كل تأثير render-ui في السمة يستهدف فتحات محددة.

linkedEntity على السمات

خاصية linkedEntity تربط السمة بكيان محدد:

{
"مرجع": "StatusManager",
"كيان_مرتبط": "Task"
}

هذا يعني:

  • ربط @entity في السمة يُحل إلى بيانات Task
  • تأثيرات مثل persist تعمل على مجموعة Task
  • آلة حالة السمة تدير نسخ Task

انظر ربط السمة بالكيان للتفاصيل.


الكيان الأساسي (Primary Entity)

خاصية primaryEntity تشير إلى الكيان الرئيسي الذي تعمل عليه الصفحة:

{
"اسم": "TaskDetailPage",
"مسار": "/tasks/:id",
"الكيان_الأساسي": "Task",
"سمات": [
{
"مرجع": "TaskViewer"
},
{
"مرجع": "CommentList",
"كيان_مرتبط": "Comment"
}
]
}

الاستخدام:

  • الكيان الافتراضي للسمات بدون linkedEntity صريح
  • التحقق من وجود الكيان
  • تلميحات توليد الكود
  • ليس مطلوباً إذا حددت جميع السمات كيانها صراحة

الفتحات وعرض واجهة المستخدم

السمات تعرض واجهة المستخدم عبر تأثيرات render-ui التي تستهدف الفتحات (Slots) - مناطق مسماة في الصفحة.

الفتحات المتاحة

الفتحةالغرض
mainمنطقة المحتوى الأساسي
sidebarلوحة جانبية
modalطبقة نافذة منبثقة
drawerلوحة درج
overlayطبقة ملء الشاشة
centerمحتوى مركزي
toastإشعارات مؤقتة
hud-topHUD علوي (واجهة الألعاب)
hud-bottomHUD سفلي (واجهة الألعاب)
floatingعنصر عائم
systemمكونات نظام غير مرئية

تأثير render-ui

السمات تملأ الفتحات باستخدام تأثير render-ui:

[
"عرض_واجهة",
"main",
{
"نوع": "entity-table",
"كيان": "Task",
"columns": [
"title",
"status",
"dueDate"
],
"itemActions": [
{
"حدث": "VIEW",
"تسمية": "View"
},
{
"حدث": "EDIT",
"تسمية": "Edit"
}
]
}
]

مسار الفتحات

┌─────────────────────────────────────────────────────────────┐
│ Page: TaskListPage │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Slot: main │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Pattern: entity-table (from TaskBrowser) │ │ │
│ │ │ - Columns: title, status, dueDate │ │ │
│ │ │ - Actions: VIEW, EDIT │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Slot: sidebar │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Pattern: filter-panel (from FilterPanel) │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

عمليات عرض متعددة لنفس الفتحة

إذا عرضت سمات متعددة في نفس الفتحة، تتراكم (الأحدث تستبدل أو تُضاف حسب نوع النمط):

// السمة A
["render-ui", "main", { "type": "stats", ... }]

// السمة B (لاحقاً في الصفحة)
["render-ui", "main", { "type": "entity-table", ... }]

التنقل (Navigation)

التنقل بين الصفحات يُعالج عبر تأثير navigate في السمات.

تأثير navigate

[
"انتقال",
"/tasks/:id",
{
"معرف": "@حمولة.taskId"
}
]

الصيغة: ["navigate", path, params?]

الوسيطالوصف
pathمسار الصفحة المستهدفة (يمكن أن يتضمن أجزاء ديناميكية)
paramsكائن اختياري لملء الأجزاء الديناميكية

أمثلة التنقل

تنقل بسيط:

[
"انتقال",
"/dashboard"
]

مع معرِّف الكيان:

[
"انتقال",
"/tasks/@entity.id"
]

مع الحمولة:

[
"انتقال",
"/tasks/:id",
{
"معرف": "@حمولة.taskId"
}
]

مسار متداخل:

[
"انتقال",
"/users/:userId/tasks/:taskId",
{
"userId": "@كيان.assigneeId",
"taskId": "@كيان.id"
}
]

التنقل في الانتقالات

التنقل عادة يحدث بعد تغييرات الحالة:

{
"من": "editing",
"إلى": "saved",
"حدث": "SAVE",
"تأثيرات": [
[
"حفظ",
"update",
"Task",
"@كيان.id",
"@حمولة"
],
[
"إشعار",
"Task saved!",
"success"
],
[
"انتقال",
"/tasks/@entity.id"
]
]
}

انظر التأثيرات لمزيد من التفاصيل.


الصفحة الأولية (Initial Page)

حدد صفحة كنقطة دخول باستخدام isInitial:

{
"اسم": "HomePage",
"مسار": "/",
"أولي": true,
"سمات": [
{
"مرجع": "WelcomeBanner"
}
]
}

السلوك:

  • التطبيق يحمّل هذه الصفحة أولاً
  • إعادة التوجيه من الجذر (/) تذهب إلى هنا
  • صفحة واحدة فقط يجب تحديدها كأولية لكل وحدة مدارية

التحقق من الصفحة (Page Validation)

تُتحقق الصفحات في وقت التصريف بهذه القواعد:

الحقول المطلوبة

  • name - يجب أن يكون بصيغة PascalCase
  • path - يجب أن يبدأ بـ /، أحرف صالحة فقط
  • traits - يجب أن تحتوي على مرجع سمة واحد على الأقل

أخطاء التحقق

الخطأالوصف
PageMissingNameاسم الصفحة مطلوب
PageMissingPathمسار الصفحة مطلوب
PageInvalidPathالمسار لا يطابق النمط
PageEmptyTraitsمصفوفة السمات لا يمكن أن تكون فارغة
PageInvalidTraitRefالسمة المشار إليها غير موجودة
PageInvalidViewTypeviewType ليس في القائمة الصالحة
PageDuplicatePathصفحة أخرى تستخدم نفس المسار

مثال كامل

مثال صفحة كاملة مع سمات متعددة:

مدار TaskManagement {
كيان Task {
id : نص!
title : نص!
status : نص
assigneeId : نص
}
سمة TaskBrowser -> Task {
أولي: idle
حالة idle {
تهيئة -> viewing
(جلب Task { })
(عرض_واجهة main { type: "entity-table", entity: "Task", fields: ["title", "status", "assigneeId"], columns: ["title", "status", "assigneeId"], itemActions: [{ event: "VIEW", label: "View" }] })
}
حالة viewing {
VIEW -> viewing
(انتقال "/tasks/@payload.id" { id: "@entity.id" })
}
}
سمة TaskViewer -> Task {
أولي: loading
حالة loading {
تهيئة -> viewing
(جلب Task { id: "@payload.id" })
(عرض_واجهة main { type: "detail-panel", entity: "Task", fields: ["title", "status", "assigneeId"] })
}
حالة viewing {
EDIT -> viewing
(انتقال "/tasks/@entity.id/edit")
BACK -> viewing
(انتقال "/tasks" { id: "@entity.id" })
}
}
صفحة "/tasks" -> TaskBrowser
صفحة "/tasks/:id" -> TaskViewer
}

المبادئ الأساسية

  1. الصفحات مدفوعة بالسمات - الصفحات حاويات لمراجع السمات. الواجهة تنبثق من تأثيرات render-ui في السمات، وليس من تعريفات الصفحات.

  2. بنية الفتحات - الواجهة تتدفق عبر فتحات موحدة (main، sidebar، modal)، مما يمكّن تركيب التخطيطات بدون تعليمات ثابتة.

  3. المسار كعقد - مسار الصفحة هو الواجهة الأساسية، يحدد عنوان URL الذي يتنقل إليه المستخدمون.

  4. ربط الكيان الصريح - linkedEntity على مراجع السمات يجعل علاقات الكيانات صريحة.

  5. لا حالة للصفحة - الصفحات تركيبية بحتة. كل الحالة تعيش في آلات حالة السمات.

  6. التنقل مدفوع بالتأثيرات - التنقل هو تأثير يُحفَّز بانتقالات السمات، وليس خاصية صفحة.


ملخص

يوفر نظام الصفحات في Orb:

  1. التوجيه - تنقل مبني على المسارات مع أجزاء ديناميكية
  2. تركيب السمات - سمات متعددة لكل صفحة، كل منها تساهم بواجهة
  3. الفتحات - مناطق مسماة لوضع الواجهة (main، sidebar، modal، إلخ.)
  4. أنواع العرض - تلميحات دلالية لغرض الصفحة (list، detail، dashboard)
  5. التنقل - توجيه مدفوع بالتأثيرات بين الصفحات
  6. ربط الكيان - علاقات كيان صريحة عبر linkedEntity
  7. التحقق - المُصرِّف يفرض تفرد المسارات ووجود السمات

الصفحات هي طبقة التوجيه والتركيب - تحدد أين يذهب المستخدمون، بينما السمات تحدد ماذا يحدث والكيانات تحدد ما هي البيانات المتضمنة.