আপনার PWA এর জন্য নতুন এবং আসন্ন ব্রাউজার ক্ষমতাগুলি অন্বেষণ করুন: Fugu With Love থেকে

1. আপনি শুরু করার আগে

প্রগ্রেসিভ ওয়েব অ্যাপ্লিকেশন (PWAs) হল ওয়েবের মাধ্যমে সরবরাহ করা এক ধরনের অ্যাপ্লিকেশন সফ্টওয়্যার, যা HTML, CSS এবং JavaScript সহ সাধারণ ওয়েব প্রযুক্তি ব্যবহার করে তৈরি করা হয়। তারা মান-সম্মত ব্রাউজার ব্যবহার করে এমন যেকোনো প্ল্যাটফর্মে কাজ করার উদ্দেশ্যে তৈরি।

এই কোডল্যাবে, আপনি একটি বেসলাইন PWA দিয়ে শুরু করবেন, এবং তারপরে নতুন ব্রাউজার ক্ষমতাগুলি অন্বেষণ করবেন যা অবশেষে আপনার PWA সুপার পাওয়ার দেবে 🦸৷

এই নতুন ব্রাউজার ক্ষমতাগুলির অনেকগুলি ইন-ফ্লাইট এবং এখনও মানসম্মত হচ্ছে, তাই কখনও কখনও আপনাকে সেগুলি ব্যবহার করার জন্য ব্রাউজার পতাকা সেট করতে হবে৷

পূর্বশর্ত

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

আপনি কি নির্মাণ করবেন

আপনি একটি অভিবাদন কার্ড ওয়েব অ্যাপ তৈরি করবেন, এবং শিখবেন কীভাবে নতুন এবং আসন্ন ব্রাউজার ক্ষমতাগুলি আপনার অ্যাপটিকে উন্নত করতে পারে যাতে এটি নির্দিষ্ট ব্রাউজারে একটি উন্নত অভিজ্ঞতা প্রদান করে (কিন্তু সমস্ত আধুনিক ব্রাউজারে উপযোগী থাকে)।

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

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

আপনি কি প্রয়োজন হবে

এই সময়ে সম্পূর্ণ সমর্থিত ব্রাউজারগুলি হল:

নির্দিষ্ট দেব চ্যানেল ব্যবহার করার পরামর্শ দেওয়া হয়।

2. ফুগু প্রকল্প

প্রগ্রেসিভ ওয়েব অ্যাপস (PWA) আধুনিক API-এর সাথে তৈরি এবং উন্নত করা হয়েছে যাতে বর্ধিত ক্ষমতা, নির্ভরযোগ্যতা এবং ইনস্টলেবিলিটি প্রদান করা হয় যখন যেকোনও ধরনের ডিভাইস ব্যবহার করে ওয়েবে, বিশ্বের যে কোনো স্থানে যে কারো কাছে পৌঁছানো যায়।

এই APIগুলির মধ্যে কিছু খুব শক্তিশালী, এবং, যদি ভুলভাবে পরিচালনা করা হয়, জিনিসগুলি ভুল হতে পারে। ঠিক ফুগু মাছের মতো 🐡: আপনি যখন এটিকে সঠিকভাবে কাটবেন, এটি একটি উপাদেয়, কিন্তু আপনি যখন এটি ভুল কাটবেন, তখন এটি প্রাণঘাতী হতে পারে (তবে চিন্তা করবেন না, এই কোডল্যাবে আসলে কিছুই ভাঙতে পারে না)।

এই কারণেই ওয়েব ক্যাপাবিলিটিস প্রজেক্টের অভ্যন্তরীণ কোড নাম (যেটিতে জড়িত কোম্পানিগুলি এই নতুন APIগুলি বিকাশ করছে) হল প্রজেক্ট ফুগু৷

ওয়েব ক্ষমতাগুলি—ইতিমধ্যেই আজ—বড় এবং ছোট উদ্যোগগুলিকে খাঁটি ব্রাউজার-ভিত্তিক সমাধানগুলি তৈরি করার অনুমতি দেয়, প্রায়শই প্ল্যাটফর্ম-নির্দিষ্ট রুটে যাওয়ার তুলনায় কম ডেভেলপমেন্ট খরচ সহ দ্রুত স্থাপনার অনুমতি দেয়।

3. শুরু করুন

যেকোনো একটি ব্রাউজার ডাউনলোড করুন, এবং তারপর about://flags -এ নেভিগেট করে নিম্নলিখিত রান-টাইম পতাকা সেট করুন, যা ক্রোম এবং এজ উভয় ক্ষেত্রেই কাজ করে:

  • #enable-experimental-web-platform-features

