Máy tính Designcember

Một nỗ lực mô phỏng để tạo lại máy tính năng lượng mặt trời trên web bằng API Lớp phủ điều khiển cửa sổ và API Cảm biến ánh sáng xung quanh.

Thách thức

Tôi là một đứa trẻ của thập niên 1980. Một thứ rất thịnh hành khi tôi còn học trường trung học là máy tính bỏ túi dùng năng lượng mặt trời. Trường phát cho chúng tôi mỗi người một chiếc máy tính TI-30X SOLAR. Tôi vẫn nhớ như in những kỷ niệm đẹp khi chúng tôi so sánh máy tính của nhau bằng cách tính giai thừa của 69, con số lớn nhất mà máy tính TI-30X có thể xử lý. (Sự khác biệt về tốc độ là rất rõ ràng, tôi vẫn không biết tại sao.)

Giờ đây, sau gần 28 năm, tôi nghĩ sẽ là một thử thách thú vị trong Designcember khi tạo lại máy tính bằng HTML, CSS và JavaScript. Vì không phải là một nhà thiết kế, nên tôi không bắt đầu từ đầu, mà bắt đầu bằng một CodePen của Sassja Ceballos.

Chế độ xem CodePen với các bảng HTML, CSS và JS xếp chồng lên nhau ở bên trái và bản xem trước máy tính ở bên phải.

Giúp ứng dụng có thể cài đặt được

Dù đây không phải là một khởi đầu tồi, nhưng tôi quyết định nâng cấp để có được giao diện mô phỏng hoàn hảo. Bước đầu tiên là biến ứng dụng thành PWA để có thể cài đặt.

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

Kết hợp với thiết bị di động

Giờ đây, khi ứng dụng có thể cài đặt được, bước tiếp theo là làm cho ứng dụng hoà hợp với các ứng dụng của hệ điều hành nhiều nhất có thể. Trên thiết bị di động, tôi có thể thực hiện việc này bằng cách đặt chế độ hiển thị thành fullscreen trong Tệp kê khai ứng dụng web.

{
  "display": "fullscreen"
}

Trên các thiết bị có lỗ hoặc rãnh camera, việc điều chỉnh khung nhìn để nội dung bao phủ toàn bộ màn hình sẽ giúp ứng dụng trông đẹp mắt hơn.

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

Máy tính Designcember chạy ở chế độ toàn màn hình trên điện thoại Pixel 6 Pro.

Kết hợp với máy tính

Trên máy tính, có một tính năng thú vị mà tôi có thể sử dụng: Lớp phủ điều khiển cửa sổ, cho phép tôi đặt nội dung vào thanh tiêu đề của cửa sổ ứng dụng. Bước đầu tiên là ghi đè trình tự dự phòng của chế độ hiển thị để chế độ này cố gắng sử dụng window-controls-overlay trước khi có sẵn.

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

Thao tác này sẽ khiến thanh tiêu đề biến mất một cách hiệu quả và nội dung sẽ di chuyển lên vùng thanh tiêu đề như thể thanh tiêu đề không có ở đó. Ý tưởng của tôi là di chuyển pin mặt trời mô phỏng lên thanh tiêu đề và phần còn lại của giao diện người dùng máy tính xuống tương ứng. Tôi có thể thực hiện việc này bằng một số CSS sử dụng các biến môi trường titlebar-area-*. Bạn sẽ thấy rằng tất cả bộ chọn đều có một lớp wco, lớp này sẽ có liên quan đến một vài đoạn văn bên dưới.

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

Tiếp theo, tôi cần quyết định phần tử nào có thể kéo được, vì thanh tiêu đề mà tôi thường dùng để kéo không có sẵn. Theo kiểu tiện ích cổ điển, tôi thậm chí có thể làm cho toàn bộ máy tính có thể kéo được bằng cách áp dụng (-webkit-)app-region: drag, ngoại trừ các nút có (-webkit-)app-region: no-drag để không thể dùng để kéo.

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

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

Bước cuối cùng là làm cho ứng dụng phản ứng với các thay đổi về lớp phủ điều khiển cửa sổ. Trong phương pháp cải tiến tăng dần thực sự, tôi chỉ tải mã cho tính năng này khi trình duyệt hỗ trợ.

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

Bất cứ khi nào hình dạng lớp phủ điều khiển cửa sổ thay đổi, tôi đều sửa đổi ứng dụng để ứng dụng trông tự nhiên nhất có thể. Bạn nên loại bỏ sự kiện này vì sự kiện này có thể được kích hoạt thường xuyên khi người dùng đổi kích thước cửa sổ. Cụ thể, tôi áp dụng lớp wco cho một số phần tử, vì vậy, CSS của tôi từ trên sẽ bắt đầu và tôi cũng thay đổi màu giao diện. Tôi có thể phát hiện xem lớp phủ điều khiển cửa sổ có hiển thị hay không bằng cách kiểm tra thuộc tính 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();

Giờ đây, khi đã có tất cả những thứ này, tôi có một tiện ích máy tính gần giống với Winamp cổ điển với một trong những giao diện Winamp cũ. Giờ đây, tôi có thể thoải mái đặt máy tính trên màn hình và kích hoạt tính năng điều khiển cửa sổ bằng cách nhấp vào biểu tượng chữ V ở góc trên bên phải.

Máy tính Designcember chạy ở chế độ độc lập và có bật tính năng Lớp phủ điều khiển cửa sổ. Màn hình hiển thị chữ &quot;Google&quot; bằng bảng chữ cái của máy tính.

Một pin mặt trời thực sự hoạt động

Để thể hiện đúng chất mọt sách, tất nhiên tôi cần phải làm cho pin mặt trời thực sự hoạt động. Máy tính chỉ hoạt động khi có đủ ánh sáng. Cách tôi mô hình hoá việc này là đặt opacity CSS của các chữ số trên màn hình thông qua một biến CSS --opacity mà tôi kiểm soát qua JavaScript.

:root {
  --opacity: 0.75;
}

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

Để phát hiện xem có đủ ánh sáng cho máy tính hoạt động hay không, tôi sử dụng API AmbientLightSensor. Để API này hoạt động, tôi cần đặt cờ #enable-generic-sensor-extra-classes trong about:flags và yêu cầu quyền 'ambient-light-sensor'. Như trước, tôi sử dụng tính năng nâng cao tăng dần để chỉ tải mã có liên quan khi API được hỗ trợ.

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

Cảm biến trả về ánh sáng xung quanh theo đơn vị lux bất cứ khi nào có giá trị đo mới. Dựa trên bảng giá trị của các tình huống ánh sáng thông thường, tôi đã đưa ra một công thức rất đơn giản để chuyển đổi giá trị lux thành một giá trị từ 0 đến 1 mà tôi gán theo phương thức lập trình cho biến --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();
  }
})();

Trong video dưới đây, bạn có thể thấy máy tính bắt đầu hoạt động khi tôi bật đèn phòng đủ sáng. Vậy là bạn đã có một máy tính năng lượng mặt trời theo phong cách mô phỏng thực tế và hoạt động được. Chiếc máy tính TI-30X SOLAR cũ kỹ nhưng đáng tin cậy của tôi quả thực đã đi được một chặng đường dài.

Bản minh hoạ

Hãy nhớ dùng thử bản minh hoạ Máy tính Designcember và xem mã nguồn trên GitHub. (Để cài đặt ứng dụng, bạn cần mở ứng dụng trong cửa sổ riêng. Phiên bản được nhúng bên dưới sẽ không kích hoạt thanh thông tin nhỏ.)

Chúc bạn có một mùa Designcember vui vẻ!