Initial commit with OG metadata
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
@ -0,0 +1,27 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files
|
||||
.env*
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
COPY package.json pnpm-lock.yaml* package-lock.json* ./
|
||||
RUN if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile; elif [ -f package-lock.json ]; then npm ci; else npm install; fi
|
||||
COPY . .
|
||||
RUN if [ -f pnpm-lock.yaml ]; then pnpm build; else npm run build; fi
|
||||
|
||||
FROM nginx:alpine
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=builder /app/out /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# Alltor.net website design
|
||||
|
||||
*Automatically synced with your [v0.app](https://v0.app) deployments*
|
||||
|
||||
[](https://vercel.com/jeff-emmetts-projects/v0-alltor-net-website-design)
|
||||
[](https://v0.app/chat/o3bjTso55bY)
|
||||
|
||||
## Overview
|
||||
|
||||
This repository will stay in sync with your deployed chats on [v0.app](https://v0.app).
|
||||
Any changes you make to your deployed app will be automatically pushed to this repository from [v0.app](https://v0.app).
|
||||
|
||||
## Deployment
|
||||
|
||||
Your project is live at:
|
||||
|
||||
**[https://vercel.com/jeff-emmetts-projects/v0-alltor-net-website-design](https://vercel.com/jeff-emmetts-projects/v0-alltor-net-website-design)**
|
||||
|
||||
## Build your app
|
||||
|
||||
Continue building your app on:
|
||||
|
||||
**[https://v0.app/chat/o3bjTso55bY](https://v0.app/chat/o3bjTso55bY)**
|
||||
|
||||
## How It Works
|
||||
|
||||
1. Create and modify your project using [v0.app](https://v0.app)
|
||||
2. Deploy your chats from the v0 interface
|
||||
3. Changes are automatically pushed to this repository
|
||||
4. Vercel deploys the latest version from this repository
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
:root {
|
||||
--background: oklch(1 0 0); /* Pure white */
|
||||
--foreground: oklch(0.05 0 0); /* Almost black */
|
||||
--card: oklch(0.95 0 0); /* Very light grey */
|
||||
--card-foreground: oklch(0.05 0 0);
|
||||
--primary: oklch(0.05 0 0); /* Black for primary actions */
|
||||
--primary-foreground: oklch(1 0 0); /* White text on black */
|
||||
--secondary: oklch(0.85 0 0); /* Light grey */
|
||||
--secondary-foreground: oklch(0.05 0 0);
|
||||
--muted: oklch(0.7 0 0); /* Mid grey */
|
||||
--muted-foreground: oklch(0.4 0 0); /* Darker grey */
|
||||
--accent: oklch(0.2 0 0); /* Dark grey */
|
||||
--accent-foreground: oklch(1 0 0);
|
||||
--border: oklch(0.85 0 0);
|
||||
--input: oklch(0.9 0 0);
|
||||
--ring: oklch(0.3 0 0);
|
||||
--radius: 0rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.05 0 0); /* Almost black */
|
||||
--foreground: oklch(1 0 0); /* Pure white */
|
||||
--card: oklch(0.1 0 0); /* Very dark grey */
|
||||
--card-foreground: oklch(1 0 0);
|
||||
--primary: oklch(1 0 0); /* White for primary */
|
||||
--primary-foreground: oklch(0.05 0 0);
|
||||
--secondary: oklch(0.15 0 0); /* Dark grey */
|
||||
--secondary-foreground: oklch(1 0 0);
|
||||
--muted: oklch(0.25 0 0); /* Mid-dark grey */
|
||||
--muted-foreground: oklch(0.6 0 0);
|
||||
--accent: oklch(0.8 0 0); /* Light grey */
|
||||
--accent-foreground: oklch(0.05 0 0);
|
||||
--border: oklch(0.2 0 0);
|
||||
--input: oklch(0.15 0 0);
|
||||
--ring: oklch(0.7 0 0);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--font-sans: "Geist", "Geist Fallback";
|
||||
--font-mono: "Geist Mono", "Geist Mono Fallback";
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import type React from "react"
|
||||
import type { Metadata } from "next"
|
||||
import { Geist, Geist_Mono } from "next/font/google"
|
||||
import { Analytics } from "@vercel/analytics/next"
|
||||
import "./globals.css"
|
||||
|
||||
const _geist = Geist({ subsets: ["latin"] })
|
||||
const _geistMono = Geist_Mono({ subsets: ["latin"] })
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL("https://alltor.net"),
|
||||
title: "alltor.net - The Alternative Internet",
|
||||
description:
|
||||
"A distributed, local-first, collaborative digital ecosystem. Access the alternative internet through physical USB keys and local mesh networks.",
|
||||
generator: "v0.app",
|
||||
icons: {
|
||||
icon: "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🧅</text></svg>",
|
||||
},
|
||||
openGraph: {
|
||||
title: "alltor.net - The Alternative Internet",
|
||||
description:
|
||||
"A distributed, local-first, collaborative digital ecosystem. Access the alternative internet through physical USB keys and local mesh networks.",
|
||||
url: "https://alltor.net",
|
||||
siteName: "alltor.net",
|
||||
images: [
|
||||
{
|
||||
url: "/og-image.jpg",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: "alltor.net - The Alternative Internet",
|
||||
},
|
||||
],
|
||||
locale: "en_US",
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "alltor.net - The Alternative Internet",
|
||||
description:
|
||||
"A distributed, local-first, collaborative digital ecosystem. Access the alternative internet through physical USB keys and local mesh networks.",
|
||||
images: ["/og-image.jpg"],
|
||||
},
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={`font-sans antialiased`}>
|
||||
{children}
|
||||
<Analytics />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { Hero } from "@/components/hero"
|
||||
import { Features } from "@/components/features"
|
||||
import { HowItWorks } from "@/components/how-it-works"
|
||||
import { Philosophy } from "@/components/philosophy"
|
||||
import { NewsletterSignup } from "@/components/newsletter-signup"
|
||||
import { Footer } from "@/components/footer"
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main className="min-h-screen">
|
||||
<Hero />
|
||||
<Features />
|
||||
<HowItWorks />
|
||||
<Philosophy />
|
||||
<NewsletterSignup />
|
||||
<Footer />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": true,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "app/globals.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import { Shield, Network, Users, Lock, Zap, Globe } from "lucide-react"
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: Network,
|
||||
title: "Distributed Architecture",
|
||||
description: "No central servers. No single point of failure. Your data lives on the mesh.",
|
||||
},
|
||||
{
|
||||
icon: Lock,
|
||||
title: "Zero Knowledge",
|
||||
description: "End-to-end encrypted by default. Nobody can see your data, not even us.",
|
||||
},
|
||||
{
|
||||
icon: Users,
|
||||
title: "Collaborative First",
|
||||
description: "Built for cooperation. Share resources, knowledge, and compute power.",
|
||||
},
|
||||
{
|
||||
icon: Shield,
|
||||
title: "Democratic Governance",
|
||||
description: "Community-driven decisions. No corporate overlords controlling your experience.",
|
||||
},
|
||||
{
|
||||
icon: Zap,
|
||||
title: "Local First",
|
||||
description: "Work offline. Sync when connected. Your data is always accessible.",
|
||||
},
|
||||
{
|
||||
icon: Globe,
|
||||
title: "New Economic Models",
|
||||
description: "Fair value distribution. Contributors are rewarded, not exploited.",
|
||||
},
|
||||
]
|
||||
|
||||
export function Features() {
|
||||
return (
|
||||
<section className="py-32 bg-background">
|
||||
<div className="container px-4">
|
||||
<div className="max-w-3xl mx-auto text-center mb-20">
|
||||
<h2 className="text-5xl md:text-6xl font-bold mb-6 text-balance">A New Digital Foundation</h2>
|
||||
<p className="text-xl text-muted-foreground text-balance leading-relaxed">
|
||||
Built on principles of freedom, privacy, and collective ownership. The internet as it should have been.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto">
|
||||
{features.map((feature, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="group p-8 border border-border hover:border-foreground transition-colors bg-card"
|
||||
>
|
||||
<div className="mb-6">
|
||||
<div className="inline-flex p-3 bg-foreground text-background">
|
||||
<feature.icon className="w-6 h-6" />
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold mb-3">{feature.title}</h3>
|
||||
<p className="text-muted-foreground leading-relaxed">{feature.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
import { Usb } from "lucide-react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer className="bg-black text-white py-20">
|
||||
<div className="container px-4">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="grid md:grid-cols-2 gap-12 items-center pb-12 border-b border-white/10">
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<Usb className="w-8 h-8" />
|
||||
<span className="font-mono text-2xl tracking-wider">ALLTOR.NET</span>
|
||||
</div>
|
||||
<p className="text-white/70 text-lg leading-relaxed">
|
||||
Connecting an alternative internet. Distributed. Democratic. Free.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<h3 className="text-2xl font-bold text-balance">Ready to break free?</h3>
|
||||
<Button size="lg" className="bg-white text-black hover:bg-white/90 text-lg px-8">
|
||||
Join the Movement
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-12 grid sm:grid-cols-3 gap-8">
|
||||
<div>
|
||||
<h4 className="font-bold mb-4">Learn</h4>
|
||||
<ul className="space-y-2 text-white/70">
|
||||
<li>
|
||||
<a href="#" className="hover:text-white transition-colors">
|
||||
Documentation
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" className="hover:text-white transition-colors">
|
||||
Whitepaper
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" className="hover:text-white transition-colors">
|
||||
Technical Specs
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" className="hover:text-white transition-colors">
|
||||
FAQ
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="font-bold mb-4">Community</h4>
|
||||
<ul className="space-y-2 text-white/70">
|
||||
<li>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" className="hover:text-white transition-colors">
|
||||
Chat
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" className="hover:text-white transition-colors">
|
||||
Contribute
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="font-bold mb-4">Connect</h4>
|
||||
<ul className="space-y-2 text-white/70">
|
||||
<li>
|
||||
<a href="#" className="hover:text-white transition-colors">
|
||||
IRL plz
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-12 mt-12 border-t border-white/10 text-center text-white/50 text-sm">
|
||||
<p>Built by the community, for the community. No corporation. No venture capital. Just humans.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import { Button } from "@/components/ui/button"
|
||||
import { Usb } from "lucide-react"
|
||||
|
||||
export function Hero() {
|
||||
return (
|
||||
<section className="relative min-h-screen flex items-center justify-center overflow-hidden bg-black text-white">
|
||||
{/* Dramatic grid background */}
|
||||
<div className="absolute inset-0 bg-[linear-gradient(to_right,#ffffff08_1px,transparent_1px),linear-gradient(to_bottom,#ffffff08_1px,transparent_1px)] bg-[size:4rem_4rem]" />
|
||||
|
||||
<div className="container relative z-10 px-4 py-20">
|
||||
<div className="max-w-5xl mx-auto text-center space-y-8">
|
||||
{/* Logo/Brand */}
|
||||
<div className="inline-flex items-center gap-3 px-4 py-2 bg-white/5 backdrop-blur-sm border border-white/10">
|
||||
<Usb className="w-6 h-6" />
|
||||
<span className="font-mono text-sm tracking-wider">ALLTOR.NET</span>
|
||||
</div>
|
||||
|
||||
{/* Main headline */}
|
||||
<h1 className="text-6xl md:text-8xl font-bold tracking-tight text-balance leading-[0.95]">
|
||||
<span className="block text-5xl md:text-7xl mb-2">We need an</span>
|
||||
<span className="bg-gradient-to-r from-red-500 via-yellow-500 via-green-500 via-blue-500 to-purple-500 bg-clip-text text-transparent">
|
||||
Alternative
|
||||
</span>
|
||||
<br />
|
||||
<span className="text-white">Internet</span>
|
||||
</h1>
|
||||
|
||||
{/* Subheadline */}
|
||||
<p className="text-xl md:text-2xl text-white/70 max-w-3xl mx-auto text-balance leading-relaxed">
|
||||
A distributed, local-first, collaborative digital ecosystem free from corporate control. Access a new
|
||||
internet through physical USB keys and local mesh networks.
|
||||
</p>
|
||||
|
||||
{/* CTA Buttons */}
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center pt-4">
|
||||
<Button size="lg" className="text-lg px-8 py-6 bg-white text-black hover:bg-white/90">
|
||||
Get Your Key
|
||||
</Button>
|
||||
<Button
|
||||
size="lg"
|
||||
variant="outline"
|
||||
className="text-lg px-8 py-6 border-white/20 hover:bg-white/10 text-white bg-transparent"
|
||||
>
|
||||
Learn More
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Key stats */}
|
||||
<div className="grid grid-cols-3 gap-8 pt-12 max-w-2xl mx-auto">
|
||||
<div className="space-y-1">
|
||||
<div className="text-3xl md:text-4xl font-bold">100%</div>
|
||||
<div className="text-sm text-muted-foreground">Zero Knowledge</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-3xl md:text-4xl font-bold">P2P</div>
|
||||
<div className="text-sm text-muted-foreground">Distributed</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-3xl md:text-4xl font-bold">Free</div>
|
||||
<div className="text-sm text-muted-foreground">No Subscriptions</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom fade */}
|
||||
<div className="absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-background to-transparent" />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import { Usb, Wifi, Share2 } from "lucide-react"
|
||||
|
||||
const steps = [
|
||||
{
|
||||
icon: Usb,
|
||||
number: "01",
|
||||
title: "Get Your USB Key",
|
||||
description:
|
||||
"A physical device that contains your identity, encryption keys, and access credentials. Your sovereignty in hardware form.",
|
||||
},
|
||||
{
|
||||
icon: Wifi,
|
||||
number: "02",
|
||||
title: "Connect to the Mesh",
|
||||
description:
|
||||
"Plug in anywhere there's a local alltornet node. Instantly access the distributed network without corporate gatekeepers.",
|
||||
},
|
||||
{
|
||||
icon: Share2,
|
||||
number: "03",
|
||||
title: "Collaborate Freely",
|
||||
description: "Share files, compute, and ideas. Contribute to the commons. Build the future together.",
|
||||
},
|
||||
]
|
||||
|
||||
export function HowItWorks() {
|
||||
return (
|
||||
<section className="py-32 bg-black text-white relative overflow-hidden">
|
||||
{/* Subtle pattern */}
|
||||
<div className="absolute inset-0 opacity-5">
|
||||
<div className="absolute inset-0 bg-[linear-gradient(45deg,#ffffff_25%,transparent_25%,transparent_75%,#ffffff_75%),linear-gradient(45deg,#ffffff_25%,transparent_25%,transparent_75%,#ffffff_75%)] bg-[size:2rem_2rem] bg-[0_0,1rem_1rem]" />
|
||||
</div>
|
||||
|
||||
<div className="container px-4 relative z-10">
|
||||
<div className="max-w-3xl mx-auto text-center mb-20">
|
||||
<h2 className="text-5xl md:text-6xl font-bold mb-6 text-balance">How It Works</h2>
|
||||
<p className="text-xl text-white/70 text-balance leading-relaxed">
|
||||
Three simple steps to break free from the legacy internet
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="max-w-5xl mx-auto space-y-16">
|
||||
{steps.map((step, index) => (
|
||||
<div key={index} className="flex flex-col md:flex-row gap-8 items-start group">
|
||||
<div className="flex-shrink-0">
|
||||
<div className="relative">
|
||||
<div className="text-8xl md:text-9xl font-bold text-white/5 select-none">{step.number}</div>
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<div className="p-6 bg-white text-black">
|
||||
<step.icon className="w-8 h-8" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 space-y-4 pt-4">
|
||||
<h3 className="text-3xl font-bold">{step.title}</h3>
|
||||
<p className="text-xl text-white/70 leading-relaxed">{step.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
const LISTMONK_URL = "https://newsletter.jeffemmett.com"
|
||||
const LIST_UUID = "0c541da4-3f04-4e72-978a-5a328b43c995" // Alltornet list
|
||||
|
||||
export function NewsletterSignup() {
|
||||
const [email, setEmail] = useState("")
|
||||
const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle")
|
||||
const [message, setMessage] = useState("")
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
if (!email) return
|
||||
|
||||
setStatus("loading")
|
||||
|
||||
try {
|
||||
const response = await fetch(`${LISTMONK_URL}/api/public/subscription`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
list_uuids: [LIST_UUID],
|
||||
name: "",
|
||||
}),
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
setStatus("success")
|
||||
setMessage("Check your email to confirm your subscription!")
|
||||
setEmail("")
|
||||
} else {
|
||||
throw new Error("Subscription failed")
|
||||
}
|
||||
} catch {
|
||||
setStatus("error")
|
||||
setMessage("Something went wrong. Please try again.")
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="py-16 bg-gradient-to-b from-background to-muted/30">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="max-w-xl mx-auto text-center space-y-6">
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-2xl font-bold">
|
||||
Stay in the Loop
|
||||
</h2>
|
||||
<p className="text-muted-foreground">
|
||||
Subscribe for updates from Alltornet.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{status === "success" ? (
|
||||
<div className="p-4 rounded-lg bg-green-500/10 border border-green-500/20 text-green-600 dark:text-green-400">
|
||||
{message}
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="flex flex-col sm:flex-row gap-3">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="your@email.com"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
className="flex-1 px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary/50"
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={status === "loading"}
|
||||
className="px-6"
|
||||
>
|
||||
{status === "loading" ? "Subscribing..." : "Subscribe"}
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
|
||||
{status === "error" && (
|
||||
<p className="text-sm text-red-500">{message}</p>
|
||||
)}
|
||||
|
||||
<p className="text-xs text-muted-foreground">
|
||||
No spam, unsubscribe anytime. We respect your privacy.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
export function Philosophy() {
|
||||
return (
|
||||
<section className="py-32 bg-background">
|
||||
<div className="container px-4">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="space-y-12">
|
||||
<h2 className="text-5xl md:text-7xl font-bold text-balance">Why the alltornet exists</h2>
|
||||
|
||||
<div className="space-y-8 text-xl leading-relaxed">
|
||||
<p className="text-muted-foreground">
|
||||
The legacy internet has become a collection of walled gardens controlled by a handful of corporations.
|
||||
Your data is commodified. Your attention is sold. Your privacy is an illusion.
|
||||
</p>
|
||||
|
||||
<p className="text-foreground font-medium">
|
||||
The alltornet is a substrate for digital collaboration that returns power to individuals and communities.
|
||||
</p>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8 py-8">
|
||||
<div className="space-y-4 p-8 border border-border bg-card">
|
||||
<h3 className="text-2xl font-bold">Democratic</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Decisions are made collectively. No CEO can unilaterally change the rules. Governance is transparent
|
||||
and participatory.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4 p-8 border border-border bg-card">
|
||||
<h3 className="text-2xl font-bold">Economic Justice</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Value flows to contributors, not shareholders. Fair compensation for computational resources,
|
||||
bandwidth, and content creation.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4 p-8 border border-border bg-card">
|
||||
<h3 className="text-2xl font-bold">Computational Freedom</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Run any code. Build any application. No platform restrictions or artificial limitations imposed by
|
||||
corporate interests.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4 p-8 border border-border bg-card">
|
||||
<h3 className="text-2xl font-bold">True Privacy</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Zero-knowledge architecture means your data never exists unencrypted outside your devices.
|
||||
Surveillance capitalism has no place here.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="text-foreground">
|
||||
This isn't just technology. It's a movement to reclaim the digital commons and build a future where
|
||||
technology serves humanity, not corporate profits.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import {
|
||||
ThemeProvider as NextThemesProvider,
|
||||
type ThemeProviderProps,
|
||||
} from 'next-themes'
|
||||
|
||||
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
import * as React from 'react'
|
||||
import { Slot } from '@radix-ui/react-slot'
|
||||
import { cva, type VariantProps } from 'class-variance-authority'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
destructive:
|
||||
'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
|
||||
outline:
|
||||
'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
|
||||
secondary:
|
||||
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
ghost:
|
||||
'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
size: {
|
||||
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
|
||||
sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
|
||||
lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
|
||||
icon: 'size-9',
|
||||
'icon-sm': 'size-8',
|
||||
'icon-lg': 'size-10',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
function Button({
|
||||
className,
|
||||
variant,
|
||||
size,
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<'button'> &
|
||||
VariantProps<typeof buttonVariants> & {
|
||||
asChild?: boolean
|
||||
}) {
|
||||
const Comp = asChild ? Slot : 'button'
|
||||
|
||||
return (
|
||||
<Comp
|
||||
data-slot="button"
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Button, buttonVariants }
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import { clsx, type ClassValue } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
output: 'export',
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
typescript: {
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
}
|
||||
|
||||
export default nextConfig
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ $uri.html =404;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"name": "my-v0-project",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"dev": "next dev",
|
||||
"lint": "eslint .",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.10.0",
|
||||
"@radix-ui/react-accordion": "1.2.2",
|
||||
"@radix-ui/react-alert-dialog": "1.1.4",
|
||||
"@radix-ui/react-aspect-ratio": "1.1.1",
|
||||
"@radix-ui/react-avatar": "1.1.2",
|
||||
"@radix-ui/react-checkbox": "1.1.3",
|
||||
"@radix-ui/react-collapsible": "1.1.2",
|
||||
"@radix-ui/react-context-menu": "2.2.4",
|
||||
"@radix-ui/react-dialog": "1.1.4",
|
||||
"@radix-ui/react-dropdown-menu": "2.1.4",
|
||||
"@radix-ui/react-hover-card": "1.1.4",
|
||||
"@radix-ui/react-label": "2.1.1",
|
||||
"@radix-ui/react-menubar": "1.1.4",
|
||||
"@radix-ui/react-navigation-menu": "1.2.3",
|
||||
"@radix-ui/react-popover": "1.1.4",
|
||||
"@radix-ui/react-progress": "1.1.1",
|
||||
"@radix-ui/react-radio-group": "1.2.2",
|
||||
"@radix-ui/react-scroll-area": "1.2.2",
|
||||
"@radix-ui/react-select": "2.1.4",
|
||||
"@radix-ui/react-separator": "1.1.1",
|
||||
"@radix-ui/react-slider": "1.2.2",
|
||||
"@radix-ui/react-slot": "latest",
|
||||
"@radix-ui/react-switch": "1.1.2",
|
||||
"@radix-ui/react-tabs": "1.1.2",
|
||||
"@radix-ui/react-toast": "1.2.4",
|
||||
"@radix-ui/react-toggle": "1.1.1",
|
||||
"@radix-ui/react-toggle-group": "1.1.1",
|
||||
"@radix-ui/react-tooltip": "1.1.6",
|
||||
"@vercel/analytics": "latest",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "1.0.4",
|
||||
"date-fns": "4.1.0",
|
||||
"embla-carousel-react": "8.5.1",
|
||||
"input-otp": "1.4.1",
|
||||
"lucide-react": "^0.454.0",
|
||||
"next": "16.0.0",
|
||||
"next-themes": "latest",
|
||||
"react": "19.2.0",
|
||||
"react-day-picker": "9.8.0",
|
||||
"react-dom": "19.2.0",
|
||||
"react-hook-form": "^7.60.0",
|
||||
"react-resizable-panels": "^2.1.7",
|
||||
"recharts": "2.15.4",
|
||||
"sonner": "^1.7.4",
|
||||
"tailwind-merge": "^2.5.5",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"vaul": "^0.9.9",
|
||||
"zod": "3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.9",
|
||||
"@types/node": "^22",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"postcss": "^8.5",
|
||||
"tailwindcss": "^4.1.9",
|
||||
"tw-animate-css": "1.3.3",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 585 B |
|
After Width: | Height: | Size: 566 B |
|
|
@ -0,0 +1,26 @@
|
|||
<svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
@media (prefers-color-scheme: light) {
|
||||
.background { fill: black; }
|
||||
.foreground { fill: white; }
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.background { fill: white; }
|
||||
.foreground { fill: black; }
|
||||
}
|
||||
</style>
|
||||
<g clip-path="url(#clip0_7960_43945)">
|
||||
<rect class="background" width="180" height="180" rx="37" />
|
||||
<g style="transform: scale(95%); transform-origin: center">
|
||||
<path class="foreground"
|
||||
d="M101.141 53H136.632C151.023 53 162.689 64.6662 162.689 79.0573V112.904H148.112V79.0573C148.112 78.7105 148.098 78.3662 148.072 78.0251L112.581 112.898C112.701 112.902 112.821 112.904 112.941 112.904H148.112V126.672H112.941C98.5504 126.672 86.5638 114.891 86.5638 100.5V66.7434H101.141V100.5C101.141 101.15 101.191 101.792 101.289 102.422L137.56 66.7816C137.255 66.7563 136.945 66.7434 136.632 66.7434H101.141V53Z" />
|
||||
<path class="foreground"
|
||||
d="M65.2926 124.136L14 66.7372H34.6355L64.7495 100.436V66.7372H80.1365V118.47C80.1365 126.278 70.4953 129.958 65.2926 124.136Z" />
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_7960_43945">
|
||||
<rect width="180" height="180" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 568 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="215" height="48" fill="none"><path fill="#000" d="M57.588 9.6h6L73.828 38h-5.2l-2.36-6.88h-11.36L52.548 38h-5.2l10.24-28.4Zm7.16 17.16-4.16-12.16-4.16 12.16h8.32Zm23.694-2.24c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.486-7.72.12 3.4c.534-1.227 1.307-2.173 2.32-2.84 1.04-.693 2.267-1.04 3.68-1.04 1.494 0 2.76.387 3.8 1.16 1.067.747 1.827 1.813 2.28 3.2.507-1.44 1.294-2.52 2.36-3.24 1.094-.747 2.414-1.12 3.96-1.12 1.414 0 2.64.307 3.68.92s1.84 1.52 2.4 2.72c.56 1.2.84 2.667.84 4.4V38h-4.96V25.92c0-1.813-.293-3.187-.88-4.12-.56-.96-1.413-1.44-2.56-1.44-.906 0-1.68.213-2.32.64-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.84-.48 3.04V38h-4.56V25.92c0-1.2-.133-2.213-.4-3.04-.24-.827-.626-1.453-1.16-1.88-.506-.427-1.133-.64-1.88-.64-.906 0-1.68.227-2.32.68-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.827-.48 3V38h-4.96V16.8h4.48Zm26.723 10.6c0-2.24.427-4.187 1.28-5.84.854-1.68 2.067-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.84 0 3.494.413 4.96 1.24 1.467.827 2.64 2.08 3.52 3.76.88 1.653 1.347 3.693 1.4 6.12v1.32h-15.08c.107 1.813.614 3.227 1.52 4.24.907.987 2.134 1.48 3.68 1.48.987 0 1.88-.253 2.68-.76a4.803 4.803 0 0 0 1.84-2.2l5.08.36c-.64 2.027-1.84 3.64-3.6 4.84-1.733 1.173-3.733 1.76-6 1.76-2.08 0-3.906-.453-5.48-1.36-1.573-.907-2.786-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84Zm15.16-2.04c-.213-1.733-.76-3.013-1.64-3.84-.853-.827-1.893-1.24-3.12-1.24-1.44 0-2.6.453-3.48 1.36-.88.88-1.44 2.12-1.68 3.72h9.92ZM163.139 9.6V38h-5.04V9.6h5.04Zm8.322 7.2.24 5.88-.64-.36c.32-2.053 1.094-3.56 2.32-4.52 1.254-.987 2.787-1.48 4.6-1.48 2.32 0 4.107.733 5.36 2.2 1.254 1.44 1.88 3.387 1.88 5.84V38h-4.96V25.92c0-1.253-.12-2.28-.36-3.08-.24-.8-.64-1.413-1.2-1.84-.533-.427-1.253-.64-2.16-.64-1.44 0-2.573.48-3.4 1.44-.8.933-1.2 2.307-1.2 4.12V38h-4.96V16.8h4.48Zm30.003 7.72c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.443 8.16V38h-5.6v-5.32h5.6Z"/><path fill="#171717" fill-rule="evenodd" d="m7.839 40.783 16.03-28.054L20 6 0 40.783h7.839Zm8.214 0H40L27.99 19.894l-4.02 7.032 3.976 6.914H20.02l-3.967 6.943Z" clip-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
|
|
@ -0,0 +1,125 @@
|
|||
@import 'tailwindcss';
|
||||
@import 'tw-animate-css';
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
:root {
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--destructive-foreground: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--radius: 0.625rem;
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.145 0 0);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.145 0 0);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.145 0 0);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.985 0 0);
|
||||
--primary-foreground: oklch(0.205 0 0);
|
||||
--secondary: oklch(0.269 0 0);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.269 0 0);
|
||||
--muted-foreground: oklch(0.708 0 0);
|
||||
--accent: oklch(0.269 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.396 0.141 25.723);
|
||||
--destructive-foreground: oklch(0.637 0.237 25.331);
|
||||
--border: oklch(0.269 0 0);
|
||||
--input: oklch(0.269 0 0);
|
||||
--ring: oklch(0.439 0 0);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.205 0 0);
|
||||
--sidebar-foreground: oklch(0.985 0 0);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.269 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(0.269 0 0);
|
||||
--sidebar-ring: oklch(0.439 0 0);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--font-sans: 'Geist', 'Geist Fallback';
|
||||
--font-mono: 'Geist Mono', 'Geist Mono Fallback';
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"target": "ES6",
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||