ThemeForge: نظام سمة CSS جاهز للتركيب يقوم وكيل الذكاء الاصطناعي بتثبيته في خطوة واحدة
- تاريخ النشر
- 5 أكتوبر 2026
- تاريخ التحديث
- 6 أكتوبر 2026
- بقلم
- جاكوب لويد — كُتب بمساعدة الذكاء الاصطناعي بعد إنجاز المشروع
- مدة القراءة
- قراءة 10 دقيقة
بعبارة مبسطة: ThemeForge هو مجلد مجاني من ملفات CSS وسكربت صغير يمنح أي تطبيق ويب محددًا للسمات، وعشر سمات ألوان، ومجموعة كاملة من الأزرار والحقول والبطاقات والنوافذ الحوارية الجاهزة. تم بناؤه بحيث يستطيع وكيل البرمجة بالذكاء الاصطناعي إدراجه في التطبيق بسطر واحد: يتبع الوكيل ملفًا قصيرًا في المستودع، ويحصل التطبيق على محدد يعمل، وإعداد افتراضي يتبع النظام، ورموز تصميم للبناء عليها.
معظم تطبيقات الويب تنتهي في النهاية بثلاثة مظهرات مكتوبة في ثلاثة أماكن مختلفة: كتلة :root في ملف CSS الرئيسي، وكتلة ثانية تحت @media (prefers-color-scheme: dark)، وثالثة في مكان ما لصقها مطوّر لجعل المُختار يعمل. والنتيجة هي نفسها كل مرة: عنصر تحكم يبدو بشكل واحد في الصفحة الرئيسية، وبشكل آخر في صفحة الإعدادات، وسؤال في سجل المشكلات يسأل لماذا يجعل المظهر الداكن التذييل أزرق. كتبتُ ThemeForge لجعل هذه الفئة من المشكلات مستحيلة. إنه مجلد واحد، ui-theme/، يحتوي على وقت التشغيل (runtime)، وطبقة أساسية، وفئات المكوّنات، ورموز (tokens) كل المظهرات العشرة، ومُختار مظهر، وتكيّفات اختيارية مع Tailwind وQuasar، وملف AGENTS.md قصير مكتوب لوكيل برمجة بالذكاء الاصطناعي. أفلت المجلد في مكانه، وأضف أربع سطور إلى رأس الصفحة، وسيحصل التطبيق على مُختار يعمل ومظهر افتراضي يتبع النظام. الوكيل الذي يثبّته يقوم بالعمل بأمر من سطر واحد؛ والباقي من هذا المقال مخصّص لمن يريد النظر تحت الغطاء.
هذا المقال هو الجولة: ما الذي يوجد فعليًا في المجلد، والمظهرات العشرة وما غرضها، وقصة التباين (contrast)، ورموز التصميم وفئات المكوّنات التي يسلّمها لك باقي المقال كبطاقة مرجعية. النصف الثاني مقصود أن يكون قابلًا للمسح السريع — كل رمز، وكل مكوّن، وكل طريقة عامة — بحيث يستطيع وكيل برمجة (أو أنت في المستقبل) نسخها كما هي.
خلاصة سريعة
- احصل عليه: github.com/LaserLloyd/ThemeForge — رخصة MIT، مجاني؛ وهناك أيضًا ملف zip للمصدر في صندوق التنزيلات أدناه.
- ما هو: مجلد واحد،
ui-theme/، يُفلت في أي تطبيق ويب ويمنحه عشرة مظهرات بألوان، ومُختار، ونحو 250 رمز تصميم، وطبقة عناصر أساسية، ومعايير نص، ومجموعة كاملة من فئات المكوّنات (أزرار، حقول، مفاتيح تبديل، بطاقات، حوارات، إشعارات toast، جداول، هيكل تطبيق). CSS عادي وسكربت صغير واحد. لا خطوة بناء، لا Node، لا تبعيات. - التثبيت بسطر واحد (نصًا من README):
python3 -c "import urllib.request as u,sys;sys.argv=['update.py','--dest','static/ui-theme'];exec(u.urlopen('https://raw.githubusercontent.com/LaserLloyd/ThemeForge/main/ui-theme/update.py').read())" - كتلة الرأس (الترتيب مهم):
ui-theme.jsأولاً (كلاسيكي، محجوز، وليس أبدًاdeferأوmodule)، ثمui-theme-base.cssوui-components.css، ثم CSS الخاص بالتطبيق نفسه، ثمui-theme.cssأخيرًا حتى تفوز رموز المظهر. - المُختار: عنصر واحد:
<select class="ui-select" data-ui-theme-picker aria-label="Theme"></select>. يملأ نفسه ويظل متزامنًا عبر التبويبات. - عشرة مظهرات: ستة أساسية (بنفسجي، ذهب منتصف الليل، جليدي، غابة، ورق، نهار) بالإضافة إلى أربعة اختيارية (أصفر كهربائي، LaserLloyd، LaserLloyd Light، أحمر ليلي). كل مظهر يجتاز تدقيق التباين بدون أي إخفاقات.
- التباين: نص الجسم 7:1، الثانوي 6:1، كل مستوى نصي على كل سطح 4.5:1، حواف العناصر التحكمية وحالات التشغيل/الإيقاف 3:1، ويُقرأ النشط/المحدد/الحالي بالشكل والعبء وليس باللون فقط.
- مصمَّم لوكلاء الذكاء الاصطناعي: AGENTS.md هو سكربت التثبيت مكتوبًا بنثر — وجّه أي وكيل نحوه وسيعمل المُختار في خطوة واحدة. CI الخاص بالمستودع نفسه (GitHub Actions، ثلاث مهام) أخضر على استنساخ، وتدقيق تباين، و
node --checkعلى كل ملف JS، وتشغيل اختبارات وقت التشغيل عبر Chrome بلا واجهة.
من أين تحصل عليه
مستودع واحد برخصة MIT: github.com/LaserLloyd/ThemeForge، مع AGENTS.md كسكربت تثبيت وتقرير التباين كتدقيق. تفضّل ملف zip؟ صندوق التنزيلات في نهاية هذه الصفحة يحتوي على المصدر الكامل، وصفحة التنزيلات في الموقع تذكره أيضًا. إذا لم تكن على جهاز فيه Python، فإن README يذكر أيضًا git clone --depth 1 وnpx degit ورابط <script> من jsDelivr مثبّت على @v1.0.0 للنماذج الأولية.
ما الذي ستنتهي إليه
على بُعد سؤال عن المظهر المفضّل للمستخدم: ترويسة مع مُختار يعرف كل المظهرات مسبقًا، ومظهر افتراضي داكن وآخر فاتح يتبعان نظام التشغيل، وسطر CSS واحد في قاعدة أكواد التطبيق يقول background: var(--surface-2) بدلًا من #1d1d39. اختر مظهرًا، أعد التحميل، ولن يكون هناك وميض — سكربت وقت التشغيل يعمل بشكل متزامن في <head>، يقرأ إعدادات data-* الخاصة به من الوسم، ويضبط المظهر قبل أول رسم. افتح المُختار في تبويبين، غيّر المظهر في أحدهما، وسيُعاد رسم الآخر ليتطابق (مستمع حدث storage). اطبع مظهرًا داكنًا أو OLED وسيتبدّل وقت التشغيل إلى شريك فاتح طوال مدة مهمة الطباعة (أو يخفي التنقل، حسب مفتاح data-print-theme) حتى تكون الصفحة المطبوعة مقروءة على الورق؛ اطبع مظهرًا فاتحًا وستُطبع الصفحة كما هي.
ui-app وui-card وui-btn وui-switch ورموز --surface-* / --text-* / --accent. المُختار هو <select data-ui-theme-picker> واحد — وقت التشغيل يملؤه ويُبقيه متزامنًا.الشكل أعلاه هو العرض التوضيحي داخل الصفحة، وليس لقطة شاشة من ملف منفصل. العينة الحقيقية — كل مكوّن في كل مظهر — موجودة في specimen/index.html داخل المستودع (افتحها عبر python3 -m http.server ثم /specimen/).
كيف تتكامل الأجزاء
وقت التشغيل هو سكربت صغير واحد، ui-theme.js (نحو 23 كيلوبايت، 575 سطرًا)، يقوم بثلاث أشياء بالترتيب. يقرأ سمات data-* الخاصة به من وسم <script> الذي يعيش فيه (حتى تسافر الإعدادات مع الملف)، ينظر إلى localStorage وتفضيل النظام الفاتح/الداكن، ويكتب المظهر المختار في <html data-palette> والسطح النشط في <html data-theme> (إحدى amoled أو dark أو light) قبل أول رسم. ثم يجوب المستند بحثًا عن عناصر <select data-ui-theme-picker> ويملؤها بقائمة المظهرات المفعّلة (ويستمع لأي عنصر يرسمه إطار عمل لاحقًا). ثم يعرّض window.UITheme و، عند تحميل ui-components.js، يعرّض window.UIComponents، ويربط مستمع حدث storage حتى يبقى تبويبان متزامنين. CSS عادي: ui-theme-base.css يضبط نص الصفحة والروابط وحلقة التركيز وأشرطة التمرير وإعدادات تقليل الحركة الافتراضية؛ ui-components.css يرسم الأزرار والحقول ومفاتيح التبديل والبطاقات والحوارات والإشعارات toast والجداول؛ ui-theme.css هو الملف الوحيد الذي يتغير بين المظهرات — فهو يعرّف كل رمز (لون، نوع، مسافة، نصف قطر، ظل، حركة) لكل المظهرات العشرة تحت محدد [data-palette="…"] (البنفسجي هو :root، أي أنه غياب data-palette). وقت التشغيل يختار المظهر؛ وCSS يرسمه.
الجزء الذي يفاجئ الناس هو متابعة سمة نظام التشغيل: data-default="auto" يقرأ prefers-color-scheme عند كل تحميل للصفحة، ويجمعها بيئة التشغيل مع الاختيار المحفوظ للزائر (أو مع data-default-dark وdata-default-light) لاختيار سمة. غيّر سمة نظام التشغيل ثم حدّث الصفحة — ستتابعها الصفحة. اختر سمة صراحةً من المُختار وستبقى هي السائدة حتى يمسحها المستخدم (أو يستدعي UITheme.reset()). كما تربط بيئة التشغيل حدث storage بحيث تبقى تبويبان مفتوحان للتطبيق نفسه متزامنين دون رحلة إلى الخادم.
التثبيت
ملف AGENTS.md في المستودع هو الشرح الكامل؛ أما الإصدار المختصر فهو السطر الواحد أدناه وكتلة ترويسة من أربع وسوم. من جذر التطبيق:
python3 -c "import urllib.request as u,sys;sys.argv=['update.py','--dest','static/ui-theme'];exec(u.urlopen('https://raw.githubusercontent.com/LaserLloyd/ThemeForge/main/ui-theme/update.py').read())"
ينزّل هذا الأمر المثبّت، الذي يجلب أحدث إصدار، ويتحقق من كل ملف مقابل قائمة SHA-256 الخاصة به في files.json ثم يكتب المجلد. على ويندوز استخدم python أو py بدلاً من python3؛ السطر نفسه يعمل في PowerShell وcmd وbash. الأسطر الأربعة في ترويسة كل صفحة <head>:
<script src="/static/ui-theme/ui-theme.js"
data-themes="purple,midnight-gold,glacier,forest,paper,daylight"
data-default="auto" data-default-dark="midnight-gold" data-default-light="daylight"
data-storage-key="myapp.theme"></script>
<link rel="stylesheet" href="/static/ui-theme/ui-theme-base.css">
<link rel="stylesheet" href="/static/ui-theme/ui-components.css">
<!-- your stylesheets -->
<link rel="stylesheet" href="/static/ui-theme/ui-theme.css">
ثلاث قواعد، لكل منها سبب. سكربت ui-theme.js كلاسيكي وحاجز — لا تجعله أبداً type="module" أو defer أو async — لأنه يقرأ إعداداته من وسمه الخاص (document.currentScript، وهو null لسكربتات الوحدات) ويضبط السمة قبل أول عرض. طبقتا الأساس والمكوّنات تُحمّلان قبل CSS الخاص بالتطبيق حتى تفوز قواعد التطبيق نفسها عند تساوي الأهمية. أما ui-theme.css فيُحمَّل بعد ذلك، فلا يمكن لمتغير قديم في التطبيق أن يخفي رمز سمة أبداً. المُختار سطر واحد: <select class="ui-select" data-ui-theme-picker aria-label="Theme"></select>. من السكربت: UITheme.set('glacier')، UITheme.current()، UITheme.onChange(fn). التثبيت بأكمله يستغرق حوالي خمس دقائق، كما في المقدمة في AGENTS.md.
الوكيل الذي أضاف هذا بخطوة واحدة، على تطبيق حقيقي، كان على هذا النحو: طلب إنسان من وكيل برمجة بالذكاء الاصطناعي منح التطبيق وضعاً داكناً ومُختاراً للسمات. قرأ الوكيل AGENTS.md، نفّذ السطر الواحد في static/ui-theme/، لصق وسوم كتلة الترويسة الأربعة في القالب الأساسي، استبدل حرفين لونيين ثابتين بـvar(--surface-2) وvar(--text-secondary)، ووضع المُختار في الترويسة. ستة أسطر من الفروق في التطبيق، وصفر تبعيات جديدة. تدقيق التباين يغطي بالفعل كل زوج يعرضه المكوّنات، وبيئة التشغيل تتابع نظام التشغيل بالفعل، والالتزام المستقبلي الذي يثبّت لوناً هو الشيء الوحيد الذي يجب على خطوة الفحص التقاطه.
السمات
الست الأولى هي المجموعة الأساسية التي يقدمها التطبيق افتراضياً؛ أما الأربع الاختيارية فتظهر فقط عندما يسردها تطبيق. كل سمة تجتاز تدقيق التباين (docs/contrast-report.md): نص الجسم بنسبة 7:1، النص الثانوي بنسبة 6:1 على كل سطح، كل طبقة نصية أخرى 4.5:1، حواف عناصر التحكم وحالات التشغيل/الإيقاف 3:1، والحالة المختارة/الحالية تُقرأ بالشكل كما باللون في كل سمة. القائمة الكاملة:
| السمة | المجموعة | الخلفية | الوصف |
|---|---|---|---|
| بنفسجي | أساسية | داكنة | لمسة بنفسجية ونص لافندر ناعم على نيلي عميق. السمة الأساسية: قيمها هي الافتراضيات في :root. |
| ذهبي منتصف الليل | أساسية | OLED | ذهبي دافئ على أسود حقيقي، لشاشات OLED. |
| جليد | أساسية | OLED | نص أزرق جليدي وتوقيع على أسود حقيقي، مع لمسة تركوازية عميقة. |
| غابة | أساسية | OLED | ميرمية شاحبة وطحالب مع بنيات لحاء على أسود حقيقي. |
| ورق | أساسية | فاتحة | رقّ دافئ، نص بني حبري، خط مائل للنثر ولمسة حمراء. |
| نهار | أساسية | فاتحة | أبيض نظيف مع لمسة زرقاء. |
| أصفر كهربائي | اختيارية | داكنة | أصفر حامضي على غرافيت بزوايا ضيقة وخطوط حادة. |
| LaserLloyd | اختيارية | داكنة | أزرق ليزر على غرافيت شبه أسود، من موقع المؤلف. يتزاوج مع LaserLloyd Light. |
| LaserLloyd Light | اختيارية | فاتحة | الشريك الفاتح لسمة LaserLloyd. |
| أحمر الليل | اختيارية | OLED | سمة ليلية منخفضة الضوء الأزرق: نص جمر على أسود حقيقي، بنية حمراء، وصفر أزرق في أي لون. |
ثلاث من الأربع الاختيارية صاخبة عمداً. الأصفر الكهربائي هي التي أستخدمها عندما أراجع CSS في الظلام وأريد للصفحة أن تكون أعلى صوتاً من محرري؛ LaserLloyd تطابق مظهر هذا الموقع الأزرق والغرافيتي للحفاظ على الاتساق بين الموقع وتطبيق أبنيه عليه؛ أحمر الليل هو "ملف ليلي" منفصل يفحصه أداة التباين مقابل مجموعة مريحة من 171 سطراً (المعيارية 147 بالإضافة إلى أسطر إضافية لظروف الإضاءة المنخفضة) وكل رمز في لوحة الألوان فيه صفر في قناة الأزرق (docs/contrast-report.md "تدقيق الصفر أزرق" ناجح؛ README.md §أحمر الليل؛ docs/THEMES.md §أحمر الليل).
نقاط الانتباه
- اللون المُثبَّت يدويًا في CSS هو الخلل، وليس السمة. الفحص يتحقق من الرموز (tokens) فقط؛ فأي
color: #fffداخل كود التطبيق سيظل أبيض في كل السمات. أداةtools/lint_colors.py(في المستودع) وأمر grep في AGENTS.md §8 تلتقط هذا؛ لكن الفحص في CI لا ينفّذ تلك الخطوة، لذا نفّذها محليًا قبل الدمج. - يجب أن يكون
ui-theme.jsأول عنصر في<head>، كلاسيكيًا، وليسdeferأوmodule. سكريبت module لا يملكdocument.currentScript، ووقت التشغيل يقرأ قيمته الخاصةdata-*من الوسم. العَرَض هو وميض السمة الخاطئة ثم السمة الصحيحة. - يجب تحميل
ui-theme.cssبعد CSS الخاص بالتطبيق، لا قبله. الترتيب هو: الأساس، المكونات، التطبيق، الرموز. قاعدة تطبيق ذات نفس مستوى الأهمية (specificity) تُحمَّل بعد الرموز تخسر. data-themesيتحكم في ما يعرضه المُنتقي (picker). السمة المخزّنة التي معرّفها المختصر (slug) غير موجود فيdata-themesتُتجاهل عند التحميل التالي (وقت التشغيل يعود إلى الافتراضي). عند إزالة سمة، أضفdata-legacy-key+data-legacy-mapمرة واحدة، وستُهاجَر القيمة المخزّنة.rounded-mdوfont-sansفي Tailwind يتغيّران بعد التثبيت. هذا متوقع: السمة تُعرّف رموز--radius-و--font-، وقيمها هي الغالبة. لا تحاول مقاومتها.- تحذير hydration في Next.js. أضف
suppressHydrationWarningإلى<html>وأسكِت قاعدة lintno-sync-scriptsلكُتلَة head: وقت التشغيل يضبط سمات على<html>قبل أن يُجري React عملية hydration. - مكتبة أخرى تقرأ
data-themeعلى<html>(daisyUI, Pico). وقت التشغيل يكتبdata-theme="amoled|dark|light"هناك؛ تأكد من أن المكتبة لا تستجيب لذلك. إن كانت تستجيب، ضع سمة مختلفة عليها عبرdata-mirror-attr. - لا تُعدّل أي شيء داخل
ui-theme/. يُستبدل المجلد عند التحديث؛ الفحص يلتقط التعديلات اليدوية وسيرفض التثبيت تجاوز ملف مُعدَّل. انقل التغيير إلى CSS الخاص بالتطبيق نفسه بدلًا من ذلك. - الخطوط المذكورة في المكدسات (stacks) غير مضمّنة. كل مكدس يعود إلى خطوط النظام؛ إن أردت Inter أو JetBrains Mono أو Space Grotesk أو Archivo، حمّلها بنفسك (وثيقة التكامل تحتوي على
<link>جاهز للنسخ واللصق). prefers-contrast: moreيرفع تباين الخطوط وأدنى مستوى نص هادئ. لا حاجة إلى علم (flag) في السمة؛ وقت التشغيل يستمع والـ CSS يستجيب. مجموعة رموزhigh-contrastهي الخيار الاختياري القديم (legacy opt-in) لنفس التأثير.
أين وصلني هذا
ما أردته هو طريقة تمنح كل تطبيق أبنيه نظام سمات حقيقيًا دون كتابة واحد من الصفر في كل مرة، وThemeForge هو النسخة التي أنا مستعد للاحتفاظ بها. المجلدات التي أضعها في التطبيقات أصبحت ui-theme/ وما يفعله التطبيق؛ وأوسمة كُتلَة head الأربعة والمُنتقي متطابقان في كل إطار عمل. الوكيل (agent) الذي يثبّتها يقرأ AGENTS.md، وليس رسالة Slack. فحص التباين، واختبارات وقت التشغيل عبر Chrome بلا واجهة (headless)، وnode --check على كل ملف JS مُصدَّر هي ما يمنحني الشجاعة للمتابعة. النسخة 1.0.0 لأن الرموز هي الواجهة البرمجية العامة (public API) وإعادة تسمية رمز تعني إصدارًا رئيسيًا (major version)؛ الإصدار هو وسم git، ومجلد VERSION يطابقه، وملفات JSON موقّعة بنفس قائمة الترميز التجزئة (checksum list) التي يتحقق منها update.py. CI الخاص بالمستودع نفسه أخضر على Linux وWindows وPython 3.9، ونفس الفحوصات تنجح على نسخة جديدة (fresh clone) على هذا الجهاز.
مرجع (لوكلاء الذكاء الاصطناعي)
بقية هذه المقالة هي بطاقة مرجع يمكن لوكيل برمجة (أو أنا في المستقبل) أن ينسخها حرفيًا. النصف الأول أعلاه هو النص السردي؛ والنصف الثاني منظم وقابل للمسح السريع ومُصمَّم ليقرأه أداة. كل رمز، وكل فئة مكوّن، وكل طريقة عامة على window.UITheme وwindow.UIComponents، وكل سمة، وكل مقبض وسمة script، وكل مُكيّف (adapter)، ومسار التثبيت الكامل، وعقد التباين، وكُتلَة الإصدار — كلها أدناه.
قائمة الملفات
للمستودع شجرتان مهمتان: الحزمة الجاهزة للنسخ التي ينسخها التطبيق، وأدوات التصميم والأدوات التي تبنيها. المقالة عن الحزمة.
الحزمة الجاهزة للنسخ — ما ينسخه التطبيق (ui-theme/):
| الملف | الحجم | الأسطر | ما هو |
|---|---|---|---|
ui-theme.js |
23,515 B | 575 | وقت التشغيل: يطبّق السمة المخزّنة قبل أول رسم، يتبع وضوح/ظلام نظام التشغيل مع data-default="auto"، يملأ المُنتقيات، مزامنة التبويبات، يعرّض window.UITheme |
ui-theme-base.css |
13,255 B | — | قيم افتراضية للعناصر: نص الجسم، الروابط، العناوين، الكود، حلقة التركيز، أشرطة التمرير، تقليل الحركة، مستويات النص، .ui-markdown، ألوان highlight.js |
ui-components.css |
51,344 B | — | المكونات: الأزرار، الحقول، مربعات الاختيار، أزرار الاختيار الأحادي، المفاتيح (switches)، البطاقات، الشارات، التنبيهات (callouts)، التبويبات، عناصر التحكم المقسمة، الجداول، النوافذ الحوارية، القوائم، التلميحات (tooltips)، الإشعارات (toasts)، التقدم، كتل الكود، هيكل تطبيق |
ui-theme.css |
86,389 B (21,197 B مضغوطًا) | — | رموز السمات العشر جميعها (حوالي 20 KB مضغوطًا) |
ui-components.js |
5,441 B | 135 | اختياري: confirm()، alert()، prompt() وtoast() مُنسّقة بالسمة |
ui-theme.d.ts |
2,841 B | — | إعلانات TypeScript لـ window.UITheme وwindow.UIComponents |
update.py |
16,081 B | — | يثبّت ويحدّث المجلد؛ يتحقق من كل ملف مقابل SHA-256 الخاص به |
themes.json |
4,089 B | — | قائمة السمات (الاسم، العائلة، الأرضية، المجموعة، العيّنة، الخطوط) |
files.json |
1,401 B | — | قائمة الترميز التجزئة التي يتحقق منها update.py |
VERSION |
30 B | — | إصدار المجلد (ThemeForge 1.0.0 3db64d9f574f) |
README.md |
6,342 B | — | ملاحظات استخدام محلية للحزمة |
adapters/quasar.css |
24,997 B | — | خرائط NiceGUI/Quasar |
adapters/quasar.js |
1,468 B | 40 | جسر JS لـ NiceGUI/Quasar |
adapters/tailwind.css |
4,399 B | — | خرائط Tailwind CSS v4 @theme inline |
adapters/tailwind-v3.preset.js |
2,915 B | 54 | إعداد مسبق (preset) لـ Tailwind CSS v3 |
أدوات التصميم والأدوات التي تبني الحزمة (لا تُنسخ إلى التطبيق):
| الملف | الحجم | ما هو |
|---|---|---|
README.md |
6,592 B | README للمستودع |
AGENTS.md |
19,063 B | سكربت التثبيت كنص سردي، لوكلاء الذكاء الاصطناعي |
CHANGELOG.md |
4,425 B | سجل الإصدارات (1.0.0 هو أول إصدار) |
CLAUDE.md |
1,498 B | أعراف المستودع لـ Claude |
CONTRIBUTING.md |
4,476 B | العمل على السمات |
LICENSE |
1,067 B | MIT، حقوق النشر (c) 2026 (الملف الأصلي في المصدر يسمّي المؤلف بالاسم الشخصي؛ الصيغة التجارية هي ما تنقله الموقع، والنص الموجود على القرص موجود في رخصة المصدر); غير مضمّن في أرشيف التنزيل zip (سطر حقوق النشر الأصلي يسمّي المؤلف بالاسم الشخصي، وحارس محتوى الموقع يعتبر ذلك إفشاءً للهوية غير قابل للمراجعة) |
docs/TOKENS.md |
15,391 B | كل رمز، حسب المجموعة |
docs/COMPONENTS.md |
13,889 B | كل فئة مكوّن، مع العلامات (markup) |
docs/THEMES.md |
8,081 B | السمات، ملاحظات التصميم، إضافة سمة |
docs/INTEGRATIONS.md |
10,604 B | خطوات التثبيت لكل إطار عمل |
docs/TEXT.md |
5,465 B | مستويات النص ونمط markdown |
docs/UPDATING.md |
4,134 B | التحديثات، التثبيت (pinning)، التخزين المؤقت، ما تثبته الترميزات التجزئة |
docs/contrast-report.md |
124,372 B | فحص التباين (10 سمات × 147–171 صفًا) |
docs/theme-template.css |
9,854 B | هيكل سمة فارغ لـ tools/sync_theme.py |
tokens/<theme>.json |
~57 KB لكل ملف | رموز كل سمة محلولة بصيغة W3C DTCG JSON |
examples/static-html/ |
3,731 B index | مثال HTML/CSS/JS بسيط |
examples/fastapi-jinja/ |
2,172 B app.py | مثال FastAPI + Jinja |
specimen/index.html |
17,721 B | كل مكوّن في كل سمة، يُقدَّم محليًا |
tools/check_contrast.py |
43,171 B | فحص التباين (يُنفَّذ في CI) |
tools/lint_colors.py |
22,711 B | يفحص القيم اللونية الثابتة من CSS الخاص بالتطبيق |
tools/sync_theme.py |
41,671 B | يعيد بناء ui-theme.css، tokens/*.json، docs/contrast-report.md من src/css/*.css |
tools/update.py |
16,081 B | سكربت التثبيت/التحقق (مرآة لـ ui-theme/update.py) |
tools/screenshots.py |
3,273 B | معاينات السمات لـ docs/images/ |
tests/test_tools.py |
17,606 B | اختبارات وحدة Python (32 في هذه النسخة، 1 متجاوز) |
tests/run_browser_tests.py |
3,570 B | اختبارات وقت التشغيل عبر Chrome بلا واجهة |
tests/runtime.html |
24,930 B | هيكل اختبارات المتصفح |
.github/workflows/ci.yml |
— | CI: التباين، node --check، اختبارات الوحدة، اختبارات المتصفح، فحص CRLF، على Linux وWindows وPython 3.9 |
CI الخاص بالمستودع نفسه يعمل في ثلاث مهام (checks على Ubuntu مع Python 3.12، tools-on-windows على Windows مع Python 3.11، updater-on-oldest-python على Ubuntu مع Python 3.9). النسخة المحلية تنجح في node --check على كل ملف JS مُصدَّر، وأداة التباين تعيد إنتاج كل صفوف الفحص العشرة، واختبارات الوحدة تنجح (32 passed, 1 skipped in 1.212 s على Linux، Python 3.14، 2026-10-05).
رموز التصميم (المجموعات، الدور، قيمة مثال)
كل سمة تحلّ كل رمز. القيم أدناه خاصة بـ Purple (أساس الـ :root)؛ بقية السمات لها قيمها المحلولة في tokens/<theme>.json (DTCG JSON). استخدم رمزًا عبر var(--name). لا تُعرّف رمزًا مرة أخرى في CSS الخاص بالتطبيق — أعطِ متغيرات التطبيق بادئة خاصة بالتطبيق (--myapp-sidebar-w) أو اجعلها مستعارة لرمز (--myapp-brand: var(--accent)). المصدر: docs/TOKENS.md.
| المجموعة | الرمز | الدور | مثال (بنفسجي) |
|---|---|---|---|
| الأسطح | --surface-void |
أغمق من الصفحة (ملء كامل) | #08080f |
| الأسطح | --surface-0 |
الصفحة نفسها | #0e0e1b |
| الأسطح | --surface-1 |
شريط التنقل | #14142a |
| الأسطح | --surface-2 |
البطاقات | #1d1d39 |
| الأسطح | --surface-3 |
عند التحويم (hover) | #232342 |
| الأسطح | --surface-4 |
عند التفعيل (active) | #262648 |
| الأسطح | --surface-sunken |
حُفَر داخلة (inset wells) | #0a0a14 |
| الأسطح | --surface-overlay |
القوائم المنبثقة، النوافذ المنبثقة | #1d1d39 |
| الأسطح | --glass-1/2/3 |
لوحات شفافة | rgba(29,29,57,.72/.84/.92) |
| الأسطح | --glass-highlight |
لمعان الزجاج | rgba(255,255,255,.055) |
| الأسطح | --code-bg |
خلفية الكود | #0b0b16 |
| النص | --text-primary |
النص الرئيسي | #e8e8f0 |
| النص | --text-secondary |
التسميات، الأوصاف | #a0a0bd |
| النص | --text-tertiary |
التلميحات، الطوابع الزمنية | #8d8db0 |
| النص | --text-disabled |
عناصر التحكم المعطلة | #717195 |
| النص | --text-inverse |
نص على خلفية فاتحة | #0e0e1b |
| النص | --text-link / --text-link-hover |
الروابط والنص البارز | #a78bfa / #c4b5fd |
| النص | --on-accent / --on-danger / --on-success / --on-warning / --on-media / --on-media-muted |
تسمية على خلفية ملوّنة | #ffffff / #2a0808 / … |
| اللون البارز | --accent / --accent-hover / --accent-pressed |
اللون البارز للعلامة التجارية، الإجراءات الأساسية | #7c3aed / #8250f0 / #6d28d9 |
| اللون البارز | --accent-subtle / --accent-muted / --accent-glow |
خلفية ملوّنة، تعبئة ناعمة، توهج | rgba(124,58,237,.16/.26/.35) |
| اللون البارز | --accent-rgb |
حتى يتمكن JavaScript من تركيب rgba(var(--accent-rgb), .2) |
124,58,237 |
| اللون البارز | --accent-2 / --accent-2-subtle |
لون بارز ثانوي | #5eead4 |
| زر الإجراء (CTA) | --cta / --cta-hover / --cta-pressed / --on-cta |
لوحة إجراء قوية | #7c3aed / #8250f0 / #6d28d9 / #ffffff |
| زر الإجراء (CTA) | --cta-shadow / --cta-shadow-hover |
ظلال سقوط للوحة | 0 6px 20px rgba(124,58,237,.28) / .38 |
| زر الإجراء (CTA) | --highlight / --highlight-subtle / --on-highlight |
علامات، لون التلميحات | #fcd34d / rgba(252,211,77,.12) / #251a00 |
| الخطوط | --border-subtle / --border / --border-strong |
حواف عناصر التحكم في النماذج هي --border-strong بنسبة 3:1 |
#21213b / #292945 / #6f6f9c |
| الخطوط | --divider |
خطوط رفيعة | #21213b |
| الخطوط | --focus-ring / --focus-ring-width / --focus-ring-offset |
حلقة التركيز | #a78bfa / 2px / 2px |
| الخطوط | --glass-stroke / --glass-stroke-strong |
حدود الزجاج | rgba(255,255,255,.08/.16) |
| حالات التحكم | --selected / --on-selected |
مفعّل / مُحدَّد / مضغوط / حالي | حسب السمة |
| حالات التحكم | --unselected-border / --unselected-fg |
إطار غير مفعّل، 3:1 على كل سطح | حسب السمة |
| الحالة | --success / --warning / --danger / --info |
نقاط، أشرطة، تعبئة | حسب السمة |
| الحالة | --success-text / --warning-text / --danger-text / --info-text |
لون نص كل حالة | حسب السمة |
| الحالة | --success-subtle / --warning-subtle / --danger-subtle / --info-subtle |
خلفية ملوّنة لكل حالة | حسب السمة |
| الحالة | --success-border / --warning-border / --danger-border / --info-border |
حدود الحالات | حسب السمة |
| الحالة | --idle / --idle-text / --idle-subtle / --idle-border / --idle-hover |
حالة محايدة | حسب السمة |
| الحالة | --live / --live-text / --live-subtle / --live-border / --live-hover |
مؤشر "مباشر" / "قيد التشغيل" | حسب السمة |
| الكود / الصياغة | --syn-bg / --syn-fg / --syn-comment / --syn-keyword / --syn-string / --syn-number / --syn-function / --syn-attr / --syn-tag / --syn-builtin / --syn-type / --syn-variable / --syn-literal / --syn-operator / --syn-title / --syn-addition |
تدرج تمييز الصياغة | حسب السمة |
| الكود / الصياغة | --code-header-bg / --code-stroke |
إطار كتلة الكود (داكن في كل سمة) | حسب السمة |
| الرسوم البيانية | --cat-1 … --cat-12 |
ألوان السلاسل، 3:1 على --surface-0 |
حسب السمة |
| الرسوم البيانية | --seq-1 … --seq-5 |
تدرج من الأدنى إلى الأعلى | حسب السمة |
| الرسوم البيانية | --div-1 … --div-5 |
سيء، محايد، جيد | حسب السمة |
| الرسوم البيانية | --chart-grid / --chart-axis |
إطار الرسم البياني | حسب السمة |
| الفقاعات | --bubble-user-text / --bubble-assistant-text / --bubble-user-bg / --bubble-assistant-bg |
فقاعات الدردشة | حسب السمة |
| الفقاعات | --rp-speech / --rp-thought / --rp-shout / --rp-whisper / --rp-ooc / --rp-action / --rp-critical |
ألوان فقاعات تمثيل الأدوار | حسب السمة |
| الاختلافات (Diff) | --diff-add-bg / --diff-add-text / --diff-remove-bg / --diff-remove-text |
عرض الاختلافات | حسب السمة |
| الطباعة | --fs-xs / --fs-sm / --fs-md / --fs-lg / --fs-xl / --fs-2xl |
أحجام الخطوط | حسب السمة |
| الطباعة | --fw-medium / --fw-semibold / --fw-bold |
الأوزان | حسب السمة |
| الطباعة | --font-sans / --font-mono / --font-display |
حزم الخطوط | حسب السمة |
| التباعد | --space-1 … --space-8 |
4–64 بكسل | حسب السمة |
| الزوايا | --radius-sm / --radius-md / --radius-lg / --radius-pill |
أشكال العناصر | حسب السمة |
| الظلال | --shadow-1 / --shadow-2 / --shadow-3 / --shadow-4 |
مستويات ظل السقوط | حسب السمة |
| طبقات Z | --z-modal / --z-toast / --z-popover / --z-nav |
التراص (stacking) | حسب السمة |
| الحركة | --motion-fast / --motion-med / --motion-slow / --easing-standard |
التوقيتات (توقف الحركات عند تقليل الحركة) | حسب السمة |
| ماركداون | --md-bold / --md-italic / --md-bolditalic / --md-bolditalic-glow |
ماركداون داخل التطبيق | حسب السمة |
| متنوع | --mark-bg / --selection-text / --selection-bg / --media-filter / --quote-bar / --heartbeat-text / --heartbeat-hover / --offline-text / --on-offline / --canvas-handle |
ميزات صغيرة | حسب السمة |
المصدر: docs/TOKENS.md (22 مجموعة، حوالي 270 رمزًا — أمر grep -oE '\| \(--[a-zA-Z][a-zA-Z0-9-]*)` |' docs/TOKENS.md | sort -u | wc -lيعيد 272 اسم رمز فريد؛ 22 مجموعة بعنوان## `).
فئات المكونات (كل معدِّل، سطر واحد)
الحالة تأتي من السمات الأصلية (disabled, checked, aria-pressed, aria-selected, aria-current, aria-invalid, aria-busy, [open]) — وليس من فئة إضافية. معظم المحددات هي فئة واحدة حتى تفوز قاعدة التطبيق ذات التحديد المتساوي والتي تُحمَّل لاحقًا. خصائص منطقية في كل مكان (تعمل من اليمين إلى اليسار). المفعّل والمُحدَّد والمضغوط والحالي يتم ملؤه بـ --selected؛ غير المفعّل هو إطار؛ المعطَّل متقطع وغير مملوء. المصدر: docs/COMPONENTS.md.
| الفئة | المعدِّلات / الأجزاء | ما هي |
|---|---|---|
ui-stack |
— | عمود، تباعد --space-3 |
ui-row |
— | صف قابل للتفاف، في المنتصف، تباعد --space-2 |
ui-grid |
--ui-grid-min |
أعمدة بتعبئة تلقائية، يُضبط min على العنصر |
ui-container |
— | في المنتصف، أقصى عرض --content-max |
ui-spacer |
— | يدفع بقية الصف إلى النهاية |
ui-app |
__header __nav __main |
هيكل التطبيق (رأس، شريط تنقل جانبي، رئيسي)؛ يختفي الشريط الجانبي تحت 760 بكسل |
ui-brand |
— | عنوان التطبيق في الرأس |
ui-nav |
__label __item |
تنقل جانبي |
ui-title / ui-heading / ui-subheading / ui-lead / ui-kicker / ui-small / ui-mono / ui-num / ui-kbd / ui-code / ui-divider |
— | تدرج الخطوط (<hr> هو .ui-divider) |
ui-text-primary / -secondary / -tertiary / -disabled / -link |
— | فئات مستويات النص (استخدم الرموز للكود الجديد) |
ui-markdown |
— | حاوية لماركداون مُصيَّغ؛ انظر docs/TEXT.md |
ui-btn |
--primary --ghost --outline --danger --cta --sm --lg --icon --block |
أزرار؛ تعمل على <a> أيضًا؛ تُستخدم مع aria-pressed / aria-busy / disabled |
ui-btn-group |
— | الأزرار المتجاورة تشارك حافة دائرية |
ui-field |
— | حاوية حقل نموذج (تسمية + عنصر تحكم + مساعدة) |
ui-label |
— | تسمية الحقل |
ui-input |
--sm |
إدخال نصي |
ui-select |
— | <select> مُصيَّغ؛ data-ui-theme-picker يركّب منتقي السمة |
ui-textarea |
— | <textarea> مُصيَّغ |
ui-help |
— | نص مساعدة الحقل (يرتبط بـ aria-describedby) |
ui-error |
— | نص خطأ الحقل (يرتبط بـ aria-describedby)؛ يظهر عند aria-invalid="true" |
ui-input-group |
— | زوج إدخال + زر (مثلًا البحث) |
ui-check |
— | صف مربع اختيار / زر اختيار / مفتاح تبديل |
ui-checkbox |
— | <input type="checkbox"> أصلي مُصيَّغ |
ui-radio |
— | <input type="radio"> أصلي مُصيَّغ |
ui-switch |
— | مربع اختيار بـ role="switch" مُصيَّغ كمفتاح تبديل |
ui-switch-state |
data-on data-off |
تسمية "تشغيل" / "إيقاف" (aria-hidden؛ المفتاح يُعلن حالته بنفسه) |
ui-range |
— | إدخال نطاق أصلي ملوّن بـ --slider-color |
ui-segmented |
— | مجموعة أزرار تعمل كزر اختيار |
ui-tabs |
ui-tab |
قائمة تبويبات (تبويبات الروابط تستخدم <a aria-current="page">)؛ معالجة لوحة المفاتيح مسؤولية التطبيق |
ui-card |
__header __title __footer --raised --interactive |
بطاقة؛ aria-selected / aria-current ترسم إطارًا حول البطاقة المحددة |
ui-well |
— | حُفرة داخلة (سجلات، معاينات، محتوى ثانوي) |
ui-stat |
__label __value |
زوج تسمية / قيمة |
ui-badge |
--success --warning --danger --info --live --accent --neutral |
شارة بيضاوية |
ui-dot |
--success --warning --danger --info --live --neutral |
نقطة حالة |
ui-count |
--accent --danger |
شريحة عدّاد |
ui-callout |
--info --success --warning --danger __title |
تنبيه ملوّن (استخدم role="alert" للأخطاء) |
ui-table-wrap |
— | يغلّف <table class="ui-table"> لرؤوس ثابتة / تمرير |
ui-table |
--hover --compact td.num |
أنماط الجدول |
ui-dialog |
— | <dialog> مُصيَّغ |
ui-drawer |
— | ورقة جانبية على <dialog> |
ui-menu |
__item |
قائمة منبثقة |
[data-ui-tooltip] |
data-ui-tooltip-side="bottom" |
تلميح (Tooltip) على أي عنصر |
ui-progress |
— | شريط تقدم خطي |
ui-spinner |
— | مؤشر تحميل دوّار |
ui-skeleton |
— | هيكل تحميل |
ui-breadcrumbs |
— | قائمة مسار التنقل |
ui-pagination |
— | ترقيم الصفحات |
ui-avatar |
— | صورة رمزية دائرية |
ui-chip |
__remove |
شريحة قابلة للإزالة / التحديد |
ui-details |
— | أكورديون على <details> |
ui-fieldset |
— | مجموعة حقول + عنوان |
ui-codeblock |
__bar |
<figure> يحتوي على <figcaption class="ui-codeblock__bar"> + <pre> |
ui-empty |
— | حالة فارغة |
ui-bubble |
--user --assistant |
فقاعة دردشة |
الطرق العامة على window.UITheme و window.UIComponents
المصدر: ui-theme/ui-theme.d.ts (إعلانات TypeScript لكلا المتغيرين العالميين).
window.UITheme (UIThemeApi):
| العضو | النوع | ما يفعله |
|---|---|---|
version |
string (قراءة فقط) |
إصدار المجلد، مثل "1.0.0" |
config |
كائن (قراءة فقط) | { themes, default, auto, storageKey, families, printTheme } |
current() |
() => string |
معرّف (slug) السمة النشطة |
theme([slug]) |
(slug?) => UIThemeInfo \| null |
معلومات عن سمة واحدة (أو السمة النشطة) |
list() |
() => UIThemeInfo[] |
جميع السمات المفعّلة |
set(slug) |
(slug) => string |
التبديل إلى سمة؛ يعيد المعرّف |
reset() |
() => string |
العودة إلى الافتراضي؛ يعيد المعرّف |
partner([slug]) |
(slug?) => string \| null |
الشريك الفاتح/الداكن في عائلة (مثل laserlloyd ↔ laserlloyd-light) |
toggleFamily() |
() => string \| null |
التبديل إلى الشريك؛ يعيد المعرّف الجديد |
onChange(listener) |
(fn) => () => void |
الاشتراك؛ يعيد دالة إلغاء الاشتراك؛ تكون detail.print صحيحة عند التبديل حول الطباعة |
token(name, [el]) |
(name, element?) => string |
قيمة الرمز الخام (مثل "#7c3aed") |
tokens(names, [el]) |
(names, element?) => Record<name, string> |
عدة رموز دفعة واحدة |
color(name) |
(name) => string |
لون rgb() المحلول للوحة الرسم (canvas) |
colors(names) |
(names) => Record<name, string> |
عدة ألوان محلولة للوحة الرسم |
mountPicker(target, [opts]) |
(elOrSel, options?) => HTMLSelectElement \| null |
تعبئة عنصر select كقائمة اختيار؛ options هي { label, coreLabel, optInLabel, systemLabel } |
تُطلق حدث ui-theme-change على document مع { slug, theme, previous, print }.
window.UIComponents (UIComponentsApi): (يتطلب ui-components.js)
| الطريقة | التوقيع | ما تفعله |
|---|---|---|
confirm |
(opts: UIDialogOptions \| string) => Promise<boolean> |
دالة confirm() مخصصة؛ الخيارات هي { title, message, label, confirmLabel, cancelLabel, danger } |
alert |
(opts: UIDialogOptions \| string) => Promise<void> |
دالة alert() مخصصة |
prompt |
(opts: UIPromptOptions \| string) => Promise<string \| null> |
دالة prompt() مخصصة؛ تحل إلى null عند الإلغاء؛ الخيارات الإضافية هي { value, placeholder, type } |
toast |
(message, { kind?, timeout? }) => HTMLElement |
إشعار من نوع info / success / warning / danger؛ يعيد العنصر |
window.UI_THEME_MANIFEST (اختياري، له الأولوية على قيم وسم السكربت الافتراضية): { themes, default, defaultDark, defaultLight, storageKey, families, legacy, mirrorAttr, fontsHref, printTheme }. يقبل themes مصفوفة أو نصاً مفصوفاً بفواصل.
إعدادات وسم السكربت (data-* على وسم <script>)
| السمة | الافتراضي | ما تفعله |
|---|---|---|
data-themes |
السمات الأساسية الست (purple,midnight-gold,glacier,forest,paper,daylight) |
قائمة مفصولة بفواصل للسمات المفعّلة؛ تتحكم في قائمة الاختيار والقيم المخزنة المقبولة. عند عدم تعيين data-themes، يفعّل ui-theme.js السمات الست ذات set==="core" (ui-theme.js:147-149). |
data-default |
أول سمة مفعّلة (أول معرّف في data-themes، أو purple إذا لم تكن أي سمة مفعّلة ولم يكن auto) |
معرّف السمة الافتراضية، أو auto لمتابعة نظام التشغيل. النص الحرفي auto يفعّل متابعة النظام عبر prefers-color-scheme (ui-theme.js:164)؛ السمة الناقصة/الفارغة تحل إلى أول سمة مفعّلة (ui-theme.js:177-179). |
data-default-dark |
أول سمة مفعّلة غير فاتحة (أول معرّف في data-themes الذي ground !== "light"، وإلا أول سمة مفعّلة، وإلا purple إذا لم تكن أي سمة مفعّلة) |
النصف الداكن من auto. يختار ui-theme.js:168-175 هذا عندما يفضّل النظام الداكن ولم تُضبط قيمة صريحة. |
data-default-light |
أول سمة فاتحة مفعّلة (أول معرّف في data-themes الذي ground === "light"، وإلا أول سمة مفعّلة، وإلا purple إذا لم تكن أي سمة مفعّلة) |
النصف الفاتح من auto. نفس مسار الكود (ui-theme.js:168-175). |
data-storage-key |
ui-theme |
مفتاح localStorage الذي يُخزن تحت اختيار الزائر (ui-theme.js:185). يوصي AGENTS.md §3 بالتجاوز باستخدام <appname>.theme حتى لا يتعارض اختيار التطبيق مع تطبيق ThemeForge آخر على نفس المصدر. |
data-families |
false |
تجميع السمات حسب العائلة في قائمة الاختيار |
data-print-theme |
auto |
ما يطبع به الصفحة: عندما تكون السمة النشطة داكنة أو OLED، يبدّل auto إلى الشريك الفاتح للعائلة (أو أول سمة فاتحة مفعّلة، أو daylight)؛ المعرّف يطبع تلك السمة؛ none لا يبدّل؛ عندما تكون السمة النشطة فاتحة، تُطبع الصفحة كما هي (ui-theme.js:474-490). |
data-legacy-key |
— | مفتاح تخزين أقدم لمرة واحدة (مع data-legacy-map) |
data-legacy-map |
— | خريطة from→to للقيم القديمة (كائن JSON) |
data-mirror-attr |
— | عكس السمة النشطة على سمة مختلفة (للمكتبات التي تقرأها) |
data-fonts-href |
— | ورقة أنماط تُحقن لمكدس خطوط السمة |
المصدر: ui-theme.js:147-149, 164, 168-174, 185, 474-490 (الافتراضيات وقت التشغيل) و AGENTS.md §3، §12 (التجاوزات الموصى بها — مثل تعيين data-themes إلى السمات الأساسية الست، data-default="auto"، data-storage-key="<appname>.theme").
المحوِّلات (Adapters)
| المحوِّل | الملفات | ما يفعله |
|---|---|---|
| NiceGUI / Quasar | adapters/quasar.js + adapters/quasar.css |
حمّل adapters/quasar.js مباشرة بعد ui-theme.js و adapters/quasar.css مباشرة بعد ui-theme.css (عبر ui.add_head_html). تستخدم مفاتيح التبديل ومربعات الاختيار والأزرار الإشعاعية في Quasar تصميم حالة التحكم؛ عناصر التحكم المعطّلة تكون متقطعة بشفافية كاملة. احذف أي استدعاء لـ ui.dark_mode() — المحوِّل يتكفل بذلك. |
| Tailwind CSS v4 | adapters/tailwind.css |
@import "./<path>/ui-theme/adapters/tailwind.css"; بعد @import "tailwindcss";. يكشف عن bg-surface-2, text-fg, text-fg-muted, bg-accent, text-on-accent, border-line، إلخ. يستخدم النص fg-* لأن أحجام text-* تنتمي إلى Tailwind. |
| Tailwind CSS v3 | adapters/tailwind-v3.preset.js |
presets: [require('./<path>/ui-theme/adapters/tailwind-v3.preset.js')]. نفس الرموز كمحوِّل v4، معبّرة كإعداد مسبق (preset) من v3. |
يُحوِّل محوِّل Tailwind رموز السمة؛ ويحوِّل محوِّل Quasar فئات المكونات. لا يُطلب أي منهما لعمل بقية الحزمة.
مسار التثبيت الكامل (نصياً، الجزء المتعلق بالتثبيت من AGENTS.md)
AGENTS.md هو سكربت التثبيت بالكتابة، مكتوب لوكيل برمجة ذكاء اصطناعي. يُقتبس القسمان الأولان أدناه كاملاً؛ هذا هو الأمر (prompt) الذي سيُوجَّه إليه وكيل الذكاء الاصطناعي. تم ترميز الأحرف وفقاً لقاعدة §8 في مهارة article-forge (وسم <blockquote> الخام يشغّل markdown حرفياً، لذا يتم ترميز <، >، & إلى <، >، &).
## 1. قرّر مرة واحدة | السؤال | الإجابة الافتراضية | |---|---| | أين يذهب المجلد؟ | مجلد الملفات الثابتة للتطبيق، ويُقدَّم كما هو: `static/ui-theme/` (Flask, FastAPI, Django)، `public/ui-theme/` (Vite, Next.js, Create React App)، `app/static/ui-theme/`، أو بجانب `index.html` لموقع عادي. | | أي سمات؟ | السمات الأساسية الست: `purple,midnight-gold,glacier,forest,paper,daylight`. أضف سمة اختيارية (`night-red`, `electric-yellow`, `laserlloyd`, `laserlloyd-light`) فقط إذا طلب المستخدم ذلك. | | السمة الافتراضية؟ | `auto`: تابع إعداد الفاتح/الداكن في نظام تشغيل الزائر حتى يختار (`data-default-dark="midnight-gold"`, `data-default-light="daylight"`). | | مفتاح التخزين؟ | `<appname>.theme`، مثل `notes.theme`. | ## 2. التثبيت شغّل من المجلد الجذر للتطبيق (Python 3.9 أو أحدث؛ غيّر `static/ui-theme` إلى المجلد الذي اخترته):استخدم `python` (أو `py`) بدلاً من `python3` على Windows؛ السطر نفسه في PowerShell، cmd و bash. يقوم بتنزيل المثبّت، الذي يجلب أحدث إصدار من GitHub، ويتحقق من كل ملف مقابل قائمة التلخيصات (checksums) ويكتب المجلد. التحديثات اللاحقة هي `python3 static/ui-theme/update.py`. دون اتصال: حمّل أرشيف الإصدار (`.tar.gz`) في مكان آخر، ثم شغّل `python3 update.py --source <archive> --dest static/ui-theme` مع `update.py` من مجلده `ui-theme/`. طرق أخرى، إذا لم يتوفر Python: - **git:** `git clone --depth 1 https://github.com/LaserLloyd/ThemeForge.git ut-tmp`، انسخ `ut-tmp/ui-theme` إلى التطبيق، احذف `ut-tmp`. - **Node:** `npx degit LaserLloyd/ThemeForge/ui-theme#v1.0.0 static/ui-theme`. - **بدون تثبيت (نماذج أولية، ملفات HTML مفردة):** حمّل الملفات من jsDelivr، مثبّتة على إصدار: `https://cdn.jsdelivr.net/gh/LaserLloyd/ThemeForge@v1.0.0/ui-theme/ui-theme.js` (ونفس المسار لكل ملف CSS). لا تثبت `@main` أبداً؛ يخزّن CDN ذلك لمدة تصل إلى 12 ساعة. يتم تحديث صفحة CDN بتغيير الإصدار المثبت؛ `update.py` والخطوات 8.5، 9 و 10 أدناه لا تنطبق عليها.python3 -c "import urllib.request as u,sys;sys.argv=['update.py','--dest','static/ui-theme'];exec(u.urlopen('https://raw.githubusercontent.com/LaserLloyd/ThemeForge/main/ui-theme/update.py').read())"
تغطي بقية AGENTS.md (الأقسام 3–12) كتلة الرأس، قائمة الاختيار، البناء من الرموز، القواعد، الرسوم البيانية، التحقق، السطر الذي يُدرج في AGENTS.md الخاص بالتطبيق نفسه حتى يحافظ الوكيل التالي على الاتفاقية، أمر التحديث، جدول استكشاف الأخطاء وإصلاحها، وقائمة المراجع أعلاه.
تدقيق التباين (ملخص، كل سمة)
تشغّل tools/check_contrast.py في CI عند كل دفع (push). التقرير الكامل حجمه 124 ك.ب (قسم لكل سمة، بالإضافة إلى ملخص) في docs/contrast-report.md؛ الملخص هو:
| السمة | المجموعة | الملف | الفحوصات | الفشل |
|---|---|---|---|---|
| purple | أساسية | قياسي | 147 | 0 |
| midnight-gold | أساسية | قياسي | 147 | 0 |
| glacier | أساسية | قياسي | 147 | 0 |
| forest | أساسية | قياسي | 147 | 0 |
| paper | أساسية | قياسي | 147 | 0 |
| daylight | أساسية | قياسي | 147 | 0 |
| electric-yellow | اختيارية | قياسي | 147 | 0 |
| laserlloyd | اختيارية | قياسي | 147 | 0 |
| laserlloyd-light | اختيارية | قياسي | 147 | 0 |
| night-red | اختيارية | ليلي | 171 | 0 |
العقد الذي تستوفيه كل سمة: نص الجسم 7:1، النص الثانوي 6:1 (وعد العقد 6:1 في تقرير التباين — يحدد docs/contrast-report.md كل صف text-secondary on surface-2 بتلك الصياغة بالضبط)، كل مستوى نصي على كل سطح 4.5:1، المعطّل 3:1، على اللون المميز وعلى حالة الحالة 4.5:1، نص الحالة على خلفيته الملوّنة 4.5:1، على المحدد 4.5:1، المحدد / حدود غير المحدد / نص غير المحدد على كل سطح 3:1، الحدود القوية / مسار التحكم / حلقة التركيز 3:1، ألوان الصياغة على --syn-bg 4.5:1 (التعليقات 3.5:1)، وسلاسل الرسم البياني (--cat-1 … --cat-12) 3:1 على --surface-0. تشغيل/إيقاف بالشكل: عنصر تحكم "تشغيل" يكون مملوءاً بـ --selected؛ عنصر تحكم "إيقاف" يكون إطاراً بـ --unselected-border؛ مفتاح التبديل "تشغيل" يضيف شريطاً للمقبض، و"إيقاف" يضيف حلقة. المعطّل يكون متقطعاً وغير مملوء في مستوى التعطيل، حتى عند التشغيل.
أطر العمل (Frameworks)
وفقاً لخطة docs/INTEGRATIONS.md: HTML عادي · FastAPI, Flask, Starlette (قوالب Jinja) · Django · Vite, Vue, Svelte, SvelteKit, Astro · Next.js (موجّه التطبيق) · NiceGUI (Quasar) · Tailwind CSS · Electron, Tauri, pywebview · الخطوط · الرسوم البيانية · سياسة أمان المحتوى. لكل إطار عمل: ضع ui-theme/ حيث يقدّم الإطار الملفات الثابتة، وأضف كتلة الرأس بالترتيب الذي يحدده AGENTS.md §3، وقدّم المجلد بـ no-cache (أو أعطِ الروابط إصدارات) حتى يظهر التحديث. مثالان محدّدان موجودان في المستودع: examples/static-html/ (صفحة واحدة) و examples/fastapi-jinja/ (FastAPI + Jinja، app.py بحجم 2,172 بايت).
الطباعة، التباين والحركة
ثلاثة أشياء يستمع إليها وقت التشغيل وتستجيب لها أوراق الأنماط، دون علم (flag) لكل سمة:
- الطباعة — يتحكم
data-print-themeفي ما يُطبع (ui-theme.js:474-490): عندما يكون السمة النشطة داكنة أو OLED، فإنautoيبدّل إلى الشريك الفاتح للعائلة (أو أول سمة فاتحة مفعّلة، أوdaylight)؛ والطباعة باسم مُعرّف (slug) تطبع تلك السمة؛ وnoneلا يُجري تبديلاً. عندما تكون السمة النشطة فاتحة، تُطبع الصفحة كما هي. تُخفي الطباعة القائمة الجانبية، والإشعارات المنبثقة (toasts)، والقوائم، والدرج (drawers)، والتلميحات (tooltips). prefers-contrast: more— ترفع كل سمة خطوطها إلى قوة حافة التحكم (control-edge) ونصّها الثالثي إلى المستوى الثانوي.prefers-reduced-motion— يوقف الحلقات ويختصر الحركات؛ وتصبح رموز--motion-*صفرًا.
الإصدارات
من المستودع عند الرأس الذي تصفه هذه المقالة (نُسخ في 2026-10-05):
$ git log -1 --format='%h %ci'
56fb665 2026-10-05 21:46:52 +0900 # ThemeForge 1.0.0
$ cat ui-theme/VERSION
ThemeForge 1.0.0 3db64d9f574f
$ wc -c ui-theme/*.js ui-theme/*.css ui-theme/*.ts ui-theme/*.py 2>/dev/null
23515 ui-theme.js
5441 ui-components.js
2841 ui-theme.d.ts
16081 update.py
13255 ui-theme-base.css
51344 ui-components.css
86389 ui-theme.css
$ node --check ui-theme.js ui-components.js
(node v24.18.0) — OK on both, and on adapters/quasar.js + adapters/tailwind-v3.preset.js
$ python -m unittest discover -s tests
Ran 32 tests in 1.212s
OK (skipped=1)
$ python tools/check_contrast.py --fail-on any
…
## Summary
| Theme | Set | Profile | Checks | Failures |
| purple | core | standard | 147 | 0 |
| midnight-gold | core | standard | 147 | 0 |
| glacier | core | standard | 147 | 0 |
| forest | core | standard | 147 | 0 |
| paper | core | standard | 147 | 0 |
| daylight | core | standard | 147 | 0 |
| electric-yellow | opt-in | standard | 147 | 0 |
| laserlloyd | opt-in | standard | 147 | 0 |
| laserlloyd-light | opt-in | standard | 147 | 0 |
| night-red | opt-in | night | 171 | 0 |
الأهداف: Chrome وEdge وFirefox وSafari الحالية (إصدارات 2024 أو أحدث). يستخدم هذا الطبق :has() وcolor-mix() وواجهة popover؛ المتصفحات الأقدم تحتفظ بالألوان، لكن بعض حالات المكونات والقوائم تتدهور.
مرتبطة: ChatForge: مساعد ذكاء اصطناعي محلي على NPU لمفتاح Copilot · StudioForge: خادم LLM يعمل على GPU فقط · DisPatch: دردشة ذكاء اصطناعي مستضافة ذاتيًا · مكدس وكلاء الذكاء الاصطناعي المحلي لديّ · كيف تجعل نموذج LLM يكيّف أي مشروع مع نظامك
التنزيلات
مجاني للاستخدام الشخصي. إذا وفّر لك عصرًا كاملًا من الوقت، فزر القهوة قريب منك.