desktop version supports rtl

This commit is contained in:
MaysWind
2025-08-18 00:45:26 +08:00
parent 4eff3a337f
commit c00770201b
57 changed files with 502 additions and 371 deletions

View File

@@ -76,8 +76,13 @@
"vue-tsc": "^2.2.10"
},
"browserslist": [
"> 1%",
"last 2 versions",
"last 5 Chrome versions",
"last 5 Firefox versions",
"last 5 Safari versions",
"last 5 Edge versions",
"last 5 ChromeAndroid versions",
"last 5 iOS versions",
"not IE <= 11",
"not dead"
]
}

View File

@@ -1,5 +1,8 @@
module.exports = {
plugins: {
'autoprefixer': {
logical: false
},
'postcss-preset-env': {},
},
};

View File

@@ -7,7 +7,7 @@
<v-tooltip activator="parent">{{ tt('Click to close') }}</v-tooltip>
<div class="d-inline-flex">
<img alt="logo" class="notification-logo" :src="APPLICATION_LOGO_PATH" />
<span class="ml-2">{{ tt('global.app.title') }}</span>
<span class="ms-2">{{ tt('global.app.title') }}</span>
</div>
<div>
{{ currentNotificationContent }}

View File

@@ -307,8 +307,8 @@ init(props.length, props.modelValue);
.pin-code-input input {
text-align: center;
padding-left: 10px;
padding-right: 10px;
padding-inline-start: 10px;
padding-inline-end: 10px;
width: 100%;
height: var(--ebk-pin-code-input-height) !important;
}

View File

