mirror of
https://github.com/Lissy93/dashy.git
synced 2024-12-27 02:43:55 +03:00
Merge pull request #8 from Lissy93/bug-fixes-and-improvments
Implements custom CSS editor, customizable item grids, other new features and bug fixes
This commit is contained in:
commit
484a62566b
15
README.md
15
README.md
@ -36,6 +36,8 @@
|
|||||||
<img width="800" src="https://i.ibb.co/L8YbNNc/dashy-demo2.gif" alt="Demo">
|
<img width="800" src="https://i.ibb.co/L8YbNNc/dashy-demo2.gif" alt="Demo">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
![More themes and screens](https://i.ibb.co/M6nyvqW/dashy-options-screen.png)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Running the App 🏃♂️
|
## Running the App 🏃♂️
|
||||||
@ -96,6 +98,7 @@ All fields are optional, unless otherwise stated.
|
|||||||
- `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_
|
||||||
|
|
||||||
@ -104,11 +107,16 @@ All fields are optional, unless otherwise stated.
|
|||||||
- `items` - Item[]: (required) An array of items - _See **`item`** below_
|
- `items` - Item[]: (required) An array of items - _See **`item`** below_
|
||||||
- `displayData`: An object with the following fields (all optional)
|
- `displayData`: An object with the following fields (all optional)
|
||||||
- `collapsed` - Boolean: If true, the section will be collapsed initially (defaults to `false`)
|
- `collapsed` - Boolean: If true, the section will be collapsed initially (defaults to `false`)
|
||||||
- `rows` - Int: Number of rows the section should span vertically, e.g. 2 (defaults to `1`)
|
|
||||||
- `cols` - Int: Number of columns the section should span horizontally, e.g. 2 (defaults to `1`)
|
|
||||||
- `color` - String: A custom accent color for the section, as a hex code or HTML color (e.g. `#fff`)
|
- `color` - String: A custom accent color for the section, as a hex code or HTML color (e.g. `#fff`)
|
||||||
- `customStyles` - String: Custom CSS properties that should be applied to that section, e.g. `border: 2px dashed #ff0000;`
|
- `customStyles` - String: Custom CSS properties that should be applied to that section, e.g. `border: 2px dashed #ff0000;`
|
||||||
- `itemSize` - String: Specify the size for items within this group, either `small`, `medium` or `large`
|
- `itemSize` - String: Specify the size for items within this group, either `small`, `medium` or `large`
|
||||||
|
- `rows` - Int: Number of rows the section should span vertically, e.g. 2 (defaults to `1`)
|
||||||
|
- `cols` - Int: Number of columns the section should span horizontally, e.g. 2 (defaults to `1`)
|
||||||
|
- `layout` - Enum: `auto` or `grid`. If `grid` is selected, then the number of items per row can be set
|
||||||
|
- `itemCountX` - Int: Number of items horizontally (for `layout: grid`)
|
||||||
|
- `itemCountY` - Int: Number of items vertically (for `layout: grid`)
|
||||||
|
|
||||||
|
Note about `rows` and `cols`: These are defined as a proportion of the screen (rather than by number of child items), and is built using [`grid-layout`](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout). For more info, see [this example](https://i.ibb.co/HXRWVRK/how-rows-and-cols-work-in-dashy.png). In order to set the number of items that will display horizontally or vertically within a section, first set `display: grid`, and then specify values for `itemCountX`, and optionally `itemCountY`.
|
||||||
|
|
||||||
**`item`**
|
**`item`**
|
||||||
- `title` - String: The text to display on the item
|
- `title` - String: The text to display on the item
|
||||||
@ -174,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`
|
||||||
- And using [`ajv`](https://github.com/ajv-validator/ajv) `MIT` JSON schema Validator [`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`
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"connect": "^3.7.0",
|
"connect": "^3.7.0",
|
||||||
"crypto-js": "^4.0.0",
|
"crypto-js": "^4.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",
|
||||||
@ -20,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"
|
||||||
|
@ -509,6 +509,6 @@
|
|||||||
],
|
],
|
||||||
"start_url": "./index.html",
|
"start_url": "./index.html",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"background_color": "#000000",
|
"background_color": "#0b1021",
|
||||||
"theme_color": "#4DBA87"
|
"theme_color": "#4DBA87"
|
||||||
}
|
}
|
25
src/App.vue
25
src/App.vue
@ -20,11 +20,21 @@ export default {
|
|||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
// pageInfo: this.getPageInfo(conf.pageInfo),
|
// pageInfo: this.getPageInfo(conf.pageInfo),
|
||||||
appConfig: conf.appConfig || Defaults.appConfig,
|
|
||||||
showFooter: Defaults.visibleComponents.footer,
|
showFooter: Defaults.visibleComponents.footer,
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
pageInfo: function pi() { return this.getPageInfo(conf.pageInfo); },
|
pageInfo() {
|
||||||
|
return this.getPageInfo(conf.pageInfo);
|
||||||
|
},
|
||||||
|
appConfig() {
|
||||||
|
if (localStorage[localStorageKeys.APP_CONFIG]) {
|
||||||
|
return JSON.parse(localStorage[localStorageKeys.APP_CONFIG]);
|
||||||
|
} else if (conf.appConfig) {
|
||||||
|
return conf.appConfig;
|
||||||
|
} else {
|
||||||
|
return Defaults.appConfig;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* Returns either page info from the config, or default values */
|
/* Returns either page info from the config, or default values */
|
||||||
@ -53,6 +63,17 @@ export default {
|
|||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
|
injectCustomStyles(usersCss) {
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = usersCss;
|
||||||
|
document.head.append(style);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.appConfig.customCss) {
|
||||||
|
const cleanedCss = this.appConfig.customCss.replace(/<\/?[^>]+(>|$)/g, '');
|
||||||
|
this.injectCustomStyles(cleanedCss);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
1
src/assets/interface-icons/config-custom-css.svg
Normal file
1
src/assets/interface-icons/config-custom-css.svg
Normal 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 |
@ -3,7 +3,7 @@
|
|||||||
<div class="section intro">
|
<div class="section intro">
|
||||||
<h2>Cloud Backup & Restore</h2>
|
<h2>Cloud Backup & Restore</h2>
|
||||||
<p class="intro">
|
<p class="intro">
|
||||||
Cloud backup and restore is an optional feature, that enabled you to upload your
|
Cloud backup and restore is an optional feature, that enables you to upload your
|
||||||
config to the internet, and then restore it on any other device or instance of Dashy.
|
config to the internet, and then restore it on any other device or instance of Dashy.
|
||||||
<br><br>
|
<br><br>
|
||||||
All data is fully end-to-end encrypted with AES, using your password as the key.
|
All data is fully end-to-end encrypted with AES, using your password as the key.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<Tabs :navAuto="true" name="Add Item" ref="tabView">
|
<Tabs :navAuto="true" name="Add Item" ref="tabView">
|
||||||
<TabItem name="Config">
|
<TabItem name="Config" class="main-tab">
|
||||||
<div class="main-options-container">
|
<div class="main-options-container">
|
||||||
<h2>Configuration Options</h2>
|
<h2>Configuration Options</h2>
|
||||||
<a href="/conf.yml" download class="hyperlink-wrapper">
|
<a href="/conf.yml" download class="hyperlink-wrapper">
|
||||||
@ -17,10 +17,25 @@
|
|||||||
<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()">
|
||||||
|
<CloudIcon class="button-icon"/>
|
||||||
|
{{backupId ? 'Edit Cloud Sync' : 'Enable Cloud Sync'}}
|
||||||
|
</button>
|
||||||
<button class="config-button center" @click="resetLocalSettings()">
|
<button class="config-button center" @click="resetLocalSettings()">
|
||||||
<DeleteIcon class="button-icon"/>
|
<DeleteIcon class="button-icon"/>
|
||||||
Reset Local Settings
|
Reset Local Settings
|
||||||
</button>
|
</button>
|
||||||
|
<div class="config-note">
|
||||||
|
<p class="sub-title">Note:</p>
|
||||||
|
<span>
|
||||||
|
All changes made here are stored locally. To apply globally, either export your config
|
||||||
|
into your conf.yml file, or use the cloud backup/ restore feature.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem name="Backup Config" class="code-container">
|
<TabItem name="Backup Config" class="code-container">
|
||||||
@ -38,24 +53,36 @@
|
|||||||
<TabItem name="Edit Site Meta">
|
<TabItem name="Edit Site Meta">
|
||||||
<EditSiteMeta :config="config" />
|
<EditSiteMeta :config="config" />
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
<TabItem name="Custom Styles">
|
||||||
|
<CustomCssEditor :config="config" initialCss="hello" />
|
||||||
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
import hljs from 'highlight.js/lib/core';
|
||||||
|
import yaml from 'highlight.js/lib/languages/yaml';
|
||||||
|
import 'highlight.js/styles/mono-blue.css';
|
||||||
|
|
||||||
import JsonToYaml from '@/utils/JsonToYaml';
|
import JsonToYaml from '@/utils/JsonToYaml';
|
||||||
|
import { localStorageKeys, modalNames } from '@/utils/defaults';
|
||||||
import EditSiteMeta from '@/components/Configuration/EditSiteMeta';
|
import EditSiteMeta from '@/components/Configuration/EditSiteMeta';
|
||||||
import JsonEditor from '@/components/Configuration/JsonEditor';
|
import JsonEditor from '@/components/Configuration/JsonEditor';
|
||||||
|
import CustomCssEditor from '@/components/Configuration/CustomCss';
|
||||||
import DownloadIcon from '@/assets/interface-icons/config-download-file.svg';
|
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';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ConfigContainer',
|
name: 'ConfigContainer',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
jsonParser: JsonToYaml,
|
jsonParser: JsonToYaml,
|
||||||
|
backupId: localStorage[localStorageKeys.BACKUP_ID] || '',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@ -69,10 +96,13 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
EditSiteMeta,
|
EditSiteMeta,
|
||||||
JsonEditor,
|
JsonEditor,
|
||||||
|
CustomCssEditor,
|
||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
DeleteIcon,
|
DeleteIcon,
|
||||||
EditIcon,
|
EditIcon,
|
||||||
|
CloudIcon,
|
||||||
MetaDataIcon,
|
MetaDataIcon,
|
||||||
|
CustomCssIcon,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* Seletcs the edit tab of the tab view */
|
/* Seletcs the edit tab of the tab view */
|
||||||
@ -84,6 +114,13 @@ 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() {
|
||||||
|
this.$modal.show(modalNames.CLOUD_BACKUP);
|
||||||
|
},
|
||||||
copyConfigToClipboard() {
|
copyConfigToClipboard() {
|
||||||
navigator.clipboard.writeText(this.jsonParser(this.config));
|
navigator.clipboard.writeText(this.jsonParser(this.config));
|
||||||
// event.target.textContent = 'Copied to clipboard';
|
// event.target.textContent = 'Copied to clipboard';
|
||||||
@ -104,13 +141,20 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
hljs.registerLanguage('yaml', yaml);
|
||||||
|
const highlighted = hljs.highlight(this.jsonParser(this.config), { language: 'yaml' }).value;
|
||||||
|
document.getElementById('conf-yaml').innerHTML = highlighted;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@import '@/styles/style-helpers.scss';
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
color: var(--config-code-color);
|
color: var(--config-code-color);
|
||||||
|
font-weight: bold !important;
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +192,12 @@ a.config-button, button.config-button {
|
|||||||
|
|
||||||
div.code-container {
|
div.code-container {
|
||||||
background: var(--config-code-background);
|
background: var(--config-code-background);
|
||||||
|
#conf-yaml {
|
||||||
|
font-family: 'Inconsolata', sans-serif;
|
||||||
|
.hljs-attr {
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
.yaml-action-buttons {
|
.yaml-action-buttons {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0.5rem;
|
top: 0.5rem;
|
||||||
@ -186,7 +236,11 @@ div.code-container {
|
|||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
@extend .scroll-bar;
|
||||||
background: var(--config-settings-background);
|
background: var(--config-settings-background);
|
||||||
|
&.main-tab {
|
||||||
|
min-height: 500px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a.hyperlink-wrapper {
|
a.hyperlink-wrapper {
|
||||||
@ -205,6 +259,25 @@ a.hyperlink-wrapper {
|
|||||||
color: var(--config-settings-color);
|
color: var(--config-settings-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.config-note {
|
||||||
|
width: 80%;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 1rem;
|
||||||
|
left: 10%;
|
||||||
|
margin: 0.5rem auto;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
border: 1px dashed var(--config-settings-color);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
text-align: left;
|
||||||
|
opacity: var(--dimming-factor);
|
||||||
|
background: var(--config-settings-background);
|
||||||
|
p.sub-title {
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -235,4 +308,8 @@ a.hyperlink-wrapper {
|
|||||||
background: var(--config-settings-color);
|
background: var(--config-settings-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#conf-yaml .hljs-attr {
|
||||||
|
color: #9c03f5;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
88
src/components/Configuration/CustomCss.vue
Normal file
88
src/components/Configuration/CustomCss.vue
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<div class="json-editor-outer">
|
||||||
|
<prism-editor class="my-editor" v-model="customCss" :highlight="highlighter" line-numbers />
|
||||||
|
<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>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<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';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JsonEditor',
|
||||||
|
props: {
|
||||||
|
config: Object,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
PrismEditor,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
customCss: this.config.appConfig.customCss || '\n\n\n\n\n',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
validate(css) {
|
||||||
|
return css.match(/((?:^\s*)([\w#.@*,:\-.:>,*\s]+)\s*{(?:[\s]*)((?:[A-Za-z\- \s]+[:]\s*['"0-9\w .,/()\-!%]+;?)*)*\s*}(?:\s*))/gmi);
|
||||||
|
},
|
||||||
|
save() {
|
||||||
|
let msg = '';
|
||||||
|
if (this.validate(this.customCss)) {
|
||||||
|
const appConfig = { ...this.config.appConfig };
|
||||||
|
appConfig.customCss = this.customCss;
|
||||||
|
localStorage.setItem(localStorageKeys.APP_CONFIG, JSON.stringify(appConfig));
|
||||||
|
msg = 'Changes saved succesfully';
|
||||||
|
this.inject(this.customCss);
|
||||||
|
} else {
|
||||||
|
msg = 'Error - Invalid CSS';
|
||||||
|
}
|
||||||
|
this.$toasted.show(msg);
|
||||||
|
},
|
||||||
|
inject(userStyles) {
|
||||||
|
const cleanedCss = userStyles.replace(/<\/?[^>]+(>|$)/g, '');
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = cleanedCss;
|
||||||
|
document.head.append(style);
|
||||||
|
},
|
||||||
|
highlighter(code) {
|
||||||
|
return highlight(code, languages.css);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
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);
|
||||||
|
border-color: var(--config-settings-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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>
|
@ -77,7 +77,7 @@ export default {
|
|||||||
title: this.config.pageInfo.title,
|
title: this.config.pageInfo.title,
|
||||||
description: this.config.pageInfo.description,
|
description: this.config.pageInfo.description,
|
||||||
footerText: this.config.pageInfo.footerText,
|
footerText: this.config.pageInfo.footerText,
|
||||||
navLinks: this.config.pageInfo.navLinks,
|
navLinks: this.config.pageInfo.navLinks || [],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -38,7 +38,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
save() {
|
save() {
|
||||||
localStorage.setItem(localStorageKeys.CONF_SECTIONS, JSON.stringify(this.jsonData));
|
localStorage.setItem(localStorageKeys.CONF_SECTIONS, JSON.stringify(this.jsonData));
|
||||||
this.$toasted.show('Changes seved succesfully');
|
this.$toasted.show('Changes saved succesfully');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<modal :name="name" :resizable="true" width="80%" height="80%" @closed="$emit('closed')">
|
<modal :name="name" :resizable="true" width="80%" height="80%" @closed="modalClosed()">
|
||||||
<div slot="top-right" @click="hide()">Close</div>
|
<div slot="top-right" @click="hide()">Close</div>
|
||||||
<a @click="hide()" class="close-button" title="Close">x</a>
|
<a @click="hide()" class="close-button" title="Close">x</a>
|
||||||
<iframe v-if="url" :src="url" @keydown.esc="close" class="frame"/>
|
<iframe v-if="url" :src="url" @keydown.esc="close" class="frame"/>
|
||||||
@ -20,10 +20,14 @@ export default {
|
|||||||
show: function show(url) {
|
show: function show(url) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.$modal.show(this.name);
|
this.$modal.show(this.name);
|
||||||
|
this.$emit('modalChanged', true);
|
||||||
},
|
},
|
||||||
hide: function hide() {
|
hide: function hide() {
|
||||||
this.$modal.hide(this.name);
|
this.$modal.hide(this.name);
|
||||||
},
|
},
|
||||||
|
modalClosed() {
|
||||||
|
this.$emit('modalChanged', false);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -11,7 +11,10 @@
|
|||||||
<div v-if="!items || items.length < 1" class="no-items">
|
<div v-if="!items || items.length < 1" class="no-items">
|
||||||
No Items to Show Yet
|
No Items to Show Yet
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="there-are-items">
|
<div v-else
|
||||||
|
:class="`there-are-items ${isGridLayout? 'item-group-grid': ''}`"
|
||||||
|
:style="gridStyle"
|
||||||
|
>
|
||||||
<Item
|
<Item
|
||||||
v-for="(item, index) in items"
|
v-for="(item, index) in items"
|
||||||
:id="`${index}_${makeId(item.title)}`"
|
:id="`${index}_${makeId(item.title)}`"
|
||||||
@ -33,6 +36,7 @@
|
|||||||
:ref="`iframeModal-${groupId}`"
|
:ref="`iframeModal-${groupId}`"
|
||||||
:name="`iframeModal-${groupId}`"
|
:name="`iframeModal-${groupId}`"
|
||||||
@closed="$emit('itemClicked')"
|
@closed="$emit('itemClicked')"
|
||||||
|
@modalChanged="modalChanged"
|
||||||
/>
|
/>
|
||||||
</Collapsable>
|
</Collapsable>
|
||||||
</template>
|
</template>
|
||||||
@ -50,6 +54,7 @@ export default {
|
|||||||
displayData: Object,
|
displayData: Object,
|
||||||
items: Array,
|
items: Array,
|
||||||
itemSize: String,
|
itemSize: String,
|
||||||
|
modalOpen: Boolean,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Collapsable,
|
Collapsable,
|
||||||
@ -57,9 +62,21 @@ export default {
|
|||||||
IframeModal,
|
IframeModal,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
newItemSize: function size() {
|
newItemSize() {
|
||||||
return this.displayData.itemSize || this.itemSize;
|
return this.displayData.itemSize || this.itemSize;
|
||||||
},
|
},
|
||||||
|
isGridLayout() {
|
||||||
|
return this.displayData.layout === 'grid'
|
||||||
|
|| !!(this.displayData.itemCountX || this.displayData.itemCountY);
|
||||||
|
},
|
||||||
|
gridStyle() {
|
||||||
|
let styles = '';
|
||||||
|
styles += this.displayData.itemCountX
|
||||||
|
? `grid-template-columns: repeat(${this.displayData.itemCountX}, 1fr);` : '';
|
||||||
|
styles += this.displayData.itemCountY
|
||||||
|
? `grid-template-rows: repeat(${this.displayData.itemCountY}, 1fr);` : '';
|
||||||
|
return styles;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* Returns a unique lowercase string, based on name, for section ID */
|
/* Returns a unique lowercase string, based on name, for section ID */
|
||||||
@ -70,11 +87,16 @@ export default {
|
|||||||
triggerModal(url) {
|
triggerModal(url) {
|
||||||
this.$refs[`iframeModal-${this.groupId}`].show(url);
|
this.$refs[`iframeModal-${this.groupId}`].show(url);
|
||||||
},
|
},
|
||||||
|
modalChanged(changedTo) {
|
||||||
|
this.$emit('change-modal-visibility', changedTo);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@import '@/styles/media-queries.scss';
|
||||||
|
@import '@/styles/style-helpers.scss';
|
||||||
|
|
||||||
.no-items {
|
.no-items {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
@ -92,6 +114,17 @@ export default {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
&.item-group-grid {
|
||||||
|
display: grid;
|
||||||
|
overflow: auto;
|
||||||
|
@extend .scroll-bar;
|
||||||
|
@include phone { grid-template-columns: repeat(1, 1fr); }
|
||||||
|
@include tablet { grid-template-columns: repeat(2, 1fr); }
|
||||||
|
@include laptop { grid-template-columns: repeat(2, 1fr); }
|
||||||
|
@include monitor { grid-template-columns: repeat(3, 1fr); }
|
||||||
|
@include big-screen { grid-template-columns: repeat(4, 1fr); }
|
||||||
|
@include big-screen-up { grid-template-columns: repeat(5, 1fr); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -27,16 +27,13 @@ import IconSpanner from '@/assets/interface-icons/config-editor.svg';
|
|||||||
import IconCloud from '@/assets/interface-icons/cloud-backup-restore.svg';
|
import IconCloud from '@/assets/interface-icons/cloud-backup-restore.svg';
|
||||||
import ConfigContainer from '@/components/Configuration/ConfigContainer';
|
import ConfigContainer from '@/components/Configuration/ConfigContainer';
|
||||||
import CloudBackupRestore from '@/components/Configuration/CloudBackupRestore';
|
import CloudBackupRestore from '@/components/Configuration/CloudBackupRestore';
|
||||||
import { topLevelConfKeys, localStorageKeys } from '@/utils/defaults';
|
import { topLevelConfKeys, localStorageKeys, modalNames } from '@/utils/defaults';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ConfigLauncher',
|
name: 'ConfigLauncher',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
modalNames: {
|
modalNames,
|
||||||
CONF_EDITOR: 'CONF_EDITOR',
|
|
||||||
CLOUD_BACKUP: 'CLOUD_BACKUP',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@ -52,11 +49,11 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showEditor: function show() {
|
showEditor: function show() {
|
||||||
this.$modal.show(this.modalNames.CONF_EDITOR);
|
this.$modal.show(modalNames.CONF_EDITOR);
|
||||||
this.$emit('modalChanged', true);
|
this.$emit('modalChanged', true);
|
||||||
},
|
},
|
||||||
showCloudModal: function show() {
|
showCloudModal: function show() {
|
||||||
this.$modal.show(this.modalNames.CLOUD_BACKUP);
|
this.$modal.show(modalNames.CLOUD_BACKUP);
|
||||||
this.$emit('modalChanged', true);
|
this.$emit('modalChanged', true);
|
||||||
},
|
},
|
||||||
combineConfig() {
|
combineConfig() {
|
||||||
|
@ -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';
|
||||||
|
@ -14,6 +14,13 @@ try {
|
|||||||
localPageInfo = undefined;
|
localPageInfo = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let localAppConfig;
|
||||||
|
try {
|
||||||
|
localAppConfig = JSON.parse(localStorage[localStorageKeys.APP_CONFIG]);
|
||||||
|
} catch (e) {
|
||||||
|
localAppConfig = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const router = new Router({
|
const router = new Router({
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
@ -23,7 +30,7 @@ const router = new Router({
|
|||||||
props: {
|
props: {
|
||||||
sections: sections || [],
|
sections: sections || [],
|
||||||
pageInfo: localPageInfo || pageInfo || defaultPageInfo,
|
pageInfo: localPageInfo || pageInfo || defaultPageInfo,
|
||||||
appConfig: appConfig || {},
|
appConfig: localAppConfig || appConfig || {},
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Home Page',
|
title: 'Home Page',
|
||||||
|
@ -35,9 +35,10 @@
|
|||||||
--outline-color: none;
|
--outline-color: none;
|
||||||
--curve-factor: 5px; // Border radius for most components
|
--curve-factor: 5px; // Border radius for most components
|
||||||
--curve-factor-navbar: 16px; // Border radius for header
|
--curve-factor-navbar: 16px; // Border radius for header
|
||||||
--dimming-factor: 0.8; // Opacity for semi-transparent components
|
--dimming-factor: 0.7; // Opacity for semi-transparent components
|
||||||
|
|
||||||
/* Settings for specific components */
|
/* Settings for specific components */
|
||||||
|
--scroll-bar-width: 8px;
|
||||||
--item-group-padding: 5px; // Determines width of item-group outline
|
--item-group-padding: 5px; // Determines width of item-group outline
|
||||||
--item-shadow: 1px 1px 2px #130f23;
|
--item-shadow: 1px 1px 2px #130f23;
|
||||||
--item-hover-shadow: 1px 2px 4px #373737;
|
--item-hover-shadow: 1px 2px 4px #373737;
|
||||||
@ -74,4 +75,6 @@
|
|||||||
--config-settings-background: var(--background-darker);
|
--config-settings-background: var(--background-darker);
|
||||||
--toast-background: var(--primary);
|
--toast-background: var(--primary);
|
||||||
--toast-color: var(--background);
|
--toast-color: var(--background);
|
||||||
|
--scroll-bar-color: var(--primary);
|
||||||
|
--scroll-bar-background: var(--background-darker);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
@import '@/styles/style-helpers.scss';
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inconsolata';
|
font-family: 'Inconsolata';
|
||||||
src: url('./assets/fonts/Inconsolata-Light.ttf');
|
src: url('./assets/fonts/Inconsolata-Light.ttf');
|
||||||
@ -8,6 +10,8 @@ html {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
transition: all 1s;
|
transition: all 1s;
|
||||||
|
margin-top: -3px;
|
||||||
|
@extend .scroll-bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default app font face */
|
/* Default app font face */
|
||||||
@ -19,33 +23,3 @@ body, div, p, a, span, label, input, button {
|
|||||||
h1, h2, h3, h4, h5 {
|
h1, h2, h3, h4, h5 {
|
||||||
font-family: 'Inconsolata', sans-serif;
|
font-family: 'Inconsolata', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bold { font-weight: bold; }
|
|
||||||
.light { font-weight: lighter; }
|
|
||||||
.text-left { text-align: left;}
|
|
||||||
.text-right { text-align: right;}
|
|
||||||
.text-center { text-align: center;}
|
|
||||||
.horizontal-center { margin: 0 auto; }
|
|
||||||
.border-box { box-sizing: border-box; }
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toast-error {
|
|
||||||
background: var(--danger) !important;
|
|
||||||
color: var(--white) !important;
|
|
||||||
font-size: 1.25rem !important;
|
|
||||||
}
|
|
||||||
.toast-success {
|
|
||||||
background: var(--success) !important;
|
|
||||||
color: var(--white) !important;
|
|
||||||
font-size: 1.25rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
44
src/styles/style-helpers.scss
Normal file
44
src/styles/style-helpers.scss
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
/* Fancy scrollbar */
|
||||||
|
.scroll-bar {
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: var(--scroll-bar-width);
|
||||||
|
height: var(--scroll-bar-width);
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
background-color: var(--scroll-bar-background);
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--scroll-bar-color);
|
||||||
|
border-radius: var(--curve-factor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Single-style helpers */
|
||||||
|
.bold { font-weight: bold; }
|
||||||
|
.light { font-weight: lighter; }
|
||||||
|
.text-left { text-align: left;}
|
||||||
|
.text-right { text-align: right;}
|
||||||
|
.text-center { text-align: center;}
|
||||||
|
.horizontal-center { margin: 0 auto; }
|
||||||
|
.border-box { box-sizing: border-box; }
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
.toast-error {
|
||||||
|
background: var(--danger) !important;
|
||||||
|
color: var(--white) !important;
|
||||||
|
font-size: 1.25rem !important;
|
||||||
|
}
|
||||||
|
.toast-success {
|
||||||
|
background: var(--success) !important;
|
||||||
|
color: var(--white) !important;
|
||||||
|
font-size: 1.25rem !important;
|
||||||
|
}
|
@ -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) => {
|
||||||
|
@ -50,6 +50,10 @@ module.exports = {
|
|||||||
BACKUP_ID: 'backupId',
|
BACKUP_ID: 'backupId',
|
||||||
BACKUP_HASH: 'backupHash',
|
BACKUP_HASH: 'backupHash',
|
||||||
},
|
},
|
||||||
|
modalNames: {
|
||||||
|
CONF_EDITOR: 'CONF_EDITOR',
|
||||||
|
CLOUD_BACKUP: 'CLOUD_BACKUP',
|
||||||
|
},
|
||||||
topLevelConfKeys: {
|
topLevelConfKeys: {
|
||||||
PAGE_INFO: 'pageInfo',
|
PAGE_INFO: 'pageInfo',
|
||||||
APP_CONFIG: 'appConfig',
|
APP_CONFIG: 'appConfig',
|
||||||
|
@ -25,8 +25,9 @@
|
|||||||
:displayData="getDisplayData(section)"
|
:displayData="getDisplayData(section)"
|
||||||
:groupId="`section-${index}`"
|
:groupId="`section-${index}`"
|
||||||
:items="filterTiles(section.items)"
|
:items="filterTiles(section.items)"
|
||||||
@itemClicked="finishedSearching()"
|
|
||||||
:itemSize="itemSizeBound"
|
:itemSize="itemSizeBound"
|
||||||
|
@itemClicked="finishedSearching()"
|
||||||
|
@change-modal-visibility="updateModalVisibility"
|
||||||
:class="(filterTiles(section.items).length === 0 && searchValue) ? 'no-results' : ''"
|
:class="(filterTiles(section.items).length === 0 && searchValue) ? 'no-results' : ''"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
48
yarn.lock
48
yarn.lock
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user