| الملخص | إضافة لـ Discourse تتيح تخصيص شاشة البداية (Splash Screen) باستخدام HTML و CSS معرّفة من قبل المسؤول. | |
| رابط المستودع | https://github.com/VaperinaDEV/custom-splash-html-builder | |
| هل كانت الإضافة مفيدة؟ | > ./support --coffee | |
| دليل التثبيت | كيفية تثبيت الإضافات في Discourse |
مرحباً ![]()
لقد أنشأتُ إضافة صغيرة لـ Discourse تتيح تخصيص شاشة البداية باستخدام HTML و CSS معرّفة من قبل المسؤول، دون الحاجة إلى الحفاظ على نسخة معدّلة من قالب شاشة البداية الأساسي في Discourse.
كان الدافع الأصلي وراء إنشاء هذه الإضافة هو أداء الجوال.
أردتُ إنشاء شاشة بداية متحركة أكثر تعقيداً، لكنني وجدتُ أن تحريكات SVG المدعومة في تنفيذ شاشة البداية الأساسية الحالية في Discourse يمكن أن تصبح مشكلة مفاجئة على أجهزة الجوال.
على سطح المكتب، قد تبدو الحركة سلسة تماماً، بينما على الجوال قد تصبح متقطعة بشكل ملحوظ، أو تفقد إطارات، أو تتأخر، أو حتى تبدو وكأنها تتوقف أثناء الحركة.
بعد تجربة مقاربات مختلفة، وجدتُ أن نقل الحركة من SVG نفسه إلى عنصر HTML محيط به، مثل <div>, أحدث فرقاً كبيراً جداً.
بدلاً من تحريك محتوى SVG بشكل مستمر، يمكن لـ SVG أن يبقى ثابتاً بينما يحرك المتصفح طبقة HTML الحاوية باستخدام تحويلات CSS (CSS transforms).
هذا يمنح المتصفح فرصة أفضل بكثير للتعامل مع الحركة كعملية تركيب (compositing operation) باستخدام عتاد الرسوميات في الجهاز.
كانت النتيجة حركة أكثر سلاسة بكثير على الجوال، دون التوقفات والتجمّدات التي كنت أراها مع الطريقة المعتمدة على SVG.
كان هذا هو السبب الرئيسي لإنشاء هذه الإضافة.
قبل (SVG متحرك: الحركة تتأخر وتتوقف)
بعد (HTML متحرك: حركة سلسة)
المشكلة في تحريك ملفات SVG
تنفيذ شاشة البداية الأصلي جيد تماماً لشعار بسيط أو حركة خفيفة نسبياً.
ومع ذلك، بمجرد أن تصبح الحركة أكثر تعقيداً، يمكن أن يصبح عرض SVG مكلفاً.
على سبيل المثال، قد تتطلب الحركة المطبقة مباشرة على SVG أو عناصره الداخلية من المتصفح معالجة أو إعادة رسم أجزاء من SVG بشكل متكرر أثناء الحركة.
على أجهزة الجوال، يمكن أن يصبح هذا ملحوظاً بشكل خاص.
أثناء الاختبار، رأيتُ حالات كانت فيها الحركة:
- تصبح متقطعة بشكل مرئي
- تتجمد مؤقتاً
- تبدو وكأنها تتوقف
- تؤدي أداءً أسوأ بكثير من سطح المكتب
الجزء المثير للاهتمام هو أن نفس الحركة المرئية يمكن أن تتصرف بشكل مختلف جداً اعتماداً على ما الذي يتم تحريكه فعلياً.
نقل الحركة إلى طبقة HTML
المقاربة التي عملت بشكل أفضل بكثير هي إبقاء SVG نفسه ثابتاً ووضعه داخل عنصر HTML عادي.
على سبيل المثال:
<div class="logo-layer">
<svg viewBox="0 0 500 500">
...
</svg>
</div>
بدلاً من تحريك SVG، يتم تطبيق الحركة على الحاوية:
#d-splash .logo-layer {
animation: pulse 1.8s ease-in-out infinite;
will-change: transform;
}
@keyframes pulse {
0%,
100% {
transform: scale(0.8);
}
50% {
transform: scale(0.85);
}
}
لا يتغير SVG نفسه.
لذلك، يمكن للمتصفح التعامل مع تحويل طبقة HTML بكفاءة أكبر بكثير، وفي الحالات المدعومة، ترقية ذلك إلى طبقة مركّبة (composited layer) يتعامل معها عتاد الرسوميات.
أنتج هذا نتيجة أكثر سلاسة بشكل درامي على أجهزة الجوال.
التمييز الهام هو إذن:
المقاربة الأساسية:
SVG
└── حركة SVG
└── يتم تحريك محتوى SVG
مقابل:
المقاربة المخصصة:
طبقة HTML
└── SVG
└── تحويل CSS على طبقة HTML
└── حركة صديقة لمحرك التركيب (compositor)
هذا لا يضمن أن كل حركة ستكون معززة بواسطة وحدة معالجة الرسوميات (GPU). المتصفح في النهاية يقرر كيف يتم تركيب الحركة، لكن في اختباراتي كان الفرق ملحوظاً جداً.
لماذا أنشأتُ Custom Splash HTML Builder
بمجرد أن أصبحت هذه المقاربة تعمل، كنتُ أيضاً بحاجة إلى طريقة لبناء شاشة البداية حولها فعلياً.
قالب شاشة البداية القياسي لا يوفر المرونة الكافية لهذا النوع من التنفيذ.
لحركة أكثر تعقيداً، قد أحتاج إلى:
- عدة طبقات SVG
- عدة حاويات HTML
- عناصر متحركة بشكل مستقل
- إطارات مفتاحية CSS مخصصة (custom CSS keyframes)
- توقيتات حركة مختلفة
- تموضع مخصص
- علامات (markup) مختلفة تماماً عن شاشة البداية الافتراضية
لذلك، بدلاً من إنشاء تنفيذ آخر لشاشة البداية برمجةً صارمة (hard-coded)، قررتُ تعويض الجزء المرئي من خلال إعدادين للموقع.
تضيف الإضافة:
splash_custom_html
علامات HTML/SVG التي يتم عرضها داخل شاشة البداية.
splash_custom_css
CSS المستخدم في شاشة البداية المخصصة، بما في ذلك الحركات، والإطارات المفتاحية، والتموضع، والسلوك المتجاوب.
هذا يجعل شاشة البداية قابلة للتخصيص فعلياً دون الحاجة إلى تعديل كود المصدر الخاص بالإضافة كل مرة تتغير فيها الحركة.
محرر إداري مدمج
توفر الإضافة أيضاً محرراً إدارياً صغيراً مدمجاً لإدارة شاشة البداية المخصصة.
تضيف قسمًا مخصصاً باسم Splash HTML Builder في واجهة إدارة Discourse، مع محررات منفصلة لـ:
- HTML مخصص
- CSS مخصص
يمكن حفظ التغييرات مباشرة من واجهة الإدارة دون الحاجة إلى تعديل إعدادات الموقع المقابلة يدوياً.
الإعدادات الأساسية لا تزال:
splash_custom_htmlsplash_custom_css
المحرر هو ببساطة واجهة أكثر راحة لإدارتها.
هذا يعني أيضاً أن الإضافة لا تتطلب تعديل ملفات مصدر الإضافة كلما احتاجت حركة شاشة البداية إلى التغيير.
مثال
يمكن أن تحتوي شاشة البداية المخصصة على عدة طبقات مستقلة:
<div class="ring-layer">
<svg viewBox="0 0 500 500">
...
</svg>
</div>
<div class="logo-layer">
<svg viewBox="0 0 500 500">
...
</svg>
</div>
ويمكن لكل طبقة أن يكون لها حركتها الخاصة:
#d-splash .ring-layer {
animation: rotate 2.2s linear infinite;
will-change: transform;
}
#d-splash .logo-layer {
animation: pulse 1.8s ease-in-out infinite;
will-change: transform;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes pulse {
0%,
100% {
transform: scale(0.8);
}
50% {
transform: scale(0.85);
}
}
تبقى ملفات SVG ثابتة بينما يتم تحريك طبقات HTML المحيطة.
هذا يجعل من الممكن إنشاء حركات شاشة بداية أكثر تعقيداً بكثير مع إبقاء العمل المكلف للحركة خارج SVG نفسه.
لماذا لا نتجاوز ببساطة قالب شاشة البداية الأساسي؟
كان هدفاً مهماً آخر هو تجنب الحفاظ على نسخة من قالب شاشة البداية الأساسي في Discourse.
المقاربة المباشرة ستكون تجاوز:
app/views/common/_discourse_splash.html.erb
ونسخ تنفيذ Discourse الحالي إلى الإضافة.
المشكلة هي أن هذا ينشئ عبئاً على الصيانة.
إذا غيّرت Discourse تنفيذ شاشة البداية في إصدار مستقبلي، فستحتوي الإضافة لا تزال على النسخة القديمة.
قد يؤدي ذلك إلى:
- فقدان تغييرات أساسية جديدة
- فقدان تحسينات الأداء
- سلوك معطوب بعد تحديث Discourse
- الحاجة إلى مقارنة قالب الإضافة بالأساسي يدوياً بعد كل تحديث
أردتُ تجنب ذلك تماماً.
خطة بديلة للقالب الأساسي (Core Fallback)
لذلك، تدعم الإضافة شاشة بداية مخصصة مع خطة بديلة للقالب الأساسي.
تم تكوين HTML مخصص
إذا:
SiteSetting.splash_custom_html.present?
عندئذٍ تعرض الإضافة شاشة البداية المخصصة.
HTML المخصص فارغ
إذا لم يتم تكوين شاشة بداية مخصصة، فإن الإضافة تعود إلى قالب شاشة البداية الأساسي الحالي في Discourse.
تحدد الإضافة الملف الأساسي الفعلي من تثبيت Discourse الجاري تشغيله:
Rails.root/app/views/common/_discourse_splash.html.erb
وتعرض ذلك التنفيذ.
من الناحية المفاهيمية:
core_splash_path = Rails.root.join("app", "views", "common", "_discourse_splash.html.erb")
if File.exist?(core_splash_path)
render inline: File.read(core_splash_path), type: :erb
end
هذا يعني أن الإضافة لا تحمل نسخة ثانية من قالب شاشة البداية الأساسي.
اعتبارات الأداء
لا تحاول الإضافة الادعاء بأن كل حركة CSS ستصبح معززة بواسطة GPU بسحر ما.
لا يزال المتصفح يقرر كيف يتم عرض الحركات الفردية وتركيبها.
الهدف بدلاً من ذلك هو منح المتصفح بنية أكثر ملاءمة بكثير للتركيب المعزز بالعتاد:
- إبقاء محتوى SVG ثابتاً
- عزل العناصر المتحركة بشكل مستقل
- تحريك طبقات HTML
- تفضيل
transformللحركة/التحجيم/الدوران - تجنب عمليات إعادة الرسم المكلفة غير الضرورية
- استخدام
will-changeحيثما يناسب
على سبيل المثال:
#d-splash .ring-layer {
will-change: transform;
animation: rotate 2.2s linear infinite;
}
```\n
عملت هذه المقاربة بشكل خاص جيد لحالتي واستبعدت تقطع الجوال الذي كنت أراه مع حركة SVG الأصلية.
---
# تفعيل أو تعطيل شاشة البداية المخصصة
توفر الإضافة أيضاً إعداد موقع باسم `custom_splash_html_builder_enabled`.
عند التعطيل، تُستخدم شاشة بداية Discourse القياسية بغض النظر عما إذا كان HTML أو CSS مخصصاً قد تم تكوينه.
يوفر هذا مفتاح أمان إضافياً لتعطيل شاشة البداية المخصصة مؤقتاً دون حذف HTML/CSS المحفوظ.
لا يتم عرض شاشة البداية المخصصة إلا عندما يكون كلا الشرطين:
custom_splash_html_builder_enabled = true
splash_custom_html is not empty
إلا ذلك، تُستخدم شاشة البداية الأساسية الحالية في Discourse.
---
الأهم من ذلك، أنها توفر طريقة لبناء شاشة بداية متحركة مخصصة تؤدي أداءً أفضل بكثير على الجوال من خلال **تحريك طبقات HTML حول محتوى SVG ثابت بدلاً من تحريك SVG نفسه مباشرة**.