السمات
السمات الست والأربعون المدمجة، والترويسة ذات الأجواء، ومنشئ السمات المخصصة، ومتغيرات CSS التي يُرسم بها التطبيق، وملف custom.css.
إذا كان أسطرلاب يحل محل مدونتك فالأرجح أنك تريده أن يكفّ عن قول «Astrolabe» ويبدو موقعَك أنت. ثلاثة إعدادات تكفي لذلك، ولا يحتاج أيّ منها إلى تغيير الشيفرة.
سمّه
SITE_NAME=Night Garden يغيّر الاسم في كل مكان يظهر فيه: علامة ✦ في اللوحة الجانبية، وعناوين تبويبات المتصفح (Note · Night Garden)، ونافذة تسجيل الدخول.
اختر المظهر الافتراضي
السمة طقم ألوان كامل للتطبيق: خلفية الصفحة، والنص، ولون التمييز الذي تُرسم به الروابط والعلامات، ولون التحديد، وحلقة التركيز، والمخطط، وألوان التنبيهات الثلاثة عشر، وألوان تلوين الشيفرة الثمانية، ومقدار استدارة الزوايا. يأتي أسطرلاب مزوَّدًا بـست وأربعين سمة: اثنتين وثلاثين داكنة وأربع عشرة فاتحة. وكل واحدة منها تعرّف الطقم كله بنفسها، فليست أيّ منها مجرد سمة أخرى بخلفية مختلفة. أربع وعشرون منها لوحات ألوان معروفة تتفق عليها محررات الشيفرة والطرفيات أصلًا، بالأسماء التي يعرفها الناس بها ومن مواصفاتها المنشورة؛ وفي هذه تقف اللوحة الجانبية وشريط التبويبات واللوحات على الأرضية الأدكن التي تستخدمها محرراتها، فتبدو سمة Dracula دراكولا من أول نظرة. وGitHub Dark هي الافتراضية.
ونسمّي كل سمة غرفة، لأن هذا ما تشعر به حين تجلس فيها عصرًا كاملًا.

