Designcember ক্যালকুলেটর

উইন্ডো কন্ট্রোল ওভারলে API এবং অ্যাম্বিয়েন্ট লাইট সেন্সর API-এর সাহায্যে ওয়েবে সোলার ক্যালকুলেটর রিক্রিয়েট করার একটি স্কিউমর্ফিক প্রচেষ্টা।

চ্যালেঞ্জ

আমি ১৯৮০-র দশকের বাচ্চা। আমি যখন হাই স্কুলে পড়তাম তখন সোলার ক্যালকুলেটর খুব জনপ্রিয় ছিল। স্কুল থেকে আমাদের সবাইকে একটি করে TI-30X SOLAR দেওয়া হয়েছিল, এবং আমার মনে আছে যে আমরা একে অপরের ক্যালকুলেটরের ক্ষমতা পরীক্ষা করার জন্য ৬৯-এর ফ্যাক্টোরিয়াল হিসেব করতাম, কারণ TI-30X-এ এর চেয়ে বড় সংখ্যার হিসেব করা যেত না। (স্পিডের তারতম্য খুব সহজেই পরিমাপ করা যাচ্ছিল, এখনও জানি না কেন।)

এখন, প্রায় ২৮ বছর পরে, আমি ভাবলাম যে HTML, CSS ও JavaScript-এ ক্যালকুলেটরটি আবার তৈরি করা Designcember-এর একটি মজাদার চ্যালেঞ্জ হবে। আমি খুব ভালো ডিজাইনার নই, তাই আমি একদম শুরু থেকে শুরু করিনি, বরং Sassja Ceballos-এর CodePen ব্যবহার করেছি।

CodePen ভিউতে বাঁদিকে স্ট্যাক করা HTML, CSS ও JS প্যানেল এবং ডানদিকে ক্যালকুলেটর প্রিভিউ দেখানো হয়েছে।

এটি ইনস্টল করার উপযুক্ত করুন

শুরুটা খারাপ না হলেও, আমি এটিকে আরও উন্নত করে সম্পূর্ণ স্কিউমর্ফিক করার সিদ্ধান্ত নিয়েছি। প্রথম ধাপ ছিল এটিকে PWA করা যাতে এটি ইনস্টল করা যায়।

self.addEventListener('install', (event) => {
  self.skipWaiting();
});

self.addEventListener('activate', (event) => {
  self.clients.claim();
  event.waitUntil(
    (async () => {
      if ('navigationPreload' in self.registration) {
        await self.registration.navigationPreload.enable();
      }
    })(),
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    (async () => {
      try {
        const response = await event.preloadResponse;
        if (response) {
          return response;
        }
        return fetch(event.request);
      } catch {
        return new Response('Offline');
      }
    })(),
  );
});

মোবাইলের সাথে ব্লেন্ড করা হচ্ছে

অ্যাপটি এখন ইন্সটল করা যাবে, পরবর্তী ধাপ হল এটিকে অপারেটিং সিস্টেম অ্যাপের সাথে যতটা সম্ভব মিশিয়ে দেওয়া। মোবাইলে, আমি ওয়েব অ্যাপ ম্যানিফেস্টে ডিসপ্লে মোড fullscreen-এ সেট করে এটি করতে পারি।

{
  "display": "fullscreen"
}

ক্যামেরা হোল বা নচ আছে এমন ডিভাইসে, ভিউ পোর্ট টুইক করা যাতে কন্টেন্ট পুরো স্ক্রিন কভার করে, অ্যাপটিকে দেখতে সুন্দর করে তোলে।

<meta name="viewport" content="initial-scale=1, viewport-fit=cover" />

Pixel 6 Pro ফোনে ফুলস্ক্রিনে Designcember Calculator চলছে।

ডেস্কটপের সাথে ব্লেন্ড করা হচ্ছে

ডেস্কটপে, আমি একটি দুর্দান্ত ফিচার ব্যবহার করতে পারি: উইন্ডো কন্ট্রোল ওভারলে, যা আমাকে অ্যাপ উইন্ডোর টাইটেল বারে কন্টেন্ট রাখতে দেয়। প্রথম ধাপ হল ডিসপ্লে মোড ফলব্যাক সিকোয়েন্স ওভাররাইড করা যাতে এটি উপলভ্য হলে প্রথমে window-controls-overlay ব্যবহার করার চেষ্টা করে।

