feat: added pages, forms, and functionality.
All checks were successful
Smart Deploy / build-deploy (push) Successful in 2m38s

This commit is contained in:
2026-02-08 21:11:57 +05:30
parent 3fb4c5bbe0
commit 1c6627bdfb
41 changed files with 6696 additions and 19 deletions

24
ui_mockup/.gitignore vendored Normal file
View 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?

30
ui_mockup/.prettierignore Normal file
View File

@@ -0,0 +1,30 @@
# Build outputs
dist/
build/
out/
# Dependencies
node_modules/
# Logs
*.log
# Cache
.eslintcache
.cache/
# Coverage
coverage/
# Misc
.DS_Store
.env*
!.env.example
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# TypeScript
*.tsbuildinfo

10
ui_mockup/.prettierrc Normal file
View File

@@ -0,0 +1,10 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "lf"
}

21
ui_mockup/components.json Normal file
View File

@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/index.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,26 @@
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';
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
'@typescript-eslint/no-unused-vars': 'off',
},
}
);

12
ui_mockup/index.html Normal file
View File

@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Move Compete Play Landing</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

65
ui_mockup/package.json Normal file
View File

@@ -0,0 +1,65 @@
{
"name": "component-forge",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
"format": "prettier --write .",
"format:check": "prettier --check ."
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@headless-tree/core": "^1.4.0",
"@headless-tree/react": "^1.4.0",
"@hookform/resolvers": "^5.2.1",
"@react-three/drei": "^10.0.6",
"@react-three/fiber": "^9.1.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.1.0",
"embla-carousel-react": "^8.6.0",
"framer-motion": "^12.4.10",
"input-otp": "^1.4.2",
"lucide-react": "^0.542.0",
"next-themes": "^0.4.6",
"radix-ui": "^1.4.3",
"react": "^19.0.0",
"react-day-picker": "^9.9.0",
"react-dom": "^19.0.0",
"react-hook-form": "^7.62.0",
"react-resizable-panels": "^3.0.5",
"recharts": "2.15.4",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"three": "^0.175.0",
"uuid": "^11.1.0",
"vaul": "^1.1.2",
"zod": "^4.1.5"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
"@tailwindcss/vite": "^4.0.9",
"@types/node": "^22.13.9",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.21.0",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^15.15.0",
"prettier": "3.5.3",
"tailwindcss": "^4.0.9",
"tw-animate-css": "^1.3.7",
"typescript": "~5.7.2",
"typescript-eslint": "^8.24.1",
"vite": "^6.2.0"
}
}

36
ui_mockup/src/App.tsx Normal file
View File

