- 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
326 lines
15 KiB
TypeScript
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>
|
|
);
|
|
}
|