{
  "display_override": ["window-controls-overlay"]
}

এর ফলে টাইটেল বার কার্যকরভাবে চলে যায় এবং কন্টেন্ট টাইটেল বারের জায়গায় চলে আসে, যেন টাইটেল বার সেখানে ছিলই না। আমার আইডিয়া হল, স্কিউমর্ফিক সোলার সেলকে টাইটেল বারে নিয়ে যাওয়া এবং ক্যালকুলেটর UI-এর বাকি অংশকে সেই অনুযায়ী নিচে নিয়ে আসা। আমি কিছু CSS ব্যবহার করে এটি করতে পারি, যা titlebar-area-* এনভায়রনমেন্ট ভেরিয়েবল ব্যবহার করে। আপনি লক্ষ্য করবেন যে সব সিলেক্টরে wco ক্লাস আছে, যা কয়েকটি প্যারাগ্রাফের পরে প্রাসঙ্গিক হবে।

#calc_solar_cell.wco {
  position: fixed;
  left: calc(0.25rem + env(titlebar-area-x, 0));
  top: calc(0.75rem + env(titlebar-area-y, 0));
  width: calc(env(titlebar-area-width, 100%) - 0.5rem);
  height: calc(env(titlebar-area-height, 33px) - 0.5rem);
}

#calc_display_surface.wco {
  margin-top: calc(env(titlebar-area-height, 33px) - 0.5rem);
}

এরপর, আমাকে সিদ্ধান্ত নিতে হবে যে কোন এলিমেন্ট ড্র্যাগেবল করতে হবে, কারণ আমি সাধারণত ড্র্যাগ করার জন্য যে টাইটেল বার ব্যবহার করি তা উপলভ্য নেই। ক্লাসিক উইজেটের স্টাইলে, আমি এমনকি (-webkit-)app-region: drag প্রয়োগ করে পুরো ক্যালকুলেটরকে ড্র্যাগেবল করতে পারি, বোতামগুলি ছাড়া, যেগুলি (-webkit-)app-region: no-drag পায়, তাই সেগুলি ড্র্যাগ করার জন্য ব্যবহার করা যাবে না।

#calc_inside.wco,
#calc_solar_cell.wco {
  -webkit-app-region: drag;
  app-region: drag;
}

button {
  -webkit-app-region: no-drag;
  app-region: no-drag;
}

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

if ('windowControlsOverlay' in navigator) {
  import('/wco.js');
}

যখনই উইন্ডো কন্ট্রোল ওভারলে জিওমেট্রি পরিবর্তন হয়, আমি অ্যাপটি পরিবর্তন করি যাতে এটি যতটা সম্ভব স্বাভাবিক দেখায়। এই ইভেন্ট ডিবাউন্স করা ভাল, কারণ ব্যবহারকারী উইন্ডো ছোট বড় করলে এটি ঘন ঘন ট্রিগার হতে পারে। যেমন, আমি কিছু এলিমেন্টে wco ক্লাস প্রয়োগ করি, যাতে আমার CSS উপরে থেকে শুরু হয় এবং আমি থিমের রঙও পরিবর্তন করি। navigator.windowControlsOverlay.visible প্রপার্টি চেক করে আমি শনাক্ত করতে পারি যে উইন্ডো কন্ট্রোল ওভারলে দেখা যাচ্ছে কিনা।

const meta = document.querySelector('meta[name="theme-color"]');
const nodes = document.querySelectorAll(
  '#calc_display_surface, #calc_solar_cell, #calc_outside, #calc_inside',
);

const toggleWCO = () => {
  if (!navigator.windowControlsOverlay.visible) {
    meta.content = '';
  } else {
    meta.content = '#385975';
  }
  nodes.forEach((node) => {
    node.classList.toggle('wco', navigator.windowControlsOverlay.visible);
  });
};

const debounce = (func, wait) => {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
};

navigator.windowControlsOverlay.ongeometrychange = debounce((e) => {
  toggleWCO();
}, 250);

toggleWCO();

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

উইন্ডো কন্ট্রোল ওভারলে ফিচার চালু থাকা অবস্থায় Designcember Calculator স্ট্যান্ডঅ্যালোন মোডে চলছে। ডিসপ্লেতে ক্যালকুলেটর অ্যালফাবেটে 'Google' লেখা আছে।

আসলে কাজ করে এমন সৌর কোষ

চূড়ান্ত গিক হওয়ার জন্য, আমাকে অবশ্যই সোলার সেলটি আসলে কাজ করাতে হবে। পর্যাপ্ত আলো থাকলে তবেই ক্যালকুলেটর কাজ করবে। আমি যেভাবে এটি মডেল করেছি তা হল, ডিসপ্লেতে থাকা সংখ্যার CSS opacity সেট করার মাধ্যমে, একটি CSS ভেরিয়েবল --opacity-এর মাধ্যমে যা আমি জাভাস্ক্রিপ্টের মাধ্যমে নিয়ন্ত্রণ করি।

:root {
  --opacity: 0.75;
}

#calc_expression,
#calc_result {
  opacity: var(--opacity);
}

ক্যালকুলেটর কাজ করার জন্য পর্যাপ্ত আলো আছে কিনা তা শনাক্ত করতে, আমি AmbientLightSensor API ব্যবহার করি। এই API উপলভ্য করার জন্য, আমাকে about:flags-এ #enable-generic-sensor-extra-classes ফ্ল্যাগ সেট করতে এবং 'ambient-light-sensor' অনুমতির জন্য অনুরোধ করতে হয়েছিল। আগের মতোই, API কাজ করলে, আমি প্রাসঙ্গিক কোড লোড করার জন্য প্রোগ্রেসিভ এনহ্যান্সমেন্ট ব্যবহার করি।

if ('AmbientLightSensor' in window) {
  import('/als.js');
}

নতুন রিডিং উপলভ্য হলেই সেন্সর লাক্স ইউনিটে অ্যাম্বিয়েন্ট লাইট রিটার্ন করে। সাধারণ আলোর পরিস্থিতির ভ্যালুর টেবিল-এর উপর ভিত্তি করে, আমি লাক্স ভ্যালুকে ০ থেকে ১-এর মধ্যে একটি ভ্যালুতে পরিবর্তন করার জন্য একটি খুব সহজ ফর্মুলা তৈরি করেছি যা আমি প্রোগ্রাম্যাটিক্যালি --opacity ভেরিয়েবলে অ্যাসাইন করি।

const luxToOpacity = (lux) => {
  if (lux > 250) {
    return 1;
  }
  return lux / 250;
};

const sensor = new window.AmbientLightSensor();
sensor.onreading = () => {
  console.log('Current light level:', sensor.illuminance);
  document.documentElement.style.setProperty(
    '--opacity',
    luxToOpacity(sensor.illuminance),
  );
};
sensor.onerror = (event) => {
  console.log(event.error.name, event.error.message);
};

(async () => {
  const {state} = await navigator.permissions.query({
    name: 'ambient-light-sensor',
  });
  if (state === 'granted') {
    sensor.start();
  }
})();

নিচের ভিডিওতে আপনি দেখতে পাবেন যে রুমের আলো যথেষ্ট উজ্জ্বল করার সাথে সাথেই ক্যালকুলেটর কীভাবে কাজ করতে শুরু করে। আর এই যে আপনার কাছে এটি আছে: একটি স্কিউমর্ফিক সোলার ক্যালকুলেটর যা আসলে কাজ করে। আমার পুরনো বিশ্বস্ত TI-30X SOLAR ক্যালকুলেটরটি সত্যিই অনেকদিন ধরে চলছে।

ডেমো

Designcember Calculator ডেমো ব্যবহার করে দেখতে ভুলবেন না এবং GitHub-এ সোর্স কোড চেক করে দেখুন। (অ্যাপ ইনস্টল করতে, আপনাকে এটি নিজস্ব উইন্ডোতে খুলতে হবে। নিচে এম্বেড করা ভার্সনটি মিনি ইনফোবার ট্রিগার করবে না।)

Designcember-এর শুভেচ্ছা!