@@ -13,6 +13,7 @@ import { type CommonAccountBalanceTrendsChartProps, useAccountBalanceTrendsChart
import { useUserStore } from '@/stores/user.ts';
import type { NameValue } from '@/core/base.ts';
import { TextDirection } from '@/core/text.ts';
import type { ColorValue } from '@/core/color.ts';
import { ThemeType } from '@/core/theme.ts';
import { AccountBalanceTrendChartType } from '@/core/statistics.ts';
@@ -47,11 +48,12 @@ interface AccountBalanceTrendsChartDataItem {
const props = defineProps<DesktopAccountBalanceTrendsChartProps>();
const theme = useTheme();
const { tt, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
const { tt, getCurrentLanguageTextDirection, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
const { allDataItems, allDisplayDateRanges } = useAccountBalanceTrendsChartBase(props);
const userStore = useUserStore();
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const allSeries = computed<AccountBalanceTrendsChartDataItem[]>(() => {
@@ -203,7 +205,7 @@ const chartOptions = computed<object>(() => {
for (let i = 0; i < displayItems.length; i++) {
tooltip += `<div><span class="chart-pointer" style="background-color: #${DEFAULT_CHART_COLORS[i]}"></span>`
+ `<span>${displayItems[i].name}</span><span style="margin-left: 20px; float: right">${displayItems[i].value}</span><br/>`
+ `<span>${displayItems[i].name}</span><span class="ms-5" style="float: inline-end">${displayItems[i].value}</span><br/>`
+ `</div>`;
}
@@ -214,7 +216,7 @@ const chartOptions = computed<object>(() => {
return `${params[0].name}<br/>`
+ '<div><span class="chart-pointer" style="background-color: #' + DEFAULT_CHART_COLORS[0] + '"></span>'
+ `<span>${props.legendName}</span><span style="margin-left: 20px; float: right">${value}</span><br/>`
+ `<span>${props.legendName}</span><span class="ms-5" style="float: inline-end">${value}</span><br/>`
+ '</div>';
}
}
@@ -226,7 +228,8 @@ const chartOptions = computed<object>(() => {
xAxis: [
{
type: 'category',
data: allDisplayDateRanges.value
data: allDisplayDateRanges.value,
inverse: textDirection.value === TextDirection.RTL
}
],
yAxis: [

View File

@@ -13,7 +13,7 @@
<div class="text-no-wrap" v-if="currency && appendText">{{ appendText }}</div>
<v-tooltip :text="tt('Enter formula mode')">
<template v-slot:activator="{ props }">
<v-icon class="ml-2" :icon="mdiCalculatorVariantOutline"
<v-icon class="ms-2" :icon="mdiCalculatorVariantOutline"
@keydown.enter="enterFormulaMode" @keydown.space="enterFormulaMode" @click="enterFormulaMode"
v-bind="props" v-if="enableFormula && !formulaMode"></v-icon>
</template>
@@ -34,14 +34,14 @@
<div class="text-no-wrap" v-if="currency && appendText">{{ appendText }}</div>
<v-tooltip :text="tt('Calculate formula result')">
<template v-slot:activator="{ props }">
<v-icon class="ml-2" color="primary" :icon="mdiCheck"
<v-icon class="ms-2" color="primary" :icon="mdiCheck"
@click="calculateFormula" v-bind="props"
v-if="formulaMode"></v-icon>
</template>
</v-tooltip>
<v-tooltip :text="tt('Exit formula mode')">
<template v-slot:activator="{ props }">
<v-icon class="ml-2" color="secondary" :icon="mdiClose"
<v-icon class="ms-2" color="secondary" :icon="mdiClose"
@click="exitFormulaMode" v-bind="props"
v-if="formulaMode"></v-icon>
</template>
@@ -379,6 +379,6 @@ watch(currentValue, (newValue) => {
}
.text-field-with-colored-label.has-pretend-text .v-field__input {
padding-left: 0.5rem;
padding-inline-start: 0.5rem;
}
</style>

View File

@@ -16,7 +16,7 @@
</template>
<template #no-data>
<div class="color-select-dropdown" ref="dropdownMenu">
<div class="color-select-dropdown px-2" ref="dropdownMenu">
<div class="color-item" :class="{ 'row-has-selected-item': hasSelectedIcon(row) }"
:style="`grid-template-columns: repeat(${itemPerRow}, minmax(0, 1fr));`"
:key="idx" v-for="(row, idx) in allColorRows">
@@ -26,7 +26,9 @@
:icon="mdiSquareRounded" :color="getFinalColor(colorInfo.color)"
v-if="!modelValue || modelValue !== colorInfo.color" />
<v-badge class="right-bottom-icon" color="primary"
location="bottom right" offset-x="8" offset-y="8" :icon="mdiCheck"
offset-x="8" offset-y="8"
:location="`bottom ${textDirection === TextDirection.LTR ? 'right' : 'left'}`"
:icon="mdiCheck"
v-if="modelValue && modelValue === colorInfo.color">
<v-icon class="ma-2" size="28" :icon="mdiSquareRounded" :color="getFinalColor(colorInfo.color)" />
</v-badge>
@@ -41,6 +43,9 @@
<script setup lang="ts">
import { ref, computed, useTemplateRef, nextTick } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import { TextDirection } from '@/core/text.ts';
import type { ColorValue, ColorInfo } from '@/core/color.ts';
import { DEFAULT_ICON_COLOR } from '@/consts/color.ts';
import { arrayContainsFieldValue } from '@/lib/common.ts';
@@ -64,9 +69,12 @@ const emit = defineEmits<{
(e: 'update:modelValue', value: ColorValue): void;
}>();
const { getCurrentLanguageTextDirection } = useI18n();
const dropdownMenu = useTemplateRef<HTMLElement>('dropdownMenu');
const itemPerRow = ref<number>(props.columnCount || 7);
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
const allColorRows = computed<ColorInfo[][]>(() => getColorsInRows(props.allColorInfos, itemPerRow.value));
const color = computed<ColorValue>({
@@ -98,11 +106,6 @@ function onMenuStateChanged(state: boolean): void {
</script>
<style>
.color-select-dropdown {
padding-left: 8px;
padding-right: 8px;
}
.color-select-dropdown .color-item {
display: grid;
}

View File

@@ -350,10 +350,10 @@ function onKeyDown(type: string, e: KeyboardEvent): void {
}
.date-time-select-time-picker-container .v-autocomplete.v-input--density-compact .v-field__append-inner .v-autocomplete__menu-icon {
margin-left: 0;
margin-inline-start: 0;
}
.date-time-select-time-picker-container .v-autocomplete .v-field--appended {
padding-right: 8px;
padding-inline-end: 8px;
}
</style>

View File

@@ -16,7 +16,7 @@
</template>
<template #no-data>
<div class="icon-select-dropdown" ref="dropdownMenu">
<div class="icon-select-dropdown px-2" ref="dropdownMenu">
<div class="icon-item" :class="{ 'row-has-selected-item': hasSelectedIcon(row) }"
:style="`grid-template-columns: repeat(${itemPerRow}, minmax(0, 1fr));`"
:key="idx" v-for="(row, idx) in allIconRows">
@@ -24,7 +24,9 @@
<div class="cursor-pointer" @click="icon = iconInfo.id">
<ItemIcon class="ma-2" icon-type="fixed" :icon-id="iconInfo.icon" :color="color" v-if="!modelValue || modelValue !== iconInfo.id" />
<v-badge class="right-bottom-icon" color="primary"
location="bottom right" offset-x="8" offset-y="10" :icon="mdiCheck"
offset-x="8" offset-y="10"
:location="`bottom ${textDirection === TextDirection.LTR ? 'right' : 'left'}`"
:icon="mdiCheck"
v-if="modelValue && modelValue === iconInfo.id">
<ItemIcon class="ma-2" icon-type="fixed" :icon-id="iconInfo.icon" :color="color" />
</v-badge>
@@ -39,6 +41,9 @@
<script setup lang="ts">
import { ref, computed, useTemplateRef, nextTick } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import { TextDirection } from '@/core/text.ts';
import type { ColorValue } from '@/core/color.ts';
import type { IconInfo, IconInfoWithId } from '@/core/icon.ts';
import { arrayContainsFieldValue } from '@/lib/common.ts';
@@ -63,9 +68,12 @@ const emit = defineEmits<{
(e: 'update:modelValue', value: string): void;
}>();
const { getCurrentLanguageTextDirection } = useI18n();
const dropdownMenu = useTemplateRef<HTMLElement>('dropdownMenu');
const itemPerRow = ref<number>(props.columnCount || 7);
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
const allIconRows = computed<IconInfoWithId[][]>(() => getIconsInRows(props.allIconInfos, itemPerRow.value));
const icon = computed<string>({
@@ -89,11 +97,6 @@ function onMenuStateChanged(state: boolean): void {
</script>
<style>
.icon-select-dropdown {
padding-left: 8px;
padding-right: 8px;
}
.icon-select-dropdown .icon-item {
display: grid;
}

View File

@@ -2,9 +2,9 @@
<i class="item-icon" :class="classes" :style="style" v-if="!hiddenStatus">
<slot></slot>
</i>
<v-badge class="right-bottom-icon" color="secondary"
location="bottom right" offset-y="4" :icon="mdiEyeOffOutline"
v-if="hiddenStatus">
<v-badge class="right-bottom-icon" color="secondary" offset-y="4"
:location="`bottom ${textDirection === TextDirection.LTR ? 'right' : 'left'}`"
:icon="mdiEyeOffOutline" v-if="hiddenStatus">
<i class="item-icon" :class="classes" :style="style">
<slot></slot>
</i>
@@ -15,6 +15,10 @@
import { computed } from 'vue';
import { type CommonIconProps, useItemIconBase } from '@/components/base/ItemIconBase.ts';
import { useI18n } from '@/locales/helpers.ts';
import { TextDirection } from '@/core/text.ts';
import {
mdiEyeOffOutline
} from '@mdi/js';
@@ -25,8 +29,12 @@ interface DesktopItemIconProps extends CommonIconProps {
}
const props = defineProps<DesktopItemIconProps>();
const { getCurrentLanguageTextDirection } = useI18n();
const { style, getAccountIcon, getCategoryIcon } = useItemIconBase(props);
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
const classes = computed<string>(() => {
let allClasses = props.class ? (props.class + ' ') : '';

View File

@@ -14,6 +14,7 @@ import { type CommonMonthlyTrendsChartProps, type MonthlyTrendsBarChartClickEven
import { useUserStore } from '@/stores/user.ts';
import { TextDirection } from '@/core/text.ts';
import { type Year1BasedMonth, DateRangeScene } from '@/core/datetime.ts';
import type { ColorValue } from '@/core/color.ts';
import { ThemeType } from '@/core/theme.ts';
@@ -71,7 +72,9 @@ const emit = defineEmits<{
const theme = useTheme();
const { tt,
const {
tt,
getCurrentLanguageTextDirection,
formatUnixTimeToShortYear,
formatYearQuarter,
formatUnixTimeToShortYearMonth,
@@ -86,6 +89,7 @@ const userStore = useUserStore();
const selectedLegends = ref<Record<string, boolean>>({});
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
const itemsMap = computed<Record<string, Record<string, unknown>>>(() => {
@@ -327,7 +331,7 @@ const chartOptions = computed<object>(() => {
if (displayItems.length === 1 || item.totalAmount !== 0) {
const value = formatAmountToLocalizedNumeralsWithCurrency(item.totalAmount, props.defaultCurrency);
tooltip += '<div><span class="chart-pointer" style="background-color: ' + item.color + '"></span>';
tooltip += `<span>${item.name}</span><span style="margin-left: 20px; float: right">${value}</span><br/>`;
tooltip += `<span>${item.name}</span><span class="ms-5" style="float: inline-end">${value}</span><br/>`;
tooltip += '</div>';
}
}
@@ -336,7 +340,7 @@ const chartOptions = computed<object>(() => {
const displayTotalAmount = formatAmountToLocalizedNumeralsWithCurrency(totalAmount, props.defaultCurrency);
tooltip = '<div style="border-bottom: ' + (isDarkMode.value ? '#eee' : '#333') + ' dashed 1px">'
+ '<span class="chart-pointer" style="background-color: ' + (isDarkMode.value ? '#eee' : '#333') + '"></span>'
+ `<span>${tt('Total Amount')}</span><span style="margin-left: 20px; float: right">${displayTotalAmount}</span><br/>`
+ `<span>${tt('Total Amount')}</span><span class="ms-5" style="float: inline-end">${displayTotalAmount}</span><br/>`
+ '</div>' + tooltip;
}
@@ -365,7 +369,8 @@ const chartOptions = computed<object>(() => {
xAxis: [
{
type: 'category',
data: allDisplayDateRanges.value
data: allDisplayDateRanges.value,
inverse: textDirection.value === TextDirection.RTL
}
],
yAxis: [

View File

@@ -143,13 +143,13 @@ const chartOptions = computed<object>(() => {
let tooltip = `<div><span class="chart-pointer" style="background-color: ${params.color}"></span>`;
if (name) {
tooltip += `<span>${name}</span><br/>`;
tooltip += `<div class="d-inline-flex">${name}</div><br/>`;
}
if (props.showValue) {
tooltip += `<span>${value} (${percent})</span>`;
tooltip += `<div class="d-inline-flex"><span>${value}</span><span class="ms-1">(${percent})</span></div>`;
} else {
tooltip += `<span>${percent}</span>`;
tooltip += `<div class="d-inline-flex">${percent}</div>`;
}
tooltip += '</div>';

View File

@@ -34,7 +34,7 @@
:class="{ 'frequency-value-selected v-list-item--active text-primary': isFrequencyValueSelected(weekDay.type) }"
v-for="weekDay in allWeekDays">
<template #prepend="{ isActive }">
<v-checkbox density="compact" class="mr-1" :model-value="isActive"></v-checkbox>
<v-checkbox density="compact" class="me-1" :model-value="isActive"></v-checkbox>
</template>
</v-list-item>
</v-list>
@@ -44,7 +44,7 @@
:class="{ 'frequency-value-selected v-list-item--active text-primary': isFrequencyValueSelected(monthDay.day) }"
v-for="monthDay in allAvailableMonthDays">
<template #prepend="{ isActive }">
<v-checkbox density="compact" class="mr-1" :model-value="isActive"></v-checkbox>
<v-checkbox density="compact" class="me-1" :model-value="isActive"></v-checkbox>
</template>
</v-list-item>
</v-list>

View File

@@ -14,12 +14,12 @@
<template #selection>
<div class="d-flex align-center text-truncate cursor-pointer">
<span class="text-truncate" v-if="customSelectionPrimaryText">{{ customSelectionPrimaryText }}</span>
<v-icon class="disabled" :icon="mdiChevronRight" size="23" v-if="customSelectionPrimaryText && customSelectionSecondaryText" />
<v-icon class="icon-with-direction disabled" :icon="mdiChevronRight" size="23" v-if="customSelectionPrimaryText && customSelectionSecondaryText" />
<span class="text-truncate" v-if="customSelectionPrimaryText && customSelectionSecondaryText">{{ customSelectionSecondaryText }}</span>
<span class="text-truncate" v-if="!customSelectionPrimaryText && !selectedPrimaryItem && !selectedSecondaryItem">{{ noSelectionText }}</span>
<span class="text-truncate" v-if="!customSelectionPrimaryText && showSelectionPrimaryText && selectedPrimaryItem">{{ selectionPrimaryItemText }}</span>
<v-icon class="disabled" :icon="mdiChevronRight" size="23" v-if="!customSelectionPrimaryText && showSelectionPrimaryText && selectedPrimaryItem && selectedSecondaryItem" />
<ItemIcon class="mr-2" icon-type="account" size="21.5px"
<v-icon class="icon-with-direction disabled" :icon="mdiChevronRight" size="23" v-if="!customSelectionPrimaryText && showSelectionPrimaryText && selectedPrimaryItem && selectedSecondaryItem" />
<ItemIcon class="me-2" icon-type="account" size="21.5px"
:icon-id="selectedSecondaryItem && secondaryIconField ? (selectedSecondaryItem as Record<string, unknown>)[secondaryIconField] : null"
:color="selectedSecondaryItem && secondaryColorField ? (selectedSecondaryItem as Record<string, unknown>)[secondaryColorField] : null"
v-if="!customSelectionPrimaryText && selectedSecondaryItem && showSelectionSecondaryIcon" />
@@ -47,7 +47,7 @@
v-for="item in filteredItems"
@click="onPrimaryItemClicked(item)">
<template #prepend>
<ItemIcon class="mr-2" :icon-type="primaryIconType"
<ItemIcon class="me-2" :icon-type="primaryIconType"
:icon-id="primaryIconField ? (item as Record<string, unknown>)[primaryIconField] : undefined" :color="primaryColorField ? (item as Record<string, unknown>)[primaryColorField] : undefined"></ItemIcon>
</template>
<template #title>
@@ -66,7 +66,7 @@
v-for="subItem in filteredSubItems"
@click="onSecondaryItemClicked(subItem)">
<template #prepend>
<ItemIcon class="mr-2" :icon-type="secondaryIconType"
<ItemIcon class="me-2" :icon-type="secondaryIconType"
:icon-id="secondaryIconField ? subItem[secondaryIconField] : undefined" :color="secondaryColorField ? subItem[secondaryColorField] : undefined"></ItemIcon>
</template>
<template #title>

4
src/core/text.ts Normal file
View File

@@ -0,0 +1,4 @@
export enum TextDirection {
LTR = 'ltr',
RTL = 'rtl'
}

View File

@@ -72,7 +72,7 @@ import draggable from 'vuedraggable';
import router from '@/router/desktop.ts';
import { DecimalSeparator } from '@/core/numeral.ts';
import { getI18nOptions } from '@/locales/helpers.ts';
import { getI18nOptions, getRtlLocales } from '@/locales/helpers.ts';
import PinCodeInput from '@/components/common/PinCodeInput.vue';
import MapView from '@/components/common/MapView.vue';
@@ -433,6 +433,7 @@ const vuetify = createVuetify({
}
},
locale: {
rtl: getRtlLocales(),
adapter: ((i18nGlobal: Composer) => {
const instance: LocaleInstance = {
name: 'ezBookkeeping i18n',

View File

@@ -4,7 +4,16 @@ import 'moment-timezone/moment-timezone-utils';
import type { PartialRecord, NameValue, TypeAndName, TypeAndDisplayName, LocalizedSwitchOption } from '@/core/base.ts';
import { type LanguageInfo, type LanguageOption, ALL_LANGUAGES, DEFAULT_LANGUAGE } from '@/locales/index.ts';
import {
type LanguageInfo,
type LanguageOption,
ALL_LANGUAGES,
DEFAULT_LANGUAGE
} from '@/locales/index.ts';
import {
TextDirection
} from '@/core/text.ts';
import {
type DateFormat,
@@ -222,6 +231,24 @@ export function getI18nOptions(): object {
};
}
export function getRtlLocales(): Record<string, boolean> {
const rtlLocales: Record<string, boolean> = {};
for (const languageKey in ALL_LANGUAGES) {
if (!Object.prototype.hasOwnProperty.call(ALL_LANGUAGES, languageKey)) {
continue;
}
const languageInfo = ALL_LANGUAGES[languageKey];
if (languageInfo.textDirection === TextDirection.RTL) {
rtlLocales[languageKey] = true;
}
}
return rtlLocales;
}
export function useI18n() {
const { t, locale } = useVueI18n();
@@ -721,6 +748,11 @@ export function useI18n() {
return currentLanguageInfo.displayName;
}
function getCurrentLanguageTextDirection(): TextDirection {
const currentLanguageInfo = getCurrentLanguageInfo();
return currentLanguageInfo.textDirection;
}
function getDefaultCurrency(): string {
return t('default.currency');
}
@@ -1894,7 +1926,9 @@ export function useI18n() {
logger.info(`No specified language, use browser default language ${languageKey}`);
}
if (!getLanguageInfo(languageKey)) {
const languageInfo = getLanguageInfo(languageKey);
if (!languageInfo) {
languageKey = getDefaultLanguage();
logger.warn(`Not found language ${languageKey}, use browser default language ${languageKey}`);
}
@@ -1925,6 +1959,12 @@ export function useI18n() {
services.setLocale(languageKey);
document.querySelector('html')?.setAttribute('lang', languageKey);
if (languageInfo && languageInfo.textDirection === TextDirection.LTR) {
document.querySelector('html')?.removeAttribute('dir');
} else if (languageInfo && languageInfo.textDirection === TextDirection.RTL) {
document.querySelector('html')?.setAttribute('dir', 'rtl');
}
const defaultCurrency = getDefaultCurrency();
const defaultFirstDayOfWeekName = getDefaultFirstDayOfWeek();
let defaultFirstDayOfWeek = WeekDay.DefaultFirstDay.type;
@@ -1933,10 +1973,12 @@ export function useI18n() {
defaultFirstDayOfWeek = (WeekDay.parse(defaultFirstDayOfWeekName) as WeekDay).type;
}
return {
const localeDefaultSettings: LocaleDefaultSettings = {
currency: defaultCurrency,
firstDayOfWeek: defaultFirstDayOfWeek
};
return localeDefaultSettings;
}
function setTimeZone(timezone: string): void {
@@ -1987,6 +2029,7 @@ export function useI18n() {
getCurrentLanguageTag,
getCurrentLanguageInfo,
getCurrentLanguageDisplayName,
getCurrentLanguageTextDirection,
// get localization default type
getDefaultCurrency,
getDefaultFirstDayOfWeek,

View File

@@ -11,12 +11,14 @@ import zhHans from './zh_Hans.json';
import zhHant from './zh_Hant.json';
import ptBR from './pt_BR.json';
import { TextDirection } from '@/core/text.ts';
export interface LanguageInfo {
readonly name: string;
readonly displayName: string;
readonly alternativeLanguageTag: string;
readonly aliases?: string[];
readonly textDirection: TextDirection;
readonly content: object;
}
@@ -34,60 +36,70 @@ export const ALL_LANGUAGES: Record<string, LanguageInfo> = {
name: 'German',
displayName: 'Deutsch',
alternativeLanguageTag: 'de-DE',
textDirection: TextDirection.LTR,
content: de
},
'en': {
name: 'English',
displayName: 'English',
alternativeLanguageTag: 'en-US',
textDirection: TextDirection.LTR,
content: en
},
'es': {
name: 'Spanish',
displayName: 'Español',
alternativeLanguageTag: 'es-ES',
textDirection: TextDirection.LTR,
content: es
},
'it': {
name: 'Italian',
displayName: 'Italiano',
alternativeLanguageTag: 'it-IT',
textDirection: TextDirection.LTR,
content: it
},
'ja': {
name: 'Japanese',
displayName: '日本語',
alternativeLanguageTag: 'ja-JP',
textDirection: TextDirection.LTR,
content: ja
},
'nl': {
name: 'Dutch',
displayName: 'Nederlands',
alternativeLanguageTag: 'nl-NL',
textDirection: TextDirection.LTR,
content: nl
},
'pt-BR': {
name: 'Portuguese (Brazil)',
displayName: 'Português (Brasil)',
alternativeLanguageTag: 'pt-BR',
textDirection: TextDirection.LTR,
content: ptBR
},
'ru': {
name: 'Russian',
displayName: 'Русский',
alternativeLanguageTag: 'ru-RU',
textDirection: TextDirection.LTR,
content: ru
},
'uk': {
name: 'Ukrainian',
displayName: 'Українська',
alternativeLanguageTag: 'uk-UA',
textDirection: TextDirection.LTR,
content: uk
},
'vi': {
name: 'Vietnamese',
displayName: 'Tiếng Việt',
alternativeLanguageTag: 'vi-VN',
textDirection: TextDirection.LTR,
content: vi
},
'zh-Hans': {
@@ -95,6 +107,7 @@ export const ALL_LANGUAGES: Record<string, LanguageInfo> = {
displayName: '中文 (简体)',
alternativeLanguageTag: 'zh-CN',
aliases: ['zh-CHS', 'zh-CN', 'zh-SG'],
textDirection: TextDirection.LTR,
content: zhHans
},
'zh-Hant': {
@@ -102,6 +115,7 @@ export const ALL_LANGUAGES: Record<string, LanguageInfo> = {
displayName: '中文 (繁體)',
alternativeLanguageTag: 'zh-TW',
aliases: ['zh-CHT', 'zh-TW', 'zh-HK', 'zh-MO'],
textDirection: TextDirection.LTR,
content: zhHant
},
};

View File

@@ -40,8 +40,8 @@ input[type=number] {
}
@media (min-width: 600px) {
.text-right-sm {
text-align: right !important;
.text-end-sm {
text-align: end !important;
}
}
@@ -131,7 +131,7 @@ input[type=number] {
.chart-pointer {
display: inline-block;
margin-right: 5px;
margin-inline-end: 5px;
border-radius: 10px;
width: 10px;
height: 10px;
@@ -142,7 +142,11 @@ input[type=number] {
}
.bidirectional-switch.v-input--horizontal .v-input__prepend {
margin-right: 10px; /* same as the padding-left of `.v-switch .v-label` */
margin-inline-end: 10px; /* same as the padding-left of `.v-switch .v-label` */
}
html[dir="rtl"] .bidirectional-switch {
transform: scaleX(-1);
}
.code-container {
@@ -276,6 +280,20 @@ input[type=number] {
margin: 0;
}
html[dir="rtl"] .v-btn.button-icon-with-direction > .v-btn__content > .v-icon > .v-icon__svg,
html[dir="rtl"] .v-btn.button-icon-with-direction > .v-btn__prepend > .v-icon > .v-icon__svg,
html[dir="rtl"] .v-btn.button-icon-with-direction > .v-btn__append > .v-icon > .v-icon__svg {
transform: scaleX(-1);
}
html[dir="rtl"] .v-icon.icon-with-direction > .v-icon__svg {
transform: scaleX(-1);
}
html[dir="rtl"] .v-img.img-with-direction > img {
transform: scaleX(-1);
}
/** Common class for replacing the default style of Materio **/
.v-application,
.text-body-1,
@@ -415,3 +433,7 @@ body .v-btn-group {
.dp__main .dp__calendar .dp__calendar_item > .dp__cell_inner {
width: 100%;
}
html[dir="rtl"] .dp__main .dp__btn.dp--arrow-btn-nav {
transform: scaleX(-1);
}

View File

@@ -6,7 +6,7 @@
<div class="d-flex align-center">
<span>{{ tt('global.app.title') }}</span>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" @click="refreshBrowserCache"
class="ms-2" :icon="true" @click="refreshBrowserCache"
v-if="!clientVersionMatchServerVersion">
<v-icon :icon="mdiWebRefresh" size="24" />
<v-tooltip activator="parent">{{ tt('Refresh Browser Cache') }}</v-tooltip>

View File

@@ -9,13 +9,13 @@
<v-row no-gutters class="auth-wrapper">
<v-col cols="12" md="8" class="d-none d-md-flex align-center justify-center position-relative">
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
<v-img src="img/desktop/background.svg"/>
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
</div>
<div class="d-flex auth-img-footer" v-if="isDarkMode">
<v-img src="img/desktop/background-dark.svg"/>
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
</div>
<div class="d-flex align-center justify-center w-100 pt-10">
<v-img max-width="600px" src="img/desktop/people4.svg"/>
<v-img class="img-with-direction" max-width="600px" src="img/desktop/people4.svg"/>
</div>
</v-col>
<v-col cols="12" md="4" class="auth-card d-flex flex-column">
@@ -45,14 +45,14 @@
<v-col cols="12">
<v-btn block type="submit" :disabled="!email || requesting" @click="requestResetPassword">
{{ tt('Send Reset Link') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="requesting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="requesting"></v-progress-circular>
</v-btn>
</v-col>
<v-col cols="12">
<router-link class="d-flex align-center justify-center" to="/login"
:class="{ 'disabled': requesting }">
<v-icon :icon="mdiChevronLeft"/>
<v-icon class="icon-with-direction" :icon="mdiChevronLeft"/>
<span>{{ tt('Back to login page') }}</span>
</router-link>
</v-col>
@@ -99,12 +99,13 @@ import { useI18n } from '@/locales/helpers.ts';
import { useRootStore } from '@/stores/index.ts';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import { ThemeType } from '@/core/theme.ts';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import { getClientDisplayVersion } from '@/lib/version.ts';
import {
mdiChevronLeft,
mdiChevronLeft
} from '@mdi/js';
type SnackBarType = InstanceType<typeof SnackBar>;

View File

@@ -10,7 +10,7 @@
<span style="font-size: 1rem">{{ tt('Expense') }}</span>
</div>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :loading="loadingOverview" @click="reload(true)">
class="ms-2" :icon="true" :loading="loadingOverview" @click="reload(true)">
<template #loader>
<v-progress-circular indeterminate size="20"/>
</template>
@@ -24,19 +24,21 @@
<h4 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 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"
<v-btn class="ms-1" density="compact" color="default" variant="text"
:icon="true" @click="showAmountInHomePage = !showAmountInHomePage">
<v-icon :icon="showAmountInHomePage ? mdiEyeOffOutline : mdiEyeOutline" size="20" />
</v-btn>
</h4>
<div class="mt-1 mb-3">
<span class="mr-2">{{ tt('Monthly income') }}</span>
<span class="me-2">{{ tt('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 skeleton-no-margin mt-2" 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">{{ tt('View Details') }}</v-btn>
<v-img class="overview-card-background" src="img/desktop/card-background.png"/>
<v-img class="overview-card-background-image" width="116px" src="img/desktop/document.svg"/>
<v-img class="overview-card-background img-with-direction"
src="img/desktop/card-background.png"/>
<v-img class="overview-card-background-image img-with-direction"
width="116px" src="img/desktop/document.svg"/>
</v-card-text>
</v-card>
</v-col>

View File

@@ -9,13 +9,13 @@
<v-row no-gutters class="auth-wrapper">
<v-col cols="12" md="8" class="d-none d-md-flex align-center justify-center position-relative">
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
<v-img src="img/desktop/background.svg"/>
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
</div>
<div class="d-flex auth-img-footer" v-if="isDarkMode">
<v-img src="img/desktop/background-dark.svg"/>
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
</div>
<div class="d-flex align-center justify-center w-100 pt-10">
<v-img max-width="600px" src="img/desktop/people1.svg"/>
<v-img class="img-with-direction" max-width="600px" src="img/desktop/people1.svg"/>
</div>
</v-col>
<v-col cols="12" md="4" class="auth-card d-flex flex-column">
@@ -102,12 +102,12 @@
<v-btn block :disabled="inputIsEmpty || logining || verifying"
@click="login" v-if="!show2faInput">
{{ tt('Log In') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="logining"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="logining"></v-progress-circular>
</v-btn>
<v-btn block :disabled="twoFAInputIsEmpty || logining || verifying"
@click="verify" v-else-if="show2faInput">
{{ tt('Continue') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="verifying"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="verifying"></v-progress-circular>
</v-btn>
</v-col>
@@ -165,9 +165,10 @@ import { useLoginPageBase } from '@/views/base/LoginPageBase.ts';
import { useRootStore } from '@/stores/index.ts';
import { ThemeType } from '@/core/theme.ts';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import { KnownErrorCode } from '@/consts/api.ts';
import { ThemeType } from '@/core/theme.ts';
import { isUserRegistrationEnabled, isUserForgetPasswordEnabled, isUserVerifyEmailEnabled } from '@/lib/server_settings.ts';
import {

View File

@@ -31,7 +31,7 @@
<v-icon class="nav-item-icon" :icon="mdiListBoxOutline"/>
<span class="nav-item-title d-inline-block">{{ tt('Transaction Details') }}</span>
<v-btn density="compact" color="secondary" variant="text" size="22"
class="ml-1" :icon="true" v-if="showAddTransactionButtonInDesktopNavbar"
class="ms-1" :icon="true" v-if="showAddTransactionButtonInDesktopNavbar"
@click="showAddDialogInTransactionListPage">
<v-icon :icon="mdiPlusCircle" size="22" />
<v-tooltip activator="parent">{{ tt('Add Transaction') }}</v-tooltip>
@@ -109,7 +109,7 @@
<div class="layout-navbar navbar-blur">
<div class="navbar-content-container">
<div class="d-flex h-100 align-center">
<v-btn class="ms-n3 mr-2 d-lg-none" color="default" variant="text"
<v-btn class="ms-n3 me-2 d-lg-none" color="default" variant="text"
:icon="true" @click="showVerticalOverlayMenu = true">
<v-icon :icon="mdiMenu" size="24" />
</v-btn>
@@ -152,7 +152,7 @@
</v-avatar>
</v-list-item-action>
</template>
<v-list-item-title class="ml-2 font-weight-semibold">
<v-list-item-title class="ms-2 font-weight-semibold">
{{ currentNickName }}
</v-list-item-title>
</v-list-item>

View File

@@ -9,13 +9,13 @@
<v-row no-gutters class="auth-wrapper">
<v-col cols="12" md="8" class="d-none d-md-flex align-center justify-center position-relative">
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
<v-img src="img/desktop/background.svg"/>
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
</div>
<div class="d-flex auth-img-footer" v-if="isDarkMode">
<v-img src="img/desktop/background-dark.svg"/>
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
</div>
<div class="d-flex align-center justify-center w-100 pt-10">
<v-img max-width="600px" src="img/desktop/people4.svg"/>
<v-img class="img-with-direction" max-width="600px" src="img/desktop/people4.svg"/>
</div>
</v-col>
<v-col cols="12" md="4" class="auth-card d-flex flex-column">
@@ -70,14 +70,14 @@
<v-col cols="12">
<v-btn block :disabled="!email || !newPassword || !confirmPassword || updating" @click="resetPassword">
{{ tt('Update Password') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="updating"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="updating"></v-progress-circular>
</v-btn>
</v-col>
<v-col cols="12">
<router-link class="d-flex align-center justify-center" to="/login"
:class="{ 'disabled': updating }">
<v-icon :icon="mdiChevronLeft"/>
<v-icon class="icon-with-direction" :icon="mdiChevronLeft"/>
<span>{{ tt('Back to login page') }}</span>
</router-link>
</v-col>
@@ -128,8 +128,9 @@ import { useI18n } from '@/locales/helpers.ts';
import { useRootStore } from '@/stores/index.ts';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import { ThemeType } from '@/core/theme.ts';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import { getClientDisplayVersion } from '@/lib/version.ts';
import {

View File

@@ -9,13 +9,13 @@
<v-row no-gutters class="auth-wrapper">
<v-col cols="12" md="4" class="d-none d-md-flex align-center justify-center position-relative">
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
<v-img src="img/desktop/background.svg"/>
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
</div>
<div class="d-flex auth-img-footer" v-if="isDarkMode">
<v-img src="img/desktop/background-dark.svg"/>
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
</div>
<div class="d-flex align-center justify-center w-100 pt-10">
<v-img max-width="320px" src="img/desktop/people2.svg"/>
<v-img class="img-with-direction" max-width="320px" src="img/desktop/people2.svg"/>
</div>
</v-col>
<v-col cols="12" md="8" class="auth-card d-flex align-center justify-center pa-10">
@@ -28,7 +28,7 @@
<h4 class="text-h4 mb-1">{{ tt('Basic Information') }}</h4>
<p class="text-sm mt-2 mb-5">
<span>{{ tt('Already have an account?') }}</span>
<router-link class="ml-1" to="/login">{{ tt('Click here to log in') }}</router-link>
<router-link class="ms-1" to="/login">{{ tt('Click here to log in') }}</router-link>
</p>
<v-row>
<v-col cols="12" md="6">
@@ -129,7 +129,7 @@
:label="tt('Use Preset Transaction Categories')"
v-model="usePresetCategories"/>
</v-col>
<v-col cols="12" sm="6" class="text-right-sm">
<v-col cols="12" sm="6" class="text-end-sm">
<language-select-button :disabled="submitting || navigateToHomePage"
:use-model-value="true" v-model="currentLocale" />
</v-col>
@@ -144,7 +144,7 @@
<v-expansion-panel :key="idx" v-for="(category, idx) in categories">
<v-expansion-panel-title class="py-0">
<ItemIcon icon-type="category" :icon-id="category.icon" :color="category.color"></ItemIcon>
<span class="ml-3">{{ category.name }}</span>
<span class="ms-3">{{ category.name }}</span>
</v-expansion-panel-title>
<v-expansion-panel-text v-if="category.subCategories.length">
<v-list rounded density="comfortable" class="pa-0">
@@ -154,7 +154,7 @@
<template #prepend>
<ItemIcon icon-type="category" :icon-id="subCategory.icon" :color="subCategory.color"></ItemIcon>
</template>
<span class="ml-3">{{ subCategory.name }}</span>
<span class="ms-3">{{ subCategory.name }}</span>
</v-list-item>
<v-divider v-if="subIdx !== category.subCategories.length - 1"/>
</template>
@@ -175,11 +175,12 @@
</v-window>
<div class="d-flex justify-sm-space-between gap-4 flex-wrap justify-center mt-5">
<v-btn :color="(currentStep === 'basicSetting' || currentStep === 'finalResult') ? 'default' : 'primary'"
<v-btn class="button-icon-with-direction"
:color="(currentStep === 'basicSetting' || currentStep === 'finalResult') ? 'default' : 'primary'"
:disabled="currentStep === 'basicSetting' || currentStep === 'finalResult' || submitting || navigateToHomePage"
:prepend-icon="mdiArrowLeft"
@click="switchToPreviousTab">{{ tt('Previous') }}</v-btn>
<v-btn color="primary"
<v-btn class="button-icon-with-direction" color="primary"
:disabled="submitting || navigateToHomePage"
:append-icon="mdiArrowRight"
@click="switchToNextTab"
@@ -190,9 +191,10 @@
@click="submit"
v-if="currentStep === 'presetCategories'">
{{ tt('Submit') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
</v-btn>
<v-btn :append-icon="mdiArrowRight"
<v-btn class="button-icon-with-direction"
:append-icon="mdiArrowRight"
@click="navigateToLogin"
v-if="currentStep === 'finalResult'">{{ tt('Continue') }}</v-btn>
</div>
@@ -385,6 +387,7 @@ function onSnackbarShowStateChanged(newValue: boolean): void {
<style>
.signup-preset-categories .v-expansion-panel-text__wrapper {
padding: 0 0 0 20px;
padding: 0 0 0 0;
padding-inline-start: 20px;
}
</style>

View File

@@ -9,13 +9,13 @@
<v-row no-gutters class="auth-wrapper">
<v-col cols="12" md="8" class="d-none d-md-flex align-center justify-center position-relative">
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
<v-img src="img/desktop/background.svg"/>
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
</div>
<div class="d-flex auth-img-footer" v-if="isDarkMode">
<v-img src="img/desktop/background-dark.svg"/>
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
</div>
<div class="d-flex align-center justify-center w-100 pt-10">
<v-img max-width="600px" src="img/desktop/people3.svg"/>
<v-img class="img-with-direction" max-width="600px" src="img/desktop/people3.svg"/>
</div>
</v-col>
<v-col cols="12" md="4" class="auth-card d-flex flex-column">
@@ -47,7 +47,7 @@
<v-btn block variant="tonal" :disabled="verifyingByWebAuthn"
@click="unlockByWebAuthn">
{{ tt('Unlock with WebAuthn') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="verifyingByWebAuthn"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="verifyingByWebAuthn"></v-progress-circular>
</v-btn>
</v-col>
@@ -105,8 +105,9 @@ import { useUnlockPageBase } from '@/views/base/UnlockPageBase.ts';
import { useSettingsStore } from '@/stores/setting.ts';
import { useUserStore } from '@/stores/user.ts';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import { ThemeType } from '@/core/theme.ts';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import {
isWebAuthnSupported,
verifyWebAuthnCredential

View File

@@ -9,13 +9,13 @@
<v-row no-gutters class="auth-wrapper">
<v-col cols="12" md="8" class="d-none d-md-flex align-center justify-center position-relative">
<div class="d-flex auth-img-footer" v-if="!isDarkMode">
<v-img src="img/desktop/background.svg"/>
<v-img class="img-with-direction" src="img/desktop/background.svg"/>
</div>
<div class="d-flex auth-img-footer" v-if="isDarkMode">
<v-img src="img/desktop/background-dark.svg"/>
<v-img class="img-with-direction" src="img/desktop/background-dark.svg"/>
</div>
<div class="d-flex align-center justify-center w-100 pt-10">
<v-img max-width="320px" src="img/desktop/people2.svg"/>
<v-img class="img-with-direction" max-width="320px" src="img/desktop/people2.svg"/>
</div>
</v-col>
<v-col cols="12" md="4" class="auth-card d-flex flex-column">
@@ -48,14 +48,14 @@
<v-col cols="12" v-if="!loading && !token && email && isUserVerifyEmailEnabled()">
<v-btn block type="submit" :disabled="loading || resending || !password" @click="resendEmail">
{{ tt('Resend Validation Email') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="resending"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="resending"></v-progress-circular>
</v-btn>
</v-col>
<v-col cols="12">
<router-link class="d-flex align-center justify-center" :to="verified ? '/' : '/login'"
:class="{ 'disabled': loading || resending }">
<v-icon :icon="mdiChevronLeft"/>
<v-icon class="icon-with-direction" :icon="mdiChevronLeft"/>
<span v-if="!verified">{{ tt('Back to login page') }}</span>
<span v-else-if="verified">{{ tt('Back to home page') }}</span>
</router-link>
@@ -106,8 +106,9 @@ import { useI18n } from '@/locales/helpers.ts';
import { useRootStore } from '@/stores/index.ts';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import { ThemeType } from '@/core/theme.ts';
import { APPLICATION_LOGO_PATH } from '@/consts/asset.ts';
import { isUserVerifyEmailEnabled } from '@/lib/server_settings.ts';
import { isUserLogined } from '@/lib/userstate.ts';
import { getClientDisplayVersion } from '@/lib/version.ts';

View File

@@ -33,13 +33,13 @@
<v-tab class="tab-text-truncate" :key="accountCategory.type" :value="accountCategory.type"
v-for="accountCategory in AccountCategory.values()">
<ItemIcon icon-type="account" :icon-id="accountCategory.defaultAccountIconId" />
<div class="d-flex flex-column text-truncate ml-2">
<small class="text-truncate text-left smaller" v-if="!loading || allAccountCount > 0">{{ accountCategoryTotalBalance(accountCategory) }}</small>
<small class="text-truncate text-left smaller my-1" v-else-if="loading && allAccountCount <= 0">
<div class="d-flex flex-column text-truncate ms-2">
<small class="text-truncate text-start smaller" v-if="!loading || allAccountCount > 0">{{ accountCategoryTotalBalance(accountCategory) }}</small>
<small class="text-truncate text-start smaller my-1" v-else-if="loading && allAccountCount <= 0">
<v-skeleton-loader class="skeleton-no-margin"
width="100px" height="16" type="text" :loading="true"></v-skeleton-loader>
</small>
<span class="text-truncate text-left">{{ tt(accountCategory.name) }}</span>
<span class="text-truncate text-start">{{ tt(accountCategory.name) }}</span>
</div>
</v-tab>
</v-tabs>
@@ -50,18 +50,18 @@
<v-card variant="flat" min-height="780">
<template #title>
<div class="title-and-toolbar d-flex align-center">
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
<v-btn class="me-3 d-md-none" density="compact" color="default" variant="plain"
:ripple="false" :icon="true" @click="showNav = !showNav">
<v-icon :icon="mdiMenu" size="24" />
</v-btn>
<span>{{ tt('Account List') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
<v-btn class="ms-3" color="default" variant="outlined"
:disabled="loading" @click="add">{{ tt('Add') }}</v-btn>
<v-btn class="ml-3" color="primary" variant="tonal"
<v-btn class="ms-3" color="primary" variant="tonal"
:disabled="loading" @click="saveSortResult"
v-if="displayOrderModified">{{ tt('Save Display Order') }}</v-btn>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :loading="loading" @click="reload(true)">
class="ms-2" :icon="true" :loading="loading" @click="reload(true)">
<template #loader>
<v-progress-circular indeterminate size="20"/>
</template>
@@ -69,7 +69,7 @@
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
</v-btn>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -92,9 +92,9 @@
<v-card-text class="accounts-overview-title text-truncate pt-0">
<span class="accounts-overview-subtitle">{{ activeAccountCategory?.isLiability ? tt('Outstanding Balance') : tt('Balance') }}</span>
<v-skeleton-loader class="skeleton-no-margin ml-3 mb-2" width="120px" type="text" :loading="true" v-if="loading && activeAccountCategory && !hasAccount(activeAccountCategory)"></v-skeleton-loader>
<span class="accounts-overview-amount ml-3" v-else-if="!loading || !activeAccountCategory || hasAccount(activeAccountCategory)">{{ activeAccountCategoryTotalBalance }}</span>
<v-btn class="ml-2" density="compact" color="default" variant="text"
<v-skeleton-loader class="skeleton-no-margin ms-3 mb-2" width="120px" type="text" :loading="true" v-if="loading && activeAccountCategory && !hasAccount(activeAccountCategory)"></v-skeleton-loader>
<span class="accounts-overview-amount ms-3" v-else-if="!loading || !activeAccountCategory || hasAccount(activeAccountCategory)">{{ activeAccountCategoryTotalBalance }}</span>
<v-btn class="ms-2" density="compact" color="default" variant="text"
:icon="true" :disabled="loading"
@click="showAccountBalance = !showAccountBalance">
<v-icon :icon="showAccountBalance ? mdiEyeOffOutline : mdiEyeOutline" size="20" />
@@ -102,13 +102,13 @@
</v-btn>
</v-card-text>
<v-row class="pl-6 pr-6 pr-md-8" v-if="loading && activeAccountCategory && !hasAccount(activeAccountCategory)">
<v-row class="ps-6 pe-6 pe-md-8" v-if="loading && activeAccountCategory && !hasAccount(activeAccountCategory)">
<v-col cols="12">
<v-card border class="card-title-with-bg account-card mb-8 h-auto">
<template #title>
<div class="account-title d-flex align-center">
<v-icon class="disabled mr-0" size="28px" :icon="mdiSquareRounded" />
<span class="account-name text-truncate ml-2">
<v-icon class="disabled me-0" size="28px" :icon="mdiSquareRounded" />
<span class="account-name text-truncate ms-2">
<v-skeleton-loader class="skeleton-no-margin my-1"
width="120px" type="text" :loading="true"></v-skeleton-loader>
</span>
@@ -126,7 +126,7 @@
{{ tt('Transaction List') }}
</v-btn>
<v-spacer/>
<span class="account-balance ml-2">
<span class="account-balance ms-2">
<v-skeleton-loader class="skeleton-no-margin"
width="100px" type="text" :loading="true"></v-skeleton-loader>
</span>
@@ -136,13 +136,13 @@
</v-col>
</v-row>
<v-row class="pl-5 pr-2 pr-md-4" v-if="!loading && activeAccountCategory && !hasAccount(activeAccountCategory)">
<v-row class="ps-5 pe-2 pe-md-4" v-if="!loading && activeAccountCategory && !hasAccount(activeAccountCategory)">
<v-col cols="12">
{{ tt('No available account') }}
</v-col>
</v-row>
<v-row class="pl-6 pr-6 pr-md-8">
<v-row class="ps-6 pe-6 pe-md-8">
<v-col cols="12">
<draggable-list
class="list-group"
@@ -161,8 +161,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 text-truncate ml-2">{{ element.name }}</span>
<small class="account-currency text-truncate ml-2">
<span class="account-name text-truncate ms-2">{{ element.name }}</span>
<small class="account-currency text-truncate ms-2">
{{ accountCurrency(element) }}
</small>
<v-spacer/>
@@ -192,7 +192,7 @@
v-show="showHidden || !subAccount.hidden">
<ItemIcon size="1.5rem" icon-type="account" :icon-id="subAccount.icon"
:color="subAccount.color" :hidden-status="subAccount.hidden" />
<span class="ml-2">{{ subAccount.name }}</span>
<span class="ms-2">{{ subAccount.name }}</span>
</v-btn>
</v-btn-toggle>
</div>
@@ -211,7 +211,7 @@
:to="`/transaction/list?accountIds=${element.getAccountOrSubAccountId(activeSubAccount[element.id])}`">
{{ tt('Transaction List') }}
</v-btn>
<v-btn class="px-2 ml-1" density="comfortable" color="default" variant="text"
<v-btn class="px-2 ms-1" density="comfortable" color="default" variant="text"
:disabled="loading" :prepend-icon="mdiInvoiceListOutline"
@click="showReconciliationStatementCustomDateRangeDialog(element.getAccountOrSubAccount(activeSubAccount[element.id]))"
v-if="element.type === AccountType.SingleAccount.type || element.getSubAccount(activeSubAccount[element.id])">
@@ -225,7 +225,7 @@
<v-list-item-title class="cursor-pointer"
@click="showReconciliationStatementCustomDateRangeDialog(element.getAccountOrSubAccount(activeSubAccount[element.id]), dateRange.type)">
<div class="d-flex align-center">
<span class="text-sm ml-3">{{ dateRange.displayName }}</span>
<span class="text-sm ms-3">{{ dateRange.displayName }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -233,7 +233,7 @@
</v-list>
</v-menu>
</v-btn>
<v-btn class="px-2 ml-1" density="comfortable" color="default" variant="text"
<v-btn class="px-2 ms-1" density="comfortable" color="default" variant="text"
:class="{ 'd-none': loading, 'hover-display': !loading }"
:disabled="loading"
:prepend-icon="element.isAccountOrSubAccountHidden(activeSubAccount[element.id]) ? mdiEyeOutline : mdiEyeOffOutline"
@@ -241,14 +241,14 @@
@click="hide(element, element.getAccountOrSubAccount(activeSubAccount[element.id]), !element.isAccountOrSubAccountHidden(activeSubAccount[element.id]))">
{{ element.isAccountOrSubAccountHidden(activeSubAccount[element.id]) ? tt('Show') : tt('Hide') }}
</v-btn>
<v-btn class="px-2 ml-1" density="comfortable" color="default" variant="text"
<v-btn class="px-2 ms-1" density="comfortable" color="default" variant="text"
:class="{ 'd-none': loading, 'hover-display': !loading }"
:disabled="loading" :prepend-icon="mdiPencilOutline"
v-if="!activeSubAccount[element.id] || element.getSubAccount(activeSubAccount[element.id])"
@click="edit(element)">
{{ tt('Edit') }}
</v-btn>
<v-btn class="px-2 ml-1" density="comfortable" color="default" variant="text"
<v-btn class="px-2 ms-1" density="comfortable" color="default" variant="text"
:class="{ 'd-none': loading, 'hover-display': !loading }"
:disabled="loading" :prepend-icon="mdiDeleteOutline"
v-if="!activeSubAccount[element.id] || element.getSubAccount(activeSubAccount[element.id])"
@@ -256,7 +256,7 @@
{{ tt('Delete') }}
</v-btn>
<v-spacer/>
<span class="account-balance ml-2">{{ accountBalance(element, activeSubAccount[element.id]) }}</span>
<span class="account-balance ms-2">{{ accountBalance(element, activeSubAccount[element.id]) }}</span>
</div>
</v-card-text>
</v-card>

View File

@@ -5,9 +5,9 @@
<div class="d-flex align-center justify-center">
<div class="d-flex w-100 align-center justify-center">
<h4 class="text-h4">{{ tt(title) }}</h4>
<v-progress-circular indeterminate size="22" class="ml-2" v-if="loading"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="loading"></v-progress-circular>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2" :icon="true"
<v-btn density="comfortable" color="default" variant="text" class="ms-2" :icon="true"
:disabled="loading || submitting || account.type !== AccountType.MultiSubAccounts.type">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -29,7 +29,7 @@
<template v-if="account.type === AccountType.MultiSubAccounts.type">
<v-tab :key="idx" :value="idx" v-for="(subAccount, idx) in subAccounts">
<span>{{ tt('Sub Account') + ' #' + (idx + 1) }}</span>
<v-btn class="ml-2" color="error" size="24" variant="text"
<v-btn class="ms-2" color="error" size="24" variant="text"
:icon="mdiDeleteOutline"
@click="removeSubAccount(subAccount)"></v-btn>
</v-tab>
@@ -38,7 +38,7 @@
</div>
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container"
:class="{ 'ml-md-5': account.type === AccountType.MultiSubAccounts.type }"
:class="{ 'ms-md-5': account.type === AccountType.MultiSubAccounts.type }"
v-model="activeTab">
<v-window-item value="account">
<v-form class="mt-2">
@@ -63,7 +63,7 @@
<ItemIcon icon-type="account"
:icon-id="item.raw.defaultAccountIconId"
v-if="item.raw" />
<span class="ml-2">{{ item.title }}</span>
<span class="ms-2">{{ item.title }}</span>
</div>
</v-list-item-title>
</template>
@@ -174,7 +174,7 @@
<div v-bind="props" class="d-inline-block">
<v-btn :disabled="inputIsEmpty || loading || submitting" @click="save">
{{ tt(saveButtonTitle) }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
</v-btn>
</div>
</template>

View File

@@ -6,7 +6,7 @@
<div class="d-flex w-100 align-center justify-center">
<h4 class="text-h4">{{ tt('Reconciliation Statement') }}</h4>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :loading="loading" @click="reload(true)">
class="ms-2" :icon="true" :loading="loading" @click="reload(true)">
<template #loader>
<v-progress-circular indeterminate size="20"/>
</template>
@@ -14,7 +14,7 @@
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
</v-btn>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:icon="true" :disabled="loading"
v-if="showAccountBalanceTrendsCharts">
<v-icon :icon="mdiTuneVertical" />
@@ -42,7 +42,7 @@
</v-list>
</v-menu>
</v-btn>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:icon="true" :disabled="loading">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -94,42 +94,42 @@
<div class="d-flex align-center mb-4">
<div class="d-flex align-center text-body-1">
<span class="ml-2">{{ tt('Opening Balance') }}</span>
<span class="ms-2">{{ tt('Opening Balance') }}</span>
<span class="text-primary" v-if="loading">
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
</span>
<span class="text-primary ml-2" v-else-if="!loading">
<span class="text-primary ms-2" v-else-if="!loading">
{{ displayOpeningBalance }}
</span>
<span class="ml-3">{{ tt('Closing Balance') }}</span>
<span class="ms-3">{{ tt('Closing Balance') }}</span>
<span class="text-primary" v-if="loading">
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
</span>
<span class="text-primary ml-2" v-else-if="!loading">
<span class="text-primary ms-2" v-else-if="!loading">
{{ displayClosingBalance }}
</span>
</div>
<v-spacer/>
<div class="d-flex align-center text-body-1">
<span class="ml-2">{{ tt('Total Inflows') }}</span>
<span class="ms-2">{{ tt('Total Inflows') }}</span>
<span class="text-income" v-if="loading">
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
</span>
<span class="text-income ml-2" v-else-if="!loading">
<span class="text-income ms-2" v-else-if="!loading">
{{ displayTotalInflows }}
</span>
<span class="ml-3">{{ tt('Total Outflows') }}</span>
<span class="ms-3">{{ tt('Total Outflows') }}</span>
<span class="text-expense" v-if="loading">
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
</span>
<span class="text-expense ml-2" v-else-if="!loading">
<span class="text-expense ms-2" v-else-if="!loading">
{{ displayTotalOutflows }}
</span>
<span class="ml-3">{{ tt('Net Cash Flow') }}</span>
<span class="ms-3">{{ tt('Net Cash Flow') }}</span>
<span class="text-primary" v-if="loading">
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
</span>
<span class="text-primary ml-2" v-else-if="!loading">
<span class="text-primary ms-2" v-else-if="!loading">
{{ displayTotalBalance }}
</span>
</div>
@@ -151,7 +151,7 @@
>
<template #item.time="{ item }">
<span>{{ getDisplayDateTime(item) }}</span>
<v-chip class="ml-1" variant="flat" color="secondary" size="x-small"
<v-chip class="ms-1" variant="flat" color="secondary" size="x-small"
v-if="item.utcOffset !== currentTimezoneOffsetMinutes">{{ getDisplayTimezone(item) }}</v-chip>
</template>
<template #item.type="{ item }">
@@ -166,23 +166,23 @@
:color="allCategoriesMap[item.categoryId].color"
v-if="allCategoriesMap[item.categoryId] && allCategoriesMap[item.categoryId]?.color"></ItemIcon>
<v-icon size="24" :icon="mdiPencilBoxOutline" v-else-if="!allCategoriesMap[item.categoryId] || !allCategoriesMap[item.categoryId]?.color" />
<span class="ml-2" v-if="item.type === TransactionType.ModifyBalance">
<span class="ms-2" v-if="item.type === TransactionType.ModifyBalance">
{{ tt('Modify Balance') }}
</span>
<span class="ml-2" v-else-if="item.type !== TransactionType.ModifyBalance && allCategoriesMap[item.categoryId]">
<span class="ms-2" v-else-if="item.type !== TransactionType.ModifyBalance && allCategoriesMap[item.categoryId]">
{{ allCategoriesMap[item.categoryId].name }}
</span>
</div>
</template>
<template #item.sourceAmount="{ item }">
<span :class="{ 'text-expense': item.type === TransactionType.Expense, 'text-income': item.type === TransactionType.Income }">{{ getDisplaySourceAmount(item) }}</span>
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId && getDisplaySourceAmount(item) !== getDisplayDestinationAmount(item)"></v-icon>
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId && getDisplaySourceAmount(item) !== getDisplayDestinationAmount(item)"></v-icon>
<span v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId && getDisplaySourceAmount(item) !== getDisplayDestinationAmount(item)">{{ getDisplayDestinationAmount(item) }}</span>
</template>
<template #item.sourceAccountId="{ item }">
<div class="d-flex align-center">
<span v-if="item.sourceAccountId && allAccountsMap[item.sourceAccountId]">{{ allAccountsMap[item.sourceAccountId].name }}</span>
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
<span v-if="item.type === TransactionType.Transfer && item.destinationAccountId && allAccountsMap[item.destinationAccountId]">{{ allAccountsMap[item.destinationAccountId].name }}</span>
</div>
</template>
@@ -197,18 +197,18 @@
</template>
<template #bottom>
<div class="title-and-toolbar d-flex align-center text-no-wrap mt-2" v-if="loading || (reconciliationStatements && reconciliationStatements.transactions && reconciliationStatements.transactions.length)">
<span class="ml-2">{{ tt('Total Transactions') }}</span>
<span class="ms-2">{{ tt('Total Transactions') }}</span>
<span v-if="loading">
<v-skeleton-loader class="skeleton-no-margin ml-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
<v-skeleton-loader class="skeleton-no-margin ms-3" type="text" style="width: 80px" :loading="true"></v-skeleton-loader>
</span>
<span class="ml-2" v-else-if="!loading">
<span class="ms-2" v-else-if="!loading">
{{ formatNumberToLocalizedNumerals(reconciliationStatements?.transactions.length ?? 0) }}
</span>
<v-spacer/>
<span v-if="reconciliationStatements && reconciliationStatements.transactions && reconciliationStatements.transactions.length > 10">
{{ tt('Transactions Per Page') }}
</span>
<v-select class="ml-2" density="compact" max-width="100"
<v-select class="ms-2" density="compact" max-width="100"
item-title="title"
item-value="value"
:disabled="loading"

View File

@@ -4,7 +4,7 @@
<v-card>
<template #title>
<span>{{ tt('Settings Sync') }}</span>
<v-progress-circular indeterminate size="20" class="ml-3" v-if="loading"></v-progress-circular>
<v-progress-circular indeterminate size="20" class="ms-3" v-if="loading"></v-progress-circular>
</template>
<v-card-text class="pb-0">
@@ -28,7 +28,7 @@
<div class="w-100">
<span>{{ tt('Synchronized Settings') }}</span>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading || enabling || disabling" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -73,7 +73,7 @@
<v-divider/>
<v-list rounded density="comfortable" class="pa-0 ml-4">
<v-list rounded density="comfortable" class="pa-0 ms-4">
<template :key="settingItem.settingKey"
v-for="(settingItem, itemIdx) in categorizedItems.items">
<v-divider v-if="itemIdx > 0"/>
@@ -85,8 +85,8 @@
@update:model-value="enabledApplicationCloudSettings[settingItem.settingKey] = !!$event">
<template #label>
<span>{{ tt(settingItem.settingName) }}</span>
<v-icon class="ml-2 mr-0" start size="16" :icon="mdiCellphone" v-if="settingItem.mobile"/>
<v-icon class="ml-2 mr-0" start size="16" :icon="mdiMonitor" v-if="settingItem.desktop"/>
<v-icon class="ms-2 me-0" start size="16" :icon="mdiCellphone" v-if="settingItem.mobile"/>
<v-icon class="ms-2 me-0" start size="16" :icon="mdiMonitor" v-if="settingItem.desktop"/>
</template>
</v-checkbox>
</template>
@@ -105,15 +105,15 @@
<v-col cols="12" class="d-flex flex-wrap gap-4">
<v-btn :disabled="loading || enabling || disabling || !hasEnabledApplicationCloudSettings" v-if="!isEnableCloudSync" @click="enable(false)">
{{ tt('Enable Settings Sync') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="enabling"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="enabling"></v-progress-circular>
</v-btn>
<v-btn :disabled="loading || enabling || disabling || !hasEnabledApplicationCloudSettings" v-if="isEnableCloudSync" @click="enable(true)">
{{ tt('Update Synchronized Settings') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="enabling"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="enabling"></v-progress-circular>
</v-btn>
<v-btn :disabled="loading || enabling || disabling" v-if="isEnableCloudSync" @click="disable">
{{ tt('Disable Settings Sync') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="disabling"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="disabling"></v-progress-circular>
</v-btn>
</v-col>
</v-row>

View File

@@ -35,18 +35,18 @@
<v-card variant="flat" :min-height="cardMinHeight">
<template #title>
<div class="title-and-toolbar d-flex align-center">
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
<v-btn class="me-3 d-md-none" density="compact" color="default" variant="plain"
:ripple="false" :icon="true" @click="showNav = !showNav">
<v-icon :icon="mdiMenu" size="24" />
</v-btn>
<span>{{ tt('Transaction Categories') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
<v-btn class="ms-3" color="default" variant="outlined"
:disabled="loading || updating" @click="add">{{ tt('Add') }}</v-btn>
<v-btn class="ml-3" color="primary" variant="tonal"
<v-btn class="ms-3" color="primary" variant="tonal"
:disabled="loading || updating" @click="saveSortResult"
v-if="displayOrderModified">{{ tt('Save Display Order') }}</v-btn>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :loading="loading || updating" @click="reload(true)">
class="ms-2" :icon="true" :loading="loading || updating" @click="reload(true)">
<template #loader>
<v-progress-circular indeterminate size="20"/>
</template>
@@ -54,7 +54,7 @@
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
</v-btn>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading || updating" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -97,7 +97,7 @@
<td>
<div class="d-flex align-center">
<span>{{ tt('No available category') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
<v-btn class="ms-3" color="default" variant="outlined"
@click="showPresetDialog = true"
v-if="hasSubCategories && noCategory">
{{ tt('Add Default Categories') }}
@@ -124,14 +124,14 @@
:icon-id="element.icon" :color="element.color"
:hidden-status="element.hidden" />
<div class="d-flex flex-column py-2">
<span class="ml-2">{{ element.name }}</span>
<span class="transaction-category-comment ml-2">{{ element.comment }}</span>
<span class="ms-2">{{ element.name }}</span>
<span class="transaction-category-comment ms-2">{{ element.comment }}</span>
</div>
</div>
<v-spacer/>
<v-btn class="px-2 ml-2" color="default"
<v-btn class="px-2 ms-2" color="default"
density="comfortable" variant="text"
:class="{ 'd-none': loading, 'hover-display': !loading }"
:prepend-icon="element.hidden ? mdiEyeOutline : mdiEyeOffOutline"
@@ -163,7 +163,7 @@
</template>
{{ tt('Delete') }}
</v-btn>
<span class="ml-2">
<span class="ms-2">
<v-icon :class="!loading && !updating && availableCategoryCount > 1 ? 'drag-handle' : 'disabled'"
:icon="mdiDrag"/>
<v-tooltip activator="parent" v-if="!loading && !updating && availableCategoryCount > 1">{{ tt('Drag to Reorder') }}</v-tooltip>

View File

@@ -4,7 +4,7 @@
<template #title>
<div class="d-flex align-center justify-center">
<h4 class="text-h4">{{ tt(title) }}</h4>
<v-progress-circular indeterminate size="22" class="ml-2" v-if="loading"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="loading"></v-progress-circular>
</div>
</template>
<v-card-text class="pt-0">
@@ -35,7 +35,7 @@
<template #item="{ props, item }">
<v-list-item v-bind="props">
<template #prepend>
<ItemIcon class="mr-2" icon-type="category"
<ItemIcon class="me-2" icon-type="category"
:icon-id="item.raw.icon" :color="item.raw.color"></ItemIcon>
</template>
<template #title>
@@ -84,7 +84,7 @@
<div v-bind="props" class="d-inline-block">
<v-btn :disabled="inputIsEmpty || loading || submitting" @click="save">
{{ tt(saveButtonTitle) }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
</v-btn>
</div>
</template>

View File

@@ -19,7 +19,7 @@
<v-expansion-panel :key="idx" v-for="(category, idx) in categories">
<v-expansion-panel-title class="py-0">
<ItemIcon icon-type="category" :icon-id="category.icon" :color="category.color"></ItemIcon>
<span class="ml-3">{{ category.name }}</span>
<span class="ms-3">{{ category.name }}</span>
</v-expansion-panel-title>
<v-expansion-panel-text v-if="category.subCategories.length">
<v-list rounded density="comfortable" class="pa-0">
@@ -29,7 +29,7 @@
<template #prepend>
<ItemIcon icon-type="category" :icon-id="subCategory.icon" :color="subCategory.color"></ItemIcon>
</template>
<span class="ml-3">{{ subCategory.name }}</span>
<span class="ms-3">{{ subCategory.name }}</span>
</v-list-item>
<v-divider v-if="subIdx !== category.subCategories.length - 1"/>
</template>
@@ -43,7 +43,7 @@
<div class="w-100 d-flex justify-center mt-2 mt-sm-4 mt-md-6 gap-4">
<v-btn :disabled="submitting" @click="save">
{{ tt('Save') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
</v-btn>
<v-btn color="secondary" density="default" variant="tonal"
:disabled="submitting" @click="showState = false">{{ tt('Cancel') }}</v-btn>
@@ -137,6 +137,7 @@ function save(): void {
<style>
.preset-transaction-categories .v-expansion-panel-text__wrapper {
padding: 0 0 0 20px;
padding: 0 0 0 0;
padding-inline-start: 20px;
}
</style>

View File

@@ -5,7 +5,7 @@
<div class="w-100 text-center">
<h4 class="text-h4">{{ tt(title) }}</h4>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading || !hasAnyAvailableAccount" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -36,7 +36,7 @@
<div class="d-flex align-center" v-else-if="!dialogMode">
<span>{{ tt(title) }}</span>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -83,7 +83,7 @@
v-for="accountCategory in allCategorizedAccounts"
v-show="showHidden || accountCategory.allVisibleAccountCount > 0">
<v-expansion-panel-title class="expand-panel-title-with-bg py-0">
<span class="ml-3">{{ tt(accountCategory.name) }}</span>
<span class="ms-3">{{ tt(accountCategory.name) }}</span>
</v-expansion-panel-title>
<v-expansion-panel-text>
<v-list rounded density="comfortable" class="pa-0">
@@ -99,7 +99,7 @@
<template #label>
<ItemIcon class="d-flex" icon-type="account" :icon-id="account.icon"
:color="account.color" :hidden-status="account.hidden"></ItemIcon>
<span class="ml-3">{{ account.name }}</span>
<span class="ms-3">{{ account.name }}</span>
</template>
</v-checkbox>
</template>
@@ -107,7 +107,7 @@
<v-divider v-if="(showHidden || !account.hidden) && account.type === AccountType.MultiSubAccounts.type && ((showHidden && accountCategory.allSubAccounts[account.id]) || accountCategory.allVisibleSubAccountCounts[account.id])"/>
<v-list rounded density="comfortable" class="pa-0 ml-4"
<v-list rounded density="comfortable" class="pa-0 ms-4"
v-if="(showHidden || !account.hidden) && account.type === AccountType.MultiSubAccounts.type && ((showHidden && accountCategory.allSubAccounts[account.id]) || accountCategory.allVisibleSubAccountCounts[account.id])">
<template :key="subAccount.id"
v-for="(subAccount, subIdx) in accountCategory.allSubAccounts[account.id]">
@@ -120,7 +120,7 @@
<template #label>
<ItemIcon class="d-flex" icon-type="account" :icon-id="subAccount.icon"
:color="subAccount.color" :hidden-status="subAccount.hidden"></ItemIcon>
<span class="ml-3">{{ subAccount.name }}</span>
<span class="ms-3">{{ subAccount.name }}</span>
</template>
</v-checkbox>
</template>

View File

@@ -5,7 +5,7 @@
<div class="w-100 text-center">
<h4 class="text-h4">{{ tt(title) }}</h4>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading || !hasAnyAvailableCategory" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -36,7 +36,7 @@
<div class="d-flex align-center" v-else-if="!dialogMode">
<span>{{ tt(title) }}</span>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -78,7 +78,7 @@
class="border"
v-for="transactionType in allTransactionCategories">
<v-expansion-panel-title class="expand-panel-title-with-bg py-0">
<span class="ml-3">{{ getCategoryTypeName(transactionType.type) }}</span>
<span class="ms-3">{{ getCategoryTypeName(transactionType.type) }}</span>
</v-expansion-panel-title>
<v-expansion-panel-text>
<v-list rounded density="comfortable" class="pa-0">
@@ -96,7 +96,7 @@
<template #label>
<ItemIcon class="d-flex" icon-type="category" :icon-id="category.icon"
:color="category.color" :hidden-status="category.hidden"></ItemIcon>
<span class="ml-3">{{ category.name }}</span>
<span class="ms-3">{{ category.name }}</span>
</template>
</v-checkbox>
</template>
@@ -104,7 +104,7 @@
<v-divider v-if="(showHidden || !category.hidden) && ((showHidden && transactionType.allSubCategories[category.id]) || transactionType.allVisibleSubCategoryCounts[category.id])"/>
<v-list rounded density="comfortable" class="pa-0 ml-4"
<v-list rounded density="comfortable" class="pa-0 ms-4"
v-if="(showHidden || !category.hidden) && ((showHidden && transactionType.allSubCategories[category.id]) || transactionType.allVisibleSubCategoryCounts[category.id])">
<template :key="subCategory.id"
v-for="(subCategory, subIdx) in transactionType.allSubCategories[category.id]">
@@ -117,7 +117,7 @@
<template #label>
<ItemIcon class="d-flex" icon-type="category" :icon-id="subCategory.icon"
:color="subCategory.color" :hidden-status="subCategory.hidden"></ItemIcon>
<span class="ml-3">{{ subCategory.name }}</span>
<span class="ms-3">{{ subCategory.name }}</span>
</template>
</v-checkbox>
</template>

View File

@@ -5,7 +5,7 @@
<div class="w-100 text-center">
<h4 class="text-h4">{{ tt(title) }}</h4>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading || !hasAnyAvailableTag" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -36,7 +36,7 @@
<div class="d-flex align-center" v-else-if="!dialogMode">
<span>{{ tt(title) }}</span>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -90,7 +90,7 @@
<v-expansion-panels class="tag-categories" multiple v-model="expandTagCategories">
<v-expansion-panel class="border" key="default" value="default">
<v-expansion-panel-title class="expand-panel-title-with-bg py-0">
<span class="ml-3">{{ tt('Tags') }}</span>
<span class="ms-3">{{ tt('Tags') }}</span>
</v-expansion-panel-title>
<v-expansion-panel-text>
<v-list rounded density="comfortable" class="pa-0">
@@ -107,7 +107,7 @@
<v-icon size="24" :icon="mdiPound"/>
</v-badge>
<v-icon size="24" :icon="mdiPound" v-else-if="!transactionTag.hidden"/>
<span class="ml-3">{{ transactionTag.name }}</span>
<span class="ms-3">{{ transactionTag.name }}</span>
</template>
</v-checkbox>
</template>
@@ -269,7 +269,8 @@ init();
}
.tag-categories .v-expansion-panel-text__wrapper {
padding: 0 0 0 20px;
padding: 0 0 0 0;
padding-inline-start: 20px;
}
.tag-categories .v-expansion-panel--active:not(:first-child),

View File

@@ -39,9 +39,9 @@
v-if="exchangeRatesData && exchangeRatesData.exchangeRates && exchangeRatesData.exchangeRates.length">
<v-tab class="tab-text-truncate" :key="exchangeRate.currencyCode" :value="exchangeRate.currencyCode"
v-for="exchangeRate in availableExchangeRates">
<div class="text-truncate">
<span>{{ exchangeRate.currencyDisplayName }}</span>
<small class="smaller ml-1">{{ exchangeRate.currencyCode }}</small>
<div class="d-flex w-100">
<span class="d-block text-truncate">{{ exchangeRate.currencyDisplayName }}</span>
<small class="smaller ms-1">{{ exchangeRate.currencyCode }}</small>
</div>
</v-tab>
</v-tabs>
@@ -61,16 +61,16 @@
<v-card variant="flat" min-height="680">
<template #title>
<div class="title-and-toolbar d-flex align-center">
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
<v-btn class="me-3 d-md-none" density="compact" color="default" variant="plain"
:ripple="false" :icon="true" @click="showNav = !showNav">
<v-icon :icon="mdiMenu" size="24" />
</v-btn>
<span>{{ tt('Exchange Rates Data') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
<v-btn class="ms-3" color="default" variant="outlined"
:disabled="loading" @click="update"
v-if="isUserCustomExchangeRates">{{ tt('Update') }}</v-btn>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :loading="loading" @click="reload(true)">
class="ms-2" :icon="true" :loading="loading" @click="reload(true)">
<template #loader>
<v-progress-circular indeterminate size="20"/>
</template>
@@ -110,11 +110,11 @@
<td>
<div class="d-flex align-center">
<span class="text-sm">{{ exchangeRate.currencyDisplayName }}</span>
<span class="text-caption ml-1">{{ exchangeRate.currencyCode }}</span>
<span class="text-caption ms-1">{{ exchangeRate.currencyCode }}</span>
<v-spacer/>
<v-btn class="px-2 ml-2" color="default"
<v-btn class="px-2 ms-2" color="default"
density="comfortable" variant="text"
:class="{ 'd-none': loading, 'hover-display': !loading }"
v-if="exchangeRate.currencyCode !== baseCurrency"
@@ -134,7 +134,7 @@
</template>
{{ tt('Delete') }}
</v-btn>
<span class="ml-3">{{ getFinalConvertedAmount(exchangeRate, true) }}</span>
<span class="ms-3">{{ getFinalConvertedAmount(exchangeRate, true) }}</span>
</div>
</td>
</tr>

View File

@@ -51,7 +51,7 @@
<div class="w-100 d-flex justify-center gap-4">
<v-btn :disabled="submitting || !defaultCurrencyAmount || !currency || !targetCurrencyAmount" @click="confirm">
{{ tt('OK') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
</v-btn>
<v-btn color="secondary" variant="tonal" :disabled="submitting" @click="cancel">{{ tt('Cancel') }}</v-btn>
</div>

View File

@@ -4,9 +4,9 @@
<v-avatar color="secondary" size="38">
<v-icon size="24" :icon="icon" />
</v-avatar>
<span class="font-weight-bold ml-3">{{ title }}</span>
<span class="font-weight-bold ms-3">{{ title }}</span>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2" :icon="true">
<v-btn density="comfortable" color="default" variant="text" class="ms-2" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
<v-list>

View File

@@ -34,6 +34,7 @@ import { useI18n } from '@/locales/helpers.ts';
import { useSettingsStore } from '@/stores/setting.ts';
import { useUserStore } from '@/stores/user.ts';
import { TextDirection } from '@/core/text.ts';
import type { HiddenAmount } from '@/core/numeral.ts';
import { TransactionType } from '@/core/transaction.ts';
import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
@@ -63,11 +64,12 @@ const emit = defineEmits<{
(e: 'click', event: MonthlyIncomeAndExpenseCardClickEvent): void;
}>();
const { tt, getMonthShortName, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
const { tt, getCurrentLanguageTextDirection, getMonthShortName, formatAmountToLocalizedNumeralsWithCurrency } = useI18n();
const settingsStore = useSettingsStore();
const userStore = useUserStore();
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
const showAmountInHomePage = computed<boolean>(() => settingsStore.appSettings.showAmountInHomePage);
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
const hasAnyData = computed<boolean>(() => {
@@ -157,21 +159,21 @@ const chartOptions = computed<object>(() => {
return `<table>` +
`<thead>` +
`<tr>` +
`<td colspan="2" class="text-left">${params[0].name}</td>` +
`<td colspan="2" class="text-start">${params[0].name}</td>` +
`</tr>` +
`</thead>` +
`<tbody>` +
(
incomeAmount !== null ?
`<tr>` +
`<td><span class="overview-monthly-chart-tooltip-indicator bg-income mr-1"></span><span class="mr-4">${tt('Income')}</span></td>` +
`<td><span class="overview-monthly-chart-tooltip-indicator bg-income me-1"></span><span class="me-4">${tt('Income')}</span></td>` +
`<td><strong>${incomeAmount}</strong></td>` +
`</tr>` : ''
)+
(
expenseAmount !== null ?
`<tr>` +
`<td><span class="overview-monthly-chart-tooltip-indicator bg-expense mr-1"></span><span class="mr-4">${tt('Expense')}</span></td>` +
`<td><span class="overview-monthly-chart-tooltip-indicator bg-expense me-1"></span><span class="me-4">${tt('Expense')}</span></td>` +
`<td><strong>${expenseAmount}</strong></td>` +
`</tr>` : ''
) +
@@ -199,6 +201,7 @@ const chartOptions = computed<object>(() => {
{
type: 'category',
data: monthNames,
inverse: textDirection.value === TextDirection.RTL,
axisLine: {
show: false
},

View File

@@ -51,13 +51,13 @@
<v-card variant="flat" min-height="680">
<template #title>
<div class="title-and-toolbar d-flex align-center">
<v-btn class="mr-3 d-md-none" density="compact" color="default" variant="plain"
<v-btn class="me-3 d-md-none" density="compact" color="default" variant="plain"
:ripple="false" :icon="true" @click="showNav = !showNav">
<v-icon :icon="mdiMenu" size="24" />
</v-btn>
<span>{{ tt('Statistics & Analysis') }}</span>
<v-btn-group class="ml-4" color="default" density="comfortable" variant="outlined" divided>
<v-btn :icon="mdiArrowLeft"
<v-btn-group class="ms-4" color="default" density="comfortable" variant="outlined" divided>
<v-btn class="button-icon-with-direction" :icon="mdiArrowLeft"
:disabled="loading || !canShiftDateRange"
@click="shiftDateRange(-1)"/>
<v-menu location="bottom">
@@ -83,14 +83,14 @@
</v-list-item>
</v-list>
</v-menu>
<v-btn :icon="mdiArrowRight"
<v-btn class="button-icon-with-direction" :icon="mdiArrowRight"
:disabled="loading || !canShiftDateRange"
@click="shiftDateRange(1)"/>
</v-btn-group>
<v-menu location="bottom" v-if="queryAnalysisType === StatisticsAnalysisType.TrendAnalysis">
<template #activator="{ props }">
<v-btn class="ml-3" color="default" variant="outlined"
<v-btn class="ms-3" color="default" variant="outlined"
:prepend-icon="mdiCalendarRangeOutline" :disabled="loading"
v-bind="props">{{ queryTrendDateAggregationTypeName }}</v-btn>
</template>
@@ -105,7 +105,7 @@
</v-menu>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :loading="loading" @click="reload(true)">
class="ms-2" :icon="true" :loading="loading" @click="reload(true)">
<template #loader>
<v-progress-circular indeterminate size="20"/>
</template>
@@ -113,7 +113,7 @@
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
</v-btn>
<v-spacer/>
<div class="transaction-keyword-filter ml-2">
<div class="transaction-keyword-filter ms-2">
<v-text-field density="compact" :disabled="loading"
:prepend-inner-icon="mdiMagnify"
:append-inner-icon="filterKeyword !== query.keyword ? mdiCheck : undefined"
@@ -123,7 +123,7 @@
@keyup.enter="setKeywordFilter(filterKeyword)"
/>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -155,12 +155,12 @@
<v-card-text class="statistics-overview-title pt-0" :class="{ 'disabled': loading }"
v-if="queryAnalysisType === StatisticsAnalysisType.CategoricalAnalysis && (initing || (categoricalAnalysisData && categoricalAnalysisData.items && categoricalAnalysisData.items.length))">
<span class="statistics-subtitle">{{ totalAmountName }}</span>
<span class="statistics-overview-amount ml-3"
<span class="statistics-overview-amount ms-3"
:class="statisticsTextColor"
v-if="!initing && categoricalAnalysisData && categoricalAnalysisData.items && categoricalAnalysisData.items.length">
{{ getDisplayAmount(categoricalAnalysisData.totalAmount, defaultCurrency) }}
</span>
<v-skeleton-loader class="skeleton-no-margin ml-3 mb-2"
<v-skeleton-loader class="skeleton-no-margin ms-3 mb-2"
width="120px" type="text" :loading="true"
v-else-if="initing"></v-skeleton-loader>
</v-card-text>
@@ -204,13 +204,13 @@
<v-card-text :class="{ 'readonly': loading }" v-if="queryAnalysisType === StatisticsAnalysisType.CategoricalAnalysis && query.categoricalChartType === CategoricalChartType.Bar.type">
<v-list rounded lines="two" v-if="initing">
<template :key="itemIdx" v-for="itemIdx in [ 1, 2, 3 ]">
<v-list-item class="pl-0">
<v-list-item class="ps-0">
<template #prepend>
<div>
<v-icon class="disabled mr-0" size="34" :icon="mdiSquareRounded" />
<v-icon class="disabled me-0" size="34" :icon="mdiSquareRounded" />
</div>
</template>
<div class="d-flex flex-column ml-2">
<div class="d-flex flex-column ms-2">
<div class="d-flex">
<v-skeleton-loader class="skeleton-no-margin my-2"
width="120px" type="text" :loading="true"></v-skeleton-loader>
@@ -226,7 +226,7 @@
<v-list class="py-0" rounded lines="two" v-else-if="!initing && categoricalAnalysisData && categoricalAnalysisData.items && categoricalAnalysisData.items.length">
<template :key="idx"
v-for="(item, idx) in categoricalAnalysisData.items">
<v-list-item class="pl-0" v-if="!item.hidden">
<v-list-item class="ps-0" v-if="!item.hidden">
<template #prepend>
<router-link class="statistics-list-item" :to="getTransactionItemLinkUrl(item.id)">
<ItemIcon :icon-type="queryChartDataCategory" size="34px"
@@ -235,7 +235,7 @@
</router-link>
</template>
<router-link class="statistics-list-item" :to="getTransactionItemLinkUrl(item.id)">
<div class="d-flex flex-column ml-2">
<div class="d-flex flex-column ms-2">
<div class="d-flex">
<span>{{ item.name }}</span>
<small class="statistics-percent" v-if="item.percent >= 0">{{ formatPercentToLocalizedNumerals(item.percent, 2, '&lt;0.01') }}</small>
@@ -1058,7 +1058,7 @@ init(props);
.statistics-list-item .statistics-percent {
font-size: 0.75rem;
opacity: 0.7;
margin-left: 6px;
margin-inline-start: 6px;
}
.statistics-list-item .statistics-amount {

View File

@@ -6,7 +6,7 @@
<div class="d-flex w-100 align-center justify-center">
<h4 class="text-h4">{{ tt('Export Results') }}</h4>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2" :icon="true">
<v-btn density="comfortable" color="default" variant="text" class="ms-2" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
<v-list>

View File

@@ -5,13 +5,13 @@
<template #title>
<div class="title-and-toolbar d-flex align-center">
<span>{{ tt('Transaction Tags') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
<v-btn class="ms-3" color="default" variant="outlined"
:disabled="loading || updating || hasEditingTag" @click="add">{{ tt('Add') }}</v-btn>
<v-btn class="ml-3" color="primary" variant="tonal"
<v-btn class="ms-3" color="primary" variant="tonal"
:disabled="loading || updating || hasEditingTag" @click="saveSortResult"
v-if="displayOrderModified">{{ tt('Save Display Order') }}</v-btn>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :disabled="loading || updating || hasEditingTag"
class="ms-2" :icon="true" :disabled="loading || updating || hasEditingTag"
:loading="loading" @click="reload">
<template #loader>
<v-progress-circular indeterminate size="20"/>
@@ -20,7 +20,7 @@
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
</v-btn>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading || updating || hasEditingTag" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -86,7 +86,7 @@
<span class="transaction-tag-name">{{ element.name }}</span>
</div>
<v-text-field class="w-100 mr-2" type="text"
<v-text-field class="w-100 me-2" type="text"
density="compact" variant="underlined"
:disabled="loading || updating"
:placeholder="tt('Tag Title')"
@@ -106,7 +106,7 @@
<v-spacer/>
<v-btn class="px-2 ml-2" color="default"
<v-btn class="px-2 ms-2" color="default"
density="comfortable" variant="text"
:class="{ 'd-none': loading, 'hover-display': !loading }"
:prepend-icon="element.hidden ? mdiEyeOutline : mdiEyeOffOutline"
@@ -163,7 +163,7 @@
v-if="editingTag.id === element.id" @click="cancelSave(editingTag)">
{{ tt('Cancel') }}
</v-btn>
<span class="ml-2">
<span class="ms-2">
<v-icon :class="!loading && !updating && !hasEditingTag && availableTagCount > 1 ? 'drag-handle' : 'disabled'"
:icon="mdiDrag"/>
<v-tooltip activator="parent" v-if="!loading && !updating && !hasEditingTag && availableTagCount > 1">{{ tt('Drag to Reorder') }}</v-tooltip>
@@ -178,7 +178,7 @@
<tr class="text-sm" :class="{ 'even-row': (availableTagCount & 1) === 1}">
<td>
<div class="d-flex align-center">
<v-text-field class="w-100 mr-2" type="text" color="primary"
<v-text-field class="w-100 me-2" type="text" color="primary"
density="compact" variant="underlined"
:disabled="loading || updating" :placeholder="tt('Tag Title')"
v-model="newTag.name" @keyup.enter="save(newTag)">
@@ -206,7 +206,7 @@
@click="cancelSave(newTag)">
{{ tt('Cancel') }}
</v-btn>
<span class="ml-2">
<span class="ms-2">
<v-icon class="disabled" :icon="mdiDrag"/>
</span>
</div>
@@ -474,7 +474,7 @@ transactionTagsStore.loadAllTags({
}
.transaction-tags-table .v-text-field .v-input__prepend {
margin-right: 0;
margin-inline-end: 0;
color: rgba(var(--v-theme-on-surface));
}

View File

@@ -5,13 +5,13 @@
<template #title>
<div class="title-and-toolbar d-flex align-center">
<span>{{ templateType === TemplateType.Schedule.type ? tt('Scheduled Transactions') : tt('Transaction Templates') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
<v-btn class="ms-3" color="default" variant="outlined"
:disabled="loading || updating" @click="add">{{ tt('Add') }}</v-btn>
<v-btn class="ml-3" color="primary" variant="tonal"
<v-btn class="ms-3" color="primary" variant="tonal"
:disabled="loading || updating" @click="saveSortResult"
v-if="displayOrderModified">{{ tt('Save Display Order') }}</v-btn>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :disabled="loading || updating"
class="ms-2" :icon="true" :disabled="loading || updating"
:loading="loading" @click="reload">
<template #loader>
<v-progress-circular indeterminate size="20"/>
@@ -20,7 +20,7 @@
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
</v-btn>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="loading || updating" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -89,7 +89,7 @@
<v-spacer/>
<v-btn class="px-2 ml-2" color="default"
<v-btn class="px-2 ms-2" color="default"
density="comfortable" variant="text"
:class="{ 'd-none': loading, 'hover-display': !loading }"
:prepend-icon="element.hidden ? mdiEyeOutline : mdiEyeOffOutline"
@@ -124,7 +124,7 @@
</template>
{{ tt('Delete') }}
</v-btn>
<span class="ml-2">
<span class="ms-2">
<v-icon :class="!loading && !updating && availableTemplateCount > 1 ? 'drag-handle' : 'disabled'"
:icon="mdiDrag"/>
<v-tooltip activator="parent" v-if="!loading && !updating && availableTemplateCount > 1">{{ tt('Drag to Reorder') }}</v-tooltip>
@@ -387,7 +387,7 @@ init();
}
.transaction-templates-table .v-text-field .v-input__prepend {
margin-right: 0;
margin-inline-end: 0;
color: rgba(var(--v-theme-on-surface));
}

View File

@@ -52,12 +52,12 @@
<v-card variant="flat" min-height="920">
<template #title>
<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"
<v-btn class="me-3 d-md-none" density="compact" color="default" variant="plain"
:ripple="false" :icon="true" @click="showNav = !showNav">
<v-icon :icon="mdiMenu" size="24" />
</v-btn>
<span>{{ tt('Transaction List') }}</span>
<v-btn class="ml-3" color="default" variant="outlined"
<v-btn class="ms-3" color="default" variant="outlined"
:disabled="loading || !canAddTransaction" @click="add()">
{{ tt('Add') }}
<v-menu activator="parent" :open-on-hover="true" v-if="allTransactionTemplates && allTransactionTemplates.length">
@@ -70,7 +70,7 @@
</v-list>
</v-menu>
</v-btn>
<v-btn class="ml-3" color="default" variant="outlined"
<v-btn class="ms-3" color="default" variant="outlined"
:disabled="loading" @click="importTransaction"
v-if="isDataImportingEnabled()">
{{ tt('Import') }}
@@ -87,7 +87,7 @@
</v-list>
</v-menu>
</v-btn>
<v-btn class="ml-3" color="default" variant="outlined"
<v-btn class="ms-3" color="default" variant="outlined"
:disabled="loading || exportingData || !transactions || !transactions.length || transactions.length < 1" v-if="!isDataImportingEnabled() && isDataExportingEnabled()">
{{ tt('Export') }}
<v-menu activator="parent">
@@ -104,7 +104,7 @@
</v-menu>
</v-btn>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :loading="loading" @click="reload(true, false)">
class="ms-2" :icon="true" :loading="loading" @click="reload(true, false)">
<template #loader>
<v-progress-circular indeterminate size="20"/>
</template>
@@ -112,7 +112,7 @@
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
</v-btn>
<v-spacer/>
<div class="transaction-keyword-filter ml-2">
<div class="transaction-keyword-filter ms-2">
<v-text-field density="compact" :disabled="loading"
:prepend-inner-icon="mdiMagnify"
:append-inner-icon="searchKeyword !== query.keyword ? mdiCheck : undefined"
@@ -128,36 +128,36 @@
<v-card-text class="pt-0">
<div class="transaction-list-datetime-range d-flex align-center">
<span class="text-body-1">{{ tt('Date Range') }}</span>
<span class="text-body-1 transaction-list-datetime-range-text ml-2"
<span class="text-body-1 transaction-list-datetime-range-text ms-2"
v-if="!query.minTime && !query.maxTime">
<span class="text-sm">{{ tt('All') }}</span>
</span>
<span class="text-body-1 transaction-list-datetime-range-text ml-2"
<span class="text-body-1 transaction-list-datetime-range-text ms-2"
v-else-if="query.minTime || query.maxTime">
<v-btn class="mr-1" size="x-small"
<v-btn class="button-icon-with-direction me-1" size="x-small"
density="compact" color="default" variant="outlined"
:icon="mdiArrowLeft" :disabled="loading"
@click="shiftDateRange(query.minTime, query.maxTime, -1)"/>
<span class="text-sm">{{ `${queryMinTime} - ${queryMaxTime}` }}</span>
<v-btn class="ml-1" size="x-small"
<v-btn class="button-icon-with-direction ms-1" size="x-small"
density="compact" color="default" variant="outlined"
:icon="mdiArrowRight" :disabled="loading"
@click="shiftDateRange(query.minTime, query.maxTime, 1)"/>
</span>
<v-spacer/>
<div class="skeleton-no-margin d-flex align-center" v-if="showTotalAmountInTransactionListPage && currentMonthTotalAmount">
<span class="ml-2 text-subtitle-1">{{ queryAllFilterAccountIdsCount ? tt('Total Inflows') : tt('Total Income') }}</span>
<span class="text-income ml-2" v-if="loading">
<span class="ms-2 text-subtitle-1">{{ queryAllFilterAccountIdsCount ? tt('Total Inflows') : tt('Total Income') }}</span>
<span class="text-income ms-2" v-if="loading">
<v-skeleton-loader type="text" style="width: 60px" :loading="true"></v-skeleton-loader>
</span>
<span class="text-income ml-2" v-else-if="!loading">
<span class="text-income ms-2" v-else-if="!loading">
{{ currentMonthTotalAmount.income }}
</span>
<span class="text-subtitle-1 ml-3">{{ queryAllFilterAccountIdsCount ? tt('Total Outflows') : tt('Total Expense') }}</span>
<span class="text-expense ml-2" v-if="loading">
<span class="text-subtitle-1 ms-3">{{ queryAllFilterAccountIdsCount ? tt('Total Outflows') : tt('Total Expense') }}</span>
<span class="text-expense ms-2" v-if="loading">
<v-skeleton-loader type="text" style="width: 60px" :loading="true"></v-skeleton-loader>
</span>
<span class="text-expense ml-2" v-else-if="!loading">
<span class="text-expense ms-2" v-else-if="!loading">
{{ currentMonthTotalAmount.expense }}
</span>
</div>
@@ -217,10 +217,10 @@
<v-list-item-title class="cursor-pointer"
@click="changeDateFilter(dateRange.type)">
<div class="d-flex align-center">
<span class="text-sm ml-3">{{ dateRange.displayName }}</span>
<span class="text-sm ms-3">{{ dateRange.displayName }}</span>
</div>
</v-list-item-title>
<div class="ml-3 smaller" v-if="((dateRange.isBillingCycle || dateRange.type === DateRange.Custom.type) && query.dateType === dateRange.type) && query.minTime && query.maxTime">
<div class="ms-3 smaller" v-if="((dateRange.isBillingCycle || dateRange.type === DateRange.Custom.type) && query.dateType === dateRange.type) && query.minTime && query.maxTime">
<span>{{ queryMinTime }}</span>
<span>&nbsp;-&nbsp;</span>
<br/>
@@ -253,7 +253,7 @@
@click="changeCategoryFilter('')">
<div class="d-flex align-center">
<v-icon :icon="mdiViewGridOutline" />
<span class="text-sm ml-3">{{ tt('All') }}</span>
<span class="text-sm ms-3">{{ tt('All') }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -265,7 +265,7 @@
@click="showFilterCategoryDialog = true">
<div class="d-flex align-center">
<v-icon :icon="mdiVectorArrangeBelow" />
<span class="text-sm ml-3">{{ tt('Multiple Categories') }}</span>
<span class="text-sm ms-3">{{ tt('Multiple Categories') }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -287,7 +287,7 @@
<v-list-item-title>
<div class="d-flex align-center">
<ItemIcon icon-type="category" size="24px" :icon-id="category.icon" :color="category.color"></ItemIcon>
<span class="text-sm ml-3">{{ category.name }}</span>
<span class="text-sm ms-3">{{ category.name }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -302,7 +302,7 @@
@click="changeCategoryFilter(category.id)">
<div class="d-flex align-center">
<v-icon :icon="mdiViewGridOutline" />
<span class="text-sm ml-3">{{ tt('All') }}</span>
<span class="text-sm ms-3">{{ tt('All') }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -319,7 +319,7 @@
@click="changeCategoryFilter(subCategory.id)">
<div class="d-flex align-center">
<ItemIcon icon-type="category" size="24px" :icon-id="subCategory.icon" :color="subCategory.color"></ItemIcon>
<span class="text-sm ml-3">{{ subCategory.name }}</span>
<span class="text-sm ms-3">{{ subCategory.name }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -349,7 +349,7 @@
<v-list-item-title class="cursor-pointer"
@click="changeAmountFilter('')">
<div class="d-flex align-center">
<span class="text-sm ml-3">{{ tt('All') }}</span>
<span class="text-sm ms-3">{{ tt('All') }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -362,18 +362,18 @@
<v-list-item-title class="cursor-pointer"
@click="currentAmountFilterType = filterType.type">
<div class="d-flex align-center">
<span class="text-sm ml-3">{{ tt(filterType.name) }}</span>
<span class="text-sm ml-4" v-if="query.amountFilter && query.amountFilter.startsWith(`${filterType.type}:`) && currentAmountFilterType !== filterType.type">{{ queryAmount }}</span>
<amount-input class="transaction-amount-filter-value ml-4" density="compact"
<span class="text-sm ms-3">{{ tt(filterType.name) }}</span>
<span class="text-sm ms-4" v-if="query.amountFilter && query.amountFilter.startsWith(`${filterType.type}:`) && currentAmountFilterType !== filterType.type">{{ queryAmount }}</span>
<amount-input class="transaction-amount-filter-value ms-4" density="compact"
:currency="defaultCurrency"
v-model="currentAmountFilterValue1"
v-if="currentAmountFilterType === filterType.type"/>
<span class="ml-2 mr-2" v-if="currentAmountFilterType === filterType.type && filterType.paramCount === 2">~</span>
<span class="ms-2 me-2" v-if="currentAmountFilterType === filterType.type && filterType.paramCount === 2">~</span>
<amount-input class="transaction-amount-filter-value" density="compact"
:currency="defaultCurrency"
v-model="currentAmountFilterValue2"
v-if="currentAmountFilterType === filterType.type && filterType.paramCount === 2"/>
<v-btn class="ml-2" density="compact" color="primary" variant="tonal"
<v-btn class="ms-2" density="compact" color="primary" variant="tonal"
@click="changeAmountFilter(filterType.type)"
v-if="currentAmountFilterType === filterType.type">{{ tt('Apply') }}</v-btn>
</div>
@@ -402,7 +402,7 @@
@click="changeAccountFilter('')">
<div class="d-flex align-center">
<v-icon :icon="mdiViewGridOutline" />
<span class="text-sm ml-3">{{ tt('All') }}</span>
<span class="text-sm ms-3">{{ tt('All') }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -414,7 +414,7 @@
@click="showFilterAccountDialog = true">
<div class="d-flex align-center">
<v-icon :icon="mdiVectorArrangeBelow" />
<span class="text-sm ml-3">{{ tt('Multiple Accounts') }}</span>
<span class="text-sm ms-3">{{ tt('Multiple Accounts') }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -430,7 +430,7 @@
@click="changeAccountFilter(account.id)">
<div class="d-flex align-center">
<ItemIcon icon-type="account" size="24px" :icon-id="account.icon" :color="account.color"></ItemIcon>
<span class="text-sm ml-3">{{ account.name }}</span>
<span class="text-sm ms-3">{{ account.name }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -457,7 +457,7 @@
@click="changeTagFilter('')">
<div class="d-flex align-center">
<v-icon :icon="mdiViewGridOutline" />
<span class="text-sm ml-3">{{ tt('All') }}</span>
<span class="text-sm ms-3">{{ tt('All') }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -468,7 +468,7 @@
@click="changeTagFilter('none')">
<div class="d-flex align-center">
<v-icon :icon="mdiBorderNoneVariant" />
<span class="text-sm ml-3">{{ tt('Without Tags') }}</span>
<span class="text-sm ms-3">{{ tt('Without Tags') }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -480,7 +480,7 @@
@click="showFilterTagDialog = true">
<div class="d-flex align-center">
<v-icon :icon="mdiVectorArrangeBelow" />
<span class="text-sm ml-3">{{ tt('Multiple Tags') }}</span>
<span class="text-sm ms-3">{{ tt('Multiple Tags') }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -497,7 +497,7 @@
@click="changeTagFilterType(filterType.type)">
<div class="d-flex align-center">
<v-icon size="24" :icon="filterType.icon"/>
<span class="text-sm ml-3">{{ filterType.displayName }}</span>
<span class="text-sm ms-3">{{ filterType.displayName }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -515,7 +515,7 @@
@click="changeTagFilter(transactionTag.id)">
<div class="d-flex align-center">
<v-icon size="24" :icon="mdiPound"/>
<span class="text-sm ml-3">{{ transactionTag.name }}</span>
<span class="text-sm ms-3">{{ transactionTag.name }}</span>
</div>
</v-list-item-title>
</v-list-item>
@@ -549,7 +549,7 @@
<td :colspan="showTagInTransactionListPage ? 6 : 5" class="font-weight-bold">
<div class="d-flex align-center">
<span>{{ getDisplayLongDate(transaction) }}</span>
<v-chip class="ml-1" color="default" size="x-small"
<v-chip class="ms-1" color="default" size="x-small"
v-if="transaction.dayOfWeek">
{{ getWeekdayLongName(transaction.dayOfWeek) }}
</v-chip>
@@ -572,13 +572,13 @@
:color="transaction.category.color"
v-if="transaction.category && transaction.category.color"></ItemIcon>
<v-icon size="24" :icon="mdiPencilBoxOutline" v-else-if="!transaction.category || !transaction.category.color" />
<span class="ml-2" v-if="transaction.type === TransactionType.ModifyBalance">
<span class="ms-2" v-if="transaction.type === TransactionType.ModifyBalance">
{{ tt('Modify Balance') }}
</span>
<span class="ml-2" v-else-if="transaction.type !== TransactionType.ModifyBalance && transaction.category">
<span class="ms-2" v-else-if="transaction.type !== TransactionType.ModifyBalance && transaction.category">
{{ transaction.category.name }}
</span>
<span class="ml-2" v-else-if="transaction.type !== TransactionType.ModifyBalance && !transaction.category">
<span class="ms-2" v-else-if="transaction.type !== TransactionType.ModifyBalance && !transaction.category">
{{ getTransactionTypeName(transaction.type, 'Transaction') }}
</span>
</div>
@@ -591,7 +591,7 @@
<td class="transaction-table-column-account">
<div class="d-flex align-center">
<span v-if="transaction.sourceAccount">{{ transaction.sourceAccount.name }}</span>
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="transaction.sourceAccount && transaction.type === TransactionType.Transfer && transaction.destinationAccount && transaction.sourceAccount.id !== transaction.destinationAccount.id"></v-icon>
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="transaction.sourceAccount && transaction.type === TransactionType.Transfer && transaction.destinationAccount && transaction.sourceAccount.id !== transaction.destinationAccount.id"></v-icon>
<span v-if="transaction.sourceAccount && transaction.type === TransactionType.Transfer && transaction.destinationAccount && transaction.sourceAccount.id !== transaction.destinationAccount.id">{{ transaction.destinationAccount.name }}</span>
</div>
</td>
@@ -1828,11 +1828,11 @@ init(props);
.transaction-table .transaction-table-column-category .v-btn .v-btn__append,
.transaction-table .transaction-table-column-account .v-btn .v-btn__append {
margin-left: 0in;
margin-inline-start: 0in;
}
.transaction-table .transaction-table-column-tags .v-chip.transaction-tag {
margin-right: 4px;
margin-inline-end: 4px;
margin-top: 2px;
margin-bottom: 2px;
}

View File

@@ -5,9 +5,9 @@
<div class="d-flex align-center justify-center">
<div class="d-flex w-100 align-center justify-center">
<h4 class="text-h4">{{ tt('Import Transactions') }}</h4>
<v-progress-circular indeterminate size="22" class="ml-2" v-if="loading"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="loading"></v-progress-circular>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:icon="true" :disabled="loading || submitting"
v-if="currentStep === 'defineColumn'">
<v-icon :icon="mdiDotsVertical" />
@@ -22,7 +22,7 @@
</v-list>
</v-menu>
</v-btn>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:icon="true" :disabled="loading || submitting"
v-if="currentStep === 'checkData'">
<v-icon :icon="mdiFilterOutline" />
@@ -110,7 +110,7 @@
</v-list>
</v-menu>
</v-btn>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:icon="true" :disabled="loading || submitting"
v-if="currentStep === 'checkData'">
<v-icon :icon="mdiDotsVertical" />
@@ -281,9 +281,9 @@
<v-col cols="12" md="12" class="mb-0 pb-0" v-if="exportFileGuideDocumentUrl">
<a :href="exportFileGuideDocumentUrl" :class="{ 'disabled': submitting }" target="_blank">
<v-icon :icon="mdiHelpCircleOutline" size="16" />
<span class="ml-1" v-if="fileType === 'dsv' || fileType === 'dsv_data'">{{ tt('How to import this file?') }}</span>
<span class="ml-1" v-if="fileType !== 'dsv' && fileType !== 'dsv_data'">{{ tt('How to export this file?') }}</span>
<span class="ml-1" v-if="exportFileGuideDocumentLanguageName">[{{ exportFileGuideDocumentLanguageName }}]</span>
<span class="ms-1" v-if="fileType === 'dsv' || fileType === 'dsv_data'">{{ tt('How to import this file?') }}</span>
<span class="ms-1" v-if="fileType !== 'dsv' && fileType !== 'dsv_data'">{{ tt('How to export this file?') }}</span>
<span class="ms-1" v-if="exportFileGuideDocumentLanguageName">[{{ exportFileGuideDocumentLanguageName }}]</span>
</a>
</v-col>
</v-row>
@@ -332,10 +332,10 @@
<v-btn color="secondary" density="compact" variant="outlined"
:append-icon="parsedFileDataColumnMapping.includeHeader ? mdiCheck : mdiClose"
@click="parsedFileDataColumnMapping.toggleIncludeHeader()">{{ tt('Include Header Line') }}</v-btn>
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
:disabled="!parsedFileDataColumnMapping || !parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionType) || !parsedFileAllTransactionTypes">
<span>{{ tt('Transaction Type Mapping') }}</span>
<span class="ml-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionType) && parsedFileAllTransactionTypes">({{ getObjectOwnFieldCount(parsedFileValidMappedTransactionTypes) || tt('None') }})</span>
<span class="ms-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionType) && parsedFileAllTransactionTypes">({{ getObjectOwnFieldCount(parsedFileValidMappedTransactionTypes) || tt('None') }})</span>
<v-menu eager activator="parent" location="bottom" max-height="500"
:close-on-content-click="false">
<v-list class="pa-0">
@@ -363,10 +363,10 @@
</v-list>
</v-menu>
</v-btn>
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
:disabled="!parsedFileDataColumnMapping || !parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTime)">
<span>{{ tt('Time Format') }}</span>
<span class="ml-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTime)">({{ parsedFileDataColumnMapping.timeFormat || parsedFileAutoDetectedTimeFormat || tt('Unknown') }})</span>
<span class="ms-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTime)">({{ parsedFileDataColumnMapping.timeFormat || parsedFileAutoDetectedTimeFormat || tt('Unknown') }})</span>
<v-menu eager activator="parent" location="bottom" max-height="500">
<v-list>
<v-list-item key="auto"
@@ -374,8 +374,8 @@
@click="parsedFileDataColumnMapping.timeFormat = ''">
<v-list-item-title class="cursor-pointer">
<span>{{ tt('Auto detect') }}</span>
<span class="ml-1" v-if="parsedFileAutoDetectedTimeFormat">({{ parsedFileAutoDetectedTimeFormat }})</span>
<span class="ml-1" v-if="!parsedFileAutoDetectedTimeFormat">({{ tt('Unknown') }})</span>
<span class="ms-1" v-if="parsedFileAutoDetectedTimeFormat">({{ parsedFileAutoDetectedTimeFormat }})</span>
<span class="ms-1" v-if="!parsedFileAutoDetectedTimeFormat">({{ tt('Unknown') }})</span>
</v-list-item-title>
</v-list-item>
<v-list-item :key="dateTimeFormat.format"
@@ -389,10 +389,10 @@
</v-list>
</v-menu>
</v-btn>
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTimezone)">
<span>{{ tt('Timezone Format') }}</span>
<span class="ml-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTimezone)">({{ KnownDateTimezoneFormat.valueOf(parsedFileDataColumnMapping.timezoneFormat || parsedFileAutoDetectedTimezoneFormat || '')?.name || tt('Unknown') }})</span>
<span class="ms-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.TransactionTimezone)">({{ KnownDateTimezoneFormat.valueOf(parsedFileDataColumnMapping.timezoneFormat || parsedFileAutoDetectedTimezoneFormat || '')?.name || tt('Unknown') }})</span>
<v-menu eager activator="parent" location="bottom" max-height="500">
<v-list>
<v-list-item key="auto"
@@ -400,8 +400,8 @@
@click="parsedFileDataColumnMapping.timezoneFormat = ''">
<v-list-item-title class="cursor-pointer">
<span>{{ tt('Auto detect') }}</span>
<span class="ml-1" v-if="parsedFileAutoDetectedTimezoneFormat && KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')">({{ KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')?.name }})</span>
<span class="ml-1" v-if="!parsedFileAutoDetectedTimezoneFormat || !KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')">({{ tt('Unknown') }})</span>
<span class="ms-1" v-if="parsedFileAutoDetectedTimezoneFormat && KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')">({{ KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')?.name }})</span>
<span class="ms-1" v-if="!parsedFileAutoDetectedTimezoneFormat || !KnownDateTimezoneFormat.valueOf(parsedFileAutoDetectedTimezoneFormat || '')">({{ tt('Unknown') }})</span>
</v-list-item-title>
</v-list-item>
<v-list-item :key="timezoneFormat.value"
@@ -415,10 +415,10 @@
</v-list>
</v-menu>
</v-btn>
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
:disabled="!parsedFileDataColumnMapping || !parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.Amount)">
<span>{{ tt('Amount Format') }}</span>
<span class="ml-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.Amount)">({{ KnownAmountFormat.valueOf(parsedFileDataColumnMapping.amountFormat || parsedFileAutoDetectedAmountFormat || '')?.format || tt('Unknown') }})</span>
<span class="ms-1" v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.Amount)">({{ KnownAmountFormat.valueOf(parsedFileDataColumnMapping.amountFormat || parsedFileAutoDetectedAmountFormat || '')?.format || tt('Unknown') }})</span>
<v-menu eager activator="parent" location="bottom" max-height="500">
<v-list>
<v-list-item key="auto"
@@ -426,8 +426,8 @@
@click="parsedFileDataColumnMapping.amountFormat = ''">
<v-list-item-title class="cursor-pointer">
<span>{{ tt('Auto detect') }}</span>
<span class="ml-1" v-if="parsedFileAutoDetectedAmountFormat && KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')">({{ KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')?.format }})</span>
<span class="ml-1" v-if="!parsedFileAutoDetectedAmountFormat || !KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')">({{ tt('Unknown') }})</span>
<span class="ms-1" v-if="parsedFileAutoDetectedAmountFormat && KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')">({{ KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')?.format }})</span>
<span class="ms-1" v-if="!parsedFileAutoDetectedAmountFormat || !KnownAmountFormat.valueOf(parsedFileAutoDetectedAmountFormat || '')">({{ tt('Unknown') }})</span>
</v-list-item-title>
</v-list-item>
<v-list-item :key="amountFormat.type"
@@ -441,10 +441,10 @@
</v-list>
</v-menu>
</v-btn>
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.GeographicLocation)">
<span>{{ tt('Geographic Location Separator') }}</span>
<span class="ml-1" v-if="parsedFileDataColumnMapping.geoLocationOrder">({{ parsedFileDataColumnMapping.formatGeoLocation(tt('Latitude'), tt('Longitude')) }})</span>
<span class="ms-1" v-if="parsedFileDataColumnMapping.geoLocationOrder">({{ parsedFileDataColumnMapping.formatGeoLocation(tt('Latitude'), tt('Longitude')) }})</span>
<v-menu eager activator="parent" location="bottom" max-height="500"
:close-on-content-click="false">
<v-list class="pa-0">
@@ -475,10 +475,10 @@
</v-list>
</v-menu>
</v-btn>
<v-btn class="ml-2" color="secondary" density="compact" variant="outlined"
<v-btn class="ms-2" color="secondary" density="compact" variant="outlined"
v-if="parsedFileDataColumnMapping && parsedFileDataColumnMapping.isColumnMappingSet(ImportTransactionColumnType.Tags)">
<span>{{ tt('Transaction Tags Separator') }}</span>
<span class="ml-1" v-if="parsedFileDataColumnMapping.tagSeparator">({{ parsedFileDataColumnMapping.tagSeparator }})</span>
<span class="ms-1" v-if="parsedFileDataColumnMapping.tagSeparator">({{ parsedFileDataColumnMapping.tagSeparator }})</span>
<v-menu eager activator="parent" location="bottom" max-height="500">
<v-list>
<v-list-item :key="separator.value"
@@ -494,7 +494,7 @@
</v-btn>
<v-spacer/>
<span>{{ tt('Lines Per Page') }}</span>
<v-select class="ml-2" density="compact" max-width="100"
<v-select class="ms-2" density="compact" max-width="100"
item-title="title"
item-value="value"
:disabled="loading || submitting"
@@ -590,7 +590,7 @@
</template>
<template #item.time="{ item }">
<span>{{ getDisplayDateTime(item) }}</span>
<v-chip class="ml-1" variant="flat" color="secondary" size="x-small"
<v-chip class="ms-1" variant="flat" color="secondary" size="x-small"
v-if="item.utcOffset !== currentTimezoneOffsetMinutes">{{ getDisplayTimezone(item) }}</v-chip>
</template>
<template #item.type="{ value }">
@@ -607,11 +607,11 @@
:icon-id="allCategoriesMap[item.categoryId].icon"
:color="allCategoriesMap[item.categoryId].color"
v-if="item.type !== TransactionType.ModifyBalance && item.categoryId && item.categoryId !== '0' && allCategoriesMap[item.categoryId]"></ItemIcon>
<span class="ml-2" v-if="item.type !== TransactionType.ModifyBalance && item.categoryId && item.categoryId !== '0' && allCategoriesMap[item.categoryId]">
<span class="ms-2" v-if="item.type !== TransactionType.ModifyBalance && item.categoryId && item.categoryId !== '0' && allCategoriesMap[item.categoryId]">
{{ allCategoriesMap[item.categoryId].name }}
</span>
<div class="text-error font-italic" v-else-if="item.type !== TransactionType.ModifyBalance && (!item.categoryId || item.categoryId === '0' || !allCategoriesMap[item.categoryId])">
<v-icon class="mr-1" :icon="mdiAlertOutline"/>
<v-icon class="me-1" :icon="mdiAlertOutline"/>
<span>{{ item.originalCategoryName }}</span>
</div>
</div>
@@ -672,20 +672,20 @@
</template>
<template #item.sourceAmount="{ item }">
<span>{{ getTransactionDisplayAmount(item) }}</span>
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId"></v-icon>
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId"></v-icon>
<span v-if="item.type === TransactionType.Transfer && item.sourceAccountId !== item.destinationAccountId">{{ getTransactionDisplayDestinationAmount(item) }}</span>
</template>
<template #item.actualSourceAccountName="{ item }">
<div class="d-flex align-center" v-if="editingTransaction !== item">
<span v-if="item.sourceAccountId && item.sourceAccountId !== '0' && allAccountsMap[item.sourceAccountId]">{{ allAccountsMap[item.sourceAccountId].name }}</span>
<div class="text-error font-italic" v-else>
<v-icon class="mr-1" :icon="mdiAlertOutline"/>
<v-icon class="me-1" :icon="mdiAlertOutline"/>
<span>{{ item.originalSourceAccountName }}</span>
</div>
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
<span v-if="item.type === TransactionType.Transfer && item.destinationAccountId && item.destinationAccountId !== '0' && allAccountsMap[item.destinationAccountId]">{{allAccountsMap[item.destinationAccountId].name }}</span>
<div class="text-error font-italic" v-else-if="item.type === TransactionType.Transfer && (!item.destinationAccountId || item.destinationAccountId === '0' || !allAccountsMap[item.destinationAccountId])">
<v-icon class="mr-1" :icon="mdiAlertOutline"/>
<v-icon class="me-1" :icon="mdiAlertOutline"/>
<span>{{ item.originalDestinationAccountName }}</span>
</div>
</div>
@@ -706,7 +706,7 @@
:items="allVisibleCategorizedAccounts"
v-model="item.sourceAccountId">
</two-column-select>
<v-icon class="mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
<v-icon class="icon-with-direction mx-1" size="13" :icon="mdiArrowRight" v-if="item.type === TransactionType.Transfer"></v-icon>
<two-column-select density="compact" variant="plain"
primary-key-field="id" primary-value-field="category"
primary-title-field="name" primary-footer-field="displayBalance"
@@ -790,7 +790,7 @@
</span>
<v-spacer/>
<span>{{ tt('Transactions Per Page') }}</span>
<v-select class="ml-2" density="compact" max-width="100"
<v-select class="ms-2" density="compact" max-width="100"
item-title="title"
item-value="value"
:disabled="loading || submitting"
@@ -815,17 +815,19 @@
<v-btn color="secondary" variant="tonal" :disabled="loading || submitting"
:prepend-icon="mdiClose" @click="close(false)"
v-if="currentStep !== 'finalResult'">{{ tt('Cancel') }}</v-btn>
<v-btn color="primary" :disabled="loading || submitting || (!isImportDataFromTextbox && !importFile) || (isImportDataFromTextbox && !importData)"
<v-btn class="button-icon-with-direction" color="primary"
:disabled="loading || submitting || (!isImportDataFromTextbox && !importFile) || (isImportDataFromTextbox && !importData)"
:append-icon="!submitting ? mdiArrowRight : undefined" @click="parseData"
v-if="currentStep === 'defineColumn' || currentStep === 'uploadFile'">
{{ tt('Next') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
</v-btn>
<v-btn color="teal" :disabled="submitting || !!editingTransaction || selectedImportTransactionCount < 1 || selectedInvalidTransactionCount > 0"
<v-btn class="button-icon-with-direction" color="teal"
:disabled="submitting || !!editingTransaction || selectedImportTransactionCount < 1 || selectedInvalidTransactionCount > 0"
:append-icon="!submitting ? mdiArrowRight : undefined" @click="submit"
v-if="currentStep === 'checkData'">
{{ (submitting && importProcess > 0 ? tt('format.misc.importingTransactions', { process: formatNumberToLocalizedNumerals(importProcess, 2) }) : tt('Import')) }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
</v-btn>
<v-btn color="secondary" variant="tonal"
:append-icon="mdiCheck"
@@ -2748,7 +2750,7 @@ defineExpose({
}
.import-transaction-table .v-chip.transaction-tag {
margin-right: 4px;
margin-inline-end: 4px;
margin-top: 2px;
margin-bottom: 2px;
}

View File

@@ -9,7 +9,7 @@
<h4 class="text-h4" v-if="type === 'transferCategory'">{{ tt('Create Nonexistent Transfer Categories') }}</h4>
<h4 class="text-h4" v-if="type === 'tag'">{{ tt('Create Nonexistent Transaction Tags') }}</h4>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:disabled="submitting || !invalidItems || !invalidItems.length" :icon="true">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -53,7 +53,7 @@
<div class="w-100 d-flex justify-center gap-4">
<v-btn :disabled="submitting || !selectedNames || !selectedNames.length" @click="confirm">
{{ tt('OK') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
</v-btn>
<v-btn color="secondary" variant="tonal" :disabled="submitting" @click="cancel">{{ tt('Cancel') }}</v-btn>
</div>

View File

@@ -6,7 +6,7 @@
<div class="d-flex w-100 align-center justify-center">
<h4 class="text-h4">{{ tt('Batch Replace Categories / Accounts / Tags') }}</h4>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :disabled="loading"
class="ms-2" :icon="true" :disabled="loading"
:loading="loading" @click="reload">
<template #loader>
<v-progress-circular indeterminate size="20"/>
@@ -15,7 +15,7 @@
<v-tooltip activator="parent">{{ tt('Refresh') }}</v-tooltip>
</v-btn>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
:icon="true" :disabled="loading">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent" max-height="500">

View File

@@ -14,7 +14,7 @@
<h4 class="text-h4" v-if="mode === 'replaceInvalidItems' && type === 'account'">{{ tt('Replace Invalid Accounts') }}</h4>
<h4 class="text-h4" v-if="mode === 'replaceInvalidItems' && type === 'tag'">{{ tt('Replace Invalid Transaction Tags') }}</h4>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :disabled="loading"
class="ms-2" :icon="true" :disabled="loading"
:loading="loading" @click="reload">
<template #loader>
<v-progress-circular indeterminate size="20"/>

View File

@@ -5,9 +5,9 @@
<div class="d-flex align-center justify-center">
<div class="d-flex w-100 align-center justify-center">
<h4 class="text-h4">{{ tt(title) }}</h4>
<v-progress-circular indeterminate size="22" class="ml-2" v-if="loading"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="loading"></v-progress-circular>
</div>
<v-btn density="comfortable" color="default" variant="text" class="ml-2" :icon="true"
<v-btn density="comfortable" color="default" variant="text" class="ms-2" :icon="true"
:disabled="loading || submitting" v-if="mode !== TransactionEditPageMode.View && (activeTab === 'basicInfo' || (activeTab === 'map' && isSupportGetGeoLocationByClick()))">
<v-icon :icon="mdiDotsVertical" />
<v-menu activator="parent">
@@ -80,7 +80,7 @@
</v-tabs>
</div>
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container ml-md-5"
<v-window class="d-flex flex-grow-1 disable-tab-transition w-100-window-container ms-md-5"
v-model="activeTab">
<v-window-item value="basicInfo">
<v-form class="mt-2">
@@ -454,7 +454,7 @@
<v-btn :disabled="inputIsEmpty || loading || submitting"
v-if="mode !== TransactionEditPageMode.View" @click="save">
{{ tt(saveButtonTitle) }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
</v-btn>
</div>
</template>
@@ -485,7 +485,7 @@
<v-btn color="error" variant="tonal" :disabled="loading || submitting"
v-if="mode === TransactionEditPageMode.View && originalTransactionEditable" @click="remove">
{{ tt('Delete') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="submitting"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
</v-btn>
<v-btn color="secondary" variant="tonal" :disabled="loading || submitting"
@click="cancel">{{ tt(cancelButtonTitle) }}</v-btn>

View File

@@ -42,7 +42,7 @@
<div ref="buttonContainer" class="w-100 d-flex justify-center gap-4">
<v-btn :disabled="generating || !currentPassword" @click="generateToken" v-if="!generatedToken">
{{ tt('Generate') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="generating"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="generating"></v-progress-circular>
</v-btn>
<v-btn color="secondary" variant="tonal" :disabled="generating"
@click="cancel" v-if="!generatedToken">{{ tt('Cancel') }}</v-btn>

View File

@@ -4,7 +4,7 @@
<v-card :class="{ 'disabled': loading || saving }">
<template #title>
<span>{{ tt('Basic Settings') }}</span>
<v-progress-circular indeterminate size="20" class="ml-3" v-if="loading"></v-progress-circular>
<v-progress-circular indeterminate size="20" class="ms-3" v-if="loading"></v-progress-circular>
</template>
<v-card-text class="d-flex">
@@ -38,10 +38,10 @@
<div class="d-flex text-body-1 align-center" style="height: 40px;">
<span v-if="!loading && emailVerified">{{ tt('Email address is verified') }}</span>
<span v-if="!loading && !emailVerified">{{ tt('Email address is not verified') }}</span>
<v-btn class="ml-2 px-2" size="small" variant="text" :disabled="loading || resending"
<v-btn class="ms-2 px-2" size="small" variant="text" :disabled="loading || resending"
@click="resendVerifyEmail" v-if="isUserVerifyEmailEnabled() && !loading && !emailVerified">
{{ tt('Resend Validation Email') }}
<v-progress-circular indeterminate size="18" class="ml-2" v-if="resending"></v-progress-circular>
<v-progress-circular indeterminate size="18" class="ms-2" v-if="resending"></v-progress-circular>
</v-btn>
<v-skeleton-loader class="skeleton-no-margin mt-2 mb-1" type="text" style="width: 160px" :loading="true" v-if="loading"></v-skeleton-loader>
</div>
@@ -351,7 +351,7 @@
<v-card-text class="d-flex flex-wrap gap-4">
<v-btn :disabled="inputIsNotChanged || inputIsInvalid || saving" @click="save">
{{ tt('Save Changes') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="saving"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="saving"></v-progress-circular>
</v-btn>
<v-btn color="default" variant="tonal" @click="reset">

View File

@@ -6,7 +6,7 @@
<div class="d-flex align-center">
<span>{{ tt('Data Management') }}</span>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :loading="loadingDataStatistics" @click="reloadUserDataStatistics(true)">
class="ms-2" :icon="true" :loading="loadingDataStatistics" @click="reloadUserDataStatistics(true)">
<template #loader>
<v-progress-circular indeterminate size="20"/>
</template>
@@ -91,7 +91,7 @@
<v-btn-group variant="elevated" density="comfortable" color="primary">
<v-btn :disabled="loadingDataStatistics || exportingData || !dataStatistics || !dataStatistics.totalTransactionCount || dataStatistics.totalTransactionCount === '0'">
{{ tt('Export Data') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="exportingData"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="exportingData"></v-progress-circular>
<v-menu activator="parent">
<v-list :disabled="loadingDataStatistics || exportingData || !dataStatistics || !dataStatistics.totalTransactionCount || dataStatistics.totalTransactionCount === '0'">
<v-list-item @click="exportData('csv')">
@@ -143,7 +143,7 @@
<v-card-text class="d-flex flex-wrap gap-4">
<v-btn color="error" :disabled="loadingDataStatistics || !currentPasswordForClearData || clearingData" @click="clearData">
{{ tt('Clear User Data') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="clearingData"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="clearingData"></v-progress-circular>
</v-btn>
</v-card-text>
</v-form>

View File

@@ -56,7 +56,7 @@
<v-card-text class="d-flex flex-wrap gap-4">
<v-btn :disabled="!currentPassword || !newPassword || !confirmPassword || updatingPassword" @click="updatePassword">
{{ tt('Save Changes') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="updatingPassword"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="updatingPassword"></v-progress-circular>
</v-btn>
</v-card-text>
</v-form>
@@ -68,10 +68,10 @@
<template #title>
<div class="d-flex align-center">
<span>{{ tt('Device & Sessions') }}</span>
<v-btn class="ml-3" density="compact" color="default" variant="outlined"
<v-btn class="ms-3" density="compact" color="default" variant="outlined"
@click="generateMCPToken" v-if="isMCPServerEnabled()">{{ tt('Generate MCP token') }}</v-btn>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :loading="loadingSession" @click="reloadSessions(false)">
class="ms-2" :icon="true" :loading="loadingSession" @click="reloadSessions(false)">
<template #loader>
<v-progress-circular indeterminate size="20"/>
</template>

View File

@@ -4,7 +4,7 @@
<v-card :class="{ 'disabled': loading }">
<template #title>
<span>{{ tt('Two-Factor Authentication') }}</span>
<v-progress-circular indeterminate size="20" class="ml-3" v-if="loading"></v-progress-circular>
<v-progress-circular indeterminate size="20" class="ms-3" v-if="loading"></v-progress-circular>
</template>
<v-card-text class="pb-0">
@@ -57,19 +57,19 @@
<v-col cols="12" class="d-flex flex-wrap gap-4">
<v-btn :disabled="!currentPassword || loading || disabling " v-if="status === true" @click="disable">
{{ tt('Disable Two-Factor Authentication') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="disabling"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="disabling"></v-progress-circular>
</v-btn>
<v-btn :disabled="!currentPassword || loading || regenerating" v-if="status === true" @click="regenerateBackupCode()">
{{ tt('Regenerate Backup Codes') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="regenerating"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="regenerating"></v-progress-circular>
</v-btn>
<v-btn :disabled="loading || enabling" v-if="status === false && !new2FAQRCode" @click="enable">
{{ tt('Enable Two-Factor Authentication') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="enabling"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="enabling"></v-progress-circular>
</v-btn>
<v-btn :disabled="!currentPasscode || loading || enableConfirming" v-if="status === false && new2FAQRCode" @click="enableConfirm">
{{ tt('Continue') }}
<v-progress-circular indeterminate size="22" class="ml-2" v-if="enableConfirming"></v-progress-circular>
<v-progress-circular indeterminate size="22" class="ms-2" v-if="enableConfirming"></v-progress-circular>
</v-btn>
</v-col>
</v-row>
@@ -82,7 +82,7 @@
<template #title>
<span>{{ tt('Backup Code') }}</span>
<v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" @click="copyBackupCodes">
class="ms-2" :icon="true" @click="copyBackupCodes">
<v-icon :icon="mdiContentCopy" size="20" />
<v-tooltip activator="parent">{{ tt('Copy') }}</v-tooltip>
</v-btn>