আপনি এটি সক্ষম করার পরে, আপনার ব্রাউজার পুনরায় চালু করুন।

আপনি প্ল্যাটফর্ম Glitch ব্যবহার করবেন, কারণ এটি আপনাকে আপনার PWA হোস্ট করতে দেয় এবং এটির একটি শালীন সম্পাদক রয়েছে। গ্লিচ গিটহাবে আমদানি এবং রপ্তানিকেও সমর্থন করে, তাই কোনও বিক্রেতা লক-ইন নেই। অ্যাপ্লিকেশনটি ব্যবহার করে দেখতে fugu- paint.glitch.me- এ নেভিগেট করুন। এটি একটি মৌলিক অঙ্কন অ্যাপ্লিকেশন 🎨 যা আপনি কোডল্যাবের সময় উন্নতি করবেন।

ফুগু গ্রিটিংস বেসলাইন PWA একটি বড় ক্যানভাসে “Google” তার উপর আঁকা।

অ্যাপ্লিকেশনটির সাথে খেলার পরে, আপনার নিজস্ব অনুলিপি তৈরি করতে অ্যাপটি রিমিক্স করুন যা আপনি সম্পাদনা করতে পারেন। আপনার রিমিক্সের URL glitch.com/edit/#!/bouncy-candytuft ("বাউন্সি-ক্যান্ডিটুফট" আপনার জন্য অন্য কিছু হবে) এর মতো দেখতে হবে৷ এই রিমিক্স বিশ্বব্যাপী সরাসরি অ্যাক্সেসযোগ্য। আপনার বিদ্যমান অ্যাকাউন্টে সাইন ইন করুন বা আপনার কাজ সংরক্ষণ করতে Glitch-এ একটি নতুন অ্যাকাউন্ট তৈরি করুন। আপনি "🕶 শো" বোতামে ক্লিক করে আপনার অ্যাপটি দেখতে পারেন এবং হোস্ট করা অ্যাপের URLটি হবে bouncy-candytuft.glitch.me (টপ-লেভেল ডোমেন হিসেবে .com এর পরিবর্তে .me কে নোট করুন)।

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

গ্লিচ IDE একটি HTML নথির সম্পাদনা দেখাচ্ছে৷

নিম্নলিখিত কাজগুলি আদর্শভাবে ক্রমানুসারে সম্পন্ন করা উচিত, কিন্তু উপরে উল্লিখিত হিসাবে, আপনার যদি একটি সামঞ্জস্যপূর্ণ ডিভাইসে অ্যাক্সেস না থাকে তবে আপনি সর্বদা একটি ধাপ এড়িয়ে যেতে পারেন। মনে রাখবেন, প্রতিটি টাস্ক 🐟, একটি নিরীহ মিঠা পানির মাছ, বা 🐡, একটি "যত্ন সহকারে" ফুগু মাছ দিয়ে চিহ্নিত করা হয়েছে, যা আপনাকে সতর্ক করে যে একটি বৈশিষ্ট্য কতটা পরীক্ষামূলক বা নয়৷

বর্তমান ডিভাইসে একটি API সমর্থিত কিনা তা দেখতে DevTools-এ কনসোল চেক করুন। এছাড়াও আমরা গ্লিচ ব্যবহার করি যাতে আপনি একই অ্যাপটি বিভিন্ন ডিভাইসে সহজেই পরীক্ষা করতে পারেন, উদাহরণস্বরূপ আপনার মোবাইল ফোন এবং আপনার ডেস্কটপ কম্পিউটারে।

DevTools-এর কনসোলে API সামঞ্জস্যতা লগ করা হয়েছে।

4. 🐟 ওয়েব শেয়ার API সমর্থন যোগ করুন

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

ওয়েব শেয়ার API ফাইল শেয়ার করা সমর্থন করে, এবং আপনি মনে করতে পারেন, একটি File হল একটি নির্দিষ্ট ধরনের Blob । অতএব, share.mjs নামক ফাইলটিতে, শেয়ার বোতাম এবং একটি সুবিধাজনক ফাংশন toBlob() এ আমদানি করুন যা একটি ক্যানভাসের বিষয়বস্তুকে একটি ব্লবে রূপান্তর করে এবং নীচের কোড অনুসারে শেয়ার কার্যকারিতা যোগ করে।

আপনি যদি এটি প্রয়োগ করে থাকেন কিন্তু বোতামটি দেখতে না পান, তাহলে আপনার ব্রাউজার ওয়েব শেয়ার API প্রয়োগ করে না।

import { shareButton, toBlob } from './script.mjs';

