Initial Commit
This commit is contained in:
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
23
eslint.config.js
Normal file
23
eslint.config.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
reactHooks.configs.flat.recommended,
|
||||
reactRefresh.configs.vite,
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
},
|
||||
])
|
||||
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>portfolio</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
3903
package-lock.json
generated
Normal file
3903
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
33
package.json
Normal file
33
package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "portfolio",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"lucide-react": "^0.575.0",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@tailwindcss/vite": "^4.2.0",
|
||||
"@types/node": "^24.10.1",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.1",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.24",
|
||||
"globals": "^16.5.0",
|
||||
"tailwindcss": "^4.2.0",
|
||||
"typescript": "~5.9.3",
|
||||
"typescript-eslint": "^8.48.0",
|
||||
"vite": "^7.3.1"
|
||||
}
|
||||
}
|
||||
6
src/App.css
Normal file
6
src/App.css
Normal file
@@ -0,0 +1,6 @@
|
||||
#root {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
}
|
||||
677
src/App.tsx
Normal file
677
src/App.tsx
Normal file
@@ -0,0 +1,677 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Terminal, Github, Mail, Layout, Cpu, Network, ExternalLink, ChevronRight, Activity, User } from 'lucide-react';
|
||||
import './App.css';
|
||||
|
||||
// --- THEME CONFIGURATION ---
|
||||
const THEMES = [
|
||||
{ name: 'Blueprint Cyan', value: '#38bdf8', id: 'cyan' },
|
||||
{ name: 'Drafting Yellow', value: '#fde047', id: 'yellow' },
|
||||
{ name: 'Red Ink', value: '#f87171', id: 'red' },
|
||||
{ name: 'Chalk White', value: '#f8fafc', id: 'white' }
|
||||
];
|
||||
|
||||
// --- MOCK DATA ---
|
||||
const PROJECTS = [
|
||||
{
|
||||
id: 'kwin-tiling',
|
||||
title: 'KWin Dynamic Tiling Script',
|
||||
category: 'Window Management',
|
||||
tech: ['JavaScript', 'KDE API', 'C++'],
|
||||
desc: 'An i3-style tiling extension for KWin. Replaces standard floating windows with a deterministic BSP (Binary Space Partitioning) tree layout.',
|
||||
icon: <Layout className="w-5 h-5" />
|
||||
},
|
||||
{
|
||||
id: 'rp2040-firmware',
|
||||
title: 'RP2040 Custom Keyboard & EMR',
|
||||
category: 'Hardware / Firmware',
|
||||
tech: ['C', 'Rust', 'PIO', 'I2C'],
|
||||
desc: 'Custom firmware integrating a standard mechanical key matrix with an experimental EMR stylus digitizer for unified input processing.',
|
||||
icon: <Cpu className="w-5 h-5" />
|
||||
},
|
||||
{
|
||||
id: 'graphql-inspector',
|
||||
title: 'GQL Traffic Interceptor',
|
||||
category: 'Reverse Engineering',
|
||||
tech: ['Go', 'eBPF', 'React'],
|
||||
desc: 'A local network utility utilizing eBPF to silently inspect, decode, and visualize GraphQL traffic between local containers.',
|
||||
icon: <Network className="w-5 h-5" />
|
||||
}
|
||||
];
|
||||
|
||||
const LAB_NOTES = [
|
||||
{ date: '2026-02-14', title: 'Reverse Engineering TrueNAS Middleware API' },
|
||||
{ date: '2026-01-28', title: 'Why I stopped using Nginx and wrote my own router' },
|
||||
{ date: '2025-12-10', title: 'Injecting dynamic themes via CSS variable mutations' }
|
||||
];
|
||||
|
||||
export default function App() {
|
||||
const [activeTheme, setActiveTheme] = useState(THEMES[0]);
|
||||
const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
|
||||
|
||||
// Update CSS variables for dynamic theming
|
||||
useEffect(() => {
|
||||
document.documentElement.style.setProperty('--color-accent', activeTheme.value);
|
||||
// Calculate a semi-transparent version for backgrounds/borders
|
||||
document.documentElement.style.setProperty('--color-accent-muted', `${activeTheme.value}33`);
|
||||
}, [activeTheme]);
|
||||
|
||||
// Subtle interactive background effect
|
||||
useEffect(() => {
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
setMousePos({ x: e.clientX, y: e.clientY });
|
||||
};
|
||||
window.addEventListener('mousemove', handleMouseMove);
|
||||
return () => window.removeEventListener('mousemove', handleMouseMove);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[var(--bg-base)] text-[var(--text-main)] font-mono selection:bg-[var(--color-accent)] selection:text-[var(--bg-base)] relative overflow-x-hidden">
|
||||
|
||||
{/* Global CSS for the dynamic theme and indie style */}
|
||||
<style>{`
|
||||
@import url('https://fonts.googleapis.com/css2?family=Architects+Daughter&family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap');
|
||||
|
||||
:root {
|
||||
/* =========================================
|
||||
🎨 CENTRAL COLOR PALETTE
|
||||
Modify these variables to change the theme!
|
||||
========================================= */
|
||||
|
||||
/* Backgrounds */
|
||||
--bg-base: #111113; /* Main page background */
|
||||
--bg-surface: rgba(24, 24, 27, 0.4); /* Cards and secondary backgrounds */
|
||||
--bg-panel: rgba(9, 9, 11, 0.85); /* Terminal panes and rigid components */
|
||||
|
||||
/* Typography */
|
||||
--text-main: #f4f4f5; /* Headings and primary text */
|
||||
--text-muted: #a1a1aa; /* Paragraphs and secondary text */
|
||||
--text-dim: #52525b; /* Annotations and subtle details */
|
||||
|
||||
/* Structure */
|
||||
--border-main: #27272a; /* Dashed lines and pane borders */
|
||||
--grid-pattern: rgba(255, 255, 255, 0.08); /* Background dot grid color */
|
||||
|
||||
/* Status Indicators */
|
||||
--status-success: #34d399; /* Emerald color for 'Online' status */
|
||||
|
||||
/* Easter Egg (Cat) */
|
||||
--cat-body: #111113; /* Main body color (usually matches bg-base) */
|
||||
--cat-stroke: #60a5fa; /* Blue stroke outline */
|
||||
--cat-nose: #f472b6; /* Pink nose */
|
||||
--cat-eyes: #ffffff; /* White eyes */
|
||||
--heart-color: #f472b6; /* Heart animation color */
|
||||
}
|
||||
|
||||
.font-sketch { font-family: 'Architects Daughter', cursive; }
|
||||
.font-mono { font-family: 'Space Mono', monospace; }
|
||||
|
||||
.accent-text { color: var(--color-accent); transition: color 0.3s ease; }
|
||||
.accent-bg { background-color: var(--color-accent); transition: background-color 0.3s ease; }
|
||||
|
||||
/* Indie / Hand-drawn borders */
|
||||
.sketch-border {
|
||||
border: 2px solid var(--color-accent-muted);
|
||||
border-radius: 255px 15px 225px 15px/15px 225px 15px 255px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.sketch-border:hover {
|
||||
border-color: var(--color-accent);
|
||||
border-radius: 15px 225px 15px 255px/255px 15px 225px 15px;
|
||||
}
|
||||
|
||||
.sketch-border-subtle {
|
||||
border: 1px solid var(--border-main);
|
||||
border-radius: 2px 255px 3px 25px / 255px 5px 225px 3px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.sketch-border-subtle:hover {
|
||||
border-color: var(--color-accent);
|
||||
border-radius: 255px 5px 225px 3px / 2px 255px 3px 25px;
|
||||
}
|
||||
|
||||
.dot-grid {
|
||||
background-image: radial-gradient(var(--grid-pattern) 1px, transparent 1px);
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
{/* SVG Noise Filter for rough paper texture */}
|
||||
<svg className="hidden">
|
||||
<filter id="noiseFilter">
|
||||
<feTurbulence type="fractalNoise" baseFrequency="0.7" numOctaves="3" stitchTiles="stitch" />
|
||||
</filter>
|
||||
</svg>
|
||||
<div className="fixed inset-0 z-0 pointer-events-none opacity-[0.04]" style={{ filter: 'url(#noiseFilter)' }} />
|
||||
|
||||
{/* Blueprint Dot Grid Background */}
|
||||
<div className="fixed inset-0 dot-grid z-0 pointer-events-none opacity-50" />
|
||||
|
||||
{/* Subtle mouse glow */}
|
||||
<div
|
||||
className="fixed inset-0 z-0 pointer-events-none opacity-20 transition-opacity duration-300"
|
||||
style={{
|
||||
background: `radial-gradient(400px circle at ${mousePos.x}px ${mousePos.y}px, var(--color-accent-muted), transparent 40%)`
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Hidden Cat Easter Egg */}
|
||||
<CatEasterEgg />
|
||||
|
||||
<div className="relative z-10 max-w-5xl mx-auto px-6 py-12 flex flex-col gap-16">
|
||||
|
||||
{/* Navigation / Command Bar */}
|
||||
<nav className="flex flex-col sm:flex-row justify-between items-start sm:items-center border-b-2 border-dashed border-[var(--border-main)] pb-4 gap-4">
|
||||
<div className="flex items-center gap-2 text-sm text-[var(--text-muted)] relative group">
|
||||
<Terminal className="w-5 h-5 accent-text transform -rotate-12 group-hover:rotate-12 transition-transform" />
|
||||
<span className="font-sketch text-2xl text-[var(--text-main)] tracking-wide">aditya_gupta <span className="text-[var(--text-dim)]">//</span> homelab</span>
|
||||
|
||||
{/* Hand-drawn annotation */}
|
||||
<div className="absolute -top-6 -right-16 font-sketch text-sm accent-text rotate-12 flex items-center gap-1 opacity-80">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="transform -scale-x-100 rotate-45"><path d="M5 12h14" /><path d="m12 5 7 7-7 7" /></svg>
|
||||
<span>root</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-sketch text-[var(--text-dim)] text-sm rotate-[-2deg]">theme_picker:</span>
|
||||
<div className="flex gap-2">
|
||||
{THEMES.map(theme => (
|
||||
<button
|
||||
key={theme.id}
|
||||
onClick={() => setActiveTheme(theme)}
|
||||
title={`Switch to ${theme.name}`}
|
||||
className={`w-5 h-5 transition-all duration-200 sketch-border-subtle ${activeTheme.id === theme.id ? 'scale-125 shadow-[0_0_10px_var(--color-accent-muted)]' : 'hover:scale-110'}`}
|
||||
style={{ backgroundColor: theme.value, borderColor: activeTheme.id === theme.id ? theme.value : 'transparent' }}
|
||||
aria-label={`Switch theme to ${theme.name}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-6 w-px border-l-2 border-dashed border-[var(--border-main)]" />
|
||||
<a href="#" className="font-sketch text-lg hover:text-[var(--text-main)] transition-colors flex items-center gap-2 group"><Github className="w-4 h-4 group-hover:-translate-y-1 transition-transform" /> github</a>
|
||||
<a href="#" className="font-sketch text-lg hover:text-[var(--text-main)] transition-colors flex items-center gap-2 group"><Mail className="w-4 h-4 group-hover:-translate-y-1 transition-transform" /> contact</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Hero Section */}
|
||||
<header className="flex flex-col md:flex-row gap-12 items-center justify-between relative">
|
||||
<div className="space-y-6 max-w-2xl">
|
||||
<div className="inline-flex items-center gap-2 px-4 py-1.5 sketch-border bg-[var(--bg-surface)] text-xs mb-4 transform -rotate-1">
|
||||
<Activity className="w-3 h-3 accent-text animate-pulse" />
|
||||
<span className="font-sketch text-sm">STATUS: <span className="text-[var(--text-main)]">ONLINE</span></span>
|
||||
</div>
|
||||
<h1 className="text-4xl sm:text-5xl font-bold tracking-tight text-[var(--text-main)] leading-tight">
|
||||
I engineer <span className="accent-text relative inline-block">
|
||||
infrastructure
|
||||
<svg className="absolute w-full h-3 -bottom-1 left-0 accent-text" viewBox="0 0 100 20" preserveAspectRatio="none" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M2,15 Q50,-5 98,15" /></svg>
|
||||
</span>,<br /> reverse-engineer black boxes,<br /> and build tools.
|
||||
</h1>
|
||||
<p className="text-lg text-[var(--text-muted)] leading-relaxed max-w-xl font-mono text-sm">
|
||||
Based in New Delhi. Exploring homelab orchestration, low-level input devices, and dynamic theming engines. This is my public scratchpad and systems notebook.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Image Placeholder */}
|
||||
<div className="relative w-48 h-56 sm:w-64 sm:h-72 shrink-0 sketch-border bg-[var(--bg-panel)] transform rotate-[3deg] hover:rotate-0 transition-transform duration-500 group flex flex-col items-center justify-center mt-8 md:mt-0">
|
||||
{/* Faux tape in corners */}
|
||||
<div className="absolute -top-3 -right-4 w-12 h-6 bg-[var(--color-accent-muted)] transform rotate-45 opacity-60 backdrop-blur-sm sketch-border-subtle border-none" />
|
||||
<div className="absolute -bottom-3 -left-4 w-12 h-6 bg-[var(--color-accent-muted)] transform rotate-45 opacity-60 backdrop-blur-sm sketch-border-subtle border-none" />
|
||||
|
||||
<div className="absolute inset-2 border-2 border-dashed border-[var(--border-main)] flex flex-col items-center justify-center text-[var(--text-dim)] group-hover:text-[var(--color-accent)] transition-colors duration-300 group-hover:bg-[var(--color-accent-muted)]/5">
|
||||
<User className="w-12 h-12 mb-3 opacity-50" />
|
||||
<span className="font-sketch text-sm">avatar.jpg</span>
|
||||
<span className="font-mono text-[10px] opacity-40 mt-1">[1024x1024]</span>
|
||||
</div>
|
||||
|
||||
{/* Hand-drawn annotation */}
|
||||
<div className="absolute -bottom-8 -left-12 font-sketch text-xs accent-text -rotate-[15deg] hidden md:flex items-center gap-2 opacity-80">
|
||||
<span className="whitespace-nowrap">the operator</span>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="transform -scale-y-100 rotate-45"><path d="M5 12h14" /><path d="m12 5 7 7-7 7" /></svg>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* System Overview Dashboard (Replaced Interactive Tiling Demo) */}
|
||||
<section className="space-y-4 relative mt-12 md:mt-0">
|
||||
<div className="absolute -left-12 top-10 font-sketch accent-text -rotate-90 hidden lg:block tracking-widest text-sm opacity-60">
|
||||
[ SYSTEM_SPECS ]
|
||||
</div>
|
||||
<div className="flex items-center justify-between border-b-2 border-dashed border-[var(--border-main)] pb-2">
|
||||
<h2 className="font-sketch text-2xl text-[var(--text-main)] flex items-center gap-2">
|
||||
<Cpu className="w-5 h-5 accent-text" /> system_overview.sh
|
||||
</h2>
|
||||
<span className="font-sketch text-[var(--text-dim)] text-sm animate-pulse">~ click panes to drill down ~</span>
|
||||
</div>
|
||||
<InteractiveSystemOverview />
|
||||
</section>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-12 mt-8">
|
||||
|
||||
{/* Featured Projects */}
|
||||
<section className="md:col-span-2 space-y-6">
|
||||
<h2 className="font-sketch text-2xl text-[var(--text-main)] border-b-2 border-dashed border-[var(--border-main)] pb-2 flex items-center gap-2">
|
||||
<Layout className="w-5 h-5 accent-text" /> architecture_studies/
|
||||
</h2>
|
||||
<div className="flex flex-col gap-6">
|
||||
{PROJECTS.map((project, idx) => (
|
||||
<article
|
||||
key={project.id}
|
||||
className={`group relative p-6 bg-[var(--bg-surface)] sketch-border-subtle cursor-pointer overflow-hidden ${idx % 2 === 0 ? 'transform rotate-[0.5deg]' : 'transform -rotate-[0.5deg]'}`}
|
||||
>
|
||||
<div className="absolute top-0 left-0 w-full h-1 bg-[var(--border-main)] group-hover:bg-[var(--color-accent)] transition-colors duration-300 opacity-50" />
|
||||
|
||||
<div className="flex justify-between items-start mb-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="p-3 sketch-border-subtle bg-[var(--bg-panel)] text-[var(--text-muted)] group-hover:text-[var(--color-accent)] group-hover:scale-110 transition-all transform -rotate-3">
|
||||
{project.icon}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-[var(--text-main)] font-bold text-lg flex items-center gap-2 font-mono">
|
||||
{project.title}
|
||||
<ExternalLink className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity accent-text" />
|
||||
</h3>
|
||||
<span className="font-sketch text-sm text-[var(--text-muted)] accent-text">{project.category}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-[var(--text-muted)] mb-5 leading-relaxed font-mono">
|
||||
{project.desc}
|
||||
</p>
|
||||
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{project.tech.map(t => (
|
||||
<span key={t} className="text-xs px-2 py-1 bg-[var(--bg-panel)] sketch-border-subtle text-[var(--text-muted)] font-mono">
|
||||
{t}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Lab Notes */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="font-sketch text-2xl text-[var(--text-main)] border-b-2 border-dashed border-[var(--border-main)] pb-2 flex items-center gap-2">
|
||||
<ChevronRight className="w-5 h-5 accent-text" /> lab_notes.txt
|
||||
</h2>
|
||||
<div className="flex flex-col gap-4 border-l-2 border-dashed border-[var(--border-main)] ml-2 relative">
|
||||
{/* Hand drawn arrow pointing to notes */}
|
||||
<div className="absolute -left-10 top-0 font-sketch text-xs accent-text -rotate-12 hidden sm:block">
|
||||
recent
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="ml-2 transform rotate-90"><path d="M5 12h14" /><path d="m12 5 7 7-7 7" /></svg>
|
||||
</div>
|
||||
|
||||
{LAB_NOTES.map((note, i) => (
|
||||
<div key={i} className="relative pl-6 py-2 group cursor-pointer">
|
||||
{/* Rough Timeline dot */}
|
||||
<div className="absolute left-[-9px] top-[14px] w-[16px] h-[16px] flex items-center justify-center bg-[var(--bg-base)] group-hover:scale-125 transition-transform">
|
||||
<span className="text-[var(--text-dim)] group-hover:text-[var(--color-accent)] font-sketch text-lg leading-none transform -rotate-12">x</span>
|
||||
</div>
|
||||
|
||||
<div className="font-mono text-[10px] text-[var(--text-dim)] mb-1">{note.date}</div>
|
||||
<h3 className="text-sm font-mono text-[var(--text-muted)] group-hover:text-[var(--text-main)] transition-colors leading-relaxed">
|
||||
{note.title}
|
||||
</h3>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-10 p-5 sketch-border bg-[var(--color-accent-muted)]/5 transform rotate-1">
|
||||
<div className="flex gap-3 items-start">
|
||||
<Terminal className="w-5 h-5 accent-text mt-1 flex-shrink-0" />
|
||||
<p className="text-[var(--text-muted)] text-sm font-mono leading-relaxed">
|
||||
<span className="font-sketch text-lg accent-text block mb-1">Observation:</span>
|
||||
All systems operating nominally. Proceeding with hardware teardown sequence 0x4B.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="border-t-2 border-dashed border-[var(--border-main)] pt-8 pb-12 flex flex-col sm:flex-row justify-between items-center gap-4 text-xs font-mono text-[var(--text-dim)]">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-sketch text-lg transform -rotate-6 block">Aditya Gupta</span>
|
||||
<span>// 2026 // NEW_DELHI</span>
|
||||
</div>
|
||||
<div className="flex gap-4 sketch-border-subtle px-4 py-2 bg-[var(--bg-surface)]">
|
||||
<span>UPTIME: 99.9%</span>
|
||||
<span className="text-[var(--text-dim)]">|</span>
|
||||
<span className="accent-text">NOMINAL</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// --- INTERACTIVE SYSTEM OVERVIEW COMPONENT ---
|
||||
// Progressively reveals more specific content as panes are "split"
|
||||
const CONTENT_MODULES = [
|
||||
{
|
||||
id: 'bio',
|
||||
title: '/home/aditya/bio.txt',
|
||||
tty: 'tty1',
|
||||
content: (
|
||||
<div className="font-mono text-sm sm:text-base text-[var(--text-muted)] leading-relaxed flex-1 space-y-4">
|
||||
<div>
|
||||
<span className="accent-text font-sketch text-xl mr-2">{'>'}</span>
|
||||
<span className="text-[var(--text-main)]">whoami</span>
|
||||
<p className="mt-2 ml-4 border-l-2 border-[var(--border-main)] pl-4 text-[var(--text-main)]">
|
||||
Aditya Gupta. 20. Based in New Delhi. <br />
|
||||
I don't just write code; I build and dismantle systems.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<span className="accent-text font-sketch text-xl mr-2">{'>'}</span>
|
||||
<span className="text-[var(--text-main)]">cat mindset.md</span>
|
||||
<div className="mt-2 ml-4 space-y-2 border-l-2 border-[var(--border-main)] pl-4">
|
||||
<p>Treat the environment as a continuous experiment.</p>
|
||||
<p className="text-xs text-[var(--text-dim)] mt-2">Split this pane to view technical stack.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'skills',
|
||||
title: 'ls /usr/bin/skills',
|
||||
tty: 'tty2',
|
||||
content: (
|
||||
<div className="font-mono text-xs text-[var(--text-main)] flex-1 content-start">
|
||||
<div className="flex flex-wrap gap-2 mt-1">
|
||||
{['Rust', 'Go', 'C/C++', 'eBPF', 'Kubernetes', 'TrueNAS', 'Linux/KWin', 'React'].map((skill) => (
|
||||
<span key={skill} className="px-2 py-1 bg-[var(--bg-surface)] border border-[var(--border-main)] rounded-sm hover:border-[var(--color-accent)] hover:text-[var(--color-accent)] transition-colors cursor-default">
|
||||
{skill}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<p className="mt-4 text-[10px] text-[var(--text-dim)] animate-pulse border-t border-dashed border-[var(--border-main)] pt-2">Split for infrastructure status...</p>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'homelab',
|
||||
title: 'kubectl get nodes',
|
||||
tty: 'tty3',
|
||||
content: (
|
||||
<div className="font-mono text-[10px] sm:text-xs text-[var(--text-muted)] flex-1 overflow-x-auto">
|
||||
<table className="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr className="text-[var(--text-dim)] border-b border-[var(--border-main)]">
|
||||
<th className="pb-1 font-normal">NAME</th>
|
||||
<th className="pb-1 font-normal">STATUS</th>
|
||||
<th className="pb-1 font-normal">ROLES</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="leading-relaxed">
|
||||
<tr className="group/row hover:bg-[var(--bg-surface)]">
|
||||
<td className="pt-1 text-[var(--text-main)]">pve-core</td>
|
||||
<td className="pt-1"><span className="text-[var(--status-success)]">Ready</span></td>
|
||||
<td className="pt-1 accent-text">control-plane</td>
|
||||
</tr>
|
||||
<tr className="group/row hover:bg-[var(--bg-surface)]">
|
||||
<td>nas-store</td>
|
||||
<td><span className="text-[var(--status-success)]">Ready</span></td>
|
||||
<td>truenas-iscsi</td>
|
||||
</tr>
|
||||
<tr className="group/row hover:bg-[var(--bg-surface)]">
|
||||
<td>edge-rout</td>
|
||||
<td><span className="text-[var(--status-success)]">Ready</span></td>
|
||||
<td>ingress-bpf</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="mt-2 flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="w-2 h-2 rounded-full bg-[var(--status-success)]"></span>
|
||||
<span className="font-sketch text-xs text-[var(--text-dim)]">Healthy</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'hardware',
|
||||
title: 'lshw -short | grep input',
|
||||
tty: 'tty4',
|
||||
content: (
|
||||
<div className="font-mono text-xs text-[var(--text-muted)] flex-1">
|
||||
<span className="accent-text font-sketch text-lg mr-2">{'>'}</span>
|
||||
<span className="text-[var(--text-main)]">Hardware focus</span>
|
||||
<ul className="mt-2 ml-2 border-l-2 border-[var(--border-main)] pl-3 space-y-1.5">
|
||||
<li>MCU: RP2040 (C/Rust)</li>
|
||||
<li>Matrix: Ortho 40%</li>
|
||||
<li>Sensor: EMR Stylus</li>
|
||||
<li>Rate: 1000Hz</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
id: 'focus',
|
||||
title: 'tail -f /var/log/focus',
|
||||
tty: 'tty5',
|
||||
content: (
|
||||
<div className="font-mono text-xs text-[var(--text-muted)] flex-1">
|
||||
<div className="text-[var(--text-dim)] border-b border-dashed border-[var(--border-main)] pb-1 mb-2">Streaming...</div>
|
||||
<p className="mb-1"><span className="accent-text">[INFO]</span> Analyzing GQL via eBPF</p>
|
||||
<p className="mb-1"><span className="accent-text">[INFO]</span> Wiring custom router</p>
|
||||
<p><span className="text-[var(--text-dim)]">[WAIT]</span> PCB transit delays</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
function InteractiveSystemOverview() {
|
||||
const [activeNodes, setActiveNodes] = useState([CONTENT_MODULES[0]]);
|
||||
const [nextModuleIndex, setNextModuleIndex] = useState(1);
|
||||
|
||||
const handleSplit = (clickedIndex: number) => {
|
||||
if (nextModuleIndex >= CONTENT_MODULES.length) return; // Max panes reached
|
||||
|
||||
setActiveNodes(prev => {
|
||||
const newNodes = [...prev];
|
||||
newNodes.splice(clickedIndex + 1, 0, CONTENT_MODULES[nextModuleIndex]);
|
||||
return newNodes;
|
||||
});
|
||||
setNextModuleIndex(prev => prev + 1);
|
||||
};
|
||||
|
||||
const getGridContainerClass = () => {
|
||||
// We use a 12-column grid to allow highly precise asymmetrical splits
|
||||
return "grid grid-cols-1 sm:grid-cols-12 gap-3 transition-all duration-500 ease-in-out p-2 auto-rows-[minmax(180px,auto)]";
|
||||
};
|
||||
|
||||
const getNodeClass = (length: number, index: number) => {
|
||||
// 1 Pane: Full width, taller
|
||||
if (length === 1) return "sm:col-span-12 sm:row-span-2 min-h-[300px]";
|
||||
|
||||
// 2 Panes: 50/50 split
|
||||
if (length === 2) return "sm:col-span-6 sm:row-span-2 min-h-[300px]";
|
||||
|
||||
// 3 Panes: 1 large left (spans 2 rows), 2 stacked on the right
|
||||
if (length === 3) {
|
||||
if (index === 0) return "sm:col-span-8 sm:row-span-2";
|
||||
if (index === 1) return "sm:col-span-4 sm:row-span-1";
|
||||
if (index === 2) return "sm:col-span-4 sm:row-span-1";
|
||||
}
|
||||
|
||||
// 4 Panes: 2x2 grid
|
||||
if (length === 4) return "sm:col-span-6 sm:row-span-1 min-h-[220px]";
|
||||
|
||||
// 5 Panes: Advanced Bento/Tiling layout (expands downward)
|
||||
if (length === 5) {
|
||||
if (index === 0) return "sm:col-span-7 sm:row-span-2"; // Bio: Top left, large
|
||||
if (index === 1) return "sm:col-span-5 sm:row-span-1"; // Skills: Top right
|
||||
if (index === 2) return "sm:col-span-5 sm:row-span-1"; // Homelab: Middle right
|
||||
if (index === 3) return "sm:col-span-6 sm:row-span-1 min-h-[200px]"; // Hardware: Bottom left
|
||||
if (index === 4) return "sm:col-span-6 sm:row-span-1 min-h-[200px]"; // Focus: Bottom right
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={getGridContainerClass()}>
|
||||
{activeNodes.map((node, i) => {
|
||||
const rotation = i % 2 === 0 ? 'rotate-[0.5deg]' : '-rotate-[0.5deg]';
|
||||
|
||||
return (
|
||||
<div
|
||||
key={node.id}
|
||||
onClick={() => handleSplit(i)}
|
||||
className={`
|
||||
sketch-border bg-[var(--bg-panel)] p-4 relative group overflow-hidden flex flex-col
|
||||
transform ${rotation} transition-all duration-500 hover:scale-[1.01] hover:z-10
|
||||
${nextModuleIndex < CONTENT_MODULES.length ? 'cursor-crosshair' : 'cursor-default'}
|
||||
${getNodeClass(activeNodes.length, i)}
|
||||
`}
|
||||
>
|
||||
{/* Top Bar */}
|
||||
<div className="flex justify-between items-center border-b-2 border-dashed border-[var(--border-main)] pb-2 mb-3 shrink-0">
|
||||
<span className="font-sketch text-xs sm:text-sm text-[var(--text-muted)] lowercase flex items-center gap-1.5 whitespace-nowrap overflow-hidden text-ellipsis">
|
||||
<span className="text-base accent-text leading-none">*</span>
|
||||
{node.title}
|
||||
</span>
|
||||
<span className="font-sketch text-[10px] sm:text-xs text-[var(--text-dim)] shrink-0 ml-2">[{node.tty}]</span>
|
||||
</div>
|
||||
|
||||
{/* Dynamic Content */}
|
||||
<div className="flex-1 overflow-y-auto custom-scrollbar pr-1">
|
||||
{node.content}
|
||||
</div>
|
||||
|
||||
{/* Hover Overlay indicating split action (only if more modules exist) */}
|
||||
{nextModuleIndex < CONTENT_MODULES.length && (
|
||||
<div className="absolute inset-0 bg-[var(--color-accent-muted)]/5 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center backdrop-blur-[1px] pointer-events-none">
|
||||
<span className="font-sketch text-lg sm:text-xl font-bold text-[var(--text-main)] bg-[var(--bg-panel)] px-3 py-1.5 sketch-border transform rotate-[-2deg] shadow-lg">
|
||||
SPLIT_VIEW
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// --- EASTER EGG COMPONENT ---
|
||||
function CatEasterEgg() {
|
||||
const [reveal, setReveal] = useState(0); // 0 (hidden) to 100 (fully visible)
|
||||
const [posX, setPosX] = useState(80); // percentage from left
|
||||
const [showHeart, setShowHeart] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let currentReveal = 0;
|
||||
|
||||
const handleScroll = () => {
|
||||
if (showHeart) return; // Prevent scroll from overriding the heart animation
|
||||
|
||||
const currentScrollY = window.scrollY;
|
||||
|
||||
// Define the specific "sliver" of scroll where the cat lives
|
||||
const period = 1200; // The pattern repeats every 1200px of scrolling
|
||||
const peakOffset = 700; // The exact scroll Y position where the cat is 100% visible
|
||||
const peekWidth = 300; // How many pixels of scrolling it takes to fully reveal/hide
|
||||
|
||||
// Calculate how far the current scroll is from the peak visibility point
|
||||
const distanceToPeak = Math.abs((currentScrollY % period) - peakOffset);
|
||||
|
||||
let newReveal = 0;
|
||||
if (distanceToPeak < peekWidth) {
|
||||
// Linearly map the distance to a 0-100 percentage
|
||||
newReveal = 100 - (distanceToPeak / peekWidth) * 100;
|
||||
}
|
||||
|
||||
// If it just fully hid, randomize its next horizontal position
|
||||
if (newReveal === 0 && currentReveal > 0) {
|
||||
setPosX(Math.floor(Math.random() * 80) + 10); // Random position between 10% and 90%
|
||||
}
|
||||
|
||||
currentReveal = newReveal;
|
||||
setReveal(newReveal);
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
handleScroll(); // Check initial position in case the user reloads halfway down
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}, [showHeart]); // Depend on showHeart
|
||||
|
||||
// Handle click: show heart, wait, then hide
|
||||
const handleCatClick = () => {
|
||||
if (showHeart || reveal === 0) return;
|
||||
setShowHeart(true);
|
||||
|
||||
// Temporarily force it fully visible for the animation
|
||||
setReveal(100);
|
||||
|
||||
// Wait 1.2s to show the heart, then hide the cat
|
||||
setTimeout(() => {
|
||||
setShowHeart(false);
|
||||
setReveal(0);
|
||||
|
||||
// Randomize position after hiding
|
||||
setTimeout(() => setPosX(Math.floor(Math.random() * 80) + 10), 500);
|
||||
}, 1200);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed bottom-[-2px] z-50 transition-transform duration-100 ease-out"
|
||||
style={{
|
||||
left: `${posX}%`,
|
||||
transform: `translateY(${150 - (reveal * 1.5)}%)` // 150% is fully hidden, 0% is fully visible
|
||||
}}
|
||||
>
|
||||
<div className="relative group cursor-pointer" onClick={handleCatClick}>
|
||||
|
||||
{/* Floating Heart Animation */}
|
||||
<div className={`absolute left-1/2 transform -translate-x-1/2 text-[var(--heart-color)] text-4xl z-50 transition-all duration-700 ease-out pointer-events-none ${showHeart ? '-top-16 opacity-100 scale-110' : 'top-2 opacity-0 scale-50'}`}>
|
||||
♥
|
||||
</div>
|
||||
|
||||
{/* Hand-drawn annotation on hover */}
|
||||
<div className="absolute -top-10 -left-20 font-sketch text-xs accent-text -rotate-12 opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap bg-[var(--bg-panel)] px-3 py-1 sketch-border-subtle backdrop-blur-sm shadow-xl">
|
||||
./purr.sh
|
||||
</div>
|
||||
|
||||
{/* Paws */}
|
||||
<div className="absolute -top-2 left-2 w-4 h-5 border-2 border-[var(--cat-stroke)] rounded-t-[12px] bg-[var(--cat-body)] z-10"></div>
|
||||
<div className="absolute -top-2 right-2 w-4 h-5 border-2 border-[var(--cat-stroke)] rounded-t-[12px] bg-[var(--cat-body)] z-10"></div>
|
||||
|
||||
{/* Head */}
|
||||
<div className="w-16 h-14 border-2 border-[var(--cat-stroke)] border-b-0 rounded-t-[24px] bg-[var(--cat-body)] flex justify-center pt-5 gap-3 relative z-0">
|
||||
|
||||
{/* Ears */}
|
||||
<div className="absolute -top-3 left-0 w-6 h-7 border-2 border-[var(--cat-stroke)] border-b-0 border-r-0 rounded-tl-full transform rotate-[20deg] bg-[var(--cat-body)] -z-10"></div>
|
||||
<div className="absolute -top-3 right-0 w-6 h-7 border-2 border-[var(--cat-stroke)] border-b-0 border-l-0 rounded-tr-full transform -rotate-[20deg] bg-[var(--cat-body)] -z-10"></div>
|
||||
|
||||
{/* Whiskers */}
|
||||
<div className="absolute top-7 -left-3 w-4 h-[2px] bg-[var(--cat-stroke)] rounded-full transform rotate-[15deg] opacity-60"></div>
|
||||
<div className="absolute top-9 -left-3 w-4 h-[2px] bg-[var(--cat-stroke)] rounded-full transform -rotate-[5deg] opacity-60"></div>
|
||||
<div className="absolute top-7 -right-3 w-4 h-[2px] bg-[var(--cat-stroke)] rounded-full transform -rotate-[15deg] opacity-60"></div>
|
||||
<div className="absolute top-9 -right-3 w-4 h-[2px] bg-[var(--cat-stroke)] rounded-full transform rotate-[5deg] opacity-60"></div>
|
||||
|
||||
{/* Eyes */}
|
||||
<div className={`w-3 h-3 rounded-full bg-[var(--cat-eyes)] relative transition-all duration-300 ${showHeart ? 'scale-y-[0.2]' : ''}`}>
|
||||
</div>
|
||||
<div className={`w-3 h-3 rounded-full bg-[var(--cat-eyes)] relative transition-all duration-300 ${showHeart ? 'scale-y-[0.2]' : ''}`}>
|
||||
</div>
|
||||
|
||||
{/* Nose/Mouth */}
|
||||
<div className="absolute top-8 left-1/2 transform -translate-x-1/2 w-1.5 h-1 bg-[var(--cat-nose)] rounded-full"></div>
|
||||
<div className="absolute top-[34px] left-1/2 transform -translate-x-1/2 text-[var(--cat-stroke)] text-[10px] font-bold tracking-tighter">w</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
13
src/index.css
Normal file
13
src/index.css
Normal file
@@ -0,0 +1,13 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
/* Keep this file minimal: Tailwind provides base styling.
|
||||
App/theme styles live in `src/App.css` and `src/theme.css`. */
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
11
src/main.tsx
Normal file
11
src/main.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import './theme.css'
|
||||
import App from './App.tsx'
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
92
src/theme.css
Normal file
92
src/theme.css
Normal file
@@ -0,0 +1,92 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Architects+Daughter&family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap');
|
||||
|
||||
:root {
|
||||
/* =========================================
|
||||
🎨 CENTRAL COLOR PALETTE
|
||||
Modify these variables to change the theme!
|
||||
========================================= */
|
||||
|
||||
/* Backgrounds */
|
||||
--bg-base: #111113;
|
||||
/* Main page background */
|
||||
--bg-surface: rgba(24, 24, 27, 0.4);
|
||||
/* Cards and secondary backgrounds */
|
||||
--bg-panel: rgba(9, 9, 11, 0.85);
|
||||
/* Terminal panes and rigid components */
|
||||
|
||||
/* Typography */
|
||||
--text-main: #f4f4f5;
|
||||
/* Headings and primary text */
|
||||
--text-muted: #a1a1aa;
|
||||
/* Paragraphs and secondary text */
|
||||
--text-dim: #52525b;
|
||||
/* Annotations and subtle details */
|
||||
|
||||
/* Structure */
|
||||
--border-main: #27272a;
|
||||
/* Dashed lines and pane borders */
|
||||
--grid-pattern: rgba(255, 255, 255, 0.08);
|
||||
/* Background dot grid color */
|
||||
|
||||
/* Status Indicators */
|
||||
--status-success: #34d399;
|
||||
/* Emerald color for 'Online' status */
|
||||
|
||||
/* Easter Egg (Cat) */
|
||||
--cat-body: #111113;
|
||||
/* Main body color (usually matches bg-base) */
|
||||
--cat-stroke: #60a5fa;
|
||||
/* Blue stroke outline */
|
||||
--cat-nose: #f472b6;
|
||||
/* Pink nose */
|
||||
--cat-eyes: #ffffff;
|
||||
/* White eyes */
|
||||
--heart-color: #f472b6;
|
||||
/* Heart animation color */
|
||||
}
|
||||
|
||||
.font-sketch {
|
||||
font-family: 'Architects Daughter', cursive;
|
||||
}
|
||||
|
||||
.font-mono {
|
||||
font-family: 'Space Mono', monospace;
|
||||
}
|
||||
|
||||
.accent-text {
|
||||
color: var(--color-accent);
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.accent-bg {
|
||||
background-color: var(--color-accent);
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Indie / Hand-drawn borders */
|
||||
.sketch-border {
|
||||
border: 2px solid var(--color-accent-muted);
|
||||
border-radius: 255px 15px 225px 15px/15px 225px 15px 255px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.sketch-border:hover {
|
||||
border-color: var(--color-accent);
|
||||
border-radius: 15px 225px 15px 255px/255px 15px 225px 15px;
|
||||
}
|
||||
|
||||
.sketch-border-subtle {
|
||||
border: 1px solid var(--border-main);
|
||||
border-radius: 2px 255px 3px 25px / 255px 5px 225px 3px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.sketch-border-subtle:hover {
|
||||
border-color: var(--color-accent);
|
||||
border-radius: 255px 5px 225px 3px / 2px 255px 3px 25px;
|
||||
}
|
||||
|
||||
.dot-grid {
|
||||
background-image: radial-gradient(var(--grid-pattern) 1px, transparent 1px);
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
28
tsconfig.app.json
Normal file
28
tsconfig.app.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"types": ["vite/client"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
7
tsconfig.json
Normal file
7
tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
26
tsconfig.node.json
Normal file
26
tsconfig.node.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2023",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"types": ["node"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
11
vite.config.ts
Normal file
11
vite.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
tailwindcss(),
|
||||
],
|
||||
})
|
||||
Reference in New Issue
Block a user