fix(mobile): stop detail-page grids from overflowing horizontally

The spot page (and the other detail pages) used `grid lg:grid-cols-3` with
no explicit mobile column. Below the `lg` breakpoint the grid falls back to
a single implicit `auto` track, whose minimum is the min-content of its
items. A long mapper name ("Tip the Mapper" card) gave the sidebar a
~559px min-content, so the whole grid widened past the viewport and was
clipped by the global `html, body { overflow-x: hidden }` — content cut off
on the right with no way to scroll to it.

Fixes:
- Add `grid-cols-1` to detail-page grids so the mobile track is
  `minmax(0, 1fr)` and can never exceed the container. Applied to Spot,
  Shop, Event, NIP-19, Crew and Coach detail pages.
- Add `min-w-0` to their sidebar/main columns so long content can shrink
  and truncate instead of forcing the track wider.
- Make the Spot Chat header wrap (`flex-wrap` + `gap-y`) so the trust
  filter and channel badge no longer get clipped on narrow phones.
This commit is contained in:
Igor Bubelov 2026-09-26 13:33:42 +07:00 committed by SkateSpots
parent 07e844e0fb
commit 571257e5c3
7 changed files with 30 additions and 30 deletions

View file

@ -206,8 +206,8 @@ export function SpotChat({
return (
<Card className={cn('flex flex-col overflow-hidden', className)}>
<CardHeader className="pb-3 border-b">
<div className="flex items-center justify-between gap-3">
<CardTitle className="text-lg flex items-center gap-2">
<div className="flex flex-wrap items-center justify-between gap-x-3 gap-y-2">
<CardTitle className="text-lg flex flex-wrap items-center gap-2 min-w-0">
<MessageCircle className="h-5 w-5 text-orange-500" />
Spot Chat
<Badge
@ -219,7 +219,7 @@ export function SpotChat({
Public
</Badge>
</CardTitle>
<div className="flex items-center gap-2">
<div className="flex flex-wrap items-center gap-2">
<TrustFilter value={trustLevel} onChange={setTrustLevel} compact />
<Badge variant="secondary" className="font-mono text-[10px] gap-1">
<Radio className="h-3 w-3" />#{channel}

View file

@ -56,8 +56,8 @@ function CoachDetailSkeleton() {
<Layout>
<div className="container px-4 py-8 max-w-4xl">
<Skeleton className="h-6 w-32 mb-6" />
<div className="grid md:grid-cols-3 gap-6">
<div className="md:col-span-2 space-y-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="md:col-span-2 space-y-6 min-w-0">
<Card>
<CardContent className="pt-6">
<div className="flex items-start gap-4">
@ -220,9 +220,9 @@ export default function CoachDetailPage() {
Back to The Lab
</Link>
<div className="grid md:grid-cols-3 gap-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{/* Main Content */}
<div className="md:col-span-2 space-y-6">
<div className="md:col-span-2 space-y-6 min-w-0">
{/* Confirm-membership prompt (only for listed pending members) */}
{isCollective && (
<ConfirmMembershipCard
@ -477,7 +477,7 @@ export default function CoachDetailPage() {
</div>
{/* Sidebar */}
<div className="space-y-6">
<div className="space-y-6 min-w-0">
{/* Contact Card */}
<Card className="bg-black/90 border-2 border-[#ccff00]/50">
<CardHeader>

View file

@ -230,8 +230,8 @@ export default function CrewDetailPage() {
<Layout>
<div className="container px-4 py-8 max-w-4xl">
<Skeleton className="h-6 w-32 mb-6" />
<div className="grid md:grid-cols-3 gap-6">
<div className="md:col-span-2 space-y-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="md:col-span-2 space-y-6 min-w-0">
<Skeleton className="h-48 w-full" />
<Skeleton className="h-64 w-full" />
</div>
@ -256,9 +256,9 @@ export default function CrewDetailPage() {
Back to Crews
</Link>
<div className="grid md:grid-cols-3 gap-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{/* Main */}
<div className="md:col-span-2 space-y-6">
<div className="md:col-span-2 space-y-6 min-w-0">
{/* Confirm membership prompt (listed pending members only) */}
{hasMembers && (
<ConfirmMembershipCard
@ -416,7 +416,7 @@ export default function CrewDetailPage() {
</div>
{/* Sidebar — ordered: leadership → who → support → band → connections → founder */}
<div className="space-y-6">
<div className="space-y-6 min-w-0">
{/* Leadership — team leader (founder) + captains (admins) */}
<CrewLeadership crew={crew} confirmedAdmins={confirmedAdmins} rolesByPubkey={rolesByPubkey} />

View file

@ -56,8 +56,8 @@ function EventDetailSkeleton() {
return (
<Layout>
<div className="container px-4 py-8">
<div className="grid lg:grid-cols-3 gap-8">
<div className="lg:col-span-2 space-y-6">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
<div className="lg:col-span-2 space-y-6 min-w-0">
<Skeleton className="aspect-video w-full rounded-xl" />
<div className="space-y-4">
<Skeleton className="h-10 w-3/4" />
@ -69,7 +69,7 @@ function EventDetailSkeleton() {
<Skeleton className="h-24 w-full" />
</div>
</div>
<div className="space-y-6">
<div className="space-y-6 min-w-0">
<Skeleton className="h-48 w-full rounded-xl" />
<Skeleton className="h-32 w-full rounded-xl" />
</div>
@ -321,9 +321,9 @@ export default function EventDetailPage() {
</div>
)}
<div className="grid lg:grid-cols-3 gap-8">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Main Content */}
<div className="lg:col-span-2 space-y-6">
<div className="lg:col-span-2 space-y-6 min-w-0">
{/* ── Immersive hero ── */}
<div className="relative overflow-hidden rounded-2xl border border-white/10">
{/* Cover */}
@ -504,7 +504,7 @@ export default function EventDetailPage() {
</div>
{/* Sidebar */}
<div className="space-y-6">
<div className="space-y-6 min-w-0">
{/* Date Card */}
<Card className="bg-gradient-to-br from-primary/5 to-accent/5">
<CardContent className="pt-6">

View file

@ -399,7 +399,7 @@ function ProfilePage({ pubkey }: { pubkey: string }) {
)}
{/* Profile Info */}
<div className="grid lg:grid-cols-3 gap-6">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main Content */}
<div className="lg:col-span-2 space-y-6 min-w-0">
{/* About */}

View file

@ -58,8 +58,8 @@ function ShopDetailSkeleton() {
return (
<Layout>
<div className="container px-4 py-8">
<div className="grid lg:grid-cols-3 gap-8">
<div className="lg:col-span-2 space-y-6">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
<div className="lg:col-span-2 space-y-6 min-w-0">
<Skeleton className="aspect-video w-full rounded-xl" />
<div className="space-y-4">
<Skeleton className="h-10 w-3/4" />
@ -67,7 +67,7 @@ function ShopDetailSkeleton() {
<Skeleton className="h-24 w-full" />
</div>
</div>
<div className="space-y-6">
<div className="space-y-6 min-w-0">
<Skeleton className="h-64 w-full rounded-xl" />
<Skeleton className="h-32 w-full rounded-xl" />
</div>
@ -210,9 +210,9 @@ export default function ShopDetailPage() {
Back to Map
</Link>
<div className="grid lg:grid-cols-3 gap-8">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Main Content */}
<div className="lg:col-span-2 space-y-6">
<div className="lg:col-span-2 space-y-6 min-w-0">
{/* Image Gallery */}
{shop.images.length > 0 ? (
<div className="aspect-video rounded-xl overflow-hidden bg-muted">
@ -364,7 +364,7 @@ export default function ShopDetailPage() {
</div>
{/* Sidebar */}
<div className="space-y-6">
<div className="space-y-6 min-w-0">
{/* Contact Card */}
{(shop.phone || shop.email || shop.website || shop.instagram) && (
<Card className="bg-[#ccff00]/10 border-2 border-[#ccff00]/50">

View file

@ -95,7 +95,7 @@ function SpotDetailSkeleton() {
return (
<Layout>
<div className="container px-4 py-8">
<div className="grid lg:grid-cols-3 gap-8">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
<div className="lg:col-span-2 space-y-6">
<Skeleton className="aspect-video w-full rounded-xl" />
<div className="space-y-4">
@ -245,7 +245,7 @@ export default function SpotDetailPage() {
Back to Map
</Link>
<div className="grid lg:grid-cols-3 gap-8">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Main Content */}
<div className="lg:col-span-2 space-y-6 min-w-0">
{/* Image Gallery - Combines owner photos + community photos */}
@ -756,7 +756,7 @@ export default function SpotDetailPage() {
</div>
{/* Sidebar */}
<div className="space-y-6">
<div className="space-y-6 min-w-0">
{/* Who's Skating - Only show for regular spots, not shops */}
{!isShop && (
<WhosSkating
@ -935,7 +935,7 @@ export default function SpotDetailPage() {
<CardContent>
<Link
to={`/${mapperNpub}`}
className="flex items-center gap-3 mb-4 group rounded-xl -m-1 p-1 hover:bg-white/5 transition-colors"
className="flex items-center gap-3 mb-4 group rounded-xl -m-1 p-1 hover:bg-white/5 transition-colors min-w-0"
>
<Avatar className="h-12 w-12 border-2 border-[#ccff00]/30">
<AvatarImage src={metadata?.picture} alt={displayName} />