| داكنة | فاتحة | ||
|---|---|---|---|
github-dark | رماديات محايدة صلبة وأزرق سماوي؛ الافتراضية | github-light | أبيض نظيف وأزرق الروابط |
nord | رماديات زرقاء قطبية وسماوي ثلجي | catppuccin-latte | رمادي فاتح ناعم وموف |
dracula | ليل بنفسجي رمادي، بنفسجي ووردي | solarized-light | ورق كريمي وأزرق |
one-dark | رمادي أتوم وأزرق ناعم | gruvbox-light | كريمي دافئ وبرتقالي محروق |
tokyo-night | ليل أزرق عميق، أزرق نيون وبنفسجي | ayu-light | أبيض ساطع وأزرق |
catppuccin-mocha | بنفسجي داكن ناعم وموف باستيل | everforest-light | ورق دافئ وأخضر غابي |
gruvbox-dark | داكن دافئ قديم وبرتقالي | rose-pine-dawn | كريمي الفجر وأخضر الصنوبر |
solarized-dark | أسود مائل للزمردي وسماوي | ||
monokai | أسود زيتوني وأخضر ليموني | ||
material-ocean | كحلي شبه أسود وأزرق محيطي | ||
palenight | ليل نيلي هادئ وليلكي | ||
ayu-dark | داكن خالص وبرتقالي دافئ | ||
ayu-mirage | رمادي أزرق وأزرق سماوي | ||
everforest-dark | رمادي أخضر غابي وأخضر مريمي | ||
rose-pine | أسود بنفسجي مخملي وزنبقي | ||
night-owl | كحلي منتصف الليل وأزرق سماوي | ||
kanagawa | فحمي كالحبر المائي وأزرق الموج | ||
iron-gall | أسود دافئ، ورق ذهب | parchment | ورق دافئ، ورق ذهب |
cinnabar | غرافيت محايد، حرف زنجفري | sandstone | ورق صحراوي جاف، برتقالي محروق |
sumi | رمادي حبر، نيلي آيزومي | solar | أنصع ورق أبيض، ذهب محروق |
void | أسود خالص، سماوي إشارة بارد | linen | ضوء نهار بارد، أزرق حبر |
basalt | حجر رمادي مزرق بارد، سماء شاحبة | palimpsest | رقّ رمادي مكشوط، أحمر رُبريك |
nocturne | ليل أزرق مسوَدّ، بنفسجي فاتح | porcelain | أبيض مزجَّج، سيلادون عميق |
lapis | لازورد أزرق مسوَدّ، ذهب منوَّر | mauveine | ليلكي شاحب، بنفسجي أنيليني |
verdigris | أخضر مسوَدّ، نحاس مؤكسد | ||
moss | أرض غابة زيتونية مسوَدّة، أشنة | ||
porphyry | حجر بنفسجي مسوَدّ، وردي مغبر | ||
tallow | ورق بني دافئ، كهرمان لهب شمعة | ||
phosphor | أخضر مسوَدّ لشاشة CRT، أخضر فوسفور P1 | ||
sidereal | فضاء عميق أزرق بنفسجي، ضوء نجوم | ||
murex | بنفسجي مسوَدّ، أرجوان صوري | ||
graphite | رماديات محايدة صلبة (كـGitHub الداكن)، ورق ذهب؛ غرفة العلامة |
ستٌّ منها وصلت معًا، ورُسمت كل واحدة لتسدّ فراغًا كان في المجموعة:
phosphorطرفيةٌ حقيقية، لا سمة تلمّح إلى طرفية. وألوان شيفرتها هي هويتها. فلأنبوب الأشعة القديم مدفع إلكترونات واحد، تصير الكلمات المفتاحية والدوال والخصائص ثلاث درجات من الأخضر نفسه، وتصير أسماء الأنواع ذلك الأخضر مدفوعًا نحو السماوي، ولا يبقى من ألوان غير الأخضر إلا كهرمان أنبوب P3 (للنصوص والأرقام) وأحمر الإنذار.siderealالفضاء العميق من بعيد: أرضية زرقاء بنفسجية أدكن بكثير من أرضيةnocturne، تحت ضوء النجوم. ونص متنها فضّي محايد عمدًا. فضوء النجوم ونص المتن كلاهما أبيض مزرق شاحب، والتمييز الذي ليس إلا درجة من لون النص ليس تمييزًا (وهذه قاعدة 18 ΔE المشروحة أدناه). ويفصل بين الاثنين 29.6 ΔE.murexسُمّيت باسم حلزون البحر الذي كانت مدينة صور تسلقه بالأطنان لتصنع اللون الوحيد الذي يُسمح للإمبراطور أن يلبسه. وporphyryهي الأرجوان الإمبراطوري الآخر؛ وقد فُصل بين الاثنتين بـ39.6 ΔE في لون التمييز: وردي مغبر دافئ هناك، والصبغة بكامل قوتها هنا.palimpsestأقدم منparchment، وهذا هو المقصود: رقٌّ كُشط ثم كُتب فوقه من جديد، رمادي حيث الرق ذهبي، تحت الأحمر الذي كان الناسخ يكتب به العناوين. وهي أيضًا أول غرفة حمراء في المجموعة الفاتحة.porcelainسيلادون عصر سونغ: أرضية بيضاء مزجَّجة فيها نَفَس من الأخضر، تحت الأخضر البحري العميق الذي بُنيت من أجله أفران لونغتشوان. الغرفة المصقولة، وأول تمييز أخضر في المجموعة الفاتحة.mauveineالحادثة التي بدأت صناعة الأصباغ: في عام 1856 أخفق ويليام بيركن، وعمره ثمانية عشر عامًا، في تركيب الكينين، فغسل القارورة بالكحول، فإذا بالراسب البنفسجي فيها أول صبغة صناعية في التاريخ. ولم يكن في المجموعة الفاتحة بنفسجيٌّ قبل هذه.
يختار كل قارئ سمته من منتقي السمات. يفتحه زرّ السمة في شريط الحالة، ويفتحه كذلك الإعدادات ← المظهر ← سمتك. كل صف فيه نموذج مصغّر للغرفة (أرضيتها وعليها خط عنوان وسطر نص وشريحة تمييز) بجانب اسم مفهوم ووصف من سطر، كلاهما مترجم. أما المعرّف الخام، وهو ما يقبله DEFAULT_THEME ولوحة الأوامر، ففي تلميح الصف. والقائمة مجمَّعة وتُقاد بلوحة المفاتيح: ↑↓←→ تحرّك التمييز وتطبّق تلك السمة مباشرة على التطبيق كله خلف اللوحة، وEnter يبقيها، وEsc يعيد السمة التي بدأت بها. والفأرة لا تحرّك تمييز لوحة المفاتيح أبدًا؛ النقرة وحدها تختار. ولوحة الأوامر فيها طريق واحد بالضبط إلى السمات: السمات يفتح اللوحة نفسها، وعليها نقطة تعلّم السمة التي أنت فيها. (كانت تسرد فيما مضى أمر Theme: <id> لكل سمة، أي 15 من 41 مدخلًا في اللوحة مصروفة على تفضيل واحد، وكل منها قفزة عمياء إلى غرفة لم ترها. والإعداد الذي له كل هذه القيم مكانه خلف سطح يعرض تلك القيم.) ويُحفظ اختيار القارئ في متصفحه هو.
افتراضيًا يرتدي الموقع العام السمة التي تكتب بها. تختار غرفة في المنتقي، فيحطّ الزوار الجدد في الغرفة نفسها: مدونة كاتب واحد تشبه كاتبها، من غير أن تضبط شيئًا. سمتك محفوظة في متصفحك، لذلك ينسخها أسطرلاب إلى الخادم حين يستقر اختيارك (بعد ثانية من توقفك عن تقليب السمات، لا مرة مع كل صف). والمكانان اللذان يختاران سمة يقولان ذلك بوضوح، مسمّيَين السمة باسمها: تذييل المنتقي والإعدادات ← هوية الموقع ← السمة الافتراضية يقرآن «يرى الزوار Cinnabar، تبعًا لسمة محررك»، ومع كل منهما زر ثبّت هذه بدلًا منها بنقرة واحدة. ثبّت سمةً فيكفّ الموقع العام عن التحرك معك («يرى الزوار Parchment، مثبّتة»، ومعها اتبع سمتي للتراجع). وDEFAULT_THEME=cinnabar يثبّت بالطريقة نفسها من ملف البيئة، وDEFAULT_THEME=follow (أو الإعداد) يعيد الأمر إلى ما كان. ويُخزَّن تثبيتك وسمة محررك منفصلين، فإلغاء التثبيت يعيد الزوار إلى ما تستخدمه فعلًا. والقارئ الذي اختار سمة لنفسه لا يحرّكه شيء من هذا أبدًا. وDEFAULT_THEME المجهول يُتجاهَل، مع سطر على stderr عند بدء التشغيل لا في صمت.
راحة للعين
الغرفة الفاتحة ساطعة بطبيعتها، والشاشة الساطعة في آخر النهار مشكلة أخرى غير مشكلة السمة الخطأ. لذلك يوجد بجانب السمة منزلقان في الإعدادات ← المظهر يعملان فوق السمة التي أنت فيها بدل أن يستبدلاها:
- دفء الشاشة يفرش صبغة كهرمانية على الصفحة كلها، كما تفعل الإضاءة الليلية في الهاتف. فتأخذ الواجهة والملاحظة والحوارات وقارئ PDF كلها لون الورق تحت مصباح القراءة، ويذهب معها الأزرق الذي يُتعب العين. اسحب حتى تكفّ الصفحة عن الوهج: درجة بين 40 و60 تشبه ضوء مصباح، و100 تشبه ضوء شمعة.
- تعتيم الشاشة يعتّم الصفحة إلى ما دون أدنى درجة يبلغها زر السطوع في شاشتك، من أجل الشاشة التي تبقى أدنى درجاتها ساطعة في منتصف الليل. ويتوقف عند 70، لأن النص بعد ذلك سيخفت مع الوهج.
كلاهما يُطبَّق وأنت تسحب. وكلاهما خاص بالجهاز: لا يتزامنان مع أجهزتك الأخرى (فللهاتف إضاءته الليلية الخاصة)، ولا يُحفظان في الخزانة أبدًا، ولا يراهما زائر. وتحمل لوحة الأوامر دفّئ الشاشة وبرّد الشاشة لمن يريد مفتاحًا واحدًا: تقلب الدفء بين الإيقاف والمستوى الذي استعملته آخر مرة. ولا تُطبع أيٌّ من الصبغتين.
وإذا كان ما تريده غرفة دافئة لا صبغة دافئة، ففي النصف الفاتح من المنتقي أربع منها أصلًا: parchment وsandstone وpalimpsest وlinen بلون الورق من تصميمها، ومنزلق الدفء يتراكب فوق أي منها.
الترويسة ذات الأجواء
السمة طقم ألوان لا يتحرك، وهذا مقصود: فكل فحص في هذا المستودع يقيس تلك الألوان بعضها مع بعض، واللون الذي يتغير مع الوقت لون لم يلتقط أحد صورته في اللحظة التي أخفق فيها في اختبار التباين. لذلك تبقى الغرف ساكنة، وتكون الحركة طبقة منفصلة اختيارية من الزخرفة خلف الكلمات.
شغّلها من الإعدادات ← هوية الموقع ← أجواء الترويسة (أو "ambient": true في settings.json؛ وهي معطّلة افتراضيًا). عندها تحمل ترويسة الموقع العام، في المدونة الجاهزة والتخطيط المصمَّم سواء، جوًّا بطيئًا مرسومًا من السمة النافذة:
| الجو | الغرف | ما هو |
|---|---|---|
| نجوم | sidereal، nocturne، lapis، murex | حقلا نجوم بمقياسين وسرعتين مختلفين، البعيد يتنفس |
| خطوط مسح | phosphor، void | شبكة 3px تزحف بالضبط خطوة واحدة كل اثنتي عشرة ثانية، تحت توهج المدفع نفسه |
| غبار | iron-gall، tallow، parchment، palimpsest، solar | ذرات ذهبية تصعد، ببطء يكفي لأن يعرض النظر المباشر إليها صفحة ساكنة |
وكل غرفة أخرى ساكنة عمدًا: فلا تأخذ السمة جوًّا إلا إذا كان لديها ما تقوله به. وكل علامة في كل جو مرسومة بلون --accent الخاص بتلك الغرفة، فنجوم murex أرجوان صوري وغبار palimpsest أحمر رُبريك من غير قاعدة خاصة بهما.
وأربع خصائص تثبت مهما تغيّر غيرها:
- زخرفة لا محتوى. عنصر فارغ يحمل
aria-hiddenوpointer-events: noneعلىz-index: -1داخل ترويسة تحملisolation: isolate. لا يبلغه مؤشر ولا مؤشر كتابة ولا قارئ شاشة ولا مفتاح Tab. - CSS خالص. لا لوحة رسم، ولا
requestAnimationFrame، ولا JavaScript غير جملةifالواحدة التي تقرر هل العنصر موجود في الصفحة. والخاصيتان المتحركتان كلتاهما مما يستطيع المتصفح تحريكه على بطاقة الرسوميات. - همسة، وهذا قياس. ليست قيمة شفافية بل أسوأ أرضية فعلية تحت عنوان الترويسة، مقروءة من بكسلات حقيقية والحركة تعمل:
phosphor11.41:1، وmurex10.74:1، وsidereal9.63:1، وiron-gall9.08:1، وparchment8.31:1. والحد الأدنى 4.5. prefers-reduced-motionيحذفها. لا يوقفها ولا يبطئها، بلdisplay: noneعلى الحاوية، فلا تأخذ أيٌّ من الطبقتين صندوقًا ولا يُرسم شيء. ولقطتان بفارق 2.6 ثانية تعودان متطابقتين بايتًا بايت.
وتركب الشيفرة في ملفات التخطيطات العامة نفسها (client/styles/ambient.css)، فالنسخة التي أوقفتها، والحزمة الرئيسية التي ينزّلها كل زائر، لا تدفعان لها شيئًا.
اصنع سمتك
السمات المدمجة نقطة بداية لا سقف. السمات ← سمة مخصصة جديدة يفتح منشئًا. اختر إحدى السمات المدمجة أساسًا، ثم بدّل أي لون تشاء: الأرضيات، والنص، والعناوين، والتمييز، والحدود، وكل سطح على حدة (لوحة الملاحظات، وشريط التبويبات، وشريط الحالة، وصفحة المحرر، وصفحة القراءة، والحقول والأزرار، والحوارات، والموقع، والبطاقات؛ وتجد أيًّا منها بالاسم في حقل التصفية)، إضافة إلى ألوان التنبيهات الثلاثة عشر وألوان الشيفرة الثمانية والمخطط. ويتغير التطبيق كله خلف اللوحة وأنت تعمل، لأن المعاينة الصادقة الوحيدة للسمة هي السمة نفسها. والألوان التي لا تمسّها تظل تأتي من السمة الأساس، فأي تحسين لاحق على ذلك الأساس يصل إلى سمتك من غير جهد، وزرّ إعادة الضبط في كل صف يحذف تبديلك بدل أن يجمّد قيمة اليوم فيه.
ويشغّل المنشئ فحص التباين الخاص بالمشروع، مباشرة: الشيفرة نفسها التي يشغّلها scripts/check-contrast.mjs. يجب أن يكون نص المتن بتباين 4.5:1 على الأقل مع الأرضيات الثلاث والنص الثانوي بـ3:1 على الأقل؛ وأن يكون التمييز بـ4.5:1 على الأقل على أرضيته؛ وأن يبعد التمييز عن نص متنك 18 ΔE على الأقل. (ΔE مقياس لمدى اختلاف لونين في عين الإنسان. وهذه القاعدة الأخيرة ليست نسبة تباين: فالسمة التي تمييزها مجرد درجة من لون نصها لا تمييز فيها أصلًا.) وتظهر التحذيرات كلمات، فوق عنصر التحكم الذي سببها، مع علامة على أي مجموعة فيها تحذير.
احفظ السمة باسم فتصير قابلة للاختيار في كل مكان تُختار فيه سمة مدمجة: المنتقي (في مجموعة «سماتك» الخاصة بها)، وزر ☾/☀، والإعدادات ← هوية الموقع ← السمة الافتراضية، وDEFAULT_THEME=custom:<name> في ملفك .env. وصدّرها بصيغة JSON، وأرسلها بالبريد، واستوردها في نسخة أخرى.
أعد تنسيقه
ضع ملفًا اسمه custom.css في مجلد بياناتك (ASTROLABE_DATA، وقيمته الافتراضية ./data/). يقدّمه أسطرلاب على /api/custom.css ويحمّله بعد أوراق أنماطه هو، لكل زائر ولك، في التطوير والإنتاج، بلا إعادة بناء ولا إعادة تشغيل. ولأنه يُحمَّل أخيرًا تغلب قواعدك. والواجهة كلها مرسومة بخصائص CSS مخصصة (متغيرات) على :root، مع تبديلات لكل سمة تحت html[data-theme="…"]، فمعظم إعادات التنسيق حفنة أسطر:
/* data/custom.css: غرفة قراءة بتمييز أخضر */
:root,
html[data-theme="lapis"] {
--accent: #5da06b;
--accent-soft: rgba(93, 160, 107, 0.14);
--font-serif: "Iowan Old Style", Georgia, serif;
}
لاسم الموقع ولشعاره النصي صنف CSS واحد لكل منهما، أينما ظهرا. .s-site-name على اسم الموقع في الترويسة فوق كل مقالة وعلى صدارة الصفحة الرئيسية معًا، و.s-site-tagline على الشعارين النصيين كليهما، فالقاعدة التي تُكتب مرة تصل إلى الاثنين:
/* data/custom.css: علامة كوفية حيثما سمّى الموقع نفسه */
.s-site-name { font-family: "Reem Kufi", var(--font-serif); font-weight: 600; }
.s-site-tagline { letter-spacing: 0.35em; text-transform: lowercase; }
والمتغيرات (اضبطها على :root لكل السمات، أو تحت html[data-theme="void"] ونحوه لسمة واحدة):
| الرمز | يقود |
|---|---|
--bg / --bg-raised / --bg-hover | خلفية الصفحة / اللوحة الجانبية واللوحات / صفوف التحويم |
--text / --text-muted / --text-faint | نص المتن / النص الثانوي / التلميحات والأعداد |
--heading | كل عنوان: عناوين المحرر وعرض القراءة وعنوان المقالة في المدونة وعناوين صفحات المكتبة. كل سمة مدمجة تضبطه درجة نحو تمييزها؛ والسمة المخصصة تضبطه مباشرة |
--accent / --accent-soft | لون العلامة (الروابط وروابط الويكي والعلامات النشطة) / غسلته الشفافة |
--selection-bg / --focus-ring | غسلة تحديد النص / حلقة :focus-visible بسمك 2px |
--graph-node / --graph-edge / --graph-vignette | لون قرص المخطط / خط الحافة الخامل / غسلة حافة لوحة الرسم |
--border | الخطوط الرفيعة 1px في كل مكان |
--danger | الإجراءات المدمرة، وصبغة الرابط المكسور |
--font-ui / --font-serif / --font-mono | قشرة الواجهة / النثر والعناوين / الشيفرة |
--font-base | حجم الحرف الجذري؛ الواجهة كلها مقاسة بـrem، فهذا الرمز الواحد يقيس القشرة كلها (الافتراضي 15.5px) |
--font-prose | حجم نثر المحرر / القراءة (الافتراضي ≈18px؛ متن مقالة المدونة درجة فوقه) |
--radius | استدارة الزوايا (الافتراضي 6px) |
--sidebar-w | عرض اللوحة الجانبية (الافتراضي 292px) |
--callout-note، --callout-tip، … | ألوان التنبيهات لكل نوع (انظر client/styles/tokens.css) |
--syn-keyword، --syn-string، … | لوحة تلوين الشيفرة |
طبقة الأسطح. كل ما سبق متغيرات أساس. وكانت الواجهة تقرؤها مباشرة، فلم تكن السمة تستطيع إعادة تلوين لوحتها الجانبية من غير إعادة تلوين كل سطح مرفوع معها. أما الآن فلكل شيء مرسوم متغير خاص به، معرَّف على :root, [data-theme] مشتقًّا من متغير أساس (--sidebar-bg: var(--bg-raised)). وهذا يعني شيئين معًا: متغير الأساس الذي تغيّره ما زال يسري في كل سطح لم تمسّه، والسطح الذي تضبطه يتحرك وحده. ويسردها المنشئ كلها بأسماء مفهومة باللغتين، مع حقل تصفية فوق الصفوف وإعادة ضبط لكل مجموعة؛ ويستطيع custom.css ضبط أي منها بالاسم. ويُقاس النص على أرضيته كما تُقاس أزواج الأساس: --sidebar-text على --sidebar-bg بنسبة 4.5:1، والنص الثانوي بنسبة 3:1، ويقول المنشئ ذلك بالكلمات حين يخفق زوج. أما أحبار التظليل الستة فليست هنا عمدًا: فالتظليل الذي يتغير لونه مع السمة فقدانٌ للبيانات لا سمة.
| السطح | الرموز (يتبع كل منها الأساس بين قوسين حتى تضبطه) |
|---|---|
| اللوحة الجانبية | --sidebar-bg (var(--bg-raised)), --sidebar-text (var(--text)), --sidebar-muted (var(--text-muted)), --sidebar-border (var(--border)), --sidebar-hover-bg (var(--bg-hover)), --sidebar-active-bg (var(--accent-soft)), --sidebar-active-bar (var(--accent)), --sidebar-search-bg (var(--bg)), --tagpill-bg (var(--bg-hover)), --tagpill-text (var(--text-muted)) |
| التبويبات واللوحات | --tabs-bg (var(--bg-raised)), --tabs-border (var(--border)), --tab-text (var(--text-muted)), --tab-hover-bg (var(--bg-hover)), --tab-active-bg (var(--bg)), --tab-active-text (var(--text)), --tab-active-bar (var(--accent)), --panel-bg (var(--bg-raised)), --panel-text (var(--text)), --panel-heading (var(--text-faint)), --panel-border (var(--border)) |
| شريط الحالة | --statusbar-bg (var(--bg-raised)), --statusbar-text (var(--text-muted)), --statusbar-border (var(--border)) |
| المحرر والشيفرة | --editor-bg (var(--bg)), --editor-text (var(--text)), --editor-caret (var(--accent)), --editor-panel-bg (var(--bg-raised)), --codeblock-bg (var(--bg-raised)), --codeblock-text (var(--text)), --inline-code-bg (var(--bg-raised)), --inline-code-text (var(--text)), --code-border (var(--border)) |
| القراءة | --reading-bg (var(--bg)), --reading-text (var(--text)), --quote-bar (var(--accent)), --quote-text (var(--text-muted)), --highlight-bg, --hr (var(--accent)), --list-bullet (var(--accent)), --table-border (var(--border)), --table-head-bg (var(--bg-raised)), --table-head-text (var(--text-muted)), --props-bg (var(--bg-raised)), --footnote-marker (var(--accent)) |
| الروابط والوسوم | --link (var(--accent)), --wikilink (var(--accent)), --wikilink-broken, --tag-bg (var(--accent-soft)), --tag-text (var(--accent)) |
| عناصر التحكم | --button-text (var(--text)), --button-hover-bg (var(--bg-hover)), --button-accent-bg (var(--accent-soft)), --button-accent-text (var(--accent)), --input-bg (var(--bg)), --input-text (var(--text)), --input-border (var(--border)), --input-placeholder (var(--text-faint)), --input-focus (var(--accent)), --menu-bg (var(--bg-raised)), --menu-text (var(--text)), --menu-hover-bg (var(--accent-soft)) |
| الحوارات والتنبيهات | --modal-bg (var(--bg-raised)), --modal-text (var(--text)), --modal-border (var(--border)), --backdrop, --toast-bg (var(--bg-raised)), --toast-text (var(--text)), --toast-bar (var(--accent)), --scrollbar-thumb (var(--border)), --scrollbar-thumb-hover (var(--text-faint)) |
| المخطط | --graph-bg (var(--bg)) |
| الموقع | --blog-bg (var(--bg)), --blog-text (var(--text)), --blog-mast-text (var(--text)), --blog-mast-tagline (var(--text-muted)), --blog-mast-star (var(--accent)), --blog-nav-text (var(--text-muted)), --blog-nav-hover-bg (var(--bg-hover)), --blog-nav-active-bg (var(--accent-soft)), --blog-nav-active-text (var(--accent)) |
| البطاقات والأشرطة | --card-bg (var(--bg-raised)), --card-text (var(--text)), --card-border (var(--border)), --card-hover-border (var(--accent)), --progress-track (var(--bg-hover)), --progress-fill (var(--accent)) |
أحضر خطوطك (طريق CSS)
لا يأتي أسطرلاب بخطوط ويب من عنده، وهذا مقصود، لكن نسختك تستطيع أن تحمل خطوطًا. ضع ملفات الخطوط في ASTROLABE_DATA/fonts/ (وقيمته الافتراضية ./data/fonts/) فتُقدَّم على /api/fonts/<file>: صيغ woff2 وwoff وttf وotf فقط، وباسم الملف وحده، مع ETags وترويسة تخزين ثابتة لسنة كاملة. ثم سمّها في قاعدة @font-face داخل custom.css:
/* data/custom.css: قدّم data/fonts/MyFont.woff2 خطًّا للنثر */
@font-face {
font-family: "MyFont";
src: url("/api/fonts/MyFont.woff2") format("woff2");
font-display: swap;
}
:root {
--font-serif: "MyFont", Georgia, serif;
}
وإن كنت تفضّل ألا تكتب CSS، فهناك كتالوج خطوط منتقاة تُقدَّم من خادمك أنت، ورافع للخطوط، وكلاهما يدعم العربية دعمًا صحيحًا: انظر الخطوط.
وكل ما وراء المتغيرات مباح أيضًا. فكل عنصر يحمل صنفًا ثابتًا يبدأ بـs- (.s-sidebar و.s-rv-p و.s-statusbar…)، فيستطيع custom.css إعادة تنسيق أجزاء بعينها من الواجهة. وما دام نص المتن بتباين 4.5:1 أو أفضل مع --bg بقي التطبيق كله مقروءًا.
نص ملوّن على مستويين
يمكنك تلوين مقطع من النص في ملاحظة بطريقتين. الطريقة الافتراضية تكتب var(--vc-blue): أي معنى («أزرق») تحوّله كل سمة مدمجة إلى لون حقيقي يجتاز اختبار التباين AA على أرضيتها، فاتحةً كانت أو داكنة. والطريقة الثانية، لوحة الحبر الثابت، تكتب قيمة hex حرفية حين تقصد ذلك اللون بعينه. وتُعرض الطريقتان بالتطابق في المحرر وعرض القراءة والمدونة، ولا يقبل المنظِّف style على <span> إلا لـcolor وbackground-color: لا url() ولا خصائص أخرى.
والمستويان موجودان لسبب يمكنك حسابه. فمقابل #050508 في void يحتاج اللون إلى إضاءة نسبية لا تقل عن 0.186، ومقابل #ffffff في solar يحتاج إلى ما لا يزيد على 0.183، وعليه لا يستطيع لون واحد أن يجتاز AA على كل سمة. يحمل المستوى المراعي للسمة (var(--vc-*)، وهو الافتراضي) قيمة واحدة لكل مجموعة سمات ويُلزَم بـ4.5:1 مقابل كل أرضية في مجموعته؛ وأسوأ قياس له 4.98:1 على أرضية palimpsest، التي أخذت هذا اللقب من أبيض solar يوم صدورها. أما مستوى الحبر الثابت فيحمل قيمة hex واحدة لكل السمات ويُلزَم بـ3:1، وهو الحد الذي يضعه WCAG 1.4.11 للعناصر غير النصية، وهو أقصى ما يستطيع لون ثابت أن يعد به. وnode scripts/check-contrast.mjs يفحص الاثنين؛ انظر التطوير.