create-y3-app
Version:
CLI to add your project structure
566 lines (514 loc) • 17.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.reactRouterStructure = void 0;
const docker_1 = require("../config/docker");
exports.reactRouterStructure = {
src: {
'index.ts': '// Barrel file for exports\n',
'App.tsx': `import { RouterProvider } from 'react-router-dom';
import { router } from './routes';
function App() {
return <RouterProvider router={router} />;
}
export default App;`,
'index.css': `@import "tailwindcss";
@import "tw-animate-css";`,
'main.tsx': `import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
`,
'vite-env.d.ts': '/// <reference types="vite/client" />\n',
assets: {
fonts: {},
icons: {},
images: {},
},
components: {
ui: {
'Button.tsx': `import { cn } from '@/lib/utils';
import { cva, type VariantProps } from 'class-variance-authority';
import { forwardRef } from 'react';
const buttonVariants = cva(
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive:
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline:
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
secondary:
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
},
size: {
default: 'h-9 px-4 py-2',
sm: 'h-8 rounded-md px-3 text-xs',
lg: 'h-10 rounded-md px-8',
icon: 'h-9 w-9',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
}
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
}
);
Button.displayName = 'Button';
export { Button, buttonVariants };`,
},
layouts: {
'RootLayout.tsx': `import { Outlet } from 'react-router-dom';
import { Navbar } from '../navigation/Navbar';
import { Footer } from '../navigation/Footer';
export function RootLayout() {
return (
<div className="flex min-h-screen flex-col">
<Navbar />
<main className="flex-1">
<Outlet />
</main>
<Footer />
</div>
);
}`,
'AuthLayout.tsx': `import { Outlet, Navigate } from 'react-router-dom';
import { useAuth } from '@/hooks/useAuth';
export function AuthLayout() {
const { isAuthenticated } = useAuth();
// Redirect to login if not authenticated
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
}`,
},
navigation: {
'Navbar.tsx': `import { Link } from 'react-router-dom';
import { Button } from '../ui/Button';
import { useAuth } from '@/hooks/useAuth';
export function Navbar() {
const { isAuthenticated, logout } = useAuth();
return (
<header className="border-b">
<div className="container mx-auto flex h-16 items-center justify-between px-4">
<Link to="/" className="text-xl font-bold">
AppName
</Link>
<nav className="flex items-center gap-6">
<Link to="/" className="text-sm font-medium hover:text-primary">
Home
</Link>
<Link to="/about" className="text-sm font-medium hover:text-primary">
About
</Link>
<Link to="/dashboard" className="text-sm font-medium hover:text-primary">
Dashboard
</Link>
{isAuthenticated ? (
<Button onClick={logout} variant="outline">
Logout
</Button>
) : (
<div className="flex items-center gap-2">
<Link to="/login">
<Button variant="outline">Login</Button>
</Link>
<Link to="/register">
<Button>Sign Up</Button>
</Link>
</div>
)}
</nav>
</div>
</header>
);
}`,
'Footer.tsx': `export function Footer() {
return (
<footer className="border-t py-6">
<div className="container mx-auto px-4 text-center text-sm text-muted-foreground">
© {new Date().getFullYear()} Your Company. All rights reserved.
</div>
</footer>
);
}`,
},
},
hooks: {
'useAuth.ts': `import { useState, useEffect, createContext, useContext } from 'react';
interface User {
id: string;
name: string;
email: string;
}
interface AuthContextType {
user: User | null;
isAuthenticated: boolean;
isLoading: boolean;
login: (email: string, password: string) => Promise<void>;
register: (name: string, email: string, password: string) => Promise<void>;
logout: () => void;
}
const AuthContext = createContext<AuthContextType | null>(null);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
// Check for existing session
const checkAuth = async () => {
try {
// Example: fetch user data from API or localStorage
const storedUser = localStorage.getItem('user');
if (storedUser) {
setUser(JSON.parse(storedUser));
}
} catch (error) {
console.error('Authentication error:', error);
} finally {
setIsLoading(false);
}
};
checkAuth();
}, []);
const login = async (email: string, password: string) => {
setIsLoading(true);
try {
// Mock login - replace with actual API call
const mockUser = { id: '1', name: 'Test User', email };
localStorage.setItem('user', JSON.stringify(mockUser));
setUser(mockUser);
} catch (error) {
console.error('Login error:', error);
throw error;
} finally {
setIsLoading(false);
}
};
const register = async (name: string, email: string, password: string) => {
setIsLoading(true);
try {
// Mock registration - replace with actual API call
const mockUser = { id: '1', name, email };
localStorage.setItem('user', JSON.stringify(mockUser));
setUser(mockUser);
} catch (error) {
console.error('Registration error:', error);
throw error;
} finally {
setIsLoading(false);
}
};
const logout = () => {
localStorage.removeItem('user');
setUser(null);
};
return (
<AuthContext.Provider
value={{
user,
isAuthenticated: !!user,
isLoading,
login,
register,
logout,
}}
>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
}`,
'index.ts': '// Barrel file for hooks\nexport * from "./useAuth";\n',
},
lib: {
'utils.ts': `import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export function delay(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}`,
},
pages: {
'HomePage.tsx': `export function HomePage() {
return (
<div className="container mx-auto py-12 px-4">
<h1 className="text-4xl font-bold mb-6">Welcome to the App</h1>
<p className="text-lg text-muted-foreground">
This is a React application with TypeScript and React Router.
</p>
</div>
);
}`,
'AboutPage.tsx': `export function AboutPage() {
return (
<div className="container mx-auto py-12 px-4">
<h1 className="text-4xl font-bold mb-6">About</h1>
<p className="text-lg text-muted-foreground">
Learn more about our application and mission.
</p>
</div>
);
}`,
'DashboardPage.tsx': `import { useAuth } from '@/hooks/useAuth';
export function DashboardPage() {
const { user } = useAuth();
return (
<div className="container mx-auto py-12 px-4">
<h1 className="text-4xl font-bold mb-6">Dashboard</h1>
<p className="text-lg mb-4">Welcome back, {user?.name}!</p>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{/* Dashboard widgets would go here */}
<div className="rounded-lg border p-6">
<h2 className="text-xl font-semibold mb-2">Analytics</h2>
<p>Your analytics data goes here.</p>
</div>
<div className="rounded-lg border p-6">
<h2 className="text-xl font-semibold mb-2">Recent Activity</h2>
<p>Your recent activity goes here.</p>
</div>
<div className="rounded-lg border p-6">
<h2 className="text-xl font-semibold mb-2">Tasks</h2>
<p>Your upcoming tasks go here.</p>
</div>
</div>
</div>
);
}`,
auth: {
'LoginPage.tsx': `import { useState } from 'react';
import { useNavigate, Link } from 'react-router-dom';
import { useAuth } from '@/hooks/useAuth';
import { Button } from '@/components/ui/Button';
export function LoginPage() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const { login, isLoading } = useAuth();
const navigate = useNavigate();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
try {
await login(email, password);
navigate('/dashboard');
} catch (err) {
setError('Invalid email or password');
}
};
return (
<div className="flex min-h-[calc(100vh-4rem)] items-center justify-center p-4">
<div className="w-full max-w-md rounded-lg border p-8">
<h1 className="text-2xl font-bold text-center mb-6">Login</h1>
{error && (
<div className="bg-destructive/10 text-destructive rounded-md p-3 mb-4">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="email" className="block text-sm font-medium mb-1">
Email
</label>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full rounded-md border p-2 text-sm"
required
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium mb-1">
Password
</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full rounded-md border p-2 text-sm"
required
/>
</div>
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? 'Logging in...' : 'Login'}
</Button>
</form>
<p className="text-center mt-4 text-sm">
Don't have an account?{' '}
<Link to="/register" className="text-primary hover:underline">
Sign up
</Link>
</p>
</div>
</div>
);
}`,
'RegisterPage.tsx': `import { useState } from 'react';
import { useNavigate, Link } from 'react-router-dom';
import { useAuth } from '@/hooks/useAuth';
import { Button } from '@/components/ui/Button';
export function RegisterPage() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const { register, isLoading } = useAuth();
const navigate = useNavigate();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
try {
await register(name, email, password);
navigate('/dashboard');
} catch (err) {
setError('Registration failed');
}
};
return (
<div className="flex min-h-[calc(100vh-4rem)] items-center justify-center p-4">
<div className="w-full max-w-md rounded-lg border p-8">
<h1 className="text-2xl font-bold text-center mb-6">Create an Account</h1>
{error && (
<div className="bg-destructive/10 text-destructive rounded-md p-3 mb-4">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="name" className="block text-sm font-medium mb-1">
Name
</label>
<input
id="name"
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="w-full rounded-md border p-2 text-sm"
required
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium mb-1">
Email
</label>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full rounded-md border p-2 text-sm"
required
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium mb-1">
Password
</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full rounded-md border p-2 text-sm"
required
/>
</div>
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? 'Creating account...' : 'Sign Up'}
</Button>
</form>
<p className="text-center mt-4 text-sm">
Already have an account?{' '}
<Link to="/login" className="text-primary hover:underline">
Login
</Link>
</p>
</div>
</div>
);
}`,
},
'NotFoundPage.tsx': `import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/Button';
export function NotFoundPage() {
return (
<div className="flex min-h-[calc(100vh-8rem)] flex-col items-center justify-center p-4 text-center">
<h1 className="text-6xl font-bold mb-4">404</h1>
<p className="text-xl mb-8">Page not found</p>
<Link to="/">
<Button>Go Home</Button>
</Link>
</div>
);
}`,
},
routes: {
'index.ts': `import { createBrowserRouter } from 'react-router-dom';
import { RootLayout } from '@/components/layouts/RootLayout';
import { AuthLayout } from '@/components/layouts/AuthLayout';
import { HomePage } from '@/pages/HomePage';
import { AboutPage } from '@/pages/AboutPage';
import { DashboardPage } from '@/pages/DashboardPage';
import { LoginPage } from '@/pages/auth/LoginPage';
import { RegisterPage } from '@/pages/auth/RegisterPage';
import { NotFoundPage } from '@/pages/NotFoundPage';
export const router = createBrowserRouter([
{
path: '/',
element: <RootLayout />,
children: [
{ index: true, element: <HomePage /> },
{ path: 'about', element: <AboutPage /> },
{
path: '/',
element: <AuthLayout />,
children: [
{ path: 'dashboard', element: <DashboardPage /> },
],
},
{ path: 'login', element: <LoginPage /> },
{ path: 'register', element: <RegisterPage /> },
{ path: '*', element: <NotFoundPage /> },
],
},
]);`,
},
context: {
'AuthContext.tsx': `// This content has been moved to hooks/useAuth.ts`,
},
},
...docker_1.dockerStructure,
};