Montana
Montana

Reputation: 502

Vuejs SPA dynamic theme

I have a Vuejs single page application that I have built, and I would like to add user-switchable dynamic themes. Something where the user has a button somewhere or something and they can click a 'light' or 'dark' theme option and the whole app updates right away. I would also like to have all of my 'theme' scss files be local.

This answer here is the closest I've found so far, but the themes are not local.

const themes = {
  flatly: "https://bootswatch.com/4/flatly/bootstrap.min.css",
  materia: "https://bootswatch.com/4/materia/bootstrap.min.css",
  solar: "https://bootswatch.com/4/solar/bootstrap.min.css"
};

If I could figure out how to get this answer to work with local theme files that would be great, but switching the link paths out with a local path doesn't work.

const themes = {
  dark: "dark-theme.scss",
  light: "light-theme.scss"
};

My suspicion is that this doesn't work because of Webpack or some other compiling problem where the scss files are not included.

I have found I can get my theme files to appear in the client source if I add something like the following to my index.html <link rel="stylesheet" type="text/css" href="<%= BASE_URL %>dark-theme.scss"> But then I don't know how to reference this in my app. Maybe a link like http://localhost:8080/dark-theme.scss? But then I don't think that would work in production (and it doesn't work locally anyway).

I have also looked at:

I've also tried doing something like import "@/path/to/theme.scss"; in my main.ts file which does work, but I don't know how I'd leverage that to make the themes switchable. It just adds an element like the following to my head, which has no id or class so I can't effectively query it to switch it out. Using require does something similar as well.

<style type="text/css" >
  ...
</style>

Upvotes: 5

Views: 665

Answers (2)

RoduanKD
RoduanKD

Reputation: 1309

Here is a trick that came to my mind you can use. Create two empty components for your theme like this:

<template><div></div></template>
<script>export default {name: 'DarkTheme'}</script>
<style>
  @import "~@/path/to/theme.scss"
</style>

now in your app you can use v-if on these two components like

<dark-theme v-if="theme == 'dark'"/>
<light-theme v-if="theme == 'light'"/>

PS: this code is not tested

Upvotes: 2

Renaud
Renaud

Reputation: 1300

main.ts:

import "@/path/to/dark-theme.scss"
import "@/path/to/light-theme.scss"

dark-theme.scss:

body.dark {
  /* rest of the theme */
}

light-theme.scss:

body.ligh {
  /* rest of the theme */
}

index.html (or injecting it from main.ts depending on local-storage or OS's mode):

<body class="light">

Where you have your switch:

methods: {
  toggleTheme() {
    document.body.classList.toggle('dark')
    document.body.classList.toggle('light')
  }
}

Upvotes: 2

Related Questions