modify style

This commit is contained in:
MaysWind
2023-08-05 23:05:39 +08:00
parent 698d94feed
commit 2390c085e4
11 changed files with 1030 additions and 885 deletions
@@ -0,0 +1,51 @@
<template>
<div class="btn-vertical-group d-flex flex-column">
<v-btn border :key="idx"
:color="value === button.value ? 'primary' : 'default'"
:variant="value === button.value ? 'tonal' : 'outlined'" :disabled="disabled"
v-for="(button, idx) in buttons"
@click="value = button.value">
{{ button.name }}
</v-btn>
</div>
</template>
<script>
export default {
props: [
'disabled',
'buttons',
'modelValue'
],
emits: [
'update:modelValue'
],
computed: {
value: {
get: function () {
return this.modelValue;
},
set: function (value) {
if (value === this.modelValue) {
return;
}
this.$emit('update:modelValue', value);
}
}
}
}
</script>
<style>
.btn-vertical-group .v-btn:not(:first-child) {
border-top-left-radius: inherit;
border-top-right-radius: inherit;
}
.btn-vertical-group .v-btn:not(:last-child) {
border-bottom: 0;
border-bottom-left-radius: inherit;
border-bottom-right-radius: inherit;
}
</style>
+8 -1
View File
@@ -23,8 +23,11 @@ import { VIcon } from 'vuetify/components/VIcon';
import { VImg } from 'vuetify/components/VImg';
import { VInput } from 'vuetify/components/VInput';
import { VLabel } from 'vuetify/components/VLabel';
import { VLayout } from 'vuetify/components/VLayout';
import { VList, VListGroup, VListImg, VListItem, VListItemAction, VListItemMedia, VListItemSubtitle, VListItemTitle, VListSubheader } from 'vuetify/components/VList';
import { VMain } from 'vuetify/components/VMain';
import { VMenu } from 'vuetify/components/VMenu';
import { VNavigationDrawer } from 'vuetify/components/VNavigationDrawer';
import { VOverlay } from 'vuetify/components/VOverlay';
import { VPagination } from 'vuetify/components/VPagination';
import { VProgressCircular } from 'vuetify/components/VProgressCircular';
@@ -77,6 +80,7 @@ import {
import PinCodeInput from '@/components/common/PinCodeInput.vue';
import ItemIcon from '@/components/desktop/ItemIcon.vue';
import BtnVerticalGroup from '@/components/desktop/BtnVerticalGroup.vue';
import AmountInput from '@/components/desktop/AmountInput.vue';
import StepsBar from '@/components/desktop/StepsBar.vue';
import ConfirmDialog from '@/components/desktop/ConfirmDialog.vue';
@@ -132,6 +136,7 @@ const vuetify = createVuetify({
VImg,
VInput,
VLabel,
VLayout,
VList,
VListGroup,
VListImg,
@@ -141,7 +146,9 @@ const vuetify = createVuetify({
VListItemSubtitle,
VListItemTitle,
VListSubheader,
VMain,
VMenu,
VNavigationDrawer,
VOverlay,
VPagination,
VProgressCircular,
@@ -168,7 +175,6 @@ const vuetify = createVuetify({
mdi
}
},
defaults: {
VAlert: {
VBtn: {
@@ -384,6 +390,7 @@ app.component('DraggableList', draggable);
app.component('PinCodeInput', PinCodeInput);
app.component('ItemIcon', ItemIcon);
app.component('BtnVerticalGroup', BtnVerticalGroup);
app.component('AmountInput', AmountInput);
app.component('StepsBar', StepsBar);
app.component('ConfirmDialog', ConfirmDialog);
+20 -2
View File
@@ -100,8 +100,10 @@ input[type=number] {
min-inline-size: 100%;
}
.w-100-window-container.v-window > .v-window__container {
width: 100%;
.title-and-toolbar {
min-height: 38px;
flex-wrap: wrap;
row-gap: 1rem;
}
/** Common class for replacing the default style of vuetify **/
@@ -153,6 +155,18 @@ input[type=number] {
height: 1rem;
}
.w-100-window-container.v-window > .v-window__container {
width: 100%;
}
.tab-text-truncate.v-tab > .v-btn__content {
overflow-x: hidden;
}
.skeleton-no-margin .v-skeleton-loader__text {
margin: 0;
}
/** Common class for replacing the default style of Materio **/
.v-application,
.text-body-1,
@@ -195,6 +209,10 @@ input[type=number] {
}
}
.v-btn-group--density-comfortable.v-btn-group {
height: 38px;
}
/** Replacing the default style of @vuepic/vue-datepicker **/
.dp__theme_light {
--dp-primary-color: #c67e48;
+50 -20
View File
@@ -2,8 +2,8 @@
<v-row class="match-height">
<v-col cols="12">
<v-card>
<div class="d-flex flex-column flex-md-row">
<div>
<v-layout>
<v-navigation-drawer :permanent="alwaysShowNav" v-model="showNav">
<div class="mx-6 my-4">
<small>{{ $t('Data source') }}</small>
<p class="text-body-1 mt-1 mb-3">
@@ -11,14 +11,14 @@
<span v-else-if="!loading && exchangeRatesData && !exchangeRatesData.referenceUrl">{{ exchangeRatesData.dataSource }}</span>
<span v-else-if="!loading && !exchangeRatesData">{{ $t('None') }}</span>
<span v-else-if="loading">
<v-skeleton-loader class="exchange-rates-summary-skeleton mt-3 mb-4" type="text" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin mt-3 mb-4" type="text" :loading="true"></v-skeleton-loader>
</span>
</p>
<small v-if="exchangeRatesDataUpdateTime">{{ $t('Last Updated') }}</small>
<p class="text-body-1 mt-1" v-if="exchangeRatesDataUpdateTime">
<small v-if="exchangeRatesDataUpdateTime || loading">{{ $t('Last Updated') }}</small>
<p class="text-body-1 mt-1" v-if="exchangeRatesDataUpdateTime || loading">
<span v-if="!loading">{{ exchangeRatesDataUpdateTime }}</span>
<span v-if="loading">
<v-skeleton-loader class="exchange-rates-summary-skeleton mt-3 mb-5" type="text" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin mt-3 mb-5" type="text" :loading="true"></v-skeleton-loader>
</span>
</p>
</div>
@@ -35,24 +35,34 @@
<v-tabs show-arrows class="mb-4" direction="vertical"
:disabled="loading" v-model="baseCurrency"
v-if="exchangeRatesData && exchangeRatesData.exchangeRates && exchangeRatesData.exchangeRates.length">
<v-tab :key="exchangeRate.currencyCode" :value="exchangeRate.currencyCode"
<v-tab class="tab-text-truncate" :key="exchangeRate.currencyCode" :value="exchangeRate.currencyCode"
v-for="exchangeRate in availableExchangeRates">
{{ exchangeRate.currencyDisplayName }}
<div class="text-truncate">
<span>{{ exchangeRate.currencyDisplayName }}</span>
<small class="smaller ml-1">{{ exchangeRate.currencyCode }}</small>
</div>
</v-tab>
</v-tabs>
<div class="mx-6 mt-2 mb-4"
v-else-if="!exchangeRatesData || !exchangeRatesData.exchangeRates || !exchangeRatesData.exchangeRates.length">
<span v-if="!loading">{{ $t('None') }}</span>
<v-skeleton-loader type="paragraph" :loading="loading" v-else-if="loading"></v-skeleton-loader>
<span v-else-if="loading">
<v-skeleton-loader class="skeleton-no-margin pt-2 pb-5" type="text"
:key="itemIdx" :loading="loading"
v-for="itemIdx in [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]"></v-skeleton-loader>
</span>
</div>
</div>
<v-window class="d-flex flex-grow-1 ml-md-5 disable-tab-transition w-100-window-container" v-model="activeTab">
</v-navigation-drawer>
<v-main>
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container" v-model="activeTab">
<v-window-item value="exchangeRatesPage">
<v-card variant="flat">
<template #title>
<div class="d-flex align-center">
<div class="title-and-toolbar d-flex align-center">
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
:ripple="false" :icon="true" @click="showNav = !showNav">
<v-icon :icon="icons.menu" size="24" />
</v-btn>
<span>{{ $t('Exchange Rates Data') }}</span>
<v-btn density="compact" color="default" variant="text"
class="ml-2" :icon="true"
@@ -110,7 +120,8 @@
</v-card>
</v-window-item>
</v-window>
</div>
</v-main>
</v-layout>
</v-card>
</v-col>
</v-row>
@@ -119,6 +130,8 @@
</template>
<script>
import { useDisplay } from 'vuetify';
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js';
@@ -130,11 +143,13 @@ import {
} from '@/lib/currency.js';
import {
mdiRefresh
mdiRefresh,
mdiMenu
} from '@mdi/js';
export default {
data() {
const { mdAndUp } = useDisplay();
const userStore = useUserStore();
return {
@@ -142,8 +157,11 @@ export default {
baseCurrency: userStore.currentUserDefaultCurrency,
baseAmount: '1',
loading: true,
alwaysShowNav: mdAndUp.value,
showNav: mdAndUp.value,
icons: {
refresh: mdiRefresh
refresh: mdiRefresh,
menu: mdiMenu
}
};
},
@@ -166,6 +184,22 @@ export default {
created() {
this.reload(false);
},
setup() {
const display = useDisplay();
return {
display: display
};
},
watch: {
'display.mdAndUp.value': function (newValue) {
this.alwaysShowNav = newValue;
if (!this.showNav) {
this.showNav = newValue;
}
}
},
methods: {
reload(force) {
const self = this;
@@ -234,10 +268,6 @@ export default {
</script>
<style>
.exchange-rates-summary-skeleton .v-skeleton-loader__text {
margin: 0;
}
.exchange-rates-table tr.exchange-rates-table-row-data .hover-display {
display: none;
}
+7 -10
View File
@@ -22,7 +22,7 @@
<v-card-text>
<h5 class="text-2xl font-weight-medium text-primary">
<span v-if="!loadingOverview || (transactionOverview && transactionOverview.thisMonth && transactionOverview.thisMonth.valid)">{{ transactionOverview && transactionOverview.thisMonth ? getDisplayExpenseAmount(transactionOverview.thisMonth) : '-' }}</span>
<v-skeleton-loader class="d-inline-block overview-card-skeleton mt-4" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!transactionOverview || !transactionOverview.thisMonth || !transactionOverview.thisMonth.valid)"></v-skeleton-loader>
<v-skeleton-loader class="d-inline-block skeleton-no-margin mt-3 pb-1" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!transactionOverview || !transactionOverview.thisMonth || !transactionOverview.thisMonth.valid)"></v-skeleton-loader>
<v-btn class="ml-1" density="compact" color="default" variant="text"
:icon="true" @click="showAmountInHomePage = !showAmountInHomePage">
<v-icon :icon="showAmountInHomePage ? icons.eyeSlash : icons.eye" size="20" />
@@ -31,7 +31,7 @@
<div class="mt-2 mb-3">
<span class="mr-2">{{ $t('Monthly income') }}</span>
<span v-if="!loadingOverview || (transactionOverview && transactionOverview.thisMonth && transactionOverview.thisMonth.valid)">{{ transactionOverview && transactionOverview.thisMonth ? getDisplayIncomeAmount(transactionOverview.thisMonth) : '-' }}</span>
<v-skeleton-loader class="d-inline-block overview-card-skeleton" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!transactionOverview || !transactionOverview.thisMonth || !transactionOverview.thisMonth.valid)"></v-skeleton-loader>
<v-skeleton-loader class="d-inline-block skeleton-no-margin mt-1" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!transactionOverview || !transactionOverview.thisMonth || !transactionOverview.thisMonth.valid)"></v-skeleton-loader>
</div>
<v-btn size="small" to="/transaction/list?dateType=7">{{ $t('View Details') }}</v-btn>
<v-img class="overview-card-background" src="img/desktop/card-background.png"/>
@@ -48,7 +48,8 @@
<v-card-text>
<h6 class="text-sm font-weight-medium mb-6">
<span>{{ $t('format.misc.youHaveAccounts', { count: allAccounts.length }) }}</span>
<span v-if="!loadingOverview || (allAccounts && allAccounts.length)">{{ $t('format.misc.youHaveAccounts', { count: allAccounts.length }) }}</span>
<v-skeleton-loader class="skeleton-no-margin mt-1 mb-2 pb-1" width="200px" type="text" :loading="true" v-else-if="loadingOverview && (!allAccounts || !allAccounts.length)"></v-skeleton-loader>
</h6>
<v-row>
@@ -63,7 +64,7 @@
<div class="d-flex flex-column">
<span class="text-caption">{{ $t('Total assets') }}</span>
<span class="text-h6" v-if="!loadingOverview || (allAccounts && allAccounts.length)">{{ totalAssets }}</span>
<v-skeleton-loader class="overview-card-skeleton mt-3 mb-2" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!allAccounts || !allAccounts.length)"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin mt-3 mb-2" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!allAccounts || !allAccounts.length)"></v-skeleton-loader>
</div>
</div>
</v-col>
@@ -79,7 +80,7 @@
<div class="d-flex flex-column">
<span class="text-caption">{{ $t('Total liabilities') }}</span>
<span class="text-h6" v-if="!loadingOverview || (allAccounts && allAccounts.length)">{{ totalLiabilities }}</span>
<v-skeleton-loader class="overview-card-skeleton mt-3 mb-2" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!allAccounts || !allAccounts.length)"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin mt-3 mb-2" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!allAccounts || !allAccounts.length)"></v-skeleton-loader>
</div>
</div>
</v-col>
@@ -95,7 +96,7 @@
<div class="d-flex flex-column">
<span class="text-caption">{{ $t('Net assets') }}</span>
<span class="text-h6" v-if="!loadingOverview || (allAccounts && allAccounts.length)">{{ netAssets }}</span>
<v-skeleton-loader class="overview-card-skeleton mt-3 mb-2" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!allAccounts || !allAccounts.length)"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin mt-3 mb-2" width="120px" type="text" :loading="true" v-else-if="loadingOverview && (!allAccounts || !allAccounts.length)"></v-skeleton-loader>
</div>
</div>
</v-col>
@@ -425,8 +426,4 @@ export default {
inset-block-end: 0.5rem;
inset-inline-end: 1rem;
}
.overview-card-skeleton .v-skeleton-loader__text {
margin: 0;
}
</style>
+56 -31
View File
@@ -2,49 +2,54 @@
<v-row class="match-height">
<v-col cols="12">
<v-card>
<div class="d-flex flex-column flex-md-row">
<div>
<v-layout>
<v-navigation-drawer :permanent="alwaysShowNav" v-model="showNav">
<div class="mx-6 my-4">
<small>{{ $t('Net assets') }}</small>
<p class="text-body-1 text-income mt-1 mb-3">
<p class="text-body-1 text-income text-truncate mt-1 mb-3">
<span v-if="!loading">{{ netAssets }}</span>
<span v-else-if="loading">
<v-skeleton-loader class="accounts-summary-skeleton mt-3 mb-4" type="text" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin pt-2 pb-1" type="text" :loading="true"></v-skeleton-loader>
</span>
</p>
<small>{{ $t('Total liabilities') }}</small>
<p class="text-body-1 text-expense mt-1 mb-3">
<p class="text-body-1 text-expense text-truncate mt-1 mb-3">
<span v-if="!loading">{{ totalLiabilities }}</span>
<span v-else-if="loading">
<v-skeleton-loader class="accounts-summary-skeleton mt-3 mb-4" type="text" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin pt-2 pb-1" type="text" :loading="true"></v-skeleton-loader>
</span>
</p>
<small>{{ $t('Total assets') }}</small>
<p class="text-body-1 mt-1">
<span v-if="!loading">{{ totalAssets }}</span>
<span v-else-if="loading">
<v-skeleton-loader class="accounts-summary-skeleton mt-3 mb-5" type="text" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin pt-2 pb-1" type="text" :loading="true"></v-skeleton-loader>
</span>
</p>
</div>
<v-divider />
<v-tabs show-arrows class="account-category-tabs my-4" direction="vertical"
:disabled="loading" v-model="activeAccountCategoryId">
<v-tab :key="accountCategory.id" :value="accountCategory.id"
<v-tab class="tab-text-truncate" :key="accountCategory.id" :value="accountCategory.id"
v-for="accountCategory in allAccountCategories">
<ItemIcon icon-type="account" :icon-id="accountCategory.defaultAccountIconId" />
<div class="ml-2 d-flex flex-column">
<small class="text-left smaller">{{ accountCategoryTotalBalance(accountCategory) }}</small>
<div class="text-left">{{ $t(accountCategory.name) }}</div>
<div class="d-flex flex-column text-truncate ml-2">
<small class="text-truncate text-left smaller">{{ accountCategoryTotalBalance(accountCategory) }}</small>
<span class="text-truncate text-left">{{ $t(accountCategory.name) }}</span>
</div>
</v-tab>
</v-tabs>
</div>
<v-window class="d-flex flex-grow-1 ml-md-5 disable-tab-transition w-100-window-container" v-model="activeTab">
</v-navigation-drawer>
<v-main>
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container" v-model="activeTab">
<v-window-item value="accountPage">
<v-card variant="flat">
<v-card variant="flat" min-height="680">
<template #title>
<div class="d-flex align-center">
<div class="title-and-toolbar d-flex align-center">
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
:ripple="false" :icon="true" @click="showNav = !showNav">
<v-icon :icon="icons.menu" size="24" />
</v-btn>
<span>{{ $t('Account List') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
:disabled="loading" @click="add">{{ $t('Add') }}</v-btn>
@@ -76,11 +81,10 @@
</div>
</template>
<v-card-text class="accounts-overview-title pt-0">
<v-card-text class="accounts-overview-title text-truncate pt-0">
<span class="text-subtitle-1">{{ $t('Balance') }}</span>
<span class="accounts-overview-amount ml-3">
{{ activeAccountCategoryTotalBalance }}
</span>
<v-skeleton-loader class="skeleton-no-margin ml-3 mb-2" width="120px" type="text" :loading="true" v-if="loading && !hasAccount(activeAccountCategory)"></v-skeleton-loader>
<span class="accounts-overview-amount ml-3" v-else-if="!loading || hasAccount(activeAccountCategory)">{{ activeAccountCategoryTotalBalance }}</span>
<v-btn class="ml-2" density="compact" color="default" variant="text"
:icon="true" :disabled="loading"
@click="showAccountBalance = !showAccountBalance">
@@ -89,18 +93,18 @@
</v-btn>
</v-card-text>
<div v-if="loading && !hasAccount(activeAccountCategory)">
<div class="pl-2 pr-2 pr-md-4 mt-n4" v-if="loading && !hasAccount(activeAccountCategory)">
<v-skeleton-loader type="paragraph" :loading="loading"
:key="itemIdx" v-for="itemIdx in [ 1, 2, 3 ]"></v-skeleton-loader>
</div>
<v-row class="pl-4 pr-4 pr-md-8" v-if="!loading && !hasAccount(activeAccountCategory)">
<v-row class="pl-2 pr-2 pr-md-4" v-if="!loading && !hasAccount(activeAccountCategory)">
<v-col cols="12">
{{ $t('No available account') }}
</v-col>
</v-row>
<v-row class="pl-4 pr-4 pr-md-8">
<v-row class="pl-6 pr-6 pr-md-8">
<v-col cols="12">
<draggable-list
class="list-group"
@@ -119,8 +123,8 @@
<div class="account-title d-flex align-baseline">
<ItemIcon size="1.5rem" icon-type="account" :icon-id="element.icon"
:color="element.color" :hidden-status="element.hidden" />
<span class="account-name ml-2">{{ element.name }}</span>
<small class="account-currency ml-2">
<span class="account-name text-truncate ml-2">{{ element.name }}</span>
<small class="account-currency text-truncate ml-2">
{{ accountCurrency(element) }}
</small>
<v-spacer/>
@@ -204,7 +208,8 @@
</v-card>
</v-window-item>
</v-window>
</div>
</v-main>
</v-layout>
</v-card>
</v-col>
</v-row>
@@ -214,6 +219,8 @@
</template>
<script>
import { useDisplay } from 'vuetify';
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js';
@@ -233,6 +240,7 @@ import {
mdiEyeOutline,
mdiEyeOffOutline,
mdiRefresh,
mdiMenu,
mdiPencilOutline,
mdiDeleteOutline,
mdiListBoxOutline,
@@ -242,17 +250,22 @@ import {
export default {
data() {
const { mdAndUp } = useDisplay();
return {
activeAccountCategoryId: accountConstants.allCategories[0].id,
activeTab: 'accountPage',
activeSubAccount: {},
loading: true,
displayOrderModified: false,
alwaysShowNav: mdAndUp.value,
showNav: mdAndUp.value,
showHidden: false,
icons: {
eye: mdiEyeOutline,
eyeSlash: mdiEyeOffOutline,
refresh: mdiRefresh,
menu: mdiMenu,
edit: mdiPencilOutline,
show: mdiEyeOutline,
hide: mdiEyeOffOutline,
@@ -328,6 +341,22 @@ export default {
created() {
this.reload(false);
},
setup() {
const display = useDisplay();
return {
display: display
};
},
watch: {
'display.mdAndUp.value': function (newValue) {
this.alwaysShowNav = newValue;
if (!this.showNav) {
this.showNav = newValue;
}
}
},
methods: {
reload(force) {
const self = this;
@@ -500,17 +529,13 @@ export default {
</script>
<style>
.accounts-summary-skeleton .v-skeleton-loader__text {
margin: 0;
}
.account-category-tabs .v-tab.v-tab {
.account-category-tabs .v-tab {
--v-btn-height: calc(var(--v-tabs-height) * 1.5);
}
.accounts-overview-title {
line-height: 2rem !important;
height: 46px;
min-height: 52px;
display: flex;
align-items: flex-end;
}
+66 -41
View File
@@ -2,52 +2,43 @@
<v-row class="match-height">
<v-col cols="12">
<v-card>
<div class="d-flex flex-column flex-md-row">
<div>
<v-layout>
<v-navigation-drawer ref="navbar" :permanent="alwaysShowNav" v-model="showNav">
<div class="mx-6 my-4">
<div class="transaction-type-buttons d-flex flex-column">
<v-btn border :color="activeCategoryType === allCategoryTypes.Expense ? 'primary' : 'default'"
:variant="activeCategoryType === allCategoryTypes.Expense ? 'tonal' : 'outlined'" :disabled="loading"
@click="switchActiveCategoryType(allCategoryTypes.Expense)">
{{ $t('Expense') }}
</v-btn>
<v-btn border :color="activeCategoryType === allCategoryTypes.Income ? 'primary' : 'default'"
:variant="activeCategoryType === allCategoryTypes.Income ? 'tonal' : 'outlined'" :disabled="loading"
@click="switchActiveCategoryType(allCategoryTypes.Income)">
{{ $t('Income') }}
</v-btn>
<v-btn border :color="activeCategoryType === allCategoryTypes.Transfer ? 'primary' : 'default'"
:variant="activeCategoryType === allCategoryTypes.Transfer ? 'tonal' : 'outlined'" :disabled="loading"
@click="switchActiveCategoryType(allCategoryTypes.Transfer)">
{{ $t('Transfer') }}
</v-btn>
</div>
<btn-vertical-group :disabled="loading" :buttons="[
{ name: $t('Expense'), value: allCategoryTypes.Expense },
{ name: $t('Income'), value: allCategoryTypes.Income },
{ name: $t('Transfer'), value: allCategoryTypes.Transfer }
]" v-model="activeCategoryType" @update:modelValue="switchActiveCategoryType" />
</div>
<v-divider />
<v-tabs show-arrows class="my-4" direction="vertical"
:disabled="loading" v-model="primaryCategoryId">
<v-tab value="0" @click="primaryCategoryId = '0'">
{{ $t('Primary Categories') }}
<v-tab class="tab-text-truncate" value="0" @click="primaryCategoryId = '0'">
<span class="text-truncate">{{ $t('Primary Categories') }}</span>
</v-tab>
<template :key="category.id" v-for="category in primaryCategories">
<v-tab :value="category.id" v-if="!category.hidden"
<v-tab class="tab-text-truncate" :value="category.id" v-if="!category.hidden"
@click="switchPrimaryCategory(category)">
<div class="d-flex align-center">
<span>{{ category.name }}</span>
</div>
<span class="text-truncate">{{ category.name }}</span>
</v-tab>
</template>
<template v-if="loading && (!primaryCategories || primaryCategories.length < 1)">
<v-skeleton-loader class="transaction-primary-category-skeleton mx-5 mt-4 mb-3" type="text"
<v-skeleton-loader class="skeleton-no-margin mx-5 mt-4 mb-3" type="text"
:key="itemIdx" :loading="true" v-for="itemIdx in [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]"></v-skeleton-loader>
</template>
</v-tabs>
</div>
<v-window class="d-flex flex-grow-1 ml-md-5 disable-tab-transition w-100-window-container" v-model="activeTab">
</v-navigation-drawer>
<v-main>
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container" v-model="activeTab">
<v-window-item value="categoryPage">
<v-card variant="flat">
<v-card variant="flat" :min-height="cardMinHeight">
<template #title>
<div class="d-flex align-center">
<div class="title-and-toolbar d-flex align-center">
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
:ripple="false" :icon="true" @click="showNav = !showNav">
<v-icon :icon="icons.menu" size="24" />
</v-btn>
<span>{{ $t('Transaction Categories') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
:disabled="loading || updating" @click="add">{{ $t('Add') }}</v-btn>
@@ -173,7 +164,8 @@
</v-card>
</v-window-item>
</v-window>
</div>
</v-main>
</v-layout>
</v-card>
</v-col>
</v-row>
@@ -188,13 +180,17 @@
<script>
import PresetCategoryDialog from './list/dialogs/PresetCategoryDialog.vue';
import { useDisplay } from 'vuetify';
import { mapStores } from 'pinia';
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
import categoryConstants from '@/consts/category.js';
import { getOuterHeight } from '@/lib/ui.desktop.js';
import {
mdiRefresh,
mdiMenu,
mdiPencilOutline,
mdiEyeOffOutline,
mdiEyeOutline,
@@ -208,6 +204,8 @@ export default {
PresetCategoryDialog
},
data() {
const { mdAndUp } = useDisplay();
return {
activeCategoryType: categoryConstants.allCategoryTypes.Expense,
activeTab: 'categoryPage',
@@ -217,10 +215,14 @@ export default {
categoryHiding: {},
categoryRemoving: {},
displayOrderModified: false,
cardMinHeight: 680,
alwaysShowNav: mdAndUp.value,
showNav: mdAndUp.value,
showHidden: false,
showPresetDialog: false,
icons: {
refresh: mdiRefresh,
menu: mdiMenu,
edit: mdiPencilOutline,
show: mdiEyeOutline,
hide: mdiEyeOffOutline,
@@ -286,6 +288,22 @@ export default {
created() {
this.reload(false);
},
setup() {
const display = useDisplay();
return {
display: display
};
},
watch: {
'display.mdAndUp.value': function (newValue) {
this.alwaysShowNav = newValue;
if (!this.showNav) {
this.showNav = newValue;
}
}
},
methods: {
reload(force) {
const self = this;
@@ -301,6 +319,8 @@ export default {
if (force) {
self.$refs.snackbar.showMessage('Category list has been updated');
}
self.updateCardMinHeight();
}).catch(error => {
self.loading = false;
@@ -410,13 +430,9 @@ export default {
this.reload(false);
}
},
switchActiveCategoryType(activeCategoryType) {
if (this.activeCategoryType === activeCategoryType) {
return;
}
this.activeCategoryType = activeCategoryType;
switchActiveCategoryType() {
this.primaryCategoryId = '0';
this.updateCardMinHeight();
},
isCategorySupportSwitch(category) {
if (!category || category.hidden) {
@@ -433,16 +449,25 @@ export default {
if (!category.parentId || category.parentId === '' || category.parentId === '0') {
this.primaryCategoryId = category.id;
}
},
updateCardMinHeight() {
const self = this
self.$nextTick(() => {
if (self.$refs.navbar && self.$refs.navbar.$el && self.$refs.navbar.$el.nextElementSibling) {
let navbarHeight = getOuterHeight(self.$refs.navbar.$el.nextElementSibling);
if (navbarHeight > self.cardMinHeight) {
self.cardMinHeight = navbarHeight;
}
}
});
}
}
}
</script>
<style>
.transaction-primary-category-skeleton .v-skeleton-loader__text {
margin: 0;
}
.transaction-category-table tr.transaction-category-table-row .hover-display {
display: none;
}
@@ -17,9 +17,9 @@
</v-card-text>
<v-card-text class="mt-1 pb-2">
<div class="font-weight-semibold text-truncate text-red text-h5 text-income me-2 mb-2" v-if="!loading || incomeAmount">{{ incomeAmount }}</div>
<v-skeleton-loader class="income-expense-overview-card-skeleton mt-4 mb-6" type="text" width="120px" :loading="true" v-else-if="loading && !incomeAmount"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin mt-4 mb-7" type="text" width="120px" :loading="true" v-else-if="loading && !incomeAmount"></v-skeleton-loader>
<div class="text-truncate text-h6 text-expense" v-if="!loading || expenseAmount">{{ expenseAmount }}</div>
<v-skeleton-loader class="income-expense-overview-card-skeleton mb-2" type="text" width="120px" :loading="true" v-else-if="loading && !expenseAmount"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin mb-2" type="text" width="120px" :loading="true" v-else-if="loading && !expenseAmount"></v-skeleton-loader>
</v-card-text>
<v-card-text class="mt-6">
<span class="text-caption">{{ datetime }}</span>
@@ -51,9 +51,3 @@ export default {
}
}
</script>
<style>
.income-expense-overview-card-skeleton .v-skeleton-loader__text {
margin: 0;
}
</style>
@@ -2,43 +2,36 @@
<v-row class="match-height">
<v-col cols="12">
<v-card>
<div class="d-flex flex-column flex-md-row">
<div>
<v-layout>
<v-navigation-drawer :permanent="alwaysShowNav" v-model="showNav">
<div class="mx-6 my-4">
<v-btn-toggle
variant="outlined"
color="primary"
density="comfortable"
mandatory="force"
divided
:disabled="loading"
v-model="query.chartType"
>
<v-btn :value="allChartTypes.Pie" @click="setChartType(allChartTypes.Pie)">
{{ $t('Pie Chart') }}
</v-btn>
<v-btn :value="allChartTypes.Bar" @click="setChartType(allChartTypes.Bar)">
{{ $t('Bar Chart') }}
</v-btn>
</v-btn-toggle>
<btn-vertical-group :disabled="loading" :buttons="[
{ name: $t('Pie Chart'), value: allChartTypes.Pie },
{ name: $t('Bar Chart'), value: allChartTypes.Bar }
]" v-model="query.chartType" @update:modelValue="setChartType" />
</div>
<v-divider />
<v-tabs show-arrows class="my-4" direction="vertical"
:disabled="loading" v-model="query.chartDataType">
<v-tab :key="dataType.type" :value="dataType.type"
<v-tab class="tab-text-truncate" :key="dataType.type" :value="dataType.type"
v-for="dataType in allChartDataTypes">
{{ $t(dataType.name) }}
<span class="text-truncate">{{ $t(dataType.name) }}</span>
<v-tooltip activator="parent" location="right">{{ $t(dataType.name) }}</v-tooltip>
</v-tab>
</v-tabs>
</div>
<v-window class="d-flex flex-grow-1 ml-md-5 disable-tab-transition w-100-window-container" v-model="activeTab">
</v-navigation-drawer>
<v-main>
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container" v-model="activeTab">
<v-window-item value="statisticsPage">
<v-card variant="flat">
<v-card variant="flat" min-height="680">
<template #title>
<div class="statistics-title d-flex align-center">
<div class="title-and-toolbar d-flex align-center">
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
:ripple="false" :icon="true" @click="showNav = !showNav">
<v-icon :icon="icons.menu" size="24" />
</v-btn>
<span>{{ $t('Statistics Data') }}</span>
<div class="ml-4">
<v-btn-group color="default" density="comfortable" variant="outlined" divided>
<v-btn-group class="ml-4" color="default" density="comfortable" variant="outlined" divided>
<v-btn :icon="icons.left"
:disabled="loading || query.dateType === allDateRanges.All.type || query.chartDataType === allChartDataTypes.AccountTotalAssets.type || query.chartDataType === allChartDataTypes.AccountTotalLiabilities.type"
@click="shiftDateRange(query.startTime, query.endTime, -1)"/>
@@ -90,7 +83,6 @@
</v-list-item>
</v-list>
</v-menu>
</div>
<v-btn density="compact" color="default" variant="text"
class="ml-2" :icon="true" :disabled="loading"
v-if="!loading" @click="reload">
@@ -191,7 +183,8 @@
</v-card>
</v-window-item>
</v-window>
</div>
</v-main>
</v-layout>
</v-card>
</v-col>
</v-row>
@@ -218,6 +211,8 @@
</template>
<script>
import { useDisplay } from 'vuetify';
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js';
@@ -239,6 +234,7 @@ import {
mdiArrowRight,
mdiSort,
mdiRefresh,
mdiMenu,
mdiFilterOutline,
mdiFilterCogOutline,
mdiPencilOutline,
@@ -254,10 +250,14 @@ export default {
CategoryFilterSettingsCard
},
data() {
const { mdAndUp } = useDisplay();
return {
activeTab: 'statisticsPage',
initing: true,
loading: true,
alwaysShowNav: mdAndUp.value,
showNav: mdAndUp.value,
showCustomDateRangeDialog: false,
showFilterAccountDialog: false,
showFilterCategoryDialog: false,
@@ -267,6 +267,7 @@ export default {
right: mdiArrowRight,
sort: mdiSort,
refresh: mdiRefresh,
menu: mdiMenu,
filter: mdiFilterOutline,
filterSettings: mdiFilterCogOutline,
pencil: mdiPencilOutline,
@@ -360,6 +361,13 @@ export default {
this.statisticsStore.updateTransactionStatisticsFilter({
chartDataType: newValue
});
},
'display.mdAndUp.value': function (newValue) {
this.alwaysShowNav = newValue;
if (!this.showNav) {
this.showNav = newValue;
}
}
},
created() {
@@ -386,6 +394,13 @@ export default {
}
});
},
setup() {
const display = useDisplay();
return {
display: display
};
},
methods: {
reload(force) {
const self = this;
@@ -537,11 +552,6 @@ export default {
</script>
<style>
.statistics-title {
overflow-x: auto;
white-space: nowrap;
}
.statistics-custom-datetime-range {
font-size: 0.7rem;
color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity)) !important;
+1 -1
View File
@@ -3,7 +3,7 @@
<v-col cols="12">
<v-card>
<template #title>
<div class="d-flex align-center">
<div class="title-and-toolbar d-flex align-center">
<span>{{ $t('Transaction Tags') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
:disabled="loading || updating || hasEditingTag" @click="add">{{ $t('Add') }}</v-btn>
+57 -69
View File
@@ -2,51 +2,36 @@
<v-row class="match-height">
<v-col cols="12">
<v-card>
<div class="d-flex flex-column flex-md-row">
<div>
<v-layout>
<v-navigation-drawer :permanent="alwaysShowNav" v-model="showNav">
<div class="mx-6 my-4">
<div class="transaction-type-buttons d-flex flex-column">
<v-btn border :color="query.type === 0 ? 'primary' : 'default'"
:variant="query.type === 0 ? 'tonal' : 'outlined'" :disabled="loading"
@click="changeTypeFilter(0)">
{{ $t('All Types') }}
</v-btn>
<v-btn border :color="query.type === 1 ? 'primary' : 'default'"
:variant="query.type === 1 ? 'tonal' : 'outlined'" :disabled="loading"
@click="changeTypeFilter(1)">
{{ $t('Modify Balance') }}
</v-btn>
<v-btn border :color="query.type === 2 ? 'primary' : 'default'"
:variant="query.type === 2 ? 'tonal' : 'outlined'" :disabled="loading"
@click="changeTypeFilter(2)">
{{ $t('Income') }}
</v-btn>
<v-btn border :color="query.type === 3 ? 'primary' : 'default'"
:variant="query.type === 3 ? 'tonal' : 'outlined'" :disabled="loading"
@click="changeTypeFilter(3)">
{{ $t('Expense') }}
</v-btn>
<v-btn border :color="query.type === 4 ? 'primary' : 'default'"
:variant="query.type === 4 ? 'tonal' : 'outlined'" :disabled="loading"
@click="changeTypeFilter(4)">
{{ $t('Transfer') }}
</v-btn>
</div>
<btn-vertical-group :disabled="loading" :buttons="[
{ name: $t('All Types'), value: 0 },
{ name: $t('Modify Balance'), value: 1 },
{ name: $t('Income'), value: 2 },
{ name: $t('Expense'), value: 3 },
{ name: $t('Transfer'), value: 4 }
]" v-model="query.type" @update:modelValue="changeTypeFilter" />
</div>
<v-divider />
<v-tabs show-arrows class="my-4" direction="vertical"
:disabled="loading" v-model="recentDateRangeType">
<v-tab :key="idx" :value="idx" v-for="(recentDateRange, idx) in recentMonthDateRanges"
<v-tab class="tab-text-truncate" :key="idx" :value="idx" v-for="(recentDateRange, idx) in recentMonthDateRanges"
@click="changeDateFilter(recentDateRange)">
{{ recentDateRange.displayName }}
<span class="text-truncate">{{ recentDateRange.displayName }}</span>
</v-tab>
</v-tabs>
</div>
<v-window class="d-flex flex-grow-1 ml-md-5 disable-tab-transition w-100-window-container" v-model="activeTab">
</v-navigation-drawer>
<v-main>
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container" v-model="activeTab">
<v-window-item value="transactionPage">
<v-card variant="flat">
<v-card variant="flat" min-height="830">
<template #title>
<div class="transaction-list-title d-flex align-center text-no-wrap">
<div class="title-and-toolbar d-flex align-center text-no-wrap">
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
:ripple="false" :icon="true" @click="showNav = !showNav">
<v-icon :icon="icons.menu" size="24" />
</v-btn>
<span>{{ $t('Transaction List') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
:disabled="loading || !canAddTransaction" @click="add">{{ $t('Add') }}</v-btn>
@@ -75,11 +60,11 @@
<div class="transaction-list-datetime-range d-flex align-center">
<span class="text-body-1">{{ $t('Date Range') }}</span>
<span class="text-body-1 transaction-list-datetime-range-text ml-2">
<span v-if="!this.query.minTime && !this.query.maxTime">{{ $t('All') }}</span>
<span v-else-if="this.query.minTime || this.query.maxTime">{{ `${queryMinTime} - ${queryMaxTime}` }}</span>
<span class="text-sm" v-if="!this.query.minTime && !this.query.maxTime">{{ $t('All') }}</span>
<span class="text-sm" v-else-if="this.query.minTime || this.query.maxTime">{{ `${queryMinTime} - ${queryMaxTime}` }}</span>
</span>
<v-spacer/>
<div class="transaction-list-total-amount-text d-flex align-center" v-if="showTotalAmountInTransactionListPage && currentMonthTotalAmount">
<div class="skeleton-no-margin d-flex align-center" v-if="showTotalAmountInTransactionListPage && currentMonthTotalAmount">
<span class="ml-2 text-subtitle-1">{{ $t('Total Income') }}</span>
<span class="text-income ml-2" v-if="loading">
<v-skeleton-loader type="text" style="width: 60px" :loading="true"></v-skeleton-loader>
@@ -316,7 +301,8 @@
</v-card>
</v-window-item>
</v-window>
</div>
</v-main>
</v-layout>
</v-card>
</v-col>
</v-row>
@@ -332,6 +318,8 @@
</template>
<script>
import { useDisplay } from 'vuetify';
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js';
@@ -370,6 +358,7 @@ import {
mdiCheck,
mdiTextBoxCheckOutline,
mdiRefresh,
mdiMenu,
mdiMenuDown,
mdiPencilBoxOutline,
mdiArrowRight,
@@ -387,6 +376,8 @@ export default {
'initAccountId'
],
data() {
const { mdAndUp } = useDisplay();
return {
loading: true,
updating: false,
@@ -396,6 +387,8 @@ export default {
searchKeyword: '',
currentPageTransactions: [],
totalPageCount: 1,
alwaysShowNav: mdAndUp.value,
showNav: mdAndUp.value,
showCustomDateRangeDialog: false,
transactionRemoving: {},
icons: {
@@ -403,6 +396,7 @@ export default {
check: mdiCheck,
all: mdiTextBoxCheckOutline,
refresh: mdiRefresh,
menu: mdiMenu,
dropdownMenu: mdiMenuDown,
modifyBalance: mdiPencilBoxOutline,
arrowRight: mdiArrowRight,
@@ -577,6 +571,22 @@ export default {
accountId: this.initAccountId
});
},
setup() {
const display = useDisplay();
return {
display: display
};
},
watch: {
'display.mdAndUp.value': function (newValue) {
this.alwaysShowNav = newValue;
if (!this.showNav) {
this.showNav = newValue;
}
}
},
beforeRouteUpdate(to) {
if (to.query) {
this.init({
@@ -707,10 +717,6 @@ export default {
this.$router.push(this.getFilterLinkUrl());
},
changeTypeFilter(type) {
if (this.query.type === type) {
return;
}
let removeCategoryFilter = false;
if (type && this.query.categoryId) {
@@ -888,42 +894,24 @@ export default {
<style>
.transaction-keyword-filter .v-input--density-compact {
--v-input-control-height: 36px;
--v-input-padding-top: 5px;
--v-input-padding-bottom: 5px;
--v-input-control-height: 36px !important;
--v-input-padding-top: 5px !important;
--v-input-padding-bottom: 5px !important;
--v-input-chips-margin-top: 0px !important;
--v-input-chips-margin-bottom: 0px !important;
inline-size: 20rem;
}
.transaction-type-buttons .v-btn:not(:first-child) {
border-top-left-radius: inherit;
border-top-right-radius: inherit;
}
.transaction-type-buttons .v-btn:not(:last-child) {
border-bottom: 0;
border-bottom-left-radius: inherit;
border-bottom-right-radius: inherit;
}
.transaction-list-title {
overflow-x: auto;
white-space: nowrap;
}
.transaction-list-datetime-range {
height: 28px;
overflow-x: auto;
white-space: nowrap;
min-height: 28px;
flex-wrap: wrap;
row-gap: 1rem;
}
.transaction-list-datetime-range .transaction-list-datetime-range-text {
color: rgba(var(--v-theme-on-background), var(--v-medium-emphasis-opacity)) !important;
}
.transaction-list-total-amount-text .v-skeleton-loader__text {
margin: 0;
}
.v-table.transaction-table .transaction-list-row-date > td {
height: 40px !important;
}