nb-theme

This is a theme manager plugin for Vue.js 3+.

Installation

Yarn
yarn add @vlalg-nimbus/nb-theme
NPM
npm install @vlalg-nimbus/nb-theme

Usage

Attention to the imported theme css file

Vue 3
import { createApp } from 'vue'
import App from './App.vue'

import ThemePlugin from '@vlalg-nimbus/nb-theme'

// Your css files
import './style/style.css';
import "./style/themes.css";  // CSS file

const app = createApp(App)

app.use(ThemePlugin, {
  theme: 'dark', // start default theme
  dev: true, // Console theme changes
})

app.mount('#app')
Nuxt 3
import ThemePlugin from '@vlalg-nimbus/nb-theme'
import "./style/themes.css";

export default defineNuxtPlugin(context => {
  context.vueApp.use(ThemePlugin, {
    theme: 'dark', // start default theme
    dev: true, // Console theme changes,
    texts: { // I18N (by theme color) - optional
      dark: {
        title: 'Dark mode',
        subtitle: 'You are in dark theme'
      },
      default: {
        title: 'Default mode',
        subtitle: 'You are in default theme'
      },
      test: {
        title: 'Test mode',
        subtitle: 'You are in test theme'
      },
      other: {
        title: 'Other mode',
        subtitle: 'You are in other theme'
      }
    }
  })
})

The only required option when creating is theme, the options (dev and texts) are optional.

To use it, simply call the gets and sets in your files using Vue inject.

Below I provide the names of the gets and sets.

component
<template>
  <button @click="updateTheme('dark')">Dark theme</button>
  <button @click="updateTheme('test')">Test theme</button>
  <button @click="updateTheme('default')">Default theme</button>
  <button @click="updateTheme('other')">Others theme</button>

  <p>getTheme (theme name): {{ getTheme }}</p>
  <p>getThemeVariableValue: {{ getThemeVariableValue('--bg-color') }}</p>
  <p>getThemeText: {{ getThemeText('subtitle') }}</p>
</template>

<script setup>
  import { inject } from 'vue'

  const getTheme = inject('$getTheme')
  const changeTheme = inject('$changeTheme')
  const getThemeVariableValue = inject('$getThemeVariableValue')
  const getThemeText = inject('$getThemeText')

  const updateTheme = (newTheme) => {
    if (changeTheme) changeTheme(newTheme)
  }
</script>

css

First of all, it is required to define :root with the names of the variables and their values.

For each theme that will be used, create a group in this css file defining the values of the variables. Pay attention to the names of the variables, if they do not exist in a theme, they will end up taking the value of :root.

Example:

:root {
  --bg-color: #ffffff;
  --text-color: #000000;
}

[data-theme='default'] {
  --bg-color: #04eeff;
  --text-color: #000000;
}

[data-theme='dark'] {
  --bg-color: #000000;
  --text-color: #ffffff;
}

[data-theme='other'] {
  --bg-color: tomato;
  --text-color: #ffffff;
}

If you do not follow the above pattern it will not work as expected.

Typescript

The lib provides automatic typing

Vue

main.js
  import { createApp } from 'vue'
  import App from './App.vue'

  import ThemePlugin from '@vlalg-nimbus/nb-theme'
  import type { ThemeTextMap, ThemeOptions } from '@vlalg-nimbus/nb-theme'

  const texts: ThemeTextMap = {
    light: {
      welcome: 'Bem-vindo',
      goodbye: 'Até logo'
    },
    dark: {
      welcome: 'Welcome',
      goodbye: 'See you'
    }
  }

  const themeOptions: ThemeOptions = {
    theme: 'dark',
    dev: true,
    texts
  }

  const app = createApp(App)
  
  app.use(ThemePlugin, themeOptions)
  
  app.mount('#app');
Component
  <script setup lang="ts">
    import { inject } from 'vue'
    import type { ThemePluginContext } from '@vlalg-nimbus/nb-theme'

    const theme = inject('$getTheme') as ThemePluginContext['theme']
    const changeTheme = inject('$changeTheme') as ThemePluginContext['changeTheme']
    const getThemeText = inject('$getThemeText') as ThemePluginContext['getThemeText']
    const getThemeVariableValue = inject('$getThemeVariableValue') as ThemePluginContext['getThemeVariableValue']
  </script>

  <template>
    <h1>{{ getThemeText('welcome') }}</h1>
    <p>{{ getThemeVariableValue('--bg-color') }}</p>

    <button @click="changeTheme('light')">Light mode</button>
    <button @click="changeTheme('dark')">Dark mode</button>
  </template>

Nuxt

main.js
  import { createApp } from 'vue'
  import App from './App.vue'

  import ThemePlugin from '@vlalg-nimbus/nb-theme'
  import type { ThemeTextMap, ThemeOptions } from '@vlalg-nimbus/nb-theme'

  const texts: ThemeTextMap = {
    light: {
      welcome: 'Bem-vindo',
      goodbye: 'Até logo'
    },
    dark: {
      welcome: 'Welcome',
      goodbye: 'See you'
    }
  }

  const themeOptions: ThemeOptions = {
    theme: 'dark',
    dev: true,
    texts
  }

  const app = createApp(App)
  
  app.use(ThemePlugin, themeOptions)
  
  app.mount('#app');
composables/useTheme.ts
  import { inject } from 'vue'
  import type { ThemePluginContext } from '@vlalg-nimbus/nb-theme'

  export const useTheme = (): ThemePluginContext => {
    const changeTheme = inject('$changeTheme') as ThemePluginContext['changeTheme']
    const getTheme = inject('$getTheme') as ThemePluginContext['theme']
    const getThemeText = inject('$getThemeText') as ThemePluginContext['getThemeText']
    const getThemeVariableValue = inject('$getThemeVariableValue') as ThemePluginContext['getThemeVariableValue']

    if (!theme || !changeTheme || !getThemeText || !getThemeVariableValue) {
      throw new Error('[nb-theme] Plugin not properly injected or used outside of Vue app context.')
    }

    return {
      changeTheme,
      getTheme,
      getThemeText,
      getThemeVariableValue
    }
  }
Component
  <script setup lang="ts">
    import { useTheme } from '@/composables/useTheme'

    const { getTheme, changeTheme, getThemeText, getThemeVariableValue } = useTheme()
  </script>

  <template>
    <h1>{{ getThemeText('welcome') }}</h1>
    <p>Background: {{ getThemeVariableValue('--bg-color') }}</p>

    <button @click="changeTheme('light')">Light mode</button>
    <button @click="changeTheme('dark')">Dark mode</button>
  </template>

Preview & Playground

Select the component you want to edit/test

Loading Sandbox...

Options

Items with an (*) mean they are required

nameValue typeDefaultDescription
theme (*)StringSets default thema name
devBooleanfalseDefines whether to print to the console when a theme changes
textsObject{}Defines texts that should change when changing the theme, as if it were an I18N, but for a theme.

The texts option accepts a object in this format:

{
  themeNameOne: {
    welcome: 'Bem-vindo',
    goodbye: 'Até logo'
  },
  themeNameTwo: {
    welcome: 'Welcome',
    goodbye: 'See you'
  },
  ...
}

Gets

nameDescription
$getThemeGet the current theme name
$getThemeVariableValueGets the value of a variable in css by theme. If not found, returns an empty value.
$getThemeTextGets the value of a variable defined in the theme texts. If not found, returns an empty value.

Sets

nameDescription
$changeThemeChange the theme that is active in the system