الوحدة 9 — السمة والمظهر وسهولة الاستخدام
الوحدات السابقة بنت تطبيقًا يعمل. هذه الوحدة تجعله يبدو كأنّه لفريقك، لا كأنّه عرض توضيحيّ. سنتناول التهيئة، والألوان، والشعار، ورسائل المساعدة، والترتيب البصريّ للأفعال، والانتقال إلى تطبيق متعدّد الصفحات. كلّ هذا لا يستغرق أكثر من ساعة، ويصنع فرقًا هائلًا في تبنّي الفريق.
ملفّ التهيئة config.toml
Streamlit يقرأ .streamlit/config.toml في مسار المشروع (أو ~/.streamlit/config.toml عالميًّا). هذا الملفّ يجمع الإعدادات: السمة، الخادم، التسجيل، الحدود.
[theme]
primaryColor = "#0F62FE"
backgroundColor = "#FFFFFF"
secondaryBackgroundColor = "#F4F4F4"
textColor = "#161616"
font = "sans serif"
[server]
port = 8501
maxUploadSize = 20
enableCORS = false
[browser]
gatherUsageStats = false
خمس نقاط على كلّ قسم. الألوان الأربع تُشكِّل السمة كاملة: أساسيّة (الأزرار، الروابط)، خلفيّة، خلفيّة ثانويّة (الشريط الجانبيّ، الحاويات)، نصّ. اختيار مدروس لهذه الأربع يعطي هويّة بصريّة كاملة. الخطّ يقبل sans serif، serif، أو monospace. maxUploadSize بالميغابايت (الوحدة 7). enableCORS = false يزيد أمن التطبيقات المُنشرة. gatherUsageStats = false يوقف إرسال إحصائيّات مجهولة إلى Streamlit.
الأوضاع الفاتحة والداكنة
Streamlit يحترم تفضيلات النظام (prefers-color-scheme) افتراضيًّا. لتوفير سمتَين، config.toml يقبل قسمًا [theme.dark] (منذ 1.30):
[theme]
primaryColor = "#0F62FE"
backgroundColor = "#FFFFFF"
secondaryBackgroundColor = "#F4F4F4"
textColor = "#161616"
base = "light"
[theme.dark]
primaryColor = "#78A9FF"
backgroundColor = "#161616"
secondaryBackgroundColor = "#262626"
textColor = "#F4F4F4"
المستخدم يبدّل من قائمة Streamlit (زاوية أعلى يمين). حين لا تُصرَّح السمة الداكنة، Streamlit يستنتج ألوانًا تلقائيّة قد لا تتوافق مع هويّتك.
الشعار
st.logo يعرض شعارًا في أعلى الشريط الجانبيّ. يستقبل مسارًا أو رابطًا:
import streamlit as st
st.logo(
"assets/logo_entreprise.svg",
link="https://entreprise.com",
icon_image="assets/logo_petit.svg", # للجوّال حين يُطوى الشريط
)
قاعدة عمليّة: شعار SVG (يتكيّف مع الحجم بلا فقدان جودة)، بارتفاع 40 إلى 60 بكسل، بلا نصّ داخل الصورة (يُصعّب التعريب). الشعار مع نصّ يعمل باللغة الأصليّة فقط؛ في تطبيق ثنائيّ اللغة، رمز مجرَّد أفضل.
أيقونة الصفحة والعنوان
st.set_page_config يقبل عدّة معلمات لهويّة التبويب:
st.set_page_config(
page_title="لوحة قيادة ترك العملاء",
page_icon=":telephone:", # أو رمز تعبيريّ أو صورة
layout="wide",
initial_sidebar_state="expanded",
menu_items={
"Get help": "https://docs.entreprise.com/churn",
"Report a bug": "mailto:support@entreprise.com",
"About": "لوحة قيادة داخليّة v1.2. © 2026 الشركة.",
},
)
menu_items يضبط قائمة «⋮» في أعلى اليمين. مفيد لإخفاء عناصر لا فائدة لها للمستخدم النهائيّ («تسجيل خطأ»، «حول») بتخصيصها.
رسائل المساعدة (help)
كلّ مكوّن يقبل معلمة help="..." تعرض تلميحًا عند التحويم:
seuil = st.slider(
"عتبة الخطر", 0.0, 1.0, 0.5, 0.05,
help="العميل يُصنَّف بخطر إن كانت درجته أعلى من هذه العتبة. القيمة الافتراضيّة 0.5 مأخوذة من التقييم عل ى 2024.",
)
st.number_input(
"المبلغ الشهريّ (USD)",
help="بدون رسوم ولا خصومات. للفواتير المُختلَطة، أدخل المتوسّط.",
)
قاعدة تصميم: رسالة المساعدة تُفسِّر «لماذا» و«ما القيمة الافتراضيّة»، لا تكرّر ما هو مكتوب في العنوان. رسائل مساعدة سيّئة («المعرّف: أدخل معرّف العميل») تُلوّث الواجهة بلا فائدة. رسائل جيّدة تُقلّل نصف أسئلة الدعم.
ترتيب الأفعال والقواعد الصريحة
مبدأ سهولة الاستخدام الأهمّ: ترتّب الأفعال يعكس مسار المستخدم. من اليسار إلى اليمين في LTR (يمين إلى يسار في RTL): بيانات → إجراء → نتيجة.
col_gauche, col_centre, col_droite = st.columns([2, 1, 2])
with col_gauche:
st.subheader("١. البيانات")
identifiant = st.text_input("المعرّف")
# ... حقول أخرى
with col_centre:
st.subheader("٢. الفعل")
if st.button("سجّل", type="primary", use_container_width=True):
st.session_state.calcul_effectue = True
with col_droite:
st.subheader("٣. النتيجة")
if st.session_state.get("calcul_effectue"):
st.metric("الدرجة", "0.72")
st.warning("عميل بخطر")
else:
st.caption("النتيجة ستظهر بعد التسجيل.")
type="primary" يجعل الزرّ ملوَّنًا بلون السمة الأساسيّ، بارزًا. use_container_width=True يمدّه على عرض العمود. type="secondary" (الافتراضيّ) للأزرار الثانويّة (إلغاء، تراجع).
التطبيق متعدّد الصفحات
عند تجاوز التطبيق حجم 500 سطر، تقسيمه إلى صفحات يُحسِّن القراءة والصيانة. Streamlit يدعم ذلك بنمطَين.
النمط الأوّل (الأبسط): مجلّد pages/ بجوار app.py. كلّ ملفّ Python فيه يُصبح صفحة تلقائيًّا:
app.py # الصفحة الرئيسيّة
pages/
1_scoring_unique.py
2_scoring_lot.py
3_historique.py
4_parametres.py
الرقم في البداية يضبط الترتيب. الأنشط يظهر بشرطة سفليّة كمسافة في القائمة. لا حاجة لتصريح شيء في app.py؛ Streamlit يكتشف الملفّات ويعرضها في الشريط الجانبيّ.
النمط الثاني (الأمرن): st.navigation مع st.Page (منذ 1.36):
import streamlit as st
pages = {
"التسجيل": [
st.Page("pages/scoring_unique.py", title="عميل واحد", icon=":material/person:"),
st.Page("pages/scoring_lot.py", title="دفعة", icon=":material/group:"),
],
"الإدارة": [
st.Page("pages/historique.py", title="السجلّ"),
st.Page("pages/parametres.py", title="الإعدادات"),
],
}
pg = st.navigation(pages)
pg.run()
الفوائد: تجميع الصفحات في أقسام، أيقونات، إخفاء ديناميكيّ (يمكن استبعاد صفحة حسب صلاحيّات المستخدم).
القراءة العربيّة الرشيقة
بعد الوحدة 3، عرفنا أساس RTL. هنا نُضيف تفاصيل تصنع الفرق:
الأرقام: Streamlit يعرض الأرقام العربيّة الغربيّة (0-9) افتراضيًّا. لتحويلها إلى العربيّة-الهنديّة (٠-٩)، استعمل format صريحًا أو حوّل قبل العرض:
def en_chiffres_arabes(n):
return str(n).translate(str.maketrans("0123456789", "٠١٢٣٤٥٦٧٨٩"))
st.metric("عدد العملاء", en_chiffres_arabes(2108))
القرار حسب الجمهور: فرق تقنيّة تفضّل الأرقام الغربيّة (أوضح مع الأدوات الأخرى)، جمهور واسع قد يفضّل الهنديّة.
التواريخ: st.date_input يعرض تقويمًا بلغة المتصفّح؛ للعربيّة تحتاج تخصيصًا. الحلّ العمليّ: عرض التقويم بلغته الأصليّة (إنجليزيّة عادةً)، ثمّ عرض النتيجة بصيغة عربيّة (fichier.strftime("%d %B %Y") مع تعيين محلّيّ ar_MA مثلًا).
الخطوط: Streamlit الافتراضيّة لا تدعم كلّ الخطوط العربيّة الأنيقة. لخطّ محدَّد (Noto Naskh Arabic، Amiri)، حقن CSS:
st.markdown("""
<style>
@import url('https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic:wght@400;700&display=swap');
html, body, [class*="st-"] { font-family: 'Noto Naskh Arabic', sans-serif; }
</style>
""", unsafe_allow_html=True)
التصميم للجوّال
Streamlit يعمل على الجوّال، لكنّه ليس مُحسَّنًا له. قواعد عمليّة:
- الشريط الجانبيّ يُطوى تلقائيًّا؛ لا تضع فيه أزرار الأفعال الرئيسيّة.
st.columnsمع نسبة[1, 1, 1, 1]تُصبح غير مقروءة على 375 بكسل.- الجداول العريضة تحتاج
use_container_width=Trueأوst.dataframe(height=...)صريح.
اختبار سريع: افتح التطبيق على متصفّح، صغِّر النافذة إلى 400 بكسل، وتنقّل. ما يصعب استعماله على شاشة صغيرة يصعب على الجوّال بالمثل.
لا تُقدِّر سهولة الاستخدام من كرسيّك. اجلس بجانب مستخدم فعليّ (فريق مبيعات هنا)، اسأله «أرِني كيف تُسجّل عميلًا»، ولا تتدخّل. ما يتردّد فيه، ما يبحث عنه، ما يكرّره — تلك هي المشاكل الحقيقيّة. عشر دقائق من الملاحظة الصامتة تكشف أكثر ممّا يمكن أن تفكّر فيه وحدك في ساعة.
الخلاصة
.streamlit/config.tomlيضبط السمة، الخادم، الحدود. الألوان الأربع كافية لهويّة بصريّة كاملة.st.logoللشعار،st.set_page_config(menu_items=...)لتخصيص القائمة،help="..."لتلميحات المساعدة.- ترتيب الأفعال: بيانات → فعل → نتيجة، مع
type="primary"للفعل الأساسيّ. - التطبيق متعدّد الصفحات: مجلّد
pages/أوst.navigation(st.Page(...))للأمرن. - العربيّة الرشيقة: أرقام حسب الجمهور، خطوط محقونة بـCSS، تصميم يتحمّل الجوّال.
الوحدة التالية: النشر والتحكّم في الوصول لجعل هذا التطبيق متاحًا فعليًّا للفريق.