UNPKG

vue-theme-manager

Version:

A vuejs plugin for Managing theme(s) colors in the whole of your Vue web app. It has support for Vue 2x, Vue 3x and Nuxt

266 lines (225 loc) 8.19 kB
import { reactive, computed, watch } from 'vue' class ThemeManager { constructor(options) { this.onThemeChangedListener = null; this.ThemeChangerWatcher = null; this.onReadyListener = null; this.theme = reactive({ name: 'default', names: computed(() => { return this.getnames() }), default: {}, currentTheme: computed(() => { return this.theme[this.theme.name] }), }) //update current theme keys watch(() => this.theme.currentTheme, (newval, oldval) => { this.updateThemeTree(newval, oldval); }); this.init(options); this.updateThemeTree(this.theme.currentTheme); } init(options) { try { JSON.parse(options) } catch (err) {} if (options !== undefined && typeof options === 'object') { this.theme.name = options.activate == undefined ? this.theme.name : options.activate let keys = Object.keys(options.styles); for (let c = 0; c < keys.length; c++) { Object.defineProperty(this.theme, keys[c], { value: options.styles[keys[c]], writable: true, enumerable: true }); } let currtheme = this.theme.name; this.theme.name = '' // to make this.theme.name = currtheme; // the changed reactibe } } setReadyListener() { try { this.onReadyListener(this.hasThemeInDB()); } catch (err) {} } setThemeChangeListener(callback) { this.ThemeChangerWatcher = callback || function () {} } onReady(callback) { this.onReadyListener = callback || function () {} } onThemeChanged(callback) { this.onThemeChangedListener = callback || function () {} } updateThemeTree(newval = [], oldval = []) { //deleting old keys let currentKeys = Object.keys(oldval); for (var x = 0; x < currentKeys.length; x++) { let key = currentKeys[x]; this.theme[key] = undefined } //adding new keys let newkeys = Object.keys(newval); for (var x = 0; x < newkeys.length; x++) { let key = newkeys[x]; //console.log(key) Object.defineProperty(this.theme, key, { value: this.theme.currentTheme[key], enumerable: true, writable: true }); } //delete old values //add new values } getnames() { var result = []; let keys = Object.keys(this.theme); for (var x = 0; x < keys.length; x++) { let key = keys[x] if (typeof this.theme[key] === 'object' && key != 'currentTheme' && !Array.isArray(this.theme[key])) { result.push(key) } } return result //get names } addTheme(style, themeName = 'default', activate = false) { if (activate) { this.theme.name = themeName try { this.onThemeChangedListener(this.theme.name, this.theme.currentTheme); } catch (err) {}; } if (typeof style !== 'object' && style !== null) { style = JSON.parse(style) } //convert to object if it is json string if (!this.theme.hasOwnProperty(themeName)) { //theme doesn't exist yet so we create one Object.defineProperty(this.theme, themeName, { value: style, enumerable: true, writable: true }) let currtheme = this.theme.name; this.theme.name = '' // to make this.theme.name = currtheme; // the changed reactibe } else { this.theme[themeName] = Object.assign({}, this.theme[themeName], style); } return this } activateTheme(name) { if (name != '' || name != null) { if (this.theme[name] !== undefined) { this.theme.name = name this.saveTheme(); //try{this.onThemeChangedListener(name,this.theme.currentTheme);}catch(err){}; this.ThemeChangerWatcher(name, this.theme.currentTheme); } else { console.log('theme doesnt exist') } } return this } getTheme(themeName = this.theme.name, which) { if (this.theme[themeName] == undefined) { return } if (which == undefined || !Array.isArray(which)) { //return's full theme options return this.theme[themeName] } var result = {}; for (let i = 0; i < which.length; i++) { let c = which[i] // console.log(JSON.stringify(this.theme['default'])); try { Object.defineProperty(result, c, { value: this.theme[themeName][c], writable: true, enumerable: true }) } catch (err) { console.log(err) } } return result; } saveTheme() { let db_theme = { activate: this.theme.name, styles: {} } for (let u = 0; u < this.theme.names.length; u++) { let ct = this.theme.names[u]; // console.log(ct) let theme = this.theme[ct]; if (theme !== undefined && typeof theme === 'object' && !Array.isArray(theme)) { // console.log(JSON.stringify(theme)) Object.defineProperty(db_theme.styles, ct, { value: theme, enumerable: true, writable: true }) } } //now we save to localStorage localStorage.setItem('VUE_THEME_MANAGER', JSON.stringify(db_theme)); return this } setThemeFromStorage() { let th = localStorage.getItem('VUE_THEME_MANAGER'); if (th !== null) { this.init(JSON.parse(th)); } //get from localStorge then initialize return this } hasThemeInDB() { let th = localStorage.getItem('VUE_THEME_MANAGER'); if (th !== null) { return true } return false } activateThemechangeListenser(name, options) { this.onThemeChangedListener(name, options); } } const VueThemeManager = { install(Vue, options) { Vue.config.globalProperties.$AppTheme = new ThemeManager(options); Vue.mixin({ mounted() { this.$AppTheme.setReadyListener(); this.$AppTheme.setThemeChangeListener((res) => { this.$AppTheme.activateThemechangeListenser(res); }); }, computed: { VueThemeManager() { let currentTheme = {}; var theme = this.$AppTheme.theme.currentTheme; let keys = Object.keys(theme); for (var i = 0; i < keys.length; i++) { let ck = keys[i]; let cp = theme[ck]; let tokebalcase = ck.replace(/\B(?:([A-Z])(?=[a-z]))|(?:(?<=[a-z0-9])([A-Z]))/g, '-$1$2').toLowerCase(); //convert to --xxx-xx for css variables Object.defineProperty(currentTheme, '--' + tokebalcase, { value: cp, enumerable: true, writable: true }); } return currentTheme } } }); } } export default VueThemeManager;