Глобальный рефакторинг SettingsPage (в процессе)

This commit is contained in:
Book Pauk
2022-10-12 20:24:08 +07:00
parent bc0c9932c8
commit 528b32ccf7
10 changed files with 353 additions and 277 deletions

View File

@@ -543,9 +543,7 @@ class Reader {
//обновим settings, если загружали обои из /upload/ //обновим settings, если загружали обои из /upload/
if (updated) { if (updated) {
const newSettings = _.cloneDeep(this.settings); this.commit('reader/setSettings', {});
newSettings.needUpdateSettingsView = (newSettings.needUpdateSettingsView < 10 ? newSettings.needUpdateSettingsView + 1 : 0);
this.commit('reader/setSettings', newSettings);
} }
dynamicCss.replace('wallpapers', newCss); dynamicCss.replace('wallpapers', newCss);

View File

@@ -23,7 +23,6 @@
stretch stretch
inline-label inline-label
> >
<div v-show="tabsScrollable" class="q-pt-lg" />
<q-tab class="tab" name="profiles" icon="la la-users" label="Профили" /> <q-tab class="tab" name="profiles" icon="la la-users" label="Профили" />
<q-tab class="tab" name="view" icon="la la-eye" label="Вид" /> <q-tab class="tab" name="view" icon="la la-eye" label="Вид" />
<q-tab class="tab" name="toolbar" icon="la la-grip-horizontal" label="Панель" /> <q-tab class="tab" name="toolbar" icon="la la-grip-horizontal" label="Панель" />
@@ -33,7 +32,6 @@
<q-tab class="tab" name="update" icon="la la-retweet" label="Обновление" /> <q-tab class="tab" name="update" icon="la la-retweet" label="Обновление" />
<q-tab class="tab" name="others" icon="la la-list-ul" label="Прочее" /> <q-tab class="tab" name="others" icon="la la-list-ul" label="Прочее" />
<q-tab class="tab" name="reset" icon="la la-broom" label="Сброс" /> <q-tab class="tab" name="reset" icon="la la-broom" label="Сброс" />
<div v-show="tabsScrollable" class="q-pt-lg" />
</q-tabs> </q-tabs>
</div> </div>
@@ -41,47 +39,7 @@
<!-- Профили ---------------------------------------------------------------------> <!-- Профили --------------------------------------------------------------------->
<ProfilesTab v-if="selectedTab == 'profiles'" :form="form" /> <ProfilesTab v-if="selectedTab == 'profiles'" :form="form" />
<!-- Вид -------------------------------------------------------------------------> <!-- Вид ------------------------------------------------------------------------->
<!--div v-if="selectedTab == 'view'" class="fit column"> <ViewTab v-if="selectedTab == 'view'" :form="form" />
<q-tabs
v-model="selectedViewTab"
active-color="black"
active-bg-color="white"
indicator-color="white"
dense
no-caps
class="no-mp bg-grey-4 text-grey-7"
>
<q-tab name="mode" label="Режим" />
<q-tab name="color" label="Цвет" />
<q-tab name="font" label="Шрифт" />
<q-tab name="text" label="Текст" />
<q-tab name="status" label="Строка статуса" />
</q-tabs>
<div class="q-mb-sm" />
<div class="col tab-panel">
<div v-if="selectedViewTab == 'mode'">
@@include('./ViewTab/Mode.inc');
</div>
<div v-if="selectedViewTab == 'color'">
@@include('./ViewTab/Color.inc');
</div>
<div v-if="selectedViewTab == 'font'">
@@include('./ViewTab/Font.inc');
</div>
<div v-if="selectedViewTab == 'text'">
@@include('./ViewTab/Text.inc');
</div>
<div v-if="selectedViewTab == 'status'">
@@include('./ViewTab/Status.inc');
</div>
</div>
</div-->
<!-- Кнопки ----------------------------------------------------------------------> <!-- Кнопки ---------------------------------------------------------------------->
<ToolBarTab v-if="selectedTab == 'toolbar'" :form="form" /> <ToolBarTab v-if="selectedTab == 'toolbar'" :form="form" />
<!-- Управление ------------------------------------------------------------------> <!-- Управление ------------------------------------------------------------------>
@@ -115,10 +73,10 @@ import wallpaperStorage from '../share/wallpaperStorage';
import readerApi from '../../../api/reader'; import readerApi from '../../../api/reader';
import rstore from '../../../store/modules/reader'; import rstore from '../../../store/modules/reader';
import defPalette from './defPalette';
//pages //pages
import ProfilesTab from './ProfilesTab/ProfilesTab.vue'; import ProfilesTab from './ProfilesTab/ProfilesTab.vue';
import ViewTab from './ViewTab/ViewTab.vue';
import ToolBarTab from './ToolBarTab/ToolBarTab.vue'; import ToolBarTab from './ToolBarTab/ToolBarTab.vue';
import KeysTab from './KeysTab/KeysTab.vue'; import KeysTab from './KeysTab/KeysTab.vue';
import PageMoveTab from './PageMoveTab/PageMoveTab.vue'; import PageMoveTab from './PageMoveTab/PageMoveTab.vue';
@@ -134,6 +92,7 @@ const componentOptions = {
Window, Window,
//pages //pages
ProfilesTab, ProfilesTab,
ViewTab,
ToolBarTab, ToolBarTab,
KeysTab, KeysTab,
PageMoveTab, PageMoveTab,
@@ -200,13 +159,6 @@ const componentOptions = {
if (hex.test(newValue)) if (hex.test(newValue))
this.backgroundColor = newValue; this.backgroundColor = newValue;
}, },
dualDivColor(newValue) {
this.dualDivColorFiltered = newValue;
},
dualDivColorFiltered(newValue) {
if (hex.test(newValue))
this.dualDivColor = newValue;
},
statusBarColor(newValue) { statusBarColor(newValue) {
this.statusBarColorFiltered = newValue; this.statusBarColorFiltered = newValue;
}, },
@@ -222,39 +174,29 @@ class SettingsPage {
form = {}; form = {};
selectedTab = 'profiles'; selectedTab = 'profiles';
selectedViewTab = 'mode';
fontBold = false;
fontItalic = false;
vertShift = 0;
tabsScrollable = false;
textColorFiltered = '';
bgColorFiltered = '';
dualDivColorFiltered = '';
statusBarColorFiltered = '';
webFonts = [];
fonts = [];
setsChanged = false; setsChanged = false;
fontBold = false;
fontItalic = false;
vertShift = 0;
textColorFiltered = '';
bgColorFiltered = '';
statusBarColorFiltered = '';
webFonts = [];
fonts = [];
created() { created() {
this.commit = this.$store.commit; this.commit = this.$store.commit;
this.reader = this.$store.state.reader;
this.debouncedCommitSettings = _.debounce(() => { this.debouncedCommitSettings = _.debounce(() => {
this.commit('reader/setSettings', _.cloneDeep(this.form)); this.commit('reader/setSettings', _.cloneDeep(this.form));
}, 100); }, 50);
this.settingsChanged();//no await this.settingsChanged();//no await
} }
mounted() { mounted() {
this.$watch(
'$refs.tabs.scrollable',
(newValue) => {
this.tabsScrollable = newValue && !this.$root.isMobileDevice;
}
);
} }
init() { init() {
@@ -263,9 +205,6 @@ class SettingsPage {
} }
async settingsChanged() { async settingsChanged() {
if (_.isEqual(this.form, this.settings))
return;
this.setsChanged = true; this.setsChanged = true;
try { try {
this.form = _.cloneDeep(this.settings); this.form = _.cloneDeep(this.settings);
@@ -326,55 +265,6 @@ class SettingsPage {
return result; return result;
} }
get predefineTextColors() {
return defPalette.concat([
'#ffffff',
'#000000',
'#202020',
'#323232',
'#aaaaaa',
'#00c0c0',
'#ebe2c9',
'#cfdc99',
'#478355',
'#909080',
]);
}
get predefineBackgroundColors() {
return defPalette.concat([
'#ffffff',
'#000000',
'#202020',
'#ebe2c9',
'#cfdc99',
'#478355',
'#a6caf0',
'#909080',
'#808080',
'#c8c8c8',
]);
}
colorPanStyle(type) {
let result = 'width: 30px; height: 30px; border: 1px solid black; border-radius: 4px;';
switch (type) {
case 'text':
result += `background-color: ${this.textColor};`
break;
case 'bg':
result += `background-color: ${this.backgroundColor};`
break;
case 'div':
result += `background-color: ${this.dualDivColor};`
break;
case 'statusbar':
result += `background-color: ${this.statusBarColor};`
break;
}
return result;
}
needReload() { needReload() {
this.$root.notify.warning('Необходимо обновить страницу (F5), чтобы изменения возымели эффект'); this.$root.notify.warning('Необходимо обновить страницу (F5), чтобы изменения возымели эффект');
} }
@@ -517,20 +407,6 @@ export default vueComponent(SettingsPage);
.tab { .tab {
justify-content: initial; justify-content: initial;
} }
.label-2 {
width: 110px;
}
.input {
max-width: 150px;
}
.no-mp {
margin: 0;
padding: 0;
}
</style> </style>
<style> <style>

View File

@@ -1,124 +0,0 @@
<!---------------------------------------------->
<div class="hidden part-header">Режим</div>
<div class="item row">
<div class="label-2"></div>
<div class="col row">
<q-checkbox v-model="dualPageMode" size="xs" label="Двухстраничный режим" />
</div>
</div>
<div class="part-header">Страницы</div>
<div class="item row">
<div class="label-2">Отступ границ</div>
<div class="col row">
<NumInput class="col-left" v-model="indentLR" :min="0" :max="2000">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Слева/справа от края экрана
</q-tooltip>
</NumInput>
<div class="q-px-sm"/>
<NumInput class="col" v-model="indentTB" :min="0" :max="2000">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Сверху/снизу от края экрана
</q-tooltip>
</NumInput>
</div>
</div>
<div v-show="dualPageMode" class="item row">
<div class="label-2">Отступ внутри</div>
<div class="col row">
<NumInput class="col-left" v-model="dualIndentLR" :min="0" :max="2000">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Слева/справа внутри страницы
</q-tooltip>
</NumInput>
</div>
</div>
<div v-show="dualPageMode">
<div class="part-header">Разделитель</div>
<div class="item row no-wrap">
<div class="label-2">Цвет</div>
<div class="col-left row">
<q-input class="col-left no-mp"
outlined dense
v-model="dualDivColorFiltered"
:rules="['hexColor']"
style="max-width: 150px"
:disable="dualDivColorAsText"
>
<template v-slot:prepend>
<q-icon name="la la-angle-down la-xs" class="cursor-pointer text-white" :style="colorPanStyle('div')">
<q-popup-proxy anchor="bottom middle" self="top middle">
<div>
<q-color v-model="dualDivColor"
no-header default-view="palette" :palette="predefineTextColors"
/>
</div>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
</div>
<div class="q-px-xs"/>
<q-checkbox v-model="dualDivColorAsText" size="xs" label="Как у текста" />
</div>
<div class="item row">
<div class="label-2">Прозрачность</div>
<div class="col row">
<NumInput class="col-left" v-model="dualDivColorAlpha" :min="0" :max="1" :digits="2" :step="0.1"/>
</div>
</div>
<div class="item row">
<div class="label-2">Ширина (px)</div>
<div class="col row">
<NumInput class="col-left" v-model="dualDivWidth" :min="0" :max="100">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Ширина разделителя
</q-tooltip>
</NumInput>
</div>
</div>
<div class="item row">
<div class="label-2">Высота (%)</div>
<div class="col row">
<NumInput class="col-left" v-model="dualDivHeight" :min="0" :max="100">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Высота разделителя
</q-tooltip>
</NumInput>
</div>
</div>
<div class="item row">
<div class="label-2">Пунктир</div>
<div class="col row">
<NumInput class="col-left" v-model="dualDivStrokeFill" :min="0" :max="2000">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Заполнение пунктира
</q-tooltip>
</NumInput>
<div class="q-px-sm"/>
<NumInput class="col" v-model="dualDivStrokeGap" :min="0" :max="2000">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Промежуток пунктира
</q-tooltip>
</NumInput>
</div>
</div>
<div class="item row">
<div class="label-2">Ширина тени</div>
<div class="col row">
<NumInput class="col-left" v-model="dualDivShadowWidth" :min="0" :max="100"/>
</div>
</div>
</div>

View File

@@ -0,0 +1,214 @@
<template>
<div class="fit sets-tab-panel">
<!---------------------------------------------->
<div class="hidden sets-part-header">
Режим
</div>
<div class="sets-item row">
<div class="sets-label label"></div>
<div class="col row">
<q-checkbox v-model="form.dualPageMode" size="xs" label="Двухстраничный режим" />
</div>
</div>
<div class="sets-part-header">
Страницы
</div>
<div class="sets-item row">
<div class="sets-label label">
Отступ границ
</div>
<div class="col row">
<NumInput v-model="form.indentLR" class="col-left" :min="0" :max="2000">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Слева/справа от края экрана
</q-tooltip>
</NumInput>
<div class="q-px-sm" />
<NumInput v-model="form.indentTB" class="col" :min="0" :max="2000">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Сверху/снизу от края экрана
</q-tooltip>
</NumInput>
</div>
</div>
<div v-show="form.dualPageMode" class="sets-item row">
<div class="sets-label label">
Отступ внутри
</div>
<div class="col row">
<NumInput v-model="form.dualIndentLR" class="col-left" :min="0" :max="2000">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Слева/справа внутри страницы
</q-tooltip>
</NumInput>
</div>
</div>
<div v-show="form.dualPageMode">
<div class="sets-part-header">
Разделитель
</div>
<div class="sets-item row no-wrap">
<div class="sets-label label">
Цвет
</div>
<div class="col-left row">
<q-input
v-model="dualDivColorFiltered"
class="col-left no-mp"
outlined dense
:rules="['hexColor']"
style="max-width: 150px"
:disable="form.dualDivColorAsText"
>
<template #prepend>
<q-icon name="la la-angle-down la-xs" class="cursor-pointer text-white" :style="helper.colorPanStyle(form.dualDivColor)">
<q-popup-proxy anchor="bottom middle" self="top middle">
<div>
<q-color
v-model="form.dualDivColor"
no-header default-view="palette" :palette="defPalette.predefineTextColors"
/>
</div>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
</div>
<div class="q-px-xs" />
<q-checkbox v-model="form.dualDivColorAsText" size="xs" label="Как у текста" />
</div>
<div class="sets-item row">
<div class="sets-label label">
Прозрачность
</div>
<div class="col row">
<NumInput v-model="form.dualDivColorAlpha" class="col-left" :min="0" :max="1" :digits="2" :step="0.1" />
</div>
</div>
<div class="sets-item row">
<div class="sets-label label">
Ширина (px)
</div>
<div class="col row">
<NumInput v-model="form.dualDivWidth" class="col-left" :min="0" :max="100">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Ширина разделителя
</q-tooltip>
</NumInput>
</div>
</div>
<div class="sets-item row">
<div class="sets-label label">
Высота (%)
</div>
<div class="col row">
<NumInput v-model="form.dualDivHeight" class="col-left" :min="0" :max="100">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Высота разделителя
</q-tooltip>
</NumInput>
</div>
</div>
<div class="sets-item row">
<div class="sets-label label">
Пунктир
</div>
<div class="col row">
<NumInput v-model="form.dualDivStrokeFill" class="col-left" :min="0" :max="2000">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Заполнение пунктира
</q-tooltip>
</NumInput>
<div class="q-px-sm" />
<NumInput v-model="form.dualDivStrokeGap" class="col" :min="0" :max="2000">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Промежуток пунктира
</q-tooltip>
</NumInput>
</div>
</div>
<div class="sets-item row">
<div class="sets-label label">
Ширина тени
</div>
<div class="col row">
<NumInput v-model="form.dualDivShadowWidth" class="col-left" :min="0" :max="100" />
</div>
</div>
</div>
</div>
</template>
<script>
//-----------------------------------------------------------------------------
import vueComponent from '../../../../vueComponent.js';
import NumInput from '../../../../share/NumInput.vue';
import * as helper from '../helper';
import defPalette from '../defPalette';
const componentOptions = {
components: {
NumInput
},
watch: {
form() {
this.formChanged();
},
dualDivColorFiltered(newValue) {
if (this.helper.isHexColor(newValue))
this.form.dualDivColor = newValue;
},
}
};
class Mode {
_options = componentOptions;
_props = {
form: Object,
};
helper = helper;
defPalette = defPalette;
dualDivColorFiltered = '';
created() {
this.formChanged();
}
mounted() {
}
formChanged() {
this.dualDivColorFiltered = this.form.dualDivColor;
}
}
export default vueComponent(Mode);
//-----------------------------------------------------------------------------
</script>
<style scoped>
.label {
width: 110px;
}
.col-left {
width: 150px;
}
.no-mp {
margin: 0;
padding: 0;
}
</style>

View File

@@ -0,0 +1,79 @@
<template>
<div class="fit column">
<q-tabs
v-model="selectedTab"
active-color="black"
active-bg-color="white"
indicator-color="white"
dense
no-caps
class="no-mp bg-grey-4 text-grey-7"
>
<q-tab name="mode" label="Режим" />
<q-tab name="color" label="Цвет" />
<q-tab name="font" label="Шрифт" />
<q-tab name="text" label="Текст" />
<q-tab name="status" label="Строка статуса" />
</q-tabs>
<div class="q-mb-sm" />
<div class="col sets-tab-panel">
<Mode v-if="selectedTab == 'mode'" :form="form" />
<!--div v-if="selectedViewTab == 'color'">
@@include('./ViewTab/Color.inc');
</div-->
<!--div v-if="selectedViewTab == 'font'">
@@include('./ViewTab/Font.inc');
</div-->
<!--div v-if="selectedViewTab == 'text'">
@@include('./ViewTab/Text.inc');
</div-->
<!--div v-if="selectedViewTab == 'status'">
@@include('./ViewTab/Status.inc');
</div-->
</div>
</div>
</template>
<script>
//-----------------------------------------------------------------------------
import vueComponent from '../../../vueComponent.js';
import Mode from './Mode/Mode.vue';
const componentOptions = {
components: {
Mode,
},
};
class ViewTab {
_options = componentOptions;
_props = {
form: Object,
};
selectedTab = 'mode';
created() {
}
mounted() {
}
}
export default vueComponent(ViewTab);
//-----------------------------------------------------------------------------
</script>
<style scoped>
.label {
width: 75px;
}
</style>

View File

@@ -14,4 +14,32 @@ const defPalette = [
'rgb(255,255,255)', 'rgb(205,205,205)', 'rgb(178,178,178)', 'rgb(153,153,153)', 'rgb(127,127,127)', 'rgb(102,102,102)', 'rgb(76,76,76)', 'rgb(51,51,51)', 'rgb(25,25,25)', 'rgb(0,0,0)' 'rgb(255,255,255)', 'rgb(205,205,205)', 'rgb(178,178,178)', 'rgb(153,153,153)', 'rgb(127,127,127)', 'rgb(102,102,102)', 'rgb(76,76,76)', 'rgb(51,51,51)', 'rgb(25,25,25)', 'rgb(0,0,0)'
]; ];
export default defPalette; export default {
predefinePalette: defPalette,
predefineTextColors: defPalette.concat([
'#ffffff',
'#000000',
'#202020',
'#323232',
'#aaaaaa',
'#00c0c0',
'#ebe2c9',
'#cfdc99',
'#478355',
'#909080',
]),
predefineBackgroundColors: defPalette.concat([
'#ffffff',
'#000000',
'#202020',
'#ebe2c9',
'#cfdc99',
'#478355',
'#a6caf0',
'#909080',
'#808080',
'#c8c8c8',
]),
};

View File

@@ -0,0 +1,9 @@
const hex = /^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/;
export function colorPanStyle(bgColor) {
return `width: 30px; height: 30px; border: 1px solid black; border-radius: 4px; background-color: ${bgColor}`;
}
export function isHexColor(value) {
return hex.test(value);
}

View File

@@ -198,10 +198,6 @@ const settingDefaults = {
bucSetOnNew: true, // автоматически включать проверку обновлений для вновь загружаемых файлов bucSetOnNew: true, // автоматически включать проверку обновлений для вновь загружаемых файлов
bucCancelEnabled: true, // вкл/выкл отмену проверки книг через bucCancelDays bucCancelEnabled: true, // вкл/выкл отмену проверки книг через bucCancelDays
bucCancelDays: 90, // количество дней, через которое отменяется проверка книги, при условии отсутствия обновлений за это время bucCancelDays: 90, // количество дней, через которое отменяется проверка книги, при условии отсутствия обновлений за это время
//для SettingsPage
needUpdateSettingsView: 0,
}; };
for (const font of fonts) for (const font of fonts)

14
package-lock.json generated
View File

@@ -29,7 +29,7 @@
"pako": "^2.0.4", "pako": "^2.0.4",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"pidusage": "^3.0.0", "pidusage": "^3.0.0",
"quasar": "^2.7.7", "quasar": "^2.9.2",
"safe-buffer": "^5.2.1", "safe-buffer": "^5.2.1",
"sanitize-html": "^2.7.1", "sanitize-html": "^2.7.1",
"sjcl": "^1.0.8", "sjcl": "^1.0.8",
@@ -8009,9 +8009,9 @@
} }
}, },
"node_modules/quasar": { "node_modules/quasar": {
"version": "2.7.7", "version": "2.9.2",
"resolved": "https://registry.npmjs.org/quasar/-/quasar-2.7.7.tgz", "resolved": "https://registry.npmjs.org/quasar/-/quasar-2.9.2.tgz",
"integrity": "sha512-tegG6EmEmv5i24MoNopRkhZOdT5kdLSAxQMA0V/fG04oco52hk2xwvB0EVS8WzT0bZZbc/9iXlAm1c29rZ3yVA==", "integrity": "sha512-Z4QWJDC4vFILKRJJdE0j/jnRTo94A2k403G6LtTiSIRSmV8dUl4YWqqNRH6lQQ01Vwjj06kKtN81fi3ontBt0w==",
"engines": { "engines": {
"node": ">= 10.18.1", "node": ">= 10.18.1",
"npm": ">= 6.13.4", "npm": ">= 6.13.4",
@@ -16394,9 +16394,9 @@
} }
}, },
"quasar": { "quasar": {
"version": "2.7.7", "version": "2.9.2",
"resolved": "https://registry.npmjs.org/quasar/-/quasar-2.7.7.tgz", "resolved": "https://registry.npmjs.org/quasar/-/quasar-2.9.2.tgz",
"integrity": "sha512-tegG6EmEmv5i24MoNopRkhZOdT5kdLSAxQMA0V/fG04oco52hk2xwvB0EVS8WzT0bZZbc/9iXlAm1c29rZ3yVA==" "integrity": "sha512-Z4QWJDC4vFILKRJJdE0j/jnRTo94A2k403G6LtTiSIRSmV8dUl4YWqqNRH6lQQ01Vwjj06kKtN81fi3ontBt0w=="
}, },
"querystringify": { "querystringify": {
"version": "2.2.0", "version": "2.2.0",

View File

@@ -67,7 +67,7 @@
"pako": "^2.0.4", "pako": "^2.0.4",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"pidusage": "^3.0.0", "pidusage": "^3.0.0",
"quasar": "^2.7.7", "quasar": "^2.9.2",
"safe-buffer": "^5.2.1", "safe-buffer": "^5.2.1",
"sanitize-html": "^2.7.1", "sanitize-html": "^2.7.1",
"sjcl": "^1.0.8", "sjcl": "^1.0.8",