Gogs 2a38f23eb6 -- 3 주 전
..
README.md 2a38f23eb6 -- 3 주 전
index.coffee 80710f8924 -- 3 주 전
index.pug 06219819b6 -- 3 주 전
index.styl 64342b1095 -- 3 주 전

README.md

Компонент ThemeToggle - Полная документация

Назначение компонента

ThemeToggle - компонент для переключения между светлой и темной темами в приложении. Сохраняет выбор пользователя в localStorage, синхронизирует состояние между вкладками и обеспечивает плавные переходы между темами.

git репозитарий

https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/src/master/vue/app/shared/ThemeToggle/

Импорт и регистрация

# В основном файле приложения (app/temp.coffee)
components:
    'themetoggle': require 'app/shared/ThemeToggle'

Базовое использование

//- Минимальное использование
themetoggle

//- С кастомными классами
themetoggle(class="ml-4")

//- В навигационной панели
div(class="flex items-center space-x-4")
    language-switcher
    themetoggle

Полный список props

size (опциональный)

  • Тип: String
  • По умолчанию: 'md'
  • Допустимые значения: 'sm', 'md', 'lg'
  • Описание: Размер переключателя
  • Пример:

    themetoggle(size="sm")
    themetoggle(size="lg")
    

variant (опциональный)

  • Тип: String
  • По умолчанию: 'default'
  • Допустимые значения: 'default', 'minimal', 'icon-only'
  • Описание: Вариант отображения переключателя
  • Пример:

    themetoggle(variant="minimal")
    themetoggle(variant="icon-only")
    

showLabels (опциональный)

  • Тип: Boolean
  • По умолчанию: true
  • Описание: Показывать текстовые метки
  • Пример:

    themetoggle(:showLabels="false")
    

labels (опциональный)

  • Тип: Object
  • По умолчанию: { light: 'Светлая', dark: 'Тёмная', system: 'Системная' }
  • Описание: Кастомные текстовые метки
  • Пример:

    themetoggle(:labels="{ light: 'Light', dark: 'Dark', system: 'Auto' }")
    

storageKey (опциональный)

  • Тип: String
  • По умолчанию: 'borbad-theme'
  • Описание: Ключ для сохранения в localStorage
  • Пример:

    themetoggle(storageKey="my-app-theme")
    

class (опциональный)

  • Тип: String | Object | Array
  • По умолчанию: ''
  • Описание: Дополнительные CSS классы
  • Пример:

    themetoggle(class="border border-gray-300 rounded-lg")
    

События (Events)

@change

  • Описание: Событие смены темы
  • Payload: { theme: String, previousTheme: String }
  • Пример:

    themetoggle(@change="handleThemeChange")
    

@init

  • Описание: Событие инициализации темы
  • Payload: { theme: String }
  • Пример:

    themetoggle(@init="handleThemeInit")
    

Слоты (Slots)

[light-icon]

  • Описание: Иконка для светлой темы
  • Пример:

    themetoggle
      template([light-icon])
          svig(class="w-4 h-4" ...) ...
    

[dark-icon]

  • Описание: Иконка для темной темы
  • Пример:

    themetoggle
      template([dark-icon])
          svig(class="w-4 h-4" ...) ...
    

[system-icon]

  • Описание: Иконка для системной темы
  • Пример:

    themetoggle
      template([system-icon])
          svig(class="w-4 h-4" ...) ...
    

Доступные темы

light

  • Светлая тема
  • Принудительно устанавливает светлый режим

dark

  • Темная тема
  • Принудительно устанавливает темный режим

system

  • Системная тема
  • Следует за настройками операционной системы
  • Использует prefers-color-scheme media query

Примеры использования

1. Базовые варианты

//- Стандартный переключатель
themetoggle

//- Только иконки
themetoggle(variant="icon-only")

//- Минималистичный вариант
themetoggle(variant="minimal")

//- Разные размеры
div(class="flex space-x-2")
    themetoggle(size="sm")
    themetoggle(size="md") 
    themetoggle(size="lg")

2. Кастомные иконки

themetoggle
    template([light-icon])
        div(class="w-4 h-4 bg-yellow-400 rounded-full")
    
    template([dark-icon])
        div(class="w-4 h-4 bg-purple-600 rounded-full")
    
    template([system-icon])
        div(class="w-4 h-4 bg-gray-500 rounded-full")

3. Кастомные метки

themetoggle(
    :labels="{ 
        light: '☀️ Светлая', 
        dark: '🌙 Тёмная', 
        system: '💻 Система' 
    }"
)

4. Интеграция с навигацией

header(class="bg-white dark:bg-gray-800 shadow-sm")
    div(class="container mx-auto px-4")
        div(class="flex justify-between items-center py-4")
            //- Логотип
            app-link(to="/" class="text-xl font-bold") Борбад
            
            //- Навигация
            nav(class="flex items-center space-x-6")
                app-link(to="/events") Мероприятия
                app-link(to="/blog") Блог
                
                //- Переключатель темы
                themetoggle(
                    variant="icon-only"
                    class="text-gray-600 dark:text-gray-300"
                )

5. В мобильном меню

div(class="mobile-menu bg-white dark:bg-gray-800 p-4")
    div(class="space-y-4")
        app-link(to="/" class="block") Главная
        app-link(to="/events" class="block") Мероприятия
        app-link(to="/blog" class="block") Блог
        
        //- Переключатель темы в мобильном меню
        div(class="pt-4 border-t dark:border-gray-700")
            themetoggle(
                variant="minimal"
                :showLabels="true"
                class="w-full"
            )

6. С обработкой событий

themetoggle(
    @change="onThemeChange"
    @init="onThemeInit"
)

