Adds code editor for user to specify custom CSS

This commit is contained in:
Alicia Sykes 2021-05-31 17:01:00 +01:00
parent 0edf235178
commit 35289df0d9
9 changed files with 98 additions and 9 deletions

View File

@ -95,10 +95,10 @@ All fields are optional, unless otherwise stated.
- `backgroundImg` - String: Path to an optional full-screen app background image. This can be either remote (http) or local (/). Note that this will slow down initial load - `backgroundImg` - String: Path to an optional full-screen app background image. This can be either remote (http) or local (/). Note that this will slow down initial load
- `enableFontAwesome` - Boolean: Where `true` is enabled, if left blank font-awesome will be enabled only if required by 1 or more icons - `enableFontAwesome` - Boolean: Where `true` is enabled, if left blank font-awesome will be enabled only if required by 1 or more icons
- `fontAwesomeKey` - String: If you have a font-awesome key, then you can use it here and make use of premium icons. It is a 10-digit alpha-numeric string from you're FA kit URL (e.g. `13014ae648`) - `fontAwesomeKey` - String: If you have a font-awesome key, then you can use it here and make use of premium icons. It is a 10-digit alpha-numeric string from you're FA kit URL (e.g. `13014ae648`)
- `customCss` - String: Raw CSS that will be applied to the page. Please minify it first.
- `theme`- String: The default theme for first load (you can change this later from the UI) - `theme`- String: The default theme for first load (you can change this later from the UI)
- `cssThemes` - String[]: An array of custom theme names which can be used in the theme switcher dropdown - _See **theming** below_ - `cssThemes` - String[]: An array of custom theme names which can be used in the theme switcher dropdown - _See **theming** below_
- `externalStyleSheet` - String or String[] - Either a URL to an external stylesheet or an array or URLs, which can be applied as themes within the UI - `externalStyleSheet` - String or String[] - Either a URL to an external stylesheet or an array or URLs, which can be applied as themes within the UI
- `customCss` - String: Raw CSS that will be applied to the page. Please minify it first.
**`sections`** - Section[]: (required) An array of sections - _See **`section`** below_ **`sections`** - Section[]: (required) An array of sections - _See **`section`** below_
@ -182,8 +182,9 @@ This wouldn't have been quite so possible without the following components, kudo
- [`vue-material-tabs`](https://github.com/jairoblatt/vue-material-tabs) - Tab view component by @jairoblatt `MIT` - [`vue-material-tabs`](https://github.com/jairoblatt/vue-material-tabs) - Tab view component by @jairoblatt `MIT`
- [`VJsoneditor`](https://github.com/yansenlei/VJsoneditor) - Interactive JSON editor component by @yansenlei `MIT` - [`VJsoneditor`](https://github.com/yansenlei/VJsoneditor) - Interactive JSON editor component by @yansenlei `MIT`
- Forked from [`JsonEditor`](https://github.com/josdejong/jsoneditor) by @josdejong `Apache-2.0 License` - Forked from [`JsonEditor`](https://github.com/josdejong/jsoneditor) by @josdejong `Apache-2.0 License`
- Using [`ajv`](https://github.com/ajv-validator/ajv) `MIT` JSON schema Validator and [`ace`](https://github.com/ajaxorg/ace) `BSD` code editor
- [`vue-toasted`](https://github.com/shakee93/vue-toasted) - Toast notification component by @shakee93 `MIT` - [`vue-toasted`](https://github.com/shakee93/vue-toasted) - Toast notification component by @shakee93 `MIT`
- [`vue-prism-editor`](https://github.com/koca/vue-prism-editor) - Lightweight code editor by @koca `MIT`
- Forked from [`prism.js`](https://github.com/PrismJS/prism) `MIT`
Utils: Utils:
- [`crypto-js`](https://github.com/brix/crypto-js) - Encryption implementations by @evanvosberg and community `MIT` - [`crypto-js`](https://github.com/brix/crypto-js) - Encryption implementations by @evanvosberg and community `MIT`

View File

@ -12,6 +12,7 @@
"connect": "^3.7.0", "connect": "^3.7.0",
"crypto-js": "^4.0.0", "crypto-js": "^4.0.0",
"highlight.js": "^11.0.0", "highlight.js": "^11.0.0",
"prismjs": "^1.23.0",
"register-service-worker": "^1.6.2", "register-service-worker": "^1.6.2",
"remedial": "^1.0.8", "remedial": "^1.0.8",
"serve-static": "^1.14.1", "serve-static": "^1.14.1",
@ -21,6 +22,7 @@
"vue-cli-plugin-yaml": "^1.0.2", "vue-cli-plugin-yaml": "^1.0.2",
"vue-js-modal": "^2.0.0-rc.6", "vue-js-modal": "^2.0.0-rc.6",
"vue-material-tabs": "^0.0.7", "vue-material-tabs": "^0.0.7",
"vue-prism-editor": "^1.2.2",
"vue-router": "^3.0.3", "vue-router": "^3.0.3",
"vue-select": "^3.11.2", "vue-select": "^3.11.2",
"vue-toasted": "^1.1.28" "vue-toasted": "^1.1.28"

View File

@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="css3-alt" class="svg-inline--fa fa-css3-alt fa-w-12" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M0 32l34.9 395.8L192 480l157.1-52.2L384 32H0zm313.1 80l-4.8 47.3L193 208.6l-.3.1h111.5l-12.8 146.6-98.2 28.7-98.8-29.2-6.4-73.9h48.9l3.2 38.3 52.6 13.3 54.7-15.4 3.7-61.6-166.3-.5v-.1l-.2.1-3.6-46.3L193.1 162l6.5-2.7H76.7L70.9 112h242.2z"></path></svg>

After

Width:  |  Height:  |  Size: 473 B

View File

@ -17,6 +17,10 @@
<MetaDataIcon class="button-icon"/> <MetaDataIcon class="button-icon"/>
Edit Meta Data Edit Meta Data
</button> </button>
<button class="config-button center" @click="goToCustomCss()">
<CustomCssIcon class="button-icon"/>
Edit Custom CSS
</button>
<button class="config-button center" @click="openCloudSync()"> <button class="config-button center" @click="openCloudSync()">
<CloudIcon class="button-icon"/> <CloudIcon class="button-icon"/>
{{backupId ? 'Edit Cloud Sync' : 'Enable Cloud Sync'}} {{backupId ? 'Edit Cloud Sync' : 'Enable Cloud Sync'}}
@ -70,6 +74,7 @@ import DownloadIcon from '@/assets/interface-icons/config-download-file.svg';
import DeleteIcon from '@/assets/interface-icons/config-delete-local.svg'; import DeleteIcon from '@/assets/interface-icons/config-delete-local.svg';
import EditIcon from '@/assets/interface-icons/config-edit-json.svg'; import EditIcon from '@/assets/interface-icons/config-edit-json.svg';
import MetaDataIcon from '@/assets/interface-icons/config-meta-data.svg'; import MetaDataIcon from '@/assets/interface-icons/config-meta-data.svg';
import CustomCssIcon from '@/assets/interface-icons/config-custom-css.svg';
import CloudIcon from '@/assets/interface-icons/cloud-backup-restore.svg'; import CloudIcon from '@/assets/interface-icons/cloud-backup-restore.svg';
export default { export default {
@ -97,6 +102,7 @@ export default {
EditIcon, EditIcon,
CloudIcon, CloudIcon,
MetaDataIcon, MetaDataIcon,
CustomCssIcon,
}, },
methods: { methods: {
/* Seletcs the edit tab of the tab view */ /* Seletcs the edit tab of the tab view */
@ -108,6 +114,10 @@ export default {
const itemToSelect = this.$refs.tabView.navItems[3]; const itemToSelect = this.$refs.tabView.navItems[3];
this.$refs.tabView.activeTabItem({ tabItem: itemToSelect, byUser: true }); this.$refs.tabView.activeTabItem({ tabItem: itemToSelect, byUser: true });
}, },
goToCustomCss() {
const itemToSelect = this.$refs.tabView.navItems[4];
this.$refs.tabView.activeTabItem({ tabItem: itemToSelect, byUser: true });
},
openCloudSync() { openCloudSync() {
this.$modal.show(modalNames.CLOUD_BACKUP); this.$modal.show(modalNames.CLOUD_BACKUP);
}, },

View File

@ -1,11 +1,17 @@
<template> <template>
<div class="json-editor-outer"> <div class="json-editor-outer">
<textarea v-model="customCss"></textarea> <prism-editor class="my-editor" v-model="customCss" :highlight="highlighter" line-numbers />
<button class="save-button" @click="save()">Save Changes</button> <button class="save-button" @click="save()">Save Changes</button>
<p>Note, you will need to refresh the page for your changes to take effect</p>
</div> </div>
</template> </template>
<script> <script>
import { PrismEditor } from 'vue-prism-editor';
import { highlight, languages } from 'prismjs/components/prism-core';
import 'prismjs/components/prism-css';
import 'prismjs/themes/prism-funky.css';
import 'vue-prism-editor/dist/prismeditor.min.css';
import { localStorageKeys } from '@/utils/defaults'; import { localStorageKeys } from '@/utils/defaults';
@ -14,18 +20,21 @@ export default {
props: { props: {
config: Object, config: Object,
}, },
components: {
PrismEditor,
},
data() { data() {
return { return {
customCss: this.config.appConfig.customCss || '', customCss: this.config.appConfig.customCss || '\n\n\n\n\n',
}; };
}, },
methods: { methods: {
validate() { validate(css) {
return true; return css.match(/((?:^\s*)([\w#.@*,:\-.:>,*\s]+)\s*{(?:[\s]*)((?:[A-Za-z\- \s]+[:]\s*['"0-9\w .,/()\-!%]+;?)*)*\s*}(?:\s*))/gmi);
}, },
save() { save() {
let msg = ''; let msg = '';
if (this.validate()) { if (this.validate(this.customCss)) {
const appConfig = { ...this.config.appConfig }; const appConfig = { ...this.config.appConfig };
appConfig.customCss = this.customCss; appConfig.customCss = this.customCss;
localStorage.setItem(localStorageKeys.APP_CONFIG, JSON.stringify(appConfig)); localStorage.setItem(localStorageKeys.APP_CONFIG, JSON.stringify(appConfig));
@ -42,6 +51,9 @@ export default {
style.textContent = cleanedCss; style.textContent = cleanedCss;
document.head.append(style); document.head.append(style);
}, },
highlighter(code) {
return highlight(code, languages.css);
},
}, },
}; };
</script> </script>
@ -64,4 +76,13 @@ button.save-button {
} }
} }
.prism-editor-wrapper {
min-height: 200px;
border: 1px solid var(--transparent-70);
border-radius: var(--curve-factor);
width: 90%;
margin: 0.5rem auto;
background: var(--transparent-50);
}
</style> </style>

View File

@ -5,7 +5,6 @@ import VModal from 'vue-js-modal'; // Modal component
import VSelect from 'vue-select'; // Select dropdown component import VSelect from 'vue-select'; // Select dropdown component
import VTabs from 'vue-material-tabs'; // Tab view component, used on the config page import VTabs from 'vue-material-tabs'; // Tab view component, used on the config page
import Toasted from 'vue-toasted'; // Toast component, used to show confirmation notifications import Toasted from 'vue-toasted'; // Toast component, used to show confirmation notifications
import { toastedOptions } from './utils/defaults'; import { toastedOptions } from './utils/defaults';
import App from './App.vue'; import App from './App.vue';
import router from './router'; import router from './router';

View File

@ -37,7 +37,6 @@ const encodeGetParams = p => Object.entries(p).map(kv => kv.map(encodeURICompone
/* Restores the backup */ /* Restores the backup */
export const restore = (backupId, password) => { export const restore = (backupId, password) => {
const params = encodeGetParams({ backupId, subHash: makeSubHash(password) }); const params = encodeGetParams({ backupId, subHash: makeSubHash(password) });
console.log(makeSubHash(password));
const url = `${ENDPOINT}/?${params}`; const url = `${ENDPOINT}/?${params}`;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.get(url).then((response) => { axios.get(url).then((response) => {

View File

@ -2,6 +2,7 @@ module.exports = {
chainWebpack: config => { chainWebpack: config => {
config.module.rules.delete('svg'); config.module.rules.delete('svg');
}, },
configureWebpack: { configureWebpack: {
module: { module: {
rules: [ rules: [
@ -9,4 +10,11 @@ module.exports = {
], ],
}, },
}, },
pwa: {
name: 'Dashy',
themeColor: '#00CCB4',
msTileColor: '#0b1021',
manifestCrossorigin: 'use-credentials',
},
}; };

View File

@ -2563,6 +2563,15 @@ cli-width@^3.0.0:
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
clipboard@^2.0.0:
version "2.0.8"
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.8.tgz#ffc6c103dd2967a83005f3f61976aa4655a4cdba"
integrity sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==
dependencies:
good-listener "^1.2.2"
select "^1.1.2"
tiny-emitter "^2.0.0"
clipboardy@^2.3.0: clipboardy@^2.3.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-2.3.0.tgz#3c2903650c68e46a91b388985bc2774287dba290" resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-2.3.0.tgz#3c2903650c68e46a91b388985bc2774287dba290"
@ -3255,6 +3264,11 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
delegate@^3.1.2:
version "3.2.0"
resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
depd@~1.1.2: depd@~1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
@ -4434,6 +4448,13 @@ globby@^9.2.0:
pify "^4.0.1" pify "^4.0.1"
slash "^2.0.0" slash "^2.0.0"
good-listener@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=
dependencies:
delegate "^3.1.2"
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.2: graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.2:
version "4.2.6" version "4.2.6"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
@ -4565,6 +4586,11 @@ highlight.js@^10.7.1:
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.2.tgz#89319b861edc66c48854ed1e6da21ea89f847360" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.2.tgz#89319b861edc66c48854ed1e6da21ea89f847360"
integrity sha512-oFLl873u4usRM9K63j4ME9u3etNF0PLiJhSQ8rdfuL51Wn3zkD6drf9ZW0dOzjnZI22YYG24z30JcmfCZjMgYg== integrity sha512-oFLl873u4usRM9K63j4ME9u3etNF0PLiJhSQ8rdfuL51Wn3zkD6drf9ZW0dOzjnZI22YYG24z30JcmfCZjMgYg==
highlight.js@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.0.0.tgz#e22ac9ca45edc4f87a2187685d591a108ceb8449"
integrity sha512-ByaTMfsSuoqerTwemOgpIhfULEIaK52JJYhky/sK7/Yqc0+t7Uh5DHay9vIC94YXSupnQ1Vqfc9VXrYP4eXW3Q==
hmac-drbg@^1.0.1: hmac-drbg@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@ -7069,6 +7095,13 @@ pretty-error@^2.0.2:
lodash "^4.17.20" lodash "^4.17.20"
renderkid "^2.0.4" renderkid "^2.0.4"
prismjs@^1.23.0:
version "1.23.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.23.0.tgz#d3b3967f7d72440690497652a9d40ff046067f33"
integrity sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==
optionalDependencies:
clipboard "^2.0.0"
process-nextick-args@~2.0.0: process-nextick-args@~2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@ -7643,6 +7676,11 @@ select-hose@^2.0.0:
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
select@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
selfsigned@^1.10.8: selfsigned@^1.10.8:
version "1.10.8" version "1.10.8"
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.8.tgz#0d17208b7d12c33f8eac85c41835f27fc3d81a30" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.8.tgz#0d17208b7d12c33f8eac85c41835f27fc3d81a30"
@ -8383,6 +8421,11 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
tiny-emitter@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
tmp@^0.0.33: tmp@^0.0.33:
version "0.0.33" version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@ -8852,6 +8895,11 @@ vue-material-tabs@^0.0.7:
resolved "https://registry.yarnpkg.com/vue-material-tabs/-/vue-material-tabs-0.0.7.tgz#5f3fa04ad35384af68582f7c89ad4cecac89207b" resolved "https://registry.yarnpkg.com/vue-material-tabs/-/vue-material-tabs-0.0.7.tgz#5f3fa04ad35384af68582f7c89ad4cecac89207b"
integrity sha512-02X5paTksYKrGvSRpMdkctRO9qhvJFD5VEGxd0xjOX4sYz6mZSAez0Z/+aYf7Z5ziY+eJ9dMQmxaLn9DVKQRJw== integrity sha512-02X5paTksYKrGvSRpMdkctRO9qhvJFD5VEGxd0xjOX4sYz6mZSAez0Z/+aYf7Z5ziY+eJ9dMQmxaLn9DVKQRJw==
vue-prism-editor@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/vue-prism-editor/-/vue-prism-editor-1.2.2.tgz#023cfd4329848f191aac851f2f5e6c7a8c2e059f"
integrity sha512-Lq2VgVygTx3Whn/tC8gD4m1ajA4lzSyCTqPLZA1Dq/ErbBaZA93FWRblwCoDR7AD2nXhGWuiTzb5ih3guzB7DA==
vue-resize@^1.0.1: vue-resize@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-1.0.1.tgz#c120bed4e09938771d622614f57dbcf58a5147ee" resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-1.0.1.tgz#c120bed4e09938771d622614f57dbcf58a5147ee"