fix: Comprehensive mobile UI improvements and fixes

Interest Table Mobile Layout:
- Fixed broken table layout on mobile screens
- Optimized column widths to fit mobile viewports better
- Improved horizontal scrolling with visual indicators
- Enhanced responsive design for contact information display
- Better badge sizing and text truncation on mobile

 Mobile Actions Enhancement:
- Added delete interest button to mobile actions section
- Improved button layout in 2x2 grid for better accessibility
- Added proper loading states and disabled states
- Enhanced visual hierarchy with icons and labels

 Email Communication Fixes:
- Fixed refresh email button icon display on mobile
- Added proper mobile styling and tooltips
- Made button more accessible with larger touch targets

 Email Thread Width Issues:
- Fixed email threads exceeding screen width on mobile
- Implemented proper text wrapping and overflow handling
- Optimized timeline layout for mobile viewports
- Enhanced email card responsiveness
- Better handling of long email addresses and content
- Improved expansion panel sizing and spacing

 Mobile UX Improvements:
- Better touch targets and button sizing
- Improved visual feedback and loading states
- Enhanced text readability with optimized font sizes
- Consistent mobile spacing and padding throughout
- Fixed container overflow issues across components

All mobile components now properly respect viewport constraints and provide optimal user experience on mobile devices.
This commit is contained in:
Matt 2025-06-12 17:14:14 +02:00
parent 41a6f7f1c8
commit 8ec6c883ab
3 changed files with 190 additions and 20 deletions

View File

