Skip to content
On this page

Theming

NuxtMicroServices has a built-in theme system. It allows you to easily change the look of you application.

Each theme can have config, assets and translations. All these things should be placed in the {srcDir}/theme/themes/{themeName} directory. Specify themeName in the theme.name option of the module config.

import { defineConfig } from 'nuxt-splitty'

export default defineConfig({
  theme: {
    name: 'default', // default theme name
    themesDir: 'theme/themes', // default themes directory
  },
})
import { defineConfig } from 'nuxt-splitty'

export default defineConfig({
  theme: {
    name: 'default', // default theme name
    themesDir: 'theme/themes', // default themes directory
  },
})

Config

By config you change the look of the site (hide/show components, change colors, etc).

Create your config file {srcDir}/theme/themes/{themeName}/config.ts.

The file should export by default a function which returns the config object as Ref (use useState for that). Extend also IThemeConfig from 'nuxt-splitty/types/theme/config'.

// theme/themes/default/config.ts
import type { Ref } from 'vue'
import type {
  IThemeConfig
} from 'nuxt-splitty/types/theme/config'

export default (): Ref<IThemeConfig & { showFooter: boolean }> => {
  return useState('theme-config', () => ({
    name: 'default',
    showFooter: true,
  }))
}
// theme/themes/default/config.ts
import type { Ref } from 'vue'
import type {
  IThemeConfig
} from 'nuxt-splitty/types/theme/config'

export default (): Ref<IThemeConfig & { showFooter: boolean }> => {
  return useState('theme-config', () => ({
    name: 'default',
    showFooter: true,
  }))
}

Usage:

<template>
  <div>
    <AppHeader />

    <slot />

    <AppFooter v-if="themeConfig.showFooter" />
  </div>
</template>

<script lang="ts" setup>
  const themeConfig = useThemeConfig()
</script>
<template>
  <div>
    <AppHeader />

    <slot />

    <AppFooter v-if="themeConfig.showFooter" />
  </div>
</template>

<script lang="ts" setup>
  const themeConfig = useThemeConfig()
</script>

Consistent config across themes

To avoid conflicts between themes, use the same config stucture. It's recommended to have a shared interface for config.

Let's move it to {srcDir}/theme/config.ts:

export interface ICurrentAppThemeConfig {
  apiUrl: string
  showFooter: boolean
}
export interface ICurrentAppThemeConfig {
  apiUrl: string
  showFooter: boolean
}

Then create a config file for each theme (mdm and imm):

import type { Ref } from 'vue'
import type {
  IThemeConfig
} from 'nuxt-splitty/types/theme/config'
import type { ICurrentAppThemeConfig } from '@/theme/config'

export default (): Ref<IThemeConfig & ICurrentAppThemeConfig> => {
  const env = useRuntimeConfig()
  
  return useState('theme-config', () => ({
    name: 'mdm',
    showFooter: true,
    apiUrl: env.API_URL,
  }))
}
import type { Ref } from 'vue'
import type {
  IThemeConfig
} from 'nuxt-splitty/types/theme/config'
import type { ICurrentAppThemeConfig } from '@/theme/config'

export default (): Ref<IThemeConfig & ICurrentAppThemeConfig> => {
  const env = useRuntimeConfig()
  
  return useState('theme-config', () => ({
    name: 'mdm',
    showFooter: true,
    apiUrl: env.API_URL,
  }))
}

Done! Now if there will be a some missmatch, typescript will throw an error.

Directory structure (mdm, imm themes):

├── theme
│   ├── config
│   │   ├── index.ts
│   ├── themes
│   │   ├── mdm
│   │   │   ├── config.ts
│   │   ├── imm
│   │   │   ├── config.ts

INFO

mdm or imm should be configured in theme.name option of the module config.

Assets

Put theme assets in {srcDir}/theme/themes/{themeName}/assets directory.

├── theme
│   ├── config
│   │   ├── index.ts
│   ├── themes
│   │   ├── mdm
│   │   │   ├── config.ts
│   │   │   ├── assets
│   │   │   │   └── ...
│   │   ├── imm
│   │   │   ├── config.ts
│   │   │   ├── assets
│   │   │   │   └── ...

You can use them manually in your components:

<script setup lang="ts" >
import logo from '@Theme/assets/logo.png'
</script>

<template>
  <img :src="logo">
</template>
<script setup lang="ts" >
import logo from '@Theme/assets/logo.png'
</script>

<template>
  <img :src="logo">
</template>

WARNING

But if you want logo.png in one theme and logo.svg in another, you can use config.

import type { Ref } from 'vue'
import type {
  IThemeConfig
} from 'nuxt-splitty/types/theme/config'

import logoSrc from './assets/logo.png'

export default (): Ref<IThemeConfig & { logo: string }> => {
  return useState('theme-config', () => ({
    name: 'mdm',
    logo: logoSrc,
  }))
}
import type { Ref } from 'vue'
import type {
  IThemeConfig
} from 'nuxt-splitty/types/theme/config'

import logoSrc from './assets/logo.png'

export default (): Ref<IThemeConfig & { logo: string }> => {
  return useState('theme-config', () => ({
    name: 'mdm',
    logo: logoSrc,
  }))
}

i18n

You can setup theme specific translations. It could be site name, footer text, etc.

Put translations in {themeName}/locales/{locale}.json

There is also a posibility to override translations of some modules. Just specify exact path for the translation field in the {themeName}/locales/{locale}-overwrite.json (use -overwrite suffix).

{
  "@core": {
    "pages": {
      "home": {
        "h1": "Theme Specific Title"
      }
    }
  }
}
{
  "@core": {
    "pages": {
      "home": {
        "h1": "Theme Specific Title"
      }
    }
  }
}

WARNING

Be careful with overwriting translations.

Recomendations

To prevent translations conflicts, it's recommended to use a specific root translation key. @Theme for example (if you don't have a module with such name).

{
  "@Theme": {
    "_": {
      "siteName": "MDM Shop"
    }
  }
}
{
  "@Theme": {
    "_": {
      "siteName": "MDM Shop"
    }
  }
}

For Internal Use Only