🚧 WIP - working on the custom theme feature

This commit is contained in:
Alicia Sykes 2021-07-11 20:52:12 +01:00
parent c7d91bed94
commit 65aa971099
11 changed files with 142 additions and 35 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 741 KiB

After

Width:  |  Height:  |  Size: 818 KiB

View File

@ -41,6 +41,13 @@
---
### Ground Control
> By [@dtctek](https://github.com/dtctek)
![screenshot-ground-control](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/7-ground-control-dtctek.png)
---
## Submitting your Dashboard
#### How to Submit
@ -69,4 +76,4 @@ If you're submitting a pull request, please use a format similar to this:
---
```
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

View File

@ -1,6 +1,6 @@
{
"name": "Dashy",
"version": "1.3.7",
"version": "1.3.8",
"license": "MIT",
"main": "server",
"scripts": {
@ -32,7 +32,7 @@
"vue": "^2.6.10",
"vue-cli-plugin-yaml": "^1.0.2",
"vue-js-modal": "^2.0.0-rc.6",
"vue-material-tabs": "^0.0.7",
"vue-material-tabs": "^0.1.2",
"vue-prism-editor": "^1.2.2",
"vue-router": "^3.0.3",
"vue-select": "^3.11.2",

View File

@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="palette" class="svg-inline--fa fa-palette fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M128 224c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.4-32-32-32zM418.6 58.1C359.2 9.3 281.3-10 204.6 5 104.9 24.4 24.7 104.2 5.1 203.7c-16.7 84.2 8.1 168.3 67.8 230.6 47.3 49.4 109.7 77.8 167.9 77.8 8.8 0 17.5-.6 26.1-2 24.2-3.7 44.6-18.7 56.1-41.1 12.3-24 12.3-52.7.2-76.6-6.1-12-5.5-26.2 1.8-38 7-11.8 18.7-18.4 32-18.4h72.2c46.4 0 82.8-35.7 82.8-81.3-.2-76.4-34.3-148.1-93.4-196.6zM429.2 288H357c-29.9 0-57.2 15.4-73 41.3-16 26.1-17.3 57.8-3.6 84.9 5.1 10.1 5.1 22.7-.2 32.9-2.6 5-8.7 13.7-20.6 15.6-49.3 7.7-108.9-16.6-152-61.6-48.8-50.9-69-119.4-55.4-188 15.9-80.6 80.8-145.3 161.6-161 62.6-12.3 126.1 3.5 174.3 43.1 48.1 39.5 75.7 97.6 75.9 159.6 0 18.6-15.3 33.2-34.8 33.2zM160 128c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.4-32-32-32zm96-32.1c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32c0-17.6-14.3-32-32-32zm96 32.1c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32z"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,5 +1,6 @@
<template>
<div class="theme-selector-section" v-if="themes" >
<div class="theme-selector-section" v-if="themes" v-click-outside="closeThemeConfigurator">
<div>
<span class="theme-label">Theme</span>
<v-select
:options="themeNames"
@ -7,13 +8,26 @@
class="theme-dropdown"
:tabindex="-2"
/>
</div>
<IconPalette
class="color-button"
v-if="selectedTheme === 'custom'"
@click="openThemeConfigurator"
/>
<div
v-if="themeConfiguratorOpen"
class="theme-configurator-wrapper"
>
<p>Custom Theme Configurator</p>
</div>
</div>
</template>
<script>
import ThemeHelper from '@/utils/ThemeHelper';
import { LoadExternalTheme, ApplyLocalTheme, ApplyCustomTheme } from '@/utils/ThemeHelper';
import Defaults, { localStorageKeys } from '@/utils/defaults';
import IconPalette from '@/assets/interface-icons/config-color-palette.svg';
export default {
name: 'ThemeSelector',
@ -22,21 +36,28 @@ export default {
confTheme: String,
userThemes: Array,
},
components: {
IconPalette,
},
watch: {
selectedTheme(newTheme) { this.updateTheme(newTheme); },
},
data() {
return {
selectedTheme: this.getInitialTheme(),
themeHelper: new ThemeHelper(),
loading: true,
builtInThemes: this.userThemes.concat(Defaults.builtInThemes),
builtInThemes: [...Defaults.builtInThemes, ...this.userThemes],
themeHelper: new LoadExternalTheme(),
// modalName: modalNames.THEME_MAKER,
themeConfiguratorOpen: false,
ApplyLocalTheme,
ApplyCustomTheme,
};
},
computed: {
themeNames: function themeNames() {
const externalThemeNames = Object.keys(this.themes);
return externalThemeNames.concat(this.builtInThemes);
const specialThemes = ['custom'];
return [...specialThemes, ...externalThemeNames, ...this.builtInThemes];
},
},
created() {
@ -54,12 +75,6 @@ export default {
}
},
methods: {
/* Sets the theme, by updating data-theme attribute on the html tag */
setLocalTheme(newTheme) {
const htmlTag = document.getElementsByTagName('html')[0];
if (htmlTag.hasAttribute('data-theme')) htmlTag.removeAttribute('data-theme');
htmlTag.setAttribute('data-theme', newTheme);
},
/* Get default theme */
getInitialTheme() {
return localStorage[localStorageKeys.THEME] || this.confTheme || Defaults.theme;
@ -67,14 +82,22 @@ export default {
isThemeLocal(themeToCheck) {
return this.builtInThemes.includes(themeToCheck);
},
openThemeConfigurator() {
this.themeConfiguratorOpen = true;
},
closeThemeConfigurator() {
this.themeConfiguratorOpen = false;
},
/* Updates theme. Checks if the new theme is local or external,
and calls appropirate updating function. Updates local storage */
updateTheme(newTheme) {
if (newTheme === 'Deafault') {
if (newTheme === 'custom') {
this.ApplyCustomTheme();
} else if (newTheme === 'Deafault') {
this.resetToDefault();
this.themeHelper.theme = 'Deafault';
} else if (this.isThemeLocal(newTheme)) {
this.setLocalTheme(newTheme);
this.ApplyLocalTheme(newTheme);
} else {
this.themeHelper.theme = newTheme;
}
@ -95,7 +118,7 @@ export default {
div.vs__dropdown-toggle {
border-color: var(--settings-text-color);
border-radius: var(--curve-factor);
min-width: 10rem;
width: 8rem;
height: 1.8rem;
font-size: 0.85rem;
cursor: pointer;
@ -111,6 +134,8 @@ export default {
width: auto;
background: var(--background);
z-index: 5;
max-width: 13rem;
overflow-x: hidden;
}
li.vs__dropdown-option--highlight {
background: var(--settings-text-color);
@ -123,7 +148,7 @@ export default {
.theme-selector-section {
display: flex;
flex-direction: column;
flex-direction: row;
align-items: flex-start;
height: 100%;
span.theme-label {
@ -133,4 +158,37 @@ export default {
}
}
svg.color-button {
path {
fill: var(--settings-text-color);
}
width: 1rem;
height: 1rem;
padding: 0.2rem;
margin: 0.5rem;
align-self: flex-end;
text-align: center;
background: var(--background);
border: 1px solid var(--settings-text-color);;
border-radius: var(--curve-factor);
cursor: pointer;
&:hover, &.selected {
background: var(--settings-text-color);
path { fill: var(--background); }
}
}
div.theme-configurator-wrapper {
position: absolute;
right: 2rem;
top: 3rem;
width: 30%;
height: 50%;
padding: 0.5rem;
background: var(--config-settings-background);
color: var(--config-settings-color);
border-radius: var(--curve-factor);
box-shadow: 0 8px 10px -2px rgba(0, 0, 0, 0.6), 1px 1px 6px var(--primary);
}
</style>

View File

@ -1,6 +1,6 @@
import ConfigAccumulator from '@/utils/ConfigAccumalator';
import { visibleComponents } from '@/utils/defaults';
import { visibleComponents, localStorageKeys, theme as defaultTheme } from '@/utils/defaults';
/**
* Initiates the Accumulator class and generates a complete config object
@ -40,3 +40,14 @@ export const componentVisibility = (appConfig) => {
? !usersChoice.hideSplashScreen : visibleComponents.splashScreen,
};
};
/**
* Gets the users saved theme, first looks for local storage theme,
* then looks at user's appConfig, and finally checks the defaults
* @returns {string} Name of theme to apply
*/
export const getTheme = () => {
const localTheme = localStorage[localStorageKeys.THEME];
const appConfigTheme = config.appConfig.theme;
return localTheme || appConfigTheme || defaultTheme;
};

View File

@ -1,8 +1,25 @@
import ErrorHandler from '@/utils/ErrorHandler';
import { getTheme } from '@/utils/ConfigHelpers';
/* Returns users current theme */
export const GetTheme = () => getTheme();
/* Sets the theme, by updating data-theme attribute on the html tag */
export const ApplyLocalTheme = (newTheme) => {
const htmlTag = document.getElementsByTagName('html')[0];
if (htmlTag.hasAttribute('data-theme')) htmlTag.removeAttribute('data-theme');
htmlTag.setAttribute('data-theme', newTheme);
};
/* Sets specific CSS variables, for the users custom theme */
export const ApplyCustomTheme = () => { };
/**
* A function for pre-loading, and easy switching of external stylesheets
* External CSS is preloaded to avoid FOUC
*/
const ThemeHelper = function th() {
export const LoadExternalTheme = function th() {
/* Preload selected external theme */
const preloadTheme = (href) => {
const link = document.createElement('link');
link.rel = 'stylesheet';
@ -18,10 +35,21 @@ const ThemeHelper = function th() {
});
};
/* Check theme is selected, and it exists */
const checkTheme = (themes, name) => {
if ((!name) || (name !== 'custom' && !themes[name])) {
ErrorHandler(`Theme: '${name || '[not selected]'}' does not exist.`);
return false;
}
return true;
};
/* Disable all but selected theme */
const selectTheme = (themes, name) => {
const t = themes; // To avoid ESLint complaining about mutating a param
if (name && !themes[name]) throw new Error(`Theme: '${name}' does not exist.`);
Object.keys(themes).forEach(n => { t[n].disabled = (n !== name); });
if (checkTheme(themes, name)) {
const t = themes; // To avoid ESLint complaining about mutating a param
Object.keys(themes).forEach(n => { t[n].disabled = (n !== name); });
}
};
const themes = {};
@ -32,5 +60,3 @@ const ThemeHelper = function th() {
get theme() { return Object.keys(themes).find(n => !themes[n].disabled); },
};
};
export default ThemeHelper;

View File

@ -70,6 +70,7 @@ module.exports = {
CONF_EDITOR: 'CONF_EDITOR',
CLOUD_BACKUP: 'CLOUD_BACKUP',
REBUILD_APP: 'REBUILD_APP',
THEME_MAKER: 'THEME_MAKER',
ABOUT_APP: 'ABOUT_APP',
},
topLevelConfKeys: {

View File

@ -9,7 +9,8 @@
import SideBar from '@/components/Workspace/SideBar';
import WebContent from '@/components/Workspace/WebContent';
import Defaults, { localStorageKeys } from '@/utils/defaults';
import Defaults from '@/utils/defaults';
import { ApplyLocalTheme, GetTheme } from '@/utils/ThemeHelper';
export default {
name: 'Workspace',
@ -19,6 +20,8 @@ export default {
},
data: () => ({
url: '', // this.$route.query.url || '',
GetTheme,
ApplyLocalTheme,
}),
components: {
SideBar,
@ -29,10 +32,7 @@ export default {
this.url = url;
},
setTheme() {
const theme = localStorage[localStorageKeys.THEME] || this.confTheme || Defaults.theme;
const htmlTag = document.getElementsByTagName('html')[0];
if (htmlTag.hasAttribute('data-theme')) htmlTag.removeAttribute('data-theme');
htmlTag.setAttribute('data-theme', theme);
this.ApplyLocalTheme(this.GetTheme());
},
initiateFontAwesome() {
const fontAwesomeScript = document.createElement('script');

View File

@ -8899,10 +8899,10 @@ vue-loader@^15.9.2:
vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0"
vue-material-tabs@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/vue-material-tabs/-/vue-material-tabs-0.0.7.tgz#5f3fa04ad35384af68582f7c89ad4cecac89207b"
integrity sha512-02X5paTksYKrGvSRpMdkctRO9qhvJFD5VEGxd0xjOX4sYz6mZSAez0Z/+aYf7Z5ziY+eJ9dMQmxaLn9DVKQRJw==
vue-material-tabs@^0.1.2:
version "0.1.5"
resolved "https://registry.yarnpkg.com/vue-material-tabs/-/vue-material-tabs-0.1.5.tgz#255fc0beb27c005eaae61c1534d782a94c30c525"
integrity sha512-ZLFRCxaCS3TM8IwnxQA4S2CVj+tBaILb8fQZDg+Ix+9Zu+k16udrdhLU2GWvJEVPLspuCzKhCEXW4cIg59YkVw==
vue-prism-editor@^1.2.2:
version "1.2.2"