Как добавить в приложение переключатель тем, который наследует цветовую схему ОС в качестве состояния по умолчанию

Есть много хороших руководств по теме «темный режим», но редко те, которые охватывают две основные цели, на мой взгляд, такой реализации в реальном приложении. Это, соответственно, дает пользователям возможность переключаться между темами, наследуя по умолчанию цветовую схему ОС, заданную платформой, тем более, что и Google, и Apple начали развертывать такие режимы в своих продуктах.

Я пишу эту статью, чтобы поделиться решением, которое мы реализовали с помощью наших участников в нашем веб-редакторе с открытым исходным кодом для презентаций DeckDeckGo.

Начиная

Чтобы реализовать наше решение, мы используем два замечательных программного обеспечения:

  • Idb-keyval: суперпростое, небольшое хранилище ключей на основе обещаний, реализованное с помощью IndexedDB, которое мы используем для сохранения выбора пользователя.
  • RxJS: библиотека реактивных расширений для JavaScript, которую мы используем для хранения и распространения состояния, представляющего тему в памяти.

Мы собираемся использовать значение времени выполнения для переключения между темами. Следовательно, можно было бы реализовать такое решение, используя сохраненное состояние React Redux. Не сомневайтесь, пишите мне, если хотите получить такой пример; У меня также есть готовый вариант в другом новом приложении, которое я сейчас разрабатываю.

Синглтон-сервис

Чтобы управлять состоянием нашей темы, мы создаем одноэлементную службу Vanilla. Если вы используете фреймворк наподобие Angular, создайте службу с корневой областью, как обычно, или, если вы предпочитаете использовать функции и статические значения, сделайте это. Важно загрузить и сохранить в памяти только одно состояние, представляющее применяемую тему для всех ваших приложений.

В нашем сервисе мы объявляем логическое значение darkTheme, которое со значением true означает «активна темная тема», а false - «активна светлая тема». Мы могли бы использовать enum, если бы было доступно более двух тем. Возможность расширения - отличное преимущество этой реализации.

Обратите внимание, что мы используем ReplaySubject<1>, так как хотим сохранить в памяти ровно одно состояние без значения, пока не выясним, какую тему применить.

Наблюдать и переключать состояние

Теперь, когда наша служба готова, мы должны раскрыть состояние приложения и предоставить пользователям метод переключения темы. Мы также должны сохранить выбор, чтобы он загрузился при следующем перезапуске приложения.

Начальное предпочтение

Во время загрузки мы должны загрузить тему в соответствии со следующими шагами:

  • У пользователя уже есть предпочтительная тема?
  • Не смогли ли мы прочитать эту информацию (возникает ли ошибка)?
  • Следует ли использовать цветовую схему ОС по умолчанию, предоставляемую платформой?

Ответив на эти вопросы, мы создаем функцию, реализующую эту логику, и используем наш предыдущий метод switch для распространения темы.

Примените тему к DOM

Мы специально не применяли тему «графически» в нашем сервисе. Следовательно, теперь мы должны решить, где мы хотим применить модификацию к DOM.

В наших проектах, поскольку мы разрабатывали наши приложения с веб-компонентами Stencil, мы начали инициализацию в корневом компоненте (app-root.tsx).

Более того, мы следим за изменениями в этом же компоненте, так как он не будет уничтожен, пока приложение не будет закрыто. Таким образом, при каждом новом генерируемом состоянии мы модифицируем нашу DOM, а точнее элемент body, чтобы применить или удалить имя класса CSS (в нашем случае dark).

Переключатель тем

До сих пор наше приложение могло обрабатывать только цветовую схему, предпочитаемую ОС, и не давало пользователям возможности переключать темы. Вот почему мы создадим новый компонент, который предоставляет, например, Ионный переключатель для переключения между светлым и темным режимами.

Укладка

Вы можете стилизовать темы с помощью переменных CSS или даже просто свойств. В обоих случаях важно применить тему в соответствии с именами классов, которые мы только что установили для элемента body, соответственно dark.

Если вы используете Ionic, вы сможете стилизовать определенный фон и цвет текста в вашем variables.scss (:root без селектора, являющегося светлой темой):

Или другой пример в простом HTML / CSS:

Все вместе

Наш проект DeckDeckGo имеет открытый исходный код. Поэтому позвольте мне поделиться с вами приведенной выше реализацией с некоторыми ссылками на GitHub нашего пульта дистанционного управления:

Вишня на торте

Возможно, вы на самом деле не заинтересованы в разделении кода на разные слои и просто хотите иметь один-единственный веб-компонент, который позаботится обо всем.

Угадай, что? У нас тоже есть такой компонент, который мы реализовали в нашей документации для разработчиков.

Кредиты

Как указано выше, мы разработали эту функцию с помощью наших участников, точнее с помощью Grant Herman. Он даже помог нам реализовать его в трех разных приложениях.

Определенно не все герои носят плащи; спасибо, Грант.