Добро пожаловать в это относительно короткое и простое руководство по созданию Custom Svelte Store, которое управляет текущей цветовой схемой.

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

Он также будет регистрировать изменения темы в других вкладках, окнах и фреймах. Для этого узнаем про Broadcast API.

Наконец, мы узнаем, как использовать наш собственный магазин в нашем приложении с Tailwindcss.

Для начала мы создаем новый проект Vite с помощью следующей команды.

npm create vite@latest

Теперь вы можете ответить на все вопросы. Что касается фреймворка, вы выбрали Svelte, и не имеет значения, используете ли вы только Svelte или Svelte Kit, потому что функция, которую мы здесь создаем, будет работать в обоих.

Затем вы можете запустить проект, набрав npm run dev, предполагая, что вы находитесь в папке проекта, где находится файл package.json.

Создание собственного магазина Svelte

Как сделать индивидуальный магазин? В Svelte обычные хранилища создаются с помощью readable/writable, но на самом деле эти функции просто возвращают объекты с тремя свойствами: subscribe, set и update.

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

Метод/свойство подписки является обязательным, но мы можем определить другие функции, называемые как угодно, которые можно вызывать для объекта хранилища.

Итак, давайте начнем с создания нового файла с именем store.js и импортируем функцию writable из Svelte.

import { writable } from "svelte/store";

ОС по умолчанию

Затем мы продолжаем получать цветовую схему ОС по умолчанию. В CSS мы можем применять стили условно на основе текущей цветовой схемы с помощью медиа-запроса prefers-color-scheme. И мы можем использовать функцию matchMedia в js, чтобы узнать, верен ли медиазапрос или нет.

// Get the OS default color scheme
const media_query = matchMedia("(prefers-color-scheme: dark)")
const os_default = media_query.matches ? "dark" : "light";

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

Базовый магазин

Затем мы вызываем доступный для записи метод либо со значением ОС по умолчанию, либо со значением из локального хранилища, если оно определено.

Мы деструктурируем методы подписки и обновления из возвращаемого объекта.

// Get the current color scheme from local storage, or default to light
const { subscribe, update } = writable(localStorage.getItem("colorScheme") ?? os_default);

Вещательный канал

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

// Create a channel so we can communicate with other tabs/windows/iframes
const channel = new BroadcastChannel("colorScheme");

// Listen for messages from other tabs/windows/iframes
channel.addEventListener("message", event => {
    update(() => event.data);
});

Мы можем добавить в этот канал прослушиватель событий для сообщений из других вкладок, окон и фреймов. Когда мы получаем сообщение, мы обновляем хранилище новым значением, которое будет light или dark.

Переключить функцию

После этого мы определяем функцию, которая будет добавлена ​​в хранилище для переключения текущей цветовой схемы. Эта функция будет единственным способом изменить цветовую схему.

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

const toggle = () => update(n => {
    const newColorScheme = n === "light" ? "dark" : "light"

    // Save the new color scheme to local storage
    localStorage.setItem("colorScheme", newColorScheme);

    // Send the new color scheme to other tabs/windows/iframes
    channel.postMessage(newColorScheme);

    return newColorScheme;
});

Мы также устанавливаем значение в локальном хранилище и размещаем сообщение на канале с новой цветовой схемой.

Ниже показано, где можно просмотреть значения в локальном хранилище с помощью инструментов разработки в MS Edge.

Экспорт магазина

Наконец, мы экспортируем объект хранилища с помощью методов подписки и переключения.

// A store object must return a subscribe function, all other properties are optional.
export const colorScheme = { subscribe, toggle };

Использование пользовательского магазина Svelte

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

<script>
    import { colorScheme } from "./store";
</script>

Работа с цветовой схемой в стиле

Чтобы управлять нашим хранилищем цветовых тем, мы могли бы установить класс для корневого элемента и использовать стратегию классов в Tailwindcss.

<script>
    import { colorScheme } from "./store";
    
    // Set the color scheme each time it changes.
    // Doing it this way could be useful if you use Tailwind with the class strategy.
    $: {
        document.firstElementChild.setAttribute("class", $colorScheme);
        document.firstElementChild.style.colorScheme = $colorScheme;
    };
</script>

Кнопка-переключатель

Наконец, чтобы переключить цветовую схему, мы можем добавить кнопку, которая вызывает функцию переключения в магазине.

<button on:click={() => colorScheme.toggle()}>Toggle</button>

Заключение

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