const share = async (title, text, blob) => {
  const data = {
    files: [
      new File([blob], 'fugu-greeting.png', {
        type: blob.type,
      }),
    ],
    title: title,
    text: text,
  };
  try {
    if (!navigator.canShare(data)) {
      throw new Error("Can't share data.", data);
    }
    await navigator.share(data);
  } catch (err) {
    console.error(err.name, err.message);
  }
};

shareButton.style.display = 'block';
shareButton.addEventListener('click', async () => {
  return share('Fugu Greetings', 'From Fugu With Love', await toBlob());
});

5. 🐟 ওয়েব শেয়ার টার্গেট API সমর্থন যোগ করুন

এখন আপনার ব্যবহারকারীরা অ্যাপ ব্যবহার করে তৈরি অভিবাদন কার্ড শেয়ার করতে পারবেন, তবে আপনি ব্যবহারকারীদের আপনার অ্যাপে ছবি শেয়ার করতে এবং সেগুলিকে অভিবাদন কার্ডে পরিণত করার অনুমতি দিতে পারেন। এর জন্য, আপনি ওয়েব শেয়ার টার্গেট API ব্যবহার করতে পারেন।

ওয়েব অ্যাপ্লিকেশন ম্যানিফেস্টে, আপনাকে অ্যাপটিকে বলতে হবে আপনি কোন ধরনের ফাইল গ্রহণ করতে পারবেন এবং এক বা একাধিক ফাইল শেয়ার করা হলে ব্রাউজারকে কোন URL কল করা উচিত। manifest.webmanifest ফাইলের নীচের অংশটি এটি দেখায়।

{
  "share_target": {
    "action": "./share-target/",
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "files": [
        {
          "name": "image",
          "accept": ["image/jpeg", "image/png", "image/webp", "image/gif"]
        }
      ]
    }
  }
}

পরিষেবা কর্মী তারপর প্রাপ্ত ফাইলগুলি নিয়ে কাজ করেন। URL ./share-target/ আসলে বিদ্যমান নেই, অ্যাপটি fetch হ্যান্ডলারে এটির উপর কাজ করে এবং একটি ক্যোয়ারী প্যারামিটার যোগ করে রুট ইউআরএলে অনুরোধ রিডাইরেক্ট করে ?share-target :

self.addEventListener('fetch', (fetchEvent) => {
  /* 🐡 Start Web Share Target */
  if (
    fetchEvent.request.url.endsWith('/share-target/') &&
    fetchEvent.request.method === 'POST'
  ) {
    return fetchEvent.respondWith(
      (async () => {
        const formData = await fetchEvent.request.formData();
        const image = formData.get('image');
        const keys = await caches.keys();
        const mediaCache = await caches.open(
          keys.filter((key) => key.startsWith('media'))[0],
        );
        await mediaCache.put('shared-image', new Response(image));
        return Response.redirect('./?share-target', 303);
      })(),
    );
  }
  /* 🐡 End Web Share Target */

  /* ... */
});

যখন অ্যাপ লোড হয়, তখন এটি পরীক্ষা করে যে এই ক্যোয়ারী প্যারামিটার সেট করা আছে কিনা, এবং যদি তাই হয়, শেয়ার করা ছবি ক্যানভাসে আঁকে এবং ক্যাশে থেকে মুছে দেয়। এই সব script.mjs এ ঘটে:

const restoreImageFromShare = async () => {
  const mediaCache = await getMediaCache();
  const image = await mediaCache.match('shared-image');
  if (image) {
    const blob = await image.blob();
    await drawBlob(blob);
    await mediaCache.delete('shared-image');
  }
};

এই ফাংশনটি তখন ব্যবহার করা হয় যখন অ্যাপটি শুরু হয়।

if (location.search.includes('share-target')) {
  restoreImageFromShare();
} else {
  drawDefaultImage();
}

6. 🐟 ইমেজ ইমেজ সাপোর্ট যোগ করুন

স্ক্র্যাচ থেকে সবকিছু আঁকা কঠিন. আপনার ব্যবহারকারীদের তাদের ডিভাইস থেকে অ্যাপে একটি স্থানীয় ছবি আপলোড করার অনুমতি দিয়ে একটি বৈশিষ্ট্য যোগ করুন।

প্রথমে, ক্যানভাসের drawImage() ফাংশন পড়ুন। এরপর, নিজেকে <​input
type=file>
উপাদান।

এই জ্ঞানের সাথে সজ্জিত, আপনি import_image_legacy.mjs নামক ফাইলটি সম্পাদনা করতে পারেন এবং নিম্নলিখিত স্নিপেট যোগ করতে পারেন। ফাইলের শীর্ষে আপনি আমদানি বোতাম এবং একটি সুবিধার ফাংশন drawBlob() আমদানি করেন যা আপনাকে ক্যানভাসে একটি ব্লব আঁকতে দেয়।

