Pencere Kontrolü Yerleşimi API'si ve Ortam Işığı Sensörü API'si ile web'de güneş enerjisi hesap makinesini yeniden oluşturmaya yönelik skeomorfik bir girişim.
Yarışma
1980'lerde büyüdüm. Lisedeyken çok popüler olan bir şey vardı: güneş enerjili hesap makineleri. Okulda hepimize TI-30X SOLAR verilmişti. TI-30X'in işleyebileceği en yüksek sayı olan 69'un faktöriyelini hesaplayarak hesap makinelerimizi birbirleriyle karşılaştırdığımız günleri özlemle hatırlıyorum. (Hız farkı çok ölçülebilirdi, nedenini hâlâ bilmiyorum.)
Aradan geçen 28 yılın ardından, hesap makinesini HTML, CSS ve JavaScript ile yeniden oluşturmanın eğlenceli bir Designcember meydan okuması olacağını düşündüm. Tasarımcı olmadığım için sıfırdan başlamadım. Sassja Ceballos'un CodePen'ini kullandım.
Yüklenebilir hale getirme
Kötü bir başlangıç olmasa da tam anlamıyla skeomorfik bir tasarım için daha da geliştirmeye karar verdim. İlk adım, yüklenebilmesi için PWA haline getirmekti.
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 cihazla harmanlama
Uygulama yüklenebilir hale geldiğine göre bir sonraki adım, uygulamanın işletim sistemi uygulamalarıyla mümkün olduğunca uyumlu olmasını sağlamaktır. Mobil cihazlarda, web uygulaması manifestinde görüntüleme modunu fullscreen
olarak ayarlayarak bunu yapabilirim.
{
"display": "fullscreen"
}
Kamera deliği veya çentik bulunan cihazlarda, içeriğin ekranın tamamını kaplayacak şekilde görünüm alanını ayarlamak uygulamanın harika görünmesini sağlar.
<meta name="viewport" content="initial-scale=1, viewport-fit=cover" />
Masaüstüyle uyum sağlama
Masaüstünde kullanabileceğim harika bir özellik var:
Pencere Denetimi Yer Paylaşımı. Bu özellik sayesinde, uygulama penceresinin başlık çubuğuna içerik yerleştirebiliyorum. İlk adım, ekran modu yedekleme sırasını geçersiz kılmaktır. Böylece, window-controls-overlay
kullanılabilir olduğunda önce bu mod kullanılmaya çalışılır.
{
"display_override": ["window-controls-overlay"]
}
Bu durumda 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. Fikrim, skeomorfik güneş pilini başlık çubuğuna, hesap makinesi kullanıcı arayüzünün geri kalanını da buna göre aşağıya taşımak. Bunu, titlebar-area-*
ortam değişkenlerini kullanan bazı CSS'lerle yapabilirim. Tüm seçicilerin wco
sınıfı taşıdığını 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, normalde sürüklemek için kullandığım başlık çubuğu mevcut olmadığından hangi öğelerin sürüklenebilir olacağına karar vermem gerekiyor. Klasik bir widget tarzında, düğmeler hariç tüm hesap makinesini (-webkit-)app-region: drag
uygulayarak sürüklenebilir hale getirebilirim. Düğmeler (-webkit-)app-region: no-drag
olarak ayarlanır, böylece sürüklemek için kullanılamazlar.
#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 kontrollerinin yerleşimi her değiştiğinde, uygulamanın mümkün olduğunca doğal görünmesi için değişiklik yapıyorum. Kullanıcı pencereyi yeniden boyutlandırdığında bu etkinlik sık sık tetiklenebileceğinden bu etkinliğin sıçrama önleme özelliğini kullanmanız önerilir. Yani bazı öğelere wco
sınıfını uyguluyorum. Böylece yukarıdaki CSS'm devreye giriyor ve tema rengini de değiştiriyorum. Pencere kontrolleri yer paylaşımının görünür olup olmadığını navigator.windowControlsOverlay.visible
özelliğini 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 bunları yaptıktan sonra, klasik Winamp'a benzeyen bir hesap makinesi widget'ı ve eski tarz Winamp temalarından birini kullanabiliyorum. Artık hesap makinesini masaüstüme istediğim gibi yerleştirebiliyor ve sağ üst köşedeki açılı işareti tıklayarak pencere kontrolleri özelliğini etkinleştirebiliyorum.
Gerçekten çalışan bir güneş pili
Elbette, en büyük geek'lik için güneş pilinin gerçekten çalışmasını sağlamam gerekiyordu. Hesap makinesi yalnızca yeterli ışık varsa çalışmalıdır. Bunu, JavaScript aracılığıyla kontrol ettiğim bir CSS değişkeni --opacity
üzerinden ekrandaki rakamların CSS'sini opacity
ayarlayarak yaptım.
:root {
--opacity: 0.75;
}
#calc_expression,
#calc_result {
opacity: var(--opacity);
}
Hesap makinesinin çalışması için yeterli ışık olup olmadığını algılamak amacıyla AmbientLightSensor
API'sini kullanıyorum. Bu API'nin kullanılabilmesi için about:flags
içinde #enable-generic-sensor-extra-classes
işaretini ayarlamam ve 'ambient-light-sensor'
iznini istemem gerekiyordu. Daha önce olduğu gibi, API desteklendiğinde yalnızca alakalı kodu yüklemek için aşamalı geliştirme kullanıyorum.
if ('AmbientLightSensor' in window) {
import('/als.js');
}
Sensör, yeni bir okuma olduğunda ortam ışığını lüks birimleriyle döndürür. Tipik ışık durumlarının değer tablosuna dayanarak lüks değerini 0 ile 1 arasında bir değere dönüştürmek için çok basit bir formül oluşturdum. Bu değeri --opacity
değişkenine programatik olarak atıyorum.
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ığımda hesap makinesinin nasıl çalışmaya başladığını görebilirsiniz. İşte bu kadar. Gerçekten çalışan bir skeomorfik güneş enerjili hesap makinesi. Eski ve güvenilir TI-30X SOLAR hesap makinem gerçekten çok yol katetti.
Demo
Designcember Calculator demosunu incelemeyi ve GitHub'daki 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.)
Mutlu Designcember!