- TypeScript 90%
- CSS 5.9%
- Shell 1.9%
- JavaScript 1.2%
- Dockerfile 0.6%
- Other 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .gitea/workflows | ||
| client | ||
| desktop | ||
| e2e | ||
| scripts | ||
| server | ||
| .dockerignore | ||
| .gitignore | ||
| CHANGELOG.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| package.json | ||
| playwright.config.ts | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
دوكو (Docu)
منصة توثيق عربية بسيطة — صفحات شجرية + محرر كتل، مع الميزة الجوهرية: اتجاه كل فقرة (RTL / LTR) يُحدَّد تلقائيًا حسب أول حرف، مع إمكانية التوجيه اليدوي.
مشروع تعليمي مبني على فكرة Docmost لكن بنسخة مبسطة ومستقلة.
الميزات
- 🌳 صفحات شجرية غير محدودة العمق — الإنشاء عبر نافذة داخلية، مع نقل (زر أو سحب وإفلات)، وحذف ناعم متسلسل.
- 🔀 نقل الصفحات: من زر «نقل» في الشريط الجانبي تنقل أي صفحة تحت أي صفحة أخرى أو للجذر.
- ✍️ محرر كتل غني (TipTap) — عناوين، غامق/مائل/شطب، فوقي/سفلي، ألوان النص والتظليل، روابط، قوائم مهام (Checkboxes)، اقتباس، كود، خط أفقي، ومحاذاة النص (يمين/وسط/يسار/ضبط).
- 🔍 بحث في نصوص الصفحات، و🖼️ صور (رفع وإدراج)، و⚡ أوامر "/" السريعة، و🧭 فهرس المحتوى.
- 🗑️ سلة المحذوفات: الحذف ناعم (soft delete) مع استرجاع أو حذف نهائي.
- 🌙 وضع داكن/فاتح + 🔤 تلوين صيغة الكود (syntax highlighting) + 🏷️ أيقونة للصفحة (إيموجي).
- 📊 جداول متقدمة: إدراج جدول، إضافة/حذف صفوف وأعمدة، صف رأس وعمود رأس، دمج الخلايا وفصلها، تغيير حجم الأعمدة بالسحب، محاذاة الخلايا، حذف الجدول، مع تحكم باتجاه الجدول كاملًا (RTL/LTR/تلقائي) دفعة واحدة.
- 📈 رسومات Mermaid التوضيحية: إدراج مخططات (flowchart وغيرها) تتحول لرسوم SVG، مع تعديل الكود بضغطة على الرسم.
- 🖥️ عرض الصفحة قابل للتبديل: زر في رأس المحرر يوسّع منطقة الكتابة للعرض الكامل (مفيد للجداول العريضة) أو يعيدها للعرض الضيّق، ويُحفظ اختيارك.
- 🧭 اتجاه الفقرة تلقائي: إذا بدأت الفقرة بحرف عربي →
RTL، وبحرف لاتيني →LTR. - 🎛️ توجيه يدوي: من شريط الأدوات اختر
تلقائي / RTL / LTRلأي فقرة على حدة. - 💾 حفظ تلقائي أثناء الكتابة (مع تأخير debounce).
- 📜 سجل النسخ (History): لقطة تلقائية كل 60 ثانية، وزر «حفظ» يدوي لالتقاط نسخة فورية، مع معاينة لأي نسخة قديمة واسترجاعها.
- 🔔 إشعار الحفظ: إشعار عند كل حفظ تلقائي/يدوي، مع عرض «آخر حفظ: منذ …» في رأس المحرر.
- 📤 تصدير الصفحة: Markdown / HTML (مستقل بصور مضمّنة ورسومات Mermaid) / نص عادي / PDF (زر تصدير في رأس المحرر).
- 🗄️ نسخ احتياطي واسترجاع: تنزيل نسخة كاملة (JSON) واسترجاعها من أسفل الشريط الجانبي.
- 🌐 واجهتان (عربي / إنجليزي): مفتاح لغة أسفل الشريط الجانبي، وعند التبديل ينقلب اتجاه الصفحة تلقائيًا (RTL ↔ LTR) وتُحفظ اللغة في المتصفح.
- 🔤 خط Tajawal مدمج محليًا (عبر
@fontsource/tajawal) — بدون أي روابط إنترنت.
كيف يعمل اتجاه الفقرة؟
كل فقرة/عنوان يحمل سمة textDirection بإحدى القيم:
| القيمة | السلوك |
|---|---|
auto |
يُترك للمتصفح (عبر dir="auto") لتحديد الاتجاه حسب أول حرف قوي — عربي → RTL، لاتيني → LTR |
rtl / ltr |
توجيه يدوي صريح يتجاوز التلقائي |
الملفات المسؤولة:
client/src/editor/extensions/paragraphDirection.ts— امتداد TipTap.client/src/editor/utils/detectDirection.ts— كشف الحرف العربي/اللاتيني.
التقنيات
- الواجهة: React + Vite + Mantine + TipTap + خط Tajawal (مدمج محليًا)
- الخادم: Fastify + Drizzle ORM + SQLite (أسهل تشغيل بدون Docker)
- إدارة الحزم: pnpm workspaces
البنية
docu/
├── server/ # Fastify + Drizzle + SQLite
│ └── src/
│ ├── index.ts # نقطة الدخول (استماع + تقديم الواجهة المبنية)
│ ├── app.ts # buildApp(): بناء التطبيق (قابل للاختبار)
│ ├── db/ # الاتصال + schema + seed ترحيبي
│ └── routes/pages.ts # مسارات الصفحات (شجرة + CRUD)
└── client/ # React + Vite + Mantine + TipTap
└── src/
├── App.tsx # التنسيق العام
├── components/ # Sidebar + EditorPage + DirectionControl
└── editor/ # امتداد اتجاه الفقرة + كشف الاتجاه
التشغيل
يتطلب Node.js 18+ و pnpm.
pnpm install
pnpm dev # يشغّل الخادم (4000) والواجهة (5175) معًا
ثم افتح http://localhost:5175
أوضاع أخرى
pnpm dev:server # الخادم فقط
pnpm dev:client # الواجهة فقط
pnpm build # بناء الإنتاج
pnpm start # تشغيل الخادم + تقديم الواجهة المبنية على http://localhost:4000
واجهة الـ API
| الطريقة | المسار | الوصف |
|---|---|---|
| GET | /api/pages/tree |
الشجرة الكاملة متداخلة |
| GET | /api/pages/:id |
صفحة مع المحتوى |
| POST | /api/pages |
إنشاء صفحة { title, parentId? } |
| PATCH | /api/pages/:id |
تحديث { title?, icon?, content?, parentId? } |
| DELETE | /api/pages/:id |
حذف (متسلسل للأبناء) |
الاختبارات
pnpm --filter client test # اختبارات الوحدة (محوّل Markdown + كشف الاتجاه)
pnpm --filter server test # اختبارات تكامل الخادم (Fastify inject: صحة + إنشاء/قراءة/حذف/سلة)
pnpm --filter server build # فحص أنواع الخادم (tsc --noEmit)
pnpm --filter client build # بناء الواجهة + فحص الأنواع
pnpm e2e # اختبارات E2E للواجهة (Playwright — نقر أزرار حقيقي في Chromium)
Docker و DevOps
المشروع جاهز للنشر عبر Docker على Gitea:
Dockerfile— بناء متعدد المراحل (بناء الواجهة ثم صورة تشغيل بخادم Node 22).docker-compose.yml— يسحب الصورة من الريجستريgit.majlis7.net/debe/docu:latestويشغّلها على المنفذ 4000 مع مجلد بيانات دائمdocu-data..gitea/workflows/ci.yml— خط أنابيب CI يعمل على رانر Gitea:- test: تثبيت الاعتماديات + اختبارات الوحدة والتكامل + فحص الأنواع + بناء الواجهة.
- e2e (بعد نجاح test): تثبيت Chromium + اختبارات Playwright للواجهة.
- docker (بعد نجاح test، على
master): بناء الصورة ورفعها للريجستري بوسمَيlatestورقم الإصدار.
النشر
# بعد أن يرفع CI الصورة للريجستري:
docker login git.majlis7.net -u debe
docker compose up -d # يسحب الصورة ويشغّلها على http://localhost:4000
إصدار جديد (رفع الإصدار تلقائيًا)
بعد أي تعديل بادئ برسالة Conventional Commit، شغّل:
./scripts/release.sh
يقرأ السكربت آخر رسالة commit ويحدّد حجم الترقيم تلقائيًا:
| الرسالة | الترقيم |
|---|---|
feat: ... |
MINOR |
fix: ... |
PATCH |
feat!: ... أو BREAKING CHANGE |
MAJOR |
ثم يحدّث version.ts وملفات package.json وCHANGELOG.md، وينشئ commit + tag ويرفعهما. يبني CI بعدها صورة بالوسم الجديد تلقائيًا.
تطبيق سطح المكتب (AppImage)
يمكن تشغيل دوكو كتطبيق سطح مكتب Linux مستقل (نافذة أصلية عبر Electron، بدون متصفح):
./scripts/build-appimage.sh
ينتج الملف desktop/build/release/Docu-<الإصدار>-x86_64.AppImage (قابل للتنفيذ مباشرة). يعمل السكربت على:
- بناء الخادم (JS) والواجهة.
- تجميعها مع غلاف Electron (
desktop/main.js+desktop/package.json). - إعادة بناء
better-sqlite3لإصدار Electron، ثم تغليف الكل بـ electron-builder.
- البيانات (قاعدة SQLite والصور) تُحفظ في مجلد المستخدم (
~/.config/Docu/) وليس داخل الـ AppImage (لأنه للقراءة فقط). - الأيقونة في
desktop/icon.png، وتفاصيل التغليف في حقلbuildداخلdesktop/package.json.
إصدارات البرنامج (Semantic Versioning)
نعتمد الترقيم MAJOR.MINOR.PATCH، ويظهر رقم الإصدار أسفل الشريط الجانبي:
| الجزء | متى يزيد |
|---|---|
| MAJOR | تعديلات كبيرة وأحيانًا جذرية (تغييرات تكسر التوافق) |
| MINOR | إضافة أو إزالة ميزة، أو تعديل بسيط |
| PATCH | إصلاح مشاكل/أخطاء |
- الإصدار الحالي: 1.7.0 (المعرّف في
client/src/version.tsوملفاتpackage.json).
استكشاف الأخطاء
- خطأ
Cannot find matching keyid(مشكلة corepack): عطّل التحقق من التوقيع ثم أعد التشغيل:COREPACK_INTEGRITY_KEYS=0 pnpm dev - المنفذ مشغول: غيّر منفذ الخادم عبر متغير
PORT، أو منفذ الواجهة فيclient/vite.config.ts.
خطوات قادمة مقترحة
- التعاون اللحظي (Yjs) — نفس نهج Docmost.
- تسجيل دخول وصلاحيات (CASL).
- السحب والإفلات لترتيب الشجرة (fractional indexing).
- الانتقال من SQLite إلى PostgreSQL.
- تصدير جماعي لكل الصفحات دفعة واحدة.