একটি টোস্ট উপাদান নির্মাণ

কীভাবে একটি অভিযোজিত এবং অ্যাক্সেসযোগ্য টোস্ট উপাদান তৈরি করা যায় তার একটি ভিত্তিগত ওভারভিউ।

এই পোস্টে আমি কীভাবে একটি টোস্ট উপাদান তৈরি করতে হয় সে সম্পর্কে চিন্তাভাবনা ভাগ করতে চাই। ডেমো চেষ্টা করুন.

ডেমো

আপনি যদি ভিডিও পছন্দ করেন তবে এখানে এই পোস্টটির একটি YouTube সংস্করণ রয়েছে:

ওভারভিউ

টোস্টগুলি ব্যবহারকারীদের জন্য অ-ইন্টারেক্টিভ, প্যাসিভ এবং অ্যাসিঙ্ক্রোনাস সংক্ষিপ্ত বার্তা। সাধারণত এগুলি একটি ক্রিয়াকলাপের ফলাফল সম্পর্কে ব্যবহারকারীকে অবহিত করার জন্য একটি ইন্টারফেস প্রতিক্রিয়া প্যাটার্ন হিসাবে ব্যবহৃত হয়।

মিথস্ক্রিয়া

টোস্টগুলি নোটিফিকেশন, সতর্কতা এবং প্রম্পটের বিপরীত কারণ তারা ইন্টারেক্টিভ নয়; তাদের বরখাস্ত করা বা অব্যাহত রাখার জন্য নয়। বিজ্ঞপ্তিগুলি আরও গুরুত্বপূর্ণ তথ্য, সিঙ্ক্রোনাস মেসেজিং যার জন্য ইন্টারঅ্যাকশন প্রয়োজন, বা সিস্টেম স্তরের বার্তাগুলি (পৃষ্ঠা স্তরের বিপরীতে)। অন্যান্য নোটিশ কৌশলগুলির তুলনায় টোস্টগুলি আরও প্যাসিভ।

মার্কআপ

<output> উপাদানটি টোস্টের জন্য একটি ভাল পছন্দ কারণ এটি স্ক্রিন পাঠকদের জন্য ঘোষণা করা হয়। সঠিক HTML আমাদের জাভাস্ক্রিপ্ট এবং CSS এর সাথে উন্নত করার জন্য একটি নিরাপদ ভিত্তি প্রদান করে এবং সেখানে প্রচুর জাভাস্ক্রিপ্ট থাকবে।

একটি টোস্ট

<output class="gui-toast">Item added to cart</output>

role="status" যোগ করে এটি আরও অন্তর্ভুক্ত হতে পারে। এটি একটি ফলব্যাক প্রদান করে যদি ব্রাউজার <output> উপাদানগুলিকে স্পেক অনুযায়ী অন্তর্নিহিত ভূমিকা না দেয়।

<output role="status" class="gui-toast">Item added to cart</output>

একটি টোস্ট পাত্রে

একবারে একাধিক টোস্ট দেখানো যেতে পারে। একাধিক টোস্ট অর্কেস্ট্রেট করার জন্য, একটি ধারক ব্যবহার করা হয়। এই ধারকটি পর্দায় টোস্টগুলির অবস্থানও পরিচালনা করে।

<section class="gui-toast-group">
  <output role="status">Wizard Rose added to cart</output>
  <output role="status">Self Watering Pot added to cart</output>
</section>

বিন্যাস

আমি ভিউপোর্টের inset-block-end টোস্টগুলি পিন করতে বেছে নিয়েছি এবং যদি আরও টোস্ট যোগ করা হয়, সেগুলি সেই স্ক্রিন প্রান্ত থেকে স্ট্যাক করে।

GUI ধারক

টোস্টের ধারকটি টোস্ট উপস্থাপনের জন্য সমস্ত লেআউটের কাজ করে। এটি ভিউপোর্টে fixed এবং কোন প্রান্তগুলিকে পিন করতে হবে তা নির্দিষ্ট করতে লজিক্যাল প্রপার্টি inset ব্যবহার করে এবং একই block-end প্রান্ত থেকে কিছুটা padding

.gui-toast-group {
  position: fixed;
  z-index: 1;
  inset-block-end: 0;
  inset-inline: 0;
  padding-block-end: 5vh;
}

DevTools বক্সের আকার এবং .gui-toast-container এলিমেন্টে ওভারলে করা প্যাডিং সহ স্ক্রিনশট।

