SkateSpots/src/pages/AboutPage.tsx
SkateSpots 09e1612db7 fix(a11y): Batch E part 1 — labels, valid nesting, touch targets
- EmptyState: render <Link> as the button (a <button> inside <Link> was invalid
  and double-focusable); AboutPage <a href> -> <Link> (no full reload)
- aria-label on icon-only controls: settings Back, conversation Refresh/Send,
  crew chat Send
- Crew invite Accept/Decline raised to 44px touch targets
2026-09-26 18:46:51 +07:00

326 lines
15 KiB
TypeScript

import { useSeoMeta } from '@unhead/react';
import { Link } from 'react-router-dom';
import { Layout } from '@/components/Layout';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useToast } from '@/hooks/useToast';
import {
MapPin,
Heart,
Globe,
Zap,
Shield,
Users,
Code,
ExternalLink,
BarChart3,
AlertCircle,
Download,
Smartphone,
MessageCircle,
} from 'lucide-react';
export default function AboutPage() {
useSeoMeta({
title: 'About - SkateSpots',
description: 'Learn about SkateSpots and our mission to build a decentralized skateboarding community.',
});
const { user } = useCurrentUser();
const { toast } = useToast();
const copyNpub = () => {
navigator.clipboard.writeText('npub1yrnuj56rnen08zp2h9h7p74ghgjx6ma39spmpj6w9hzxywutevsst7k5cx');
toast({
title: 'Copied!',
description: 'npub copied to clipboard. Paste it in your favorite Nostr client to send a DM.',
});
};
// Bug report template for DM
const bugReportTemplate = `🐛 Bug Report
What happened:
What I expected:
Steps to reproduce:
Device/Browser: ${navigator.userAgent.includes('Mobile') ? 'Mobile' : 'Desktop'} - ${navigator.userAgent.split(' ').slice(-2).join(' ')}
Version: v0.1.0`;
const bugReportUrl = `/messages/npub1yrnuj56rnen08zp2h9h7p74ghgjx6ma39spmpj6w9hzxywutevsst7k5cx?message=${encodeURIComponent(bugReportTemplate)}`;
return (
<Layout>
<div className="container px-4 py-12 max-w-4xl">
{/* Hero */}
<div className="text-center mb-12">
<div className="mb-6">
<div className="inline-flex items-center justify-center w-20 h-20 rounded-2xl bg-gradient-to-br from-[#ff0040] to-[#ff6600] mb-4">
<MapPin className="h-10 w-10 text-white" />
</div>
</div>
<h1 className="text-4xl md:text-6xl font-black uppercase mb-4" style={{
fontFamily: 'Impact, "Arial Black", sans-serif',
letterSpacing: '0.05em'
}}>
<span className="neon-red">ABOUT</span>{' '}
<span className="gradient-text">SKATESPOTS</span>
</h1>
<p className="text-xl text-gray-300 max-w-2xl mx-auto mb-6">
Connect with local skate scenes worldwide. <strong className="text-[#ff0040]">Skater-owned data</strong>, community-run relays.
</p>
<Link to="/stats">
<Button
variant="outline"
className="gap-2 border-2 border-[#ccff00] text-[#ccff00] hover:bg-[#ccff00]/10"
>
<BarChart3 className="h-4 w-4" />
View Community Stats
</Button>
</Link>
</div>
{/* Mission */}
<Card className="bg-black/90 border-2 border-[#ff0040]/50 mb-8">
<CardContent className="p-8">
<div className="flex items-start gap-4 mb-4">
<Heart className="h-8 w-8 text-[#ff0040] flex-shrink-0" />
<div>
<h2 className="text-2xl font-black uppercase text-white mb-3">Our Mission</h2>
<p className="text-gray-300 leading-relaxed">
SkateSpots helps skateboarders discover spots, connect with pros at The Lab, and organize sessions -
all without corporate control. The real skating happens offline, this tool just connects you to it.
</p>
</div>
</div>
<p className="text-gray-300 leading-relaxed">
Skateboarding knowledge should live with the community, not locked in corporate apps.
That's why SkateSpots runs on Nostr - a relay-based system where skaters control their own
data, choose which relays store it, and can even run their own. No single company owns the map.
</p>
</CardContent>
</Card>
{/* Why Nostr */}
<Card className="bg-black/90 border-2 border-[#ccff00]/50 mb-8">
<CardContent className="p-8">
<div className="flex items-start gap-4 mb-6">
<Globe className="h-8 w-8 text-[#ccff00] flex-shrink-0" />
<div>
<h2 className="text-2xl font-black uppercase text-white mb-3">Why Nostr?</h2>
</div>
</div>
<div className="grid md:grid-cols-2 gap-4">
<div className="p-4 rounded-lg bg-black/50 border border-[#ff0040]/20">
<Shield className="h-6 w-6 text-[#ff0040] mb-2" />
<h3 className="font-bold text-white uppercase text-sm mb-2">Community-Controlled</h3>
<p className="text-sm text-gray-400">
Your spots live on community relays. Skaters run the servers, not corporations.
</p>
</div>
<div className="p-4 rounded-lg bg-black/50 border border-[#ccff00]/20">
<Users className="h-6 w-6 text-[#ccff00] mb-2" />
<h3 className="font-bold text-white uppercase text-sm mb-2">You Own Your Data</h3>
<p className="text-sm text-gray-400">
Your Nostr identity is yours. Take it to any Nostr app - no lock-in.
</p>
</div>
<div className="p-4 rounded-lg bg-black/50 border border-[#ff6600]/20">
<Zap className="h-6 w-6 text-[#ff6600] mb-2" />
<h3 className="font-bold text-white uppercase text-sm mb-2">Bitcoin Integration</h3>
<p className="text-sm text-gray-400">
Zap creators directly with Bitcoin. No platform taking 30%.
</p>
</div>
<div className="p-4 rounded-lg bg-black/50 border border-[#ccff00]/20">
<Code className="h-6 w-6 text-[#ccff00] mb-2" />
<h3 className="font-bold text-white uppercase text-sm mb-2">Open Source</h3>
<p className="text-sm text-gray-400">
Built in the open. Anyone can contribute or fork the code.
</p>
</div>
</div>
</CardContent>
</Card>
{/* Links */}
<div className="grid md:grid-cols-1 gap-6 max-w-md mx-auto">
<Card className="bg-black/90 border-2 border-[#ccff00]/50">
<CardContent className="p-6 text-center">
<h3 className="font-black uppercase text-[#ccff00] mb-4">Get Involved</h3>
<p className="text-gray-300 mb-4 text-sm">
SkateSpots is open source and community-driven. Contribute code, share spots, or help others get started.
</p>
<Link to="/onboarding">
<Button className="gap-2 bg-[#ccff00] text-black hover:bg-[#ccff00]/90 font-bold uppercase w-full">
Get Started
</Button>
</Link>
</CardContent>
</Card>
</div>
{/* Beta Testing Notice */}
<Card className="bg-yellow-950/20 border-yellow-500/30 mt-8">
<CardContent className="p-6">
<div className="flex items-start gap-4">
<AlertCircle className="h-6 w-6 text-yellow-500 flex-shrink-0 mt-0.5" />
<div className="flex-1">
<h3 className="font-bold text-yellow-500 uppercase mb-2">Beta Testing</h3>
<p className="text-sm text-gray-300 mb-4">
Dear User! Thank you for beta testing SkateSpots. Please note that the app is still
in beta, and there may be bugs or security issues. If you encounter any problems
or want to report a bug/issue, please reach out!
</p>
<div className="flex flex-col sm:flex-row gap-3 items-start sm:items-center">
<div className="flex-1 bg-black/30 rounded-lg p-3 border border-yellow-500/20 min-w-0">
<p className="text-xs text-gray-400 mb-1">Give us feedback:</p>
<code className="text-xs text-yellow-400 break-all">
npub1yrnuj56rnen08zp2h9h7p74ghgjx6ma39spmpj6w9hzxywutevsst7k5cx
</code>
</div>
<div className="flex gap-2 flex-shrink-0">
<Button
variant="outline"
size="sm"
className="border-yellow-500/50 text-yellow-500 hover:bg-yellow-500/10"
onClick={copyNpub}
>
Copy npub
</Button>
{user ? (
<Link to={bugReportUrl}>
<Button
size="sm"
className="bg-yellow-500 text-black hover:bg-yellow-400"
>
Report Bug
</Button>
</Link>
) : (
<a
href="https://njump.me/npub1yrnuj56rnen08zp2h9h7p74ghgjx6ma39spmpj6w9hzxywutevsst7k5cx"
target="_blank"
rel="noopener noreferrer"
>
<Button
size="sm"
className="bg-yellow-500 text-black hover:bg-yellow-400"
>
View Profile
</Button>
</a>
)}
</div>
</div>
</div>
</div>
</CardContent>
</Card>
{/* Download on Zapstore */}
<Card className="bg-black/90 border-2 border-[#ccff00]/50 mt-8">
<CardContent className="p-6">
<div className="flex flex-col sm:flex-row items-center gap-4">
<div className="flex-1 text-center sm:text-left">
<div className="flex items-center gap-2 justify-center sm:justify-start mb-2">
<Smartphone className="h-5 w-5 text-[#ccff00]" />
<h3 className="font-black uppercase text-[#ccff00]">Download the App</h3>
</div>
<p className="text-sm text-gray-300">
Install SkateSpots on Android via Zapstore — the open-source, Bitcoin-native app store.
</p>
</div>
<a
href="https://zapstore.dev/apps/org.skatespots.app"
target="_blank"
rel="noopener noreferrer"
className="flex-shrink-0"
>
<Button className="gap-2 bg-[#ccff00] text-black hover:bg-[#ccff00]/90 font-bold uppercase px-6">
<Download className="h-4 w-4" />
Get on Zapstore
</Button>
</a>
</div>
</CardContent>
</Card>
{/* Credits */}
<Card className="bg-black/90 border-2 border-gray-700 mt-8">
<CardContent className="p-6">
<h3 className="font-black uppercase text-white mb-4 flex items-center gap-2">
<Heart className="h-5 w-5 text-[#ff0040]" />
Credits
</h3>
<div className="grid sm:grid-cols-2 gap-3 text-sm">
{[
{ label: 'Built with', name: 'MKStack', url: 'https://soapbox.pub/mkstack', desc: 'Nostr client framework' },
{ label: 'Vibed with', name: 'Shakespeare', url: 'https://shakespeare.diy', desc: 'AI-powered development' },
{ label: 'Powered by', name: 'Nostr', url: 'https://nostr.com', desc: 'Decentralized protocol' },
{ label: 'Crowdfunding', name: 'Angor', url: 'https://angor.io/project/angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z', desc: 'Decentralized Bitcoin crowdfunding' },
{ label: 'Distributed on', name: 'Zapstore', url: 'https://zapstore.dev/apps/org.skatespots.app', desc: 'Open-source app store' },
{ label: 'Trust & crew chat via', name: 'ContextVM', url: 'https://contextvm.org/s/e3564bb877adb0c99a7e4973ccb22e516d7d9eca0027d0bd62a04174ed670530', desc: 'Relatr trust scores & encrypted crew-chat coordination' },
].map((item) => (
<a
key={item.name}
href={item.url}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-3 p-3 rounded-lg bg-black/50 border border-gray-800 hover:border-[#ccff00]/40 hover:bg-[#ccff00]/5 transition-all group"
>
<ExternalLink className="h-4 w-4 text-gray-600 group-hover:text-[#ccff00] flex-shrink-0" />
<div className="min-w-0">
<span className="text-gray-500 text-xs">{item.label}: </span>
<span className="font-bold text-white group-hover:text-[#ccff00] transition-colors">{item.name}</span>
<p className="text-xs text-gray-500 truncate">{item.desc}</p>
</div>
</a>
))}
</div>
</CardContent>
</Card>
{/* Sasquatch — Ask me anything */}
<Card className="bg-gradient-to-br from-amber-950/30 to-[#ff6600]/10 border-2 border-amber-500/40 mb-8">
<CardContent className="p-6 flex flex-col sm:flex-row items-center gap-5">
<div className="text-5xl flex-shrink-0">🦧</div>
<div className="flex-1 text-center sm:text-left">
<h3 className="text-xl font-black text-white uppercase mb-1">Still have questions?</h3>
<p className="text-gray-400 text-sm">
The Sasquatch is our AI guide — powered by live SkateSpots data. Ask him about spots, events, coaches, gear, or how anything works.
</p>
</div>
<Button
onClick={() => window.dispatchEvent(new CustomEvent('sasquatch:ask', { detail: { question: 'Tell me about SkateSpots' } }))}
className="bg-amber-500 hover:bg-amber-400 text-black font-bold gap-2 flex-shrink-0 rounded-full px-6"
>
<MessageCircle className="h-4 w-4" />
Ask The Sasquatch
</Button>
</CardContent>
</Card>
{/* Powered By */}
<div className="text-center mt-8 pb-6 px-4">
<p className="text-gray-400 mb-3 uppercase tracking-wide text-sm">Powered by</p>
<div className="flex flex-wrap items-center justify-center gap-2 md:gap-3">
<a href="https://nostr.com" target="_blank" rel="noopener noreferrer"
className="text-[#ccff00] hover:text-[#ccff00]/80 font-black text-lg md:text-xl uppercase">
Nostr
</a>
<span className="text-gray-600">•</span>
<span className="text-[#ff0040] font-black text-lg md:text-xl uppercase">Decentralized</span>
<span className="text-gray-600">•</span>
<span className="text-orange-400 font-black text-lg md:text-xl uppercase">Community-Owned</span>
</div>
</div>
</div>
</Layout>
);
}