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) حتى تكون الصفحة المطبوعة مقروءة على الورق؛ اطبع مظهرًا فاتحًا وستُطبع الصفحة كما هي.

ملاحظات

الوارد

3 ملاحظات، 1 غير مقروءة

مراجعة ربع سنوية مثبّتة

مسودة مراجعة الربع الثالث — أبحث عن مثالين إضافيين قبل يوم الجمعة.

قائمة حزم السفر

جواز السفر، الشاحن، المصباح الصغير.

هيكل تطبيق مبني من 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> وأسكِت قاعدة lint no-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 حرفياً، لذا يتم ترميز <، >، & إلى &lt;، &gt;، &amp;).

## 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` إلى المجلد
الذي اخترته):


python3 -c &quot;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())&quot;
استخدم `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 أدناه لا تنطبق عليها.

تغطي بقية 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 يكيّف أي مشروع مع نظامك

التنزيلات

مجاني للاستخدام الشخصي. إذا وفّر لك عصرًا كاملًا من الوقت، فزر القهوة قريب منك.


← المزيد من الذكاء الاصطناعي والنماذج المحلية