Improve mobile responsiveness across expense tracking interface

- Add horizontal margins to modals on mobile devices
- Optimize grid layouts with smaller breakpoints (md→sm)
- Make action buttons full-width on mobile with touch optimization
- Adjust text sizes and spacing for better mobile readability
- Enhance date filter and export controls for mobile interaction
This commit is contained in:
2025-07-04 10:44:42 -04:00
parent e66d6ad1f2
commit 2774b4050f
5 changed files with 96 additions and 62 deletions

View File

@@ -1,88 +1,123 @@
<template>
<div class="container mx-auto px-4 py-6">
<!-- Header with Actions -->
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-6 gap-4">
<div class="flex flex-col gap-4 mb-6">
<div>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">
<h1 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-white">
Expense Tracking
</h1>
<p class="text-gray-600 dark:text-gray-300 mt-1">
<p class="text-sm sm:text-base text-gray-600 dark:text-gray-300 mt-1">
Track and manage expense receipts with smart grouping and export options
</p>
</div>
<div class="flex flex-col sm:flex-row gap-3">
<!-- Export Actions -->
<!-- Mobile-optimized export buttons -->
<div class="flex flex-col sm:flex-row gap-2 sm:gap-3 w-full sm:w-auto">
<button
@click="exportCSV"
:disabled="loading || selectedExpenses.length === 0"
class="btn btn-outline btn-sm"
class="btn btn-outline btn-sm sm:btn-md w-full sm:w-auto touch-manipulation"
>
<Icon name="mdi:file-excel" class="w-4 h-4" />
Export CSV
<span class="hidden xs:inline">Export </span>CSV
</button>
<button
@click="showPDFModal = true"
:disabled="loading || selectedExpenses.length === 0"
class="btn btn-primary btn-sm"
class="btn btn-primary btn-sm sm:btn-md w-full sm:w-auto touch-manipulation"
>
<Icon name="mdi:file-pdf" class="w-4 h-4" />
Generate PDF
<span class="hidden xs:inline">Generate </span>PDF
</button>
</div>
</div>
<!-- Date Range Filter -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4 mb-6">
<div class="flex flex-col sm:flex-row gap-4 items-end">
<div class="flex-1">
<label class="label">
<span class="label-text">Start Date</span>
</label>
<input
v-model="filters.startDate"
type="date"
class="input input-bordered w-full"
@change="fetchExpenses"
/>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-3 sm:p-4 mb-6">
<div class="flex flex-col gap-3 sm:gap-4">
<!-- Mobile: Stack date inputs in first row -->
<div class="grid grid-cols-2 sm:flex sm:flex-row gap-3 sm:gap-4">
<div class="flex-1">
<label class="label">
<span class="label-text text-xs sm:text-sm">Start Date</span>
</label>
<input
v-model="filters.startDate"
type="date"
class="input input-bordered input-sm sm:input-md w-full text-sm"
@change="fetchExpenses"
/>
</div>
<div class="flex-1">
<label class="label">
<span class="label-text text-xs sm:text-sm">End Date</span>
</label>
<input
v-model="filters.endDate"
type="date"
class="input input-bordered input-sm sm:input-md w-full text-sm"
@change="fetchExpenses"
/>
</div>
<!-- Category and button on larger screens -->
<div class="hidden sm:block flex-1">
<label class="label">
<span class="label-text">Category</span>
</label>
<select
v-model="filters.category"
class="select select-bordered w-full"
@change="fetchExpenses"
>
<option value="">All Categories</option>
<option value="Food/Drinks">Food/Drinks</option>
<option value="Shop">Shop</option>
<option value="Online">Online</option>
<option value="Other">Other</option>
</select>
</div>
<div class="hidden sm:flex items-end">
<button
@click="resetToCurrentMonth"
class="btn btn-ghost btn-sm"
>
Current Month
</button>
</div>
</div>
<div class="flex-1">
<label class="label">
<span class="label-text">End Date</span>
</label>
<input
v-model="filters.endDate"
type="date"
class="input input-bordered w-full"
@change="fetchExpenses"
/>
<!-- Mobile: Category and button in second row -->
<div class="flex gap-3 sm:hidden">
<div class="flex-1">
<label class="label">
<span class="label-text text-xs">Category</span>
</label>
<select
v-model="filters.category"
class="select select-bordered select-sm w-full text-sm"
@change="fetchExpenses"
>
<option value="">All Categories</option>
<option value="Food/Drinks">Food/Drinks</option>
<option value="Shop">Shop</option>
<option value="Online">Online</option>
<option value="Other">Other</option>
</select>
</div>
<div class="flex items-end">
<button
@click="resetToCurrentMonth"
class="btn btn-ghost btn-sm text-xs px-2"
>
Current Month
</button>
</div>
</div>
<div class="flex-1">
<label class="label">
<span class="label-text">Category</span>
</label>
<select
v-model="filters.category"
class="select select-bordered w-full"
@change="fetchExpenses"
>
<option value="">All Categories</option>
<option value="Food/Drinks">Food/Drinks</option>
<option value="Shop">Shop</option>
<option value="Online">Online</option>
<option value="Other">Other</option>
</select>
</div>
<button
@click="resetToCurrentMonth"
class="btn btn-ghost btn-sm"
>
Current Month
</button>
</div>
</div>
@@ -224,9 +259,8 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import type { Expense } from '@/utils/types';
import { groupExpensesByPayer } from '@/server/utils/nocodb';
// Component imports (to be created)
// Component imports
const ExpenseList = defineAsyncComponent(() => import('@/components/ExpenseList.vue'));
const PDFOptionsModal = defineAsyncComponent(() => import('@/components/PDFOptionsModal.vue'));
const ExpenseDetailsModal = defineAsyncComponent(() => import('@/components/ExpenseDetailsModal.vue'));