Дизайндекабрь Калькулятор

Скевоморфная попытка воссоздания солнечного калькулятора в сети с помощью API наложения элементов управления окнами и API датчика внешней освещенности.

Вызов

Я вырос в 80-х. В старших классах моей школы были очень популярны калькуляторы на солнечных батареях. В школе нам всем подарили TI-30X SOLAR , и я с теплотой вспоминаю, как мы сравнивали свои калькуляторы, вычисляя факториал 69 — максимального числа, которое мог обработать TI-30X. (Разброс в скорости был очень ощутимым, до сих пор не понимаю, почему.)

Теперь, почти 28 лет спустя, я подумал, что было бы интересно попробовать воссоздать калькулятор на HTML, CSS и JavaScript в рамках конкурса Designcember. Не будучи большим дизайнером, я начал не с нуля, а с 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" />

Калькулятор Designcember запущен в полноэкранном режиме на телефоне Pixel 6 Pro.

Смешивание с рабочим столом

На десктопе есть замечательная функция, которой я могу воспользоваться: Window Controls Overlay (Наложение элементов управления окна), которая позволяет размещать контент в заголовке окна приложения. Первым шагом является переопределение последовательности переключения режимов отображения, чтобы приложение сначала использовало window-controls-overlay когда он доступен.

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

Это фактически приводит к исчезновению заголовка, а содержимое перемещается в область заголовка, как будто его там нет. Моя идея заключается в том, чтобы переместить скевоморфную солнечную батарею в заголовок, а остальную часть интерфейса калькулятора — вниз. Это можно сделать с помощью 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, работающий в автономном режиме с активированной функцией наложения элементов управления окна. На дисплее отображается слово «Google» в алфавитном коде калькулятора.

Действительно работающая солнечная батарея

Для достижения максимального гик-эффекта мне, конечно же, нужно было заставить солнечную батарею работать. Калькулятор должен работать только при достаточном освещении. Я смоделировал это, установив opacity цифр на дисплее через CSS-переменную --opacity , которой я управляю через JavaScript.

:root {
  --opacity: 0.75;
}

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

Чтобы определить, достаточно ли освещённости для работы калькулятора, я использую API AmbientLightSensor . Для этого мне нужно было установить флаг #enable-generic-sensor-extra-classes в about:flags и запросить разрешение 'ambient-light-sensor' . Как и прежде, я использую прогрессивное улучшение, чтобы загружать соответствующий код только при поддержке API.

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

Датчик возвращает значение освещенности в люксах при каждом получении новых показаний. Основываясь на таблице значений типичных условий освещенности, я разработал очень простую формулу для преобразования значения люкс в значение от 0 до 1, которое программно присваиваю переменной --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 . (Чтобы установить приложение, необходимо открыть его в отдельном окне. Встроенная версия ниже не будет отображать мини-панель информации.)

Счастливого Дизайн-фестиваля !