Initialized repository for chat Myc0punkz website
Co-authored-by: Jeff Emmett <46964190+Jeff-Emmett@users.noreply.github.com>
|
|
@ -0,0 +1,30 @@
|
|||
# Myc0punkz website
|
||||
|
||||
*Automatically synced with your [v0.app](https://v0.app) deployments*
|
||||
|
||||
[](https://vercel.com/jeff-emmetts-projects/v0-myc0punkz-website)
|
||||
[](https://v0.app/chat/vhSv16QjVPp)
|
||||
|
||||
## 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-myc0punkz-website](https://vercel.com/jeff-emmetts-projects/v0-myc0punkz-website)**
|
||||
|
||||
## Build your app
|
||||
|
||||
Continue building your app on:
|
||||
|
||||
**[https://v0.app/chat/vhSv16QjVPp](https://v0.app/chat/vhSv16QjVPp)**
|
||||
|
||||
## 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,50 @@
|
|||
import { NextResponse } from 'next/server'
|
||||
|
||||
// This is a simple in-memory store for demo purposes
|
||||
// In production, you'd want to use a database
|
||||
const waitlist = new Set<string>()
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const { email } = await request.json()
|
||||
|
||||
if (!email || !email.includes('@')) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Valid email required' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
if (waitlist.has(email)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Already in the network' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
waitlist.add(email)
|
||||
|
||||
// In production, you'd save to a database here
|
||||
// and potentially send a confirmation email
|
||||
console.log('[v0] New waitlist signup:', email)
|
||||
console.log('[v0] Total waitlist size:', waitlist.size)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Welcome to the underground',
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[v0] Waitlist error:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Network error occurred' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: Add a GET endpoint to check waitlist status (for admin use)
|
||||
export async function GET() {
|
||||
return NextResponse.json({
|
||||
count: waitlist.size,
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
@import 'tailwindcss';
|
||||
@import 'tw-animate-css';
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
:root {
|
||||
--background: oklch(0.12 0.02 60);
|
||||
--foreground: oklch(0.85 0.03 80);
|
||||
--card: oklch(0.16 0.02 55);
|
||||
--card-foreground: oklch(0.88 0.03 75);
|
||||
--popover: oklch(0.16 0.02 55);
|
||||
--popover-foreground: oklch(0.88 0.03 75);
|
||||
--primary: oklch(0.45 0.12 110);
|
||||
--primary-foreground: oklch(0.98 0.01 90);
|
||||
--secondary: oklch(0.22 0.02 50);
|
||||
--secondary-foreground: oklch(0.85 0.03 80);
|
||||
--muted: oklch(0.20 0.02 55);
|
||||
--muted-foreground: oklch(0.55 0.02 65);
|
||||
--accent: oklch(0.55 0.14 130);
|
||||
--accent-foreground: oklch(0.98 0.01 90);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--destructive-foreground: oklch(0.98 0.01 90);
|
||||
--border: oklch(0.25 0.02 55);
|
||||
--input: oklch(0.22 0.02 55);
|
||||
--ring: oklch(0.45 0.12 110);
|
||||
--chart-1: oklch(0.45 0.12 110);
|
||||
--chart-2: oklch(0.55 0.14 130);
|
||||
--chart-3: oklch(0.38 0.10 95);
|
||||
--chart-4: oklch(0.65 0.15 140);
|
||||
--chart-5: oklch(0.35 0.08 85);
|
||||
--radius: 0.25rem;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.noise-texture {
|
||||
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 400 400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='3.5' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)' opacity='0.08'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.mycelium-glow {
|
||||
text-shadow: 0 0 20px oklch(0.45 0.12 110 / 0.5), 0 0 40px oklch(0.45 0.12 110 / 0.3);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import type { Metadata } from 'next'
|
||||
import { Space_Mono, Inter } from 'next/font/google'
|
||||
import { Analytics } from '@vercel/analytics/next'
|
||||
import './globals.css'
|
||||
|
||||
const spaceMono = Space_Mono({
|
||||
weight: ['400', '700'],
|
||||
subsets: ["latin"],
|
||||
variable: '--font-mono'
|
||||
});
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
variable: '--font-sans'
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'myc0punkz.xyz - The Underground Awaits',
|
||||
description: 'Welcome to the underground of the underground. Where technology meets Earth wisdom. Sovereign infrastructure for the regenerative future.',
|
||||
generator: 'v0.app',
|
||||
icons: {
|
||||
icon: [
|
||||
{
|
||||
url: '/icon-light-32x32.png',
|
||||
media: '(prefers-color-scheme: light)',
|
||||
},
|
||||
{
|
||||
url: '/icon-dark-32x32.png',
|
||||
media: '(prefers-color-scheme: dark)',
|
||||
},
|
||||
{
|
||||
url: '/icon.svg',
|
||||
type: 'image/svg+xml',
|
||||
},
|
||||
],
|
||||
apple: '/apple-icon.png',
|
||||
},
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={`${inter.variable} ${spaceMono.variable} font-sans antialiased`}>
|
||||
{children}
|
||||
<Analytics />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { HeroSection } from '@/components/hero-section'
|
||||
import { ManifestoSection } from '@/components/manifesto-section'
|
||||
import { DeviceSection } from '@/components/device-section'
|
||||
import { NetworkSection } from '@/components/network-section'
|
||||
import { WaitlistSection } from '@/components/waitlist-section'
|
||||
import { FooterSection } from '@/components/footer-section'
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="min-h-screen noise-texture">
|
||||
<HeroSection />
|
||||
<ManifestoSection />
|
||||
<DeviceSection />
|
||||
<NetworkSection />
|
||||
<WaitlistSection />
|
||||
<FooterSection />
|
||||
</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,67 @@
|
|||
import { Lock, HardDrive, Radio, Users } from 'lucide-react'
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: Lock,
|
||||
title: 'Zero-Knowledge Security',
|
||||
description: 'Metadata-encrypted. Your data, your keys, your sovereignty.',
|
||||
},
|
||||
{
|
||||
icon: HardDrive,
|
||||
title: 'Local Edge Storage',
|
||||
description: 'Sovereign data hosting. Media servers. All at the edge.',
|
||||
},
|
||||
{
|
||||
icon: Radio,
|
||||
title: 'Secure Communications',
|
||||
description: 'Encrypted channels. Private by default. Owned by you.',
|
||||
},
|
||||
{
|
||||
icon: Users,
|
||||
title: 'Collaborative Spaces',
|
||||
description: 'Powered by folkjs.org. Real connection, no extraction.',
|
||||
},
|
||||
]
|
||||
|
||||
export function DeviceSection() {
|
||||
return (
|
||||
<section className="py-24 px-4 border-t border-border">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="text-center mb-16">
|
||||
<div className="text-xs font-mono text-primary tracking-widest uppercase mb-4">
|
||||
The Node
|
||||
</div>
|
||||
<h2 className="text-3xl md:text-5xl font-bold mb-6 font-mono text-balance">
|
||||
Regenerative Sovereign Infrastructure
|
||||
</h2>
|
||||
<p className="text-muted-foreground max-w-2xl mx-auto leading-relaxed text-pretty">
|
||||
A local edge node that puts power back where it belongs. Secure, affordable, and built
|
||||
for the regenerative future.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-6 mb-12">
|
||||
{features.map((feature) => (
|
||||
<div
|
||||
key={feature.title}
|
||||
className="bg-card border border-border p-6 hover:border-primary/50 transition-colors"
|
||||
>
|
||||
<feature.icon className="w-8 h-8 text-primary mb-4" />
|
||||
<h3 className="text-xl font-semibold mb-2">{feature.title}</h3>
|
||||
<p className="text-muted-foreground leading-relaxed">{feature.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="bg-secondary/50 border border-primary/30 p-8 text-center">
|
||||
<div className="text-sm font-mono text-primary mb-2 tracking-wider uppercase">
|
||||
Exclusive First Run
|
||||
</div>
|
||||
<p className="text-lg text-foreground">
|
||||
Limited initial devices. Early access for those who found the underground first.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
export function FooterSection() {
|
||||
return (
|
||||
<footer className="py-12 px-4 border-t border-border">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="flex flex-col md:flex-row justify-between items-center gap-6">
|
||||
<div className="text-sm text-muted-foreground font-mono">
|
||||
© 2025 myc0punkz.xyz — underground infrastructure
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-6 text-sm font-mono">
|
||||
<a
|
||||
href="mailto:hello@myc0punkz.xyz"
|
||||
className="text-muted-foreground hover:text-accent transition-colors"
|
||||
>
|
||||
Signal us
|
||||
</a>
|
||||
<div className="text-muted-foreground">
|
||||
Built with <span className="text-primary">♦</span> from the underground
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
'use client'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export function HeroSection() {
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setIsVisible(true)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<section className="relative min-h-screen flex items-center justify-center overflow-hidden px-4">
|
||||
{/* Background network lines */}
|
||||
<div className="absolute inset-0 opacity-20">
|
||||
<svg className="w-full h-full" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="network" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
|
||||
<path d="M 0 50 Q 25 25 50 50 T 100 50" stroke="oklch(0.45 0.12 110)" fill="none" strokeWidth="0.5" />
|
||||
<circle cx="50" cy="50" r="2" fill="oklch(0.45 0.12 110)" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="url(#network)" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className={`relative z-10 text-center max-w-4xl transition-all duration-1000 ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}>
|
||||
<div className="mb-6 text-sm tracking-[0.3em] text-muted-foreground font-mono uppercase">
|
||||
{'>>>_ You made it'}
|
||||
</div>
|
||||
|
||||
<h1 className="text-5xl md:text-7xl lg:text-8xl font-bold mb-8 font-mono mycelium-glow">
|
||||
<span className="block text-balance">myc0punkz</span>
|
||||
</h1>
|
||||
|
||||
<div className="text-lg md:text-xl text-muted-foreground mb-12 max-w-2xl mx-auto font-mono leading-relaxed">
|
||||
<p className="text-balance">
|
||||
{'Congratulations. You found the underground of the underground.'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center gap-2 text-primary animate-bounce">
|
||||
<div className="text-sm font-mono tracking-wider">DESCEND</div>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 14l-7 7m0 0l-7-7m7 7V3" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
export function ManifestoSection() {
|
||||
return (
|
||||
<section className="py-24 px-4 border-t border-border">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="grid md:grid-cols-2 gap-12 mb-16">
|
||||
<div className="space-y-4">
|
||||
<div className="text-xs font-mono text-primary tracking-widest uppercase">The Old Way</div>
|
||||
<div className="text-muted-foreground leading-relaxed">
|
||||
Tools built to <span className="line-through">capture</span> and{' '}
|
||||
<span className="line-through">extract</span>. Data as commodity. Users as products.
|
||||
Centralized power. Extractive systems.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="text-xs font-mono text-accent tracking-widest uppercase">The Underground</div>
|
||||
<div className="text-foreground leading-relaxed">
|
||||
Technology grounded in <span className="text-primary font-semibold">Earth wisdom</span>.
|
||||
Tools built to <span className="text-accent font-semibold">lift and empower</span>.
|
||||
Sovereign infrastructure. Regenerative systems. True ownership.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-card border border-border p-8 md:p-12">
|
||||
<p className="text-lg md:text-xl leading-relaxed text-pretty">
|
||||
Where technology of the future meets wisdom of the Earth. Where networks grow like{' '}
|
||||
<span className="text-primary font-semibold">mycelium</span> — decentralized, resilient,
|
||||
interconnected. Where sovereignty isn't a luxury, it's the foundation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
const nodes = [
|
||||
{ name: 'alltor.net', url: 'https://alltor.net', description: 'Distributed networks' },
|
||||
{ name: 'post-appitalism.app', url: 'https://post-appitalism.app', description: 'Beyond extraction' },
|
||||
{ name: 'compostcapitalism.xyz', url: 'https://compostcapitalism.xyz', description: 'Regenerative economics' },
|
||||
{ name: 'mycofi.earth', url: 'https://mycofi.earth', description: 'Mycelial finance' },
|
||||
{ name: 'folkjs.org', url: 'https://folkjs.org', description: 'Collaborative tools' },
|
||||
{ name: 'rspace.online', url: 'https://rspace.online', description: 'Interaction spaces' },
|
||||
]
|
||||
|
||||
export function NetworkSection() {
|
||||
return (
|
||||
<section className="py-24 px-4 border-t border-border">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="text-center mb-16">
|
||||
<div className="text-xs font-mono text-primary tracking-widest uppercase mb-4">
|
||||
The Mycelial Network
|
||||
</div>
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-6 font-mono text-balance">
|
||||
Interconnected. Resilient. Growing.
|
||||
</h2>
|
||||
<p className="text-muted-foreground leading-relaxed max-w-2xl mx-auto text-pretty">
|
||||
Like mycelium beneath the forest floor, we're part of a larger living network. These are
|
||||
our kindred nodes.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
{nodes.map((node) => (
|
||||
<Link
|
||||
key={node.name}
|
||||
href={node.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="bg-card border border-border p-4 hover:border-accent hover:bg-card/80 transition-all group"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<div className="font-mono text-accent group-hover:text-accent/80 transition-colors">
|
||||
{node.name}
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground mt-1">{node.description}</div>
|
||||
</div>
|
||||
<svg
|
||||
className="w-5 h-5 text-muted-foreground group-hover:text-accent group-hover:translate-x-1 transition-all"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M13 7l5 5m0 0l-5 5m5-5H6"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</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,21 @@
|
|||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
data-slot="input"
|
||||
className={cn(
|
||||
'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
||||
'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',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Input }
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
|
||||
export function WaitlistSection() {
|
||||
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()
|
||||
setStatus('loading')
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/waitlist', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email }),
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (response.ok) {
|
||||
setStatus('success')
|
||||
setMessage('Welcome to the underground. We\'ll reach out when nodes are ready.')
|
||||
setEmail('')
|
||||
} else {
|
||||
setStatus('error')
|
||||
setMessage(data.error || 'Something went wrong. Try again.')
|
||||
}
|
||||
} catch (error) {
|
||||
setStatus('error')
|
||||
setMessage('Connection failed. The network is watching.')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="py-24 px-4 border-t border-border">
|
||||
<div className="max-w-2xl mx-auto">
|
||||
<div className="text-center mb-12">
|
||||
<div className="text-xs font-mono text-primary tracking-widest uppercase mb-4">
|
||||
Join the Underground
|
||||
</div>
|
||||
<h2 className="text-3xl md:text-5xl font-bold mb-6 font-mono text-balance">
|
||||
Secure Your Node
|
||||
</h2>
|
||||
<p className="text-muted-foreground leading-relaxed text-pretty">
|
||||
Exclusive access to the first run of sovereign edge nodes. Add your signal to the
|
||||
network. We'll reach out when devices are ready for pre-order.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div className="bg-card border border-border p-8">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label htmlFor="email" className="text-sm font-mono text-muted-foreground mb-2 block">
|
||||
Your encrypted signal
|
||||
</label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="your@email.xyz"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
disabled={status === 'loading' || status === 'success'}
|
||||
className="bg-background border-border font-mono"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={status === 'loading' || status === 'success'}
|
||||
className="w-full bg-primary text-primary-foreground hover:bg-primary/90 font-mono tracking-wider"
|
||||
>
|
||||
{status === 'loading' ? 'CONNECTING...' : status === 'success' ? 'CONNECTED' : 'JOIN THE NETWORK'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{message && (
|
||||
<div
|
||||
className={`text-center text-sm font-mono ${
|
||||
status === 'success' ? 'text-accent' : 'text-destructive'
|
||||
}`}
|
||||
>
|
||||
{message}
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
|
||||
<div className="mt-12 text-center text-xs text-muted-foreground font-mono">
|
||||
<p className="text-pretty">Your data is sovereign. Zero-knowledge. Encrypted. Always yours.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -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,12 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
typescript: {
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
export default nextConfig
|
||||
|
|
@ -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": "1.1.1",
|
||||
"@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.3",
|
||||
"next-themes": "^0.4.6",
|
||||
"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: 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"]
|
||||
}
|
||||