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:
Matt 2025-07-04 10:44:42 -04:00
parent e66d6ad1f2
commit 2774b4050f
5 changed files with 96 additions and 62 deletions

View File

@ -253,7 +253,7 @@ const downloadAllReceipts = async () => {
}
.modal-content {
@apply bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-hidden;
@apply bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-hidden mx-4 sm:mx-0;
}
.modal-header {

View File

@ -22,8 +22,8 @@
</div>
</div>
<!-- Expense Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- Expense Grid - Mobile optimized -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4">
<div
v-for="expense in expenses"
:key="expense.Id"

View File

@ -255,7 +255,7 @@ watch(() => props.modelValue, (isOpen) => {
}
.modal-content {
@apply bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full max-h-[90vh] overflow-hidden;
@apply bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full max-h-[90vh] overflow-hidden mx-4 sm:mx-0;
}
.modal-header {

View File

@ -258,7 +258,7 @@ watch(() => props.modelValue, (isOpen) => {
}
.modal-content {
@apply bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-4xl w-full max-h-[90vh] overflow-hidden;
@apply bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-4xl w-full max-h-[90vh] overflow-hidden mx-2 sm:mx-4;
}
.modal-header {

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'));