Сохранение темы
По умолчанию Web Host определяет светлую/тёмную тему из theme_mode (умолчание фасада) и держит её
в памяти — поэтому явный выбор пользователя теряется при следующей перезагрузке. Сохранение темы позволяет этому
выбору пережить перезагрузки, храня его в cookie или в localStorage, и загружает его как можно
раньше, чтобы не было мигания неправильной темы.
Сохранение целиком живёт в фасаде. Web Host остаётся независимым от хранилища: он лишь порождает
событие themeChanged, которое фасад (или любая встраивающая сторона) использует для сохранения выбора.
По согласию.
theme_persistпо умолчанию равенnone— сохранение выключено, если развёртывание явно не установитcookieилиlocalStorage. При умолчании поведение ровно такое же, как раньше (тема всегда берётся изtheme_modeи не запоминается между перезагрузками). Ничего не сохраняется, cookie не записывается, а генерируемый скрипт ничего не делает, пока вы не включите эту возможность.
Настройка
Ею управляют два параметра фасада (см. Фронтенд-фасад):
| Параметр | По умолчанию | Значения | Описание |
|---|---|---|---|
theme_persist |
none |
none | cookie | localStorage |
Где хранится выбранный режим. none = текущее поведение. |
theme_storage_key |
@wippy-theme-mode |
string | Ключ cookie / localStorage. |
Оба возвращаются публичной конечной точкой конфигурации как themePersist и themeStorageKey, поэтому страницы,
раздаваемые вне Web Host, тоже могут их прочитать.
# в параметрах вашей зависимости фасада
- name: theme_persist
value: cookie
- name: theme_storage_key
value: "@wippy-theme-mode"
cookie против localStorage
cookie— отрисовываемая через Jet оболочка хоста читает cookie на стороне сервера и записывает классw-theme-*в<html>до отправки ответа, поэтому уже самая первая отрисовка идёт с темой. Без мигания. Лучший вариант по умолчанию.localStorage— сервер не может прочитать localStorage, поэтому сохранённое значение применяется синхронным встроенным скриптом как можно раньше. Кратковременное мигание технически возможно, но минимизировано.
Генерируемый скрипт
Когда сохранение включено, фасад генерирует и раздаёт небольшой скрипт по адресу:
GET /api/public/facade/theme-persist.js
Настроенные ключ и режим в него запечены — на странице настраивать нечего. Подключите его
один раз, как можно раньше в <head>:
<script src="/api/public/facade/theme-persist.js"></script>
При загрузке он читает сохранённое значение и применяет класс w-theme-*, затем предоставляет небольшой API:
window.wippyThemePersist = {
mode, // 'none' | 'cookie' | 'localStorage'
key, // ключ хранилища
read(), // -> 'auto' | 'light' | 'dark' | null
write(mode), // сохранить режим (ничего не делает при mode === 'none')
apply(mode), // переключить класс w-theme-* на <html>
}
Оболочка хоста (index.html / Jet-шаблон index.jet) уже подключает этот скрипт, передаёт сохранённое
значение в приложение и сохраняет изменения — трогать её не нужно. Разделы ниже касаются
других страниц.
Как это складывается вместе (оболочка хоста)
- Первая отрисовка — режим cookie: сервер выставил
<html class="w-theme-dark">. Режим localStorage: класс выставил скрипт раннего применения. В любом случае страница оформлена до загрузки бандла. - Начальная загрузка — оболочка передаёт сохранённое значение в хост:
themeMode: window.wippyThemePersist.read() ?? cfg.themeMode, поэтому хост применяет тот же режим. - При изменении — хост порождает
themeChanged(mode); оболочка сохраняет его:events.on('themeChanged', window.wippyThemePersist.write).
Событие хоста themeChanged
globalEvents — генератор событий, возвращаемый window.initWippyApp(...), — порождает themeChanged(mode)
('auto' | 'light' | 'dark') при инициализации и при каждом изменении темы. Оно не зависит от способа сохранения: хост
никогда не обращается к хранилищу; что с этим делать, решают встраивающие стороны.
const events = window.initWippyApp(config, '#app')
events.on('themeChanged', (mode) => {
// например, сохранить или уведомить родительское окно
})
Страницы вне размещения Wippy
Документ вне контракта переносимых модулей Wippy может уважать и сохранять
ту же тему. Нативные кнопки ниже уместны только для такого
внешнего статического документа. Страница или компонент Wippy с такими элементами управления должны
использовать PrimeVue согласно Контракту переносимого UI.
Подключите генерируемый скрипт и вызывайте write() из собственного переключателя:
<head>
<!-- как можно раньше: применяет сохранённую тему + предоставляет window.wippyThemePersist -->
<script src="/api/public/facade/theme-persist.js"></script>
<!-- необязательно: переиспользовать и брендовую тему фасада -->
<link rel="stylesheet" href="/api/public/facade/variables.css">
</head>
<body>
<button type="button" data-mode="auto">Auto</button>
<button type="button" data-mode="light">Light</button>
<button type="button" data-mode="dark">Dark</button>
<script>
document.querySelectorAll('[data-mode]').forEach((btn) => {
btn.addEventListener('click', () => {
const mode = btn.dataset.mode
window.wippyThemePersist.apply(mode) // обновить <html> сейчас
window.wippyThemePersist.write(mode) // сохранить для следующей загрузки / для хоста
})
})
</script>
</body>
Поскольку ключ и режим хранения общие (скрипт генерируется из той же конфигурации фасада), выбор, сделанный на странице входа, напрямую переносится в Web Host, и наоборот.
Если вы предпочитаете не загружать скрипт, можно запросить
/api/public/facade/config, прочитатьthemePersist/themeStorageKeyи реализовать чтение/запись самостоятельно — но генерируемый скрипт держит логику хранения в одном месте.
Отрисовка cookie на стороне сервера (нулевое мигание)
Для собственной страницы с серверным рендерингом (например, Jet-шаблона входа) можно применить тему на сервере
ровно так же, как это делает оболочка хоста: прочитать из запроса cookie с именем из theme_storage_key и
выдать соответствующий класс на <html>:
<html lang="en"{{ if hasTheme }} class="{{ themeClass }}" style="color-scheme: {{ colorScheme }};"{{ end }}>
где обработчик установил themeClass в w-theme-dark / w-theme-light (а colorScheme в
dark / light) на основе cookie. Всё равно подключайте theme-persist.js, чтобы страница могла записывать
изменения обратно.