ভিউপোর্টের মধ্যে অবস্থান করার পাশাপাশি, টোস্ট কন্টেইনার হল একটি গ্রিড ধারক যা টোস্টগুলিকে সারিবদ্ধ এবং বিতরণ করতে পারে। আইটেমগুলিকে justify-content সহ একটি গ্রুপ হিসাবে কেন্দ্রীভূত করা হয় এবং স্বতন্ত্রভাবে justify-items সাথে কেন্দ্রীভূত হয়। একটু gap করে ফেলুন যাতে টোস্টগুলি স্পর্শ না করে।

.gui-toast-group {
  display: grid;
  justify-items: center;
  justify-content: center;
  gap: 1vh;
}

টোস্ট গ্রুপে CSS গ্রিড ওভারলে সহ স্ক্রিনশট, এবার টোস্ট চাইল্ড উপাদানগুলির মধ্যে স্থান এবং ফাঁকগুলি হাইলাইট করছে।

GUI টোস্ট

একটি পৃথক টোস্টে কিছু padding , border-radius সহ কিছু নরম কোণ এবং মোবাইল এবং ডেস্কটপের আকার নির্ধারণে সহায়তা করার জন্য একটি min() ফাংশন রয়েছে। নিম্নলিখিত CSS-এ প্রতিক্রিয়াশীল আকার টোস্টগুলিকে ভিউপোর্টের 90% বা 25ch এর চেয়ে বেশি প্রশস্ত হতে বাধা দেয়।

.gui-toast {
  max-inline-size: min(25ch, 90vw);
  padding-block: .5ch;
  padding-inline: 1ch;
  border-radius: 3px;
  font-size: 1rem;
}

একটি একক .gui-টোস্ট উপাদানের স্ক্রিনশট, যেখানে প্যাডিং এবং সীমানা ব্যাসার্ধ দেখানো হয়েছে৷

শৈলী

লেআউট এবং পজিশনিং সেটের সাথে, CSS যোগ করুন যা ব্যবহারকারীর সেটিংস এবং ইন্টারঅ্যাকশনের সাথে মানিয়ে নিতে সাহায্য করে।

টোস্ট ধারক

টোস্টগুলি ইন্টারেক্টিভ নয়, তাদের উপর ট্যাপ করা বা সোয়াইপ করা কিছুই করে না, তবে তারা বর্তমানে পয়েন্টার ইভেন্টগুলি গ্রাস করে। নিম্নলিখিত CSS দিয়ে ক্লিক চুরি থেকে toasts প্রতিরোধ করুন.

.gui-toast-group {
  pointer-events: none;
}

GUI টোস্ট

কাস্টম বৈশিষ্ট্য, HSL এবং একটি পছন্দ মিডিয়া ক্যোয়ারী সহ টোস্টগুলিকে একটি হালকা বা অন্ধকার অভিযোজিত থিম দিন৷

.gui-toast {
  --_bg-lightness: 90%;

  color: black;
  background: hsl(0 0% var(--_bg-lightness) / 90%);
}

@media (prefers-color-scheme: dark) {
  .gui-toast {
    color: white;
    --_bg-lightness: 20%;
  }
}

অ্যানিমেশন

একটি নতুন টোস্ট স্ক্রিনে প্রবেশ করার সাথে সাথে একটি অ্যানিমেশনের সাথে নিজেকে উপস্থাপন করা উচিত। সংক্ষিপ্ত গতির মানগুলি ডিফল্টরূপে translate মানকে 0 তে সেট করে করা হয়, তবে গতি পছন্দ মিডিয়া ক্যোয়ারীতে গতির মানটিকে দৈর্ঘ্যে আপডেট করে। প্রত্যেকেই কিছু অ্যানিমেশন পায়, কিন্তু শুধুমাত্র কিছু ব্যবহারকারীর টোস্ট দূরত্বে ভ্রমণ করতে পারে।

এখানে টোস্ট অ্যানিমেশনের জন্য ব্যবহৃত কীফ্রেমগুলি রয়েছে। CSS প্রবেশদ্বার, অপেক্ষা এবং টোস্টের প্রস্থান নিয়ন্ত্রণ করবে, সবই এক অ্যানিমেশনে।

@keyframes fade-in {
  from { opacity: 0 }
}

@keyframes fade-out {
  to { opacity: 0 }
}

@keyframes slide-in {
  from { transform: translateY(var(--_travel-distance, 10px)) }
}

টোস্ট উপাদান তারপর ভেরিয়েবল সেট আপ করে এবং কীফ্রেমগুলি অর্কেস্ট্রেট করে।

.gui-toast {
  --_duration: 3s;
  --_travel-distance: 0;

  will-change: transform;
  animation: 
    fade-in .3s ease,
    slide-in .3s ease,
    fade-out .3s ease var(--_duration);
}

