Initialized repository for chat Personal website redesign

Co-authored-by: Jeff Emmett <46964190+Jeff-Emmett@users.noreply.github.com>
This commit is contained in:
v0 2025-11-24 01:59:54 +00:00
commit a369139872
41 changed files with 4345 additions and 0 deletions

30
README.md Normal file
View File

@ -0,0 +1,30 @@
# Personal website redesign
*Automatically synced with your [v0.app](https://v0.app) deployments*
[![Deployed on Vercel](https://img.shields.io/badge/Deployed%20on-Vercel-black?style=for-the-badge&logo=vercel)](https://vercel.com/jeff-emmetts-projects/v0-personal-website-redesign)
[![Built with v0](https://img.shields.io/badge/Built%20with-v0.app-black?style=for-the-badge)](https://v0.app/chat/c8jGR8t3eSX)
## 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-personal-website-redesign](https://vercel.com/jeff-emmetts-projects/v0-personal-website-redesign)**
## Build your app
Continue building your app on:
**[https://v0.app/chat/c8jGR8t3eSX](https://v0.app/chat/c8jGR8t3eSX)**
## 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

149
app/globals.css Normal file
View File

@ -0,0 +1,149 @@
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
:root {
--background: oklch(0.16 0.01 265);
--foreground: oklch(0.95 0.01 265);
--card: oklch(0.2 0.015 265);
--card-foreground: oklch(0.95 0.01 265);
--popover: oklch(0.2 0.015 265);
--popover-foreground: oklch(0.95 0.01 265);
--primary: oklch(0.7 0.15 265);
--primary-foreground: oklch(0.98 0.01 265);
--secondary: oklch(0.25 0.015 265);
--secondary-foreground: oklch(0.95 0.01 265);
--muted: oklch(0.25 0.015 265);
--muted-foreground: oklch(0.55 0.01 265);
--accent: oklch(0.65 0.18 185);
--accent-foreground: oklch(0.98 0.01 265);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.98 0.01 265);
--border: oklch(0.28 0.015 265);
--input: oklch(0.28 0.015 265);
--ring: oklch(0.7 0.15 265);
--chart-1: oklch(0.7 0.15 265);
--chart-2: oklch(0.65 0.18 185);
--chart-3: oklch(0.6 0.12 145);
--chart-4: oklch(0.75 0.16 285);
--chart-5: oklch(0.65 0.14 225);
--radius: 0.75rem;
--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;
cursor: none;
}
a,
button {
cursor: none;
}
html {
scroll-behavior: smooth;
}
}
@keyframes float {
0%,
100% {
transform: translateY(0px);
}
50% {
transform: translateY(-20px);
}
}
.animate-float {
animation: float 6s ease-in-out infinite;
}

55
app/layout.tsx Normal file
View File

@ -0,0 +1,55 @@
import type React from "react"
import type { Metadata } from "next"
import { Inter, Space_Mono } from "next/font/google"
import { Analytics } from "@vercel/analytics/next"
import "./globals.css"
const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
})
const spaceMono = Space_Mono({
subsets: ["latin"],
weight: ["400", "700"],
variable: "--font-space-mono",
})
export const metadata: Metadata = {
title: "Jeff Emmett - Token Engineering & Regenerative Economics",
description:
"Token engineering researcher exploring bonding curves, Web3 economies, and mycoeconomics. Co-founder of Commons Stack and MycoFi.",
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>
)
}

21
app/page.tsx Normal file
View File

@ -0,0 +1,21 @@
import { CursorEffect } from '@/components/cursor-effect'
import { HeroSection } from '@/components/hero-section'
import { WorkSection } from '@/components/work-section'
import { AboutSection } from '@/components/about-section'
import { SkillsSection } from '@/components/skills-section'
import { ContactSection } from '@/components/contact-section'
export default function Home() {
return (
<>
<CursorEffect />
<main className="relative">
<HeroSection />
<WorkSection />
<AboutSection />
<SkillsSection />
<ContactSection />
</main>
</>
)
}

21
components.json Normal file
View File

@ -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"
}

View File