@@ -0,0 +1,36 @@
import { useMemo } from 'react';
import { Container, Theme } from './settings/types';
import { LandingPage } from './components/generated/LandingPage';
let theme: Theme = 'dark';
// only use 'centered' container for standalone components, never for full page apps or websites.
let container: Container = 'none';
function App() {
function setTheme(theme: Theme) {
if (theme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
setTheme(theme);
const generatedComponent = useMemo(() => {
// THIS IS WHERE THE TOP LEVEL GENRATED COMPONENT WILL BE RETURNED!
return <LandingPage />; // %EXPORT_STATEMENT%
}, []);
if (container === 'centered') {
return (
<div className="h-full w-full flex flex-col items-center justify-center">
{generatedComponent}
</div>
);
} else {
return generatedComponent;
}
}
export default App;

View File

@@ -0,0 +1,463 @@
import React, { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { ChevronRight, Tv, Network, Handshake, Users, Code2, Zap, ArrowRight, Terminal, Cpu, Layers, Globe, Rocket, Twitter, Github, Linkedin } from 'lucide-react';
// --- Constants & Types ---
const TECH_STACK = ["MCP", "Supabase", "Gemini", "Claude", "UCP", "Agent-to-Agent", "OpenAI", "LangChain", "VectorDB", "LlamaIndex", "Pinecone"];
const PROFILES = [{
name: "Alex Chen",
role: "Computer Science Student",
story: "From anxious undergrad to shipping an MCP-based task automation agent.",
badge: "Automation Pro",
image: "https://images.unsplash.com/photo-1539571696357-5a69c17a67c6?w=400&h=400&fit=crop"
}, {
name: "Sarah Jenkins",
role: "IT Specialist",
story: "Future-proofed my career by building a private UCP gateway for my company.",
badge: "Infrastructure Lead",
image: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=400&fit=crop"
}, {
name: "Marcus Vane",
role: "SaaS Founder",
story: "Pivoted from legacy software to an AI-first startup using A2A protocols.",
badge: "Serial Founder",
image: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=400&h=400&fit=crop"
}] as any[];
// --- Sub-components (Internal) ---
const GlassCard = ({
icon: Icon,
title,
text,
delay = 0
}: {
icon: any;
title: string;
text: string;
delay?: number;
}) => <motion.div initial={{
opacity: 0,
y: 20
}} whileInView={{
opacity: 1,
y: 0
}} viewport={{
once: true
}} transition={{
duration: 0.6,
delay
}} className="relative group p-8 rounded-2xl border border-white/10 bg-white/5 backdrop-blur-xl hover:bg-white/10 transition-all duration-300">
<div className="mb-6 w-12 h-12 flex items-center justify-center rounded-lg bg-indigo-500/20 text-indigo-400 group-hover:scale-110 transition-transform duration-300">
<Icon size={24} />
</div>
<h3 className="text-xl font-bold mb-3 text-white font-['Space_Grotesk']">{title}</h3>
<p className="text-slate-400 leading-relaxed font-['Inter']">{text}</p>
<div className="absolute inset-0 border-2 border-transparent group-hover:border-indigo-500/30 rounded-2xl transition-all duration-300 pointer-events-none" />
</motion.div>;
const CodeWindow = () => {
const [lines, setLines] = useState([{
text: "const agent = new BuilderAgent({",
color: "text-indigo-400"
}, {
text: " protocol: 'MCP',",
color: "text-amber-400"
}, {
text: " squad: 'Alpha-Team',",
color: "text-amber-400"
}, {
text: " mission: 'Future-Proof',",
color: "text-amber-400"
}, {
text: "});",
color: "text-indigo-400"
}, {
text: "",
color: ""
}, {
text: "await agent.startBuilding();",
color: "text-emerald-400"
}]);
return <div className="bg-[#0f172a] rounded-xl border border-slate-700 overflow-hidden shadow-2xl h-full flex flex-col font-mono text-sm">
<div className="flex items-center gap-2 px-4 py-3 bg-slate-800/50 border-b border-slate-700">
<div className="flex gap-1.5">
<div className="w-3 h-3 rounded-full bg-red-500/50" />
<div className="w-3 h-3 rounded-full bg-amber-500/50" />
<div className="w-3 h-3 rounded-full bg-emerald-500/50" />
</div>
<div className="ml-4 text-slate-500 text-xs tracking-wider">BUILDER_SQUAD_01.ts</div>
</div>
<div className="p-6 flex-1 relative">
<div className="space-y-2">
{lines.map((line, i) => <motion.div key={i} initial={{
opacity: 0,
x: -10
}} animate={{
opacity: 1,
x: 0
}} transition={{
delay: i * 0.1
}} className="flex gap-4">
<span className="text-slate-600 w-4 text-right select-none">{i + 1}</span>
<span className={line.color}>{line.text}</span>
</motion.div>)}
</div>
{/* Animated Cursors */}
<motion.div animate={{
x: [0, 40, -20, 0],
y: [0, 60, 20, 0]
}} transition={{
duration: 8,
repeat: Infinity,
ease: "easeInOut"
}} className="absolute top-20 left-40">
<div className="relative group">
<div className="w-1 h-5 bg-amber-400" />
<div className="absolute left-1 top-0 bg-amber-400 text-[#1E293B] text-[10px] px-1.5 py-0.5 rounded-sm whitespace-nowrap font-bold">Priya_Dev</div>
</div>
</motion.div>
<motion.div animate={{
x: [0, -30, 40, 0],
y: [0, -20, 80, 0]
}} transition={{
duration: 12,
repeat: Infinity,
ease: "easeInOut",
delay: 1
}} className="absolute top-10 left-60">
<div className="relative group">
<div className="w-1 h-5 bg-indigo-400" />
<div className="absolute left-1 top-0 bg-indigo-400 text-white text-[10px] px-1.5 py-0.5 rounded-sm whitespace-nowrap font-bold">Arjun_AI</div>
</div>
</motion.div>
</div>
</div>;
};
const ProfileCard = ({
profile
}: {
profile: typeof PROFILES[0];
}) => <motion.div whileHover={{
y: -5
}} className="bg-slate-800/40 border border-slate-700/50 p-6 rounded-2xl flex flex-col items-center text-center group">
<div className="relative mb-6">
<div className="w-24 h-24 rounded-full overflow-hidden border-2 border-indigo-500/30 group-hover:border-indigo-400 transition-colors">
<img src={profile.image} alt={profile.name} className="w-full h-full object-cover" />
</div>
<div className="absolute -bottom-2 -right-2 bg-amber-500 text-[#1E293B] text-[10px] font-bold px-2 py-1 rounded-full uppercase tracking-tighter shadow-lg" style={{
fontSize: "9px"
}}>Portfolio Builder</div>
</div>
<h4 className="text-white font-bold text-lg mb-1">The Student</h4>
<p className="text-indigo-400 text-sm font-mono mb-4">Future-Proofing the Degree</p>
<p className="text-slate-400 text-sm italic">"Universities teach theory; the market demands shipping. Stop worrying about your GPA and start building an Agent portfolio that makes recruiters ignore your grades."</p>
</motion.div>;
// @component: LandingPage
export const LandingPage = () => {
const [isScrolled, setIsScrolled] = useState(false);
useEffect(() => {
const handleScroll = () => setIsScrolled(window.scrollY > 50);
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
// @return
return <div className="min-h-screen bg-[#1E293B] text-slate-100 selection:bg-amber-500/30 font-['Inter'] selection:text-amber-200">
{/* Navbar */}
<nav className={`fixed top-0 w-full z-50 transition-all duration-300 ${isScrolled ? 'bg-[#1E293B]/80 backdrop-blur-md py-4 shadow-xl' : 'bg-transparent py-6'}`}>
<div className="container mx-auto px-6 flex items-center justify-between">
<div className="flex items-center gap-2">
<div className="w-8 h-8 bg-amber-500 rounded-lg flex items-center justify-center transform rotate-12">
<Code2 size={18} className="text-[#1E293B]" />
</div>
<span className="text-xl font-bold font-['Space_Grotesk'] tracking-tight">
Move. <span className="text-indigo-400">Compete.</span> Play.
</span>
</div>
<div className="hidden md:flex items-center gap-10">
{['The Mission', 'Build Projects', 'Squads', 'Manifesto'].map(link => <a key={link} href={`#${link.toLowerCase().replace(' ', '-')}`} className="text-sm font-medium text-slate-300 hover:text-amber-400 transition-colors">
{link}
</a>)}
</div>
<button className="bg-amber-500 hover:bg-amber-400 text-[#1E293B] font-bold px-6 py-2.5 rounded-full transition-all hover:scale-105 active:scale-95 shadow-lg shadow-amber-500/20">
Join the Builders
</button>
</div>
</nav>
{/* Hero Section */}
<section className="relative pt-32 pb-20 overflow-hidden">
{/* Background Grid Pattern */}
<div className="absolute inset-0 z-0 opacity-10 pointer-events-none" style={{
backgroundImage: 'radial-gradient(#6366F1 0.5px, transparent 0.5px)',
backgroundSize: '24px 24px'
}} />
<div className="absolute top-0 right-0 w-[500px] h-[500px] bg-indigo-500/10 blur-[120px] rounded-full -z-10" />
<div className="absolute bottom-0 left-0 w-[500px] h-[500px] bg-amber-500/5 blur-[120px] rounded-full -z-10" />
<div className="container mx-auto px-6 relative z-10">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
<motion.div initial={{
opacity: 0,
x: -50
}} animate={{
opacity: 1,
x: 0
}} transition={{
duration: 0.8
}}>
<div className="inline-flex items-center gap-2 bg-indigo-500/10 border border-indigo-500/20 px-3 py-1 rounded-full text-indigo-400 text-xs font-bold mb-6 tracking-wide uppercase">
<Zap size={14} /> Future-Proof Your Career
</div>
<h1 className="text-4xl md:text-6xl lg:text-7xl font-bold font-['Space_Grotesk'] leading-[1.1] mb-8">
Don't Fear the AI. <br />
<span className="text-transparent bg-clip-text bg-gradient-to-r from-amber-400 to-amber-600">Build with AI.</span>
</h1>
<p className="text-xl text-slate-400 mb-10 leading-relaxed max-w-xl">
The safe harbor for developers, students, and founders to stop watching tutorials and start shipping. Master MCP, UCP, and Agents by building real products together.
</p>
<div className="flex flex-col sm:flex-row gap-4">
<button className="w-full sm:w-auto bg-amber-500 hover:bg-amber-400 text-[#1E293B] font-bold px-8 py-4 rounded-xl transition-all flex items-center justify-center gap-2 group">Join the Community</button>
<button className="w-full sm:w-auto border border-slate-700 hover:border-slate-500 bg-white/5 px-8 py-4 rounded-xl font-bold transition-all text-white flex items-center justify-center gap-2">
Read Manifesto
</button>
</div>
<div className="mt-12 flex items-center gap-6">
<div className="flex -space-x-3">
{[1, 2, 3, 4].map(i => <div key={i} className="w-10 h-10 rounded-full border-2 border-[#1E293B] bg-slate-700 flex items-center justify-center overflow-hidden">
<img src={`https://api.dicebear.com/7.x/avataaars/svg?seed=${i + 123}`} alt="avatar" />
</div>)}
<div className="w-10 h-10 rounded-full border-2 border-[#1E293B] bg-indigo-600 flex items-center justify-center text-[10px] font-bold">+</div>
</div>
<p className="text-sm text-slate-500" style={{
fontWeight: "400",
fontStyle: "normal",
color: "#90a1b9"
}}>
Join the Founding Class of 2026
<button onClick={() => {
const buildSection = document.getElementById('build-season');
buildSection?.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}} className="ml-2 inline-flex items-center gap-1 px-3 py-1 rounded-full bg-amber-500/10 border border-amber-500/20 text-amber-500 text-xs font-bold hover:bg-amber-500/20 transition-all">
Learn More <ChevronRight size={14} />
</button>
</p>
</div>
</motion.div>
<motion.div initial={{
opacity: 0,
scale: 0.9
}} animate={{
opacity: 1,
scale: 1
}} transition={{
duration: 0.8,
delay: 0.2
}} className="relative mt-12 lg:mt-0">
<div className="relative z-10">
<CodeWindow />
</div>
{/* Decorative elements */}
<div className="absolute -top-12 -right-8 w-64 h-64 bg-indigo-500/20 rounded-full blur-[80px] -z-10" />
<div className="absolute -bottom-8 -left-12 w-48 h-48 bg-amber-500/10 rounded-full blur-[60px] -z-10" />
{/* Floating Badge */}
<motion.div animate={{
y: [0, -10, 0]
}} transition={{
duration: 4,
repeat: Infinity,
ease: "easeInOut"
}} className="absolute -bottom-6 right-10 z-20 bg-slate-800 border border-slate-700 p-4 rounded-xl shadow-2xl flex items-center gap-3">
<div className="p-2 bg-amber-500/10 text-amber-500 rounded-lg">
<Terminal size={20} />
</div>
<div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">Active Stack</div>
<div className="text-sm font-bold text-white">Gemini 3 Pro + MCP</div>
</div>
</motion.div>
</motion.div>
</div>
</div>
</section>
{/* Feature Grid */}
<section className="py-24 bg-slate-900/50">
<div className="container mx-auto px-6">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold font-['Space_Grotesk'] mb-4">A Gym for Builders, Not a Classroom</h2>
<p className="text-slate-400 max-w-2xl mx-auto">Skip the generic videos. Join a community where the curriculum is "Building things that matter."</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
<GlassCard icon={Tv} title="No More Tutorials" text="Stop gathering 'knowledge' and start building skill. Tutorials make you feel smart while your skills stagnate. We ship from Day 1." delay={0.1} />
<GlassCard icon={Network} title="Protocol First" text="Master the plumbing of the future. Deep dive into Model Context Protocol (MCP), Universal Commerce Protocol (UCP), and Agentic frameworks." delay={0.2} />
<GlassCard icon={Handshake} title="Squad Mode" text="Never build alone. Match with creators who share your stack. Weekly sprints, peer reviews, and collaborative repos." delay={0.3} />
</div>
</div>
</section>
{/* Tech Marquee */}
<section className="py-12 border-y border-white/5 bg-[#1E293B]">
<div className="flex overflow-hidden group">
<div className="flex animate-scroll hover:[animation-play-state:paused] whitespace-nowrap">
{[...TECH_STACK, ...TECH_STACK].map((tech, i) => <div key={i} className="mx-8 px-6 py-2 rounded-full border border-slate-800 bg-slate-800/30 text-slate-400 font-mono text-sm flex items-center gap-2 hover:border-indigo-500/50 hover:text-indigo-400 transition-all cursor-default">
<div className="w-1.5 h-1.5 rounded-full bg-indigo-500/50" />
{tech}
</div>)}
</div>
</div>
</section>
{/* Community Spotlight */}
<section className="py-24">
<div className="container mx-auto px-6">
<div className="flex flex-col md:flex-row justify-between items-end mb-16 gap-6">
<div className="max-w-xl">
<h2 className="text-4xl font-bold font-['Space_Grotesk'] mb-4">From Anxiety to Action</h2>
<p className="text-slate-400">The Gym is open for everyone. Whether you are starting out or leveling up, you have a squad waiting for you.</p>
</div>
<button className="text-amber-500 font-bold flex items-center gap-2 hover:text-amber-400 transition-colors">
See all alumni <ArrowRight size={18} />
</button>
</div>
<div className="grid md:grid-cols-3 gap-8">
{PROFILES.map((profile, i) => <ProfileCard key={i} profile={profile} />)}
</div>
<div id="build-season" className="mt-20 p-12 rounded-[2rem] bg-gradient-to-br from-indigo-600/20 to-amber-600/10 border border-white/10 relative overflow-hidden">
<div className="relative z-10 flex flex-col md:flex-row items-center gap-10">
<div className="flex-1">
<h3 className="text-3xl font-bold font-['Space_Grotesk'] mb-4">Build Season #01 is approaching. 📣</h3>
<p className="text-slate-300 text-lg mb-8 max-w-lg">Don't build alone. Join a Squad of 4-5 builders to ship your first MCP Agent in 6 weeks. Whether you are a student looking for a portfolio piece or a pro updating your skillsyour Squad keeps you shipping.</p>
<div className="flex flex-wrap gap-4">
<button className="bg-white text-[#1E293B] font-bold px-8 py-4 rounded-xl hover:bg-slate-200 transition-all">Apply for Season #01</button>
<div className="flex items-center gap-4 px-6 text-sm text-slate-400 border-l border-white/10">
<div className="flex flex-col">
<span className="font-bold text-white uppercase tracking-widest text-[10px]">START DATE</span>
<span>TBD</span>
</div>
</div>
</div>
</div>
<div className="hidden lg:grid grid-cols-2 gap-4 flex-shrink-0">
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-amber-500">Build an MCP Server</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">CURRENT MISSION</div>
</div>
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-indigo-400">4-6 Builders</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">SQUAD SIZE</div>
</div>
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-emerald-400">6 Weeks</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">DURATION</div>
</div>
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-purple-400">Free</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">COST</div>
</div>
</div>
</div>
{/* Background elements for this section */}
<div className="absolute top-0 right-0 w-full h-full bg-[radial-gradient(circle_at_top_right,rgba(99,102,241,0.1),transparent)] pointer-events-none" />
</div>
</div>
</section>
{/* Footer */}
<footer className="py-20 border-t border-white/5 bg-slate-950">
<div className="container mx-auto px-6">
<div className="grid md:grid-cols-4 gap-12 mb-16">
<div className="col-span-1 md:col-span-2">
<div className="flex items-center gap-2 mb-6">
<div className="w-8 h-8 bg-amber-500 rounded-lg flex items-center justify-center transform rotate-12">
<Code2 size={18} className="text-[#1E293B]" />
</div>
<span className="text-xl font-bold font-['Space_Grotesk'] tracking-tight">
Move. <span className="text-indigo-400">Compete.</span> Play.
</span>
</div>
<p className="text-slate-500 max-w-sm mb-6 leading-relaxed">
The premier hub for tech professionals to transition from AI-anxiety to AI-mastery through building and community.
</p>
<div className="flex gap-4">
<a href="#" className="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all">
<span className="sr-only">Discord</span>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M9.5 7.5c-.828 0-1.5.671-1.5 1.5 0 .828.672 1.5 1.5 1.5s1.5-.672 1.5-1.5c0-.829-.672-1.5-1.5-1.5zm5 0c-.828 0-1.5.671-1.5 1.5 0 .828.672 1.5 1.5 1.5s1.5-.672 1.5-1.5c0-.829-.672-1.5-1.5-1.5z" />
<path d="M18.7 4.1c-1.26-.42-2.61-.73-4-.91-.18.31-.35.63-.49.97-1.5-.23-3-.23-4.5 0-.14-.34-.31-.66-.49-.97-1.39.18-2.74.49-4 .91-2.59 3.89-3.29 7.69-2.94 11.44 1.69 1.25 3.33 2.01 4.95 2.51.4-.54.75-1.12 1.05-1.72-.58-.22-1.13-.48-1.66-.78.14-.1.27-.21.4-.32 3.21 1.49 6.76 1.49 9.96 0 .13.11.26.22.4.32-.53.3-1.08.56-1.66.78.3.6.65 1.18 1.05 1.72 1.62-.5 3.26-1.26 4.95-2.51.39-4.2-.65-7.84-2.94-11.44z" />
</svg>
</a>
<a href="#" className="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all">
<span className="sr-only">GitHub</span>
<Github size={18} />
</a>
<a href="#" className="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all">
<span className="sr-only">Twitter</span>
<Twitter size={18} />
</a>
<a href="#" className="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all">
<span className="sr-only">LinkedIn</span>
<Linkedin size={18} />
</a>
</div>
</div>
<div>
<h5 className="text-white font-bold mb-6 font-['Space_Grotesk']">Resource</h5>
<ul className="space-y-4 text-sm text-slate-500">
<li><a href="#" className="hover:text-amber-400 transition-colors">The Manifesto</a></li>
<li><a href="#" className="hover:text-amber-400 transition-colors">Build Kits</a></li>
<li><a href="#" className="hover:text-amber-400 transition-colors">Squad Directory</a></li>
<li><a href="#" className="hover:text-amber-400 transition-colors">Alumni Network</a></li>
</ul>
</div>
<div>
<h5 className="text-white font-bold mb-6 font-['Space_Grotesk']">Protocols</h5>
<ul className="space-y-4 text-sm text-slate-500 font-mono">
<li><a href="#" className="hover:text-indigo-400 transition-colors">MCP Spec</a></li>
<li><a href="#" className="hover:text-indigo-400 transition-colors">UCP Handshake</a></li>
<li><a href="#" className="hover:text-indigo-400 transition-colors">Agent SDK</a></li>
<li><a href="#" className="hover:text-indigo-400 transition-colors">A2A Messaging</a></li>
</ul>
</div>
</div>
<div className="flex flex-col md:flex-row justify-between items-center gap-6 pt-10 border-t border-white/5">
<p className="text-sm text-slate-600 font-['Space_Grotesk'] font-bold">© 2023 Move. Compete. Play. The future belongs to the builders. Built with AI</p>
<div className="flex gap-8 text-xs text-slate-600">
<a href="#" className="hover:text-slate-400">Privacy Policy</a>
<a href="#" className="hover:text-slate-400">Terms of Service</a>
<a href="#" className="hover:text-slate-400">Code of Conduct</a>
</div>
</div>
</div>
</footer>
{/* Global Styles for the marquee animation */}
<style>{`
@keyframes scroll {
0% { transform: translateX(0); }
100% { transform: translateX(-50%); }
}
.animate-scroll {
animation: scroll 30s linear infinite;
}
`}</style>
</div>;
};

View File

@@ -0,0 +1,19 @@
import * as React from 'react';
const MOBILE_BREAKPOINT = 768;
export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
};
mql.addEventListener('change', onChange);
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
return () => mql.removeEventListener('change', onChange);
}, []);
return !!isMobile;
}

181
ui_mockup/src/index.css Normal file
View File

@@ -0,0 +1,181 @@
@import url('https://fonts.googleapis.com/css2?family=Inter&family=Arial&family=Helvetica&family=Times+New+Roman&family=Georgia&family=Roboto&display=swap');
@import 'tailwindcss';
@plugin "tailwindcss-animate";
@custom-variant dark (&:is(.dark *));
body {
margin: 0;
padding: 0;
display: flex;
width: 100%;
height: 100%;
min-height: 100vh;
box-sizing: border-box;
overflow: auto;
overscroll-behavior-x: none;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-body: var(--font-body);
--font-heading: var(--font-heading);
--font-mono: var(--font-geist-mono);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
}
:root {
--radius: 0.625rem;
--background: oklch(0.2795 0.0368 260.0299);
--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);
--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);
--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.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 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.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 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(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
font-family: var(--font-body);
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: var(--font-heading);
}
html,
body,
#root {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overscroll-behavior-x: none;
}
}
/* Broken Image Fallback Styles */
img.broken-image-fallback {
position: relative;
display: inline-block;
background: #f9fafb;
border: 1px solid #e5e7eb;
object-fit: none;
object-position: center;
animation: fadeIn 0.3s ease-in-out;
}
.dark img.broken-image-fallback {
background: #1f2937;
border-color: #374151;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

View File

@@ -0,0 +1,29 @@
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
/**
* Ensures light mode is always used by removing the dark class from the document element.
* This can be called from any component that needs to ensure light mode.
*/
export function ensureLightMode() {
if (typeof document !== 'undefined') {
// Always set dark mode to false
document.documentElement.classList.toggle('dark', false);
}
}
/**
* Removes any dark mode classes from a className string
* @param className The class string to process
* @returns The class string with dark mode classes removed
*/
export function removeDarkClasses(className: string): string {
return className
.split(' ')
.filter(cls => !cls.startsWith('dark:'))
.join(' ');
}

45
ui_mockup/src/main.tsx Normal file
View File

@@ -0,0 +1,45 @@
import { StrictMode } from 'react';
// Force light mode by removing dark class and preventing it from being added
document.documentElement.classList.remove('dark');
// Override the system preference detection
const forceLightMode = () => {
// Always set dark mode to false regardless of localStorage or system preference
document.documentElement.classList.toggle('dark', false // Force to false instead of checking localStorage or system preference
);
};
const addBrokenImageHandler = () => {
document.addEventListener('error', function (e) {
if (e.target instanceof HTMLImageElement) {
const img = e.target;
if (!img.dataset.fallbackApplied) {
img.dataset.fallbackApplied = 'true';
// Create a simple fallback SVG icon as data URL
const fallbackSvg = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E`;
img.src = fallbackSvg;
img.classList.add('broken-image-fallback');
if (!img.alt || img.alt.trim() === '') {
img.alt = 'Image not available';
}
}
}
}, true);
};
// Run immediately
forceLightMode();
addBrokenImageHandler();
// Also run when the DOM is loaded to ensure it applies
document.addEventListener('DOMContentLoaded', forceLightMode);
// Override system preference changes
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', forceLightMode);
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App.tsx';
createRoot(document.getElementById('root')!).render(<StrictMode>
<App />
</StrictMode>);

View File

@@ -0,0 +1,19 @@
import { Theme, Container } from './types';
const injectedTheme: string = '%INJECTED_THEME%';
const injectedContainer: string = '%INJECTED_CONTAINER%';
let theme: Theme = 'light';
let container: Container = 'none';
if (injectedTheme === 'light' || injectedTheme === 'dark') {
theme = injectedTheme;
}
if (injectedContainer === 'centered' || injectedContainer === 'none') {
container = injectedContainer;
}
export default {
theme,
container,
};

2
ui_mockup/src/settings/types.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export type Theme = 'light' | 'dark';
export type Container = 'centered' | 'none';

1
ui_mockup/src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@@ -0,0 +1,31 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"noImplicitAny": false,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"]
}

10
ui_mockup/tsconfig.json Normal file
View File

@@ -0,0 +1,10 @@
{
"files": [],
"references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}

View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

14
ui_mockup/vite.config.ts Normal file
View File

@@ -0,0 +1,14 @@
import path from 'path';
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()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
});

3526
ui_mockup/yarn.lock Normal file

File diff suppressed because it is too large Load Diff