use the same code for page scrolling on both the desktop and mobile versions

This commit is contained in:
MaysWind
2025-12-21 02:34:35 +08:00
parent 931d5e8395
commit a535fbcef1
20 changed files with 197 additions and 255 deletions
+2 -2
View File
@@ -50,7 +50,7 @@ import type { ColorValue, ColorInfo } from '@/core/color.ts';
import { arrayContainsFieldValue } from '@/lib/common.ts';
import { getColorsInRows, getDisplayColor } from '@/lib/color.ts';
import { scrollToSelectedItem } from '@/lib/ui/desktop.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import {
mdiSquareRounded,
@@ -90,7 +90,7 @@ function onMenuStateChanged(state: boolean): void {
if (state) {
nextTick(() => {
if (dropdownMenu.value && dropdownMenu.value.parentElement) {
scrollToSelectedItem(dropdownMenu.value.parentElement, null, '.row-has-selected-item');
scrollToSelectedItem(dropdownMenu.value.parentElement, null, null, '.row-has-selected-item');
}
});
}
+2 -2
View File
@@ -48,7 +48,7 @@ import type { ColorValue } from '@/core/color.ts';
import type { IconInfo, IconInfoWithId } from '@/core/icon.ts';
import { arrayContainsFieldValue } from '@/lib/common.ts';
import { getIconsInRows } from '@/lib/icon.ts';
import { scrollToSelectedItem } from '@/lib/ui/desktop.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import {
mdiCheck
@@ -89,7 +89,7 @@ function onMenuStateChanged(state: boolean): void {
if (state) {
nextTick(() => {
if (dropdownMenu.value && dropdownMenu.value.parentElement) {
scrollToSelectedItem(dropdownMenu.value.parentElement, null, '.row-has-selected-item');
scrollToSelectedItem(dropdownMenu.value.parentElement, null, null, '.row-has-selected-item');
}
});
}
@@ -67,7 +67,7 @@ import { useUserStore } from '@/stores/user.ts';
import { type WeekDayValue } from '@/core/datetime.ts';
import { ScheduledTemplateFrequencyType } from '@/core/template.ts';
import { sortNumbersArray } from '@/lib/common.ts';
import { scrollToSelectedItem } from '@/lib/ui/desktop.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
const props = defineProps<CommonScheduleFrequencySelectionProps>();
const emit = defineEmits<{
@@ -159,7 +159,7 @@ function onMenuStateChanged(state: boolean): void {
if (state) {
nextTick(() => {
if (dropdownMenu.value && dropdownMenu.value.parentElement) {
scrollToSelectedItem(dropdownMenu.value.parentElement, '.schedule-frequency-value-container', '.frequency-value-selected');
scrollToSelectedItem(dropdownMenu.value.parentElement, '.schedule-frequency-value-container', '.schedule-frequency-value-container', '.frequency-value-selected');
}
});
}
+4 -3
View File
@@ -102,7 +102,8 @@ import {
getItemByKeyValue,
getNameByKeyValue
} from '@/lib/common.ts';
import { type ComponentDensity, type InputVariant, setChildInputFocus, scrollToSelectedItem } from '@/lib/ui/desktop.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import { type ComponentDensity, type InputVariant, setChildInputFocus } from '@/lib/ui/desktop.ts';
import {
mdiChevronRight,
@@ -246,8 +247,8 @@ function onMenuStateChanged(state: boolean): void {
if (state) {
nextTick(() => {
if (dropdownMenu.value && dropdownMenu.value.parentElement) {
scrollToSelectedItem(dropdownMenu.value.parentElement, '.primary-list-container', '.primary-list-item-selected');
scrollToSelectedItem(dropdownMenu.value.parentElement, '.secondary-list-container', '.secondary-list-item-selected');
scrollToSelectedItem(dropdownMenu.value.parentElement, '.primary-list-container', '.primary-list-container', '.primary-list-item-selected');
scrollToSelectedItem(dropdownMenu.value.parentElement, '.secondary-list-container', '.secondary-list-container', '.secondary-list-item-selected');
}
});
}
@@ -33,7 +33,8 @@ import { ref, computed } from 'vue';
import type { ColorValue, ColorInfo } from '@/core/color.ts';
import { arrayContainsFieldValue } from '@/lib/common.ts';
import { getColorsInRows } from '@/lib/color.ts';
import { type Framework7Dom, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import { type Framework7Dom } from '@/lib/ui/mobile.ts';
const props = defineProps<{
modelValue: ColorValue;
@@ -63,7 +64,7 @@ function hasSelectedIcon(row: ColorInfo[]): boolean {
function onSheetOpen(event: { $el: Framework7Dom }): void {
currentValue.value = props.modelValue;
scrollToSelectedItem(event.$el, '.page-content', '.row-has-selected-item');
scrollToSelectedItem(event.$el[0], '.sheet-modal-inner', '.page-content', '.row-has-selected-item');
}
function onSheetClosed(): void {
+3 -2
View File
@@ -33,7 +33,8 @@ import { ref, computed } from 'vue';
import type { IconInfo, IconInfoWithId } from '@/core/icon.ts';
import { arrayContainsFieldValue } from '@/lib/common.ts';
import { getIconsInRows } from '@/lib/icon.ts';
import { type Framework7Dom, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import { type Framework7Dom } from '@/lib/ui/mobile.ts';
const props = defineProps<{
modelValue: string;
@@ -73,7 +74,7 @@ function hasSelectedIcon(row: IconInfoWithId[]): boolean {
}
function onSheetOpen(event: { $el: Framework7Dom }): void {
scrollToSelectedItem(event.$el, '.page-content', '.row-has-selected-item');
scrollToSelectedItem(event.$el[0], '.sheet-modal-inner', '.page-content', '.row-has-selected-item');
}
function onSheetClosed(): void {
@@ -56,7 +56,8 @@ import type { Searchbar } from 'framework7/types';
import { useI18n } from '@/locales/helpers.ts';
import { type Framework7Dom, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import { type Framework7Dom } from '@/lib/ui/mobile.ts';
const props = defineProps<{
modelValue: unknown;
@@ -186,7 +187,7 @@ function onItemClicked(item: unknown, index: number): void {
function onPopupOpen(event: { $el: Framework7Dom }): void {
currentValue.value = props.modelValue;
scrollToSelectedItem(event.$el, '.page-content', 'li.list-item-selected', false);
scrollToSelectedItem(event.$el[0], '.popup > .page', '.page-content', 'li.list-item-selected');
}
function onPopupClosed(): void {
@@ -36,7 +36,8 @@ import { ref, computed } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import { type Framework7Dom, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import { type Framework7Dom } from '@/lib/ui/mobile.ts';
const props = defineProps<{
modelValue: unknown;
@@ -117,7 +118,7 @@ function onItemClicked(item: unknown, index: number): void {
function onSheetOpen(event: { $el: Framework7Dom }): void {
currentValue.value = props.modelValue;
scrollToSelectedItem(event.$el, '.page-content', 'li.list-item-selected');
scrollToSelectedItem(event.$el[0], '.sheet-modal-inner', '.page-content', 'li.list-item-selected');
}
function onSheetClosed(): void {
@@ -76,7 +76,8 @@ import { itemAndIndex } from '@/core/base.ts';
import { type WeekDayValue } from '@/core/datetime.ts';
import { ScheduledTemplateFrequencyType } from '@/core/template.ts';
import { sortNumbersArray } from '@/lib/common.ts';
import { type Framework7Dom, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import { type Framework7Dom } from '@/lib/ui/mobile.ts';
interface MobileScheduleFrequencySelectionProps extends CommonScheduleFrequencySelectionProps {
show: boolean;
@@ -151,7 +152,7 @@ function close(): void {
function onSheetOpen(event: { $el: Framework7Dom }): void {
currentFrequencyType.value = props.type;
currentFrequencyValue.value = getFrequencyValues(props.modelValue);
scrollToSelectedItem(event.$el, '.schedule-frequency-value-container', 'li.list-item-selected');
scrollToSelectedItem(event.$el[0], '.schedule-frequency-value-container', '.schedule-frequency-value-container', 'li.list-item-selected');
}
function onSheetClosed(): void {
@@ -94,7 +94,8 @@ import { useI18nUIComponents, showLoading, hideLoading } from '@/lib/ui/mobile.t
import { TransactionTag } from '@/models/transaction_tag.ts';
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
import { type Framework7Dom, scrollToSelectedItem, scrollSheetToTop } from '@/lib/ui/mobile.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import { type Framework7Dom, scrollSheetToTop } from '@/lib/ui/mobile.ts';
const props = defineProps<{
modelValue: string[];
@@ -229,7 +230,7 @@ function onSearchBarFocus(): void {
function onSheetOpen(event: { $el: Framework7Dom }): void {
selectedItemIds.value = Array.from(props.modelValue);
newTag.value = null;
scrollToSelectedItem(event.$el, '.page-content', 'li.list-item-selected');
scrollToSelectedItem(event.$el[0], '.sheet-modal-inner', '.page-content', 'li.list-item-selected');
}
function onSheetClosed(): void {
@@ -19,7 +19,7 @@
<f7-list class="no-margin-top no-margin-bottom" v-if="!filteredItems || !filteredItems.length">
<f7-list-item :title="filterNoItemsText"></f7-list-item>
</f7-list>
<f7-treeview>
<f7-treeview class="tree-view-selection-treeview">
<f7-treeview-item item-toggle
:opened="isPrimaryItemHasSecondaryValue(item)"
:label="ti((primaryTitleField ? item[primaryTitleField] : item) as string, !!primaryTitleI18n)"
@@ -54,7 +54,8 @@ import type { Sheet, Searchbar } from 'framework7/types';
import { useI18n } from '@/locales/helpers.ts';
import { type TwoLevelItemSelectionBaseProps, useTwoLevelItemSelectionBase } from '@/components/base/TwoLevelItemSelectionBase.ts';
import { type Framework7Dom, scrollToSelectedItem, scrollSheetToTop } from '@/lib/ui/mobile.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import { type Framework7Dom, scrollSheetToTop } from '@/lib/ui/mobile.ts';
interface MobileTwoLevelItemSelectionBaseProps extends TwoLevelItemSelectionBaseProps {
show: boolean;
@@ -137,7 +138,7 @@ function onSearchBarFocus(): void {
function onSheetOpen(event: { $el: Framework7Dom }): void {
currentValue.value = props.modelValue;
scrollToSelectedItem(event.$el, '.page-content', '.treeview-item .treeview-item-selected');
scrollToSelectedItem(event.$el[0], '.sheet-modal-inner', '.page-content', '.treeview-item > .treeview-item-selected');
}
function onSheetClosed(): void {
@@ -168,4 +169,8 @@ function onSheetClosed(): void {
height: 320px;
}
}
.tree-view-selection-treeview {
position: relative;
}
</style>
@@ -75,7 +75,8 @@ import type { Sheet, Searchbar } from 'framework7/types';
import { useI18n } from '@/locales/helpers.ts';
import { type CommonTwoColumnListItemSelectionProps, useTwoColumnListItemSelectionBase } from '@/components/base/TwoColumnListItemSelectionBase.ts';
import { type Framework7Dom, scrollToSelectedItem, scrollSheetToTop } from '@/lib/ui/mobile.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import { type Framework7Dom, scrollSheetToTop } from '@/lib/ui/mobile.ts';
interface MobileTwoColumnListItemSelectionProps extends CommonTwoColumnListItemSelectionProps {
show: boolean;
@@ -135,8 +136,8 @@ function onSearchBarFocus(): void {
function onSheetOpen(event: { $el: Framework7Dom }): void {
currentPrimaryValue.value = getCurrentPrimaryValueBySecondaryValue(props.modelValue);
currentSecondaryValue.value = props.modelValue;
scrollToSelectedItem(event.$el, '.primary-list-container', 'li.primary-list-item-selected');
scrollToSelectedItem(event.$el, '.secondary-list-container', 'li.secondary-list-item-selected');
scrollToSelectedItem(event.$el[0], '.primary-list-container', '.primary-list-container', 'li.primary-list-item-selected');
scrollToSelectedItem(event.$el[0], '.secondary-list-container', '.secondary-list-container', 'li.secondary-list-item-selected');
}
function onSheetClosed(): void {
+53
View File
@@ -7,6 +7,59 @@ import { KnownFileType } from '@/core/file.ts';
import logger from '../logger.ts';
export function scrollToSelectedItem(parentEl: Element | null | undefined, containerSelector: string | null, scrollableListSelector: string | null, selectedItemSelector: string): void {
if (!parentEl) {
return;
}
const container = containerSelector ? parentEl.querySelector<HTMLElement>(containerSelector) : parentEl;
if (!container) {
return;
}
const scrollableList = scrollableListSelector ? parentEl.querySelector<HTMLElement>(scrollableListSelector) : parentEl;
if (!scrollableList) {
return;
}
const selectedItems = scrollableList.querySelectorAll<HTMLElement>(selectedItemSelector);
if (!selectedItems.length) {
return;
}
const containerHeight: number = container.clientHeight;
const firstSelectedItem: HTMLElement = selectedItems[0] as HTMLElement;
const lastSelectedItem: HTMLElement = selectedItems[selectedItems.length - 1] as HTMLElement;
const firstSelectedItemHeight: number = firstSelectedItem.offsetHeight;
const firstSelectedItemTop: number = firstSelectedItem.offsetTop;
const lastSelectedItemTop: number = lastSelectedItem.offsetTop;
const lastSelectedItemBottom: number = lastSelectedItem.offsetTop + lastSelectedItem.offsetHeight;
const middle: number = (firstSelectedItemTop + lastSelectedItemBottom) / 2;
let targetScrollTop: number = middle - containerHeight / 2;
if (containerSelector !== scrollableListSelector) {
const scrollableListStyle = window.getComputedStyle(scrollableList);
const paddingTop: number = parseFloat(scrollableListStyle.paddingTop) || 0;
targetScrollTop += paddingTop / 3 * 2;
if (selectedItems.length > 1 && lastSelectedItemTop - firstSelectedItemTop > containerHeight - firstSelectedItemHeight - paddingTop) {
targetScrollTop = firstSelectedItemTop;
}
} else {
if (selectedItems.length > 1 && lastSelectedItemTop - firstSelectedItemTop > containerHeight - firstSelectedItemHeight) {
targetScrollTop = firstSelectedItemTop;
}
}
scrollableList.scrollTop = Math.max(0, targetScrollTop);
}
export function getSystemTheme(): ThemeType {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return ThemeType.Dark;
-63
View File
@@ -39,15 +39,6 @@ export function getNavSideBarOuterHeight(element: HTMLElement | null): number {
return totalHeight;
}
export function getCssValue(element: HTMLElement | null, name: string): string {
if (!element) {
return '0';
}
const computedStyle = window.getComputedStyle(element);
return computedStyle.getPropertyValue(name);
}
export function setChildInputFocus(parentEl: HTMLElement | undefined, childSelector: string): void {
if (!parentEl) {
return;
@@ -63,57 +54,3 @@ export function setChildInputFocus(parentEl: HTMLElement | undefined, childSelec
childInput.focus();
childInput.select();
}
export function scrollToSelectedItem(parentEl: HTMLElement | null | undefined, containerSelector: string | null, selectedItemSelector: string): void {
if (!parentEl) {
return;
}
let container = parentEl;
if (containerSelector) {
const lists = parentEl.querySelectorAll(containerSelector);
if (!lists.length || !lists[0]) {
return;
}
container = lists[0] as HTMLElement;
}
const selectedItems = container.querySelectorAll(selectedItemSelector);
if (!selectedItems.length || !selectedItems[0]) {
return;
}
const selectedItem = selectedItems[0] as HTMLElement;
const containerOuterHeight = getOuterHeight(container);
const selectedItemOuterHeight = getOuterHeight(selectedItem);
let targetPos = selectedItem.offsetTop - container.offsetTop - parseInt(getCssValue(container, 'padding-top'), 10)
- (containerOuterHeight - selectedItemOuterHeight) / 2;
if (selectedItems.length > 1) {
const firstSelectedItem = selectedItems[0] as HTMLElement;
const lastSelectedItem = selectedItems[selectedItems.length - 1] as HTMLElement;
const firstSelectedItemInTop = firstSelectedItem.offsetTop - container.offsetTop - parseInt(getCssValue(container, 'padding-top'), 10);
const lastSelectedItemInTop = lastSelectedItem.offsetTop - container.offsetTop - parseInt(getCssValue(container, 'padding-top'), 10);
const lastSelectedItemInBottom = lastSelectedItem.offsetTop - container.offsetTop - parseInt(getCssValue(container, 'padding-top'), 10)
- (containerOuterHeight - selectedItemOuterHeight);
targetPos = (firstSelectedItemInTop + lastSelectedItemInBottom) / 2;
if (lastSelectedItemInTop - firstSelectedItemInTop > containerOuterHeight) {
targetPos = firstSelectedItemInTop;
}
}
if (targetPos <= 0) {
return;
}
container.scrollTop = targetPos;
}
-46
View File
@@ -6,7 +6,6 @@ import { useI18n } from '@/locales/helpers.ts';
import { TextDirection } from '@/core/text.ts';
import { FontSize, FONT_SIZE_PREVIEW_CLASSNAME_PREFIX } from '@/core/font.ts';
import { getNumberValue } from '../common.ts';
import { isEnableAnimate } from '../settings.ts';
export interface Framework7Dom {
@@ -148,51 +147,6 @@ export function getElementBoundingRect(selector: string): DOMRect | null {
return el.getBoundingClientRect();
}
export function scrollToSelectedItem(parentEl: Framework7Dom, containerSelector: string, selectedItemSelector: string, hasBottomToolbar?: boolean): void {
if (!parentEl || !parentEl.length) {
return;
}
const container = parentEl.find(containerSelector);
const selectedItem = parentEl.find(selectedItemSelector);
if (!container.length || !selectedItem.length) {
return;
}
const containerPaddingTop = getNumberValue(container.css('padding-top'), 0) / 2;
let targetPos = selectedItem.offset().top - container.offset().top - containerPaddingTop
- (container.outerHeight() - selectedItem.outerHeight()) / 2;
if (selectedItem.length > 1) {
const firstSelectedItem = f7.$(selectedItem[0]);
const lastSelectedItem = f7.$(selectedItem[selectedItem.length - 1]);
const firstSelectedItemInTop = firstSelectedItem.offset().top - container.offset().top - containerPaddingTop;
const lastSelectedItemInTop = lastSelectedItem.offset().top - container.offset().top - containerPaddingTop;
const lastSelectedItemInBottom = lastSelectedItem.offset().top - container.offset().top - containerPaddingTop
- (container.outerHeight() - firstSelectedItem.outerHeight());
targetPos = (firstSelectedItemInTop + lastSelectedItemInBottom) / 2;
if (lastSelectedItemInTop - firstSelectedItemInTop > container.outerHeight()) {
targetPos = firstSelectedItemInTop;
}
}
if (targetPos <= 0) {
return;
}
if (hasBottomToolbar) {
const toolbarHeight = parentEl.find('.toolbar.toolbar-bottom').outerHeight() || 0;
targetPos += toolbarHeight / 2;
}
container.scrollTop(targetPos);
}
export function scrollSheetToTop(sheetElement: HTMLElement | undefined, windowNormalInnerHeight: number): void {
if (!sheetElement) {
return;
+2 -4
View File
@@ -135,6 +135,8 @@ i.icon.la, i.icon.las, i.icon.lab {
}
.ios .popover-inner {
touch-action: inherit;
> :not(.list) {
display: none;
}
@@ -222,10 +224,6 @@ i.icon.la, i.icon.las, i.icon.lab {
.lang-popover-menu .popover-inner {
max-height: 350px;
> .list {
overflow-y: auto;
}
}
.lang-popover-menu .popover-inner .item-title {
+2 -3
View File
@@ -711,8 +711,7 @@ import {
transactionTypeToCategoryType
} from '@/lib/category.ts';
import { isDataExportingEnabled, isDataImportingEnabled, isTransactionFromAIImageRecognitionEnabled } from '@/lib/server_settings.ts';
import { startDownloadFile } from '@/lib/ui/common.ts';
import { scrollToSelectedItem } from '@/lib/ui/desktop.ts';
import { scrollToSelectedItem, startDownloadFile } from '@/lib/ui/common.ts';
import logger from '@/lib/logger.ts';
import {
@@ -1696,7 +1695,7 @@ function scrollTagMenuToSelectedItem(opened: boolean): void {
function scrollMenuToSelectedItem(menu: VMenu | null): void {
nextTick(() => {
scrollToSelectedItem(menu?.contentEl, 'div.v-list', 'div.v-list-item.list-item-selected');
scrollToSelectedItem(menu?.contentEl, 'div.v-list', 'div.v-list', 'div.v-list-item.list-item-selected');
});
}
+1 -4
View File
@@ -440,9 +440,6 @@ init();
.template-popover-menu .popover-inner {
max-height: 400px;
> .list {
overflow-y: auto;
}
overflow-y: auto;
}
</style>
+43 -51
View File
@@ -16,51 +16,45 @@
<f7-popover class="chart-data-type-popover-menu"
@popover:open="scrollPopoverToSelectedItem">
<f7-list dividers>
<f7-list-group>
<f7-list-item group-title>
<small>{{ tt('Categorical Analysis') }}</small>
</f7-list-item>
<f7-list-item link="#" no-chevron popover-close
:title="tt(dataType.name)"
:class="{ 'list-item-selected': analysisType === StatisticsAnalysisType.CategoricalAnalysis && query.chartDataType === dataType.type }"
:key="dataType.type"
v-for="dataType in ChartDataType.values(StatisticsAnalysisType.CategoricalAnalysis)"
@click="setChartDataType(StatisticsAnalysisType.CategoricalAnalysis, dataType.type)">
<template #after>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="analysisType === StatisticsAnalysisType.CategoricalAnalysis && query.chartDataType === dataType.type"></f7-icon>
</template>
</f7-list-item>
</f7-list-group>
<f7-list-group>
<f7-list-item group-title>
<small>{{ tt('Trend Analysis') }}</small>
</f7-list-item>
<f7-list-item link="#" no-chevron popover-close
:title="tt(dataType.name)"
:class="{ 'list-item-selected': analysisType === StatisticsAnalysisType.TrendAnalysis && query.chartDataType === dataType.type }"
:key="dataType.type"
v-for="dataType in ChartDataType.values(StatisticsAnalysisType.TrendAnalysis)"
@click="setChartDataType(StatisticsAnalysisType.TrendAnalysis, dataType.type)">
<template #after>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="analysisType === StatisticsAnalysisType.TrendAnalysis && query.chartDataType === dataType.type"></f7-icon>
</template>
</f7-list-item>
</f7-list-group>
<f7-list-group>
<f7-list-item group-title>
<small>{{ tt('Asset Trends') }}</small>
</f7-list-item>
<f7-list-item link="#" no-chevron popover-close
:title="tt(dataType.name)"
:class="{ 'list-item-selected': analysisType === StatisticsAnalysisType.AssetTrends && query.chartDataType === dataType.type }"
:key="dataType.type"
v-for="dataType in ChartDataType.values(StatisticsAnalysisType.AssetTrends)"
@click="setChartDataType(StatisticsAnalysisType.AssetTrends, dataType.type)">
<template #after>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="analysisType === StatisticsAnalysisType.AssetTrends && query.chartDataType === dataType.type"></f7-icon>
</template>
</f7-list-item>
</f7-list-group>
<f7-list-item group-title>
<small>{{ tt('Categorical Analysis') }}</small>
</f7-list-item>
<f7-list-item link="#" no-chevron popover-close
:title="tt(dataType.name)"
:class="{ 'list-item-selected': analysisType === StatisticsAnalysisType.CategoricalAnalysis && query.chartDataType === dataType.type }"
:key="dataType.type"
v-for="dataType in ChartDataType.values(StatisticsAnalysisType.CategoricalAnalysis)"
@click="setChartDataType(StatisticsAnalysisType.CategoricalAnalysis, dataType.type)">
<template #after>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="analysisType === StatisticsAnalysisType.CategoricalAnalysis && query.chartDataType === dataType.type"></f7-icon>
</template>
</f7-list-item>
<f7-list-item group-title>
<small>{{ tt('Trend Analysis') }}</small>
</f7-list-item>
<f7-list-item link="#" no-chevron popover-close
:title="tt(dataType.name)"
:class="{ 'list-item-selected': analysisType === StatisticsAnalysisType.TrendAnalysis && query.chartDataType === dataType.type }"
:key="dataType.type"
v-for="dataType in ChartDataType.values(StatisticsAnalysisType.TrendAnalysis)"
@click="setChartDataType(StatisticsAnalysisType.TrendAnalysis, dataType.type)">
<template #after>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="analysisType === StatisticsAnalysisType.TrendAnalysis && query.chartDataType === dataType.type"></f7-icon>
</template>
</f7-list-item>
<f7-list-item group-title>
<small>{{ tt('Asset Trends') }}</small>
</f7-list-item>
<f7-list-item link="#" no-chevron popover-close
:title="tt(dataType.name)"
:class="{ 'list-item-selected': analysisType === StatisticsAnalysisType.AssetTrends && query.chartDataType === dataType.type }"
:key="dataType.type"
v-for="dataType in ChartDataType.values(StatisticsAnalysisType.AssetTrends)"
@click="setChartDataType(StatisticsAnalysisType.AssetTrends, dataType.type)">
<template #after>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="analysisType === StatisticsAnalysisType.AssetTrends && query.chartDataType === dataType.type"></f7-icon>
</template>
</f7-list-item>
</f7-list>
</f7-popover>
@@ -437,7 +431,8 @@ import {
getDateTypeByDateRange,
getDateRangeByDateType
} from '@/lib/datetime.ts';
import { type Framework7Dom, useI18nUIComponents, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import { type Framework7Dom, useI18nUIComponents } from '@/lib/ui/mobile.ts';
const props = defineProps<{
f7router: Router.Router;
@@ -884,7 +879,7 @@ function settings(): void {
}
function scrollPopoverToSelectedItem(event: { $el: Framework7Dom }): void {
scrollToSelectedItem(event.$el, '.popover-inner', 'li.list-item-selected');
scrollToSelectedItem(event.$el[0], '.popover-inner', '.popover-inner', 'li.list-item-selected');
}
function onClickPieChartItem(item: Record<string, unknown>): void {
@@ -949,9 +944,6 @@ init();
.chart-data-type-popover-menu .popover-inner {
max-height: 440px;
> .list {
overflow-y: auto;
}
overflow-y: auto;
}
</style>
+56 -57
View File
@@ -339,7 +339,7 @@
@update:modelValue="changeCustomMonthDateFilter">
</month-selection-sheet>
<f7-popover class="category-popover-menu" @popover:open="onPopoverOpen">
<f7-popover class="category-popover-menu" @popover:open="onCategoryPopoverOpen">
<f7-list dividers accordion-list>
<f7-list-item link="#" no-chevron popover-close
:class="{ 'list-item-selected': !query.categoryIds }"
@@ -364,57 +364,55 @@
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="query.categoryIds && queryAllFilterCategoryIdsCount > 1"></f7-icon>
</template>
</f7-list-item>
</f7-list>
<f7-list dividers accordion-list
class="no-margin-vertical"
:key="categoryType"
v-for="(categories, categoryType) in allPrimaryCategories"
v-show="categories && categories.length"
>
<f7-list-item divider :title="getTransactionTypeName(categoryTypeToTransactionType(parseInt(categoryType)), 'Type')"></f7-list-item>
<f7-list-item accordion-item
:title="category.name"
:class="getCategoryListItemCheckedClass(category, queryAllFilterCategoryIds)"
:key="category.id"
v-for="category in categories"
v-show="!category.hidden || queryAllFilterCategoryIds[category.id] || allCategories[query.categoryIds]?.parentId === category.id || hasSubCategoryInQuery(category)"
>
<template #media>
<ItemIcon icon-type="category" :icon-id="category.icon" :color="category.color"></ItemIcon>
<template :key="categoryType"
v-for="(categories, categoryType) in allPrimaryCategories">
<template v-if="categories && categories.length">
<f7-list-item divider :title="getTransactionTypeName(categoryTypeToTransactionType(parseInt(categoryType)), 'Type')"></f7-list-item>
<f7-list-item accordion-item
:title="category.name"
:class="getCategoryListItemCheckedClass(category, queryAllFilterCategoryIds)"
:key="category.id"
v-for="category in categories"
v-show="!category.hidden || queryAllFilterCategoryIds[category.id] || allCategories[query.categoryIds]?.parentId === category.id || hasSubCategoryInQuery(category)"
>
<template #media>
<ItemIcon icon-type="category" :icon-id="category.icon" :color="category.color"></ItemIcon>
</template>
<f7-accordion-content>
<f7-list dividers class="padding-inline-start">
<f7-list-item link="#" no-chevron popover-close
:class="{ 'list-item-selected': query.categoryIds === category.id, 'item-in-multiple-selection': queryAllFilterCategoryIdsCount > 1 && queryAllFilterCategoryIds[category.id] }"
:title="tt('All')" @click="changeCategoryFilter(category.id)">
<template #media>
<f7-icon f7="rectangle_grid_2x2"></f7-icon>
</template>
<template #after>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="query.categoryIds === category.id"></f7-icon>
</template>
</f7-list-item>
<f7-list-item link="#" no-chevron popover-close
:class="{ 'list-item-selected': query.categoryIds === subCategory.id, 'item-in-multiple-selection': queryAllFilterCategoryIdsCount > 1 && queryAllFilterCategoryIds[subCategory.id] }"
:title="subCategory.name"
:key="subCategory.id"
v-for="subCategory in category.subCategories"
v-show="!subCategory.hidden || queryAllFilterCategoryIds[subCategory.id]"
@click="changeCategoryFilter(subCategory.id)"
>
<template #media>
<ItemIcon icon-type="category" :icon-id="subCategory.icon" :color="subCategory.color"></ItemIcon>
</template>
<template #after>
<f7-icon class="list-item-checked-icon"
f7="checkmark_alt"
v-if="query.categoryIds === subCategory.id">
</f7-icon>
</template>
</f7-list-item>
</f7-list>
</f7-accordion-content>
</f7-list-item>
</template>
<f7-accordion-content>
<f7-list dividers class="padding-inline-start">
<f7-list-item link="#" no-chevron popover-close
:class="{ 'list-item-selected': query.categoryIds === category.id, 'item-in-multiple-selection': queryAllFilterCategoryIdsCount > 1 && queryAllFilterCategoryIds[category.id] }"
:title="tt('All')" @click="changeCategoryFilter(category.id)">
<template #media>
<f7-icon f7="rectangle_grid_2x2"></f7-icon>
</template>
<template #after>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="query.categoryIds === category.id"></f7-icon>
</template>
</f7-list-item>
<f7-list-item link="#" no-chevron popover-close
:class="{ 'list-item-selected': query.categoryIds === subCategory.id, 'item-in-multiple-selection': queryAllFilterCategoryIdsCount > 1 && queryAllFilterCategoryIds[subCategory.id] }"
:title="subCategory.name"
:key="subCategory.id"
v-for="subCategory in category.subCategories"
v-show="!subCategory.hidden || queryAllFilterCategoryIds[subCategory.id]"
@click="changeCategoryFilter(subCategory.id)"
>
<template #media>
<ItemIcon icon-type="category" :icon-id="subCategory.icon" :color="subCategory.color"></ItemIcon>
</template>
<template #after>
<f7-icon class="list-item-checked-icon"
f7="checkmark_alt"
v-if="query.categoryIds === subCategory.id">
</f7-icon>
</template>
</f7-list-item>
</f7-list>
</f7-accordion-content>
</f7-list-item>
</template>
</f7-list>
</f7-popover>
@@ -598,6 +596,7 @@ import { ref, computed, nextTick, onMounted, onUnmounted } from 'vue';
import type { Router } from 'framework7/types';
import { useI18n } from '@/locales/helpers.ts';
import { scrollToSelectedItem } from '@/lib/ui/common.ts';
import {
type Framework7Dom,
useI18nUIComponents,
@@ -606,7 +605,6 @@ import {
onSwipeoutDeleted,
getElementActualHeights,
getElementBoundingRect,
scrollToSelectedItem,
onInfiniteScrolling
} from '@/lib/ui/mobile.ts';
import { TransactionListPageType, useTransactionListPageBase } from '@/views/base/transactions/TransactionListPageBase.ts';
@@ -1440,7 +1438,11 @@ function collapseTransactionMonthList(monthList: TransactionMonthList, collapse:
}
function onPopoverOpen(event: { $el: Framework7Dom }): void {
scrollToSelectedItem(event.$el, '.popover-inner', 'li.list-item-selected');
scrollToSelectedItem(event.$el[0], '.popover-inner', '.popover-inner', 'li.list-item-selected');
}
function onCategoryPopoverOpen(event: { $el: Framework7Dom }): void {
scrollToSelectedItem(event.$el[0], '.popover-inner', '.popover-inner', 'li.list-item-checked');
}
function onPageAfterIn(): void {
@@ -1604,10 +1606,7 @@ html[dir="rtl"] .list.transaction-info-list li.transaction-info .transaction-foo
.account-popover-menu .popover-inner,
.more-popover-menu .popover-inner {
max-height: 400px;
> .list {
overflow-y: auto;
}
overflow-y: auto;
}
.transaction-calendar-container .dp__theme_light,