@ -0,0 +1,63 @@
export function AboutSection() {
return (
<section className="py-32 px-6 bg-card/30">
<div className="max-w-4xl mx-auto">
<div className="mb-16">
<h2 className="text-5xl md:text-6xl font-bold mb-6">About Me</h2>
</div>
<div className="space-y-6 text-lg leading-relaxed">
<p className="text-foreground/90">
I'm a token engineering researcher and systems designer exploring the intersection of economics, ecology,
and decentralized coordination. My work focuses on creating tools and frameworks that enable communities to
manage shared resources sustainably and equitablywhat I call "decent/ralised" systems.
</p>
<p className="text-muted-foreground">
As a co-founder of the Commons Stack, I've been instrumental in developing cyber-physical commons
architectures that translate Elinor Ostrom's principles into DAO templates. We're building customizable
libraries of tools for communal management of public goods, including innovations like Augmented Bonding
Curves and Conviction Votinga novel continuous decision-making mechanism that addresses critical attack
vectors in traditional governance systems.
</p>
<p className="text-muted-foreground">
Through the Bonding Curve Research Group, I research and develop Primary Issuance Markets that enable
dynamic token supply mechanisms. This work challenges the fixed supply paradigm dominant in Web3, offering
adaptive approaches that dampen volatility and generate sustainable revenue for token ecosystems. Our
research shows that tokens using primary issuance markets significantly outperform fixed-supply tokens in
price stability and risk-adjusted returns.
</p>
<p className="text-muted-foreground">
My MycoFi research explores mycoeconomicseconomic systems inspired by fungal networks. By emulating
nature's evolutionary resource allocation algorithms through mycelial intelligence, we can design
regenerative protocols built on cooperation, mutual aid, and permaculture currency principles rather than
extractive growth models. I authored book.mycofi.earth to share these insights.
</p>
<p className="text-muted-foreground">
I'm passionate about open-source token engineering tools like cadCAD, which I helped open source at the 2019
Token Engineering Global Gathering. Just as the Golden Gate Bridge required rigorous engineering, our token
economies need mathematical validation and simulation to serve as robust public infrastructure.
</p>
</div>
<div className="mt-16 grid md:grid-cols-3 gap-8">
<div>
<h3 className="text-3xl font-bold text-primary mb-2">8+</h3>
<p className="text-muted-foreground">Years in Token Engineering</p>
</div>
<div>
<h3 className="text-3xl font-bold text-primary mb-2">50+</h3>
<p className="text-muted-foreground">Research Publications</p>
</div>
<div>
<h3 className="text-3xl font-bold text-primary mb-2"></h3>
<p className="text-muted-foreground">Regenerative Impact</p>
</div>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,77 @@
import { Github, Mail } from "lucide-react"
const socials = [
{ icon: Mail, label: "Email", href: "mailto:jeff@emmett.com" },
{
icon: () => (
<svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 0C5.37 0 0 5.37 0 12s5.37 12 12 12 12-5.37 12-12S18.63 0 12 0zm5.01 18.5c-1.75 1.75-4.08 2.71-6.51 2.71s-4.76-.96-6.51-2.71C2.24 16.75 1.28 14.42 1.28 12s.96-4.76 2.71-6.51C5.74 3.74 8.07 2.78 10.5 2.78s4.76.96 6.51 2.71c1.75 1.75 2.71 4.08 2.71 6.51s-.96 4.76-2.71 6.51z" />
</svg>
),
label: "Bluesky",
href: "https://bsky.app/profile/jeffemmett.bsky.social",
},
{
icon: () => (
<svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M13.54 12a6.8 6.8 0 01-6.77 6.82A6.8 6.8 0 010 12a6.8 6.8 0 016.77-6.82A6.8 6.8 0 0113.54 12zM20.96 12c0 3.54-1.51 6.42-3.38 6.42-1.87 0-3.39-2.88-3.39-6.42s1.52-6.42 3.39-6.42 3.38 2.88 3.38 6.42M24 12c0 3.17-.53 5.75-1.19 5.75-.66 0-1.19-2.58-1.19-5.75s.53-5.75 1.19-5.75C23.47 6.25 24 8.83 24 12z" />
</svg>
),
label: "Medium",
href: "https://medium.com/@jeffemmett",
},
{
icon: Github,
label: "Commons Stack",
href: "https://commonsstack.org",
},
{
icon: () => (
<svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
</svg>
),
label: "MycoFi",
href: "https://mycofi.earth",
},
]
export function ContactSection() {
return (
<section id="contact" className="py-32 px-6 bg-card/30">
<div className="max-w-4xl mx-auto text-center">
<div className="mb-16">
<h2 className="text-5xl md:text-6xl font-bold mb-6">Let's Connect</h2>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto text-balance leading-relaxed">
Interested in token engineering, regenerative economics, or building commons-based systems? Let's
collaborate.
</p>
</div>
<div className="flex flex-wrap gap-6 justify-center mb-12">
{socials.map((social) => {
const Icon = social.icon
return (
<a
key={social.label}
href={social.href}
target="_blank"
rel="noopener noreferrer"
className="group flex items-center gap-3 px-6 py-4 bg-secondary text-secondary-foreground rounded-lg font-medium transition-all hover:scale-105 hover:bg-primary hover:text-primary-foreground"
>
<Icon className="h-5 w-5" />
<span>{social.label}</span>
</a>
)
})}
</div>
<div className="pt-12 border-t border-border">
<p className="text-muted-foreground font-mono text-sm">
© 2025 Jeff Emmett. Built with Next.js & TailwindCSS
</p>
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,79 @@
'use client'
import { useEffect, useState } from 'react'
export function CursorEffect() {
const [position, setPosition] = useState({ x: 0, y: 0 })
const [isHovering, setIsHovering] = useState(false)
const [trails, setTrails] = useState<Array<{ x: number; y: number; id: number }>>([])
useEffect(() => {
let trailId = 0
const handleMouseMove = (e: MouseEvent) => {
setPosition({ x: e.clientX, y: e.clientY })
// Add trail
const newTrail = { x: e.clientX, y: e.clientY, id: trailId++ }
setTrails(prev => [...prev.slice(-8), newTrail])
// Check if hovering over interactive element
const target = e.target as HTMLElement
const isInteractive = target.closest('a, button, [role="button"]')
setIsHovering(!!isInteractive)
}
window.addEventListener('mousemove', handleMouseMove)
return () => window.removeEventListener('mousemove', handleMouseMove)
}, [])
return (
<>
{/* Main cursor */}
<div
className="pointer-events-none fixed z-[9999] mix-blend-difference"
style={{
left: `${position.x}px`,
top: `${position.y}px`,
transform: 'translate(-50%, -50%)',
transition: 'width 0.2s, height 0.2s',
}}
>
<div
className={`rounded-full bg-primary transition-all duration-200 ${
isHovering ? 'h-12 w-12' : 'h-6 w-6'
}`}
/>
</div>
{/* Trail effect */}
{trails.map((trail, index) => (
<div
key={trail.id}
className="pointer-events-none fixed z-[9998] rounded-full bg-accent mix-blend-screen"
style={{
left: `${trail.x}px`,
top: `${trail.y}px`,
transform: 'translate(-50%, -50%)',
width: `${4 + index}px`,
height: `${4 + index}px`,
opacity: (index + 1) / trails.length * 0.3,
transition: 'opacity 0.5s',
}}
/>
))}
{/* Outer ring */}
<div
className="pointer-events-none fixed z-[9997] rounded-full border-2 border-primary/30 transition-all duration-300"
style={{
left: `${position.x}px`,
top: `${position.y}px`,
transform: 'translate(-50%, -50%)',
width: isHovering ? '64px' : '48px',
height: isHovering ? '64px' : '48px',
}}
/>
</>
)
}

View File

@ -0,0 +1,81 @@
"use client"
import { useEffect, useState } from "react"
export function HeroSection() {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 })
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
setMousePosition({
x: (e.clientX / window.innerWidth - 0.5) * 20,
y: (e.clientY / window.innerHeight - 0.5) * 20,
})
}
window.addEventListener("mousemove", handleMouseMove)
return () => window.removeEventListener("mousemove", handleMouseMove)
}, [])
return (
<section className="relative min-h-screen flex items-center justify-center overflow-hidden px-6">
{/* Animated background elements */}
<div className="absolute inset-0 overflow-hidden opacity-20">
<div
className="absolute top-1/4 left-1/4 h-96 w-96 rounded-full bg-primary blur-[120px] animate-float"
style={{
transform: `translate(${mousePosition.x}px, ${mousePosition.y}px)`,
transition: "transform 0.3s ease-out",
}}
/>
<div
className="absolute bottom-1/4 right-1/4 h-96 w-96 rounded-full bg-accent blur-[120px]"
style={{
transform: `translate(${-mousePosition.x}px, ${-mousePosition.y}px)`,
transition: "transform 0.3s ease-out",
animationDelay: "2s",
}}
/>
</div>
{/* Content */}
<div className="relative z-10 max-w-5xl text-center">
<div className="mb-6 inline-block">
<span className="text-sm font-mono text-muted-foreground border border-border px-4 py-2 rounded-full">
{"{ Token Engineering & Regenerative Economics }"}
</span>
</div>
<h1 className="text-6xl md:text-8xl font-bold mb-6 text-balance leading-tight">Jeff Emmett</h1>
<p className="text-xl md:text-2xl text-muted-foreground mb-12 max-w-3xl mx-auto text-balance leading-relaxed">
Token engineering researcher exploring bonding curves, Web3 economies, and mycoeconomics. Building tools for
regenerative communities and commons-based governance.
</p>
<div className="flex flex-wrap gap-4 justify-center">
<a
href="#work"
className="group relative px-8 py-4 bg-primary text-primary-foreground rounded-lg font-medium overflow-hidden transition-all hover:scale-105"
>
<span className="relative z-10">View Research</span>
<div className="absolute inset-0 bg-accent opacity-0 group-hover:opacity-100 transition-opacity" />
</a>
<a
href="#contact"
className="px-8 py-4 bg-secondary text-secondary-foreground rounded-lg font-medium transition-all hover:scale-105 hover:bg-secondary/80"
>
Get in Touch
</a>
</div>
</div>
{/* Scroll indicator */}
<div className="absolute bottom-12 left-1/2 -translate-x-1/2 animate-bounce">
<div className="h-12 w-8 rounded-full border-2 border-muted-foreground/30 flex items-start justify-center p-2">
<div className="h-2 w-1 bg-muted-foreground/50 rounded-full animate-pulse" />
</div>
</div>
</section>
)
}

