diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index 78d2587..39f8399 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -317,6 +317,7 @@ input:focus-visible { position: sticky; top: 0; z-index: 2; + touch-action: pan-y; min-height: 70px; display: flex; align-items: center; diff --git a/apps/web/src/views/LedgerView.vue b/apps/web/src/views/LedgerView.vue index 7be2994..135604c 100644 --- a/apps/web/src/views/LedgerView.vue +++ b/apps/web/src/views/LedgerView.vue @@ -39,6 +39,7 @@ const ledgerContent = ref(null); const loadMoreTrigger = ref(null); const monthInput = ref(null); const selectedMonth = ref(toMonthValue(new Date())); +const monthSwipeStart = ref<{ x: number; y: number } | null>(null); let loadMoreObserver: IntersectionObserver | null = null; const selectedMonthParts = computed(() => { @@ -155,6 +156,28 @@ function openMonthPicker() { else input.click(); } +function startMonthSwipe(event: TouchEvent) { + const touch = event.touches[0]; + if (touch) monthSwipeStart.value = { x: touch.clientX, y: touch.clientY }; +} + +function finishMonthSwipe(event: TouchEvent) { + const start = monthSwipeStart.value; + const touch = event.changedTouches[0]; + monthSwipeStart.value = null; + if (!start || !touch) return; + const deltaX = touch.clientX - start.x; + const deltaY = touch.clientY - start.y; + if (Math.abs(deltaX) < 48 || Math.abs(deltaX) <= Math.abs(deltaY)) return; + shiftMonth(deltaX < 0 ? 1 : -1); +} + +function shiftMonth(offset: number) { + const selected = selectedMonthParts.value; + if (!selected) return; + selectedMonth.value = toMonthValue(new Date(selected.year, selected.month + offset, 1)); +} + function dateHeading(value: string) { const date = new Date(`${value}T00:00:00`); const today = new Date(); @@ -321,7 +344,7 @@ async function shareLedger() { {{ pendingConversionCount }} 条外币账目等待换算 -
+