পছন্দ সহায়ক

প্রতি ফ্রেমওয়ার্কে সাতটি ছোট প্যাকেজ, প্রতিটি ব্যবহারকারীর একটি কাজ শুরু থেকে শেষ পর্যন্ত নিজের হাতে রাখে, সঙ্গে এমন একটি বার যা তার পাঁচটিকে জোড়া লাগায়। আপনি আগেই পরিচিত হয়েছেন theme-picker-এর সঙ্গে; এই যে locale-picker, text-size-picker ও motion-picker (পছন্দ), share-picker ও search-picker (কাজ), date-time-picker (ফর্মের মান) এবং picker-bar।

আপনি কী তৈরি করবেন

একটি সেটিংস প্যানেল যেখানে ব্যবহারকারীরা ভাষা ও লেখার আকার বেছে নেন — পছন্দগুলো পুরো নথিতে প্রযোজ্য, ভিজিটের মধ্যে টিকে থাকে এবং আপনার খরচ দুটি কম্পোনেন্ট ও কয়েক লাইন CSS। প্রায় ১৫ মিনিট।

শুরু করার আগে

আগে সম্পন্ন করুন ফ্রেমওয়ার্ক টিউটোরিয়াল আপনার স্ট্যাকের জন্য। নিচের নমুনাগুলো 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 prop-এর মাধ্যমে)। 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 -এ আর পুরো অ্যাপ ব্যবহারকারীর পছন্দের সঙ্গে মাপ বদলায়। লেবেল slug থেকে বড় হাতের প্রথম অক্ষরে তৈরি হয় ("X Large") বা এর মাধ্যমে ওভাররাইড হয় sizeLabels.

আপনার কাজ পরীক্ষা করুন: নির্বাচক থেকে "Large" বেছে নিন, আর পাতার লেখা বড় হয়। পুনরায় লোড করুন — এখনো বড়: পছন্দ এখানে ধরে রাখা হয়েছিল localStorage। আপনার ভাষা নির্বাচককে আরবিতে বদলান আর dir="rtl" নথিতে স্বয়ংক্রিয়ভাবে সেট হয়।

share-picker — এই পাতা পাঠান

একটি এক-চিহ্নের বোতাম যা যেখানে আছে সেখানে ডিভাইসের নেটিভ শেয়ার শিট খোলে, নইলে আপনার দেওয়া গন্তব্যের তালিকায় ফিরে যায়, সঙ্গে URL কপি করার কাজ। এটি কোনো সোশ্যাল-নেটওয়ার্ক URL পাঠায় না — কোন নেটওয়ার্ক আপনার পণ্যে থাকবে তা আপনার সিদ্ধান্ত, ডিজাইন সিস্টেমের নয়।

<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 তারিখ-নির্বাচক ডায়ালগ খোলে। গঠনগতভাবেই লোকেল অনুযায়ী সঠিক — মাসের নাম, সপ্তাহের দিনের নাম, সপ্তাহের প্রথম দিন ও ১২ বা ২৪ ঘণ্টার ঘড়ি সবই আসে 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 (২০২৬-০৮-২৯); motion-picker, search-picker ও picker-bar-এর খণ্ড ২০২৬-১০-০৬ তারিখে প্যাকেজের নিজস্ব কম্পোনেন্টের বিরুদ্ধে রেন্ডার করা হয়েছে।

কোথায় পাবেন

# 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 প্যাকেজ আদর্শ; সন্দেহে তাদের চুক্তি জেতে।

পরবর্তী ধাপ

পথে প্রশ্ন আছে? সহায়তা পাতা উত্তরে ভরা — আর কোনো ধাপ আরও পরিষ্কার হতে পারলে, আমাদের জানান আর আমরা খুশি মনে টিউটোরিয়াল উন্নত করব।