View File

@ -0,0 +1,60 @@
const skills = {
"Token Engineering": [
"Bonding Curves",
"cadCAD Modeling",
"Primary Issuance Markets",
"Dynamic Supply Tokens",
"Cryptoeconomics",
"Agent-Based Modeling",
],
"DAO Tooling": [
"Conviction Voting",
"Augmented Bonding Curves",
"Commons Stack",
"Governance Systems",
"Cyber-Physical Commons",
"Ostrom Compliance",
],
"Research Areas": [
"Regenerative Economics",
"Mycoeconomics",
"Complex Systems",
"Behavioral Economics",
"Token Design",
"Public Goods Funding",
],
Technical: ["Python", "Solidity", "Simulation", "Data Analysis", "Systems Design", "Web3"],
}
export function SkillsSection() {
return (
<section className="py-32 px-6">
<div className="max-w-6xl mx-auto">
<div className="mb-16">
<h2 className="text-5xl md:text-6xl font-bold mb-6">Expertise & Focus Areas</h2>
<p className="text-xl text-muted-foreground max-w-2xl text-balance leading-relaxed">
Interdisciplinary approach to building resilient token economies and regenerative systems
</p>
</div>
<div className="grid md:grid-cols-2 gap-12">
{Object.entries(skills).map(([category, items]) => (
<div key={category}>
<h3 className="text-2xl font-semibold mb-6 text-primary">{category}</h3>
<div className="flex flex-wrap gap-3">
{items.map((skill) => (
<span
key={skill}
className="px-4 py-2 bg-secondary text-secondary-foreground rounded-lg font-medium hover:bg-primary hover:text-primary-foreground transition-colors"
>
{skill}
</span>
))}
</div>
</div>
))}
</div>
</div>
</section>
)
}

