feat: update footer text to reflect Creative Commons license
Align footer with commons-oriented ethos and clarify licensing. #VERCEL_SKIP Co-authored-by: Jeff Emmett <46964190+Jeff-Emmett@users.noreply.github.com>
46
Dockerfile
|
|
@ -1,46 +0,0 @@
|
||||||
FROM node:20-alpine AS base
|
|
||||||
|
|
||||||
# Install pnpm
|
|
||||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
||||||
|
|
||||||
# Install dependencies only when needed
|
|
||||||
FROM base AS deps
|
|
||||||
RUN apk add --no-cache libc6-compat
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY package.json pnpm-lock.yaml ./
|
|
||||||
RUN pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
# Rebuild the source code only when needed
|
|
||||||
FROM base AS builder
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
|
|
||||||
RUN pnpm run build
|
|
||||||
|
|
||||||
# Production image, copy all the files and run next
|
|
||||||
FROM base AS runner
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
|
||||||
|
|
||||||
RUN addgroup --system --gid 1001 nodejs
|
|
||||||
RUN adduser --system --uid 1001 nextjs
|
|
||||||
|
|
||||||
COPY --from=builder /app/public ./public
|
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|
||||||
|
|
||||||
USER nextjs
|
|
||||||
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
ENV PORT=3000
|
|
||||||
ENV HOSTNAME="0.0.0.0"
|
|
||||||
|
|
||||||
CMD ["node", "server.js"]
|
|
||||||
|
|
@ -0,0 +1,233 @@
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Card, CardContent } from "@/components/ui/card"
|
||||||
|
import { ArrowRight, Users, Heart, Sprout, Network, Sparkles } from "lucide-react"
|
||||||
|
import Link from "next/link"
|
||||||
|
|
||||||
|
export default function AboutPage() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen">
|
||||||
|
{/* Hero Section */}
|
||||||
|
<section className="relative min-h-[60vh] flex items-center justify-center overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 bg-cover bg-center z-0"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url('/images/20220429-145359.jpg')`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-b from-background/90 via-background/80 to-background z-[1]" />
|
||||||
|
|
||||||
|
<div className="container mx-auto px-4 relative z-10 text-center max-w-4xl py-20">
|
||||||
|
<h1 className="text-4xl md:text-6xl font-black mb-6 text-balance leading-tight">About CCG 2026</h1>
|
||||||
|
<p className="text-lg md:text-xl text-muted-foreground text-pretty">
|
||||||
|
Six years of thinkering with the promises and paradoxes of crypto and the commons
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Main Content */}
|
||||||
|
<section className="py-16 px-4">
|
||||||
|
<div className="container mx-auto max-w-4xl">
|
||||||
|
<div className="prose prose-lg max-w-none">
|
||||||
|
<h2 className="text-3xl font-bold mb-6">A Growing Movement</h2>
|
||||||
|
<p className="text-muted-foreground leading-relaxed mb-6">
|
||||||
|
What began in 2020 as a modest excuse for then-PhD researcher Felix Fritsch to bring together
|
||||||
|
crypto-commons thinkers from around the world in his own backyard has since evolved into an annual moment
|
||||||
|
of (re)connection and reflection for a growing community—and for the many lived practices and experiments
|
||||||
|
in commoning, degrowth, mutualism, and post-capitalist economic worldbuilding it is linked to.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p className="text-muted-foreground leading-relaxed mb-8">
|
||||||
|
Over the years, CCG has welcomed activists, researchers, hackers, builders, artists, game designers, and
|
||||||
|
others—newcomers and "OGs" alike. It has shaped itself as a convivial and fertile space for people and
|
||||||
|
projects working across and beyond web3 to cross-pollinate visions, trajectories, and strategies for
|
||||||
|
realizing regenerative and cooperative infrastructures.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="grid md:grid-cols-3 gap-4 my-12">
|
||||||
|
<Card className="border-primary/20">
|
||||||
|
<CardContent className="p-6 text-center">
|
||||||
|
<div className="text-4xl font-black text-primary mb-2">6th</div>
|
||||||
|
<p className="text-sm text-muted-foreground">Annual Edition</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<Card className="border-primary/20">
|
||||||
|
<CardContent className="p-6 text-center">
|
||||||
|
<div className="text-4xl font-black text-primary mb-2">100+</div>
|
||||||
|
<p className="text-sm text-muted-foreground">Expected Participants</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<Card className="border-primary/20">
|
||||||
|
<CardContent className="p-6 text-center">
|
||||||
|
<div className="text-4xl font-black text-primary mb-2">7</div>
|
||||||
|
<p className="text-sm text-muted-foreground">Days of Connection</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 className="text-3xl font-bold mb-6 mt-16">The 2026 Edition: New Infrastructures</h2>
|
||||||
|
<p className="text-muted-foreground leading-relaxed mb-6">
|
||||||
|
While remaining an unconference at heart, each edition has reflected the community's shifting priorities
|
||||||
|
and aspirations. In 2026, the gathering enters its sixth year, presenting not only a space to collectively
|
||||||
|
take stock of what crypto commons has become and what it still could be, but also a moment for the growing
|
||||||
|
community to think and organize itself anew.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="bg-muted/50 border border-border rounded-lg p-8 my-8">
|
||||||
|
<h3 className="text-2xl font-bold mb-4">What's Evolving in 2026</h3>
|
||||||
|
<ul className="space-y-4">
|
||||||
|
<li className="flex gap-3">
|
||||||
|
<Sparkles className="w-5 h-5 text-primary flex-shrink-0 mt-1" />
|
||||||
|
<div>
|
||||||
|
<strong className="text-foreground">The Commons Hub</strong> has become a full-fledged event hosting
|
||||||
|
organization, co-led by brothers Felix and Emil Fritsch, with exciting expansion and ecovillage
|
||||||
|
plans underway.
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li className="flex gap-3">
|
||||||
|
<Sparkles className="w-5 h-5 text-primary flex-shrink-0 mt-1" />
|
||||||
|
<div>
|
||||||
|
<strong className="text-foreground">The Crypto Commons Association</strong>, previously stewarded by
|
||||||
|
Felix Fritsch and Giulio Quarta, is being reimagined as a cooperative vehicle for organizing and
|
||||||
|
supporting events at the Hub and beyond, introducing peer-production values and frameworks.
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 className="text-3xl font-bold mb-6 mt-16">What to Expect</h2>
|
||||||
|
|
||||||
|
<div className="space-y-6 mb-12">
|
||||||
|
<Card className="border-primary/20">
|
||||||
|
<CardContent className="p-6">
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<Heart className="w-6 h-6 text-primary flex-shrink-0 mt-1" />
|
||||||
|
<div>
|
||||||
|
<h3 className="font-bold mb-2">Gather & Connect</h3>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
Meet others in a convivial, off-grid setting in the Austrian countryside, whether you're
|
||||||
|
reconnecting or arriving for the first time. Form friendships that last a lifetime.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-primary/20">
|
||||||
|
<CardContent className="p-6">
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<Sprout className="w-6 h-6 text-primary flex-shrink-0 mt-1" />
|
||||||
|
<div>
|
||||||
|
<h3 className="font-bold mb-2">Explore Key Themes</h3>
|
||||||
|
<p className="text-muted-foreground mb-3">
|
||||||
|
Engage through participant-led sessions on regenerative and collaborative finance, MycoFi,
|
||||||
|
community currencies, digital and crypto commons, open source, degrowth, post-capitalism,
|
||||||
|
ecofeminism, multispecies justice, radical game design, speculative fiction, and more.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-primary/20">
|
||||||
|
<CardContent className="p-6">
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<Users className="w-6 h-6 text-primary flex-shrink-0 mt-1" />
|
||||||
|
<div>
|
||||||
|
<h3 className="font-bold mb-2">Participate Fully</h3>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
Experience a fully unconferenced structure where time and sessions are collectively managed.
|
||||||
|
Bring your ideas for talks, roundtables, workshops, prototyping sessions, board game nights,
|
||||||
|
LARPs, and more. Immerse yourself, find inspiration, and team up with others.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-primary/20">
|
||||||
|
<CardContent className="p-6">
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<Network className="w-6 h-6 text-primary flex-shrink-0 mt-1" />
|
||||||
|
<div>
|
||||||
|
<h3 className="font-bold mb-2">Co-Create the Future</h3>
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
If you're interested, contribute to the ongoing co-creation of the Crypto Commons Association as
|
||||||
|
it transitions into an events-oriented cooperative, a DAO, or something in between.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 className="text-3xl font-bold mb-6 mt-16">Spawning New Movements</h2>
|
||||||
|
<p className="text-muted-foreground leading-relaxed mb-6">
|
||||||
|
CCG has been a catalyst for emerging movements and initiatives. From the gathering, movements like{" "}
|
||||||
|
<strong className="text-primary">#CoFi</strong> (Cooperative Finance) and{" "}
|
||||||
|
<strong className="text-primary">#MycoFi</strong> (Mycelial Finance) have emerged, embodying the potential
|
||||||
|
for technologically-enabled commons that leverage network technologies to reclaim ground from state and
|
||||||
|
corporate control.
|
||||||
|
</p>
|
||||||
|
<p className="text-muted-foreground leading-relaxed mb-8">
|
||||||
|
The solidarity built here has coalesced into new digital public infrastructures, experimental protocols,
|
||||||
|
and collaborative frameworks that continue to evolve between gatherings.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Photo Section */}
|
||||||
|
<section className="py-16 px-4 bg-muted/30">
|
||||||
|
<div className="container mx-auto max-w-6xl">
|
||||||
|
<h2 className="text-3xl font-bold mb-8 text-center">Experience CCG</h2>
|
||||||
|
<div className="grid md:grid-cols-3 gap-4">
|
||||||
|
<div className="aspect-[4/3] rounded-lg overflow-hidden">
|
||||||
|
<img
|
||||||
|
src="/images/20220830-104828.jpg"
|
||||||
|
alt="CCG discussion circle"
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="aspect-[4/3] rounded-lg overflow-hidden">
|
||||||
|
<img src="/images/20220503-155430.jpg" alt="Community gathering" className="w-full h-full object-cover" />
|
||||||
|
</div>
|
||||||
|
<div className="aspect-[4/3] rounded-lg overflow-hidden">
|
||||||
|
<img src="/images/image.png" alt="Alpine setting" className="w-full h-full object-cover" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* CTA Section */}
|
||||||
|
<section className="py-24 px-4">
|
||||||
|
<div className="container mx-auto max-w-3xl text-center">
|
||||||
|
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-balance">Be Part of the Sixth Edition</h2>
|
||||||
|
<p className="text-lg text-muted-foreground mb-8 text-pretty">
|
||||||
|
Join us August 16-22, 2026 in the Austrian Alps for an unforgettable week of connection, collaboration, and
|
||||||
|
commons-building.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||||
|
<Button size="lg" className="gap-2" asChild>
|
||||||
|
<Link href="/register">
|
||||||
|
Register Now <ArrowRight className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
<Button size="lg" variant="outline" asChild>
|
||||||
|
<Link href="/">Back to Home</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<footer className="py-12 px-4 border-t border-border">
|
||||||
|
<div className="container mx-auto max-w-6xl text-center">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
© 2026 Crypto Commons Gathering. Built with solidarity for the commons.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,9 @@
|
||||||
import { type NextRequest, NextResponse } from "next/server"
|
import { type NextRequest, NextResponse } from "next/server"
|
||||||
import Stripe from "stripe"
|
import Stripe from "stripe"
|
||||||
|
|
||||||
// Lazy initialization to avoid build-time errors when env vars aren't set
|
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
|
||||||
let stripeInstance: Stripe | null = null
|
apiVersion: "2024-12-18.acacia",
|
||||||
function getStripe(): Stripe {
|
})
|
||||||
if (!stripeInstance) {
|
|
||||||
if (!process.env.STRIPE_SECRET_KEY) {
|
|
||||||
throw new Error("STRIPE_SECRET_KEY is not configured")
|
|
||||||
}
|
|
||||||
stripeInstance = new Stripe(process.env.STRIPE_SECRET_KEY, {
|
|
||||||
apiVersion: "2024-12-18.acacia",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return stripeInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
const CCG_TICKET_PRICE_ID = "price_1SbokZ8IwXvKSVJpRvkTqePT"
|
const CCG_TICKET_PRICE_ID = "price_1SbokZ8IwXvKSVJpRvkTqePT"
|
||||||
const CCG_ACCOMMODATION_PRICE_ID = "price_1Sboq08IwXvKSVJpf8RRSoCy"
|
const CCG_ACCOMMODATION_PRICE_ID = "price_1Sboq08IwXvKSVJpf8RRSoCy"
|
||||||
|
|
@ -60,7 +50,7 @@ export async function POST(request: NextRequest) {
|
||||||
paymentMethodTypes = ["customer_balance"]
|
paymentMethodTypes = ["customer_balance"]
|
||||||
}
|
}
|
||||||
|
|
||||||
const session = await getStripe().checkout.sessions.create({
|
const session = await stripe.checkout.sessions.create({
|
||||||
payment_method_types: paymentMethodTypes,
|
payment_method_types: paymentMethodTypes,
|
||||||
line_items: lineItems,
|
line_items: lineItems,
|
||||||
mode: "payment",
|
mode: "payment",
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,11 @@
|
||||||
import { type NextRequest, NextResponse } from "next/server"
|
import { type NextRequest, NextResponse } from "next/server"
|
||||||
import Stripe from "stripe"
|
import Stripe from "stripe"
|
||||||
|
|
||||||
// Lazy initialization to avoid build-time errors when env vars aren't set
|
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
|
||||||
let stripeInstance: Stripe | null = null
|
apiVersion: "2024-12-18.acacia",
|
||||||
function getStripe(): Stripe {
|
})
|
||||||
if (!stripeInstance) {
|
|
||||||
if (!process.env.STRIPE_SECRET_KEY) {
|
|
||||||
throw new Error("STRIPE_SECRET_KEY is not configured")
|
|
||||||
}
|
|
||||||
stripeInstance = new Stripe(process.env.STRIPE_SECRET_KEY, {
|
|
||||||
apiVersion: "2024-12-18.acacia",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return stripeInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWebhookSecret(): string {
|
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!
|
||||||
if (!process.env.STRIPE_WEBHOOK_SECRET) {
|
|
||||||
throw new Error("STRIPE_WEBHOOK_SECRET is not configured")
|
|
||||||
}
|
|
||||||
return process.env.STRIPE_WEBHOOK_SECRET
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function POST(request: NextRequest) {
|
export async function POST(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -30,7 +15,7 @@ export async function POST(request: NextRequest) {
|
||||||
let event: Stripe.Event
|
let event: Stripe.Event
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event = getStripe().webhooks.constructEvent(body, signature, getWebhookSecret())
|
event = stripe.webhooks.constructEvent(body, signature, webhookSecret)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("[v0] Webhook signature verification failed:", err)
|
console.error("[v0] Webhook signature verification failed:", err)
|
||||||
return NextResponse.json({ error: "Invalid signature" }, { status: 400 })
|
return NextResponse.json({ error: "Invalid signature" }, { status: 400 })
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { ArrowLeft } from "lucide-react"
|
||||||
|
import Link from "next/link"
|
||||||
|
|
||||||
|
export default function GalleryPage() {
|
||||||
|
const photos = [
|
||||||
|
{
|
||||||
|
src: "/images/20220429-145734.jpg",
|
||||||
|
alt: "Commons Hub venue with Austrian Alps mountains backdrop",
|
||||||
|
caption: "The Commons Hub nestled in the foothills of the Austrian Alps",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/images/20220505-113225.jpg",
|
||||||
|
alt: "CCG 2022 group photo with all participants",
|
||||||
|
caption: "The CCG community gathered together in 2022",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/images/20220830-104828.jpg",
|
||||||
|
alt: "Overhead view of unconference discussion circle",
|
||||||
|
caption: "Unconference discussion circles at CCG",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/images/20220503-155430.jpg",
|
||||||
|
alt: "Ground-level view of discussion circle in courtyard",
|
||||||
|
caption: "Participant-driven sessions in the Commons Hub courtyard",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/images/20220429-145359.jpg",
|
||||||
|
alt: "Yellow tulips at Hirschwangerhof venue",
|
||||||
|
caption: "Spring at the Hirschwangerhof venue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/images/image.jpeg",
|
||||||
|
alt: "Evening bonfire gathering",
|
||||||
|
caption: "Evening bonfire gathering with the community",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/images/image.png",
|
||||||
|
alt: "Alpine wildflowers with mountain backdrop",
|
||||||
|
caption: "The natural beauty surrounding the venue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/images/image.jpeg",
|
||||||
|
alt: "Outdoor discussion session with mountain views",
|
||||||
|
caption: "Sessions in a circle with the Austrian Alps as backdrop",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/images/image.png",
|
||||||
|
alt: "Hacking session with participants",
|
||||||
|
caption: "Hands-on building and prototyping sessions",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/images/image.jpeg",
|
||||||
|
alt: "Community meal together",
|
||||||
|
caption: "Shared meals and convivial moments",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen">
|
||||||
|
{/* Header */}
|
||||||
|
<section className="py-16 px-4 bg-muted/30">
|
||||||
|
<div className="container mx-auto max-w-6xl">
|
||||||
|
<Button variant="ghost" className="mb-8" asChild>
|
||||||
|
<Link href="/">
|
||||||
|
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||||
|
Back to Home
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<h1 className="text-4xl md:text-5xl font-bold mb-4 text-balance">Gallery</h1>
|
||||||
|
<p className="text-lg text-muted-foreground max-w-2xl">
|
||||||
|
Explore moments from past Crypto Commons Gatherings - from unconference sessions in the Austrian Alps to
|
||||||
|
community building and lifelong friendships.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Photo Grid */}
|
||||||
|
<section className="py-16 px-4">
|
||||||
|
<div className="container mx-auto max-w-7xl">
|
||||||
|
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{photos.map((photo, index) => (
|
||||||
|
<div key={index} className="group relative overflow-hidden rounded-lg bg-card border border-border">
|
||||||
|
<div className="aspect-[4/3] overflow-hidden">
|
||||||
|
<img
|
||||||
|
src={photo.src || "/placeholder.svg"}
|
||||||
|
alt={photo.alt}
|
||||||
|
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
<p className="text-sm text-muted-foreground">{photo.caption}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* CTA Section */}
|
||||||
|
<section className="py-16 px-4 bg-muted/30">
|
||||||
|
<div className="container mx-auto max-w-3xl text-center">
|
||||||
|
<h2 className="text-3xl font-bold mb-4">Join Us in 2026</h2>
|
||||||
|
<p className="text-muted-foreground mb-8">
|
||||||
|
Be part of the next chapter of Crypto Commons Gathering and create new memories in the Austrian Alps.
|
||||||
|
</p>
|
||||||
|
<Button size="lg" asChild>
|
||||||
|
<Link href="/register">Register for CCG 2026</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -79,6 +79,8 @@
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--font-sans: "Geist", "Geist Fallback";
|
--font-sans: "Geist", "Geist Fallback";
|
||||||
--font-mono: "Geist Mono", "Geist Mono Fallback";
|
--font-mono: "Geist Mono", "Geist Mono Fallback";
|
||||||
|
/* Added spray-paint font for graffiti-style text */
|
||||||
|
--font-spray: "Permanent Marker", "Permanent Marker Fallback", cursive;
|
||||||
--color-background: var(--background);
|
--color-background: var(--background);
|
||||||
--color-foreground: var(--foreground);
|
--color-foreground: var(--foreground);
|
||||||
--color-card: var(--card);
|
--color-card: var(--card);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import type React from "react"
|
import type React from "react"
|
||||||
import type { Metadata } from "next"
|
import type { Metadata } from "next"
|
||||||
import { Geist, Geist_Mono } from "next/font/google"
|
import { Geist, Geist_Mono, Permanent_Marker } from "next/font/google"
|
||||||
import { Analytics } from "@vercel/analytics/next"
|
import { Analytics } from "@vercel/analytics/next"
|
||||||
import "./globals.css"
|
import "./globals.css"
|
||||||
|
|
||||||
const _geist = Geist({ subsets: ["latin"] })
|
const _geist = Geist({ subsets: ["latin"] })
|
||||||
const _geistMono = Geist_Mono({ subsets: ["latin"] })
|
const _geistMono = Geist_Mono({ subsets: ["latin"] })
|
||||||
|
const _permanentMarker = Permanent_Marker({ weight: "400", subsets: ["latin"] })
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Crypto Commons Gathering 2026 | CCG",
|
title: "Crypto Commons Gathering 2026 | CCG",
|
||||||
|
|
|
||||||
201
app/page.tsx
|
|
@ -1,11 +1,55 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
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 } from "lucide-react"
|
import { ArrowRight, Calendar, MapPin, Users, Heart, Sprout, Network, X } from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
import { useState } from "react"
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
|
const [selectedImage, setSelectedImage] = useState<string | null>(null)
|
||||||
|
|
||||||
|
const handleImageClick = (imageSrc: string) => {
|
||||||
|
setSelectedImage(imageSrc)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCloseModal = () => {
|
||||||
|
setSelectedImage(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||||
|
if (e.key === "Escape") {
|
||||||
|
handleCloseModal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen">
|
<div className="min-h-screen">
|
||||||
|
{selectedImage && (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 z-50 flex items-center justify-center bg-black/90 p-4"
|
||||||
|
onClick={handleCloseModal}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="absolute top-4 right-4 text-white hover:text-white/70 transition-colors"
|
||||||
|
onClick={handleCloseModal}
|
||||||
|
aria-label="Close"
|
||||||
|
>
|
||||||
|
<X className="w-8 h-8" />
|
||||||
|
</button>
|
||||||
|
<img
|
||||||
|
src={selectedImage || "/placeholder.svg"}
|
||||||
|
alt="Zoomed view"
|
||||||
|
className="max-w-full max-h-[90vh] object-contain rounded-lg"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
<section className="relative min-h-[90vh] flex items-center justify-center overflow-hidden">
|
<section className="relative min-h-[90vh] flex items-center justify-center overflow-hidden">
|
||||||
<div
|
<div
|
||||||
|
|
@ -17,7 +61,11 @@ export default function HomePage() {
|
||||||
<div className="absolute inset-0 bg-gradient-to-b from-background/80 via-background/70 to-background z-[1]" />
|
<div className="absolute inset-0 bg-gradient-to-b from-background/80 via-background/70 to-background z-[1]" />
|
||||||
|
|
||||||
<div className="container mx-auto px-4 relative z-10 text-center max-w-5xl">
|
<div className="container mx-auto px-4 relative z-10 text-center max-w-5xl">
|
||||||
<h1 className="text-5xl md:text-7xl lg:text-8xl font-bold mb-6 text-balance leading-[1.1]">
|
<p className="text-xl md:text-2xl font-spray text-primary mb-2 tracking-wide animate-in fade-in slide-in-from-bottom-4 duration-700 [text-shadow:_2px_2px_0_rgb(0_0_0_/_10%)]">
|
||||||
|
Join the SIXTH edition of the
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h1 className="text-5xl md:text-7xl lg:text-8xl font-black mb-6 text-balance leading-[1.05] tracking-tight animate-in fade-in slide-in-from-bottom-6 duration-1000 [font-feature-settings:'ss01'] [text-shadow:_3px_3px_0_rgb(0_0_0_/_5%)]">
|
||||||
Crypto Commons
|
Crypto Commons
|
||||||
<br />
|
<br />
|
||||||
Gathering
|
Gathering
|
||||||
|
|
@ -28,8 +76,8 @@ export default function HomePage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-lg md:text-xl text-muted-foreground mb-8 max-w-2xl mx-auto text-pretty leading-relaxed">
|
<p className="text-lg md:text-xl text-muted-foreground mb-8 max-w-2xl mx-auto text-pretty leading-relaxed">
|
||||||
A hack-ademic confluence of commons praxis and the latest cryptographic technologies, set in the foothills
|
A week-long retreat where genuine desire for postcapitalist change meets blockchain tinkering, commons
|
||||||
of 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-12">
|
||||||
|
|
@ -66,18 +114,35 @@ export default function HomePage() {
|
||||||
<section className="py-16 px-4 bg-background">
|
<section className="py-16 px-4 bg-background">
|
||||||
<div className="container mx-auto max-w-6xl">
|
<div className="container mx-auto max-w-6xl">
|
||||||
<div className="grid md:grid-cols-3 gap-4">
|
<div className="grid md:grid-cols-3 gap-4">
|
||||||
<div className="aspect-[4/3] rounded-lg overflow-hidden">
|
<div
|
||||||
|
className="aspect-[4/3] rounded-lg overflow-hidden cursor-pointer hover:opacity-90 transition-opacity"
|
||||||
|
onClick={() => handleImageClick("/images/20220901-085249.jpg")}
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
src="/images/image.jpeg"
|
src="/images/20220901-085249.jpg"
|
||||||
alt="CCG participants in discussion circle"
|
alt="Wooden bridge in Reichenau an der Rax with Austrian Alps"
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="aspect-[4/3] rounded-lg overflow-hidden">
|
<div
|
||||||
<img src="/images/image.jpeg" alt="Community meal at CCG" className="w-full h-full object-cover" />
|
className="aspect-[4/3] rounded-lg overflow-hidden cursor-pointer hover:opacity-90 transition-opacity"
|
||||||
|
onClick={() => handleImageClick("/images/20220505-113225.jpg")}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="/images/20220505-113225.jpg"
|
||||||
|
alt="CCG 2022 community group photo in the Austrian Alps"
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="aspect-[4/3] rounded-lg overflow-hidden">
|
<div
|
||||||
<img src="/images/image.png" alt="Hands-on hacking at CCG" className="w-full h-full object-cover" />
|
className="aspect-[4/3] rounded-lg overflow-hidden cursor-pointer hover:opacity-90 transition-opacity"
|
||||||
|
onClick={() => handleImageClick("/images/20220429-145734.jpg")}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="/images/20220429-145734.jpg"
|
||||||
|
alt="Commons Hub venue in the Austrian Alps"
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -88,21 +153,18 @@ export default function HomePage() {
|
||||||
<div className="container mx-auto max-w-6xl">
|
<div className="container mx-auto max-w-6xl">
|
||||||
<div className="grid md:grid-cols-2 gap-12 items-center">
|
<div className="grid md:grid-cols-2 gap-12 items-center">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-balance">The Best Event in the World</h2>
|
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-balance">What is CCG?</h2>
|
||||||
<p className="text-muted-foreground leading-relaxed mb-4">
|
<p className="text-muted-foreground leading-relaxed mb-4">
|
||||||
Join us for an unconference-style gathering where you bring as much as you receive. Friendships are made
|
The Crypto Commons Gathering (CCG) is an annual week-long retreat organised by the Crypto Commons
|
||||||
that last a lifetime, and solidarity is built that might just coalesce into new digital public
|
Association in collaboration with the Commons Hub. To its growing community, it serves as a recurring
|
||||||
infrastructures.
|
temporary refuge from late-capitalism (or something worse) and as a convivium to reimagine how we
|
||||||
|
organize value, care and meaning for a "post-capitalist world of many worlds".
|
||||||
</p>
|
</p>
|
||||||
<p className="text-muted-foreground leading-relaxed mb-4">
|
<p className="text-muted-foreground leading-relaxed mb-4">
|
||||||
CCG has spawned movements like <span className="text-primary font-semibold">#CoFi</span> and{" "}
|
2026 marks the 6th edition of the CCG — six years of bringing together commons builders, token
|
||||||
<span className="text-primary font-semibold">#MycoFi</span>, and holds the possibility for a new
|
tinkerers, speculative worldbuilders, artists, complex systems thinkers, degens turned regen, and
|
||||||
technologically-enabled commons that leverages network technologies to regain ground against state and
|
everyone curious about the weird futures that emerge when crypto meets genuine international and
|
||||||
corporate control.
|
intersectional postcapitalist desire.
|
||||||
</p>
|
|
||||||
<p className="text-muted-foreground leading-relaxed">
|
|
||||||
What began in 2020 as a modest gathering has evolved into an annual moment of (re)connection and
|
|
||||||
reflection for a growing community of crypto-commons thinkers from around the world.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -148,33 +210,44 @@ export default function HomePage() {
|
||||||
{/* Themes Section */}
|
{/* Themes Section */}
|
||||||
<section className="py-24 px-4">
|
<section className="py-24 px-4">
|
||||||
<div className="container mx-auto max-w-5xl">
|
<div className="container mx-auto max-w-5xl">
|
||||||
<h2 className="text-3xl md:text-4xl font-bold mb-4 text-center text-balance">Explore Key Themes</h2>
|
<h2 className="text-3xl md:text-4xl font-bold mb-4 text-center text-balance">Themes: What to Expect</h2>
|
||||||
<p className="text-muted-foreground text-center mb-12 max-w-2xl mx-auto">
|
<p className="text-muted-foreground text-center mb-12 max-w-3xl mx-auto leading-relaxed">
|
||||||
Through participant-led sessions, we collectively explore the intersection of commoning, degrowth, and web3
|
Talks, workshops, and spontaneous experiments at CCG cover a wide range of topics. They often start with a
|
||||||
|
curiosity in using blockchain, tokenization and decentralized governance for the common good, but rarely
|
||||||
|
stay there exclusively – cooperative, non-crypto alternatives, open source projects, degrowth initiatives,
|
||||||
|
and other spheres increasingly cross-pollinate here under a decolonial, feminist, queer,
|
||||||
|
multispecies-attuned frame.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className="grid sm:grid-cols-2 gap-6 mb-8">
|
||||||
{[
|
<Card className="border-primary/20">
|
||||||
"Regenerative Finance",
|
<CardContent className="p-6">
|
||||||
"MycoFi",
|
<h3 className="font-bold mb-3 text-lg">Regenerative & Collaborative Finance</h3>
|
||||||
"Community Currencies",
|
<p className="text-sm text-muted-foreground">
|
||||||
"Digital Commons",
|
ReFi DAO, EthicHub, CoFi Gathering, Regen Network, Circles UBI
|
||||||
"Crypto Commons",
|
</p>
|
||||||
"Open Source",
|
</CardContent>
|
||||||
"Degrowth",
|
</Card>
|
||||||
"Post-Capitalism",
|
<Card className="border-primary/20">
|
||||||
"Ecofeminism",
|
<CardContent className="p-6">
|
||||||
"Multispecies Justice",
|
<h3 className="font-bold mb-3 text-lg">Myco-Economics</h3>
|
||||||
"Radical Game Design",
|
<p className="text-sm text-muted-foreground">MycoFi and interconnected economic models</p>
|
||||||
"Speculative Fiction",
|
</CardContent>
|
||||||
].map((theme) => (
|
</Card>
|
||||||
<div
|
<Card className="border-primary/20">
|
||||||
key={theme}
|
<CardContent className="p-6">
|
||||||
className="p-4 bg-card border border-border rounded-lg hover:border-primary/40 transition-colors"
|
<h3 className="font-bold mb-3 text-lg">Governance & Mutualism</h3>
|
||||||
>
|
<p className="text-sm text-muted-foreground">Economic Space Agency, Bread Coop, Holochain</p>
|
||||||
<p className="font-medium text-card-foreground">{theme}</p>
|
</CardContent>
|
||||||
</div>
|
</Card>
|
||||||
))}
|
<Card className="border-primary/20">
|
||||||
|
<CardContent className="p-6">
|
||||||
|
<h3 className="font-bold mb-3 text-lg">Solarpunk & Radical Games</h3>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
pocas, Solar Punk WOW, Futurescraft, economic science fiction
|
||||||
|
</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -190,21 +263,16 @@ export default function HomePage() {
|
||||||
<div className="absolute inset-0 bg-primary/90" />
|
<div className="absolute inset-0 bg-primary/90" />
|
||||||
<div className="container mx-auto max-w-4xl text-center relative z-10">
|
<div className="container mx-auto max-w-4xl text-center relative z-10">
|
||||||
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-balance text-primary-foreground">
|
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-balance text-primary-foreground">
|
||||||
What is an Unconference?
|
Format: How We Explore
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg leading-relaxed opacity-90 mb-8 text-primary-foreground">
|
<p className="text-lg leading-relaxed opacity-90 mb-8 text-primary-foreground">
|
||||||
An unconference is a participant-driven event format that emphasizes open, flexible, and spontaneous
|
CCG follows an open space or "unconference" format. This means the schedule is co-created on-site by all
|
||||||
discussions rather than traditional pre-planned presentations. Unlike conventional conferences,
|
participants: during the daily morning circle, anyone can propose a session, host a discussion, or start a
|
||||||
unconferences have no predefined agenda or speakers.
|
collective experiment, and schedule it at one of five sites across the Hub, each with its own affordances.
|
||||||
</p>
|
|
||||||
<p className="leading-relaxed opacity-90 mb-8 text-primary-foreground">
|
|
||||||
Attendees collaboratively propose topics, sessions, and activities on the spot. Participants vote or
|
|
||||||
self-organize around topics they find most interesting, forming small groups or breakout sessions where
|
|
||||||
discussions, workshops, or hands-on activities take place.
|
|
||||||
</p>
|
</p>
|
||||||
<p className="leading-relaxed opacity-90 text-primary-foreground">
|
<p className="leading-relaxed opacity-90 text-primary-foreground">
|
||||||
Everyone is considered equally qualified to contribute, share insights, and guide conversations. Bring your
|
Workshops, keynotes, rituals, games and evening performances traditionally unfold organically, reflecting
|
||||||
ideas for talks, roundtables, workshops, prototyping sessions, board game nights, LARPs, and more.
|
the shared interests, dynamics and projects that emerge over the week.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -216,7 +284,7 @@ export default function HomePage() {
|
||||||
<div className="order-2 md:order-1">
|
<div className="order-2 md:order-1">
|
||||||
<div className="aspect-[4/3] bg-muted rounded-lg overflow-hidden">
|
<div className="aspect-[4/3] bg-muted rounded-lg overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src="/austrian-alps-foothills-mountain-landscape-with-tr.jpg"
|
src="/images/20220429-145734.jpg"
|
||||||
alt="Commons Hub in the Austrian Alps"
|
alt="Commons Hub in the Austrian Alps"
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
|
|
@ -280,7 +348,6 @@ export default function HomePage() {
|
||||||
<Link href="/transparency">Financial Transparency</Link>
|
<Link href="/transparency">Financial Transparency</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</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>
|
||||||
|
|
@ -304,10 +371,12 @@ export default function HomePage() {
|
||||||
<h3 className="font-semibold mb-4 text-sm">Links</h3>
|
<h3 className="font-semibold mb-4 text-sm">Links</h3>
|
||||||
<ul className="space-y-2 text-sm">
|
<ul className="space-y-2 text-sm">
|
||||||
<li>
|
<li>
|
||||||
<Link
|
<Link href="/gallery" className="text-muted-foreground hover:text-foreground transition-colors">
|
||||||
href="https://ccg2025.vercel.app/about"
|
Gallery
|
||||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
</Link>
|
||||||
>
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link href="/about" className="text-muted-foreground hover:text-foreground transition-colors">
|
||||||
About CCG 2026
|
About CCG 2026
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -372,7 +441,7 @@ export default function HomePage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="pt-8 border-t border-border text-center text-sm text-muted-foreground">
|
<div className="pt-8 border-t border-border text-center text-sm text-muted-foreground">
|
||||||
<p>© 2026 Crypto Commons Gathering. Built with solidarity for the commons.</p>
|
<p>This website is under Creative Commons license. Built with solidarity for the commons.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ export default function RegisterPage() {
|
||||||
food: false,
|
food: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const baseTicketPrice = 200
|
const baseTicketPrice = 80 // Updated to early bird price €80
|
||||||
const accommodationPrice = 227.4
|
const accommodationPrice = 39.2 * 6 // Updated to €39.20/night * 6 nights = €235.20
|
||||||
const foodPrice = 135
|
const foodPrice = 35 * 3 + 10 * 3 // Updated to reflect catered (€35*3) + self-organized (€10*3) = €135
|
||||||
const calculateTotal = () => {
|
const calculateTotal = () => {
|
||||||
let total = baseTicketPrice
|
let total = baseTicketPrice
|
||||||
if (packages.accommodation) total += accommodationPrice
|
if (packages.accommodation) total += accommodationPrice
|
||||||
|
|
@ -83,7 +83,9 @@ export default function RegisterPage() {
|
||||||
<Card className="mb-8 border-primary/40">
|
<Card className="mb-8 border-primary/40">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Select Your Packages</CardTitle>
|
<CardTitle>Select Your Packages</CardTitle>
|
||||||
<CardDescription>Ticket is required. Add accommodation and food as needed.</CardDescription>
|
<CardDescription>
|
||||||
|
Ticket is required (€80 early bird until Dec 31, 2025). Add accommodation and food as needed.
|
||||||
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
|
@ -93,10 +95,16 @@ export default function RegisterPage() {
|
||||||
<Checkbox checked disabled className="mt-1" />
|
<Checkbox checked disabled className="mt-1" />
|
||||||
<div>
|
<div>
|
||||||
<div className="font-medium">CCG 2026 Ticket (Required)</div>
|
<div className="font-medium">CCG 2026 Ticket (Required)</div>
|
||||||
<div className="text-sm text-muted-foreground">Venue rental & infrastructure</div>
|
<div className="text-sm text-muted-foreground">
|
||||||
|
€80 Early bird (until Dec 31, 2025) • €120 Regular (Jan-Jun 2026) • €150 Late (after Jul 1,
|
||||||
|
2026)
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-muted-foreground mt-1">
|
||||||
|
CCA members: Bring two newcomers, get a free ticket!
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-lg font-semibold">€200.00</span>
|
<span className="text-lg font-semibold">€{baseTicketPrice}.00</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Accommodation */}
|
{/* Accommodation */}
|
||||||
|
|
@ -110,10 +118,13 @@ export default function RegisterPage() {
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="accommodation" className="cursor-pointer">
|
<Label htmlFor="accommodation" className="cursor-pointer">
|
||||||
<div className="font-medium">Accommodation (Optional)</div>
|
<div className="font-medium">Accommodation (Optional)</div>
|
||||||
<div className="text-sm text-muted-foreground">6 nights dorm at Commons Hub (€37.90/night)</div>
|
<div className="text-sm text-muted-foreground">6 nights dorm at Commons Hub (€39.20/night)</div>
|
||||||
|
<div className="text-xs text-muted-foreground mt-1">
|
||||||
|
Double rooms available at €50.20/night per person
|
||||||
|
</div>
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-lg font-semibold">€227.40</span>
|
<span className="text-lg font-semibold">€{accommodationPrice.toFixed(2)}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Food */}
|
{/* Food */}
|
||||||
|
|
@ -127,10 +138,13 @@ export default function RegisterPage() {
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="food" className="cursor-pointer">
|
<Label htmlFor="food" className="cursor-pointer">
|
||||||
<div className="font-medium">Food Package (Optional)</div>
|
<div className="font-medium">Food Package (Optional)</div>
|
||||||
<div className="text-sm text-muted-foreground">6 days of meals (€22.50/day avg)</div>
|
<div className="text-sm text-muted-foreground">6 days: vegetarian breakfast, lunch & dinner</div>
|
||||||
|
<div className="text-xs text-muted-foreground mt-1">
|
||||||
|
3 days catered (€35/day), 3 days self-organized (€10/day)
|
||||||
|
</div>
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-lg font-semibold">€135.00</span>
|
<span className="text-lg font-semibold">€{foodPrice.toFixed(2)}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Total */}
|
{/* Total */}
|
||||||
|
|
|
||||||
|
|
@ -40,18 +40,45 @@ export default function FinancialTransparencyPage() {
|
||||||
{/* Ticket Price */}
|
{/* Ticket Price */}
|
||||||
<Card className="mb-8">
|
<Card className="mb-8">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-2xl">Ticket Price</CardTitle>
|
<CardTitle className="text-2xl">Ticket Pricing</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<div className="flex items-baseline gap-4">
|
<div className="space-y-4 mb-6">
|
||||||
<span className="text-4xl font-bold text-primary">€200</span>
|
<div className="flex items-baseline justify-between border-b pb-3">
|
||||||
<span className="text-muted-foreground">per person</span>
|
<div>
|
||||||
|
<span className="text-3xl font-bold text-primary">€80</span>
|
||||||
|
<span className="text-sm text-muted-foreground ml-3">Early bird</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-muted-foreground">Until Dec 31, 2025</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-baseline justify-between border-b pb-3">
|
||||||
|
<div>
|
||||||
|
<span className="text-3xl font-bold">€120</span>
|
||||||
|
<span className="text-sm text-muted-foreground ml-3">Regular</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-muted-foreground">Jan 1 – Jun 30, 2026</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-baseline justify-between pb-3">
|
||||||
|
<div>
|
||||||
|
<span className="text-3xl font-bold">€150</span>
|
||||||
|
<span className="text-sm text-muted-foreground ml-3">Late</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-muted-foreground">After Jul 1, 2026</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-accent/20 border border-accent p-4 rounded-lg">
|
||||||
|
<p className="font-semibold mb-2">CCA Members Special:</p>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Bring two newcomers (who've never attended CCG before) and get a free ticket! If you've already paid,
|
||||||
|
we'll refund you.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p className="text-muted-foreground leading-relaxed">
|
<p className="text-muted-foreground leading-relaxed">
|
||||||
The ticket price is set to cover the venue rental and basic infrastructure, based on expected
|
The ticket price covers venue rental and basic infrastructure. No one from the organizing team is being
|
||||||
attendance. No one from the organizing team is being paid from ticket sales, and all are covering their
|
paid from ticket sales, and all are covering their own travel, food and accommodation, until more
|
||||||
own travel, food and accommodation, until more sustainable structures and future sponsorships are in
|
sustainable structures and future sponsorships are in place.
|
||||||
place.
|
|
||||||
</p>
|
</p>
|
||||||
<div className="pt-4">
|
<div className="pt-4">
|
||||||
<Button asChild>
|
<Button asChild>
|
||||||
|
|
@ -68,19 +95,41 @@ export default function FinancialTransparencyPage() {
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<p className="text-sm text-muted-foreground mb-4">
|
<p className="text-sm text-muted-foreground mb-4">
|
||||||
Note that accommodation is not included in the ticket price. These are provided by the Commons Hub:
|
The Commons Hub offers 30 beds on-site. Accommodation is not included in the ticket price:
|
||||||
</p>
|
</p>
|
||||||
<div className="bg-muted/50 p-6 rounded-lg">
|
<div className="space-y-3">
|
||||||
<div className="flex items-baseline gap-3 mb-2">
|
<div className="bg-muted/50 p-6 rounded-lg">
|
||||||
<span className="text-3xl font-bold">€37.90</span>
|
<div className="flex items-baseline gap-3 mb-2">
|
||||||
<span className="text-muted-foreground">per night</span>
|
<span className="text-3xl font-bold">€39.20</span>
|
||||||
|
<span className="text-muted-foreground">per night</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground">26 beds in dorms</p>
|
||||||
|
</div>
|
||||||
|
<div className="bg-muted/50 p-6 rounded-lg">
|
||||||
|
<div className="flex items-baseline gap-3 mb-2">
|
||||||
|
<span className="text-3xl font-bold">€50.20</span>
|
||||||
|
<span className="text-muted-foreground">per night per person</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground">4 beds in double rooms</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-muted-foreground">Dorm accommodation</p>
|
|
||||||
</div>
|
</div>
|
||||||
<p className="text-muted-foreground leading-relaxed">
|
<div className="pt-4">
|
||||||
Accommodation includes shared dormitory-style rooms with basic amenities. Bedding and towels are
|
<h4 className="font-semibold mb-3">Additional accommodation nearby:</h4>
|
||||||
provided.
|
<ul className="space-y-2 text-sm text-muted-foreground">
|
||||||
</p>
|
<li className="flex items-start gap-2">
|
||||||
|
<CheckCircle2 className="w-4 h-4 text-primary mt-0.5 flex-shrink-0" />
|
||||||
|
<span>
|
||||||
|
<strong>Herrnhof.at</strong> — comfortable apartments, ideal for teams
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li className="flex items-start gap-2">
|
||||||
|
<CheckCircle2 className="w-4 h-4 text-primary mt-0.5 flex-shrink-0" />
|
||||||
|
<span>
|
||||||
|
<strong>Gasthof Kobald</strong> — simple rooms, affordable, 12 min walk from the hub
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|
@ -91,39 +140,55 @@ export default function FinancialTransparencyPage() {
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<p className="text-sm text-muted-foreground mb-4">
|
<p className="text-sm text-muted-foreground mb-4">
|
||||||
Food is also not included in the ticket price and is provided by the Commons Hub:
|
Food is not included in the ticket price and is provided by the Commons Hub:
|
||||||
</p>
|
</p>
|
||||||
<div className="bg-muted/50 p-6 rounded-lg mb-4">
|
|
||||||
<div className="flex items-baseline gap-3 mb-2">
|
|
||||||
<span className="text-3xl font-bold">€22.50</span>
|
|
||||||
<span className="text-muted-foreground">per day average</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div className="bg-muted/50 p-6 rounded-lg">
|
||||||
<h4 className="font-semibold mb-2">Breakdown:</h4>
|
<h4 className="font-semibold mb-3">What's Included:</h4>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
<li className="flex items-start gap-2">
|
<li className="flex items-start gap-2">
|
||||||
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
|
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
|
||||||
<span className="text-muted-foreground">
|
<span className="text-sm">A rich vegetarian breakfast buffet</span>
|
||||||
<strong>First 3 days:</strong> fully catered at €35/day
|
|
||||||
</span>
|
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-start gap-2">
|
<li className="flex items-start gap-2">
|
||||||
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
|
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
|
||||||
<span className="text-muted-foreground">
|
<span className="text-sm">Coffee & tea throughout the day</span>
|
||||||
<strong>Last 3 days:</strong> self-organized by participants and the Crypto Commons Association
|
</li>
|
||||||
at ~€10/day
|
<li className="flex items-start gap-2">
|
||||||
|
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
|
||||||
|
<span className="text-sm">Catered lunches (vegetarian/vegan and meat-based options)</span>
|
||||||
|
</li>
|
||||||
|
<li className="flex items-start gap-2">
|
||||||
|
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
|
||||||
|
<span className="text-sm">Catered dinners from Aug 17-21</span>
|
||||||
|
</li>
|
||||||
|
<li className="flex items-start gap-2">
|
||||||
|
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
|
||||||
|
<span className="text-sm">
|
||||||
|
Self-made dinners on Aug 16 & 22, prepared by community kitchen team
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-muted-foreground leading-relaxed">
|
<div className="bg-muted/50 p-6 rounded-lg">
|
||||||
Meals include breakfast, lunch, and dinner with vegetarian and vegan options available. The
|
<h4 className="font-semibold mb-2">Estimated Cost:</h4>
|
||||||
self-organized days involve communal cooking and shared meal preparation.
|
<div className="space-y-2 text-sm">
|
||||||
</p>
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">First 3 days (fully catered)</span>
|
||||||
|
<span className="font-semibold">€35/day</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-muted-foreground">Last 3 days (self-organized)</span>
|
||||||
|
<span className="font-semibold">~€10/day</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between pt-2 border-t">
|
||||||
|
<span className="font-semibold">Total for 6 days</span>
|
||||||
|
<span className="font-bold text-lg">€135</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -135,31 +200,31 @@ export default function FinancialTransparencyPage() {
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<p className="text-muted-foreground mb-6">
|
<p className="text-muted-foreground mb-6">
|
||||||
For the full 6-day event (August 16-22, 2026), here's what you can expect to pay:
|
For the full event (August 16-22, 2026), here's what you can expect to pay with early bird pricing:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="flex justify-between items-center py-3 border-b border-border">
|
<div className="flex justify-between items-center py-3 border-b border-border">
|
||||||
<span className="font-medium">Ticket</span>
|
<span className="font-medium">Ticket (Early bird)</span>
|
||||||
<span className="text-lg font-semibold">€200</span>
|
<span className="text-lg font-semibold">€80</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center py-3 border-b border-border">
|
<div className="flex justify-between items-center py-3 border-b border-border">
|
||||||
<span className="font-medium">Accommodation (6 nights)</span>
|
<span className="font-medium">Accommodation (6 nights, dorm)</span>
|
||||||
<span className="text-lg font-semibold">€227.40</span>
|
<span className="text-lg font-semibold">€235.20</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center py-3 border-b border-border">
|
<div className="flex justify-between items-center py-3 border-b border-border">
|
||||||
<span className="font-medium">Food (6 days)</span>
|
<span className="font-medium">Food (6 days)</span>
|
||||||
<span className="text-lg font-semibold">€135</span>
|
<span className="text-lg font-semibold">€135</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center py-4 bg-primary/10 -mx-6 px-6 mt-4">
|
<div className="flex justify-between items-center py-4 bg-primary/10 -mx-6 px-6 mt-4">
|
||||||
<span className="font-bold text-lg">Total</span>
|
<span className="font-bold text-lg">Total (Early bird)</span>
|
||||||
<span className="text-2xl font-bold text-primary">€562.40</span>
|
<span className="text-2xl font-bold text-primary">€450.20</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-sm text-muted-foreground italic pt-4">
|
<p className="text-sm text-muted-foreground italic pt-4">
|
||||||
*This is an estimate. Final costs may vary slightly based on actual meal arrangements and accommodation
|
*With regular pricing (€120 ticket), total would be €490.20. With late pricing (€150 ticket), total
|
||||||
choices.
|
would be €520.20.
|
||||||
</p>
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
services:
|
|
||||||
ccg-website:
|
|
||||||
build: .
|
|
||||||
container_name: ccg-website
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
|
|
||||||
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
|
|
||||||
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY}
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.ccg.rule=Host(`cryptocommonsgather.ing`) || Host(`www.cryptocommonsgather.ing`)"
|
|
||||||
- "traefik.http.routers.ccg.entrypoints=web,websecure"
|
|
||||||
- "traefik.http.services.ccg.loadbalancer.server.port=3000"
|
|
||||||
networks:
|
|
||||||
- traefik-public
|
|
||||||
|
|
||||||
networks:
|
|
||||||
traefik-public:
|
|
||||||
external: true
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
output: 'standalone',
|
|
||||||
typescript: {
|
typescript: {
|
||||||
ignoreBuildErrors: true,
|
ignoreBuildErrors: true,
|
||||||
},
|
},
|
||||||
images: {
|
images: {
|
||||||
unoptimized: true,
|
unoptimized: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default nextConfig
|
export default nextConfig
|
||||||
|
After Width: | Height: | Size: 2.3 MiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 176 KiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 503 KiB After Width: | Height: | Size: 580 KiB |