import { importButton, drawBlob } from './script.mjs';

const importImage = async () => {
  return new Promise((resolve) => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = 'image/png, image/jpeg, image/*';
    input.addEventListener('change', () => {
      const file = input.files[0];
      input.remove();
      return resolve(file);
    });
    input.click();
  });
};

importButton.style.display = 'block';
importButton.addEventListener('click', async () => {
  const file = await importImage();
  if (file) {
    await drawBlob(file);
  }
});

7. 🐟 এক্সপোর্ট ইমেজ সাপোর্ট যোগ করুন

কিভাবে আপনার ব্যবহারকারী তাদের ডিভাইসে অ্যাপে তৈরি একটি ফাইল সংরক্ষণ করবে? ঐতিহ্যগতভাবে, এটি একটি <​a
download>
দিয়ে অর্জন করা হয়েছে <​a
download>
উপাদান।

export_image_legacy.mjs ফাইলে নিচের মত বিষয়বস্তু যোগ করুন। এক্সপোর্ট বোতাম এবং একটি toBlob() সুবিধার ফাংশন আমদানি করুন যা ক্যানভাসের বিষয়বস্তুকে একটি ব্লবে রূপান্তর করে।

import { exportButton, toBlob } from './script.mjs';

export const exportImage = async (blob) => {
  const a = document.createElement('a');
  a.download = 'fugu-greeting.png';
  a.href = URL.createObjectURL(blob);
  a.addEventListener('click', (e) => {
    a.remove();
    setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000);
  });
  setTimeout(() => a.click(), 0);
};

exportButton.style.display = 'block';
exportButton.addEventListener('click', async () => {
  exportImage(await toBlob());
});

8. 🐟 ফাইল সিস্টেম অ্যাক্সেস API সমর্থন যোগ করুন

ভাগ করা যত্নশীল, কিন্তু আপনার ব্যবহারকারীরা সম্ভবত তাদের নিজের ডিভাইসে তাদের সেরা কাজ সংরক্ষণ করতে চাইবেন। একটি বৈশিষ্ট্য যোগ করুন যা আপনার ব্যবহারকারীদের তাদের অঙ্কনগুলি সংরক্ষণ করতে (এবং পুনরায় খুলতে) অনুমতি দেয়৷

আগে, আপনি ফাইল আমদানি করার জন্য একটি <​input type=file> উত্তরাধিকার পদ্ধতি এবং ফাইল রপ্তানির জন্য একটি <​a download> উত্তরাধিকার পদ্ধতি ব্যবহার করেছিলেন। এখন, আপনি অভিজ্ঞতা উন্নত করতে ফাইল সিস্টেম অ্যাক্সেস API ব্যবহার করবেন।

এই API অপারেটিং সিস্টেমের ফাইল সিস্টেম থেকে ফাইল খোলার এবং সংরক্ষণ করার অনুমতি দেয়। নিচের বিষয়বস্তু যোগ করে দুটি ফাইল যথাক্রমে import_image.mjs এবং export_image.mjs সম্পাদনা করুন। এই ফাইলগুলি লোড করার জন্য, script.mjs থেকে script.mjs ইমোজিগুলি সরান।

এই লাইনটি প্রতিস্থাপন করুন:

// Remove all the emojis for this feature test to succeed.
if ('show🐡Open🐡File🐡Picker' in window) {
  /* ... */
}

...এই লাইনের সাথে:

if ('showOpenFilePicker' in window) {
  /* ... */
}

import_image.mjs এ:

import { importButton, drawBlob } from './script.mjs';

const importImage = async () => {
  try {
    const [handle] = await window.showOpenFilePicker({
      types: [
        {
          description: 'Image files',
          accept: {
            'image/*': ['.png', '.jpg', '.jpeg', '.avif', '.webp', '.svg'],
          },
        },
      ],
    });
    return await handle.getFile();
  } catch (err) {
    console.error(err.name, err.message);
  }
};

importButton.style.display = 'block';
importButton.addEventListener('click', async () => {
  const file = await importImage();
  if (file) {
    await drawBlob(file);
  }
});

export_image.mjs এ:

import { exportButton, toBlob } from './script.mjs';

const exportImage = async () => {
  try {
    const handle = await window.showSaveFilePicker({
      suggestedName: 'fugu-greetings.png',
      types: [
        {
          description: 'Image file',
          accept: {
            'image/png': ['.png'],
          },
        },
      ],
    });
    const blob = await toBlob();
    const writable = await handle.createWritable();
    await writable.write(blob);
    await writable.close();
  } catch (err) {
    console.error(err.name, err.message);
  }
};

