feat: add email subscribe CTAs, Valley of the Commons section, update button text
- Add Ghost blog newsletter subscribe form (blog.crypto-commons.org) in hero and bottom CTA sections - Update register buttons to "Register Now to Save Your Seat!" - Add Valley of the Commons section with weekly themes and overlap info Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
42a406f46c
commit
f82cd57aa9
199
app/page.tsx
199
app/page.tsx
|
|
@ -4,12 +4,42 @@ import type React from "react"
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Card, CardContent } from "@/components/ui/card"
|
import { Card, CardContent } from "@/components/ui/card"
|
||||||
import { ArrowRight, Calendar, MapPin, Users, Heart, Sprout, Network, X } from "lucide-react"
|
import { Input } from "@/components/ui/input"
|
||||||
|
import { ArrowRight, Calendar, MapPin, Users, Heart, Sprout, Network, X, Mail, Loader2, CheckCircle2 } from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
const [selectedImage, setSelectedImage] = useState<string | null>(null)
|
const [selectedImage, setSelectedImage] = useState<string | null>(null)
|
||||||
|
const [email, setEmail] = useState("")
|
||||||
|
const [subscribeStatus, setSubscribeStatus] = useState<"idle" | "loading" | "success" | "error">("idle")
|
||||||
|
const [subscribeError, setSubscribeError] = useState("")
|
||||||
|
|
||||||
|
const handleSubscribe = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (!email) return
|
||||||
|
|
||||||
|
setSubscribeStatus("loading")
|
||||||
|
setSubscribeError("")
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch("https://blog.crypto-commons.org/members/api/send-magic-link/", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ email, emailType: "subscribe" }),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
setSubscribeStatus("success")
|
||||||
|
setEmail("")
|
||||||
|
} else {
|
||||||
|
throw new Error("Subscription failed")
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
setSubscribeStatus("error")
|
||||||
|
setSubscribeError("Something went wrong. Please try again.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleImageClick = (imageSrc: string) => {
|
const handleImageClick = (imageSrc: string) => {
|
||||||
setSelectedImage(imageSrc)
|
setSelectedImage(imageSrc)
|
||||||
|
|
@ -114,10 +144,10 @@ END:VCALENDAR`
|
||||||
building, and radical imagination in the Austrian Alps.
|
building, and radical imagination in the Austrian Alps.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center mb-12">
|
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center mb-8">
|
||||||
<Button size="lg" className="gap-2 text-base" asChild>
|
<Button size="lg" className="gap-2 text-base" asChild>
|
||||||
<Link href="/register">
|
<Link href="/register">
|
||||||
Register Now <ArrowRight className="w-4 h-4" />
|
Register Now to Save Your Seat! <ArrowRight className="w-4 h-4" />
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -142,6 +172,40 @@ END:VCALENDAR`
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="max-w-md mx-auto mb-12">
|
||||||
|
<p className="text-sm text-foreground/80 mb-3 font-medium">
|
||||||
|
Drop your email to stay in the loop on upcoming announcements!
|
||||||
|
</p>
|
||||||
|
{subscribeStatus === "success" ? (
|
||||||
|
<div className="flex items-center justify-center gap-2 text-sm text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-950/30 rounded-md py-2.5 px-4 border border-green-200 dark:border-green-800">
|
||||||
|
<CheckCircle2 className="w-4 h-4" />
|
||||||
|
You're subscribed! Check your inbox to confirm.
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<form onSubmit={handleSubscribe} className="flex gap-2">
|
||||||
|
<Input
|
||||||
|
type="email"
|
||||||
|
placeholder="your@email.com"
|
||||||
|
value={email}
|
||||||
|
onChange={(e) => { setEmail(e.target.value); setSubscribeStatus("idle") }}
|
||||||
|
required
|
||||||
|
className="bg-background/80 backdrop-blur-sm"
|
||||||
|
/>
|
||||||
|
<Button type="submit" size="default" className="gap-2 shrink-0" disabled={subscribeStatus === "loading"}>
|
||||||
|
{subscribeStatus === "loading" ? (
|
||||||
|
<Loader2 className="w-4 h-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<Mail className="w-4 h-4" />
|
||||||
|
)}
|
||||||
|
Subscribe
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
{subscribeStatus === "error" && (
|
||||||
|
<p className="text-sm text-destructive mt-2">{subscribeError}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap gap-6 justify-center text-sm text-muted-foreground">
|
<div className="flex flex-wrap gap-6 justify-center text-sm text-muted-foreground">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<MapPin className="w-4 h-4 text-primary" />
|
<MapPin className="w-4 h-4 text-primary" />
|
||||||
|
|
@ -406,19 +470,146 @@ END:VCALENDAR`
|
||||||
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8">
|
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8">
|
||||||
<Button size="lg" className="gap-2" asChild>
|
<Button size="lg" className="gap-2" asChild>
|
||||||
<Link href="/register">
|
<Link href="/register">
|
||||||
Register and Get Tickets <ArrowRight className="w-4 h-4" />
|
Register Now to Save Your Seat! <ArrowRight className="w-4 h-4" />
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="lg" variant="outline" asChild>
|
<Button size="lg" variant="outline" asChild>
|
||||||
<Link href="/transparency">Financial Transparency</Link>
|
<Link href="/transparency">Financial Transparency</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="max-w-md mx-auto mb-8">
|
||||||
|
<p className="text-sm text-muted-foreground mb-3 font-medium">
|
||||||
|
Drop your email to stay in the loop on upcoming announcements!
|
||||||
|
</p>
|
||||||
|
{subscribeStatus === "success" ? (
|
||||||
|
<div className="flex items-center justify-center gap-2 text-sm text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-950/30 rounded-md py-2.5 px-4 border border-green-200 dark:border-green-800">
|
||||||
|
<CheckCircle2 className="w-4 h-4" />
|
||||||
|
You're subscribed! Check your inbox to confirm.
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<form onSubmit={handleSubscribe} className="flex gap-2">
|
||||||
|
<Input
|
||||||
|
type="email"
|
||||||
|
placeholder="your@email.com"
|
||||||
|
value={email}
|
||||||
|
onChange={(e) => { setEmail(e.target.value); setSubscribeStatus("idle") }}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<Button type="submit" size="default" className="gap-2 shrink-0" disabled={subscribeStatus === "loading"}>
|
||||||
|
{subscribeStatus === "loading" ? (
|
||||||
|
<Loader2 className="w-4 h-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<Mail className="w-4 h-4" />
|
||||||
|
)}
|
||||||
|
Subscribe
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
{subscribeStatus === "error" && (
|
||||||
|
<p className="text-sm text-destructive mt-2">{subscribeError}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Interested in the Crypto Commons Association cooperative? Learn more at the event.
|
Interested in the Crypto Commons Association cooperative? Learn more at the event.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* Valley of the Commons Section */}
|
||||||
|
<section className="py-24 px-4 relative overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 bg-cover bg-center"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url('/images/20220429-145359.jpg')`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-br from-background/95 via-background/90 to-background/95" />
|
||||||
|
<div className="container mx-auto max-w-5xl relative z-10">
|
||||||
|
<div className="text-center mb-12">
|
||||||
|
<p className="text-sm font-mono text-primary mb-3 tracking-wider uppercase">New for 2026</p>
|
||||||
|
<h2 className="text-3xl md:text-4xl font-bold mb-4 text-balance">
|
||||||
|
Stay for the Valley of the Commons
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-muted-foreground max-w-2xl mx-auto text-pretty">
|
||||||
|
When CCG wraps on August 22, the experiment is just getting started. Stick around for 1 to 4 weeks and
|
||||||
|
join a new extended event right where you are — in the Austrian Alps.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid md:grid-cols-2 gap-8 items-start mb-12">
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl font-bold mb-4">What is it?</h3>
|
||||||
|
<p className="text-muted-foreground leading-relaxed mb-4">
|
||||||
|
Valley of the Commons is a four-week experimental pop-up village running{" "}
|
||||||
|
<span className="font-semibold text-foreground">August 24 – September 20, 2026</span> — picking up
|
||||||
|
just two days after CCG ends. It's not a conference or a simulation: it's a functioning co-living
|
||||||
|
community taking concrete steps toward permanent settlement in the Höllental valley.
|
||||||
|
</p>
|
||||||
|
<p className="text-muted-foreground leading-relaxed">
|
||||||
|
Mornings are structured learning paths, afternoons bring workshops and working groups, evenings are
|
||||||
|
communal time, and weekends are open for exploring the Alps. You can stay for one week or all four.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl font-bold mb-4">Weekly Themes</h3>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="flex gap-3 items-start">
|
||||||
|
<span className="text-primary font-mono font-bold text-sm mt-0.5 shrink-0">WK 1</span>
|
||||||
|
<div>
|
||||||
|
<p className="font-semibold text-sm">Return of the Commons</p>
|
||||||
|
<p className="text-sm text-muted-foreground">Commons theory and history, with guest speakers</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-3 items-start">
|
||||||
|
<span className="text-primary font-mono font-bold text-sm mt-0.5 shrink-0">WK 2</span>
|
||||||
|
<div>
|
||||||
|
<p className="font-semibold text-sm">Production & Value</p>
|
||||||
|
<p className="text-sm text-muted-foreground">Cosmo-local production, open value accounting systems</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-3 items-start">
|
||||||
|
<span className="text-primary font-mono font-bold text-sm mt-0.5 shrink-0">WK 3</span>
|
||||||
|
<div>
|
||||||
|
<p className="font-semibold text-sm">Cooperative Housing</p>
|
||||||
|
<p className="text-sm text-muted-foreground">Nomad-friendly communal housing, renovation, ecological integration</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-3 items-start">
|
||||||
|
<span className="text-primary font-mono font-bold text-sm mt-0.5 shrink-0">WK 4</span>
|
||||||
|
<div>
|
||||||
|
<p className="font-semibold text-sm">Governance & Funding</p>
|
||||||
|
<p className="text-sm text-muted-foreground">Horizontal governance, legal frameworks, funding mechanisms</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card className="border-primary/20 bg-background/80 backdrop-blur-sm">
|
||||||
|
<CardContent className="p-6 md:p-8">
|
||||||
|
<div className="flex flex-col md:flex-row gap-6 items-center justify-between">
|
||||||
|
<div className="text-center md:text-left">
|
||||||
|
<h3 className="font-bold text-lg mb-2">CCG + Valley: The Full Experience</h3>
|
||||||
|
<p className="text-sm text-muted-foreground max-w-lg">
|
||||||
|
Come for CCG's unconference week (Aug 16-22), then flow straight into Valley of the Commons
|
||||||
|
(Aug 24 – Sep 20). Same mountains, same community, deeper roots. Perfect for digital workers,
|
||||||
|
post-corporate professionals, and anyone seeking grounded, cooperative ways of living.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button size="lg" variant="outline" className="gap-2 shrink-0" asChild>
|
||||||
|
<Link href="https://www.valleyofthecommons.com/" target="_blank" rel="noopener noreferrer">
|
||||||
|
Learn More <ArrowRight className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<footer className="py-12 px-4 border-t border-border">
|
<footer className="py-12 px-4 border-t border-border">
|
||||||
<div className="container mx-auto max-w-6xl">
|
<div className="container mx-auto max-w-6xl">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue