Designcember Hesap Makinesi

Window Controls Overlay API ve Ambient Light Sensor API ile web'de güneş hesaplayıcıyı yeniden oluşturmaya yönelik skeuomorf bir girişim.

Yarışma

1980'lerin çocuğuyum. Lisedeyken güneş enerjili hesap makineleri çok popülerdi. Okulda hepimize bir TI-30X SOLAR verildi. TI-30X'in kaldırabildiği en yüksek sayı olan 69'un faktöriyel değerini hesaplayarak hesap makinelerimizi birbiriyle karşılaştırdığımız anılar hâlâ aklımda. (Hız varyansı çok ölçülebilirdi, nedenini hâlâ bilmiyorum.)

Şimdi, yaklaşık 28 yıl sonra, hesap makinesini HTML, CSS ve JavaScript ile yeniden oluşturmanın Designcember yarışması için eğlenceli bir meydan okuma olacağını düşündüm. Tasarımcı olmadığım için sıfırdan başlamadım. Bunun yerine, Sassja Ceballos tarafından oluşturulan bir CodePen'i kullandım.

Sol tarafta yığın halinde HTML, CSS ve JS panelleri, sağ tarafta ise hesap makinesi önizlemesi bulunan CodePen görünümü.

Uygulamanızın yüklenmeye uygun olmasını sağlayın

Kötü bir başlangıç olmasa da skeuomorfik harikalığı tam anlamıyla yansıtmak için daha da geliştirmeye karar verdim. İlk adım, yüklenebilmesi için uygulamayı PWA'ya dönüştürmekti. Hızlı bir demoya ihtiyacım olduğunda remikslediğim Glitch'te temel bir PWA şablonu kullanıyorum. Hizmet çalışanı size kodlama ödülü kazandırmaz ve kesinlikle üretime hazır değildir. Ancak uygulamanın yüklenebilmesi için Chromium'un mini bilgi çubuğunu tetiklemeye yeterlidir.

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');
      }
    })(),
  );
});

Mobil cihazlarla uyumlu hale getirme

Uygulama yüklenmeye hazır olduğunda bir sonraki adım, uygulamayı işletim sistemi uygulamalarıyla mümkün olduğunca uyumlu hale getirmektir. Mobil cihazlarda bunu, web uygulaması manifest dosyasında görüntüleme modunu fullscreen olarak ayarlayarak yapabilirim.

{
  "display": "fullscreen"
}

Kamera deliği veya çentiği olan cihazlarda, içeriğin tüm ekranı kaplayacak şekilde görünüm alanını ayarlayarak uygulamanızın muhteşem görünmesini sağlayabilirsiniz.

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

Pixel 6 Pro telefonda tam ekran çalışan Designcember Calculator.

Masaüstüyle uyumlulaştırma

Masaüstünde kullanabileceğim harika bir özellik var: Pencere denetimi yer paylaşımı. Bu özellik, uygulama penceresinin başlık çubuğuna içerik yerleştirmeme olanak tanır. İlk adım, ekran modu yedek sırasını geçersiz kılarak mevcut olduğunda önce window-controls-overlay kullanmayı denemektir.

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

Bu sayede başlık çubuğu etkili bir şekilde kaybolur ve içerik, başlık çubuğu yokmuş gibi başlık çubuğu alanına taşınır. Skeuomorfik güneş hücresini başlık çubuğuna, hesap makinesinin kullanıcı arayüzünün geri kalanını da buna göre aşağıya taşımak istiyorum. Bunu, titlebar-area-* ortam değişkenlerini kullanan bazı CSS'lerle yapabilirim. Tüm seçicilerde bir wco sınıfı olduğunu fark edeceksiniz. Bu sınıf, birkaç paragraf aşağıda ele alınacaktır.

#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);
}

Ardından, genellikle sürüklemek için kullanacağım başlık çubuğu kullanılamadığından hangi öğelerin sürüklenebileceğine karar vermem gerekiyor. Klasik widget tarzında, (-webkit-)app-region: drag uygulayarak hesap makinesinin tamamını bile sürüklenebilir hale getirebilirim. (-webkit-)app-region: no-drag alan düğmeler ise sürüklemek için kullanılamaz.

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

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

Son adım, uygulamanın pencere denetimi yer paylaşımı değişikliklerine tepki vermesini sağlamaktır. Gerçek bir aşamalı geliştirme yaklaşımında, bu özelliğin kodunu yalnızca tarayıcı desteklediğinde yüklerim.

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

Pencere denetimleri yer paylaşımı geometrisi her değiştiğinde, uygulamayı mümkün olduğunca doğal görünecek şekilde değiştiriyorum. Kullanıcı pencereyi yeniden boyutlandırdığında sık sık tetiklenebileceğinden bu etkinliğin gecikmesini ayarlamak iyi bir fikirdir. Yani bazı öğelere wco sınıfını uygulayarak yukarıdaki CSS'mi etkinleştiriyorum ve tema rengini de değiştiriyorum. Pencere kontrolleri yer paylaşımının görünür olup olmadığını navigator.windowControlsOverlay.visible mülkünü kontrol ederek algılayabilirim.

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();

Tüm bu işlemleri tamamladıktan sonra, eski Winamp temalarından biriyle klasik Winamp'a benzeyen bir hesap makinesi widget'ı elde ettim. Artık hesap makinesini masaüstüme istediğim yere yerleştirebiliyor ve sağ üst köşedeki yukarı bakan oku tıklayarak pencere denetimleri özelliğini etkinleştirebiliyorum.

Pencere Denetimleri Yer Paylaşımı özelliği etkinken bağımsız modda çalışan Designcember Hesap Makinesi. Ekranda hesap makinesi alfabesinde &quot;Google&quot; yazıyor.

Gerçekten çalışan bir güneş pili

Elbette, bu projenin tam anlamıyla bir teknoloji tutkunu projesi olması için güneş hücresinin gerçekten çalışmasını sağlamam gerekiyordu. Hesap makinesi yalnızca yeterli ışık varsa çalışır. Bunu modelleme şeklim, ekrandaki basamakların CSS'sini opacity, JavaScript aracılığıyla kontrol ettiğim bir CSS değişkeni --opacity aracılığıyla ayarlamaktı.

:root {
  --opacity: 0.75;
}

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

Hesap makinesinin çalışması için yeterli ışık olup olmadığını tespit etmek üzere AmbientLightSensor API'yi kullanıyorum. Bu API'nin kullanılabilir olması için about:flags'te #enable-generic-sensor-extra-classes işaretini ayarlamam ve 'ambient-light-sensor' iznini istemem gerekiyordu. Daha önce olduğu gibi, yalnızca API desteklendiğinde ilgili kodu yüklemek için aşamalı geliştirmeyi kullanıyorum.

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

Sensör, yeni bir ölçüm olduğunda ortam ışığını lüks birimlerinde döndürür. Tipik ışık koşullarına ait bir değer tablosuna dayanarak, lux değerini --opacity değişkenine programatik olarak atadığım 0 ile 1 arasında bir değere dönüştüren çok basit bir formül geliştirdim.

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();
  }
})();

Aşağıdaki videoda, oda ışığını yeterince açtıktan sonra hesap makinesinin nasıl çalışmaya başladığını görebilirsiniz. İşte bu kadar: Gerçekten çalışan skeuomorf bir güneş hesap makinesi. Zamana meydan okuyan eski TI-30X SOLAR'ım gerçekten çok yol kat etti.

Demo

Designcember hesap makinesi demosunu denemeyi ve Glitch'teki kaynak koduna göz atmayı unutmayın. (Uygulamayı yüklemek için kendi penceresinde açmanız gerekir. Aşağıdaki yerleştirilmiş sürüm mini bilgi çubuğunu tetiklemez.)

Tasarım Ayı kutlu olsun.