exportButton.style.display = 'block';
exportButton.addEventListener('click', async () => {
  await exportImage();
});

9. 🐟 পরিচিতি পিকার API সমর্থন যোগ করুন

আপনার ব্যবহারকারীরা তাদের অভিবাদন কার্ডে একটি বার্তা যোগ করতে এবং ব্যক্তিগতভাবে কাউকে সম্বোধন করতে চাইতে পারে। একটি বৈশিষ্ট্য যোগ করুন যা আপনার ব্যবহারকারীদের তাদের স্থানীয় পরিচিতিগুলির একটি (বা একাধিক) বাছাই করতে এবং শেয়ার বার্তায় তাদের নাম যোগ করতে দেয়৷

একটি Android বা iOS ডিভাইসে, Contact Picker API আপনাকে ডিভাইসের পরিচিতি ম্যানেজার অ্যাপ থেকে পরিচিতি বাছাই করতে এবং সেগুলিকে অ্যাপ্লিকেশনে ফেরত দিতে দেয়। contacts.mjs ফাইলটি সম্পাদনা করুন এবং নীচের কোডটি যোগ করুন।

import { contactsButton, ctx, canvas } from './script.mjs';

const getContacts = async () => {
  const properties = ['name'];
  const options = { multiple: true };
  try {
    return await navigator.contacts.select(properties, options);
  } catch (err) {
    console.error(err.name, err.message);
  }
};

contactsButton.style.display = 'block';
contactsButton.addEventListener('click', async () => {
  const contacts = await getContacts();
  if (contacts) {
    ctx.font = '1em Comic Sans MS';
    contacts.forEach((contact, index) => {
      ctx.fillText(contact.name.join(), 20, 16 * ++index, canvas.width);
    });
  }
});

10. 🐟 Async ক্লিপবোর্ড API সমর্থন যোগ করুন

আপনার ব্যবহারকারীরা আপনার অ্যাপে অন্য অ্যাপ থেকে একটি ছবি পেস্ট করতে চাইতে পারেন, অথবা আপনার অ্যাপ থেকে একটি অঙ্কন অন্য অ্যাপে কপি করতে চাইতে পারেন। একটি বৈশিষ্ট্য যোগ করুন যা আপনার ব্যবহারকারীদের আপনার অ্যাপের মধ্যে এবং বাইরে ছবি কপি এবং পেস্ট করতে দেয়। Async ক্লিপবোর্ড API PNG ছবিগুলিকে সমর্থন করে, তাই এখন আপনি ক্লিপবোর্ডে চিত্র ডেটা পড়তে এবং লিখতে পারেন৷

clipboard.mjs ফাইলটি খুঁজুন এবং নিম্নলিখিত যোগ করুন:

import { copyButton, pasteButton, toBlob, drawImage } from './script.mjs';

const copy = async (blob) => {
  try {
    await navigator.clipboard.write([
      /* global ClipboardItem */
      new ClipboardItem({
        [blob.type]: blob,
      }),
    ]);
  } catch (err) {
    console.error(err.name, err.message);
  }
};

const paste = async () => {
  try {
    const clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
      try {
        for (const type of clipboardItem.types) {
          const blob = await clipboardItem.getType(type);
          return blob;
        }
      } catch (err) {
        console.error(err.name, err.message);
      }
    }
  } catch (err) {
    console.error(err.name, err.message);
  }
};

copyButton.style.display = 'block';
copyButton.addEventListener('click', async () => {
  await copy(await toBlob());
});

pasteButton.style.display = 'block';
pasteButton.addEventListener('click', async () => {
  const image = new Image();
  image.addEventListener('load', () => {
    drawImage(image);
  });
  image.src = URL.createObjectURL(await paste());
});

11. 🐟 ব্যাজিং API সমর্থন যোগ করুন

যখন আপনার ব্যবহারকারীরা আপনার অ্যাপটি ইনস্টল করবেন, তখন তাদের হোম স্ক্রিনে একটি আইকন প্রদর্শিত হবে। আপনি এই আইকনটি মজার তথ্য জানাতে ব্যবহার করতে পারেন, যেমন একটি প্রদত্ত অঙ্কন নেওয়া ব্রাশস্ট্রোকের সংখ্যা।

আপনার ব্যবহারকারী যখনই একটি নতুন ব্রাশস্ট্রোক করেন তখন একটি বৈশিষ্ট্য যোগ করুন যা ব্যাজ গণনা করে৷ ব্যাজিং API অ্যাপ আইকনে একটি সংখ্যাসূচক ব্যাজ সেট করার অনুমতি দেয়। আপনি যখনই একটি পয়েন্টারডাউন ইভেন্ট ঘটবে (অর্থাৎ, যখন একটি pointerdown ঘটবে) ব্যাজটি আপডেট করতে পারেন এবং ক্যানভাস সাফ হয়ে গেলে ব্যাজটি পুনরায় সেট করতে পারেন৷

