Создание виджета темы сайта на Yii2

Краткий обзор создания виджета в Yii2 по переключению дневной/ночной темы сайта и некоторые нюансы при работе с куками


Вдохновило меня на написание переключалки ночной/дневной темы блога расширение Dark Reader. Он в приятном тёмном цвете представляет любой сайт, но бывает так, что на некоторых ресурсах может делать менее заметными ключевые детали, как например, некоторые заголовки и блоки с важной информацией, да и к тому же посетители сайта могут зайти из отличных от chrome/chromium браузеров. В принципе, я считаю что каждый уважаемый ресурс должен предоставлять своим пользователям такую фичу, а в приложениях (десктоп/мобильные) так и тем более. Поэтому с этой точки зрения, необходимо детально проработать собственную ночную тему таким образом, чтобы пользователям было комфортно читать страницы сайта и, что не менее важно, находить необходимую информацию.

Поделюсь реализацией виджета в Yii2, а именно старенькой 2.0.10 версии и некоторыми нюансами при работе с куками, которые у меня возникли в этом фреймворке. Сам виджет очень простой и представляет собой блок html кода, описывающий заголовок и две кнопки, для светлой (по умолчанию) и тёмной темы сайта:

widget

В layout сайта, в области вывода стилей нужно сделать проверку на то что в куках зарегистрировано интересующее значение, активирующее темную тему, подключением специального файла стилей (для каждого сайта этот файл, конечно же свой, который переписывает все стили, которые относились к светлой теме):

$modeStateCookie = (array_key_exists('mode_state', $_COOKIE)) ? $_COOKIE['mode_state'] : null;
$isNightMode = $modeStateCookie === 'need_night';
if ($isNightMode) : ?>
   <link rel="stylesheet" href="/css/night.css">
<? endif; ?>

По умолчанию валидация кук в yii включена и с этим связано получение куки напрямую из супер глобального массива. Валидацию можно отключить, установив свойство yii\web\Request::$enableCookieValidation в false, но делать это не рекомендуется (почитать об этом можно здесь https://www.yiiframework.com/doc/guide/2.0/ru/runtime-sessions-cookies#cookie-validation). Поэтому для этого решения можно поработать с куками на чистом php, $_COOKIE, вместо объектно-ориентированного интерфейса во фреймворке, типа взять куки таким образом из request компонента: $cookies = Yii::$app->request->cookies;. Сначала, я не мог понять почему на бэкенде не могу прочитать куку в таком варианте, пока не отключил валидацию. Вообщем, я несколько был удивлён этим странным явлением, которое явно не прибавляет баллов в моей оценке yii2.. Но это лишь моя субъективная оценка.

Там где должен выводиться виджет, подключаем вызов статического метода из класса компонента LightDarkModeArea, которой мы объявим позже и прокидываем ему нашу куку:

<?=LightDarkModeArea::widget(['modeCookie' => $modeStateCookie])?>

И в области скриптов:

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="/js/lightnight.js"></script>

Файл lightnight.js. Собственно установка/переключение куки:

$(function () {
    function handlerClickButton() {
        var mode = $(this).attr('id');
        if (mode === 'night-mode') {
            $.cookie("mode_state", "need_night", {path: '/'});
        } else {
            $.cookie("mode_state", "need_light", {path: '/'});
        }
        window.location.reload();
    }
    $('.night-mode-widget .btn').on('click', handlerClickButton);
});

Компонент LightDarkModeArea.php:

namespace app\components;

use yii\base\Widget;

class LightDarkModeArea extends Widget
{

    public $isDarkTheme = false;

    public $modeCookie;

    public function init()
    {
        parent::init();
        if ($this->modeCookie === 'need_night') {
            $this->isDarkTheme = true;
        }
    }

    public function run()
    {
        ob_start();
        ?>
        <div class="night-mode-widget">
            <h3>Тема сайта:</h3>
            <div class="btn-group" data-toggle="buttons">
                <label id="light-mode" class="btn <?= ($this->isDarkTheme) ? '' : 'active' ?>">
                    <img src="/icons/light.svg" alt="light mode" title="День" width="25">
                    <input type="radio" name="options" id="light-mode-option" autocomplete="off">
                </label>
                <label id="night-mode" class="btn <?= ($this->isDarkTheme) ? 'active' : '' ?>">
                    <img src="/icons/night.svg" alt="night mode" title="Ночь" width="25">
                    <input type="radio" name="options" id="night-mode-option" autocomplete="off">
                </label>
            </div>
        </div>
        <?
        return ob_get_clean();
    }

}

Компонент рисует html и в зависимости от проброшенной ему куки из основного шаблона, делает активной кнопку дневной или ночной темы.

Вот в целом и весь механизм, останется добавить иконки light и night.



Похожие заметки:

Корзина на сайте — часть 2

В статье рассказывается как c помощью simpleCart.js делать такие вещи:

  • Выводить товары в том виде, в котором вам надо
  • Обрабатывать переданные товары и возвращать результат
  • Делать дальнейшие операции с заказом

Открыть здесь

Скрипт динамической ширины

Скрипт для равномерного распределения блоков по ширине родительского контейнера. В качестве контейнера может выступать любой блок как определенной ширины, так и неопределенной, вплоть до body. Что умеет?

  • Нарезать блоки на одинаковую ширину в зависимости от заданного количества колонок
  • Генерировать нужное количество колонок
  • Проставлять clearfix после оканчивающей ряд колонки, чтобы вовремя отменить обтекание
  • Удалять лишние clearfix

Открыть здесь

Корзина на сайте — часть 1

В статье рассказывается как создать JavaScript корзину на сайте с помощью плагина simpleCart.js

Открыть здесь


Перед тем как писать комментарии, рекомендую ознакомиться:

Markdown синтаксис »

Оформление кода »

Нужна аватарка »

Комментарии