@media (prefers-reduced-motion: no-preference) {
  .gui-toast {
    --_travel-distance: 5vh;
  }
}

জাভাস্ক্রিপ্ট

শৈলী এবং স্ক্রিন রিডার অ্যাক্সেসযোগ্য HTML প্রস্তুত সহ, ব্যবহারকারীর ইভেন্টের উপর ভিত্তি করে টোস্ট তৈরি, সংযোজন এবং ধ্বংস করার জন্য জাভাস্ক্রিপ্টের প্রয়োজন। টোস্ট উপাদানটির বিকাশকারীর অভিজ্ঞতা ন্যূনতম এবং শুরু করা সহজ হওয়া উচিত, যেমন:

import Toast from './toast.js'

Toast('My first toast')

টোস্ট গ্রুপ এবং টোস্ট তৈরি করা

যখন জাভাস্ক্রিপ্ট থেকে টোস্ট মডিউল লোড হয়, তখন এটি একটি টোস্ট কন্টেইনার তৈরি করে পৃষ্ঠায় যোগ করতে হবে। আমি body এর আগে উপাদানটি যুক্ত করতে বেছে নিয়েছি, এটি z-index স্ট্যাকিং সমস্যাগুলিকে অসম্ভাব্য করে তুলবে কারণ ধারকটি সমস্ত শরীরের উপাদানগুলির জন্য ধারকটির উপরে থাকে৷

const init = () => {
  const node = document.createElement('section')
  node.classList.add('gui-toast-group')

  document.firstElementChild.insertBefore(node, document.body)
  return node
}

মাথা এবং শরীরের ট্যাগের মধ্যে টোস্ট গ্রুপের স্ক্রিনশট।

init() ফাংশনটিকে মডিউলে অভ্যন্তরীণভাবে বলা হয়, উপাদানটিকে Toaster হিসাবে আটকে রাখে:

const Toaster = init()

createToast() ফাংশন দিয়ে টোস্ট HTML উপাদান তৈরি করা হয়। ফাংশনের টোস্টের জন্য কিছু পাঠ্য প্রয়োজন, একটি <output> উপাদান তৈরি করে, এটিকে কিছু শ্রেণী এবং বৈশিষ্ট্য দিয়ে সাজায়, পাঠ্য সেট করে এবং নোড প্রদান করে।

const createToast = text => {
  const node = document.createElement('output')
  
  node.innerText = text
  node.classList.add('gui-toast')
  node.setAttribute('role', 'status')

  return node
}

এক বা একাধিক টোস্ট পরিচালনা করা

জাভাস্ক্রিপ্ট এখন টোস্ট ধারণ করার জন্য নথিতে একটি ধারক যোগ করে এবং তৈরি টোস্ট যোগ করার জন্য প্রস্তুত। addToast() ফাংশন এক বা একাধিক টোস্ট পরিচালনা করে। প্রথমে টোস্টের সংখ্যা পরীক্ষা করুন এবং গতি ঠিক আছে কিনা, তারপরে এই তথ্যটি ব্যবহার করে হয় টোস্ট যুক্ত করুন বা কিছু অভিনব অ্যানিমেশন করুন যাতে অন্যান্য টোস্টগুলি নতুন টোস্টের জন্য "ঘর তৈরি করে" বলে মনে হয়।

const addToast = toast => {
  const { matches:motionOK } = window.matchMedia(
    '(prefers-reduced-motion: no-preference)'
  )

  Toaster.children.length && motionOK
    ? flipToast(toast)
    : Toaster.appendChild(toast)
}

প্রথম টোস্ট যোগ করার সময়, Toaster.appendChild(toast) CSS অ্যানিমেশনগুলিকে ট্রিগার করে পৃষ্ঠায় একটি টোস্ট যোগ করে: অ্যানিমেট ইন, ওয়েট 3s , অ্যানিমেট আউট। flipToast() বলা হয় যখন বিদ্যমান টোস্ট থাকে, পল লুইস দ্বারা FLIP নামক একটি কৌশল ব্যবহার করে। ধারণাটি হল নতুন টোস্ট যোগ করার আগে এবং পরে পাত্রের অবস্থানের পার্থক্য গণনা করা। টোস্টারটি এখন কোথায় আছে, এটি কোথায় হবে তা চিহ্নিত করার মতো চিন্তা করুন, তারপর এটি যেখানে ছিল সেখান থেকে অ্যানিমেটিং করুন।

const flipToast = toast => {
  // FIRST
  const first = Toaster.offsetHeight

  // add new child to change container size
  Toaster.appendChild(toast)

  // LAST
  const last = Toaster.offsetHeight

  // INVERT
  const invert = last - first

  // PLAY
  const animation = Toaster.animate([
    { transform: `translateY(${invert}px)` },
    { transform: 'translateY(0)' }
  ], {
    duration: 150,
    easing: 'ease-out',
  })
}

