import { useSeoMeta } from '@unhead/react'; import { Link } from 'react-router-dom'; import { Layout } from '@/components/Layout'; import { SpotCard, SpotCardSkeleton } from '@/components/SpotCard'; import { EventCard, EventCardSkeleton } from '@/components/EventCard'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { LoginArea } from '@/components/auth/LoginArea'; import { useSkateSpots } from '@/hooks/useSkateSpots'; import { useUpcomingSkateEvents } from '@/hooks/useSkateEvents'; import { useLabProfiles } from '@/hooks/useLabProfiles'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useAuthor } from '@/hooks/useAuthor'; import { useTranslation } from '@/contexts/LanguageContext'; import { genUserName } from '@/lib/genUserName'; import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'; import { Badge } from '@/components/ui/badge'; import { MapPin, Calendar, Plus, ChevronRight, Sparkles, CheckCircle2, GraduationCap, Video, Crown, } from 'lucide-react'; import { FounderFollow } from '@/components/FounderFollow'; import { SponsorSlot } from '@/components/SponsorSlot'; function HeroSection() { const { user } = useCurrentUser(); const { t } = useTranslation(); return (
{/* Neon background glows */}
{t('home.tagline')}
{/* Main headline — Bebas Neue split into two lines for visual impact */}

SKATE SPOTS

{/* Subtitle — Barlow Condensed, bold and spaced */}

{t('home.subtitle')}

{t('home.description')}

⚠️ {t('home.betaWarning')}
📱 {t('home.pwaHint')}
{user && ( )}
{/* Login/Signup Area - Prominent for logged out users (desktop only, mobile has it in header) */} {!user && (

Join the community to add spots, create events & more

)}
); } function FeaturedSpots() { const { data: spots, isLoading } = useSkateSpots(8); const { t } = useTranslation(); return (

{t('home.featuredSpots')}

{t('home.featuredSpotsDesc')}

{isLoading ? (
{Array.from({ length: 4 }).map((_, i) => ( ))}
) : spots && spots.length > 0 ? (
{spots.slice(0, 4).map((spot) => ( ))}
) : (

{t('home.noSpotsYet')}

)}
); } function UpcomingEvents() { const { data: events, isLoading } = useUpcomingSkateEvents(4); const { t } = useTranslation(); return (

{t('home.upcomingEvents')}

{t('home.upcomingEventsDesc')}

{isLoading ? (
{Array.from({ length: 4 }).map((_, i) => ( ))}
) : events && events.length > 0 ? (
{events.map((event) => ( ))}
) : (

{t('home.noEventsYet')}

)}
); } function TheLabSection() { const { data: profiles, isLoading } = useLabProfiles(100); const { t } = useTranslation(); // Get 2 coaches and 2 filmers const coaches = profiles?.filter(p => p.profileType === 'coach').slice(0, 2) || []; const filmers = profiles?.filter(p => p.profileType === 'filmer').slice(0, 2) || []; const displayProfiles = [...coaches, ...filmers]; return (

THE LAB

{t('home.theLabDesc')}

{isLoading ? (
{Array.from({ length: 4 }).map((_, i) => (
{/* Avatar skeleton */}
{/* Name skeleton */}
{/* Location skeleton */}
{/* Bio skeleton */}
{/* Skills skeleton */}
))}
) : displayProfiles.length > 0 ? (
{displayProfiles.map((profile) => ( ))}
) : (

{t('lab.noCoaches')}

)}
); } function LabProfileCard({ profile }: { profile: any }) { const author = useAuthor(profile.pubkey); const metadata = author.data?.metadata; const displayName = metadata?.name ?? genUserName(profile.pubkey); const avatar = profile.image || metadata?.picture; const isCoach = profile.profileType === 'coach'; const accentColor = isCoach ? '#ff0040' : '#ff6600'; return (
{displayName.slice(0, 2).toUpperCase()}

{displayName}

{isCoach ? ( ) : (
{profile.location && (

{profile.location}

)} {profile.bio && (

{profile.bio}

)} {profile.skills.length > 0 && (
{profile.skills.slice(0, 3).map((skill: string) => ( {skill} ))} {profile.skills.length > 3 && ( +{profile.skills.length - 3} )}
)}
); } function NewToNostrSection() { const { t } = useTranslation(); const { user } = useCurrentUser(); // Don't show this section if user is already logged in if (user) return null; return (
{/* Neon glow */}

NEW HERE?

Create a free account to add spots, join events, connect with skaters, and become part of the community. No email required.

{/* Founder Follow - prominent placement */}
Follow the Founder

Hold the avatar for 3 seconds to follow and stay updated on new features and events!

Your account works across all apps in the network

); } function CTASection() { const { t } = useTranslation(); return (
{/* Neon glows */}

{t('home.readyToShare')}

{t('home.readyToShareDesc')}

); } function Footer() { const { t } = useTranslation(); return ( ); } export default function Index() { useSeoMeta({ title: 'SkateSpots - Discover Skateboarding Locations Worldwide', description: 'Find the best skateboarding spots, connect with fellow skaters, and discover events near you. Built on Nostr for true decentralization.', }); // Platform sponsors - currently empty (invisible placeholder) // When sponsors are added, pass them here: sponsors={[{name: "Vans", logo: "...", tier: "title"}]} const platformSponsors = undefined; return ( {/* Sponsor slot - invisible until sponsors are added */}