@ -5,12 +5,18 @@
Email History Email History
<v-spacer /> <v-spacer />
<v-btn <v-btn
icon="mdi-refresh" :icon="mobile ? undefined : 'mdi-refresh'"
size="small" :size="mobile ? 'default' : 'small'"
variant="text" variant="text"
@click="loadEmails" @click="loadEmails"
:loading="loading" :loading="loading"
/> :class="mobile ? 'rounded-circle' : ''"
>
<v-icon v-if="!loading">mdi-refresh</v-icon>
<v-tooltip v-if="mobile" activator="parent" location="bottom">
Refresh emails
</v-tooltip>
</v-btn>
</v-card-title> </v-card-title>
<v-card-text> <v-card-text>
<div v-if="loading && threads.length === 0" class="text-center py-8"> <div v-if="loading && threads.length === 0" class="text-center py-8">
@ -147,6 +153,7 @@ const emit = defineEmits<{
const user = useDirectusUser(); const user = useDirectusUser();
const toast = useToast(); const toast = useToast();
const { mobile } = useDisplay();
const loading = ref(false); const loading = ref(false);
const threads = ref<EmailThread[]>([]); const threads = ref<EmailThread[]>([]);
@ -287,4 +294,109 @@ defineExpose({
font-size: 0.875rem; font-size: 0.875rem;
line-height: 1.5; line-height: 1.5;
} }
/* Mobile-specific styles */
@media (max-width: 768px) {
/* Fix container width on mobile */
:deep(.v-card) {
max-width: 100vw;
overflow-x: hidden;
}
/* Ensure card text doesn't exceed screen width */
:deep(.v-card-text) {
padding: 8px 12px !important;
overflow-x: hidden;
}
/* Fix expansion panel width */
:deep(.v-expansion-panels) {
width: 100%;
max-width: calc(100vw - 24px);
}
/* Timeline adjustments for mobile */
:deep(.v-timeline) {
padding-left: 8px !important;
padding-right: 8px !important;
}
:deep(.v-timeline-item) {
margin-bottom: 12px !important;
}
/* Email card adjustments */
:deep(.v-timeline-item .v-card) {
max-width: calc(100vw - 80px);
overflow-x: hidden;
}
/* Email content width constraints */
:deep(.v-card-title) {
font-size: 0.875rem !important;
padding: 8px 12px !important;
word-break: break-word;
}
:deep(.v-card-subtitle) {
font-size: 0.75rem !important;
padding: 4px 12px !important;
word-break: break-all;
overflow-wrap: break-word;
}
:deep(.v-card-text) {
padding: 8px 12px !important;
font-size: 0.875rem !important;
}
/* Fix pre-formatted text width */
.email-full pre {
font-size: 0.75rem !important;
white-space: pre-wrap;
word-break: break-word;
overflow-wrap: break-word;
max-width: 100%;
}
/* Thread title adjustments */
:deep(.v-expansion-panel-title) {
padding: 12px !important;
min-height: 48px !important;
}
:deep(.v-expansion-panel-title .font-weight-medium) {
font-size: 0.875rem !important;
word-break: break-word;
overflow-wrap: break-word;
}
:deep(.v-expansion-panel-title .text-caption) {
font-size: 0.75rem !important;
}
/* Timeline opposite content (timestamps) */
:deep(.v-timeline-item .v-timeline-item__opposite) {
max-width: 60px;
font-size: 0.7rem !important;
padding-right: 4px;
}
/* Compact email actions */
:deep(.v-card-actions) {
padding: 4px 8px !important;
min-height: 40px !important;
}
:deep(.v-card-actions .v-btn) {
font-size: 0.75rem !important;
height: 32px !important;
}
}
/* Ensure text wrapping for long email addresses */
:deep(.v-card-subtitle) {
white-space: normal !important;
line-height: 1.3;
}
</style> </style>

View File

@ -194,14 +194,35 @@
<span class="text-caption">Request Info</span> <span class="text-caption">Request Info</span>
</v-btn> </v-btn>
</v-col> </v-col>
<v-col cols="12"> <v-col cols="6">
<v-btn
@click="confirmDelete"
variant="outlined"
color="error"
block
:loading="isDeleting"
:disabled="
isRequestingMoreInfo ||
isRequestingMoreInformation ||
isSendingEOI ||
isSaving ||
isDeleting
"
class="mb-2 d-flex flex-column"
size="large"
>
<v-icon size="large" class="mb-1">mdi-delete</v-icon>
<span class="text-caption">Delete</span>
</v-btn>
</v-col>
<v-col cols="6">
<v-btn <v-btn
@click="() => debouncedSaveInterest ? debouncedSaveInterest() : saveInterest()" @click="() => debouncedSaveInterest ? debouncedSaveInterest() : saveInterest()"
variant="flat" variant="flat"
color="success" color="success"
block block
:loading="isSaving" :loading="isSaving"
:disabled="isSaving" :disabled="isSaving || isDeleting"
class="mb-2 d-flex flex-column" class="mb-2 d-flex flex-column"
size="large" size="large"
> >

View File

@ -588,58 +588,78 @@ const getRelativeTime = (dateString: string) => {
position: relative; position: relative;
overflow-x: auto; overflow-x: auto;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
/* Remove negative margins to prevent cutoff */ margin: 0 -16px; /* Extend to screen edge */
padding: 0 16px; /* Add padding back */
} }
/* Add padding to the wrapper instead */ /* Add padding to the wrapper instead */
.modern-table :deep(.v-table__wrapper) { .modern-table :deep(.v-table__wrapper) {
min-width: 600px; /* Minimum width to ensure scrolling */ min-width: 400px; /* Reduced minimum width for mobile */
} }
.modern-table :deep(th) { .modern-table :deep(th) {
padding: 8px !important; padding: 8px 4px !important;
font-size: 0.75rem; font-size: 0.75rem;
white-space: nowrap; white-space: nowrap;
} }
.modern-table :deep(td) { .modern-table :deep(td) {
padding: 12px 8px !important; padding: 12px 4px !important;
vertical-align: middle;
} }
/* Show all columns but with smaller widths on mobile */ /* Optimize mobile column widths to fit better */
.modern-table :deep(th:nth-child(1)), .modern-table :deep(th:nth-child(1)),
.modern-table :deep(td:nth-child(1)) { .modern-table :deep(td:nth-child(1)) {
min-width: 180px !important; min-width: 220px !important; /* Contact info needs more space */
max-width: 220px !important;
} }
.modern-table :deep(th:nth-child(2)), .modern-table :deep(th:nth-child(2)),
.modern-table :deep(td:nth-child(2)) { .modern-table :deep(td:nth-child(2)) {
min-width: 120px !important; min-width: 100px !important;
max-width: 100px !important;
} }
.modern-table :deep(th:nth-child(3)), .modern-table :deep(th:nth-child(3)),
.modern-table :deep(td:nth-child(3)) { .modern-table :deep(td:nth-child(3)) {
min-width: 100px !important; min-width: 80px !important;
max-width: 80px !important;
} }
/* Contact cell optimization */ /* Contact cell optimization */
.contact-cell { .contact-cell {
max-width: 180px; max-width: 220px;
padding: 8px 4px !important;
} }
.contact-cell .text-truncate { .contact-cell .text-truncate {
max-width: 140px; max-width: 160px;
}
.contact-cell .v-avatar {
margin-right: 8px !important;
flex-shrink: 0;
} }
/* Adjust table row height on mobile */ /* Adjust table row height on mobile */
.table-row td { .table-row td {
padding: 12px 8px !important; padding: 8px 4px !important;
height: auto !important;
min-height: 60px;
} }
/* Ensure badges are sized appropriately */ /* Ensure badges are sized appropriately */
.modern-table :deep(.v-chip) { .modern-table :deep(.v-chip) {
height: 20px !important; height: 18px !important;
font-size: 0.625rem !important; font-size: 0.625rem !important;
padding: 0 6px !important;
}
/* Style the date column to be more compact */
.modern-table :deep(td:nth-child(3) .text-caption) {
font-size: 0.6rem !important;
line-height: 1.2;
} }
/* Add visual scroll indicators */ /* Add visual scroll indicators */
@ -647,11 +667,28 @@ const getRelativeTime = (dateString: string) => {
content: ''; content: '';
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 16px;
bottom: 0; bottom: 0;
width: 30px; width: 20px;
background: linear-gradient(to right, transparent, rgba(255,255,255,0.8)); background: linear-gradient(to right, transparent, rgba(255,255,255,0.9));
pointer-events: none; pointer-events: none;
z-index: 1;
}
/* Fix container padding */
.v-container {
padding: 12px 16px !important;
}
/* Improve mobile row layout */
.modern-table :deep(tbody tr) {
height: auto !important;
}
/* Better text overflow handling */
.modern-table :deep(td) {
word-break: break-word;
overflow-wrap: break-word;
} }
} }