mirror of https://github.com/Lissy93/dashy.git
Merge pull request #3 from Lissy93/config-editor-feature
UI Config Editor Feature
This commit is contained in:
commit
265a8b42ba
10
README.md
10
README.md
|
@ -162,12 +162,16 @@ There are a few self-hosted web apps, that serve a similar purpose to Dashy. Inc
|
||||||
|
|
||||||
### Credits 🏆
|
### Credits 🏆
|
||||||
|
|
||||||
The app makes use of the following components, kudos to their respective authors
|
And the app itself is built with [Vue.js](https://github.com/vuejs/vue) ![vue-logo](https://i.ibb.co/xqKW6h5/vue-logo.png)
|
||||||
|
|
||||||
|
And wouldn't have been quite possible, without the following components, kudos to their respective authors
|
||||||
- [`vue-select`](https://github.com/sagalbot/vue-select) - Dropdown component by @sagalbot
|
- [`vue-select`](https://github.com/sagalbot/vue-select) - Dropdown component by @sagalbot
|
||||||
- [`vue-js-modal`](https://github.com/euvl/vue-js-modal) - Modal component by @euvl
|
- [`vue-js-modal`](https://github.com/euvl/vue-js-modal) - Modal component by @euvl
|
||||||
- [`v-tooltip`](https://github.com/Akryum/v-tooltip) - Tooltip component by @Akryum
|
- [`v-tooltip`](https://github.com/Akryum/v-tooltip) - Tooltip component by @Akryum
|
||||||
|
- [`vue-material-tabs`](https://github.com/jairoblatt/vue-material-tabs) - Tab view component by @jairoblatt
|
||||||
And the app itself is built with [Vue.js](https://github.com/vuejs/vue) ![vue-logo](https://i.ibb.co/xqKW6h5/vue-logo.png)
|
- [`VJsoneditor`](https://github.com/yansenlei/VJsoneditor) - Interactive JSON editor component by @yansenlei
|
||||||
|
- Forked from [JsonEditor](https://github.com/josdejong/jsoneditor) by @josdejong
|
||||||
|
- [`vue-toasted`](https://github.com/shakee93/vue-toasted) - Toast notification component by @shakee93
|
||||||
|
|
||||||
### License 📜
|
### License 📜
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,17 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"connect": "^3.7.0",
|
"connect": "^3.7.0",
|
||||||
"register-service-worker": "^1.6.2",
|
"register-service-worker": "^1.6.2",
|
||||||
|
"remedial": "^1.0.8",
|
||||||
"serve-static": "^1.14.1",
|
"serve-static": "^1.14.1",
|
||||||
|
"v-jsoneditor": "^1.4.2",
|
||||||
"v-tooltip": "^2.1.3",
|
"v-tooltip": "^2.1.3",
|
||||||
"vue": "^2.6.10",
|
"vue": "^2.6.10",
|
||||||
"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-router": "^3.0.3",
|
"vue-router": "^3.0.3",
|
||||||
"vue-select": "^3.11.2"
|
"vue-select": "^3.11.2",
|
||||||
|
"vue-toasted": "^1.1.28"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^4.5.12",
|
"@vue/cli-plugin-babel": "^4.5.12",
|
||||||
|
@ -61,4 +65,4 @@
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions"
|
"last 2 versions"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
13
src/App.vue
13
src/App.vue
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
import Header from '@/components/PageStrcture/Header.vue';
|
import Header from '@/components/PageStrcture/Header.vue';
|
||||||
import Footer from '@/components/PageStrcture/Footer.vue';
|
import Footer from '@/components/PageStrcture/Footer.vue';
|
||||||
import Defaults from '@/utils/defaults';
|
import Defaults, { localStorageKeys } from '@/utils/defaults';
|
||||||
import conf from '../public/conf.yml';
|
import conf from '../public/conf.yml';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -27,10 +27,17 @@ export default {
|
||||||
/* Returns either page info from the config, or default values */
|
/* Returns either page info from the config, or default values */
|
||||||
getPageInfo(pageInfo) {
|
getPageInfo(pageInfo) {
|
||||||
const defaults = Defaults.pageInfo;
|
const defaults = Defaults.pageInfo;
|
||||||
|
|
||||||
|
let localPageInfo;
|
||||||
|
try {
|
||||||
|
localPageInfo = JSON.parse(localStorage[localStorageKeys.PAGE_INFO]);
|
||||||
|
} catch (e) {
|
||||||
|
localPageInfo = {};
|
||||||
|
}
|
||||||
if (pageInfo) {
|
if (pageInfo) {
|
||||||
return {
|
return {
|
||||||
title: pageInfo.title || defaults.title,
|
title: localPageInfo.title || pageInfo.title || defaults.title,
|
||||||
description: pageInfo.description || defaults.description,
|
description: localPageInfo.description || pageInfo.description || defaults.description,
|
||||||
navLinks: pageInfo.navLinks || defaults.navLinks,
|
navLinks: pageInfo.navLinks || defaults.navLinks,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="trash-alt" class="svg-inline--fa fa-trash-alt fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M268 416h24a12 12 0 0 0 12-12V188a12 12 0 0 0-12-12h-24a12 12 0 0 0-12 12v216a12 12 0 0 0 12 12zM432 80h-82.41l-34-56.7A48 48 0 0 0 274.41 0H173.59a48 48 0 0 0-41.16 23.3L98.41 80H16A16 16 0 0 0 0 96v16a16 16 0 0 0 16 16h16v336a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128h16a16 16 0 0 0 16-16V96a16 16 0 0 0-16-16zM171.84 50.91A6 6 0 0 1 177 48h94a6 6 0 0 1 5.15 2.91L293.61 80H154.39zM368 464H80V128h288zm-212-48h24a12 12 0 0 0 12-12V188a12 12 0 0 0-12-12h-24a12 12 0 0 0-12 12v216a12 12 0 0 0 12 12z"></path></svg>
|
After Width: | Height: | Size: 739 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="file-download" class="svg-inline--fa fa-file-download fa-w-12" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="currentColor" d="M216 236.07c0-6.63-5.37-12-12-12h-24c-6.63 0-12 5.37-12 12v84.01h-48.88c-10.71 0-16.05 12.97-8.45 20.52l72.31 71.77c4.99 4.95 13.04 4.95 18.03 0l72.31-71.77c7.6-7.54 2.26-20.52-8.45-20.52H216v-84.01zM369.83 97.98L285.94 14.1c-9-9-21.2-14.1-33.89-14.1H47.99C21.5.1 0 21.6 0 48.09v415.92C0 490.5 21.5 512 47.99 512h287.94c26.5 0 48.07-21.5 48.07-47.99V131.97c0-12.69-5.17-24.99-14.17-33.99zM255.95 51.99l76.09 76.08h-76.09V51.99zM336 464.01H47.99V48.09h159.97v103.98c0 13.3 10.7 23.99 24 23.99H336v287.95z"></path></svg>
|
After Width: | Height: | Size: 749 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="edit" class="svg-inline--fa fa-edit fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M402.3 344.9l32-32c5-5 13.7-1.5 13.7 5.7V464c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h273.5c7.1 0 10.7 8.6 5.7 13.7l-32 32c-1.5 1.5-3.5 2.3-5.7 2.3H48v352h352V350.5c0-2.1.8-4.1 2.3-5.6zm156.6-201.8L296.3 405.7l-90.4 10c-26.2 2.9-48.5-19.2-45.6-45.6l10-90.4L432.9 17.1c22.9-22.9 59.9-22.9 82.7 0l43.2 43.2c22.9 22.9 22.9 60 .1 82.8zM460.1 174L402 115.9 216.2 301.8l-7.3 65.3 65.3-7.3L460.1 174zm64.8-79.7l-43.2-43.2c-4.1-4.1-10.8-4.1-14.8 0L436 82l58.1 58.1 30.9-30.9c4-4.2 4-10.8-.1-14.9z"></path></svg>
|
After Width: | Height: | Size: 746 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="wrench" class="svg-inline--fa fa-wrench fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M507.73 109.1c-2.24-9.03-13.54-12.09-20.12-5.51l-74.36 74.36-67.88-11.31-11.31-67.88 74.36-74.36c6.62-6.62 3.43-17.9-5.66-20.16-47.38-11.74-99.55.91-136.58 37.93-39.64 39.64-50.55 97.1-34.05 147.2L18.74 402.76c-24.99 24.99-24.99 65.51 0 90.5 24.99 24.99 65.51 24.99 90.5 0l213.21-213.21c50.12 16.71 107.47 5.68 147.37-34.22 37.07-37.07 49.7-89.32 37.91-136.73zM64 472c-13.25 0-24-10.75-24-24 0-13.26 10.75-24 24-24s24 10.74 24 24c0 13.25-10.75 24-24 24z"></path></svg>
|
After Width: | Height: | Size: 685 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fal" data-icon="digital-tachograph" class="svg-inline--fa fa-digital-tachograph fa-w-20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M608 96H32c-17.67 0-32 14.33-32 32v256c0 17.67 14.33 32 32 32h576c17.67 0 32-14.33 32-32V128c0-17.67-14.33-32-32-32zm0 288H32V128h576v256zM80 272h208c8.84 0 16-7.16 16-16v-80c0-8.84-7.16-16-16-16H80c-8.84 0-16 7.16-16 16v80c0 8.84 7.16 16 16 16zm8-88h192v64H88v-64zM72 360h224c4.42 0 8-3.58 8-8v-8c0-4.42-3.58-8-8-8H72c-4.42 0-8 3.58-8 8v8c0 4.42 3.58 8 8 8zm272 0h224c4.42 0 8-3.58 8-8v-8c0-4.42-3.58-8-8-8H344c-4.42 0-8 3.58-8 8v8c0 4.42 3.58 8 8 8zM80 288c-4.42 0-8 3.58-8 8v16c0 4.42 3.58 8 8 8h16c4.42 0 8-3.58 8-8v-16c0-4.42-3.58-8-8-8H80zm64 0c-4.42 0-8 3.58-8 8v16c0 4.42 3.58 8 8 8h16c4.42 0 8-3.58 8-8v-16c0-4.42-3.58-8-8-8h-16zm64 0c-4.42 0-8 3.58-8 8v16c0 4.42 3.58 8 8 8h16c4.42 0 8-3.58 8-8v-16c0-4.42-3.58-8-8-8h-16zm64 0c-4.42 0-8 3.58-8 8v16c0 4.42 3.58 8 8 8h16c4.42 0 8-3.58 8-8v-16c0-4.42-3.58-8-8-8h-16z"></path></svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,204 @@
|
||||||
|
<template>
|
||||||
|
<Tabs :navAuto="true" name="Add Item" ref="tabView">
|
||||||
|
<TabItem name="Config">
|
||||||
|
<div class="main-options-container">
|
||||||
|
<h2>Configuration Options</h2>
|
||||||
|
<a href="/conf.yml" download class="hyperlink-wrapper">
|
||||||
|
<button class="config-button center">
|
||||||
|
<DownloadIcon class="button-icon"/>
|
||||||
|
Download Config
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
<button class="config-button center" @click="goToEdit()">
|
||||||
|
<EditIcon class="button-icon"/>
|
||||||
|
Edit Sections
|
||||||
|
</button>
|
||||||
|
<button class="config-button center" @click="goToMetaEdit()">
|
||||||
|
<MetaDataIcon class="button-icon"/>
|
||||||
|
Edit Meta Data
|
||||||
|
</button>
|
||||||
|
<button class="config-button center" @click="resetLocalSettings()">
|
||||||
|
<DeleteIcon class="button-icon"/>
|
||||||
|
Reset Local Settings
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</TabItem>
|
||||||
|
<TabItem name="Edit Sections">
|
||||||
|
<JsonEditor :sections="sections" />
|
||||||
|
</TabItem>
|
||||||
|
<TabItem name="View Raw YAML">
|
||||||
|
<pre>{{this.jsonParser(this.config)}}</pre>
|
||||||
|
<a class="download-button" href="/conf.yml" download>Download Config</a>
|
||||||
|
</TabItem>
|
||||||
|
<TabItem name="Edit Site Meta">
|
||||||
|
<EditSiteMeta :config="config" />
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import JsonToYaml from '@/utils/JsonToYaml';
|
||||||
|
import EditSiteMeta from '@/components/Configuration/EditSiteMeta';
|
||||||
|
import JsonEditor from '@/components/Configuration/JsonEditor';
|
||||||
|
import DownloadIcon from '@/assets/interface-icons/config-download-file.svg';
|
||||||
|
import DeleteIcon from '@/assets/interface-icons/config-delete-local.svg';
|
||||||
|
import EditIcon from '@/assets/interface-icons/config-edit-json.svg';
|
||||||
|
import MetaDataIcon from '@/assets/interface-icons/config-meta-data.svg';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ConfigContainer',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
jsonParser: JsonToYaml,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
config: Object,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
sections: function getSections() {
|
||||||
|
return this.config.sections;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
EditSiteMeta,
|
||||||
|
JsonEditor,
|
||||||
|
DownloadIcon,
|
||||||
|
DeleteIcon,
|
||||||
|
EditIcon,
|
||||||
|
MetaDataIcon,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/* Seletcs the edit tab of the tab view */
|
||||||
|
goToEdit() {
|
||||||
|
const itemToSelect = this.$refs.tabView.navItems[1];
|
||||||
|
this.$refs.tabView.activeTabItem({ tabItem: itemToSelect, byUser: true });
|
||||||
|
},
|
||||||
|
goToMetaEdit() {
|
||||||
|
const itemToSelect = this.$refs.tabView.navItems[3];
|
||||||
|
this.$refs.tabView.activeTabItem({ tabItem: itemToSelect, byUser: true });
|
||||||
|
},
|
||||||
|
/* Checks that the user is sure, then resets site-wide local storage, and reloads page */
|
||||||
|
resetLocalSettings() {
|
||||||
|
const msg = 'This will remove all user settings from local storage, '
|
||||||
|
+ 'but won\'t effect your \'conf.yml\' file. '
|
||||||
|
+ 'It is recommend to make a backup of your modified YAML settings first.\n\n'
|
||||||
|
+ 'Are you sure you want to proceed?';
|
||||||
|
const isTheUserSure = confirm(msg); // eslint-disable-line no-alert, no-restricted-globals
|
||||||
|
if (isTheUserSure) {
|
||||||
|
localStorage.clear();
|
||||||
|
this.$toasted.show('Data cleared succesfully');
|
||||||
|
setTimeout(() => {
|
||||||
|
location.reload(); // eslint-disable-line no-restricted-globals
|
||||||
|
}, 1900);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
pre {
|
||||||
|
color: var(--config-code-color);
|
||||||
|
background: var(--config-code-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.config-button, button.config-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
margin: 0.25rem auto;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
background: var(--config-settings-background);
|
||||||
|
color: var(--config-settings-color);
|
||||||
|
border: 1px solid var(--config-settings-color);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0.5rem auto;
|
||||||
|
width: 18rem;
|
||||||
|
svg.button-icon {
|
||||||
|
path {
|
||||||
|
fill: var(--config-settings-color);
|
||||||
|
}
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
padding: 0.2rem;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background: var(--config-settings-color);
|
||||||
|
color: var(--config-settings-background);
|
||||||
|
svg path {
|
||||||
|
fill: var(--config-settings-background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.download-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
right: 2px;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--config-settings-background);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background: var(--config-settings-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.hyperlink-wrapper {
|
||||||
|
margin: 0 auto;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-options-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-top: 2rem;
|
||||||
|
background: var(--background-darker);
|
||||||
|
height: calc(100% - 2rem);
|
||||||
|
h2 {
|
||||||
|
margin: 1rem auto;
|
||||||
|
color: var(--config-settings-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.tab__pagination {
|
||||||
|
background: var(--config-settings-background);
|
||||||
|
color: var(--config-settings-color);
|
||||||
|
.tab__nav__items .tab__nav__item {
|
||||||
|
span {
|
||||||
|
color: var(--config-settings-color);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background: var(--config-settings-color) !important;
|
||||||
|
span {
|
||||||
|
color: var(--config-settings-background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
span {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--config-settings-color) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tab__nav__items .tab__nav__item.active {
|
||||||
|
border-bottom: 2px solid var(--config-settings-color);
|
||||||
|
}
|
||||||
|
hr.tab__slider {
|
||||||
|
background: var(--config-settings-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,111 @@
|
||||||
|
<template>
|
||||||
|
<div class="site-meta-container">
|
||||||
|
<h2>Edit Site Meta</h2>
|
||||||
|
<div class="form">
|
||||||
|
<div class="row">
|
||||||
|
<span>Title</span>
|
||||||
|
<input v-model="formElements.title" />
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span>Description</span>
|
||||||
|
<input v-model="formElements.description" />
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span>Footer Text</span>
|
||||||
|
<input v-model="formElements.footerText" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="save-button" @click="save()">Save Changes</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { localStorageKeys } from '@/utils/defaults';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'EditSiteMeta',
|
||||||
|
props: {
|
||||||
|
config: Object,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
save() {
|
||||||
|
const pageInfo = { ...this.config.pageInfo };
|
||||||
|
pageInfo.title = this.formElements.title;
|
||||||
|
pageInfo.description = this.formElements.description;
|
||||||
|
pageInfo.footerText = this.formElements.footerText;
|
||||||
|
localStorage.setItem(localStorageKeys.PAGE_INFO, JSON.stringify(pageInfo));
|
||||||
|
this.$toasted.show('Changes seved succesfully');
|
||||||
|
setTimeout(() => { location.reload(); }, 1500); // eslint-disable-line no-restricted-globals
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formElements: {
|
||||||
|
title: this.config.pageInfo.title,
|
||||||
|
description: this.config.pageInfo.description,
|
||||||
|
footerText: this.config.pageInfo.footerText,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.site-meta-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-top: 1rem;
|
||||||
|
background: var(--background-darker);
|
||||||
|
height: calc(100% - 1rem);
|
||||||
|
h2 {
|
||||||
|
margin: 1rem auto;
|
||||||
|
color: var(--config-settings-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
div.row {
|
||||||
|
margin: 0.25rem auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: baseline;
|
||||||
|
min-width: 24rem;
|
||||||
|
span {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
color: var(--config-settings-color);
|
||||||
|
background: none;
|
||||||
|
border: 1px solid var(--config-settings-color);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
margin: 0.5rem;
|
||||||
|
min-width: 8rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 1px 1px 6px #00ccb4;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button.save-button {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
margin: 0.5rem auto;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
width: 24rem;
|
||||||
|
background: var(--config-settings-background);
|
||||||
|
color: var(--config-settings-color);
|
||||||
|
border: 1px solid var(--config-settings-color);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background: var(--config-settings-color);
|
||||||
|
color: var(--config-settings-background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,85 @@
|
||||||
|
<template>
|
||||||
|
<div class="json-editor-outer">
|
||||||
|
<v-jsoneditor
|
||||||
|
v-model="jsonData"
|
||||||
|
:options="options"
|
||||||
|
height="650px"
|
||||||
|
/>
|
||||||
|
<button class="save-button" @click="save()">Save Changes</button>
|
||||||
|
<p class="note">
|
||||||
|
It is recommend to backup your existing confiruration before making any changes.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import VJsoneditor from 'v-jsoneditor';
|
||||||
|
import { localStorageKeys } from '@/utils/defaults';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JsonEditor',
|
||||||
|
props: {
|
||||||
|
sections: Array,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
VJsoneditor,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
jsonData: this.sections,
|
||||||
|
options: {
|
||||||
|
mode: 'tree',
|
||||||
|
modes: ['tree', 'code', 'preview'],
|
||||||
|
name: 'sections',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
save() {
|
||||||
|
localStorage.setItem(localStorageKeys.CONF_SECTIONS, JSON.stringify(this.jsonData));
|
||||||
|
this.$toasted.show('Changes seved succesfully');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
.json-editor-outer {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
p.note {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--medium-grey);
|
||||||
|
margin: 0.2rem;
|
||||||
|
}
|
||||||
|
button.save-button {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
margin: 0.25rem auto;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
background: var(--config-settings-color);
|
||||||
|
color: var(--config-settings-background);
|
||||||
|
border: 1px solid var(--config-settings-background);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background: var(--config-settings-background);
|
||||||
|
color: var(--config-settings-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.jsoneditor-menu {
|
||||||
|
background: var(--config-settings-background);
|
||||||
|
color: var(--config-settings-color);
|
||||||
|
}
|
||||||
|
.jsoneditor-contextmenu .jsoneditor-menu li button.jsoneditor-selected,
|
||||||
|
.jsoneditor-contextmenu .jsoneditor-menu li button.jsoneditor-selected:focus,
|
||||||
|
.jsoneditor-contextmenu .jsoneditor-menu li button.jsoneditor-selected:hover {
|
||||||
|
background: var(--config-settings-color);
|
||||||
|
color: var(--config-settings-background);
|
||||||
|
}
|
||||||
|
.jsoneditor-poweredBy {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -100,7 +100,6 @@ export default {
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
position: relative;
|
|
||||||
color: var(--item-text-color);
|
color: var(--item-text-color);
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin: 0.5rem;
|
margin: 0.5rem;
|
||||||
|
@ -116,6 +115,7 @@ export default {
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: var(--item-hover-shadow);
|
box-shadow: var(--item-hover-shadow);
|
||||||
background: var(--item-background-hover);
|
background: var(--item-background-hover);
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: 2px solid var(--primary);
|
outline: 2px solid var(--primary);
|
||||||
|
|
|
@ -99,7 +99,7 @@ export default {
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.tile-icon {
|
.tile-icon {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
filter: var(--item-icon-transform);
|
// filter: var(--item-icon-transform);
|
||||||
&.broken { display: none; }
|
&.broken { display: none; }
|
||||||
}
|
}
|
||||||
i.fas, i.fab, i.far, i.fal, i.fad {
|
i.fas, i.fab, i.far, i.fal, i.fad {
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
<template>
|
||||||
|
<div class="config-options">
|
||||||
|
<!-- Button and label -->
|
||||||
|
<span>Config</span>
|
||||||
|
<div class="config-buttons">
|
||||||
|
<IconSpanner v-tooltip="tooltip('Update configuration locally')" @click="showEditor()" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal containing all the configuration options -->
|
||||||
|
<modal :name="modalName" :resizable="true" width="60%" height="80%"
|
||||||
|
@closed="$emit('modalChanged', false)">
|
||||||
|
<ConfigContainer :config="combineConfig()" />
|
||||||
|
</modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import IconSpanner from '@/assets/interface-icons/config-editor.svg';
|
||||||
|
import ConfigContainer from '@/components/Configuration/ConfigContainer';
|
||||||
|
import { topLevelConfKeys } from '@/utils/defaults';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ConfigLauncher',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
modalName: 'CONF-EDITOR',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
IconSpanner,
|
||||||
|
ConfigContainer,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
sections: Array,
|
||||||
|
pageInfo: Object,
|
||||||
|
appConfig: Object,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showEditor: function show() {
|
||||||
|
this.$modal.show(this.modalName);
|
||||||
|
this.$emit('modalChanged', true);
|
||||||
|
},
|
||||||
|
combineConfig() {
|
||||||
|
const conf = {};
|
||||||
|
conf[topLevelConfKeys.APP_CONFIG] = this.appConfig;
|
||||||
|
conf[topLevelConfKeys.PAGE_INFO] = this.pageInfo;
|
||||||
|
conf[topLevelConfKeys.SECTIONS] = this.sections;
|
||||||
|
return conf;
|
||||||
|
},
|
||||||
|
updateConfig() {
|
||||||
|
// this.$emit('iconSizeUpdated', iconSize);
|
||||||
|
},
|
||||||
|
tooltip(content) {
|
||||||
|
return { content, trigger: 'hover focus', delay: 250 };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.config-options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: var(--settings-text-color);
|
||||||
|
svg {
|
||||||
|
path {
|
||||||
|
fill: var(--settings-text-color);
|
||||||
|
}
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
margin: 0.2rem;
|
||||||
|
padding: 0.2rem;
|
||||||
|
text-align: center;
|
||||||
|
background: var(--background);
|
||||||
|
border: 1px solid currentColor;
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover, &.selected {
|
||||||
|
background: var(--settings-text-color);
|
||||||
|
path { fill: var(--background); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.vm--modal {
|
||||||
|
box-shadow: 0 40px 70px -2px hsl(0deg 0% 0% / 60%), 1px 1px 6px var(--primary);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -21,13 +21,13 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
shouldHide: true, // False = show/ true = hide. Intuitive, eh?
|
shouldHide: true, // False = show/ true = hide. Intuitive, eh?
|
||||||
|
timeDelay: 3000, // Short delay in ms before popup appears
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/**
|
||||||
* If the session storage item exists, true will be returned
|
* Returns true if the key exists in session storage, otherwise false
|
||||||
* Otherwise, if not then false is returned.
|
* And the !! just converts 'false' to false, as strings resolve to true
|
||||||
* Note the !! just converts 'false' to false, as strings resolve to true
|
|
||||||
*/
|
*/
|
||||||
shouldHideWelcomeMessage() {
|
shouldHideWelcomeMessage() {
|
||||||
return !!localStorage[localStorageKeys.HIDE_WELCOME_BANNER];
|
return !!localStorage[localStorageKeys.HIDE_WELCOME_BANNER];
|
||||||
|
@ -39,7 +39,11 @@ export default {
|
||||||
hideWelcomeHelper() {
|
hideWelcomeHelper() {
|
||||||
this.shouldHide = true;
|
this.shouldHide = true;
|
||||||
localStorage.setItem(localStorageKeys.HIDE_WELCOME_BANNER, true);
|
localStorage.setItem(localStorageKeys.HIDE_WELCOME_BANNER, true);
|
||||||
window.removeEventListener('keyup');
|
window.removeEventListener('keyup', this.keyPressEvent);
|
||||||
|
},
|
||||||
|
/* Passed to window function, to add/ remove event listener */
|
||||||
|
keyPressEvent(event) {
|
||||||
|
if (event.keyCode === 27) this.hideWelcomeHelper();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -50,11 +54,8 @@ export default {
|
||||||
mounted() {
|
mounted() {
|
||||||
const shouldHide = this.shouldHideWelcomeMessage();
|
const shouldHide = this.shouldHideWelcomeMessage();
|
||||||
if (!shouldHide) {
|
if (!shouldHide) {
|
||||||
window.setTimeout(() => { this.shouldHide = shouldHide; }, 3000);
|
window.setTimeout(() => { this.shouldHide = shouldHide; }, this.timeDelay);
|
||||||
window.addEventListener('keyup', (ev) => {
|
window.addEventListener('keyup', this.keyPressEvent);
|
||||||
// User pressed the escape key. Trigger permanent dismissal of dialog
|
|
||||||
if (ev.keyCode === 27) this.hideWelcomeHelper();
|
|
||||||
});
|
|
||||||
} else { // Meh, component not needed.
|
} else { // Meh, component not needed.
|
||||||
// No point wasting valuable bytes of your 32GB Ram, lets kill it
|
// No point wasting valuable bytes of your 32GB Ram, lets kill it
|
||||||
this.$destroy();
|
this.$destroy();
|
||||||
|
|
|
@ -21,6 +21,9 @@ import ArrowKeyNavigation from '@/utils/ArrowKeyNavigation';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FilterTile',
|
name: 'FilterTile',
|
||||||
|
props: {
|
||||||
|
active: Boolean,
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
input: '', // Users current search term
|
input: '', // Users current search term
|
||||||
|
@ -31,6 +34,8 @@ export default {
|
||||||
window.addEventListener('keydown', (event) => {
|
window.addEventListener('keydown', (event) => {
|
||||||
const currentElem = document.activeElement.id;
|
const currentElem = document.activeElement.id;
|
||||||
const { key, keyCode } = event;
|
const { key, keyCode } = event;
|
||||||
|
/* If a modal is open, then do nothing */
|
||||||
|
if (!this.active) return;
|
||||||
if (/^[a-zA-Z]$/.test(key) && currentElem !== 'filter-tiles') {
|
if (/^[a-zA-Z]$/.test(key) && currentElem !== 'filter-tiles') {
|
||||||
/* Letter key pressed - start searching */
|
/* Letter key pressed - start searching */
|
||||||
this.$refs.filter.focus();
|
this.$refs.filter.focus();
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<section>
|
||||||
<SearchBar @user-is-searchin="userIsTypingSomething" ref="SearchBar" v-if="searchVisible" />
|
<SearchBar ref="SearchBar"
|
||||||
|
@user-is-searchin="userIsTypingSomething"
|
||||||
|
v-if="searchVisible"
|
||||||
|
:active="!modalOpen"
|
||||||
|
/>
|
||||||
<div class="options-container" v-if="settingsVisible">
|
<div class="options-container" v-if="settingsVisible">
|
||||||
<ThemeSelector :themes="availableThemes"
|
<ThemeSelector :themes="availableThemes"
|
||||||
:confTheme="getInitialTheme()" :userThemes="getUserThemes()" />
|
:confTheme="getInitialTheme()" :userThemes="getUserThemes()" />
|
||||||
<LayoutSelector :displayLayout="displayLayout" @layoutUpdated="updateDisplayLayout"/>
|
<LayoutSelector :displayLayout="displayLayout" @layoutUpdated="updateDisplayLayout"/>
|
||||||
<ItemSizeSelector :iconSize="iconSize" @iconSizeUpdated="updateIconSize" />
|
<ItemSizeSelector :iconSize="iconSize" @iconSizeUpdated="updateIconSize" />
|
||||||
|
<ConfigLauncher :sections="sections" :pageInfo="pageInfo" :appConfig="appConfig"
|
||||||
|
@modalChanged="modalChanged" />
|
||||||
</div>
|
</div>
|
||||||
<KeyboardShortcutInfo />
|
<KeyboardShortcutInfo />
|
||||||
</section>
|
</section>
|
||||||
|
@ -14,6 +20,7 @@
|
||||||
<script>
|
<script>
|
||||||
import Defaults from '@/utils/defaults';
|
import Defaults from '@/utils/defaults';
|
||||||
import SearchBar from '@/components/Settings/SearchBar';
|
import SearchBar from '@/components/Settings/SearchBar';
|
||||||
|
import ConfigLauncher from '@/components/Settings/ConfigLauncher';
|
||||||
import ThemeSelector from '@/components/Settings/ThemeSelector';
|
import ThemeSelector from '@/components/Settings/ThemeSelector';
|
||||||
import LayoutSelector from '@/components/Settings/LayoutSelector';
|
import LayoutSelector from '@/components/Settings/LayoutSelector';
|
||||||
import ItemSizeSelector from '@/components/Settings/ItemSizeSelector';
|
import ItemSizeSelector from '@/components/Settings/ItemSizeSelector';
|
||||||
|
@ -26,9 +33,13 @@ export default {
|
||||||
iconSize: String,
|
iconSize: String,
|
||||||
availableThemes: Object,
|
availableThemes: Object,
|
||||||
appConfig: Object,
|
appConfig: Object,
|
||||||
|
pageInfo: Object,
|
||||||
|
sections: Array,
|
||||||
|
modalOpen: Boolean,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
SearchBar,
|
SearchBar,
|
||||||
|
ConfigLauncher,
|
||||||
ThemeSelector,
|
ThemeSelector,
|
||||||
LayoutSelector,
|
LayoutSelector,
|
||||||
ItemSizeSelector,
|
ItemSizeSelector,
|
||||||
|
@ -47,6 +58,9 @@ export default {
|
||||||
updateIconSize(iconSize) {
|
updateIconSize(iconSize) {
|
||||||
this.$emit('change-icon-size', iconSize);
|
this.$emit('change-icon-size', iconSize);
|
||||||
},
|
},
|
||||||
|
modalChanged(changedTo) {
|
||||||
|
this.$emit('change-modal-visibility', changedTo);
|
||||||
|
},
|
||||||
getInitialTheme() {
|
getInitialTheme() {
|
||||||
return this.appConfig.theme || '';
|
return this.appConfig.theme || '';
|
||||||
},
|
},
|
||||||
|
@ -59,7 +73,7 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
searchVisible: Defaults.visibleComponents.searchBar,
|
searchVisible: Defaults.visibleComponents.searchBar && !this.modalOpen,
|
||||||
settingsVisible: Defaults.visibleComponents.settings,
|
settingsVisible: Defaults.visibleComponents.settings,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -89,6 +103,7 @@ export default {
|
||||||
div {
|
div {
|
||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
opacity: var(--dimming-factor);
|
opacity: var(--dimming-factor);
|
||||||
|
opacity: 1;
|
||||||
&:hover { opacity: 1; }
|
&:hover { opacity: 1; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,18 @@ import Vue from 'vue';
|
||||||
import VTooltip from 'v-tooltip'; // A Vue directive for Popper.js, tooltip component
|
import VTooltip from 'v-tooltip'; // A Vue directive for Popper.js, tooltip component
|
||||||
import VModal from 'vue-js-modal'; // Modal component
|
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 Toasted from 'vue-toasted'; // Toast component, used to show confirmation notifications
|
||||||
|
|
||||||
|
import { toastedOptions } from './utils/defaults';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
import './registerServiceWorker';
|
import './registerServiceWorker';
|
||||||
|
|
||||||
Vue.use(VTooltip);
|
Vue.use(VTooltip);
|
||||||
Vue.use(VModal);
|
Vue.use(VModal);
|
||||||
|
Vue.use(VTabs);
|
||||||
|
Vue.use(Toasted, toastedOptions);
|
||||||
Vue.component('v-select', VSelect);
|
Vue.component('v-select', VSelect);
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
|
|
|
@ -2,9 +2,18 @@ import Vue from 'vue';
|
||||||
import Router from 'vue-router';
|
import Router from 'vue-router';
|
||||||
import Home from './views/Home.vue';
|
import Home from './views/Home.vue';
|
||||||
import conf from '../public/conf.yml'; // Main site configuration
|
import conf from '../public/conf.yml'; // Main site configuration
|
||||||
|
import { pageInfo as defaultPageInfo, localStorageKeys } from './utils/defaults';
|
||||||
|
|
||||||
Vue.use(Router);
|
Vue.use(Router);
|
||||||
|
|
||||||
|
const { sections, pageInfo, appConfig } = conf;
|
||||||
|
let localPageInfo;
|
||||||
|
try {
|
||||||
|
localPageInfo = JSON.parse(localStorage[localStorageKeys.PAGE_INFO]);
|
||||||
|
} catch (e) {
|
||||||
|
localPageInfo = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const router = new Router({
|
const router = new Router({
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
|
@ -12,8 +21,9 @@ const router = new Router({
|
||||||
name: 'home',
|
name: 'home',
|
||||||
component: Home,
|
component: Home,
|
||||||
props: {
|
props: {
|
||||||
sections: conf.sections || [],
|
sections: sections || [],
|
||||||
appConfig: conf.appConfig || {},
|
pageInfo: localPageInfo || pageInfo || defaultPageInfo,
|
||||||
|
appConfig: appConfig || {},
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Home Page',
|
title: 'Home Page',
|
||||||
|
|
|
@ -31,7 +31,9 @@
|
||||||
--item-group-shadow: var(--item-shadow);
|
--item-group-shadow: var(--item-shadow);
|
||||||
--settings-container-shadow: none;
|
--settings-container-shadow: none;
|
||||||
|
|
||||||
/* Specific components, using variables allows them to be overridden individually */
|
/* Color variables for specific components
|
||||||
|
* all variables are optional, since they inherit initial values from above*
|
||||||
|
* Using specific variables makes overriding for custom themes really easy */
|
||||||
--heading-text-color: var(--primary);
|
--heading-text-color: var(--primary);
|
||||||
--nav-link-text-color: var(--primary);
|
--nav-link-text-color: var(--primary);
|
||||||
--nav-link-background-color: #607d8b33;
|
--nav-link-background-color: #607d8b33;
|
||||||
|
@ -51,4 +53,10 @@
|
||||||
--footer-text-color-link: var(--primary);
|
--footer-text-color-link: var(--primary);
|
||||||
--welcome-popup-background: var(--background-darker);
|
--welcome-popup-background: var(--background-darker);
|
||||||
--welcome-popup-text-color: var(--primary);
|
--welcome-popup-text-color: var(--primary);
|
||||||
|
--config-code-background: #fff;
|
||||||
|
--config-code-color: var(--background);
|
||||||
|
--config-settings-color: var(--primary);
|
||||||
|
--config-settings-background: var(--background-darker);
|
||||||
|
--toast-background: var(--primary);
|
||||||
|
--toast-color: var(--background);
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,8 @@ html[data-theme='material-dark'] {
|
||||||
--item-icon-transform-hover: drop-shadow(1px 3px 2px var(--transparent-30)) saturate(2);
|
--item-icon-transform-hover: drop-shadow(1px 3px 2px var(--transparent-30)) saturate(2);
|
||||||
--welcome-popup-background: #131a1f;
|
--welcome-popup-background: #131a1f;
|
||||||
--welcome-popup-text-color: var(--primary);
|
--welcome-popup-text-color: var(--primary);
|
||||||
|
--config-settings-background: #131a1f;
|
||||||
|
--config-settings-color: #41e2ed;
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-theme='colorful'] {
|
html[data-theme='colorful'] {
|
||||||
|
|
|
@ -11,7 +11,7 @@ html {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default app font face */
|
/* Default app font face */
|
||||||
body, div, p, a, span, label, input {
|
body, div, p, a, span, label, input, button {
|
||||||
font-family: 'Inconsolata', sans-serif;
|
font-family: 'Inconsolata', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,4 +20,13 @@ h1, h2, h3, h4, h5 {
|
||||||
font-family: 'Inconsolata', sans-serif;
|
font-family: 'Inconsolata', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Overiding styles for the global toast component */
|
||||||
|
.toast-message {
|
||||||
|
background: var(--toast-background) !important;
|
||||||
|
color: var(--toast-color) !important;
|
||||||
|
border: 1px solid var(--toast-color) !important;
|
||||||
|
border-radius: var(--curve-factor) !important;
|
||||||
|
font-size: 1.25rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
import { typeOf } from 'remedial';
|
||||||
|
|
||||||
|
const trimWhitespace = (input) => input.split('\n').map(x => x.trimRight()).join('\n');
|
||||||
|
|
||||||
|
const throwError = (msg) => {
|
||||||
|
throw new Error(`Error in Json to YAML conversion: ${msg}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A function that converts valid JSON into valid YAML */
|
||||||
|
const stringify = (data) => {
|
||||||
|
let indentLevel = '';
|
||||||
|
const handlers = {
|
||||||
|
undefined() {
|
||||||
|
return 'null';
|
||||||
|
},
|
||||||
|
null() {
|
||||||
|
return 'null';
|
||||||
|
},
|
||||||
|
number(x) {
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
boolean(x) {
|
||||||
|
return x ? 'true' : 'false';
|
||||||
|
},
|
||||||
|
string(x) {
|
||||||
|
return JSON.stringify(x);
|
||||||
|
},
|
||||||
|
array(x) {
|
||||||
|
let output = '';
|
||||||
|
if (x.length === 0) {
|
||||||
|
output += '[]';
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
indentLevel = indentLevel.replace(/$/, ' ');
|
||||||
|
x.forEach((y) => {
|
||||||
|
const handler = handlers[typeOf(y)];
|
||||||
|
|
||||||
|
if (!handler) throwError(typeOf(y));
|
||||||
|
|
||||||
|
output += `\n${indentLevel}- ${handler(y, true)}`;
|
||||||
|
});
|
||||||
|
indentLevel = indentLevel.replace(/ {2}/, '');
|
||||||
|
|
||||||
|
return output;
|
||||||
|
},
|
||||||
|
object(x, inArray, rootNode) {
|
||||||
|
let output = '';
|
||||||
|
|
||||||
|
if (Object.keys(x).length === 0) {
|
||||||
|
output += '{}';
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rootNode) {
|
||||||
|
indentLevel = indentLevel.replace(/$/, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(x).forEach((k, i) => {
|
||||||
|
const val = x[k];
|
||||||
|
const handler = handlers[typeOf(val)];
|
||||||
|
|
||||||
|
if (typeof val === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handler) throwError(typeOf(val));
|
||||||
|
|
||||||
|
if (!(inArray && i === 0)) {
|
||||||
|
output += `\n${indentLevel}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
output += `${k}: ${handler(val)}`;
|
||||||
|
});
|
||||||
|
indentLevel = indentLevel.replace(/ {2}/, '');
|
||||||
|
|
||||||
|
return output;
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
return '[object Function]';
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return trimWhitespace(`${handlers[typeOf(data)](data, true, true)}\n`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default stringify;
|
|
@ -44,5 +44,20 @@ module.exports = {
|
||||||
COLLAPSE_STATE: 'collapseState',
|
COLLAPSE_STATE: 'collapseState',
|
||||||
ICON_SIZE: 'iconSize',
|
ICON_SIZE: 'iconSize',
|
||||||
THEME: 'theme',
|
THEME: 'theme',
|
||||||
|
CONF_SECTIONS: 'confSections',
|
||||||
|
PAGE_INFO: 'pageInfo',
|
||||||
|
APP_CONFIG: 'appConfig',
|
||||||
|
},
|
||||||
|
topLevelConfKeys: {
|
||||||
|
PAGE_INFO: 'pageInfo',
|
||||||
|
APP_CONFIG: 'appConfig',
|
||||||
|
SECTIONS: 'sections',
|
||||||
|
},
|
||||||
|
toastedOptions: {
|
||||||
|
position: 'bottom-center',
|
||||||
|
duration: 2000,
|
||||||
|
keepOnHover: true,
|
||||||
|
className: 'toast-message',
|
||||||
|
iconPack: 'fontawesome',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,17 +5,21 @@
|
||||||
@user-is-searchin="searching"
|
@user-is-searchin="searching"
|
||||||
@change-display-layout="setLayoutOrientation"
|
@change-display-layout="setLayoutOrientation"
|
||||||
@change-icon-size="setItemSize"
|
@change-icon-size="setItemSize"
|
||||||
|
@change-modal-visibility="updateModalVisibility"
|
||||||
:displayLayout="layout"
|
:displayLayout="layout"
|
||||||
:iconSize="itemSizeBound"
|
:iconSize="itemSizeBound"
|
||||||
:availableThemes="getExternalCSSLinks()"
|
:availableThemes="getExternalCSSLinks()"
|
||||||
|
:sections="getSections(sections)"
|
||||||
:appConfig="appConfig"
|
:appConfig="appConfig"
|
||||||
|
:pageInfo="pageInfo"
|
||||||
|
:modalOpen="modalOpen"
|
||||||
class="filter-container"
|
class="filter-container"
|
||||||
/>
|
/>
|
||||||
<!-- Main content, section for each group of items -->
|
<!-- Main content, section for each group of items -->
|
||||||
<div v-if="checkTheresData(sections)"
|
<div v-if="checkTheresData(sections)"
|
||||||
:class="`item-group-container orientation-${layout} item-size-${itemSizeBound}`">
|
:class="`item-group-container orientation-${layout} item-size-${itemSizeBound}`">
|
||||||
<ItemGroup
|
<ItemGroup
|
||||||
v-for="(section, index) in sections"
|
v-for="(section, index) in getSections(sections)"
|
||||||
:key="index"
|
:key="index"
|
||||||
:title="section.name"
|
:title="section.name"
|
||||||
:displayData="getDisplayData(section)"
|
:displayData="getDisplayData(section)"
|
||||||
|
@ -44,6 +48,7 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
sections: Array, // Main site content
|
sections: Array, // Main site content
|
||||||
appConfig: Object, // Main site configuation (optional)
|
appConfig: Object, // Main site configuation (optional)
|
||||||
|
pageInfo: Object, // Page metadata (optional)
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
SettingsContainer,
|
SettingsContainer,
|
||||||
|
@ -53,6 +58,7 @@ export default {
|
||||||
searchValue: '',
|
searchValue: '',
|
||||||
layout: '',
|
layout: '',
|
||||||
itemSizeBound: '',
|
itemSizeBound: '',
|
||||||
|
modalOpen: false, // When true, keybindings are disabled
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
layoutOrientation: {
|
layoutOrientation: {
|
||||||
|
@ -73,7 +79,19 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
/* Returns true if there is one or more sections in the config */
|
/* Returns true if there is one or more sections in the config */
|
||||||
checkTheresData(sections) {
|
checkTheresData(sections) {
|
||||||
return sections && sections.length >= 1;
|
const localSections = localStorage[localStorageKeys.CONF_SECTIONS];
|
||||||
|
return (sections && sections.length >= 1) || (localSections && localSections.length >= 1);
|
||||||
|
},
|
||||||
|
/* Returns sections from local storage if available, otherwise uses the conf.yml */
|
||||||
|
getSections(sections) {
|
||||||
|
// If the user has stored sections in local storage, return those
|
||||||
|
const localSections = localStorage[localStorageKeys.CONF_SECTIONS];
|
||||||
|
if (localSections) {
|
||||||
|
const json = JSON.parse(localSections);
|
||||||
|
if (json.length >= 1) return json;
|
||||||
|
}
|
||||||
|
// Otherwise, return the usuall data from conf.yml
|
||||||
|
return sections;
|
||||||
},
|
},
|
||||||
/* Updates local data with search value, triggered from filter comp */
|
/* Updates local data with search value, triggered from filter comp */
|
||||||
searching(searchValue) {
|
searching(searchValue) {
|
||||||
|
@ -116,6 +134,10 @@ export default {
|
||||||
setItemSize(itemSize) {
|
setItemSize(itemSize) {
|
||||||
this.iconSize = itemSize;
|
this.iconSize = itemSize;
|
||||||
},
|
},
|
||||||
|
/* Update data when modal is open (so that key bindings can be disabled) */
|
||||||
|
updateModalVisibility(modalState) {
|
||||||
|
this.modalOpen = modalState;
|
||||||
|
},
|
||||||
/* Returns an array of links to external CSS from the Config */
|
/* Returns an array of links to external CSS from the Config */
|
||||||
getExternalCSSLinks() {
|
getExternalCSSLinks() {
|
||||||
const availibleThemes = {};
|
const availibleThemes = {};
|
||||||
|
|
86
yarn.lock
86
yarn.lock
|
@ -957,6 +957,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@soda/get-current-script/-/get-current-script-1.0.2.tgz#a53515db25d8038374381b73af20bb4f2e508d87"
|
resolved "https://registry.yarnpkg.com/@soda/get-current-script/-/get-current-script-1.0.2.tgz#a53515db25d8038374381b73af20bb4f2e508d87"
|
||||||
integrity sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==
|
integrity sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==
|
||||||
|
|
||||||
|
"@sphinxxxx/color-conversion@^2.2.2":
|
||||||
|
version "2.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz#03ecc29279e3c0c832f6185a5bfa3497858ac8ca"
|
||||||
|
integrity sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw==
|
||||||
|
|
||||||
"@types/anymatch@*":
|
"@types/anymatch@*":
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
|
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
|
||||||
|
@ -1580,6 +1585,11 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
|
||||||
mime-types "~2.1.24"
|
mime-types "~2.1.24"
|
||||||
negotiator "0.6.2"
|
negotiator "0.6.2"
|
||||||
|
|
||||||
|
ace-builds@^1.4.12:
|
||||||
|
version "1.4.12"
|
||||||
|
resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.12.tgz#888efa386e36f4345f40b5233fcc4fe4c588fae7"
|
||||||
|
integrity sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg==
|
||||||
|
|
||||||
acorn-jsx@^5.2.0, acorn-jsx@^5.3.1:
|
acorn-jsx@^5.2.0, acorn-jsx@^5.3.1:
|
||||||
version "5.3.1"
|
version "5.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
|
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
|
||||||
|
@ -1623,7 +1633,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
|
||||||
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
|
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
|
||||||
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
|
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
|
||||||
|
|
||||||
ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4:
|
ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.6:
|
||||||
version "6.12.6"
|
version "6.12.6"
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
||||||
|
@ -5231,6 +5241,11 @@ isstream@~0.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||||
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
||||||
|
|
||||||
|
javascript-natural-sort@^0.7.1:
|
||||||
|
version "0.7.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
|
||||||
|
integrity sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k=
|
||||||
|
|
||||||
javascript-stringify@^2.0.1:
|
javascript-stringify@^2.0.1:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79"
|
resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79"
|
||||||
|
@ -5244,6 +5259,11 @@ jest-worker@^25.4.0:
|
||||||
merge-stream "^2.0.0"
|
merge-stream "^2.0.0"
|
||||||
supports-color "^7.0.0"
|
supports-color "^7.0.0"
|
||||||
|
|
||||||
|
jmespath@^0.15.0:
|
||||||
|
version "0.15.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217"
|
||||||
|
integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=
|
||||||
|
|
||||||
js-message@1.0.7:
|
js-message@1.0.7:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/js-message/-/js-message-1.0.7.tgz#fbddd053c7a47021871bb8b2c95397cc17c20e47"
|
resolved "https://registry.yarnpkg.com/js-message/-/js-message-1.0.7.tgz#fbddd053c7a47021871bb8b2c95397cc17c20e47"
|
||||||
|
@ -5314,6 +5334,11 @@ json-schema@0.2.3:
|
||||||
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
||||||
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
|
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
|
||||||
|
|
||||||
|
json-source-map@^0.6.1:
|
||||||
|
version "0.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/json-source-map/-/json-source-map-0.6.1.tgz#e0b1f6f4ce13a9ad57e2ae165a24d06e62c79a0f"
|
||||||
|
integrity sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg==
|
||||||
|
|
||||||
json-stable-stringify-without-jsonify@^1.0.1:
|
json-stable-stringify-without-jsonify@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
|
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
|
||||||
|
@ -5355,6 +5380,21 @@ json5@^2.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
minimist "^1.2.5"
|
minimist "^1.2.5"
|
||||||
|
|
||||||
|
jsoneditor@^9.1.1:
|
||||||
|
version "9.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/jsoneditor/-/jsoneditor-9.4.1.tgz#cebd6cefc74ae3c8354b6d84c4e86d4e78fea0b9"
|
||||||
|
integrity sha512-Uf/ru12Y4eRo4xoYaFjpbB13fIXVUQG6GZO21i3yhlfKL389HLV8e8El77grup01IRdtcoB01P8rZTY4d6uXjA==
|
||||||
|
dependencies:
|
||||||
|
ace-builds "^1.4.12"
|
||||||
|
ajv "^6.12.6"
|
||||||
|
javascript-natural-sort "^0.7.1"
|
||||||
|
jmespath "^0.15.0"
|
||||||
|
json-source-map "^0.6.1"
|
||||||
|
jsonrepair "^2.2.0"
|
||||||
|
mobius1-selectr "^2.4.13"
|
||||||
|
picomodal "^3.0.0"
|
||||||
|
vanilla-picker "^2.11.2"
|
||||||
|
|
||||||
jsonfile@^4.0.0:
|
jsonfile@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
|
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
|
||||||
|
@ -5367,6 +5407,11 @@ jsonify@~0.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
|
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
|
||||||
integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=
|
integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=
|
||||||
|
|
||||||
|
jsonrepair@^2.2.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/jsonrepair/-/jsonrepair-2.2.0.tgz#3cdaa6fbc9ced360f401cef9c97f1a8caf3470e5"
|
||||||
|
integrity sha512-NyqcDyer9N4OEDwkZZjmSwd17T9tOfvqTSs9GDpbmPp928Rc1Tot7sOTNenIpMaavD3LkAFkDcNcjmxv3Vqvbg==
|
||||||
|
|
||||||
jsprim@^1.2.2:
|
jsprim@^1.2.2:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
||||||
|
@ -5874,6 +5919,11 @@ mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
minimist "^1.2.5"
|
minimist "^1.2.5"
|
||||||
|
|
||||||
|
mobius1-selectr@^2.4.13:
|
||||||
|
version "2.4.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/mobius1-selectr/-/mobius1-selectr-2.4.13.tgz#0019dfd9f984840d6e40f70683ab3ec78ce3b5df"
|
||||||
|
integrity sha512-Mk9qDrvU44UUL0EBhbAA1phfQZ7aMZPjwtL7wkpiBzGh8dETGqfsh50mWoX9EkjDlkONlErWXArHCKfoxVg0Bw==
|
||||||
|
|
||||||
move-concurrently@^1.0.1:
|
move-concurrently@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
|
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
|
||||||
|
@ -6553,6 +6603,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
|
||||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d"
|
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d"
|
||||||
integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==
|
integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==
|
||||||
|
|
||||||
|
picomodal@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/picomodal/-/picomodal-3.0.0.tgz#facd30f4fbf34a809c1e04ea525f004f399c0b82"
|
||||||
|
integrity sha1-+s0w9PvzSoCcHgTqUl8ATzmcC4I=
|
||||||
|
|
||||||
pify@^2.0.0:
|
pify@^2.0.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||||
|
@ -7314,6 +7369,11 @@ relateurl@0.2.x:
|
||||||
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
|
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
|
||||||
integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
|
integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
|
||||||
|
|
||||||
|
remedial@^1.0.8:
|
||||||
|
version "1.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/remedial/-/remedial-1.0.8.tgz#a5e4fd52a0e4956adbaf62da63a5a46a78c578a0"
|
||||||
|
integrity sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg==
|
||||||
|
|
||||||
remove-trailing-separator@^1.0.1:
|
remove-trailing-separator@^1.0.1:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
|
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
|
||||||
|
@ -8657,6 +8717,13 @@ uuid@^3.3.2, uuid@^3.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||||
|
|
||||||
|
v-jsoneditor@^1.4.2:
|
||||||
|
version "1.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/v-jsoneditor/-/v-jsoneditor-1.4.2.tgz#2a877fb3ed137732f8e6269b99b32758bd304ad0"
|
||||||
|
integrity sha512-cLY/41uD7+1fJGpbs7HPwBv20UHlNpi8A6zhI9t5lVGLgQ/7lK5pLsZeLAz+4ybOXXK091HDgdB/wEnCTYMFFw==
|
||||||
|
dependencies:
|
||||||
|
jsoneditor "^9.1.1"
|
||||||
|
|
||||||
v-tooltip@^2.1.3:
|
v-tooltip@^2.1.3:
|
||||||
version "2.1.3"
|
version "2.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/v-tooltip/-/v-tooltip-2.1.3.tgz#281c2015d1e73787f13c8956aa295b8c3a73f261"
|
resolved "https://registry.yarnpkg.com/v-tooltip/-/v-tooltip-2.1.3.tgz#281c2015d1e73787f13c8956aa295b8c3a73f261"
|
||||||
|
@ -8680,6 +8747,13 @@ validate-npm-package-license@^3.0.1:
|
||||||
spdx-correct "^3.0.0"
|
spdx-correct "^3.0.0"
|
||||||
spdx-expression-parse "^3.0.0"
|
spdx-expression-parse "^3.0.0"
|
||||||
|
|
||||||
|
vanilla-picker@^2.11.2:
|
||||||
|
version "2.11.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/vanilla-picker/-/vanilla-picker-2.11.2.tgz#eaa24efa68c27e7ee9e0776df55d6913b855f133"
|
||||||
|
integrity sha512-2cP7LlUnxHxwOf06ReUVtd2RFJMnJGaxN2s0p8wzBH3In5b00Le7fFZ9VrIoBE0svZkSq/BC/Pwq/k/9n+AA2g==
|
||||||
|
dependencies:
|
||||||
|
"@sphinxxxx/color-conversion" "^2.2.2"
|
||||||
|
|
||||||
vary@~1.1.2:
|
vary@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||||
|
@ -8756,6 +8830,11 @@ vue-loader@^15.9.2:
|
||||||
vue-hot-reload-api "^2.3.0"
|
vue-hot-reload-api "^2.3.0"
|
||||||
vue-style-loader "^4.1.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-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"
|
||||||
|
@ -8802,6 +8881,11 @@ vue-template-es2015-compiler@^1.9.0:
|
||||||
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
||||||
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
||||||
|
|
||||||
|
vue-toasted@^1.1.28:
|
||||||
|
version "1.1.28"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-toasted/-/vue-toasted-1.1.28.tgz#dbabb83acc89f7a9e8765815e491d79f0dc65c26"
|
||||||
|
integrity sha512-UUzr5LX51UbbiROSGZ49GOgSzFxaMHK6L00JV8fir/CYNJCpIIvNZ5YmS4Qc8Y2+Z/4VVYRpeQL2UO0G800Raw==
|
||||||
|
|
||||||
vue@^2.6.10:
|
vue@^2.6.10:
|
||||||
version "2.6.12"
|
version "2.6.12"
|
||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
|
||||||
|
|
Loading…
Reference in New Issue