مساعدات التفضيلات
سبع حزم صغيرة لكل إطار عمل، تملك كل منها مهمة مستخدم واحدة من البداية إلى النهاية، مع شريط يجمع خمسًا منها. سبق أن عرفت theme-picker؛ وهذه locale-picker وtext-size-picker وmotion-picker (التفضيلات)، وshare-picker وsearch-picker (الإجراءات)، وdate-time-picker (قيمة نموذج)، وpicker-bar.
ما الذي ستبنيه
لوحة إعدادات يختار فيها المستخدمون لغتهم وحجم النص — اختيارات تُطبَّق على المستند كله وتبقى بين الزيارات وتكلفك مكوّنين وبضعة أسطر من CSS. نحو 15 دقيقة.
قبل أن تبدأ
أنهِ أولًا دليل إطار العمل لمجموعتك التقنية. الأمثلة أدناه بـ Svelte؛ ومساعدات React وVue وAngular وHTML وNunjucks وBlazor تطابقها عقدًا بعقد.
الشكل الذي يتشاركونه
- زر أيقونة عديم الرأس يفتح قائمة WAI-ARIA APG (أو، في date-time-picker، مربع حوار لاختيار التاريخ) — بلا عنصر
<select>أصلي، فيحصل كل إطار على سلوك لوحة المفاتيح وخطّافات التنسيق نفسها. - خطّاف صنف واحد لكل حزمة (
.locale-picker,.text-size-picker,.share-picker,.date-time-picker)، وصفر CSS مشحون. - آمن لـ SSR: تحدث كتابات DOM فقط في دورة حياة mount/effect.
- نظيف لـ i18n: كل سلسلة يراها المستخدم هي prop.
- متاح لـ Svelte (المرجعي) وReact وVue وAngular وعنصر HTML مخصص وNunjucks وBlazor — بالعقد نفسه في كل منها.
يملك theme-picker وlocale-picker وtext-size-picker كلٌّ
تفضيلًا واحدًا للمستخدم من البداية إلى النهاية (الاختيار، والتطبيق على DOM، و
localStorage الثبات الاختياري عبر الخاصية storageKey
). أما share-picker وdate-time-picker فمختلفان في النوع: يملك share-picker إجراءً — لا يطبّق شيئًا على المستند ولا يحفظ شيئًا — ويملك date-time-picker
قيمة نموذج، لأن التاريخ في النموذج بيانات لا تفضيل.
locale-picker — اللغة والاتجاه
يتيح للمستخدم اختيار لغة محلية، ثم يكتب lang و
dir على جذر المستند لتتبعه مكتبة i18n وCSS والتقنيات المساعدة جميعها. يُكتشف RTL تلقائيًا للعربية والعبرية وغيرهما من الكتابات من اليمين إلى اليسار. يركّز على الإشارة فقط — أما الترجمة فتتولاها مكتبة i18n لديك.
<script>
import LocalePicker from "@lilydesignsystem/svelte-locale-picker";
let locale = $state("en-US");
</script>
<LocalePicker
label="Language"
locales={["en-US", "fr", "ar", "he", "ja"]}
bind:value={locale}
storageKey="my-app-locale"
/>
تُسمّى الخيارات من جدول مدمج لأسماء اللغات المحلية (يمكن تجاوزه عبر localeLabels)، ويحمل كل خيار سمة
lang الخاصة به لينطق قارئ الشاشة «Français» بالفرنسية، وتُحوَّل الرموز ذات الشرطة السفلية مثل en_US
إلى BCP 47 وبالعكس دون فقد en-US. اربط
onChange (أو القيمة المربوطة) بـ i18next أو Paraglide أو vue-i18n أو أي شيء تستخدمه.
text-size-picker — حجم يتحكم به القارئ
مكسب في إمكانية الوصول يستغرق دقائق: يضبط المساعد
data-text-size="{slug}" على جذر المستند ويربط CSS لديك كل قيمة بحجم.
<script>
import TextSizePicker from "@lilydesignsystem/svelte-text-size-picker";
</script>
<TextSizePicker
label="Text size"
sizes={["small", "medium", "large", "x-large"]}
storageKey="my-app-text-size"
/>
:root[data-text-size="small"] { font-size: 87.5%; }
:root[data-text-size="medium"] { font-size: 100%; }
:root[data-text-size="large"] { font-size: 112.5%; }
:root[data-text-size="x-large"] { font-size: 125%; }
اضبط تخطيطك بوحدة rem فيتدرّج التطبيق كله مع اختيار المستخدم. تُشتق التسميات من المعرّفات بحرف أول كبير («X Large») أو تُتجاوز بـ sizeLabels.
تحقق من عملك: اختر «Large» من المنتقي فيكبر نص الصفحة. أعد التحميل — ما زال كبيرًا: حُفظ الاختيار في
localStorage. بدّل منتقي اللغة إلى العربية فيُضبط
dir="rtl" على المستند تلقائيًا.
share-picker — أرسل هذه الصفحة
زر برمز واحد يفتح ورقة المشاركة الأصلية للجهاز حيثما وُجدت، وإلا يعود إلى قائمة وجهات تقدّمها أنت، مع إجراء نسخ الرابط. لا يشحن أي عناوين لشبكات اجتماعية — أي الشبكات تناسب منتجك قرارك أنت لا قرار نظام التصميم.
<script>
import SharePicker from "@lilydesignsystem/svelte-share-picker";
const targets = [
{ id: "mastodon", label: "Mastodon",
href: (url, title) => `https://mastodon.social/share?text=${encodeURIComponent(title)}%20${encodeURIComponent(url)}` },
{ id: "email", label: "Email",
href: (url, title) => `mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(url)}`, newTab: false },
];
</script>
<SharePicker
label="Share this page"
title="An article worth reading"
{targets}
copyLabel="Copy link"
copiedLabel="Link copied"
/>
url افتراضيه location.hrefفلا تحتاج الحالة الشائعة إلى أي توصيل. افرض مسارًا بـ strategy="list" أو
strategy="native" حين تحتاج إلى سلوك متسق عبر المنصات للاختبارات أو لقطات الشاشة.
date-time-picker — تاريخ أو وقت أو كلاهما
حقل نصي يمكنك الكتابة فيه، مع زر أيقونة يفتح مربع حوار اختيار التاريخ وفق WAI-ARIA APG. صحيح لغويًا بالبناء — أسماء الأشهر وأيام الأسبوع وأول يوم في الأسبوع ونظام الساعة 12 أو 24 كلها تأتي من Intl — والقيمة دائمًا سلسلة ISO قابلة للفرز وبلا منطقة زمنية: "2026-03-15" لـ
mode="date", "09:30" لـ
mode="time", "2026-03-15T09:30" لـ
mode="datetime".
<script>
import DateTimePicker from "@lilydesignsystem/svelte-date-time-picker";
let appointment = $state("");
</script>
<DateTimePicker
inputId="appointment"
name="appointment"
label="Choose an appointment date"
locale="en-GB"
bind:value={appointment}
labels={{
previousYear: "Previous year",
previousMonth: "Previous month",
nextMonth: "Next month",
nextYear: "Next year",
confirm: "OK",
cancel: "Cancel",
}}
/>
قيمة ISO مطابقة لما يرسله <input type="date">
فيمكنك تبديل عنصر التحكم الأصلي دخولًا وخروجًا دون المساس بالواجهة الخلفية.
motion-picker — احترم الحركة المخفَّضة
يضبط المساعد data-motion="{slug}" على جذر المستند. تأتي قيمته الأولى من إعداد
prefers-reduced-motion نظام تشغيل الزائر — دائمًا، دون علَم اشتراك، لأن الحركة حاجة حقيقية لإمكانية الوصول (WCAG 2.3.3). يقرر CSS لديك وبرامجك النصية ما يُكبَح.
<script>
import MotionPicker from "@lilydesignsystem/svelte-motion-picker";
</script>
<MotionPicker
label="Motion"
motions={["no-preference", "reduce"]}
storageKey="my-app-motion"
/>
:root[data-motion="reduce"] *,
:root[data-motion="reduce"] *::before,
:root[data-motion="reduce"] *::after {
animation: none !important;
transition: none !important;
scroll-behavior: auto !important;
}
search-picker — مربع بحث لا يعترض الطريق
زر أيقونة يفتح حقل بحث. الضغط على Return، أو على زر ⏎ بجوار الحقل، ينتقل بطلب GET بسيط إلى
/?<text> (يُقصّ النص ويُرمَّز كـ URI؛ والاستعلام الفارغ لا يذهب إلى أي مكان). أسماؤه الثلاثة القابلة للوصول إلزامية لأن المساعد لا يشحن الإنجليزية.
<script>
import SearchPicker from "@lilydesignsystem/svelte-search-picker";
import { goto } from "$app/navigation";
</script>
<SearchPicker
label="Search this site"
inputLabel="Search terms"
submitLabel="Search"
placeholder="Search…"
action="/search"
navigate={(href) => goto(href)}
/>
action يغيّر المسار (/search?foo)، و
navigate يُبقي التنقل داخل التطبيق؛ وبدونه يستدعي المساعد location.assign.
picker-bar — صف الترويسة كله دفعة واحدة
picker-bar يعرض البحث والسمة واللغة المحلية وحجم النص والمشاركة في صف واحد، مع المجموعة الكاملة لسمات المرجع ومقياس النص ذي السبع درجات موصولَين مسبقًا. يصل كل اسم قابل للوصول في كائن
labels إلزامي واحد.
<script>
import PickerBar from "@lilydesignsystem/svelte-picker-bar";
</script>
<PickerBar
labels={{
search: "Search", searchInput: "Search terms", searchSubmit: "Search",
theme: "Theme", locale: "Language", textSize: "Text size", share: "Share",
}}
themesUrl="/themes/"
locales={["en", "fr", "es"]}
shareTargets={targets}
/>
تناول أي منتقٍ ملفوف عبر searchProps,
themeProps, localeProps,
textSizeProps و shareProps.
التلميحات مدمجة
يعرض كل منتقٍ تسميته في تلميح حين يستقر المؤشر على زره أو يكون للزر تركيز لوحة المفاتيح. يبقى التلميح ما دام المؤشر يتحرك إليه، ويغلقه Escape أينما كان التركيز، ولا يظهر أبدًا ما دامت النافذة المنبثقة للمنتقي مفتوحة. يحمل النص نفسه للاسم القابل للوصول للزر، فلا شيء يُضبط ولا شيء يُترجم مرتين؛ وتنسّقه سمات المرجع.
لوحة إعدادات في مكان واحد
تتركّب مساعدات التفضيلات الأربعة طبيعيًا:
<fieldset class="fieldset">
<legend>Preferences</legend>
<ThemePicker label="Theme" themesUrl="/themes/" themes={themes} storageKey="pref-theme" />
<LocalePicker label="Language" locales={locales} storageKey="pref-locale" />
<TextSizePicker label="Text size" sizes={sizes} storageKey="pref-text-size" />
<MotionPicker label="Motion" motions={motions} storageKey="pref-motion" />
</fieldset>
تم التحقق: جُمّعت مقتطفات locale-picker وtext-size-picker وshare-picker وdate-time-picker واللوحة المدمجة كلًّا على حدة مقابل الحزم 0.1.1 المنشورة، عبر
svelte/server (2026-08-29)؛ وعُرضت مقتطفات motion-picker وsearch-picker وpicker-bar مقابل مكوّنات الحزم نفسها في 2026-10-06.
أين تجدها
# one directory per package in the monorepo, e.g.
git clone https://github.com/LilyDesignSystem/lily-design-system
cd lily-design-system/lily-design-system-svelte-theme-picker
# or lily-design-system-react-theme-picker, -vue- / -angular- / -html- / -web-components- / -nunjucks- / -blazor-
لكل حزمة spec خاص بها، واختبارات مرتبطة ببنود الـ spec، وأمثلة قابلة للتشغيل (بما فيها أنماط ملفات تعريف الارتباط لـ SSR)، وخط بناء ونشر. حزم Svelte هي المرجعية؛ وعند الشك تغلب عقودها.
الخطوات التالية
- فهرس المكوّنات — المرجع الكامل للمكوّنات الـ 571.
- المساعدة — استكشاف الأخطاء والأسئلة الشائعة.
- لماذا Lily — وكيف تدعم المشروع.
أسئلة في الطريق؟ صفحة المساعدة مليئة بالإجابات — وإن أمكن توضيح خطوة أكثر، أخبرنا وسنحسّن الدليل بكل سرور.