//- В methods компонента
methods:
    onThemeChange: ({ theme, previousTheme }) ->
        debug.log "Тема изменена: "+previousTheme+" -> "+theme
        # Можно добавить аналитику
        analytics.track('theme_changed', { 
            new_theme: theme,
            previous_theme: previousTheme 
        })
    
    onThemeInit: ({ theme }) ->
        debug.log "Тема инициализирована: "+theme

Программное взаимодействие

Получение текущей темы

# Через глобальный объект
currentTheme = _.appState?.currentTheme

# Через EventBus
EventBus.on 'theme_changed', (theme) ->
    debug.log "Текущая тема: "+theme

Установка темы программно

# Через глобальный объект
_.setTheme('dark')

# Через EventBus
EventBus.emit('set_theme', 'light')

Подписка на изменения темы

# В компоненте
beforeMount: ->
    EventBus.on 'theme_changed', @handleThemeChange

methods:
    handleThemeChange: (theme) ->
        # Обновляем стили компонента
        @updateComponentStyles(theme)

Стили и кастомизация

CSS-переменные

Компонент использует стандартные CSS-переменные Tailwind:

:root {
  --color-bg-primary: #ffffff;
  --color-bg-secondary: #f7fafc;
  --color-text-primary: #2d3748;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-bg-primary: #1a202c;
    --color-bg-secondary: #2d3748;
    --color-text-primary: #f7fafc;
  }
}

Кастомные стили

// Переопределение стандартных стилей
.theme-toggle--custom
    @apply bg-gradient-to-r from-blue-500 to-purple-600 text-white
    
    .theme-toggle__button
        @apply hover:from-blue-600 hover:to-purple-700
    
    .theme-toggle__button--active
        @apply from-blue-700 to-purple-800

Анимации переходов

// Плавные переходы
.theme-transition
    transition: all 0.3s ease-in-out

// Анимация переключения
@keyframes theme-switch
    0%
        opacity: 0
        transform: scale(0.8)
    100%
        opacity: 1
        transform: scale(1)

.theme-toggle--animating
    animation: theme-switch 0.3s ease-in-out

Интеграция с Tailwind CSS

Конфигурация tailwind.config.js

module.exports = {
  darkMode: 'class', // или 'media' для системной темы
  // ...
}

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

div(class="bg-white dark:bg-gray-800 text-gray-900 dark:text-white")
    h1(class="text-2xl font-bold") Заголовок
    p(class="text-gray-600 dark:text-gray-300") Текст

Особенности работы

Определение системной темы

# Использует matchMedia для определения системных предпочтений
systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches

Синхронизация между вкладками

# Слушает события storage для синхронизации
window.addEventListener('storage', (event) ->
    if event.key == @storageKey
        @applyTheme(event.newValue)
)

Плавные переходы

# Добавляет класс для анимации при переключении
document.documentElement.classList.add('theme-transition')
setTimeout(() ->
    document.documentElement.classList.remove('theme-transition')
, 300)

Методы API

setTheme(theme)

  • Описание: Устанавливает указанную тему
  • Параметры: theme - 'light', 'dark', или 'system'
  • Пример:

    @$refs.themeToggle.setTheme('dark')
    

getCurrentTheme()

  • Описание: Возвращает текущую активную тему
  • Возвращает: String
  • Пример:

    currentTheme = @$refs.themeToggle.getCurrentTheme()
    

toggle()

  • Описание: Переключает между светлой и темной темами
  • Пример:

    @$refs.themeToggle.toggle()
    

Обработка ошибок

Валидация темы

# Проверка допустимых значений
if !['light', 'dark', 'system'].includes(theme)
    throw new Error("Недопустимое значение темы: "+theme)

Fallback для localStorage

try
    localStorage.setItem(@storageKey, theme)
catch error
    # Используем cookie как fallback
    document.cookie = @storageKey+"="+theme+"; path=/; max-age=31536000"

Примеры интеграции

1. С аналитикой

methods:
    handleThemeChange: ({ theme, previousTheme }) ->
        # Отправка в аналитику
        gtag('event', 'theme_change', {
            event_category: 'ui',
            event_label: theme,
            value: theme == 'dark' ? 1 : 0
        })

2. С синхронизацией с сервером

methods:
    handleThemeChange: ({ theme }) ->
        # Сохранение на сервере (если пользователь авторизован)
        if @user
            await @api.saveUserPreferences({ theme: theme })

3. С кастомной логикой

methods:
    handleThemeChange: ({ theme }) ->
        # Изменение meta-тегов
        const themeColor = theme == 'dark' ? '#1a202c' : '#ffffff'
        document.querySelector('meta[name="theme-color"]').content = themeColor
        
        # Изменение favicon
        const favicon = theme == 'dark' ? '/favicon-dark.ico' : '/favicon-light.ico'
        document.querySelector('link[rel="icon"]').href = favicon

Best Practices

1. Всегда предоставляйте все три варианта

//- Правильно
themetoggle

//- Неправильно (ограниченный выбор)
themetoggle(:themes="['light', 'dark']")

2. Используйте системную тему по умолчанию

//- Позволяет следовать системным настройкам
themetoggle

3. Сохраняйте состояние пользователя

//- Автоматически сохраняет в localStorage
themetoggle

4. Обеспечивайте доступность

//- Правильные ARIA-атрибуты
themetoggle(aria-label="Переключение темы")

5. Тестируйте все варианты

# В тестах
describe('ThemeToggle', ->
    it('should switch between themes', ->
        toggle.setTheme('light')
        expect(toggle.getCurrentTheme()).toBe('light')
        
        toggle.setTheme('dark')
        expect(toggle.getCurrentTheme()).toBe('dark')
    )
)

Компонент ThemeToggle предоставляет полнофункциональное решение для управления темами в приложении с поддержкой доступности, сохранения состояния и плавных переходов.