CSS গ্রিড লেআউট উত্তোলন করে। যখন একটি নতুন টোস্ট যোগ করা হয়, গ্রিড এটিকে শুরুতে রাখে এবং অন্যদের সাথে ফাঁকা করে। ইতিমধ্যে, একটি ওয়েব অ্যানিমেশন পুরানো অবস্থান থেকে কন্টেইনার অ্যানিমেট করতে ব্যবহৃত হয়।

সব জাভাস্ক্রিপ্ট একসাথে রাখা

যখন Toast('my first toast') কল করা হয়, একটি টোস্ট তৈরি করা হয়, পৃষ্ঠায় যোগ করা হয় (সম্ভবত নতুন টোস্টের জন্য ধারকটি অ্যানিমেটেড করা হয়), একটি প্রতিশ্রুতি দেওয়া হয় এবং তৈরি টোস্টটি CSS অ্যানিমেশন সমাপ্তির জন্য দেখা হয় ( তিনটি কীফ্রেম অ্যানিমেশন) প্রতিশ্রুতি রেজোলিউশনের জন্য।

const Toast = text => {
  let toast = createToast(text)
  addToast(toast)

  return new Promise(async (resolve, reject) => {
    await Promise.allSettled(
      toast.getAnimations().map(animation => 
        animation.finished
      )
    )
    Toaster.removeChild(toast)
    resolve() 
  })
}

আমি অনুভব করেছি এই কোডের বিভ্রান্তিকর অংশটি Promise.allSettled() ফাংশন এবং toast.getAnimations() ম্যাপিং-এ রয়েছে। যেহেতু আমি টোস্টের জন্য একাধিক কীফ্রেম অ্যানিমেশন ব্যবহার করেছি, আত্মবিশ্বাসের সাথে জানার জন্য যে সেগুলি সব শেষ হয়ে গেছে, প্রতিটিকে অবশ্যই JavaScript থেকে অনুরোধ করতে হবে এবং তাদের প্রতিটি finished প্রতিশ্রুতি সম্পূর্ণ করার জন্য পর্যবেক্ষণ করতে হবে। allSettled আমাদের জন্য সেই কাজটি করে, এর সমস্ত প্রতিশ্রুতি পূরণ হয়ে গেলে নিজেকে সম্পূর্ণরূপে সমাধান করে। await Promise.allSettled() ব্যবহার করার অর্থ হল কোডের পরবর্তী লাইনটি আত্মবিশ্বাসের সাথে উপাদানটিকে সরিয়ে দিতে পারে এবং ধরে নিতে পারে টোস্টটি তার জীবনচক্র সম্পূর্ণ করেছে। অবশেষে, কলিং resolve() উচ্চ স্তরের টোস্ট প্রতিশ্রুতি পূরণ করে যাতে বিকাশকারীরা টোস্ট দেখানোর পরে পরিষ্কার করতে বা অন্য কাজ করতে পারে।

export default Toast

সবশেষে, Toast ফাংশনটি মডিউল থেকে রপ্তানি করা হয়, অন্যান্য স্ক্রিপ্ট আমদানি ও ব্যবহার করার জন্য।

টোস্ট উপাদান ব্যবহার করে

টোস্ট ব্যবহার করে, বা টোস্টের বিকাশকারীর অভিজ্ঞতা, Toast ফাংশন আমদানি করে এবং এটিকে একটি বার্তা স্ট্রিং দিয়ে কল করে করা হয়।

import Toast from './toast.js'

Toast('Wizard Rose added to cart')

ডেভেলপার যদি টোস্ট দেখানোর পরে পরিষ্কারের কাজ বা যাই হোক না কেন করতে চান, তারা অ্যাসিঙ্ক ব্যবহার করতে পারেন এবং অপেক্ষা করতে পারেন

import Toast from './toast.js'

async function example() {
  await Toast('Wizard Rose added to cart')
  console.log('toast finished')
}

উপসংহার

এখন যেহেতু আপনি জানেন যে আমি কীভাবে এটি করেছি, আপনি কেমন হবে‽ 🙂৷

আসুন আমাদের পদ্ধতির বৈচিত্র্য আনুন এবং ওয়েবে তৈরি করার সমস্ত উপায় শিখি। একটি ডেমো তৈরি করুন, আমাকে লিঙ্কগুলি টুইট করুন এবং আমি নীচের সম্প্রদায়ের রিমিক্স বিভাগে এটি যুক্ত করব!

কমিউনিটি রিমিক্স