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
+22 -1
View File
@@ -157,8 +157,29 @@ export function ComparisonView({
};
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 {
await navigator.clipboard.writeText(window.location.href);
await navigator.clipboard.writeText(url);
setShareConfirm(true);
setTimeout(() => setShareConfirm(false), 2000);
} catch { /* fallback: do nothing */ }