Page 1 of 1

Theme switch with scss

Posted: 06 Jun 2020, 14:04
by TDZTechnika
I can see the theme is using css files to be able to switch the theme:

Code: Select all

changeTheme(theme) {
            this.theme = theme.split('-')[0];
			this.changeStyleSheetUrl('layout-css', theme, 'layout');
			this.changeStyleSheetUrl('theme-css', theme, 'theme');
		},
I would like to move .scss files to the /src/ folder to be abale to use scss variables (colors and font sizes) in my custom scss styles. But what I can see is the theme switch stops working. Is there any chance to have an example with having .scss files working and in the same time to keep theme switch ability working.

I guess all themes must be compiled into css in production or development mode.

Thanks

Re: Theme switch with scss

Posted: 08 Jun 2020, 13:26
by TDZTechnika
I am trying to do something as the example bellow. But I cannot get the results. I got the error:

Code: Select all

Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ReferenceError: document is not defined
    at insertStyleElement (webpack-internal:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js:93:15)
    at addStyle (webpack-internal:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js:208:13)
    at modulesToDom (webpack-internal:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js:81:18)
    at module.exports (webpack-internal:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js:239:25)
    at eval (webpack-internal:///./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/assets/theme/theme-yellow-light.scss:15:14)
    at Object../node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/assets/theme/theme-yellow-light.scss
Please let me guys know if you have a better idea or you can point me out in the right direction with my solution. Thanks.

Image

Re: Theme switch with scss

Posted: 08 Jun 2020, 13:35
by TDZTechnika
Also I tried to import scss based on the user setting but it is only working in development environment. In production build it stops working:

Image

Re: Theme switch with scss

Posted: 08 Jun 2020, 15:00
by TDZTechnika
Another solution is to change the theme scc styles in a way to make just one css bundle with the following aproach:

Code: Select all

<body class="theme-blue-light">
So we can change the theme by switching the class on the body.

Hope guys from primevue could join the conversation.

Re: Theme switch with scss

Posted: 06 Jul 2020, 12:22
by cagatay.civici
The themes are loaded with script tags at demo for easy theme switching functionality, for sure they can be included to app so vue-cli can compile sass and add it to bundle. However we'd like to avoid doing that as there are so many themes with color alternatives and the bundle will be a big one so solution could be a configuration with lazy loaded themes similar to lazy loaded routing. This is an enhancement for future though, we're discussing this internally now with our team. Any feedback is welcome.

Re: Theme switch with scss

Posted: 06 Jul 2020, 17:55
by FairKing
Thanks for the reply.
I managed to solve the challenge.

Bellow is my code

vue.config.js:

Code: Select all

const webpack = require('webpack');
const path = require('path');
const isDevelopment = process.env.NODE_ENV === 'development';

var config = {};
if (isDevelopment) {
    // Development
} else {
    // Production
    config = {
        entry: {
            "assets/theme/theme-blue-light": [path.resolve(__dirname, 'src/assets/theme/theme-blue-light.scss')],
            "assets/theme/theme-blue-dark": [path.resolve(__dirname, 'src/assets/theme/theme-blue-dark.scss')],
            "assets/theme/theme-green-light": [path.resolve(__dirname, 'src/assets/theme/theme-green-light.scss')],
            "assets/theme/theme-green-dark": [path.resolve(__dirname, 'src/assets/theme/theme-green-dark.scss')],
            "assets/theme/theme-cyan-light": [path.resolve(__dirname, 'src/assets/theme/theme-cyan-light.scss')],
            "assets/theme/theme-cyan-dark": [path.resolve(__dirname, 'src/assets/theme/theme-cyan-dark.scss')],
            "assets/theme/theme-purple-light": [path.resolve(__dirname, 'src/assets/theme/theme-purple-light.scss')],
            "assets/theme/theme-purple-dark": [path.resolve(__dirname, 'src/assets/theme/theme-purple-dark.scss')],
            "assets/theme/theme-indigo-light": [path.resolve(__dirname, 'src/assets/theme/theme-indigo-light.scss')],
            "assets/theme/theme-indigo-dark": [path.resolve(__dirname, 'src/assets/theme/theme-indigo-dark.scss')],
            "assets/theme/theme-yellow-light": [path.resolve(__dirname, 'src/assets/theme/theme-yellow-light.scss')],
            "assets/theme/theme-yellow-dark": [path.resolve(__dirname, 'src/assets/theme/theme-yellow-dark.scss')],
            "assets/theme/theme-orange-light": [path.resolve(__dirname, 'src/assets/theme/theme-orange-light.scss')],
            "assets/theme/theme-orange-dark": [path.resolve(__dirname, 'src/assets/theme/theme-orange-dark.scss')],
            "assets/theme/theme-pink-light": [path.resolve(__dirname, 'src/assets/theme/theme-pink-light.scss')],
            "assets/theme/theme-pink-dark": [path.resolve(__dirname, 'src/assets/theme/theme-pink-dark.scss')],
            "assets/layout/css/layout-blue-light": [path.resolve(__dirname, 'src/assets/layout/css/layout-blue-light.scss')],
            "assets/layout/css/layout-blue-dark": [path.resolve(__dirname, 'src/assets/layout/css/layout-blue-dark.scss')],
            "assets/layout/css/layout-green-light": [path.resolve(__dirname, 'src/assets/layout/css/layout-green-light.scss')],
            "assets/layout/css/layout-green-dark": [path.resolve(__dirname, 'src/assets/layout/css/layout-green-dark.scss')],
            "assets/layout/css/layout-cyan-light": [path.resolve(__dirname, 'src/assets/layout/css/layout-cyan-light.scss')],
            "assets/layout/css/layout-cyan-dark": [path.resolve(__dirname, 'src/assets/layout/css/layout-cyan-dark.scss')],
            "assets/layout/css/layout-purple-light": [path.resolve(__dirname, 'src/assets/layout/css/layout-purple-light.scss')],
            "assets/layout/css/layout-purple-dark": [path.resolve(__dirname, 'src/assets/layout/css/layout-purple-dark.scss')],
            "assets/layout/css/layout-indigo-light": [path.resolve(__dirname, 'src/assets/layout/css/layout-indigo-light.scss')],
            "assets/layout/css/layout-indigo-dark": [path.resolve(__dirname, 'src/assets/layout/css/layout-indigo-dark.scss')],
            "assets/layout/css/layout-yellow-light": [path.resolve(__dirname, 'src/assets/layout/css/layout-yellow-light.scss')],
            "assets/layout/css/layout-yellow-dark": [path.resolve(__dirname, 'src/assets/layout/css/layout-yellow-dark.scss')],
            "assets/layout/css/layout-orange-light": [path.resolve(__dirname, 'src/assets/layout/css/layout-orange-light.scss')],
            "assets/layout/css/layout-orange-dark": [path.resolve(__dirname, 'src/assets/layout/css/layout-orange-dark.scss')],
            "assets/layout/css/layout-pink-light": [path.resolve(__dirname, 'src/assets/layout/css/layout-pink-light.scss')],
            "assets/layout/css/layout-pink-dark": [path.resolve(__dirname, 'src/assets/layout/css/layout-pink-dark.scss')],
        },
    };
}

module.exports = {
	publicPath: process.env.BASE_URL,
	assetsDir: process.env.BASE_URL,
    productionSourceMap: isDevelopment,
    configureWebpack: config,
};
BrowserSettings class (TypeScript):

Code: Select all

export class BrowserSettings {
	themeMode: string;
    layoutMode: string;
    colorMode: string;
	pageSize: number;
	constructor() {}
}
main.ts:

Code: Select all

/* Load Theme Css dynamically */
import { BrowserSettings } from "@/models/CoreModels";
var strSettings = localStorage.getItem("settings");
var themeMode = "light";
var colorMode = "blue";
if (strSettings) {
    var browserSettings = JSON.parse(strSettings || "{}") as BrowserSettings;
    themeMode = browserSettings.themeMode || "light";
    colorMode = browserSettings.colorMode || "blue";
}
if (process.env.NODE_ENV === "development") {
    require(`@/assets/theme/theme-${colorMode}-${themeMode}.scss`);
    require(`@/assets/layout/css/layout-${colorMode}-${themeMode}.scss`);
} else {
    var allStyles = {};
    let layoutStyles = document.querySelectorAll("head > link[href*='/assets/layout/css/layout-'][rel='stylesheet']");
    layoutStyles.forEach(function (item) {
        var themeHref = item.getAttribute("href");
        var key = themeHref.substring(themeHref.indexOf("/layout-") + 1, themeHref.indexOf(".css") - 9).replace(/-/g, "_");
        allStyles[key] = themeHref;
        if (key.indexOf(colorMode + "_" + themeMode) === -1) {
            document.head.removeChild(item);
        }
    });
    let themeStyles = document.querySelectorAll("head > link[href*='/assets/theme/theme-'][rel='stylesheet']");
    themeStyles.forEach(function (item) {
        var themeHref = item.getAttribute("href");
        var key = themeHref.substring(themeHref.indexOf("/theme-") + 1, themeHref.indexOf(".css") - 9).replace(/-/g, "_");
        allStyles[key] = themeHref;
        if (key.indexOf(colorMode + "_" + themeMode) === -1) {
            document.head.removeChild(item);
        }
    });
    Vue.mixin({
        data() {
            return {
                themeStyles: allStyles,
            }
        }
    });
}
App.vue:

Code: Select all

	methods: {
		...mapActions("browserSettings", ["setTheme", "setLayout", "setColor", "setPageSize"]), // vuex actions
		onThemeChange(themeMode) {
			this.setTheme(themeMode); // vuex action to save user preference
			this.changeTheme();
		},
		onLayoutChange(layoutMode) {
			this.setLayout(layoutMode); // vuex action to save user preference
		},
		onColorChange(colorMode) {
			this.setColor(colorMode); // vuex action to save user preference
			this.changeTheme();
		},
		onRowCountChange(rowCount) {
			this.setPageSize(rowCount); // vuex action to save user preference
		},
		changeTheme() {
			if (process.env.NODE_ENV === "development") {
				window.location.reload(false);
			} else {
				var theme = this.colorMode + "-" + this.themeMode;
				this.changeStyleSheetUrl(theme, "layout-", '/assets/layout/css/');
				this.changeStyleSheetUrl(theme, "theme-", '/assets/theme/');
				window.location.reload(false);
                	}
		},
		changeStyleSheetUrl(theme, prefix, path) {
			var themeHref = this.themeStyles[(prefix + theme).replace("-", "_")];
			if (themeHref) {
				let styles = document.querySelectorAll(`head > link[href*='${path}${prefix}'][rel='stylesheet']`);
				styles.forEach(function (item) { document.head.removeChild(item); });
				var newStyle = document.createElement('link');
				newStyle.setAttribute('href', themeHref);
				newStyle.setAttribute('rel', 'stylesheet');
				document.head.appendChild(newStyle);
                	}
		},
	},