badge.mjs ফাইলে নিচের কোডটি রাখুন:

import { canvas, clearButton } from './script.mjs';

let strokes = 0;

canvas.addEventListener('pointerdown', () => {
  navigator.setAppBadge(++strokes);
});

clearButton.addEventListener('click', () => {
  strokes = 0;
  navigator.setAppBadge(strokes);
});

12. 🐟 স্ক্রীন ওয়েক লক এপিআই সমর্থন যোগ করুন

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

wake_lock.mjs ফাইলটি খুঁজুন এবং নীচের বিষয়বস্তু যোগ করুন। এটি কাজ করে কিনা তা পরীক্ষা করতে, আপনার স্ক্রিনসেভারটি এক মিনিট পরে দেখানোর জন্য কনফিগার করুন।

import { wakeLockInput, wakeLockLabel } from './script.mjs';

let wakeLock = null;

const requestWakeLock = async () => {
  try {
    wakeLock = await navigator.wakeLock.request('screen');
    wakeLock.addEventListener('release', () => {
      console.log('Wake Lock was released');
    });
    console.log('Wake Lock is active');
  } catch (err) {
    console.error(err.name, err.message);
  }
};

const handleVisibilityChange = () => {
  if (wakeLock !== null && document.visibilityState === 'visible') {
    requestWakeLock();
  }
};

document.addEventListener('visibilitychange', handleVisibilityChange);

wakeLockInput.style.display = 'block';
wakeLockLabel.style.display = 'block';
wakeLockInput.addEventListener('change', async () => {
  if (wakeLockInput.checked) {
    await requestWakeLock();
  } else {
    wakeLock.release();
  }
});

13. 🐟 পর্যায়ক্রমিক পটভূমি সিঙ্ক API সমর্থন যোগ করুন

একটি ফাঁকা ক্যানভাস দিয়ে শুরু করা বিরক্তিকর হতে পারে। আপনি পর্যায়ক্রমিক ব্যাকগ্রাউন্ড সিঙ্ক API ব্যবহার করতে পারেন আপনার ব্যবহারকারীদের ক্যানভাসকে প্রতিদিন একটি নতুন ইমেজ দিয়ে শুরু করতে, উদাহরণস্বরূপ, আনস্প্ল্যাশের দৈনিক ফুগু ফটো

এর জন্য দুটি ফাইল প্রয়োজন, একটি ফাইল periodic_background_sync.mjs যা পর্যায়ক্রমিক ব্যাকগ্রাউন্ড সিঙ্ক নিবন্ধন করে এবং আরেকটি ফাইল image_of_the_day.mjs যা দিনের ছবি ডাউনলোড করার বিষয়ে কাজ করে।

periodic_background_sync.mjs এ:

import { periodicBackgroundSyncButton, drawBlob } from './script.mjs';

const getPermission = async () => {
  const status = await navigator.permissions.query({
    name: 'periodic-background-sync',
  });
  return status.state === 'granted';
};

const registerPeriodicBackgroundSync = async () => {
  const registration = await navigator.serviceWorker.ready;
  try {
    registration.periodicSync.register('image-of-the-day-sync', {
      // An interval of one day.
      minInterval: 24 * 60 * 60 * 1000,
    });
  } catch (err) {
    console.error(err.name, err.message);
  }
};

navigator.serviceWorker.addEventListener('message', async (event) => {
  const fakeURL = event.data.image;
  const mediaCache = await getMediaCache();
  const response = await mediaCache.match(fakeURL);
  drawBlob(await response.blob());
});

const getMediaCache = async () => {
  const keys = await caches.keys();
  return await caches.open(keys.filter((key) => key.startsWith('media'))[0]);
};

periodicBackgroundSyncButton.style.display = 'block';
periodicBackgroundSyncButton.addEventListener('click', async () => {
  if (await getPermission()) {
    await registerPeriodicBackgroundSync();
  }
  const mediaCache = await getMediaCache();
  let blob = await mediaCache.match('./assets/background.jpg');
  if (!blob) {
    blob = await mediaCache.match('./assets/fugu_greeting_card.jpg');
  }
  drawBlob(await blob.blob());
});

image_of_the_day.mjs :

