mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-21 02:04:26 +08:00
add desktop frontend framework
This commit is contained in:
Generated
+820
-26
File diff suppressed because it is too large
Load Diff
+5
-1
@@ -18,6 +18,7 @@
|
|||||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
|
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@mdi/js": "^7.2.96",
|
||||||
"@vuepic/vue-datepicker": "^5.1.2",
|
"@vuepic/vue-datepicker": "^5.1.2",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"cbor-js": "^0.1.0",
|
"cbor-js": "^0.1.0",
|
||||||
@@ -38,7 +39,10 @@
|
|||||||
"swiper": "^9.3.2",
|
"swiper": "^9.3.2",
|
||||||
"ua-parser-js": "^1.0.35",
|
"ua-parser-js": "^1.0.35",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.2.2"
|
"vue-i18n": "^9.2.2",
|
||||||
|
"vue-router": "^4.2.2",
|
||||||
|
"vue3-perfect-scrollbar": "^1.6.1",
|
||||||
|
"vuetify": "^3.3.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^4.2.0",
|
"@vitejs/plugin-vue": "^4.2.0",
|
||||||
|
|||||||
+67
-6
@@ -1,15 +1,76 @@
|
|||||||
<template>
|
<template>
|
||||||
<div></div>
|
<img style="display: none;" :src="devCookiePath" v-if="!isProduction" />
|
||||||
|
<v-app>
|
||||||
|
<router-view />
|
||||||
|
</v-app>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { useTheme } from 'vuetify';
|
||||||
|
|
||||||
|
import { mapStores } from 'pinia';
|
||||||
|
import { useSettingsStore } from '@/stores/setting.js';
|
||||||
|
import { useUserStore } from '@/stores/user.js';
|
||||||
|
import { useTokensStore } from '@/stores/token.js';
|
||||||
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.js';
|
||||||
|
|
||||||
|
import { loadMapAssets } from '@/lib/map/index.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
created() {
|
data() {
|
||||||
if (process.env.NODE_ENV === 'production') {
|
const self = this;
|
||||||
window.location.replace('../mobile/');
|
|
||||||
} else {
|
return {
|
||||||
window.location.replace('../mobile.html');
|
isProduction: self.$settings.isProduction(),
|
||||||
|
devCookiePath: self.$settings.isProduction() ? '' : '/dev/cookies'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapStores(useSettingsStore, useUserStore, useTokensStore, useExchangeRatesStore),
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
const self = this;
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
if (self.$settings.getTheme() === 'light') {
|
||||||
|
theme.global.name.value = 'light';
|
||||||
|
} else if (self.$settings.getTheme() === 'dark') {
|
||||||
|
theme.global.name.value = 'dark';
|
||||||
|
}
|
||||||
|
|
||||||
|
let localeDefaultSettings = self.$locale.initLocale(self.userStore.currentUserLanguage);
|
||||||
|
self.settingsStore.updateLocalizedDefaultSettings(localeDefaultSettings);
|
||||||
|
|
||||||
|
if (self.$user.isUserLogined()) {
|
||||||
|
if (!self.$settings.isEnableApplicationLock()) {
|
||||||
|
// refresh token if user is logined
|
||||||
|
self.tokensStore.refreshTokenAndRevokeOldToken().then(response => {
|
||||||
|
if (response.user && response.user.language) {
|
||||||
|
localeDefaultSettings = self.$locale.setLanguage(response.user.language);
|
||||||
|
self.settingsStore.updateLocalizedDefaultSettings(localeDefaultSettings);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// auto refresh exchange rates data
|
||||||
|
if (self.$settings.isAutoUpdateExchangeRatesData()) {
|
||||||
|
self.exchangeRatesStore.getLatestExchangeRates({ silent: true, force: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const languageInfo = this.$locale.getCurrentLanguageInfo();
|
||||||
|
loadMapAssets(languageInfo ? languageInfo.code : null);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/** Global style **/
|
||||||
|
* {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
+311
-1
@@ -1,6 +1,316 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue';
|
||||||
|
import { createPinia } from 'pinia';
|
||||||
|
import { createI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import { createVuetify } from 'vuetify';
|
||||||
|
import { VApp } from 'vuetify/components/VApp';
|
||||||
|
import { VAvatar } from 'vuetify/components/VAvatar';
|
||||||
|
import { VBtn } from 'vuetify/components/VBtn';
|
||||||
|
import { VCard, VCardActions, VCardItem, VCardSubtitle, VCardText, VCardTitle } from 'vuetify/components/VCard';
|
||||||
|
import { VChip } from 'vuetify/components/VChip';
|
||||||
|
import { VDialog } from 'vuetify/components/VDialog';
|
||||||
|
import { VDivider } from 'vuetify/components/VDivider';
|
||||||
|
import { VForm } from 'vuetify/components/VForm';
|
||||||
|
import { VContainer, VCol, VRow, VSpacer } from 'vuetify/components/VGrid';
|
||||||
|
import { VIcon } from 'vuetify/components/VIcon';
|
||||||
|
import { VImg } from 'vuetify/components/VImg';
|
||||||
|
import { VInput } from 'vuetify/components/VInput';
|
||||||
|
import { VList, VListGroup, VListImg, VListItem, VListItemAction, VListItemMedia, VListItemSubtitle, VListItemTitle, VListSubheader } from 'vuetify/components/VList';
|
||||||
|
import { VMenu } from 'vuetify/components/VMenu';
|
||||||
|
import { VOverlay } from 'vuetify/components/VOverlay';
|
||||||
|
import { VPagination } from 'vuetify/components/VPagination';
|
||||||
|
import { VProgressCircular } from 'vuetify/components/VProgressCircular';
|
||||||
|
import { VProgressLinear } from 'vuetify/components/VProgressLinear';
|
||||||
|
import { VSelect } from 'vuetify/components/VSelect';
|
||||||
|
import { VSheet } from 'vuetify/components/VSheet';
|
||||||
|
import { VSnackbar } from 'vuetify/components/VSnackbar';
|
||||||
|
import { VTabs } from 'vuetify/components/VTabs';
|
||||||
|
import { VTable } from 'vuetify/components/VTable';
|
||||||
|
import { VTextField } from 'vuetify/components/VTextField';
|
||||||
|
import { aliases, mdi } from 'vuetify/iconsets/mdi-svg';
|
||||||
|
import 'vuetify/styles';
|
||||||
|
|
||||||
|
import 'line-awesome/dist/line-awesome/css/line-awesome.css';
|
||||||
|
|
||||||
|
import { PerfectScrollbar } from 'vue3-perfect-scrollbar';
|
||||||
|
import 'vue3-perfect-scrollbar/dist/vue3-perfect-scrollbar.min.css';
|
||||||
|
|
||||||
|
import VueDatePicker from '@vuepic/vue-datepicker';
|
||||||
|
import '@vuepic/vue-datepicker/dist/main.css';
|
||||||
|
|
||||||
|
import router from '@/router/desktop.js';
|
||||||
|
|
||||||
|
import version from '@/lib/version.js';
|
||||||
|
import settings from '@/lib/settings.js';
|
||||||
|
import userstate from '@/lib/userstate.js';
|
||||||
|
import {
|
||||||
|
getI18nOptions,
|
||||||
|
translateIf,
|
||||||
|
translateError,
|
||||||
|
i18nFunctions
|
||||||
|
} from '@/lib/i18n.js';
|
||||||
|
|
||||||
|
import '@/styles/desktop/base.css';
|
||||||
|
import '@/styles/desktop/layout.css';
|
||||||
|
import '@/styles/desktop/font-size.css';
|
||||||
|
import '@/styles/desktop/gap-size.css';
|
||||||
|
import '@/styles/desktop/vuetify.css';
|
||||||
|
import '@/styles/desktop/classess.css';
|
||||||
|
|
||||||
import App from './DesktopApp.vue';
|
import App from './DesktopApp.vue';
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
const pinia = createPinia();
|
||||||
|
const i18n = createI18n(getI18nOptions());
|
||||||
|
const vuetify = createVuetify({
|
||||||
|
components: {
|
||||||
|
VApp,
|
||||||
|
VAvatar,
|
||||||
|
VBtn,
|
||||||
|
VCard,
|
||||||
|
VCardActions,
|
||||||
|
VCardItem,
|
||||||
|
VCardSubtitle,
|
||||||
|
VCardText,
|
||||||
|
VCardTitle,
|
||||||
|
VChip,
|
||||||
|
VDialog,
|
||||||
|
VDivider,
|
||||||
|
VForm,
|
||||||
|
VContainer,
|
||||||
|
VCol,
|
||||||
|
VRow,
|
||||||
|
VSpacer,
|
||||||
|
VIcon,
|
||||||
|
VImg,
|
||||||
|
VInput,
|
||||||
|
VList,
|
||||||
|
VListGroup,
|
||||||
|
VListImg,
|
||||||
|
VListItem,
|
||||||
|
VListItemAction,
|
||||||
|
VListItemMedia,
|
||||||
|
VListItemSubtitle,
|
||||||
|
VListItemTitle,
|
||||||
|
VListSubheader,
|
||||||
|
VMenu,
|
||||||
|
VOverlay,
|
||||||
|
VPagination,
|
||||||
|
VProgressCircular,
|
||||||
|
VProgressLinear,
|
||||||
|
VSelect,
|
||||||
|
VSheet,
|
||||||
|
VSnackbar,
|
||||||
|
VTabs,
|
||||||
|
VTable,
|
||||||
|
VTextField
|
||||||
|
},
|
||||||
|
icons: {
|
||||||
|
defaultSet: 'mdi',
|
||||||
|
aliases,
|
||||||
|
sets: {
|
||||||
|
mdi
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
defaults: {
|
||||||
|
VAlert: {
|
||||||
|
VBtn: {
|
||||||
|
color: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
VAutocomplete: {
|
||||||
|
variant: 'outlined',
|
||||||
|
color: 'primary',
|
||||||
|
hideDetails: 'auto'
|
||||||
|
},
|
||||||
|
VAvatar: {
|
||||||
|
variant: 'flat',
|
||||||
|
VIcon: {
|
||||||
|
size: 24,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
VBadge: {
|
||||||
|
color: 'primary'
|
||||||
|
},
|
||||||
|
VBtn: {
|
||||||
|
color: 'primary'
|
||||||
|
},
|
||||||
|
VCheckbox: {
|
||||||
|
color: 'primary',
|
||||||
|
hideDetails: 'auto'
|
||||||
|
},
|
||||||
|
VChip: {
|
||||||
|
elevation: 0
|
||||||
|
},
|
||||||
|
VList: {
|
||||||
|
color: 'primary'
|
||||||
|
},
|
||||||
|
VPagination: {
|
||||||
|
activeColor: 'primary'
|
||||||
|
},
|
||||||
|
VRadio: {
|
||||||
|
color: 'primary',
|
||||||
|
hideDetails: 'auto'
|
||||||
|
},
|
||||||
|
VSelect: {
|
||||||
|
variant: 'outlined',
|
||||||
|
color: 'primary',
|
||||||
|
hideDetails: 'auto'
|
||||||
|
},
|
||||||
|
VSlider: {
|
||||||
|
color: 'primary',
|
||||||
|
hideDetails: 'auto'
|
||||||
|
},
|
||||||
|
VSwitch: {
|
||||||
|
color: 'primary',
|
||||||
|
hideDetails: 'auto'
|
||||||
|
},
|
||||||
|
VProgressCircular: {
|
||||||
|
size: 40
|
||||||
|
},
|
||||||
|
VTabs: {
|
||||||
|
color: 'primary',
|
||||||
|
VSlideGroup: {
|
||||||
|
showArrows: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
VTextarea: {
|
||||||
|
variant: 'outlined',
|
||||||
|
color: 'primary',
|
||||||
|
hideDetails: 'auto'
|
||||||
|
},
|
||||||
|
VTextField: {
|
||||||
|
variant: 'outlined',
|
||||||
|
color: 'primary',
|
||||||
|
hideDetails: 'auto'
|
||||||
|
},
|
||||||
|
VTooltip: {
|
||||||
|
location: 'top'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
defaultTheme: 'light',
|
||||||
|
themes: {
|
||||||
|
light: {
|
||||||
|
dark: false,
|
||||||
|
colors: {
|
||||||
|
'primary': '#c67e48',
|
||||||
|
'secondary': '#8a8d93',
|
||||||
|
'on-secondary': '#fff',
|
||||||
|
'success': '#4cd964',
|
||||||
|
'info': '#2196f3',
|
||||||
|
'warning': '#ff9500',
|
||||||
|
'error': '#ff3b30',
|
||||||
|
'on-primary': '#ffffff',
|
||||||
|
'on-success': '#ffffff',
|
||||||
|
'on-warning': '#ffffff',
|
||||||
|
'background': '#faf8f4',
|
||||||
|
'on-background': '#413935',
|
||||||
|
'on-surface': '#413935',
|
||||||
|
'grey-50': '#fafafa',
|
||||||
|
'grey-100': '#f0f2f8',
|
||||||
|
'grey-200': '#eeeeee',
|
||||||
|
'grey-300': '#e0e0e0',
|
||||||
|
'grey-400': '#bdbdbd',
|
||||||
|
'grey-500': '#9e9e9e',
|
||||||
|
'grey-600': '#757575',
|
||||||
|
'grey-700': '#616161',
|
||||||
|
'grey-800': '#424242',
|
||||||
|
'grey-900': '#212121',
|
||||||
|
'perfect-scrollbar-thumb': '#dbdade',
|
||||||
|
'skin-bordered-background': '#fff',
|
||||||
|
'skin-bordered-surface': '#fff'
|
||||||
|
},
|
||||||
|
variables: {
|
||||||
|
'btn-height': '38px',
|
||||||
|
'code-color': '#ff8000',
|
||||||
|
'overlay-scrim-background': '#3a3541',
|
||||||
|
'overlay-scrim-opacity': 0.5,
|
||||||
|
'hover-opacity': 0.04,
|
||||||
|
'focus-opacity': 0.1,
|
||||||
|
'selected-opacity': 0.12,
|
||||||
|
'activated-opacity': 0.1,
|
||||||
|
'pressed-opacity': 0.14,
|
||||||
|
'dragged-opacity': 0.1,
|
||||||
|
'border-color': '#3a3541',
|
||||||
|
'table-header-background': '#f9fafc',
|
||||||
|
'custom-background': '#f9f8f9',
|
||||||
|
'shadow-key-umbra-opacity': 'rgba(var(--v-theme-on-surface), 0.08)',
|
||||||
|
'shadow-key-penumbra-opacity': 'rgba(var(--v-theme-on-surface), 0.12)',
|
||||||
|
'shadow-key-ambient-opacity': 'rgba(var(--v-theme-on-surface), 0.04)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
dark: true,
|
||||||
|
colors: {
|
||||||
|
'primary': '#c67e48',
|
||||||
|
'secondary': '#8a8d93',
|
||||||
|
'on-secondary': '#fff',
|
||||||
|
'success': '#4cd964',
|
||||||
|
'info': '#2196f3',
|
||||||
|
'warning': '#ff9500',
|
||||||
|
'error': '#ff3b30',
|
||||||
|
'on-primary': '#ffffff',
|
||||||
|
'on-success': '#ffffff',
|
||||||
|
'on-warning': '#ffffff',
|
||||||
|
'background': '#28243d',
|
||||||
|
'on-background': '#fcf0e3',
|
||||||
|
'surface': '#312d4b',
|
||||||
|
'on-surface': '#fcf0e3',
|
||||||
|
'grey-50': '#2a2e42',
|
||||||
|
'grey-100': '#474360',
|
||||||
|
'grey-200': '#4a5072',
|
||||||
|
'grey-300': '#5e6692',
|
||||||
|
'grey-400': '#7983bb',
|
||||||
|
'grey-500': '#8692d0',
|
||||||
|
'grey-600': '#aab3de',
|
||||||
|
'grey-700': '#b6bee3',
|
||||||
|
'grey-800': '#cfd3ec',
|
||||||
|
'grey-900': '#e7e9f6',
|
||||||
|
'perfect-scrollbar-thumb': '#4a5072',
|
||||||
|
'skin-bordered-background': '#312d4b',
|
||||||
|
'skin-bordered-surface': '#312d4b'
|
||||||
|
},
|
||||||
|
variables: {
|
||||||
|
'btn-height': '38px',
|
||||||
|
'code-color': '#ff8000',
|
||||||
|
'overlay-scrim-background': '#2C2942',
|
||||||
|
'overlay-scrim-opacity': 0.6,
|
||||||
|
'hover-opacity': 0.04,
|
||||||
|
'focus-opacity': 0.1,
|
||||||
|
'selected-opacity': 0.12,
|
||||||
|
'activated-opacity': 0.1,
|
||||||
|
'pressed-opacity': 0.14,
|
||||||
|
'dragged-opacity': 0.1,
|
||||||
|
'border-color': '#E7E3FC',
|
||||||
|
'table-header-background': '#3D3759',
|
||||||
|
'custom-background': '#373452',
|
||||||
|
'shadow-key-umbra-opacity': 'rgba(20, 18, 33, 0.08)',
|
||||||
|
'shadow-key-penumbra-opacity': 'rgba(20, 18, 33, 0.12)',
|
||||||
|
'shadow-key-ambient-opacity': 'rgba(20, 18, 33, 0.04)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(pinia);
|
||||||
|
app.use(i18n);
|
||||||
|
app.use(vuetify);
|
||||||
|
app.use(router);
|
||||||
|
|
||||||
|
app.component('PerfectScrollbar', PerfectScrollbar);
|
||||||
|
app.component('VueDatePicker', VueDatePicker);
|
||||||
|
|
||||||
|
app.config.globalProperties.$version = version.getVersion();
|
||||||
|
app.config.globalProperties.$buildTime = version.getBuildTime();
|
||||||
|
|
||||||
|
app.config.globalProperties.$settings = settings;
|
||||||
|
app.config.globalProperties.$locale = i18nFunctions(i18n.global);
|
||||||
|
app.config.globalProperties.$tIf = (text, isTranslate) => translateIf(text, isTranslate, i18n.global.t);
|
||||||
|
app.config.globalProperties.$tError = (message) => translateError(message, i18n.global.t);
|
||||||
|
|
||||||
|
app.config.globalProperties.$user = userstate;
|
||||||
|
|
||||||
app.mount('#app');
|
app.mount('#app');
|
||||||
|
|||||||
@@ -702,6 +702,7 @@ export default {
|
|||||||
'Not Specified': 'Not Specified',
|
'Not Specified': 'Not Specified',
|
||||||
'No results': 'No results',
|
'No results': 'No results',
|
||||||
'Unknown': 'Unknown',
|
'Unknown': 'Unknown',
|
||||||
|
'Other': 'Other',
|
||||||
'Default': 'Default',
|
'Default': 'Default',
|
||||||
'Done': 'Done',
|
'Done': 'Done',
|
||||||
'Continue': 'Continue',
|
'Continue': 'Continue',
|
||||||
@@ -746,6 +747,7 @@ export default {
|
|||||||
'Accounts': 'Accounts',
|
'Accounts': 'Accounts',
|
||||||
'Statistics': 'Statistics',
|
'Statistics': 'Statistics',
|
||||||
'Settings': 'Settings',
|
'Settings': 'Settings',
|
||||||
|
'Application Settings': 'Application Settings',
|
||||||
'Select All': 'Select All',
|
'Select All': 'Select All',
|
||||||
'Select None': 'Select None',
|
'Select None': 'Select None',
|
||||||
'Invert Selection': 'Invert Selection',
|
'Invert Selection': 'Invert Selection',
|
||||||
@@ -806,6 +808,7 @@ export default {
|
|||||||
'PIN code is invalid': 'PIN code is invalid',
|
'PIN code is invalid': 'PIN code is invalid',
|
||||||
'PIN code is wrong': 'PIN code is wrong',
|
'PIN code is wrong': 'PIN code is wrong',
|
||||||
'Sign Up': 'Sign Up',
|
'Sign Up': 'Sign Up',
|
||||||
|
'Overview': 'Overview',
|
||||||
'Transaction List': 'Transaction List',
|
'Transaction List': 'Transaction List',
|
||||||
'Account List': 'Account List',
|
'Account List': 'Account List',
|
||||||
'This Week': 'This Week',
|
'This Week': 'This Week',
|
||||||
@@ -915,6 +918,8 @@ export default {
|
|||||||
'No transaction data': 'No transaction data',
|
'No transaction data': 'No transaction data',
|
||||||
'Are you sure you want to delete this transaction?': 'Are you sure you want to delete this transaction?',
|
'Are you sure you want to delete this transaction?': 'Are you sure you want to delete this transaction?',
|
||||||
'Unable to delete this transaction': 'Unable to delete this transaction',
|
'Unable to delete this transaction': 'Unable to delete this transaction',
|
||||||
|
'Transaction Data': 'Transaction Data',
|
||||||
|
'Statistics Data': 'Statistics Data',
|
||||||
'Unable to get transaction statistics': 'Unable to get transaction statistics',
|
'Unable to get transaction statistics': 'Unable to get transaction statistics',
|
||||||
'Total Amount': 'Total Amount',
|
'Total Amount': 'Total Amount',
|
||||||
'Total Assets': 'Total Assets',
|
'Total Assets': 'Total Assets',
|
||||||
|
|||||||
@@ -702,6 +702,7 @@ export default {
|
|||||||
'Not Specified': '未指定',
|
'Not Specified': '未指定',
|
||||||
'No results': '无结果',
|
'No results': '无结果',
|
||||||
'Unknown': '未知',
|
'Unknown': '未知',
|
||||||
|
'Other': '其他',
|
||||||
'Default': '默认',
|
'Default': '默认',
|
||||||
'Done': '完成',
|
'Done': '完成',
|
||||||
'Continue': '继续',
|
'Continue': '继续',
|
||||||
@@ -746,6 +747,7 @@ export default {
|
|||||||
'Accounts': '账户',
|
'Accounts': '账户',
|
||||||
'Statistics': '统计',
|
'Statistics': '统计',
|
||||||
'Settings': '设置',
|
'Settings': '设置',
|
||||||
|
'Application Settings': '应用设置',
|
||||||
'Select All': '全部选择',
|
'Select All': '全部选择',
|
||||||
'Select None': '全部不选',
|
'Select None': '全部不选',
|
||||||
'Invert Selection': '反向选择',
|
'Invert Selection': '反向选择',
|
||||||
@@ -806,6 +808,7 @@ export default {
|
|||||||
'PIN code is invalid': 'PIN码无效',
|
'PIN code is invalid': 'PIN码无效',
|
||||||
'PIN code is wrong': 'PIN码错误',
|
'PIN code is wrong': 'PIN码错误',
|
||||||
'Sign Up': '注册',
|
'Sign Up': '注册',
|
||||||
|
'Overview': '总览',
|
||||||
'Transaction List': '交易列表',
|
'Transaction List': '交易列表',
|
||||||
'Account List': '账户列表',
|
'Account List': '账户列表',
|
||||||
'This Week': '本周',
|
'This Week': '本周',
|
||||||
@@ -915,6 +918,8 @@ export default {
|
|||||||
'No transaction data': '没有交易数据',
|
'No transaction data': '没有交易数据',
|
||||||
'Are you sure you want to delete this transaction?': '您确定要删除该交易?',
|
'Are you sure you want to delete this transaction?': '您确定要删除该交易?',
|
||||||
'Unable to delete this transaction': '无法删除该交易',
|
'Unable to delete this transaction': '无法删除该交易',
|
||||||
|
'Transaction Data': '交易数据',
|
||||||
|
'Statistics Data': '统计数据',
|
||||||
'Unable to get transaction statistics': '无法获取交易统计数据',
|
'Unable to get transaction statistics': '无法获取交易统计数据',
|
||||||
'Total Amount': '总金额',
|
'Total Amount': '总金额',
|
||||||
'Total Assets': '总资产',
|
'Total Assets': '总资产',
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
import { createRouter, createWebHashHistory } from 'vue-router';
|
||||||
|
|
||||||
|
import userState from '@/lib/userstate.js';
|
||||||
|
|
||||||
|
import MainLayout from '@/views/desktop/MainLayout.vue';
|
||||||
|
import LoginPage from '@/views/desktop/LoginPage.vue';
|
||||||
|
import SignUpPage from '@/views/desktop/SignupPage.vue';
|
||||||
|
import UnlockPage from '@/views/desktop/UnlockPage.vue';
|
||||||
|
|
||||||
|
import HomePage from '@/views/desktop/HomePage.vue';
|
||||||
|
import TransactionsPage from '@/views/desktop/TransactionsPage.vue';
|
||||||
|
import StatisticsTransactionPage from '@/views/desktop/statistics/TransactionPage.vue';
|
||||||
|
import AccountsPage from '@/views/desktop/AccountsPage.vue';
|
||||||
|
import TransactionCategoriesPage from '@/views/desktop/TransactionCategoriesPage.vue';
|
||||||
|
import TransactionTagsPage from '@/views/desktop/TransactionTagsPage.vue';
|
||||||
|
import ExchangeRatesPage from '@/views/desktop/ExchangeRatesPage.vue';
|
||||||
|
import UserSettingsPage from '@/views/desktop/user/UserSettingsPage.vue';
|
||||||
|
import AppSettingsPage from '@/views/desktop/app/AppSettingsPage.vue';
|
||||||
|
import AboutPage from '@/views/desktop/AboutPage.vue';
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
if (!userState.isUserLogined()) {
|
||||||
|
return {
|
||||||
|
path: '/login',
|
||||||
|
replace: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userState.isUserUnlocked()) {
|
||||||
|
return {
|
||||||
|
path: '/unlock',
|
||||||
|
replace: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLocked() {
|
||||||
|
if (!userState.isUserLogined()) {
|
||||||
|
return {
|
||||||
|
path: '/login',
|
||||||
|
replace: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userState.isUserUnlocked()) {
|
||||||
|
return {
|
||||||
|
path: '/',
|
||||||
|
replace: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkNotLogin() {
|
||||||
|
if (userState.isUserLogined() && !userState.isUserUnlocked()) {
|
||||||
|
return {
|
||||||
|
path: '/unlock',
|
||||||
|
replace: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userState.isUserLogined()) {
|
||||||
|
return {
|
||||||
|
path: '/',
|
||||||
|
replace: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHashHistory(),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
component: MainLayout,
|
||||||
|
beforeEnter: checkLogin,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: HomePage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/transactions',
|
||||||
|
component: TransactionsPage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/statistics/transaction',
|
||||||
|
component: StatisticsTransactionPage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/accounts',
|
||||||
|
component: AccountsPage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/categories',
|
||||||
|
component: TransactionCategoriesPage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/tags',
|
||||||
|
component: TransactionTagsPage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/exchange_rates',
|
||||||
|
component: ExchangeRatesPage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/user/settings',
|
||||||
|
component: UserSettingsPage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/app/settings',
|
||||||
|
component: AppSettingsPage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/about',
|
||||||
|
component: AboutPage
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/login',
|
||||||
|
component: LoginPage,
|
||||||
|
beforeEnter: checkNotLogin
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/signup',
|
||||||
|
component: LoginPage,
|
||||||
|
beforeEnter: SignUpPage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/unlock',
|
||||||
|
component: UnlockPage,
|
||||||
|
beforeEnter: checkLocked
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router;
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/** Base class **/
|
||||||
|
/** reference: https://github.com/themeselection/materio-vuetify-vuejs-admin-template-free **/
|
||||||
|
|
||||||
|
*,
|
||||||
|
::before,
|
||||||
|
::after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--v-theme-overlay-multiplier: 1;
|
||||||
|
--v-scrollbar-offset: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: inter,sans-serif,-apple-system,blinkmacsystemfont,Segoe UI,roboto,Helvetica Neue,arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-size: 1rem;
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.overflow-y-hidden {
|
||||||
|
overflow-y: hidden!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: rgb(var(--v-theme-primary));
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-block-end: 1rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
.disabled {
|
||||||
|
opacity: 0.55 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readonly {
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/** Text size class **/
|
||||||
|
/** reference: https://github.com/themeselection/materio-vuetify-vuejs-admin-template-free **/
|
||||||
|
|
||||||
|
.text-xs {
|
||||||
|
font-size: .75rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-sm {
|
||||||
|
font-size: .875rem;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-base {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-lg {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-xl {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-2xl {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-3xl {
|
||||||
|
font-size: 1.875rem;
|
||||||
|
line-height: 2.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-4xl {
|
||||||
|
font-size: 2.25rem;
|
||||||
|
line-height: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-5xl {
|
||||||
|
font-size: 3rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-6xl {
|
||||||
|
font-size: 3.75rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-7xl {
|
||||||
|
font-size: 4.5rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-8xl {
|
||||||
|
font-size: 6rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-9xl {
|
||||||
|
font-size: 8rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,362 @@
|
|||||||
|
/** Gap size class **/
|
||||||
|
/** reference: https://github.com/themeselection/materio-vuetify-vuejs-admin-template-free **/
|
||||||
|
|
||||||
|
.gap-0 {
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-0 {
|
||||||
|
column-gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-0 {
|
||||||
|
row-gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-1 {
|
||||||
|
gap: .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-1 {
|
||||||
|
column-gap: .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-1 {
|
||||||
|
row-gap: .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-2 {
|
||||||
|
gap: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-2 {
|
||||||
|
column-gap: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-2 {
|
||||||
|
row-gap: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-3 {
|
||||||
|
gap: .75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-3 {
|
||||||
|
column-gap: .75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-3 {
|
||||||
|
row-gap: .75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-4 {
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-4 {
|
||||||
|
column-gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-4 {
|
||||||
|
row-gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-5 {
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-5 {
|
||||||
|
column-gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-5 {
|
||||||
|
row-gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-6 {
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-6 {
|
||||||
|
column-gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-6 {
|
||||||
|
row-gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-7 {
|
||||||
|
gap: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-7 {
|
||||||
|
column-gap: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-7 {
|
||||||
|
row-gap: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-8 {
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-8 {
|
||||||
|
column-gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-8 {
|
||||||
|
row-gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-9 {
|
||||||
|
gap: 2.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-9 {
|
||||||
|
column-gap: 2.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-9 {
|
||||||
|
row-gap: 2.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-10 {
|
||||||
|
gap: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-10 {
|
||||||
|
column-gap: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-10 {
|
||||||
|
row-gap: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-11 {
|
||||||
|
gap: 2.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-11 {
|
||||||
|
column-gap: 2.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-11 {
|
||||||
|
row-gap: 2.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-12 {
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-12 {
|
||||||
|
column-gap: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-12 {
|
||||||
|
row-gap: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-14 {
|
||||||
|
gap: 3.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-14 {
|
||||||
|
column-gap: 3.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-14 {
|
||||||
|
row-gap: 3.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-16 {
|
||||||
|
gap: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-16 {
|
||||||
|
column-gap: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-16 {
|
||||||
|
row-gap: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-20 {
|
||||||
|
gap: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-20 {
|
||||||
|
column-gap: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-20 {
|
||||||
|
row-gap: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-24 {
|
||||||
|
gap: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-24 {
|
||||||
|
column-gap: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-24 {
|
||||||
|
row-gap: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-28 {
|
||||||
|
gap: 7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-28 {
|
||||||
|
column-gap: 7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-28 {
|
||||||
|
row-gap: 7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-32 {
|
||||||
|
gap: 8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-32 {
|
||||||
|
column-gap: 8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-32 {
|
||||||
|
row-gap: 8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-36 {
|
||||||
|
gap: 9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-36 {
|
||||||
|
column-gap: 9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-36 {
|
||||||
|
row-gap: 9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-40 {
|
||||||
|
gap: 10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-40 {
|
||||||
|
column-gap: 10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-40 {
|
||||||
|
row-gap: 10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-44 {
|
||||||
|
gap: 11rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-44 {
|
||||||
|
column-gap: 11rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-44 {
|
||||||
|
row-gap: 11rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-48 {
|
||||||
|
gap: 12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-48 {
|
||||||
|
column-gap: 12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-48 {
|
||||||
|
row-gap: 12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-52 {
|
||||||
|
gap: 13rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-52 {
|
||||||
|
column-gap: 13rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-52 {
|
||||||
|
row-gap: 13rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-56 {
|
||||||
|
gap: 14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-56 {
|
||||||
|
column-gap: 14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-56 {
|
||||||
|
row-gap: 14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-60 {
|
||||||
|
gap: 15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-60 {
|
||||||
|
column-gap: 15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-60 {
|
||||||
|
row-gap: 15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-64 {
|
||||||
|
gap: 16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-64 {
|
||||||
|
column-gap: 16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-64 {
|
||||||
|
row-gap: 16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-72 {
|
||||||
|
gap: 18rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-72 {
|
||||||
|
column-gap: 18rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-72 {
|
||||||
|
row-gap: 18rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-80 {
|
||||||
|
gap: 20rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-80 {
|
||||||
|
column-gap: 20rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-80 {
|
||||||
|
row-gap: 20rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-96 {
|
||||||
|
gap: 24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-x-96 {
|
||||||
|
column-gap: 24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-y-96 {
|
||||||
|
row-gap: 24rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,544 @@
|
|||||||
|
/** Layout class **/
|
||||||
|
/** reference: https://github.com/themeselection/materio-vuetify-vuejs-admin-template-free **/
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
min-block-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > :first-child,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group > :first-child {
|
||||||
|
margin-block: 0;
|
||||||
|
margin-inline: 0 1.125rem;
|
||||||
|
padding-block: 0;
|
||||||
|
padding-inline: 1.375rem 1rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > :first-child,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group > :first-child {
|
||||||
|
border-radius: .4rem;
|
||||||
|
block-size: 2.75rem;
|
||||||
|
margin-block-end: .375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link .nav-item-icon,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group .nav-item-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-inline-end: .625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group .nav-group .nav-item-icon,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group .nav-link .nav-item-icon {
|
||||||
|
font-size: .9rem;
|
||||||
|
margin-inline-end: .925rem;
|
||||||
|
margin-inline-start: .3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group .nav-group .nav-link .nav-item-icon,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group .nav-group .nav-group .nav-item-icon {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.active > :first-child:before,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.open > :first-child:before {
|
||||||
|
opacity: calc(var(--v-selected-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.active > :hover:first-child .nav-group.active > :first-child:before,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.open > :hover:first-child .nav-group.active > :first-child:before,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.active > :hover:first-child .nav-group.open > :first-child:before,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.open > :hover:first-child .nav-group.open > :first-child:before {
|
||||||
|
opacity: calc(var(--v-selected-opacity) + var(--v-hover-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.active > :focus-visible:first-child .nav-group.active > :first-child:before,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.open > :focus-visible:first-child .nav-group.active > :first-child:before,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.active > :focus-visible:first-child .nav-group.open > :first-child:before,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.open > :focus-visible:first-child .nav-group.open > :first-child:before {
|
||||||
|
opacity: calc(var(--v-selected-opacity) + var(--v-focus-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports not selector(:focus-visible) {
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.active > :focus:first-child:before,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.open > :focus:first-child:before {
|
||||||
|
opacity: calc(var(--v-selected-opacity) + var(--v-focus-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title {
|
||||||
|
block-size: 1.5rem;
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
|
||||||
|
font-size: .75rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-item-badge {
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
font-size: .8em;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1;
|
||||||
|
padding-block: .25em;
|
||||||
|
padding-inline: .55em;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: baseline;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-item-title {
|
||||||
|
letter-spacing: .15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title {
|
||||||
|
letter-spacing: .4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > .router-link-exact-active {
|
||||||
|
background-color: rgb(var(--v-theme-primary));
|
||||||
|
color: rgb(var(--v-theme-on-primary));
|
||||||
|
box-shadow: 0 4px 14px -4px var(--v-shadow-key-umbra-opacity), 0 4px 8px -4px var(--v-shadow-key-penumbra-opacity), 0 4px 8px -4px var(--v-shadow-key-ambient-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-navbar {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
html.v-overlay-scroll-blocked:not([style*="--v-body-scroll-y: 0px;"]) .layout-navbar-sticky .navbar-blur.layout-navbar .navbar-content-container,
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.window-scrolled.layout-navbar-sticky .navbar-blur.layout-navbar .navbar-content-container {
|
||||||
|
-webkit-backdrop-filter: blur(6px);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
background-color: rgb(var(--v-theme-surface), .9);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.v-overlay-scroll-blocked:not([style*="--v-body-scroll-y: 0px;"]) .layout-navbar-sticky .layout-navbar .navbar-content-container,
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.window-scrolled.layout-navbar-sticky .layout-navbar .navbar-content-container {
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
}
|
||||||
|
|
||||||
|
html.v-overlay-scroll-blocked:not([style*="--v-body-scroll-y: 0px;"]) .layout-navbar-sticky .layout-navbar .navbar-content-container,
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.window-scrolled.layout-navbar-sticky .layout-navbar .navbar-content-container {
|
||||||
|
box-shadow: 0 4px 14px -4px var(--v-shadow-key-umbra-opacity), 0 4px 8px -4px var(--v-shadow-key-penumbra-opacity), 0 4px 8px -4px var(--v-shadow-key-ambient-opacity);
|
||||||
|
padding-inline: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > .router-link-exact-active {
|
||||||
|
background: linear-gradient(-72.47deg, rgb(var(--v-theme-primary)) 22.16%, rgba(var(--v-theme-primary), .7) 76.47%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title .title-text {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
column-gap: .625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title .title-text:before,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title .title-text:after {
|
||||||
|
border-block-end: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title .title-text:after {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title .title-text:before {
|
||||||
|
flex: 0 1 .75rem;
|
||||||
|
margin-inline-start: -1.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical.layout-vertical-nav-collapsed .layout-vertical-nav:not(.hovered) .nav-section-title {
|
||||||
|
margin-inline: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > :first-child,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group > :first-child {
|
||||||
|
block-size: 2.625rem !important;
|
||||||
|
border-end-end-radius: 3.125rem !important;
|
||||||
|
border-end-start-radius: 0 !important;
|
||||||
|
border-start-end-radius: 3.125rem !important;
|
||||||
|
border-start-start-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > :first-child,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group > :first-child {
|
||||||
|
transition: margin-inline .15s ease-in-out;
|
||||||
|
will-change: margin-inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical.layout-vertical-nav-collapsed .layout-vertical-nav:not(.hovered) .nav-link > :first-child,
|
||||||
|
.layout-nav-type-vertical.layout-vertical-nav-collapsed .layout-vertical-nav:not(.hovered) .nav-group > :first-child {
|
||||||
|
margin-inline: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav {
|
||||||
|
background-color: rgb(var(--v-theme-background));
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav-collapsed.layout-nav-type-vertical .layout-vertical-nav.hovered {
|
||||||
|
box-shadow: 0 4px 5px -2px var(--v-shadow-key-umbra-opacity), 0 2px 10px 1px var(--v-shadow-key-penumbra-opacity), 0 2px 16px 1px var(--v-shadow-key-ambient-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-header {
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 1rem .25rem 1rem 1.375rem;
|
||||||
|
margin-inline: 0 1.125rem;
|
||||||
|
min-block-size: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-header .app-logo {
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: transform .25s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav-collapsed.layout-nav-type-vertical .layout-vertical-nav:not(.hovered) .nav-header .app-logo {
|
||||||
|
transform: translate(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-header .app-title {
|
||||||
|
margin-inline-start: .9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .vertical-nav-items-shadow {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
background: linear-gradient(rgb(var(--v-theme-background)) 5%, rgba(var(--v-theme-background), 75%) 45%, rgba(var(--v-theme-background), 20%) 80%, transparent);
|
||||||
|
block-size: 55px;
|
||||||
|
inline-size: 100%;
|
||||||
|
inset-block-start: 62px;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity .15s ease-in-out;
|
||||||
|
will-change: opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav.scrolled .vertical-nav-items-shadow {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .ps__rail-y {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title {
|
||||||
|
margin-block-end: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title:not(:first-child) {
|
||||||
|
margin-block-start: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-section-title .placeholder-icon {
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link.disabled,
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.disabled {
|
||||||
|
opacity: var(--v-disabled-opacity);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > a {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > a:before {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: currentcolor;
|
||||||
|
block-size: 100%;
|
||||||
|
content: "";
|
||||||
|
inline-size: 100%;
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > a:hover:before {
|
||||||
|
opacity: calc(var(--v-hover-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > a:focus-visible:before {
|
||||||
|
opacity: calc(var(--v-focus-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports not selector(:focus-visible) {
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-link > a:focus:before {
|
||||||
|
opacity: calc(var(--v-focus-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group .nav-group-arrow {
|
||||||
|
flex-shrink: 0;
|
||||||
|
transform-origin: center;
|
||||||
|
transition: transform .15s ease-in-out;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group.open > .nav-group-label .nav-group-arrow {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group > :first-child {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group > :first-child:before {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: currentcolor;
|
||||||
|
block-size: 100%;
|
||||||
|
content: "";
|
||||||
|
inline-size: 100%;
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group > :first-child:hover:before {
|
||||||
|
opacity: calc(var(--v-hover-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group > :first-child:focus-visible:before {
|
||||||
|
opacity: calc(var(--v-focus-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports not selector(:focus-visible) {
|
||||||
|
.layout-nav-type-vertical .layout-vertical-nav .nav-group > :first-child:focus:before {
|
||||||
|
opacity: calc(var(--v-focus-opacity) * var(--v-theme-overlay-multiplier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-nav-section-title-enter-active,
|
||||||
|
.vertical-nav-section-title-leave-active {
|
||||||
|
transition: opacity .1s ease-in-out, transform .1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-nav-section-title-enter-from,
|
||||||
|
.vertical-nav-section-title-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(15px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition-slide-x-enter-active,
|
||||||
|
.transition-slide-x-leave-active {
|
||||||
|
transition: opacity .1s ease-in-out, transform .12s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition-slide-x-enter-from,
|
||||||
|
.transition-slide-x-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-15px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-nav-app-title-enter-active,
|
||||||
|
.vertical-nav-app-title-leave-active {
|
||||||
|
transition: opacity .1s ease-in-out, transform .12s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-nav-app-title-enter-from,
|
||||||
|
.vertical-nav-app-title-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-15px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav ol, .layout-vertical-nav ul,
|
||||||
|
.layout-horizontal-nav ol, .layout-horizontal-nav ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollable-content.v-navigation-drawer .v-navigation-drawer__content {
|
||||||
|
display: flex;
|
||||||
|
overflow: hidden;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical .layout-navbar .navbar-content-container {
|
||||||
|
transition: padding .2s ease, background-color .18s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical .layout-navbar .navbar-content-container {
|
||||||
|
border-radius: 0 0 10px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical .layout-footer .footer-content-container {
|
||||||
|
border-radius: 10px 10px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-footer-sticky.layout-wrapper.layout-nav-type-vertical .layout-footer .footer-content-container {
|
||||||
|
background-color: rgb(var(--v-theme-surface));
|
||||||
|
padding-block: 0;
|
||||||
|
padding-inline: 1.2rem;
|
||||||
|
box-shadow: 0 4px 14px -4px var(--v-shadow-key-umbra-opacity), 0 4px 8px -4px var(--v-shadow-key-penumbra-opacity), 0 4px 8px -4px var(--v-shadow-key-ambient-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.layout-content-height-fixed .page-content-container > .v-layout:first-child {
|
||||||
|
overflow: hidden;
|
||||||
|
min-block-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.layout-content-height-fixed .page-content-container > .v-layout:first-child > .v-main .v-main__wrap > :first-child {
|
||||||
|
block-size: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-horizontal.layout-content-height-fixed > .layout-page-content {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1004;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
block-size: 100%;
|
||||||
|
inline-size: 260px;
|
||||||
|
inset-block-start: 0;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
transition: transform .25s ease-in-out, inline-size .25s ease-in-out, box-shadow .25s ease-in-out;
|
||||||
|
will-change: transform, inline-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav .nav-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav .app-title-wrapper {
|
||||||
|
margin-inline-end: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav .nav-items {
|
||||||
|
block-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav .nav-item-title {
|
||||||
|
overflow: hidden;
|
||||||
|
margin-inline-end: auto;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav-collapsed .layout-vertical-nav:not(.hovered) {
|
||||||
|
inline-size: 68px
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav.overlay-nav:not(.visible) {
|
||||||
|
transform: translate(-260px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-content-width-boxed.layout-wrapper.layout-nav-type-vertical .layout-navbar {
|
||||||
|
inline-size: 100%;
|
||||||
|
margin-inline: auto;
|
||||||
|
max-inline-size: 1440px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical .layout-navbar {
|
||||||
|
padding-inline: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.layout-navbar-hidden .layout-navbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.layout-navbar-sticky .layout-navbar {
|
||||||
|
position: sticky;
|
||||||
|
inset-block-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical {
|
||||||
|
block-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical .layout-content-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
min-block-size: calc(var(--vh, 1vh) * 100);
|
||||||
|
transition: padding-inline-start .2s ease-in-out;
|
||||||
|
will-change: padding-inline-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical .layout-navbar {
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical .layout-navbar .navbar-content-container {
|
||||||
|
block-size: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical .layout-overlay {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1003;
|
||||||
|
background-color: #0009;
|
||||||
|
cursor: pointer;
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity .25s ease-in-out;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical .layout-overlay.visible {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical:not(.layout-overlay-nav) .layout-content-wrapper {
|
||||||
|
padding-inline-start: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.layout-vertical-nav-collapsed .layout-content-wrapper {
|
||||||
|
padding-inline-start: 68px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.layout-content-height-fixed .layout-content-wrapper {
|
||||||
|
max-block-size: calc(var(--vh) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.layout-content-height-fixed .layout-page-content {
|
||||||
|
display: flex;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.layout-content-height-fixed .layout-page-content .page-content-container {
|
||||||
|
inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-wrapper.layout-nav-type-vertical.layout-content-height-fixed .layout-page-content .page-content-container > :first-child {
|
||||||
|
max-block-size: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-vertical-nav .nav-link a {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-page-content {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-block: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-page-content {
|
||||||
|
padding-inline: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
/** Vuetify class overrides **/
|
||||||
|
/** reference: https://github.com/themeselection/materio-vuetify-vuejs-admin-template-free **/
|
||||||
|
|
||||||
|
.v-application__wrap {
|
||||||
|
min-height: calc(var(--vh, 1vh) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
.text-h1,
|
||||||
|
.text-h2,
|
||||||
|
.text-h3,
|
||||||
|
.text-h4,
|
||||||
|
.text-h5,
|
||||||
|
.text-h6,
|
||||||
|
.text-button,
|
||||||
|
.text-overline,
|
||||||
|
.v-card-title {
|
||||||
|
color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-application,
|
||||||
|
.text-body-1,
|
||||||
|
.text-body-2,
|
||||||
|
.text-subtitle-1,
|
||||||
|
.text-subtitle-2 {
|
||||||
|
color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-row .v-col .v-input__details,
|
||||||
|
.v-row [class^="v-col-*"] .v-input__details {
|
||||||
|
margin-block-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-btn--density-compact.v-btn--size-default .v-btn__content > svg {
|
||||||
|
block-size: 22px;
|
||||||
|
font-size: 22px;
|
||||||
|
inline-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-card-text + .v-card-text {
|
||||||
|
padding-block-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-checkbox.v-input,
|
||||||
|
.v-switch.v-input {
|
||||||
|
--v-input-control-height: auto;
|
||||||
|
flex: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-selection-control--density-comfortable.v-checkbox-btn .v-selection-control__wrapper,
|
||||||
|
.v-selection-control--density-comfortable.v-radio .v-selection-control__wrapper,
|
||||||
|
.v-selection-control--density-comfortable.v-radio-btn .v-selection-control__wrapper {
|
||||||
|
margin-inline-start: -.5625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-selection-control--density-compact.v-radio .v-selection-control__wrapper,
|
||||||
|
.v-selection-control--density-compact.v-radio-btn .v-selection-control__wrapper,
|
||||||
|
.v-selection-control--density-compact.v-checkbox-btn .v-selection-control__wrapper {
|
||||||
|
margin-inline-start: -.3125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-selection-control--density-default.v-checkbox-btn .v-selection-control__wrapper,
|
||||||
|
.v-selection-control--density-default.v-radio .v-selection-control__wrapper,
|
||||||
|
.v-selection-control--density-default.v-radio-btn .v-selection-control__wrapper {
|
||||||
|
margin-inline-start: -.6875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-radio-group .v-selection-control-group .v-radio:not(:last-child) {
|
||||||
|
margin-inline-end: .9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disable-tab-transition {
|
||||||
|
overflow: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disable-tab-transition .v-window__container {
|
||||||
|
block-size: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disable-tab-transition .v-window-item:not(.v-window-item--active) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disable-tab-transition .v-window__container .v-window-item {
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-list .v-list-item__prepend > .v-icon,
|
||||||
|
.v-list .v-list-item__append > .v-icon {
|
||||||
|
opacity: var(--v-high-emphasis-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
--v-card-list-gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list.v-list {
|
||||||
|
padding-block: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list .v-list-item {
|
||||||
|
min-block-size: unset;
|
||||||
|
min-block-size: auto !important;
|
||||||
|
padding-block: 0 !important;
|
||||||
|
padding-inline: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list .v-list-item > .v-ripple__container {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list .v-list-item:not(:last-child) {
|
||||||
|
padding-block-end: var(--v-card-list-gap) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list .v-list-item: hover > .v-list-item__overlay,
|
||||||
|
.card-list .v-list-item:focus > .v-list-item__overlay,
|
||||||
|
.card-list .v-list-item:active > .v-list-item__overlay,
|
||||||
|
.card-list .v-list-item.active > .v-list-item__overlay {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-divider {
|
||||||
|
color: rgb(var(--v-border-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-data-table .v-checkbox-btn .v-selection-control__wrapper {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-data-table .v-selection-control {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-data-table .v-pagination {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-data-table-footer {
|
||||||
|
margin-block-start: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-field:hover .v-field__outline {
|
||||||
|
--v-field-border-opacity: var(--v-medium-emphasis-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-label {
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-label:not(.v-field-label--floating) {
|
||||||
|
color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-messages {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-alert__close .v-btn--icon .v-icon {
|
||||||
|
--v-icon-size-multiplier: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-badge__badge {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-btn:focus-visible:after {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-input:not(.v-select--chips) .v-select__selection .v-chip {
|
||||||
|
margin-block: 2px var(--select-chips-margin-bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-card-subtitle,
|
||||||
|
.v-list-item-subtitle {
|
||||||
|
color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-field__input input::placeholder,
|
||||||
|
input.v-field__input::placeholder,
|
||||||
|
textarea.v-field__input::placeholder {
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity)) !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-card-item {
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-card-text {
|
||||||
|
letter-spacing: .0094rem;
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-card--variant-elevated {
|
||||||
|
box-shadow: 0 4px 5px -2px var(--v-shadow-key-umbra-opacity), 0 2px 10px 1px var(--v-shadow-key-penumbra-opacity), 0 2px 16px 1px var(--v-shadow-key-ambient-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-card--variant-elevated,
|
||||||
|
.v-card--variant-flat {
|
||||||
|
background: rgb(var(--v-theme-surface));
|
||||||
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<v-row class="match-height">
|
||||||
|
about
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<v-row class="match-height">
|
||||||
|
accounts
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<v-row class="match-height">
|
||||||
|
exchange rates
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<v-row class="match-height">
|
||||||
|
overview
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,344 @@
|
|||||||
|
<template>
|
||||||
|
<div class="auth-wrapper d-flex align-center justify-center pa-4">
|
||||||
|
<v-card class="auth-card pa-4 pt-7" max-width="448">
|
||||||
|
<v-card-item class="justify-center">
|
||||||
|
<v-card-title class="d-grid font-weight-semibold text-2xl">
|
||||||
|
<v-img alt="logo" class="login-page-logo" src="/img/ezbookkeeping-192.png" :width="96" />
|
||||||
|
<p class="mt-4 font-weight-bold">{{ $t('global.app.title') }}</p>
|
||||||
|
</v-card-title>
|
||||||
|
</v-card-item>
|
||||||
|
|
||||||
|
<v-card-text>
|
||||||
|
<v-form>
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-text-field
|
||||||
|
type="text"
|
||||||
|
autocomplete="username"
|
||||||
|
clearable
|
||||||
|
:disabled="show2faInput"
|
||||||
|
:label="$t('Username')"
|
||||||
|
:placeholder="$t('Your username or email')"
|
||||||
|
v-model="username"
|
||||||
|
@input="tempToken = ''"
|
||||||
|
@keyup.enter="$refs.passwordInput.focus()"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-text-field
|
||||||
|
autocomplete="current-password"
|
||||||
|
clearable
|
||||||
|
ref="passwordInput"
|
||||||
|
:type="isPasswordVisible ? 'text' : 'password'"
|
||||||
|
:disabled="show2faInput"
|
||||||
|
:label="$t('Password')"
|
||||||
|
:placeholder="$t('Your password')"
|
||||||
|
:append-inner-icon="isPasswordVisible ? icons.eyeSlash : icons.eye"
|
||||||
|
v-model="password"
|
||||||
|
@input="tempToken = ''"
|
||||||
|
@click:append-inner="isPasswordVisible = !isPasswordVisible"
|
||||||
|
@keyup.enter="login"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12" v-show="show2faInput">
|
||||||
|
<v-text-field
|
||||||
|
type="number"
|
||||||
|
autocomplete="one-time-code"
|
||||||
|
clearable
|
||||||
|
ref="passcodeInput"
|
||||||
|
:label="$t('Passcode')"
|
||||||
|
:placeholder="$t('Passcode')"
|
||||||
|
:append-inner-icon="icons.backupCode"
|
||||||
|
v-model="passcode"
|
||||||
|
@click:append-inner="twoFAVerifyType = 'backupcode'"
|
||||||
|
@keyup.enter="verify"
|
||||||
|
v-if="twoFAVerifyType === 'passcode'"
|
||||||
|
/>
|
||||||
|
<v-text-field
|
||||||
|
type="text"
|
||||||
|
clearable
|
||||||
|
:label="$t('Backup Code')"
|
||||||
|
:placeholder="$t('Backup Code')"
|
||||||
|
:append-inner-icon="icons.passcode"
|
||||||
|
v-model="backupCode"
|
||||||
|
@click:append-inner="twoFAVerifyType = 'passcode'"
|
||||||
|
@keyup.enter="verify"
|
||||||
|
v-if="twoFAVerifyType === 'backupcode'"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-btn block :class="{ 'disabled': inputIsEmpty || logining }"
|
||||||
|
@click="login" v-if="!show2faInput">
|
||||||
|
{{ $t('Log In') }}
|
||||||
|
</v-btn>
|
||||||
|
<v-btn block :class="{ 'disabled': twoFAInputIsEmpty || verifying }"
|
||||||
|
@click="verify" v-else-if="show2faInput">
|
||||||
|
{{ $t('Continue') }}
|
||||||
|
</v-btn>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12" class="text-center text-base">
|
||||||
|
<span>{{ $t('Don\'t have an account?') }}</span>
|
||||||
|
<router-link class="text-primary ms-2" to="/signup">
|
||||||
|
{{ $t('Create an account') }}
|
||||||
|
</router-link>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12" class="text-center">
|
||||||
|
<v-menu location="bottom">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<v-btn variant="text" v-bind="props">{{ currentLanguageName }}</v-btn>
|
||||||
|
</template>
|
||||||
|
<v-list>
|
||||||
|
<v-list-item v-for="(lang, locale) in allLanguages" :key="locale">
|
||||||
|
<v-list-item-title
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="changeLanguage(locale)">
|
||||||
|
{{ lang.displayName }}
|
||||||
|
</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12" class="d-flex align-center">
|
||||||
|
<VDivider />
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12" class="text-center text-sm">
|
||||||
|
<span>Powered by </span>
|
||||||
|
<a href="https://github.com/mayswind/ezbookkeeping" target="_blank">ezBookkeeping</a> <span>{{ version }}</span>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-form>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
|
||||||
|
<v-snackbar v-model="showSnackbar">
|
||||||
|
{{ snackbarMessage }}
|
||||||
|
|
||||||
|
<template #actions>
|
||||||
|
<v-btn color="primary" variant="text" @click="showSnackbar = false">{{ $t('Close') }}</v-btn>
|
||||||
|
</template>
|
||||||
|
</v-snackbar>
|
||||||
|
|
||||||
|
<v-overlay class="justify-center align-center" :persistent="true" v-model="logining">
|
||||||
|
<v-progress-circular indeterminate></v-progress-circular>
|
||||||
|
</v-overlay>
|
||||||
|
|
||||||
|
<v-overlay class="justify-center align-center" :persistent="true" v-model="verifying">
|
||||||
|
<v-progress-circular indeterminate></v-progress-circular>
|
||||||
|
</v-overlay>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapStores } from 'pinia';
|
||||||
|
import { useRootStore } from '@/stores/index.js';
|
||||||
|
import { useSettingsStore } from '@/stores/setting.js';
|
||||||
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
mdiEyeOutline,
|
||||||
|
mdiEyeOffOutline,
|
||||||
|
mdiOnepassword,
|
||||||
|
mdiHelpCircleOutline
|
||||||
|
} from '@mdi/js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
passcode: '',
|
||||||
|
backupCode: '',
|
||||||
|
tempToken: '',
|
||||||
|
isPasswordVisible: false,
|
||||||
|
logining: false,
|
||||||
|
verifying: false,
|
||||||
|
show2faInput: false,
|
||||||
|
twoFAVerifyType: 'passcode',
|
||||||
|
showSnackbar: false,
|
||||||
|
snackbarMessage: '',
|
||||||
|
icons: {
|
||||||
|
eye: mdiEyeOutline,
|
||||||
|
eyeSlash: mdiEyeOffOutline,
|
||||||
|
passcode: mdiOnepassword,
|
||||||
|
backupCode: mdiHelpCircleOutline
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapStores(useRootStore, useSettingsStore, useExchangeRatesStore),
|
||||||
|
version() {
|
||||||
|
return 'v' + this.$version;
|
||||||
|
},
|
||||||
|
allLanguages() {
|
||||||
|
return this.$locale.getAllLanguageInfos();
|
||||||
|
},
|
||||||
|
isUserRegistrationEnabled() {
|
||||||
|
return this.$settings.isUserRegistrationEnabled();
|
||||||
|
},
|
||||||
|
inputIsEmpty() {
|
||||||
|
return !this.username || !this.password;
|
||||||
|
},
|
||||||
|
twoFAInputIsEmpty() {
|
||||||
|
if (this.twoFAVerifyType === 'backupcode') {
|
||||||
|
return !this.backupCode;
|
||||||
|
} else {
|
||||||
|
return !this.passcode;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentLanguageName() {
|
||||||
|
const currentLocale = this.$i18n.locale;
|
||||||
|
let lang = this.$locale.getLanguageInfo(currentLocale);
|
||||||
|
|
||||||
|
if (!lang) {
|
||||||
|
lang = this.$locale.getLanguageInfo(this.$locale.getDefaultLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return lang.displayName;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
login() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
if (!self.username) {
|
||||||
|
self.showSnackbarMessage(self.$t('Username cannot be empty'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!self.password) {
|
||||||
|
self.showSnackbarMessage(self.$t('Password cannot be empty'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.tempToken) {
|
||||||
|
self.show2faInput = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.logining) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.isPasswordVisible = false;
|
||||||
|
self.logining = true;
|
||||||
|
|
||||||
|
self.rootStore.authorize({
|
||||||
|
loginName: self.username,
|
||||||
|
password: self.password
|
||||||
|
}).then(authResponse => {
|
||||||
|
self.logining = false;
|
||||||
|
|
||||||
|
if (authResponse.need2FA) {
|
||||||
|
self.tempToken = authResponse.token;
|
||||||
|
self.show2faInput = true;
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (self.$refs.passcodeInput) {
|
||||||
|
self.$refs.passcodeInput.focus();
|
||||||
|
self.$refs.passcodeInput.select();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authResponse.user && authResponse.user.language) {
|
||||||
|
const localeDefaultSettings = self.$locale.setLanguage(authResponse.user.language);
|
||||||
|
self.settingsStore.updateLocalizedDefaultSettings(localeDefaultSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.$settings.isAutoUpdateExchangeRatesData()) {
|
||||||
|
self.exchangeRatesStore.getLatestExchangeRates({silent: true, force: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$router.replace('/');
|
||||||
|
}).catch(error => {
|
||||||
|
self.logining = false;
|
||||||
|
|
||||||
|
if (!error.processed) {
|
||||||
|
self.showSnackbarMessage(self.$tError(error.message || error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
verify() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
if (self.twoFAInputIsEmpty || self.verifying) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.twoFAVerifyType === 'passcode' && !this.passcode) {
|
||||||
|
self.showSnackbarMessage(self.$t('Passcode cannot be empty'));
|
||||||
|
return;
|
||||||
|
} else if (this.twoFAVerifyType === 'backupcode' && !this.backupCode) {
|
||||||
|
self.showSnackbarMessage(self.$t('Backup code cannot be empty'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.verifying = true;
|
||||||
|
|
||||||
|
self.rootStore.authorize2FA({
|
||||||
|
token: self.tempToken,
|
||||||
|
passcode: self.twoFAVerifyType === 'passcode' ? self.passcode : null,
|
||||||
|
recoveryCode: self.twoFAVerifyType === 'backupcode' ? self.backupCode : null
|
||||||
|
}).then(authResponse => {
|
||||||
|
self.verifying = false;
|
||||||
|
|
||||||
|
if (authResponse.user && authResponse.user.language) {
|
||||||
|
const localeDefaultSettings = self.$locale.setLanguage(authResponse.user.language);
|
||||||
|
self.settingsStore.updateLocalizedDefaultSettings(localeDefaultSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.$settings.isAutoUpdateExchangeRatesData()) {
|
||||||
|
self.exchangeRatesStore.getLatestExchangeRates({ silent: true, force: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$router.replace('/');
|
||||||
|
}).catch(error => {
|
||||||
|
self.verifying = false;
|
||||||
|
|
||||||
|
if (!error.processed) {
|
||||||
|
self.showSnackbarMessage(self.$tError(error.message || error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
switch2FAVerifyType() {
|
||||||
|
if (this.twoFAVerifyType === 'passcode') {
|
||||||
|
this.twoFAVerifyType = 'backupcode';
|
||||||
|
} else {
|
||||||
|
this.twoFAVerifyType = 'passcode';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeLanguage(locale) {
|
||||||
|
const localeDefaultSettings = this.$locale.setLanguage(locale);
|
||||||
|
this.settingsStore.updateLocalizedDefaultSettings(localeDefaultSettings);
|
||||||
|
},
|
||||||
|
showSnackbarMessage(message) {
|
||||||
|
this.showSnackbar = true;
|
||||||
|
this.snackbarMessage = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.auth-wrapper {
|
||||||
|
min-block-size: calc(var(--vh, 1vh) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-card {
|
||||||
|
z-index: 1 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-page-logo {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout-wrapper layout-nav-type-vertical layout-navbar-static layout-footer-static layout-content-width-fluid"
|
||||||
|
:class="{ 'layout-overlay-nav': mdAndDown }">
|
||||||
|
<div class="layout-vertical-nav" :class="{'visible': showVerticalOverlayMenu, 'scrolled': isVerticalNavScrolled, 'overlay-nav': mdAndDown}">
|
||||||
|
<div class="nav-header">
|
||||||
|
<router-link to="/" class="app-logo d-flex align-center gap-x-3 app-title-wrapper">
|
||||||
|
<div class="d-flex">
|
||||||
|
<v-img alt="logo" class="main-logo" src="/img/ezbookkeeping-192.png" />
|
||||||
|
</div>
|
||||||
|
<h1 class="font-weight-medium text-xl">{{ $t('global.app.title') }}</h1>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
<perfect-scrollbar
|
||||||
|
tag="ul" class="nav-items"
|
||||||
|
:options="{ wheelPropagation: false }"
|
||||||
|
@ps-scroll-y="handleNavScroll"
|
||||||
|
>
|
||||||
|
<li class="nav-link">
|
||||||
|
<RouterLink to="/">
|
||||||
|
<v-icon class="nav-item-icon" :icon="icons.overview"/>
|
||||||
|
<span class="nav-item-title">{{ $t('Overview') }}</span>
|
||||||
|
</RouterLink>
|
||||||
|
</li>
|
||||||
|
<li class="nav-section-title">
|
||||||
|
<div class="title-wrapper">
|
||||||
|
<span class="title-text">{{ $t('Transaction Data') }}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="nav-link">
|
||||||
|
<RouterLink to="/transactions">
|
||||||
|
<v-icon class="nav-item-icon" :icon="icons.transactions"/>
|
||||||
|
<span class="nav-item-title">{{ $t('Transaction List') }}</span>
|
||||||
|
</RouterLink>
|
||||||
|
</li>
|
||||||
|
<li class="nav-link">
|
||||||
|
<RouterLink to="/statistics/transaction">
|
||||||
|
<v-icon class="nav-item-icon" :icon="icons.statistics"/>
|
||||||
|
<span class="nav-item-title">{{ $t('Statistics Data') }}</span>
|
||||||
|
</RouterLink>
|
||||||
|
</li>
|
||||||
|
<li class="nav-section-title">
|
||||||
|
<div class="title-wrapper">
|
||||||
|
<span class="title-text">{{ $t('Data Management') }}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="nav-link">
|
||||||
|
<RouterLink to="/accounts">
|
||||||
|
<v-icon class="nav-item-icon" :icon="icons.accounts"/>
|
||||||
|
<span class="nav-item-title">{{ $t('Account List') }}</span>
|
||||||
|
</RouterLink>
|
||||||
|
</li>
|
||||||
|
<li class="nav-link">
|
||||||
|
<RouterLink to="/categories">
|
||||||
|
<v-icon class="nav-item-icon" :icon="icons.categories"/>
|
||||||
|
<span class="nav-item-title">{{ $t('Transaction Categories') }}</span>
|
||||||
|
</RouterLink>
|
||||||
|
</li>
|
||||||
|
<li class="nav-link">
|
||||||
|
<RouterLink to="/tags">
|
||||||
|
<v-icon class="nav-item-icon" :icon="icons.tags"/>
|
||||||
|
<span class="nav-item-title">{{ $t('Transaction Tags') }}</span>
|
||||||
|
</RouterLink>
|
||||||
|
</li>
|
||||||
|
<li class="nav-section-title">
|
||||||
|
<div class="title-wrapper">
|
||||||
|
<span class="title-text">{{ $t('Other') }}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="nav-link">
|
||||||
|
<RouterLink to="/exchange_rates">
|
||||||
|
<v-icon class="nav-item-icon" :icon="icons.exchangeRates"/>
|
||||||
|
<span class="nav-item-title">{{ $t('Exchange Rates Data') }}</span>
|
||||||
|
</RouterLink>
|
||||||
|
</li>
|
||||||
|
<li class="nav-link">
|
||||||
|
<RouterLink to="/about">
|
||||||
|
<v-icon class="nav-item-icon" :icon="icons.about"/>
|
||||||
|
<span class="nav-item-title">{{ $t('About') }}</span>
|
||||||
|
</RouterLink>
|
||||||
|
</li>
|
||||||
|
</perfect-scrollbar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layout-content-wrapper">
|
||||||
|
<div class="layout-navbar navbar-blur">
|
||||||
|
<div class="navbar-content-container">
|
||||||
|
<div class="d-flex h-100 align-center">
|
||||||
|
<v-btn class="ms-n3 d-lg-none" color="default" variant="text"
|
||||||
|
:icon="true" @click="showVerticalOverlayMenu = true">
|
||||||
|
<v-icon :icon="icons.menu" size="24" />
|
||||||
|
</v-btn>
|
||||||
|
<div class="app-logo d-flex align-center gap-x-3 app-title-wrapper" v-if="mdAndDown">
|
||||||
|
<div class="d-flex">
|
||||||
|
<v-img alt="logo" class="main-logo" src="/img/ezbookkeeping-192.png" />
|
||||||
|
</div>
|
||||||
|
<h1 class="font-weight-medium text-xl">{{ $t('global.app.title') }}</h1>
|
||||||
|
</div>
|
||||||
|
<v-spacer />
|
||||||
|
<v-avatar class="cursor-pointer" color="primary" variant="tonal">
|
||||||
|
<v-icon :icon="icons.user"/>
|
||||||
|
<v-menu activator="parent" width="230" location="bottom end" offset="14px">
|
||||||
|
<v-list>
|
||||||
|
<v-list-item>
|
||||||
|
<template #prepend>
|
||||||
|
<v-list-item-action start>
|
||||||
|
<v-avatar color="primary" variant="tonal">
|
||||||
|
<v-icon :icon="icons.user"/>
|
||||||
|
</v-avatar>
|
||||||
|
</v-list-item-action>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title class="font-weight-semibold">
|
||||||
|
{{ currentNickName }}
|
||||||
|
</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<v-divider class="my-2"/>
|
||||||
|
<v-list-item to="/user/settings">
|
||||||
|
<template #prepend>
|
||||||
|
<v-icon class="me-2" :icon="icons.profile" size="22"/>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>{{ $t('User Profile') }}</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item to="/app/settings">
|
||||||
|
<template #prepend>
|
||||||
|
<v-icon class="me-2" :icon="icons.settings" size="22"/>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>{{ $t('Application Settings') }}</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<v-divider class="my-2"/>
|
||||||
|
<v-list-item :class="{ 'disabled': logouting }" @click="logout">
|
||||||
|
<template #prepend>
|
||||||
|
<v-icon class="me-2" :icon="icons.logout" size="22"/>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>{{ $t('Log Out') }}</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</v-avatar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layout-page-content">
|
||||||
|
<div class="page-content-container">
|
||||||
|
<router-view/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layout-overlay" :class="{ 'visible': showVerticalOverlayMenu }" @click="showVerticalOverlayMenu = false"></div>
|
||||||
|
|
||||||
|
<v-overlay class="justify-center align-center" :persistent="true" v-model="showLoading">
|
||||||
|
<v-progress-circular indeterminate></v-progress-circular>
|
||||||
|
</v-overlay>
|
||||||
|
|
||||||
|
<v-snackbar :timeout="2000" v-model="showSnackbar">
|
||||||
|
{{ snackbarMessage }}
|
||||||
|
|
||||||
|
<template #actions>
|
||||||
|
<v-btn color="red" variant="text" @click="showSnackbar = false">{{ $t('Close') }}</v-btn>
|
||||||
|
</template>
|
||||||
|
</v-snackbar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useDisplay } from 'vuetify';
|
||||||
|
import { mapStores } from 'pinia';
|
||||||
|
import { useRootStore } from '@/stores/index.js';
|
||||||
|
import { useSettingsStore } from '@/stores/setting.js';
|
||||||
|
import { useUserStore } from '@/stores/user.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
mdiMenu,
|
||||||
|
mdiHomeOutline,
|
||||||
|
mdiListBoxOutline,
|
||||||
|
mdiCreditCardOutline,
|
||||||
|
mdiViewDashboardOutline,
|
||||||
|
mdiTagOutline,
|
||||||
|
mdiChartPieOutline,
|
||||||
|
mdiSwapHorizontal,
|
||||||
|
mdiCogOutline,
|
||||||
|
mdiInformationOutline,
|
||||||
|
mdiAccount,
|
||||||
|
mdiAccountOutline,
|
||||||
|
mdiLogout
|
||||||
|
} from '@mdi/js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
logouting: false,
|
||||||
|
isVerticalNavScrolled: false,
|
||||||
|
showVerticalOverlayMenu: false,
|
||||||
|
showLoading: false,
|
||||||
|
showSnackbar: false,
|
||||||
|
snackbarMessage: '',
|
||||||
|
icons: {
|
||||||
|
menu: mdiMenu,
|
||||||
|
overview: mdiHomeOutline,
|
||||||
|
transactions: mdiListBoxOutline,
|
||||||
|
accounts: mdiCreditCardOutline,
|
||||||
|
categories: mdiViewDashboardOutline,
|
||||||
|
tags: mdiTagOutline,
|
||||||
|
statistics: mdiChartPieOutline,
|
||||||
|
exchangeRates: mdiSwapHorizontal,
|
||||||
|
settings: mdiCogOutline,
|
||||||
|
about: mdiInformationOutline,
|
||||||
|
user: mdiAccount,
|
||||||
|
profile: mdiAccountOutline,
|
||||||
|
logout: mdiLogout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapStores(useRootStore, useSettingsStore, useUserStore),
|
||||||
|
mdAndDown() {
|
||||||
|
const { mdAndDown } = useDisplay();
|
||||||
|
return mdAndDown.value;
|
||||||
|
},
|
||||||
|
currentNickName() {
|
||||||
|
return this.userStore.currentUserNickname || this.$t('User');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleNavScroll(e) {
|
||||||
|
this.isVerticalNavScrolled = e.target.scrollTop > 0;
|
||||||
|
},
|
||||||
|
logout() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
self.logouting = true;
|
||||||
|
self.showLoading = true;
|
||||||
|
|
||||||
|
self.rootStore.logout().then(() => {
|
||||||
|
self.logouting = false;
|
||||||
|
self.showLoading = false;
|
||||||
|
|
||||||
|
self.$settings.clearSettings();
|
||||||
|
|
||||||
|
const localeDefaultSettings = self.$locale.initLocale(self.userStore.currentUserLanguage);
|
||||||
|
self.settingsStore.updateLocalizedDefaultSettings(localeDefaultSettings);
|
||||||
|
|
||||||
|
this.$router.replace('/login');
|
||||||
|
}).catch(error => {
|
||||||
|
self.logouting = false;
|
||||||
|
self.showLoading = false;
|
||||||
|
|
||||||
|
if (!error.processed) {
|
||||||
|
self.showSnackbarMessage(self.$tError(error.message || error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showSnackbarMessage(message) {
|
||||||
|
this.showSnackbar = true;
|
||||||
|
this.snackbarMessage = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.main-logo {
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<div class="auth-wrapper d-flex align-center justify-center pa-4">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<v-row class="match-height">
|
||||||
|
categories
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<v-row class="match-height">
|
||||||
|
tags
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<v-row class="match-height">
|
||||||
|
transactions
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<div class="auth-wrapper d-flex align-center justify-center pa-4">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<v-row class="match-height">
|
||||||
|
app settings
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<v-row class="match-height">
|
||||||
|
statistics
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<v-row class="match-height">
|
||||||
|
user settings
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -93,12 +93,24 @@
|
|||||||
"url": "https://github.com/vuejs/pinia",
|
"url": "https://github.com/vuejs/pinia",
|
||||||
"licenseUrl": "https://github.com/vuejs/pinia/blob/pinia%402.1.4/LICENSE"
|
"licenseUrl": "https://github.com/vuejs/pinia/blob/pinia%402.1.4/LICENSE"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "vue-router",
|
||||||
|
"copyright": "Copyright (c) 2019-present Eduardo San Martin Morote",
|
||||||
|
"url": "https://github.com/vuejs/router",
|
||||||
|
"licenseUrl": "https://github.com/vuejs/router/blob/v4.2.2/LICENSE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "vue-i18n",
|
"name": "vue-i18n",
|
||||||
"copyright": "Copyright (c) 2016 kazuya kawaguchi",
|
"copyright": "Copyright (c) 2016 kazuya kawaguchi",
|
||||||
"url": "https://github.com/intlify/vue-i18n-next",
|
"url": "https://github.com/intlify/vue-i18n-next",
|
||||||
"licenseUrl": "https://github.com/intlify/vue-i18n-next/blob/v9.2.2/LICENSE"
|
"licenseUrl": "https://github.com/intlify/vue-i18n-next/blob/v9.2.2/LICENSE"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "vuetify",
|
||||||
|
"copyright": "Copyright (c) 2016-2023 John Jeremy Leider",
|
||||||
|
"url": "https://vuetifyjs.com",
|
||||||
|
"licenseUrl": "https://github.com/vuetifyjs/vuetify/blob/v3.3.5/LICENSE.md"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "register-service-worker",
|
"name": "register-service-worker",
|
||||||
"copyright": "Copyright (c) 2013-present, Yuxi (Evan) You",
|
"copyright": "Copyright (c) 2013-present, Yuxi (Evan) You",
|
||||||
@@ -141,6 +153,12 @@
|
|||||||
"url": "https://github.com/nolimits4web/skeleton-elements",
|
"url": "https://github.com/nolimits4web/skeleton-elements",
|
||||||
"licenseUrl": "https://github.com/nolimits4web/skeleton-elements/blob/v4.0.1/LICENSE"
|
"licenseUrl": "https://github.com/nolimits4web/skeleton-elements/blob/v4.0.1/LICENSE"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "vue3-perfect-scrollbar",
|
||||||
|
"copyright": "Copyright (c) 2018 Adam",
|
||||||
|
"url": "https://github.com/mercs600/vue3-perfect-scrollbar",
|
||||||
|
"licenseUrl": "https://github.com/mercs600/vue3-perfect-scrollbar/blob/1.6.1/LICENSE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "@vuepic/vue-datepicker",
|
"name": "@vuepic/vue-datepicker",
|
||||||
"copyright": "Copyright (c) 2021-present Vuepic",
|
"copyright": "Copyright (c) 2021-present Vuepic",
|
||||||
@@ -201,9 +219,20 @@
|
|||||||
"url": "https://github.com/faisalman/ua-parser-js",
|
"url": "https://github.com/faisalman/ua-parser-js",
|
||||||
"licenseUrl": "https://github.com/faisalman/ua-parser-js/blob/1.0.35/license.md"
|
"licenseUrl": "https://github.com/faisalman/ua-parser-js/blob/1.0.35/license.md"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Materio - Vuetify VueJS 3 Free Admin Template",
|
||||||
|
"copyright": "Copyright (c) 2022 ThemeSelection",
|
||||||
|
"url": "https://github.com/themeselection/materio-vuetify-vuejs-admin-template-free",
|
||||||
|
"licenseUrl": "https://github.com/themeselection/materio-vuetify-vuejs-admin-template-free/blob/v2.1.0/LICENSE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Icons8 Line Awesome",
|
"name": "Icons8 Line Awesome",
|
||||||
"url": "https://icons8.com/line-awesome",
|
"url": "https://icons8.com/line-awesome",
|
||||||
"licenseUrl": "https://github.com/icons8/line-awesome/blob/master/LICENSE.md"
|
"licenseUrl": "https://github.com/icons8/line-awesome/blob/master/LICENSE.md"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Material Design Icons for JS/TypeScript",
|
||||||
|
"url": "https://materialdesignicons.com",
|
||||||
|
"licenseUrl": "https://github.com/Templarian/MaterialDesign-JS/blob/v7.2.96/LICENSE"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
+11
-1
@@ -110,10 +110,20 @@ export default defineConfig(async () => {
|
|||||||
manualChunks: function (id) {
|
manualChunks: function (id) {
|
||||||
if (/[\\/]node_modules[\\/]leaflet[\\/]/i.test(id)) {
|
if (/[\\/]node_modules[\\/]leaflet[\\/]/i.test(id)) {
|
||||||
return 'leaflet';
|
return 'leaflet';
|
||||||
|
} else if (/[\\/]node_modules[\\/](moment|moment-timezone)[\\/]/i.test(id)) {
|
||||||
|
return 'moment';
|
||||||
} else if (/[\\/]node_modules[\\/](dom7|framework7.*|skeleton-elements|swiper)[\\/]/i.test(id)) {
|
} else if (/[\\/]node_modules[\\/](dom7|framework7.*|skeleton-elements|swiper)[\\/]/i.test(id)) {
|
||||||
return 'vendor-mobile';
|
return 'vendor-mobile';
|
||||||
|
} else if (/[\\/]node_modules[\\/](vuetify|vue-router|vue3-perfect-scrollbar|@mdi.*)[\\/]/i.test(id)) {
|
||||||
|
return 'vendor-desktop';
|
||||||
} else if (/[\\/]node_modules[\\/]/i.test(id)) {
|
} else if (/[\\/]node_modules[\\/]/i.test(id)) {
|
||||||
return 'vendor';
|
return 'vendor-common';
|
||||||
|
} else if (/[\\/]src[\\/]locales[\\/]/i.test(id)) {
|
||||||
|
return 'locales';
|
||||||
|
} else if (/[\\/]src[\\/](consts|stores)[\\/]/i.test(id)) {
|
||||||
|
return 'common';
|
||||||
|
} else if (/[\\/]src[\\/]lib[\\/](map[\\/]|[a-zA-Z0-9-_]+\.js)/i.test(id)) {
|
||||||
|
return 'common';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user