View File

@ -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>
}

92
components/ui/card.tsx Normal file
View File

@ -0,0 +1,92 @@
import * as React from 'react'
import { cn } from '@/lib/utils'
function Card({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card"
className={cn(
'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
className,
)}
{...props}
/>
)
}
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-header"
className={cn(
'@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
className,
)}
{...props}
/>
)
}
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-title"
className={cn('leading-none font-semibold', className)}
{...props}
/>
)
}
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-description"
className={cn('text-muted-foreground text-sm', className)}
{...props}
/>
)
}
function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-action"
className={cn(
'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
className,
)}
{...props}
/>
)
}
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-content"
className={cn('px-6', className)}
{...props}
/>
)
}
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="card-footer"
className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
{...props}
/>
)
}
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardAction,
CardDescription,
CardContent,
}

View File

@ -0,0 +1,94 @@
import { Card } from "@/components/ui/card"
const projects = [
{
title: "Commons Stack",
description:
"Cyber-physical commons architecture translating Ostrom's principles into DAO templates. Building open-source, token engineered component libraries for communal management of public goods.",
tags: ["Token Engineering", "DAOs", "Ostrom Compliance", "Public Goods"],
image: "/commons-stack-dao-governance-blockchain.jpg",
},
{
title: "Bonding Curve Research Group",
description:
"Research and development of Primary Issuance Markets enabling dynamic token supply. Challenging fixed supply paradigms with adaptive mechanisms that dampen volatility.",
tags: ["Bonding Curves", "cadCAD", "Token Economics", "DeFi"],
image: "/bonding-curve-token-economics-chart.jpg",
},
{
title: "MycoFi & Mycoeconomics",
description:
"Economic systems inspired by fungal networks. Regenerative protocols built on cooperation, mutual aid, and permaculture currency principles. Author of book.mycofi.earth.",
tags: ["Regenerative Economics", "Biomimicry", "Permaculture", "Web3"],
image: "/mycelium-network-nature-fungal.jpg",
},
{
title: "Conviction Voting",
description:
"Novel continuous decision-making mechanism for DAO governance. Eliminates time-boxed voting attack vectors while increasing community participation and long-term alignment.",
tags: ["Governance", "Voting Systems", "Social Sensor Fusion", "cadCAD"],
image: "/conviction-voting-governance-dashboard.jpg",
},
{
title: "Augmented Bonding Curves",
description:
"Primary Issuance Markets that create economic boundaries for commons ecosystems. Enables continuous fundraising, algorithmic liquidity, and price volatility dampening.",
tags: ["Token Design", "AMMs", "Cryptoeconomics", "Funding Mechanisms"],
image: "/augmented-bonding-curve-economic-system.jpg",
},
{
title: "Token Engineering Commons",
description:
"First field test of Commons Stack components. Outperformed other public goods tokens in risk-adjusted returns, demonstrating benefits of primary issuance markets.",
tags: ["DAO", "TEC", "Token Engineering", "Community Governance"],
image: "/token-engineering-community-collaborative.jpg",
},
]
export function WorkSection() {
return (
<section id="work" className="py-32 px-6">
<div className="max-w-7xl mx-auto">
<div className="mb-16">
<h2 className="text-5xl md:text-6xl font-bold mb-6">Research & Projects</h2>
<p className="text-xl text-muted-foreground max-w-2xl text-balance leading-relaxed">
Exploring token engineering, regenerative economics, and decentralized governance systems
</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
{projects.map((project, index) => (
<Card
key={index}
className="group relative overflow-hidden bg-card border-border hover:border-primary/50 transition-all duration-300 hover:scale-[1.02]"
>
<div className="aspect-video overflow-hidden bg-muted">
<img
src={project.image || "/placeholder.svg"}
alt={project.title}
className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-110"
/>
</div>
<div className="p-6">
<h3 className="text-2xl font-semibold mb-3 group-hover:text-primary transition-colors">
{project.title}
</h3>
<p className="text-muted-foreground mb-4 leading-relaxed">{project.description}</p>
<div className="flex flex-wrap gap-2">
{project.tags.map((tag, tagIndex) => (
<span
key={tagIndex}
className="text-xs font-mono px-3 py-1 bg-secondary text-secondary-foreground rounded-full"
>
{tag}
</span>
))}
</div>
</div>
</Card>
))}
</div>
</div>
</section>
)
}

6
lib/utils.ts Normal file
View File

@ -0,0 +1,6 @@
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}

12
next.config.mjs Normal file
View File

@ -0,0 +1,12 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
typescript: {
ignoreBuildErrors: true,
},
images: {
unoptimized: true,
},
}
export default nextConfig

73
package.json Normal file
View File

@ -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"
}
}

3233
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

8
postcss.config.mjs Normal file
View File

@ -0,0 +1,8 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
'@tailwindcss/postcss': {},
},
}
export default config

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

BIN
public/apple-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

BIN
public/icon-dark-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

BIN
public/icon-light-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

26
public/icon.svg Normal file
View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

BIN
public/placeholder-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

View File

@ -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

BIN
public/placeholder-user.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
public/placeholder.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

1
public/placeholder.svg Normal file
View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

125
styles/globals.css Normal file
View File

@ -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;
}
}

27
tsconfig.json Normal file
View File

@ -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"]
}