ThemeModule

Theme - модуль для темизации приложений (SPA/SSR)

Nuxt install

// nuxt.config.js
export default {
  modules: ['shared-front/nuxt/theme'],
};

Module options

storeName

  • type: string
  • default: 'color-theme'

Ключ для хранения темы пользователя в Cookie и localStorage

themes

  • type: Themes
  • required: false

Список тем с css переменными

interface Theme extends StylObject {}

interface Themes extends StylObject {
  [key: string]: Theme;
}

Далее данный список доступен так же по алиасу #runtime/shared-front/themes.json и $themes переменной из stylus

Пример

themeContainer

  • type: string
  • default: 'html'

Контейнер в котором будет использоваться темизация

helperVariablePrefix

  • type: string
  • default: 'c-'

Префикс для сгенерированных css переменных

В модуле компонентов используются переменные с префиксом 'c-'

defaultColorTheme

  • type: string
  • default: 'light'

Цветовая тема по-умолчанию

themeSelector

  • type: string
  • default: '&.theme-$s'

Аргумент для css-theme-generator

Vue install

Vue 2

// main.js
import Vue from 'vue';
import { Plugin, useThemeSymbol } from 'shared-front/lib/modules/theme';

Vue.use(Plugin, {
  storeName: 'color-theme',
  isClient: true,
});

const app = new Vue({
  // For using `useTheme`
  provide: {
    [useThemeSymbol]: Vue.prototype.$theme,
  },
});

Vue 3

// main.ts
import { createApp } from 'vue';
import { Plugin } from 'shared-front/lib/modules/theme';

import App from './App.vue';

const app = createApp(App);

app.use(Plugin, {
  storeName: 'color-theme',
  isClient: true,
});

Plugin options

storeName

  • type: string
  • default: 'color-theme'

Ключ для хранения темы пользователя в Cookie и localStorage

isClient

  • type: boolean
  • default: true

Флаг, запущен ли плагин на клиенте. Если true, то инициализирует клиентскую логику

Stylus

Для подключения stylus миксинов необходимо импортировать shared-front/lib/nuxt-modules/theme/styles/index.styl

При использовании NuxtJS это будет сделано автоматически в модуле

Глобально

// stylus options
{
  import: ['shared-front/lib/nuxt-modules/theme/dist/runtime/styles/index.styl'],
  paths: [
    path.resolve(__dirname, 'node_modules'),
  ],
},

В конкретном файле

@import 'node_modules/shared-front/lib/nuxt-modules/theme/dist/runtime/styles/index.styl'

defaultColorTheme

  • type: string
  • default: 'light'

Стандартная цветовая тема, от неё зависят селекторы в миксине theme

theme

Миксин для работы со стилями тем. Нужен для более удобного применения стилей, поскольку может быть случай когда у нас еще нет темы в куках или еще нет класса на документе и тогда используется prefers-color-scheme.

.foo
  +theme('light')
    color black

  +theme('dark')
    color white

themeName

  • type: string
  • default: defaultColorTheme

selector

  • type: string
  • default: '.theme-%s &'

%s - заменяется на themeName внутри миксина

Если класс темы находится на App Component и нужно задать какие-то стили/переменные для отдельных тем на нем же, selector может иметь вид &.theme-%s.

Example

// Input
html
  +theme('light', '&.theme-%s')
    color #000

  +theme('dark', '&.theme-%s')
    color #fff
// Output
html {
  color: #000;
}
html.theme-light {
  color: #000;
}
@media (prefers-color-scheme: dark) {
  html {
    color: #fff;
  }
}
html.theme-dark {
  color: #fff;
}

css-theme-generator

Генератор тем

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

themes

  • type: object
  • required: true

Объект тем вида { light: { text-primary: #fff } }

selector

  • type: string
  • default: '&.theme-%s'

Селектор передаваемый в миксин theme

Example

// Input
html
  $themes = {
    light: {
      text-primary: #000,
    },
    dark: {
      text-primary: #fff,
    },
  }

  css-theme-generator($themes)
// Output
html {
  --c-text-primary: #000;
}
html.theme-light {
  --c-text-primary: #000;
}
@media (prefers-color-scheme: dark) {
  html {
    --c-text-primary: #fff;
  }
}
html.theme-dark {
  --c-text-primary: #fff;
}

Usage

Перед самой стилизацией, нужно проставить класс текущей темы на контейнер. Класс должен иметь структуру ${prefixSelector}-${themeName}, prefixSelector из stylus. Далее в стилях приложения использовать stylus mixin theme.

<template>
  <div class="app">
    App

    <div class="content">Some content</div>
  </div>
</template>

<script>
import { useTheme } from 'shared-front/lib/modules/theme';

export default {
  head() {
    const htmlAttrs = {};

    if (this.userTheme) htmlAttrs.class = `theme-${this.userTheme}`;

    return { htmlAttrs };
  },

  computed: {
    userTheme() {
      return this.$theme.userTheme;
    },
  },

  methods: {
    setTheme(themeName) {
      this.$theme.setTheme(themeName);
    },
  },

  setup() {
    const theme = useTheme();

    const userTheme = computed(() => theme.userTheme);
    const setTheme = (themeName) => theme.setTheme(themeName);

    return {
      userTheme,
      setTheme,
    };
  },
};
</script>

<style lang="stylus">
$themes = {
  light: {
    text-primary: black,
    bg-primary: white,
  },
  dark: {
    text-primary: white,
    bg-primary: black,
  },
}

html
  css-theme-generator($themes)

.content
  transition color .25s, background .25s
  color var(--c-text-primary)
  backround var(--c-bg-primary)

  :hover
    +theme('light')
      color dark-grey

    +theme('dark')
      color grey
</style>