feat(mobile): compare table scroll fade and native share sheet
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 12s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 48s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 14s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s

MOB-14: PerformanceChart and ComparisonChart both already configure
legend position 'top' — no change needed.

MOB-15: Compare's detailedTable is 774px wide inside an overflow-x:
auto wrapper. Add a right-edge mask-image fade at ≤640px so phone
users see the table extends past the viewport.

MOB-16: ComparisonView's Share button previously did clipboard-only.
Prefer navigator.share when available (iOS/Android native sheet) so
users can send straight to Messages / WhatsApp / Mail / etc. Fall
back to clipboard with the existing "Copied!" toast otherwise. User
cancellations swallow silently; only real errors trigger fallback.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Tudor Sitaru
2026-05-19 09:40:23 +01:00
parent 59f13a74f9
commit 56ab1368b1
2 changed files with 31 additions and 1 deletions
@@ -306,6 +306,15 @@
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
} }
/* Right-edge fade so phone users see the comparison table scrolls.
Otherwise the wider-than-viewport table silently clips. */
@media (max-width: 640px) {
.tableWrapper {
-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
}
}
.comparisonTable { .comparisonTable {
width: 100%; width: 100%;
border-collapse: separate; border-collapse: separate;
+22 -1
View File
@@ -157,8 +157,29 @@ export function ComparisonView({
}; };
const handleShare = async () => { const handleShare = async () => {
const url = window.location.href;
const count = selectedSchools.length;
const shareData = {
title: 'School comparison · SchoolCompare',
text: count > 0
? `Comparing ${count} school${count === 1 ? '' : 's'} on SchoolCompare`
: 'SchoolCompare',
url,
};
// Prefer the native share sheet on platforms that support it (iOS / Android).
// canShare is feature-detected because Safari iOS exposes share() but
// some configurations refuse the payload.
if (typeof navigator !== 'undefined' && navigator.share && (!navigator.canShare || navigator.canShare(shareData))) {
try {
await navigator.share(shareData);
return;
} catch (err) {
// User cancelled — bail silently. Any other error falls through to clipboard.
if ((err as DOMException)?.name === 'AbortError') return;
}
}
try { try {
await navigator.clipboard.writeText(window.location.href); await navigator.clipboard.writeText(url);
setShareConfirm(true); setShareConfirm(true);
setTimeout(() => setShareConfirm(false), 2000); setTimeout(() => setShareConfirm(false), 2000);
} catch { /* fallback: do nothing */ } } catch { /* fallback: do nothing */ }