const getImageOfTheDay = async () => {
  try {
    const fishes = ['blowfish', 'pufferfish', 'fugu'];
    const fish = fishes[Math.floor(fishes.length * Math.random())];
    const response = await fetch(`https://source.unsplash.com/daily?${fish}`);
    if (!response.ok) {
      throw new Error('Response was', response.status, response.statusText);
    }
    return await response.blob();
  } catch (err) {
    console.error(err.name, err.message);
  }
};

const getMediaCache = async () => {
  const keys = await caches.keys();
  return await caches.open(keys.filter((key) => key.startsWith('media'))[0]);
};

self.addEventListener('periodicsync', (syncEvent) => {
  if (syncEvent.tag === 'image-of-the-day-sync') {
    syncEvent.waitUntil(
      (async () => {
        try {
          const blob = await getImageOfTheDay();
          const mediaCache = await getMediaCache();
          const fakeURL = './assets/background.jpg';
          await mediaCache.put(fakeURL, new Response(blob));
          const clients = await self.clients.matchAll();
          clients.forEach((client) => {
            client.postMessage({
              image: fakeURL,
            });
          });
        } catch (err) {
          console.error(err.name, err.message);
        }
      })(),
    );
  }
});

14. 🐟 আকৃতি সনাক্তকরণ API সমর্থন যোগ করুন

কখনও কখনও আপনার ব্যবহারকারীদের আঁকা বা ব্যবহৃত ব্যাকগ্রাউন্ড চিত্রগুলিতে দরকারী তথ্য থাকতে পারে যেমন, বারকোড৷ শেপ ডিটেকশন এপিআই , এবং বিশেষ করে, বারকোড ডিটেকশন এপিআই, আপনাকে এই তথ্য বের করতে দেয়। একটি বৈশিষ্ট্য যোগ করুন যা আপনার ব্যবহারকারীদের অঙ্কন থেকে বারকোড সনাক্ত করার চেষ্টা করে। barcode.mjs ফাইলটি সনাক্ত করুন এবং নীচের বিষয়বস্তু যোগ করুন। এই বৈশিষ্ট্যটি পরীক্ষা করতে, ক্যানভাসে বারকোড সহ একটি চিত্র লোড বা পেস্ট করুন৷ আপনি QR কোডগুলির জন্য একটি চিত্র অনুসন্ধান থেকে একটি উদাহরণ বারকোড অনুলিপি করতে পারেন৷

/* global BarcodeDetector */
import {
  scanButton,
  clearButton,
  canvas,
  ctx,
  CANVAS_BACKGROUND,
  CANVAS_COLOR,
  floor,
} from './script.mjs';

const barcodeDetector = new BarcodeDetector();

const detectBarcodes = async (canvas) => {
  return await barcodeDetector.detect(canvas);
};

scanButton.style.display = 'block';
let seenBarcodes = [];
clearButton.addEventListener('click', () => {
  seenBarcodes = [];
});
scanButton.addEventListener('click', async () => {
  const barcodes = await detectBarcodes(canvas);
  if (barcodes.length) {
    barcodes.forEach((barcode) => {
      const rawValue = barcode.rawValue;
      if (seenBarcodes.includes(rawValue)) {
        return;
      }
      seenBarcodes.push(rawValue);
      ctx.font = '1em Comic Sans MS';
      ctx.textAlign = 'center';
      ctx.fillStyle = CANVAS_BACKGROUND;
      const boundingBox = barcode.boundingBox;
      const left = boundingBox.left;
      const top = boundingBox.top;
      const height = boundingBox.height;
      const oneThirdHeight = floor(height / 3);
      const width = boundingBox.width;
      ctx.fillRect(left, top + oneThirdHeight, width, oneThirdHeight);
      ctx.fillStyle = CANVAS_COLOR;
      ctx.fillText(
        rawValue,
        left + floor(width / 2),
        top + floor(height / 2),
        width,
      );
    });
  }
});

15. 🐡 নিষ্ক্রিয় সনাক্তকরণ API সমর্থন যোগ করুন

আপনি যদি কল্পনা করেন যে আপনার অ্যাপটি কিয়স্ক-এর মতো সেটআপে চলছে, তাহলে একটি দরকারী বৈশিষ্ট্য হল নির্দিষ্ট পরিমাণ নিষ্ক্রিয়তার পরে ক্যানভাস রিসেট করা। Idle Detection API আপনাকে সনাক্ত করতে দেয় কখন কোন ব্যবহারকারী তাদের ডিভাইসের সাথে আর ইন্টারঅ্যাক্ট করে না।

idle_detection.mjs ফাইলটি খুঁজুন এবং নিচের বিষয়বস্তুতে পেস্ট করুন।

import { ephemeralInput, ephemeralLabel, clearCanvas } from './script.mjs';

