diff --git a/php-framework/.gitignore b/php-framework/.gitignore
new file mode 100644
index 0000000..f650315
--- /dev/null
+++ b/php-framework/.gitignore
@@ -0,0 +1,27 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# env files
+.env*
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
\ No newline at end of file
diff --git a/php-framework/app/globals.css b/php-framework/app/globals.css
new file mode 100644
index 0000000..8abdb15
--- /dev/null
+++ b/php-framework/app/globals.css
@@ -0,0 +1,76 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 222.2 84% 4.9%;
+
+ --card: 0 0% 100%;
+ --card-foreground: 222.2 84% 4.9%;
+
+ --popover: 0 0% 100%;
+ --popover-foreground: 222.2 84% 4.9%;
+
+ --primary: 222.2 47.4% 11.2%;
+ --primary-foreground: 210 40% 98%;
+
+ --secondary: 210 40% 96.1%;
+ --secondary-foreground: 222.2 47.4% 11.2%;
+
+ --muted: 210 40% 96.1%;
+ --muted-foreground: 215.4 16.3% 46.9%;
+
+ --accent: 210 40% 96.1%;
+ --accent-foreground: 222.2 47.4% 11.2%;
+
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 210 40% 98%;
+
+ --border: 214.3 31.8% 91.4%;
+ --input: 214.3 31.8% 91.4%;
+ --ring: 222.2 84% 4.9%;
+
+ --radius: 0.5rem;
+ }
+
+ .dark {
+ --background: 222.2 84% 4.9%;
+ --foreground: 210 40% 98%;
+
+ --card: 222.2 84% 4.9%;
+ --card-foreground: 210 40% 98%;
+
+ --popover: 222.2 84% 4.9%;
+ --popover-foreground: 210 40% 98%;
+
+ --primary: 210 40% 98%;
+ --primary-foreground: 222.2 47.4% 11.2%;
+
+ --secondary: 217.2 32.6% 17.5%;
+ --secondary-foreground: 210 40% 98%;
+
+ --muted: 217.2 32.6% 17.5%;
+ --muted-foreground: 215 20.2% 65.1%;
+
+ --accent: 217.2 32.6% 17.5%;
+ --accent-foreground: 210 40% 98%;
+
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 210 40% 98%;
+
+ --border: 217.2 32.6% 17.5%;
+ --input: 217.2 32.6% 17.5%;
+ --ring: 212.7 26.8% 83.9%;
+ }
+}
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
diff --git a/php-framework/app/layout.tsx b/php-framework/app/layout.tsx
new file mode 100644
index 0000000..e5d8ebd
--- /dev/null
+++ b/php-framework/app/layout.tsx
@@ -0,0 +1,25 @@
+import type React from "react"
+import "@/app/globals.css"
+import { ThemeProvider } from "@/components/theme-provider"
+
+export const metadata = {
+ title: "PHP Framework Generator",
+ description: "Generate PHP framework projects with custom configurations",
+ generator: 'v0.dev'
+}
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+
+
+ {children}
+
+
+
+ )
+}
diff --git a/php-framework/app/login/page.tsx b/php-framework/app/login/page.tsx
new file mode 100644
index 0000000..5c2de1f
--- /dev/null
+++ b/php-framework/app/login/page.tsx
@@ -0,0 +1,81 @@
+import { LoginForm } from "@/components/login-form"
+import { ThemeToggle } from "@/components/theme-toggle"
+import { MobileNav } from "@/components/mobile-nav"
+import Link from "next/link"
+
+export default function LoginPage() {
+ const navItems = [
+ { title: "Home", href: "/" },
+ { title: "Documentation", href: "#" },
+ { title: "Guides", href: "#" },
+ ]
+
+ return (
+
+
+
+
+
+
+
PHP Framework Generator
+
+
+
+
+
+
+
+
+
+
+
+
+
Login to Your Account
+
+ Access your PHP Framework Generator account
+
+
+
+
+
+
+
+ )
+}
diff --git a/php-framework/app/page.tsx b/php-framework/app/page.tsx
new file mode 100644
index 0000000..caf9f0c
--- /dev/null
+++ b/php-framework/app/page.tsx
@@ -0,0 +1,98 @@
+import { ProjectForm } from "@/components/project-form"
+import { ProjectInfo } from "@/components/project-info"
+import { ThemeToggle } from "@/components/theme-toggle"
+import { MobileNav } from "@/components/mobile-nav"
+import Link from "next/link"
+
+export default function Home() {
+ const navItems = [
+ { title: "Documentation", href: "#" },
+ { title: "Guides", href: "#" },
+ { title: "GitHub", href: "https://github.com", external: true },
+ { title: "Login", href: "/login" },
+ ]
+
+ return (
+
+
+
+
+
+
+
PHP Framework Generator
+
+
+
+
+
+
+
+
+
+
+
+
+
PHP Framework Project Generator
+
+ Bootstrap your PHP application by selecting framework and configuration options
+
+
+
+
+
+
+
+ )
+}
diff --git a/php-framework/components.json b/php-framework/components.json
new file mode 100644
index 0000000..d9ef0ae
--- /dev/null
+++ b/php-framework/components.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "default",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "tailwind.config.ts",
+ "css": "app/globals.css",
+ "baseColor": "neutral",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "iconLibrary": "lucide"
+}
\ No newline at end of file
diff --git a/php-framework/components/dependency-selector.tsx b/php-framework/components/dependency-selector.tsx
new file mode 100644
index 0000000..025151d
--- /dev/null
+++ b/php-framework/components/dependency-selector.tsx
@@ -0,0 +1,269 @@
+"use client"
+
+import { useState, useEffect } from "react"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { ScrollArea } from "@/components/ui/scroll-area"
+import { X, Search, Plus } from "lucide-react"
+
+interface DependencySelectorProps {
+ framework: string
+ onAddDependency: (dependency: string) => void
+ onRemoveDependency: (dependency: string) => void
+ selectedDependencies: string[]
+}
+
+// Laravel dependencies
+const laravelDependencies = [
+ {
+ id: "database",
+ name: "Database",
+ dependencies: [
+ { id: "laravel/sanctum", name: "Laravel Sanctum", description: "API token authentication" },
+ { id: "laravel/passport", name: "Laravel Passport", description: "OAuth2 server implementation" },
+ { id: "spatie/laravel-permission", name: "Spatie Permissions", description: "Role and permission management" },
+ ],
+ },
+ {
+ id: "ui",
+ name: "UI",
+ dependencies: [
+ { id: "livewire/livewire", name: "Livewire", description: "Full-stack framework for Laravel" },
+ { id: "inertiajs/inertia-laravel", name: "Inertia.js", description: "Modern monolith SPA framework" },
+ { id: "laravel/breeze", name: "Laravel Breeze", description: "Minimal authentication scaffolding" },
+ { id: "laravel/jetstream", name: "Laravel Jetstream", description: "Application scaffolding with teams" },
+ ],
+ },
+ {
+ id: "testing",
+ name: "Testing",
+ dependencies: [
+ { id: "pestphp/pest", name: "Pest", description: "Elegant PHP testing framework" },
+ { id: "mockery/mockery", name: "Mockery", description: "Mock object framework for testing" },
+ { id: "nunomaduro/larastan", name: "Larastan", description: "PHPStan extension for Laravel" },
+ ],
+ },
+]
+
+// Symfony dependencies
+const symfonyDependencies = [
+ {
+ id: "database",
+ name: "Database",
+ dependencies: [
+ { id: "doctrine/doctrine-bundle", name: "Doctrine ORM", description: "Object-relational mapper" },
+ { id: "doctrine/mongodb-odm-bundle", name: "MongoDB ODM", description: "MongoDB integration" },
+ { id: "symfony/orm-pack", name: "ORM Pack", description: "Doctrine ORM pack" },
+ ],
+ },
+ {
+ id: "ui",
+ name: "UI",
+ dependencies: [
+ { id: "symfony/webpack-encore-bundle", name: "Webpack Encore", description: "Asset management" },
+ { id: "symfony/ux-turbo", name: "Turbo", description: "Hotwire's Turbo integration" },
+ { id: "symfony/twig-bundle", name: "Twig Bundle", description: "Twig integration" },
+ ],
+ },
+ {
+ id: "api",
+ name: "API",
+ dependencies: [
+ { id: "api-platform/core", name: "API Platform", description: "REST and GraphQL framework" },
+ { id: "symfony/serializer", name: "Serializer", description: "Serialize/deserialize data" },
+ { id: "lexik/jwt-authentication-bundle", name: "JWT Authentication", description: "JWT auth for Symfony" },
+ ],
+ },
+]
+
+// CodeIgniter dependencies
+const codeigniterDependencies = [
+ {
+ id: "database",
+ name: "Database",
+ dependencies: [
+ { id: "myth/auth", name: "Myth Auth", description: "Authentication & Authorization" },
+ { id: "agungsugiarto/codeigniter4-cors", name: "CORS", description: "CORS middleware" },
+ { id: "tatter/alerts", name: "Alerts", description: "Flash messages" },
+ ],
+ },
+ {
+ id: "ui",
+ name: "UI",
+ dependencies: [
+ { id: "codeigniter4/shield", name: "Shield", description: "Authentication for CodeIgniter 4" },
+ { id: "benedmunds/codeigniter-ion-auth", name: "Ion Auth", description: "Simple auth system" },
+ { id: "lonnieezell/codeigniter-forensics", name: "Forensics", description: "Profiling tools" },
+ ],
+ },
+]
+
+// Combined dependencies map
+const frameworkDependencies: Record = {
+ laravel: laravelDependencies,
+ symfony: symfonyDependencies,
+ codeigniter: codeigniterDependencies,
+ slim: [
+ {
+ id: "core",
+ name: "Core",
+ dependencies: [
+ { id: "slim/twig-view", name: "Twig View", description: "Twig integration for Slim" },
+ { id: "slim/php-view", name: "PHP View", description: "PHP renderer for Slim" },
+ { id: "slim/csrf", name: "CSRF Protection", description: "CSRF guard middleware" },
+ ],
+ },
+ ],
+ lumen: [
+ {
+ id: "core",
+ name: "Core",
+ dependencies: [
+ { id: "flipbox/lumen-generator", name: "Lumen Generator", description: "Artisan commands for Lumen" },
+ { id: "vlucas/phpdotenv", name: "PHP dotenv", description: "Loads environment variables" },
+ { id: "tymon/jwt-auth", name: "JWT Auth", description: "JSON Web Token Authentication" },
+ ],
+ },
+ ],
+}
+
+export function DependencySelector({
+ framework,
+ onAddDependency,
+ onRemoveDependency,
+ selectedDependencies,
+}: DependencySelectorProps) {
+ const [searchQuery, setSearchQuery] = useState("")
+ const [categories, setCategories] = useState([])
+ const [defaultTab, setDefaultTab] = useState("")
+
+ useEffect(() => {
+ const deps = frameworkDependencies[framework] || []
+ setCategories(deps)
+ setDefaultTab(deps.length > 0 ? deps[0].id : "")
+ }, [framework])
+
+ // Filter dependencies based on search query
+ const filteredDependencies =
+ searchQuery.trim() === ""
+ ? []
+ : categories.flatMap((category) =>
+ category.dependencies.filter(
+ (dep) =>
+ dep.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ dep.description.toLowerCase().includes(searchQuery.toLowerCase()),
+ ),
+ )
+
+ return (
+
+
+
+ setSearchQuery(e.target.value)}
+ />
+
+
+ {selectedDependencies.length > 0 && (
+
+
Selected Dependencies:
+
+ {selectedDependencies.map((dep) => (
+
+ {dep}
+
+
+ ))}
+
+
+ )}
+
+ {searchQuery.trim() !== "" ? (
+
+
Search Results:
+
+ {filteredDependencies.length > 0 ? (
+
+ {filteredDependencies.map((dep) => (
+
+
+
{dep.name}
+
{dep.description}
+
+
+
+ ))}
+
+ ) : (
+ No dependencies found
+ )}
+
+
+ ) : categories.length > 0 ? (
+
+
+ {categories.map((category) => (
+
+ {category.name}
+
+ ))}
+
+
+ {categories.map((category) => (
+
+
+
+ {category.dependencies.map((dep) => (
+
+
+
{dep.name}
+
{dep.description}
+
+
+
+ ))}
+
+
+
+ ))}
+
+ ) : (
+
+
No dependencies available for this framework
+
+ )}
+
+ )
+}
diff --git a/php-framework/components/login-form.tsx b/php-framework/components/login-form.tsx
new file mode 100644
index 0000000..1f81403
--- /dev/null
+++ b/php-framework/components/login-form.tsx
@@ -0,0 +1,195 @@
+"use client"
+
+import type React from "react"
+
+import { useState } from "react"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Checkbox } from "@/components/ui/checkbox"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Eye, EyeOff, Lock, Mail, User } from "lucide-react"
+import { Separator } from "@/components/ui/separator"
+
+export function LoginForm() {
+ const [showPassword, setShowPassword] = useState(false)
+ const [email, setEmail] = useState("")
+ const [password, setPassword] = useState("")
+
+ const handleLogin = (e: React.FormEvent) => {
+ e.preventDefault()
+ // In a real application, this would handle authentication
+ console.log("Login attempt with:", { email, password })
+ alert("Login functionality would be implemented in a real application")
+ }
+
+ return (
+
+
+ Login
+ Enter your credentials to access your account
+
+
+
+
+ Email
+ Username
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OR CONTINUE WITH
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/php-framework/components/mobile-nav.tsx b/php-framework/components/mobile-nav.tsx
new file mode 100644
index 0000000..1160b79
--- /dev/null
+++ b/php-framework/components/mobile-nav.tsx
@@ -0,0 +1,97 @@
+"use client"
+
+import { useState } from "react"
+import { Menu, X } from "lucide-react"
+import { Button } from "@/components/ui/button"
+import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"
+import { ThemeToggle } from "@/components/theme-toggle"
+import Link from "next/link"
+
+interface MobileNavProps {
+ items: {
+ title: string
+ href: string
+ external?: boolean
+ }[]
+}
+
+export function MobileNav({ items }: MobileNavProps) {
+ const [open, setOpen] = useState(false)
+
+ return (
+
+
+
+
+
+
+
+
+
PHP Framework Generator
+
+
+
+
+
+ Theme
+
+
+
+
+ )
+}
diff --git a/php-framework/components/project-form.tsx b/php-framework/components/project-form.tsx
new file mode 100644
index 0000000..16cea79
--- /dev/null
+++ b/php-framework/components/project-form.tsx
@@ -0,0 +1,179 @@
+"use client"
+
+import { useState } from "react"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Checkbox } from "@/components/ui/checkbox"
+import { DependencySelector } from "@/components/dependency-selector"
+import { Download, RefreshCw } from "lucide-react"
+
+export function ProjectForm() {
+ const [framework, setFramework] = useState("laravel")
+ const [phpVersion, setPhpVersion] = useState("8.2")
+ const [projectName, setProjectName] = useState("my-app")
+ const [description, setDescription] = useState("My PHP application")
+ const [authorName, setAuthorName] = useState("")
+ const [authorEmail, setAuthorEmail] = useState("")
+ const [dependencies, setDependencies] = useState([])
+
+ const handleAddDependency = (dependency: string) => {
+ if (!dependencies.includes(dependency)) {
+ setDependencies([...dependencies, dependency])
+ }
+ }
+
+ const handleRemoveDependency = (dependency: string) => {
+ setDependencies(dependencies.filter((dep) => dep !== dependency))
+ }
+
+ const handleGenerateProject = () => {
+ // In a real application, this would send the configuration to a backend
+ // For now, we'll just show an alert
+ alert("Project generation would happen here in a real application!")
+ }
+
+ return (
+
+
+ Project
+ Configure your PHP framework project options
+
+
+
+
+ Project
+ Dependencies
+ Advanced
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setProjectName(e.target.value)} />
+
+
+
+ setDescription(e.target.value)} />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {framework === "laravel" && (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+ {framework === "symfony" && (
+
+
+
+
+
+
+ )}
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/php-framework/components/project-info.tsx b/php-framework/components/project-info.tsx
new file mode 100644
index 0000000..6615090
--- /dev/null
+++ b/php-framework/components/project-info.tsx
@@ -0,0 +1,585 @@
+"use client"
+
+import { useState } from "react"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+import { Download, Eye } from "lucide-react"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+
+export function ProjectInfo() {
+ const [activeTab, setActiveTab] = useState("structure")
+ const [framework, setFramework] = useState("laravel")
+
+ // Laravel project structure
+ const laravelStructure = `my-app/
+├── app/
+│ ├── Console/
+│ ├── Exceptions/
+│ ├── Http/
+│ │ ├── Controllers/
+│ │ ├── Middleware/
+│ │ └── Requests/
+│ ├── Models/
+│ └── Providers/
+├── bootstrap/
+├── config/
+├── database/
+│ ├── factories/
+│ ├── migrations/
+│ └── seeders/
+├── public/
+├── resources/
+│ ├── css/
+│ ├── js/
+│ └── views/
+├── routes/
+│ ├── api.php
+│ ├── channels.php
+│ ├── console.php
+│ └── web.php
+├── storage/
+├── tests/
+├── .env
+├── .env.example
+├── .gitignore
+├── artisan
+├── composer.json
+├── package.json
+└── README.md`
+
+ // Symfony project structure
+ const symfonyStructure = `my-app/
+├── bin/
+│ └── console
+├── config/
+│ ├── bundles.php
+│ ├── packages/
+│ ├── routes.yaml
+│ └── services.yaml
+├── migrations/
+├── public/
+│ └── index.php
+├── src/
+│ ├── Controller/
+│ ├── Entity/
+│ ├── Repository/
+│ ├── Service/
+│ └── Kernel.php
+├── templates/
+├── tests/
+├── translations/
+├── var/
+│ ├── cache/
+│ └── log/
+├── vendor/
+├── .env
+├── .env.local
+├── .gitignore
+├── composer.json
+└── symfony.lock`
+
+ // CodeIgniter project structure
+ const codeigniterStructure = `my-app/
+├── app/
+│ ├── Config/
+│ ├── Controllers/
+│ ├── Database/
+│ │ ├── Migrations/
+│ │ └── Seeds/
+│ ├── Filters/
+│ ├── Helpers/
+│ ├── Libraries/
+│ ├── Models/
+│ └── Views/
+├── public/
+│ ├── assets/
+│ └── index.php
+├── system/
+├── tests/
+├── writable/
+│ ├── cache/
+│ ├── logs/
+│ └── session/
+├── .env
+├── .gitignore
+├── composer.json
+├── phpunit.xml.dist
+└── spark`
+
+ // Slim project structure
+ const slimStructure = `my-app/
+├── app/
+│ ├── Controllers/
+│ ├── Middleware/
+│ ├── Models/
+│ └── Views/
+├── config/
+│ ├── container.php
+│ ├── middleware.php
+│ └── routes.php
+├── public/
+│ └── index.php
+├── src/
+├── templates/
+├── tests/
+├── var/
+│ ├── cache/
+│ └── log/
+├── vendor/
+├── .env
+├── .gitignore
+├── composer.json
+└── README.md`
+
+ // Lumen project structure
+ const lumenStructure = `my-app/
+├── app/
+│ ├── Console/
+│ ├── Events/
+│ ├── Exceptions/
+│ ├── Http/
+│ │ ├── Controllers/
+│ │ └── Middleware/
+│ ├── Jobs/
+│ ├── Listeners/
+│ ├── Models/
+│ └── Providers/
+├── bootstrap/
+│ └── app.php
+├── database/
+│ ├── factories/
+│ ├── migrations/
+│ └── seeders/
+├── public/
+│ └── index.php
+├── resources/
+│ └── views/
+├── routes/
+│ └── web.php
+├── storage/
+├── tests/
+├── .env
+├── .env.example
+├── .gitignore
+├── artisan
+├── composer.json
+└── README.md`
+
+ const frameworkStructures = {
+ laravel: laravelStructure,
+ symfony: symfonyStructure,
+ codeigniter: codeigniterStructure,
+ slim: slimStructure,
+ lumen: lumenStructure,
+ }
+
+ // Laravel composer.json
+ const laravelComposerJson = `{
+ "name": "laravel/laravel",
+ "type": "project",
+ "description": "My PHP application",
+ "keywords": ["framework", "laravel"],
+ "license": "MIT",
+ "require": {
+ "php": "^8.2",
+ "laravel/framework": "^10.10",
+ "laravel/sanctum": "^3.2",
+ "laravel/tinker": "^2.8"
+ },
+ "require-dev": {
+ "fakerphp/faker": "^1.9.1",
+ "laravel/pint": "^1.0",
+ "laravel/sail": "^1.18",
+ "mockery/mockery": "^1.4.4",
+ "nunomaduro/collision": "^7.0",
+ "phpunit/phpunit": "^10.1",
+ "spatie/laravel-ignition": "^2.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "App\\\\": "app/",
+ "Database\\\\Factories\\\\": "database/factories/",
+ "Database\\\\Seeders\\\\": "database/seeders/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\\\": "tests/"
+ }
+ },
+ "scripts": {
+ "post-autoload-dump": [
+ "Illuminate\\\\Foundation\\\\ComposerScripts::postAutoloadDump",
+ "@php artisan package:discover --ansi"
+ ],
+ "post-update-cmd": [
+ "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
+ ],
+ "post-root-package-install": [
+ "@php -r \\"file_exists('.env') || copy('.env.example', '.env');\\"
+ ],
+ "post-create-project-cmd": [
+ "@php artisan key:generate --ansi"
+ ]
+ },
+ "extra": {
+ "laravel": {
+ "dont-discover": []
+ }
+ },
+ "config": {
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true,
+ "allow-plugins": {
+ "pestphp/pest-plugin": true,
+ "php-http/discovery": true
+ }
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": true
+}`
+
+ // Symfony composer.json
+ const symfonyComposerJson = `{
+ "name": "symfony/skeleton",
+ "type": "project",
+ "description": "My PHP application",
+ "license": "MIT",
+ "require": {
+ "php": "^8.2",
+ "ext-ctype": "*",
+ "ext-iconv": "*",
+ "symfony/console": "^6.3",
+ "symfony/dotenv": "^6.3",
+ "symfony/flex": "^2",
+ "symfony/framework-bundle": "^6.3",
+ "symfony/runtime": "^6.3",
+ "symfony/yaml": "^6.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5",
+ "symfony/browser-kit": "^6.3",
+ "symfony/css-selector": "^6.3",
+ "symfony/debug-bundle": "^6.3",
+ "symfony/maker-bundle": "^1.0",
+ "symfony/phpunit-bridge": "^6.3",
+ "symfony/stopwatch": "^6.3",
+ "symfony/web-profiler-bundle": "^6.3"
+ },
+ "config": {
+ "allow-plugins": {
+ "php-http/discovery": true,
+ "symfony/flex": true,
+ "symfony/runtime": true
+ },
+ "sort-packages": true
+ },
+ "autoload": {
+ "psr-4": {
+ "App\\\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "App\\\\Tests\\\\": "tests/"
+ }
+ },
+ "scripts": {
+ "auto-scripts": {
+ "cache:clear": "symfony-cmd",
+ "assets:install %PUBLIC_DIR%": "symfony-cmd"
+ },
+ "post-install-cmd": [
+ "@auto-scripts"
+ ],
+ "post-update-cmd": [
+ "@auto-scripts"
+ ]
+ },
+ "conflict": {
+ "symfony/symfony": "*"
+ },
+ "extra": {
+ "symfony": {
+ "allow-contrib": false,
+ "require": "6.3.*"
+ }
+ }
+}`
+
+ // CodeIgniter composer.json
+ const codeigniterComposerJson = `{
+ "name": "codeigniter4/appstarter",
+ "type": "project",
+ "description": "My PHP application",
+ "homepage": "https://codeigniter.com",
+ "license": "MIT",
+ "require": {
+ "php": "^8.0",
+ "codeigniter4/framework": "^4.0"
+ },
+ "require-dev": {
+ "fakerphp/faker": "^1.9",
+ "mikey179/vfsstream": "^1.6",
+ "phpunit/phpunit": "^9.1"
+ },
+ "autoload": {
+ "exclude-from-classmap": [
+ "**/Database/Migrations/**"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\\\Support\\\\": "tests/_support"
+ }
+ },
+ "scripts": {
+ "test": "phpunit"
+ },
+ "support": {
+ "forum": "https://forum.codeigniter.com/",
+ "source": "https://github.com/codeigniter4/CodeIgniter4",
+ "slack": "https://codeigniterchat.slack.com"
+ }
+}`
+
+ const frameworkComposerJson = {
+ laravel: laravelComposerJson,
+ symfony: symfonyComposerJson,
+ codeigniter: codeigniterComposerJson,
+ slim: `{
+ "name": "slim/slim-skeleton",
+ "description": "My PHP application",
+ "license": "MIT",
+ "require": {
+ "php": "^8.0",
+ "slim/slim": "^4.10",
+ "slim/psr7": "^1.5",
+ "php-di/php-di": "^6.4",
+ "monolog/monolog": "^2.8"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5"
+ },
+ "autoload": {
+ "psr-4": {
+ "App\\\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\\\": "tests/"
+ }
+ },
+ "scripts": {
+ "start": "php -S localhost:8080 -t public"
+ }
+}`,
+ lumen: `{
+ "name": "laravel/lumen",
+ "description": "My PHP application",
+ "keywords": ["framework", "laravel", "lumen"],
+ "license": "MIT",
+ "type": "project",
+ "require": {
+ "php": "^8.0",
+ "laravel/lumen-framework": "^9.0"
+ },
+ "require-dev": {
+ "fakerphp/faker": "^1.9.1",
+ "mockery/mockery": "^1.4.4",
+ "phpunit/phpunit": "^9.5.10"
+ },
+ "autoload": {
+ "psr-4": {
+ "App\\\\": "app/",
+ "Database\\\\Factories\\\\": "database/factories/",
+ "Database\\\\Seeders\\\\": "database/seeders/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\\\": "tests/"
+ }
+ },
+ "scripts": {
+ "post-root-package-install": [
+ "@php -r \\"file_exists('.env') || copy('.env.example', '.env');\\"
+ ]
+ },
+ "config": {
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true
+}`,
+ }
+
+ // Laravel main file
+ const laravelMainFile = `render('home/index.html.twig', [
+ 'controller_name' => 'HomeController',
+ ]);
+ }
+}
+`
+
+ // CodeIgniter main file
+ const codeigniterMainFile = `getBody()->write('Hello, World!');
+ return $response;
+ }
+}
+`,
+ lumen: `
+
+ Project Preview
+ Preview your project structure and files
+
+
+
+
+
+
+
+ Structure
+ Files
+
+
+
+
+ {frameworkStructures[framework as keyof typeof frameworkStructures]}
+
+
+
+
+
+
+
composer.json
+
+
+ {frameworkComposerJson[framework as keyof typeof frameworkComposerJson]}
+
+
+
+
+
+ {framework === "laravel" && "app/Http/Controllers/HomeController.php"}
+ {framework === "symfony" && "src/Controller/HomeController.php"}
+ {framework === "codeigniter" && "app/Controllers/Home.php"}
+ {framework === "slim" && "src/Controller/HomeController.php"}
+ {framework === "lumen" && "app/Http/Controllers/HomeController.php"}
+
+
+
{frameworkMainFile[framework as keyof typeof frameworkMainFile]}
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/php-framework/components/theme-provider.tsx b/php-framework/components/theme-provider.tsx
new file mode 100644
index 0000000..1cd216d
--- /dev/null
+++ b/php-framework/components/theme-provider.tsx
@@ -0,0 +1,7 @@
+"use client"
+import { ThemeProvider as NextThemesProvider } from "next-themes"
+import type { ThemeProviderProps } from "next-themes"
+
+export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
+ return {children}
+}
diff --git a/php-framework/components/theme-toggle.tsx b/php-framework/components/theme-toggle.tsx
new file mode 100644
index 0000000..e655555
--- /dev/null
+++ b/php-framework/components/theme-toggle.tsx
@@ -0,0 +1,43 @@
+"use client"
+
+import { useEffect, useState } from "react"
+import { Moon, Sun } from "lucide-react"
+import { useTheme } from "next-themes"
+
+import { Button } from "@/components/ui/button"
+import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
+
+export function ThemeToggle() {
+ const { theme, setTheme } = useTheme()
+ const [mounted, setMounted] = useState(false)
+
+ // Ensure component is mounted to avoid hydration mismatch
+ useEffect(() => {
+ setMounted(true)
+ }, [])
+
+ if (!mounted) {
+ return (
+
+ )
+ }
+
+ return (
+
+
+
+
+
+ setTheme("light")}>Light
+ setTheme("dark")}>Dark
+ setTheme("system")}>System
+
+
+ )
+}
diff --git a/php-framework/components/ui/accordion.tsx b/php-framework/components/ui/accordion.tsx
new file mode 100644
index 0000000..24c788c
--- /dev/null
+++ b/php-framework/components/ui/accordion.tsx
@@ -0,0 +1,58 @@
+"use client"
+
+import * as React from "react"
+import * as AccordionPrimitive from "@radix-ui/react-accordion"
+import { ChevronDown } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+const Accordion = AccordionPrimitive.Root
+
+const AccordionItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AccordionItem.displayName = "AccordionItem"
+
+const AccordionTrigger = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+ svg]:rotate-180",
+ className
+ )}
+ {...props}
+ >
+ {children}
+
+
+
+))
+AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
+
+const AccordionContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+ {children}
+
+))
+
+AccordionContent.displayName = AccordionPrimitive.Content.displayName
+
+export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
diff --git a/php-framework/components/ui/alert-dialog.tsx b/php-framework/components/ui/alert-dialog.tsx
new file mode 100644
index 0000000..25e7b47
--- /dev/null
+++ b/php-framework/components/ui/alert-dialog.tsx
@@ -0,0 +1,141 @@
+"use client"
+
+import * as React from "react"
+import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
+
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "@/components/ui/button"
+
+const AlertDialog = AlertDialogPrimitive.Root
+
+const AlertDialogTrigger = AlertDialogPrimitive.Trigger
+
+const AlertDialogPortal = AlertDialogPrimitive.Portal
+
+const AlertDialogOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
+
+const AlertDialogContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+))
+AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
+
+const AlertDialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+AlertDialogHeader.displayName = "AlertDialogHeader"
+
+const AlertDialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+AlertDialogFooter.displayName = "AlertDialogFooter"
+
+const AlertDialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
+
+const AlertDialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogDescription.displayName =
+ AlertDialogPrimitive.Description.displayName
+
+const AlertDialogAction = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
+
+const AlertDialogCancel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
+
+export {
+ AlertDialog,
+ AlertDialogPortal,
+ AlertDialogOverlay,
+ AlertDialogTrigger,
+ AlertDialogContent,
+ AlertDialogHeader,
+ AlertDialogFooter,
+ AlertDialogTitle,
+ AlertDialogDescription,
+ AlertDialogAction,
+ AlertDialogCancel,
+}
diff --git a/php-framework/components/ui/alert.tsx b/php-framework/components/ui/alert.tsx
new file mode 100644
index 0000000..41fa7e0
--- /dev/null
+++ b/php-framework/components/ui/alert.tsx
@@ -0,0 +1,59 @@
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const alertVariants = cva(
+ "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
+ {
+ variants: {
+ variant: {
+ default: "bg-background text-foreground",
+ destructive:
+ "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+const Alert = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes & VariantProps
+>(({ className, variant, ...props }, ref) => (
+
+))
+Alert.displayName = "Alert"
+
+const AlertTitle = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+AlertTitle.displayName = "AlertTitle"
+
+const AlertDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+AlertDescription.displayName = "AlertDescription"
+
+export { Alert, AlertTitle, AlertDescription }
diff --git a/php-framework/components/ui/aspect-ratio.tsx b/php-framework/components/ui/aspect-ratio.tsx
new file mode 100644
index 0000000..d6a5226
--- /dev/null
+++ b/php-framework/components/ui/aspect-ratio.tsx
@@ -0,0 +1,7 @@
+"use client"
+
+import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
+
+const AspectRatio = AspectRatioPrimitive.Root
+
+export { AspectRatio }
diff --git a/php-framework/components/ui/avatar.tsx b/php-framework/components/ui/avatar.tsx
new file mode 100644
index 0000000..51e507b
--- /dev/null
+++ b/php-framework/components/ui/avatar.tsx
@@ -0,0 +1,50 @@
+"use client"
+
+import * as React from "react"
+import * as AvatarPrimitive from "@radix-ui/react-avatar"
+
+import { cn } from "@/lib/utils"
+
+const Avatar = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+Avatar.displayName = AvatarPrimitive.Root.displayName
+
+const AvatarImage = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AvatarImage.displayName = AvatarPrimitive.Image.displayName
+
+const AvatarFallback = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
+
+export { Avatar, AvatarImage, AvatarFallback }
diff --git a/php-framework/components/ui/badge.tsx b/php-framework/components/ui/badge.tsx
new file mode 100644
index 0000000..f000e3e
--- /dev/null
+++ b/php-framework/components/ui/badge.tsx
@@ -0,0 +1,36 @@
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const badgeVariants = cva(
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
+ {
+ variants: {
+ variant: {
+ default:
+ "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
+ secondary:
+ "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ destructive:
+ "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
+ outline: "text-foreground",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+export interface BadgeProps
+ extends React.HTMLAttributes,
+ VariantProps {}
+
+function Badge({ className, variant, ...props }: BadgeProps) {
+ return (
+
+ )
+}
+
+export { Badge, badgeVariants }
diff --git a/php-framework/components/ui/breadcrumb.tsx b/php-framework/components/ui/breadcrumb.tsx
new file mode 100644
index 0000000..60e6c96
--- /dev/null
+++ b/php-framework/components/ui/breadcrumb.tsx
@@ -0,0 +1,115 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { ChevronRight, MoreHorizontal } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+const Breadcrumb = React.forwardRef<
+ HTMLElement,
+ React.ComponentPropsWithoutRef<"nav"> & {
+ separator?: React.ReactNode
+ }
+>(({ ...props }, ref) => )
+Breadcrumb.displayName = "Breadcrumb"
+
+const BreadcrumbList = React.forwardRef<
+ HTMLOListElement,
+ React.ComponentPropsWithoutRef<"ol">
+>(({ className, ...props }, ref) => (
+
+))
+BreadcrumbList.displayName = "BreadcrumbList"
+
+const BreadcrumbItem = React.forwardRef<
+ HTMLLIElement,
+ React.ComponentPropsWithoutRef<"li">
+>(({ className, ...props }, ref) => (
+
+))
+BreadcrumbItem.displayName = "BreadcrumbItem"
+
+const BreadcrumbLink = React.forwardRef<
+ HTMLAnchorElement,
+ React.ComponentPropsWithoutRef<"a"> & {
+ asChild?: boolean
+ }
+>(({ asChild, className, ...props }, ref) => {
+ const Comp = asChild ? Slot : "a"
+
+ return (
+
+ )
+})
+BreadcrumbLink.displayName = "BreadcrumbLink"
+
+const BreadcrumbPage = React.forwardRef<
+ HTMLSpanElement,
+ React.ComponentPropsWithoutRef<"span">
+>(({ className, ...props }, ref) => (
+
+))
+BreadcrumbPage.displayName = "BreadcrumbPage"
+
+const BreadcrumbSeparator = ({
+ children,
+ className,
+ ...props
+}: React.ComponentProps<"li">) => (
+ svg]:w-3.5 [&>svg]:h-3.5", className)}
+ {...props}
+ >
+ {children ?? }
+
+)
+BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
+
+const BreadcrumbEllipsis = ({
+ className,
+ ...props
+}: React.ComponentProps<"span">) => (
+
+
+ More
+
+)
+BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
+
+export {
+ Breadcrumb,
+ BreadcrumbList,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+ BreadcrumbEllipsis,
+}
diff --git a/php-framework/components/ui/button.tsx b/php-framework/components/ui/button.tsx
new file mode 100644
index 0000000..36496a2
--- /dev/null
+++ b/php-framework/components/ui/button.tsx
@@ -0,0 +1,56 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
+ {
+ 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-10 px-4 py-2",
+ sm: "h-9 rounded-md px-3",
+ lg: "h-11 rounded-md px-8",
+ icon: "h-10 w-10",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button"
+ return (
+
+ )
+ }
+)
+Button.displayName = "Button"
+
+export { Button, buttonVariants }
diff --git a/php-framework/components/ui/calendar.tsx b/php-framework/components/ui/calendar.tsx
new file mode 100644
index 0000000..61d2b45
--- /dev/null
+++ b/php-framework/components/ui/calendar.tsx
@@ -0,0 +1,66 @@
+"use client"
+
+import * as React from "react"
+import { ChevronLeft, ChevronRight } from "lucide-react"
+import { DayPicker } from "react-day-picker"
+
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "@/components/ui/button"
+
+export type CalendarProps = React.ComponentProps
+
+function Calendar({
+ className,
+ classNames,
+ showOutsideDays = true,
+ ...props
+}: CalendarProps) {
+ return (
+ ,
+ IconRight: ({ ...props }) => ,
+ }}
+ {...props}
+ />
+ )
+}
+Calendar.displayName = "Calendar"
+
+export { Calendar }
diff --git a/php-framework/components/ui/card.tsx b/php-framework/components/ui/card.tsx
new file mode 100644
index 0000000..f62edea
--- /dev/null
+++ b/php-framework/components/ui/card.tsx
@@ -0,0 +1,79 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+const Card = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+Card.displayName = "Card"
+
+const CardHeader = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardHeader.displayName = "CardHeader"
+
+const CardTitle = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardTitle.displayName = "CardTitle"
+
+const CardDescription = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardDescription.displayName = "CardDescription"
+
+const CardContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardContent.displayName = "CardContent"
+
+const CardFooter = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardFooter.displayName = "CardFooter"
+
+export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
diff --git a/php-framework/components/ui/carousel.tsx b/php-framework/components/ui/carousel.tsx
new file mode 100644
index 0000000..ec505d0
--- /dev/null
+++ b/php-framework/components/ui/carousel.tsx
@@ -0,0 +1,262 @@
+"use client"
+
+import * as React from "react"
+import useEmblaCarousel, {
+ type UseEmblaCarouselType,
+} from "embla-carousel-react"
+import { ArrowLeft, ArrowRight } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+
+type CarouselApi = UseEmblaCarouselType[1]
+type UseCarouselParameters = Parameters
+type CarouselOptions = UseCarouselParameters[0]
+type CarouselPlugin = UseCarouselParameters[1]
+
+type CarouselProps = {
+ opts?: CarouselOptions
+ plugins?: CarouselPlugin
+ orientation?: "horizontal" | "vertical"
+ setApi?: (api: CarouselApi) => void
+}
+
+type CarouselContextProps = {
+ carouselRef: ReturnType[0]
+ api: ReturnType[1]
+ scrollPrev: () => void
+ scrollNext: () => void
+ canScrollPrev: boolean
+ canScrollNext: boolean
+} & CarouselProps
+
+const CarouselContext = React.createContext(null)
+
+function useCarousel() {
+ const context = React.useContext(CarouselContext)
+
+ if (!context) {
+ throw new Error("useCarousel must be used within a ")
+ }
+
+ return context
+}
+
+const Carousel = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes & CarouselProps
+>(
+ (
+ {
+ orientation = "horizontal",
+ opts,
+ setApi,
+ plugins,
+ className,
+ children,
+ ...props
+ },
+ ref
+ ) => {
+ const [carouselRef, api] = useEmblaCarousel(
+ {
+ ...opts,
+ axis: orientation === "horizontal" ? "x" : "y",
+ },
+ plugins
+ )
+ const [canScrollPrev, setCanScrollPrev] = React.useState(false)
+ const [canScrollNext, setCanScrollNext] = React.useState(false)
+
+ const onSelect = React.useCallback((api: CarouselApi) => {
+ if (!api) {
+ return
+ }
+
+ setCanScrollPrev(api.canScrollPrev())
+ setCanScrollNext(api.canScrollNext())
+ }, [])
+
+ const scrollPrev = React.useCallback(() => {
+ api?.scrollPrev()
+ }, [api])
+
+ const scrollNext = React.useCallback(() => {
+ api?.scrollNext()
+ }, [api])
+
+ const handleKeyDown = React.useCallback(
+ (event: React.KeyboardEvent) => {
+ if (event.key === "ArrowLeft") {
+ event.preventDefault()
+ scrollPrev()
+ } else if (event.key === "ArrowRight") {
+ event.preventDefault()
+ scrollNext()
+ }
+ },
+ [scrollPrev, scrollNext]
+ )
+
+ React.useEffect(() => {
+ if (!api || !setApi) {
+ return
+ }
+
+ setApi(api)
+ }, [api, setApi])
+
+ React.useEffect(() => {
+ if (!api) {
+ return
+ }
+
+ onSelect(api)
+ api.on("reInit", onSelect)
+ api.on("select", onSelect)
+
+ return () => {
+ api?.off("select", onSelect)
+ }
+ }, [api, onSelect])
+
+ return (
+
+
+ {children}
+
+
+ )
+ }
+)
+Carousel.displayName = "Carousel"
+
+const CarouselContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => {
+ const { carouselRef, orientation } = useCarousel()
+
+ return (
+
+ )
+})
+CarouselContent.displayName = "CarouselContent"
+
+const CarouselItem = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => {
+ const { orientation } = useCarousel()
+
+ return (
+
+ )
+})
+CarouselItem.displayName = "CarouselItem"
+
+const CarouselPrevious = React.forwardRef<
+ HTMLButtonElement,
+ React.ComponentProps
+>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
+ const { orientation, scrollPrev, canScrollPrev } = useCarousel()
+
+ return (
+
+ )
+})
+CarouselPrevious.displayName = "CarouselPrevious"
+
+const CarouselNext = React.forwardRef<
+ HTMLButtonElement,
+ React.ComponentProps
+>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
+ const { orientation, scrollNext, canScrollNext } = useCarousel()
+
+ return (
+
+ )
+})
+CarouselNext.displayName = "CarouselNext"
+
+export {
+ type CarouselApi,
+ Carousel,
+ CarouselContent,
+ CarouselItem,
+ CarouselPrevious,
+ CarouselNext,
+}
diff --git a/php-framework/components/ui/chart.tsx b/php-framework/components/ui/chart.tsx
new file mode 100644
index 0000000..8620baa
--- /dev/null
+++ b/php-framework/components/ui/chart.tsx
@@ -0,0 +1,365 @@
+"use client"
+
+import * as React from "react"
+import * as RechartsPrimitive from "recharts"
+
+import { cn } from "@/lib/utils"
+
+// Format: { THEME_NAME: CSS_SELECTOR }
+const THEMES = { light: "", dark: ".dark" } as const
+
+export type ChartConfig = {
+ [k in string]: {
+ label?: React.ReactNode
+ icon?: React.ComponentType
+ } & (
+ | { color?: string; theme?: never }
+ | { color?: never; theme: Record }
+ )
+}
+
+type ChartContextProps = {
+ config: ChartConfig
+}
+
+const ChartContext = React.createContext(null)
+
+function useChart() {
+ const context = React.useContext(ChartContext)
+
+ if (!context) {
+ throw new Error("useChart must be used within a ")
+ }
+
+ return context
+}
+
+const ChartContainer = React.forwardRef<
+ HTMLDivElement,
+ React.ComponentProps<"div"> & {
+ config: ChartConfig
+ children: React.ComponentProps<
+ typeof RechartsPrimitive.ResponsiveContainer
+ >["children"]
+ }
+>(({ id, className, children, config, ...props }, ref) => {
+ const uniqueId = React.useId()
+ const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
+
+ return (
+
+
+
+
+ {children}
+
+
+
+ )
+})
+ChartContainer.displayName = "Chart"
+
+const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
+ const colorConfig = Object.entries(config).filter(
+ ([_, config]) => config.theme || config.color
+ )
+
+ if (!colorConfig.length) {
+ return null
+ }
+
+ return (
+