let controller;

ephemeralInput.style.display = 'block';
ephemeralLabel.style.display = 'block';

ephemeralInput.addEventListener('change', async () => {
  if (ephemeralInput.checked) {
    const state = await IdleDetector.requestPermission();
    if (state !== 'granted') {
      ephemeralInput.checked = false;
      return alert('Idle detection permission must be granted!');
    }
    try {
      controller = new AbortController();
      const idleDetector = new IdleDetector();
      idleDetector.addEventListener('change', (e) => {
        const { userState, screenState } = e.target;
        console.log(`idle change: ${userState}, ${screenState}`);
        if (userState === 'idle') {
          clearCanvas();
        }
      });
      idleDetector.start({
        threshold: 60000,
        signal: controller.signal,
      });
    } catch (err) {
      console.error(err.name, err.message);
    }
  } else {
    console.log('Idle detection stopped.');
    controller.abort();
  }
});

16. 🐡 ফাইল হ্যান্ডলিং API সমর্থন যোগ করুন

কি হবে যদি আপনার ব্যবহারকারীরা একটি ইমেজ ফাইলে ডাবল ক্লিক করতে পারে এবং আপনার অ্যাপটি পপ আপ হবে? ফাইল হ্যান্ডলিং API আপনাকে এটি করতে দেয়।

আপনাকে চিত্রগুলির জন্য একটি ফাইল হ্যান্ডলার হিসাবে PWA নিবন্ধন করতে হবে৷ এটি ওয়েব অ্যাপ্লিকেশন ম্যানিফেস্টে ঘটে, manifest.webmanifest ফাইলের নীচের অংশ এটি দেখায়। (এটি ইতিমধ্যেই ম্যানিফেস্টের অংশ, এটি নিজেকে যোগ করার দরকার নেই।)

{
  "file_handlers": [
    {
      "action": "./",
      "accept": {
        "image/*": [".jpg", ".jpeg", ".png", ".webp", ".svg"]
      }
    }
  ]
}

আসলে খোলা ফাইলগুলি পরিচালনা করতে, ফাইল file-handling.mjs এ নীচের কোডটি যোগ করুন:

import { drawBlob } from './script.mjs';

const handleLaunchFiles = () => {
  window.launchQueue.setConsumer((launchParams) => {
    if (!launchParams.files.length) {
      return;
    }
    launchParams.files.forEach(async (handle) => {
      const file = await handle.getFile();
      drawBlob(file);
    });
  });
};

handleLaunchFiles();

17. অভিনন্দন

🎉 উহু, আপনি এটা তৈরি করেছেন!

প্রজেক্ট ফুগু 🐡 এর পরিপ্রেক্ষিতে অনেকগুলি উত্তেজনাপূর্ণ ব্রাউজার API তৈরি করা হচ্ছে যে এই কোডল্যাবটি খুব কমই পৃষ্ঠকে স্ক্র্যাচ করতে পারে।

আরও গভীরে ডুব দেওয়ার জন্য, বা আরও জানতে, আমাদের ওয়েবসাইট web.dev- এ আমাদের প্রকাশনাগুলি অনুসরণ করুন।

ল্যান্ডিং পৃষ্ঠা &ldquo;ক্ষমতা&rdquo; সাইট web.dev এর বিভাগ।

কিন্তু সেখানেই শেষ হয় না। আপডেটের জন্য এখনও প্রচারিত হয়নি, আপনি আমাদের ফুগু API ট্র্যাকার অ্যাক্সেস করতে পারেন সমস্ত প্রস্তাবের লিঙ্ক সহ যেগুলি পাঠানো হয়েছে, মূল ট্রায়াল বা ডেভ ট্রায়ালে রয়েছে, সমস্ত প্রস্তাব যার উপর কাজ শুরু হয়েছে, এবং সবকিছু বিবেচনা করা হচ্ছে, কিন্তু এখনও শুরু হয়নি৷

Fugu API ট্র্যাকার ওয়েবসাইট

এই কোডল্যাবটি টমাস স্টেইনার ( @টোমায়াক ) দ্বারা লেখা হয়েছে, আমি আপনার প্রশ্নের উত্তর দিতে পেরে খুশি এবং আপনার প্রতিক্রিয়া পড়ার জন্য উন্মুখ! হেমন্থ HM ( @GNUmanth ), ক্রিশ্চিয়ান লাইবেল ( @christianliebel ), Sven May ( @Svenmay ), লারস নুডসেন ( @larsgk ), এবং জ্যাকি হ্যান ( @hanguokai ) কে বিশেষ ধন্যবাদ যারা এই কোডল্যাবটি তৈরি করতে সাহায্য করেছেন!