aethex-studio/PROJECT_BACKUP.md
2026-01-27 06:16:41 +00:00

212 KiB

Project Backup

This file contains a full backup of all your project files. You can copy the contents of this file to your local machine to recreate the project.


FILE: .env



FILE: .gitignore

# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

# archives
*.zip

FILE: README.md

# Firebase Studio

This is a NextJS starter in Firebase Studio.

To get started, take a look at src/app/page.tsx.

FILE: apphosting.yaml

# Settings to manage and configure a Firebase App Hosting backend.
# https://firebase.google.com/docs/app-hosting/configure

runConfig:
  # Increase this value if you'd like to automatically spin up
  # more instances in response to increased traffic.
  maxInstances: 1

FILE: components.json

{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "default",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "src/app/globals.css",
    "baseColor": "neutral",
    "cssVariables": true,
    "prefix": ""
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  },
  "iconLibrary": "lucide"
}

FILE: next-env.d.ts

/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

FILE: next.config.ts

import type {NextConfig} from 'next';

const nextConfig: NextConfig = {
  /* config options here */
  typescript: {
    ignoreBuildErrors: true,
  },
  eslint: {
    ignoreDuringBuilds: true,
  },
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'placehold.co',
        port: '',
        pathname: '/**',
      },
      {
        protocol: 'https',
        hostname: 'images.unsplash.com',
        port: '',
        pathname: '/**',
      },
      {
        protocol: 'https',
        hostname: 'picsum.photos',
        port: '',
        pathname: '/**',
      },
    ],
  },
};

export default nextConfig;

FILE: package.json

{
  "name": "nextn",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack -p 9002",
    "genkit:dev": "genkit start -- tsx src/ai/dev.ts",
    "genkit:watch": "genkit start -- tsx --watch src/ai/dev.ts",
    "build": "NODE_ENV=production next build",
    "start": "next start",
    "lint": "next lint",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@genkit-ai/google-genai": "^1.20.0",
    "@genkit-ai/next": "^1.20.0",
    "@hookform/resolvers": "^4.1.3",
    "@radix-ui/react-accordion": "^1.2.3",
    "@radix-ui/react-alert-dialog": "^1.1.6",
    "@radix-ui/react-avatar": "^1.1.3",
    "@radix-ui/react-checkbox": "^1.1.4",
    "@radix-ui/react-collapsible": "^1.1.11",
    "@radix-ui/react-dialog": "^1.1.6",
    "@radix-ui/react-dropdown-menu": "^2.1.6",
    "@radix-ui/react-label": "^2.1.2",
    "@radix-ui/react-menubar": "^1.1.6",
    "@radix-ui/react-popover": "^1.1.6",
    "@radix-ui/react-progress": "^1.1.2",
    "@radix-ui/react-radio-group": "^1.2.3",
    "@radix-ui/react-scroll-area": "^1.2.3",
    "@radix-ui/react-select": "^2.1.6",
    "@radix-ui/react-separator": "^1.1.2",
    "@radix-ui/react-slider": "^1.2.3",
    "@radix-ui/react-slot": "^1.2.3",
    "@radix-ui/react-switch": "^1.1.3",
    "@radix-ui/react-tabs": "^1.1.3",
    "@radix-ui/react-toast": "^1.2.6",
    "@radix-ui/react-tooltip": "^1.1.8",
    "@tailwindcss/typography": "^0.5.13",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "date-fns": "^3.6.0",
    "dotenv": "^16.5.0",
    "embla-carousel-react": "^8.6.0",
    "firebase": "^11.9.1",
    "genkit": "^1.20.0",
    "lucide-react": "^0.475.0",
    "marked": "^12.0.2",
    "next": "15.5.9",
    "patch-package": "^8.0.0",
    "react": "^19.2.1",
    "react-day-picker": "^9.11.3",
    "react-dom": "^19.2.1",
    "react-hook-form": "^7.54.2",
    "react-syntax-highlighter": "^15.5.0",
    "recharts": "^2.15.1",
    "tailwind-merge": "^3.0.1",
    "tailwindcss-animate": "^1.0.7",
    "zod": "^3.24.2"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^19.2.1",
    "@types/react-dom": "^19.2.1",
    "@types/react-syntax-highlighter": "^15.5.13",
    "genkit-cli": "^1.20.0",
    "postcss": "^8",
    "tailwindcss": "^3.4.1",
    "typescript": "^5"
  }
}

FILE: src/ai/dev.ts

import { config } from 'dotenv';
config();

import '@/ai/flows/ai-suggested-sync-conflict-resolution.ts';
import '@/ai/flows/contextual-code-suggestions.ts';
import '@/ai/flows/ai-help-from-prompt.ts';

FILE: src/ai/flows/ai-help-from-prompt.ts

'use server';

/**
 * @fileOverview This file defines a Genkit flow that helps new users by suggesting an initial set of code files
 * and project structure based on a simple prompt describing the desired application.
 *
 * - aiHelpFromPrompt - A function that takes a prompt and returns suggested code files and project structure.
 * - AIHelpFromPromptInput - The input type for the aiHelpFromPrompt function.
 * - AIHelpFromPromptOutput - The return type for the aiHelpFromPrompt function.
 */

import {ai} from '@/ai/genkit';
import {z} from 'genkit';

const AIHelpFromPromptInputSchema = z.object({
  prompt: z.string().describe('A prompt describing the type of application to build.'),
});
export type AIHelpFromPromptInput = z.infer<typeof AIHelpFromPromptInputSchema>;

const AIHelpFromPromptOutputSchema = z.object({
  suggestedFiles: z.array(z.object({
    filePath: z.string().describe('The path for the suggested file.'),
    fileContent: z.string().describe('The content of the suggested file.'),
  })).describe('An array of suggested code files and their content.'),
  explanation: z.string().describe('An explanation of the suggested file structure and code.'),
});
export type AIHelpFromPromptOutput = z.infer<typeof AIHelpFromPromptOutputSchema>;

export async function aiHelpFromPrompt(input: AIHelpFromPromptInput): Promise<AIHelpFromPromptOutput> {
  return aiHelpFromPromptFlow(input);
}

const prompt = ai.definePrompt({
  name: 'aiHelpFromPromptPrompt',
  input: {schema: AIHelpFromPromptInputSchema},
  output: {schema: AIHelpFromPromptOutputSchema},
  prompt: `You are an AI assistant designed to help new users quickly start developing applications.

  Based on the user's prompt describing the desired application, suggest an initial set of code files and a project structure to get them started.

  Provide the suggested files as an array of objects, each containing the file path and the file content.
  Explain the suggested file structure and the code in detail so that the user understands the purpose of each file and how they fit together.

  User Prompt: {{{prompt}}}

  Example Output:
  {
    "suggestedFiles": [
      {
        "filePath": "src/components/MyComponent.tsx",
        "fileContent": "// MyComponent.tsx\nimport React from 'react';\n\nconst MyComponent = () => {\n  return (\n    <div>\n      <h1>Hello, world!</h1>\n    </div>\n  );\n};\n\nexport default MyComponent;"
      },
      {
        "filePath": "src/pages/index.tsx",
        "fileContent": "// index.tsx\nimport MyComponent from '../components/MyComponent';\n\nconst Home = () => {\n  return (\n    <div>\n      <MyComponent />\n    </div>\n  );\n};\n\nexport default Home;"
      }
    ],
    "explanation": "This project structure includes a component (MyComponent.tsx) and a page (index.tsx) that uses the component. This is a basic structure for a React application."
  }
  `,
});

const aiHelpFromPromptFlow = ai.defineFlow(
  {
    name: 'aiHelpFromPromptFlow',
    inputSchema: AIHelpFromPromptInputSchema,
    outputSchema: AIHelpFromPromptOutputSchema,
  },
  async input => {
    const {output} = await prompt(input, {
      config: {
        safetySettings: [
          {
            category: 'HARM_CATEGORY_HATE_SPEECH',
            threshold: 'BLOCK_ONLY_HIGH',
          },
          {
            category: 'HARM_CATEGORY_DANGEROUS_CONTENT',
            threshold: 'BLOCK_NONE',
          },
          {
            category: 'HARM_CATEGORY_HARASSMENT',
            threshold: 'BLOCK_MEDIUM_AND_ABOVE',
          },
          {
            category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
            threshold: 'BLOCK_LOW_AND_ABOVE',
          },
        ],
      },
    });
    return output!;
  }
);



FILE: src/ai/flows/ai-suggested-sync-conflict-resolution.ts

'use server';

/**
 * @fileOverview An AI agent that detects synchronization conflicts between platform-specific code and data,
 * and suggests solutions to resolve them.
 *
 * - aiSuggestedSyncConflictResolution - A function that handles the conflict resolution process.
 * - AISuggestedSyncConflictResolutionInput - The input type for the aiSuggestedSyncConflictResolution function.
 * - AISuggestedSyncConflictResolutionOutput - The return type for the aiSuggestedSyncConflictResolution function.
 */

import {ai} from '@/ai/genkit';
import {z} from 'genkit';

const AISuggestedSyncConflictResolutionInputSchema = z.object({
  robloxCode: z.string().describe('The Lua code for the Roblox platform.'),
  webCode: z.string().describe('The JavaScript code for the web platform.'),
  mobileCode: z.string().describe('The React Native code for the mobile platform.'),
  sharedState: z.string().describe('The shared state data in JSON format.'),
});
export type AISuggestedSyncConflictResolutionInput = z.infer<typeof AISuggestedSyncConflictResolutionInputSchema>;

const AISuggestedSyncConflictResolutionOutputSchema = z.object({
  conflictDetected: z.boolean().describe('Whether a synchronization conflict was detected.'),
  suggestedSolutions: z.array(z.string()).describe('An array of suggested solutions to resolve the conflicts.'),
  explanation: z.string().describe('Explanation of the detected conflicts and suggested solutions.'),
});
export type AISuggestedSyncConflictResolutionOutput = z.infer<typeof AISuggestedSyncConflictResolutionOutputSchema>;

export async function aiSuggestedSyncConflictResolution(input: AISuggestedSyncConflictResolutionInput): Promise<AISuggestedSyncConflictResolutionOutput> {
  return aiSuggestedSyncConflictResolutionFlow(input);
}

const prompt = ai.definePrompt({
  name: 'aiSuggestedSyncConflictResolutionPrompt',
  input: {schema: AISuggestedSyncConflictResolutionInputSchema},
  output: {schema: AISuggestedSyncConflictResolutionOutputSchema},
  prompt: `You are an AI assistant specialized in detecting synchronization conflicts between different platform codebases and suggesting solutions.

You are given the code for Roblox (Lua), Web (JavaScript), and Mobile (React Native), as well as the shared state data in JSON format. Analyze the code and the shared state to identify any inconsistencies or conflicts.

Based on your analysis, determine if there are any conflicts, and suggest solutions to resolve them. Explain the conflicts and the suggested solutions in detail.

Roblox Code:
{{robloxCode}}

Web Code:
{{webCode}}

Mobile Code:
{{mobileCode}}

Shared State:
{{sharedState}}`,
});

const aiSuggestedSyncConflictResolutionFlow = ai.defineFlow(
  {
    name: 'aiSuggestedSyncConflictResolutionFlow',
    inputSchema: AISuggestedSyncConflictResolutionInputSchema,
    outputSchema: AISuggestedSyncConflictResolutionOutputSchema,
  },
  async input => {
    const {output} = await prompt(input, {
      config: {
        safetySettings: [
          {
            category: 'HARM_CATEGORY_HATE_SPEECH',
            threshold: 'BLOCK_ONLY_HIGH',
          },
          {
            category: 'HARM_CATEGORY_DANGEROUS_CONTENT',
            threshold: 'BLOCK_NONE',
          },
          {
            category: 'HARM_CATEGORY_HARASSMENT',
            threshold: 'BLOCK_MEDIUM_AND_ABOVE',
          },
          {
            category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
            threshold: 'BLOCK_LOW_AND_ABOVE',
          },
        ],
      },
    });
    return output!;
  }
);



FILE: src/ai/flows/contextual-code-suggestions.ts

'use server';
/**
 * @fileOverview This file defines a Genkit flow for providing contextual code suggestions.
 *
 * - contextualCodeSuggestions - A function that takes the current file content and cursor position
 *   and returns code suggestions.
 * - ContextualCodeSuggestionsInput - The input type for the contextualCodeSuggestions function.
 * - ContextualCodeSuggestionsOutput - The return type for the contextualCodeSuggestions function.
 */

import {ai} from '@/ai/genkit';
import {z} from 'genkit';

const ContextualCodeSuggestionsInputSchema = z.object({
  fileContent: z.string().describe('The content of the currently open file.'),
  cursorPosition: z.number().describe('The cursor position within the file.'),
  language: z.string().describe('The programming language of the file.'),
  context: z.string().optional().describe('Additional context for code suggestions, e.g., error messages or related code snippets.'),
});
export type ContextualCodeSuggestionsInput = z.infer<
  typeof ContextualCodeSuggestionsInputSchema
>;

const ContextualCodeSuggestionsOutputSchema = z.object({
  suggestions: z
    .array(z.string())
    .describe('An array of code suggestions based on the context.'),
});
export type ContextualCodeSuggestionsOutput = z.infer<
  typeof ContextualCodeSuggestionsOutputSchema
>;

export async function contextualCodeSuggestions(
  input: ContextualCodeSuggestionsInput
): Promise<ContextualCodeSuggestionsOutput> {
  return contextualCodeSuggestionsFlow(input);
}

const prompt = ai.definePrompt({
  name: 'contextualCodeSuggestionsPrompt',
  input: {schema: ContextualCodeSuggestionsInputSchema},
  output: {schema: ContextualCodeSuggestionsOutputSchema},
  prompt: `You are an AI assistant that provides code suggestions and autocompletions based on the context of the currently open file and cursor position.

  Given the following file content, cursor position, programming language, and any available context, provide a list of code suggestions that would be helpful to the developer.

  File Content:
  {{fileContent}}

  Cursor Position: {{cursorPosition}}

  Programming Language: {{language}}

  Context: {{context}}

  Suggestions should be relevant to the current context, incorporate best practices, and avoid common mistakes. Return the suggestions as an array of strings.

  Example:
  [
    "console.log('Hello, world!');",
    "// Add a comment to explain the code",
    "function myFunction() {\n      // Function body\n    }",
  ]`,  
});

const contextualCodeSuggestionsFlow = ai.defineFlow(
  {
    name: 'contextualCodeSuggestionsFlow',
    inputSchema: ContextualCodeSuggestionsInputSchema,
    outputSchema: ContextualCodeSuggestionsOutputSchema,
  },
  async input => {
    const {output} = await prompt(input);
    return output!;
  }
);


FILE: src/ai/genkit.ts

import {genkit} from 'genkit';
import {googleAI} from '@genkit-ai/google-genai';

export const ai = genkit({
  plugins: [googleAI()],
  model: 'googleai/gemini-2.5-flash',
});


FILE: src/app/dashboard/page.tsx

import { DashboardPage } from "@/components/aethex/dashboard-page";

export default function Page() {
  return <DashboardPage />;
}


FILE: src/app/globals.css

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 0 0% 3.9%;
    --card: 0 0% 100%;
    --card-foreground: 0 0% 3.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 0 0% 3.9%;
    --primary: 278 52% 49%;
    --primary-foreground: 0 0% 98%;
    --secondary: 277 100% 25%;
    --secondary-foreground: 0 0% 98%;
    --muted: 0 0% 96.1%;
    --muted-foreground: 0 0% 45.1%;
    --accent: 180 100% 25%;
    --accent-foreground: 0 0% 9%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 0 0% 98%;
    --border: 0 0% 89.8%;
    --input: 0 0% 89.8%;
    --ring: 278 52% 49%;
    --chart-1: 12 76% 61%;
    --chart-2: 173 58% 39%;
    --chart-3: 197 37% 24%;
    --chart-4: 43 74% 66%;
    --chart-5: 27 87% 67%;
    --radius: 0.5rem;
  }
  .dark {
    --background: 0 0% 13.3%;
    --foreground: 0 0% 98%;
    --card: 0 0% 20%;
    --card-foreground: 0 0% 98%;
    --popover: 0 0% 13.3%;
    --popover-foreground: 0 0% 98%;
    --primary: 278 52% 49%;
    --primary-foreground: 0 0% 98%;
    --secondary: 277 100% 25%;
    --secondary-foreground: 0 0% 98%;
    --muted: 0 0% 20%;
    --muted-foreground: 0 0% 63.9%;
    --accent: 180 100% 25%;
    --accent-foreground: 0 0% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 0 0% 98%;
    --border: 0 0% 25%;
    --input: 0 0% 25%;
    --ring: 278 52% 49%;
    --chart-1: 220 70% 50%;
    --chart-2: 160 60% 45%;
    --chart-3: 30 80% 55%;
    --chart-4: 280 65% 60%;
    --chart-5: 340 75% 55%;
  }
}

@layer base {
  * {
    @apply border-border;
  }
  body {
    @apply bg-background text-foreground;
  }
}


FILE: src/app/ide/page.tsx

import { AethexStudio } from "@/components/aethex/aethex-studio";

export default function IdePage() {
  return (
    <main className="h-[100svh] w-screen overflow-hidden bg-background">
      <AethexStudio />
    </main>
  );
}


FILE: src/app/layout.tsx

import type { Metadata } from "next";
import { Toaster } from "@/components/ui/toaster";
import "./globals.css";

export const metadata: Metadata = {
  title: "AeThex Studio",
  description: "The Next-Generation Cross-Platform IDE",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en" className="dark">
      <head>
        <link rel="preconnect" href="https://fonts.googleapis.com" />
        <link
          rel="preconnect"
          href="https://fonts.gstatic.com"
          crossOrigin="anonymous"
        />
        <link
          href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&family=Source+Code+Pro:wght@400&family=Space+Grotesk:wght@400;700&display=swap"
          rel="stylesheet"
        />
      </head>
      <body className="font-body antialiased">
        {children}
        <Toaster />
      </body>
    </html>
  );
}


FILE: src/app/page.tsx

import { LoginPage } from "@/components/aethex/login-page";

export default function Page() {
  return <LoginPage />;
}


FILE: src/components/aethex/aethex-studio.tsx

"use client";

import { useState } from "react";
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable";
import { Navbar } from "./navbar";
import { FileNavigator } from "./file-navigator";
import { MainView } from "./main-view";
import { BottomPanel } from "./bottom-panel";
import { AiAssistant } from "./ai-assistant";
import {
  openFiles as initialOpenFiles,
  fileTree as initialFileTree,
  File as OpenFileType,
  FolderNode,
  FileNode,
} from "@/lib/aethex-data";
import { NewProjectModal } from "./new-project-modal";
import {
  ProjectTemplate,
  generateFileContent,
} from "@/lib/templates";
import type { NewProjectFormValues } from "./new-project-modal";

export type { OpenFileType };

export function AethexStudio() {
  const [openFiles, setOpenFiles] = useState<OpenFileType[]>(initialOpenFiles);
  const [activeTab, setActiveTab] = useState<string>(openFiles[0]?.id || "");
  const [fileTree, setFileTree] = useState<FolderNode>(initialFileTree);
  const [isNewProjectModalOpen, setIsNewProjectModalOpen] = useState(false);

  const handleOpenFile = (file: OpenFileType) => {
    if (!openFiles.find((f) => f.id === file.id)) {
      setOpenFiles((prev) => [...prev, file]);
    }
    setActiveTab(file.id);
  };

  const handleCloseFile = (fileId: string) => {
    const newOpenFiles = openFiles.filter((file) => file.id !== fileId);
    setOpenFiles(newOpenFiles);

    if (activeTab === fileId) {
      if (newOpenFiles.length > 0) {
        setActiveTab(newOpenFiles[newOpenFiles.length - 1].id);
      } else {
        setActiveTab("");
      }
    }
  };

  const handleCreateProject = (
    template: ProjectTemplate,
    config: NewProjectFormValues
  ) => {
    const newFileTree: FolderNode = {
      ...template.fileTree,
      name: config.projectName,
    };
    setFileTree(newFileTree);

    let mainFileToOpen: OpenFileType | undefined;

    const findMainFile = (node: FolderNode | FileNode, currentPath: string) => {
      if (mainFileToOpen) return;
      const newPath = currentPath ? `${currentPath}/${node.name}` : node.name;
      if (node.type === "file" && node.name === template.mainFile) {
        mainFileToOpen = {
          id: newPath,
          name: node.name,
          language: node.language,
          content: generateFileContent(node.name, node.language),
        };
      } else if (node.type === "folder" && node.children) {
        for (const child of node.children) {
          findMainFile(child, newPath);
        }
      }
    };
    findMainFile(newFileTree, "");

    if (mainFileToOpen) {
      setOpenFiles([mainFileToOpen]);
      setActiveTab(mainFileToOpen.id);
    } else {
      setOpenFiles([]);
      setActiveTab("");
    }

    setIsNewProjectModalOpen(false);
  };
  
  const handleAiGeneratedFiles = (files: { filePath: string, fileContent: string }[]) => {
    const addNodeToTree = (
      root: FolderNode,
      path: string
    ): FolderNode => {
      const parts = path.split('/');
      // The AI generates paths relative to the project root, e.g., "src/components/new.tsx"
      // The file tree's root is the project folder itself, so we start traversing from its children.
      let currentNode: FolderNode | undefined = root;
      
      // Handle cases where AI gives a full path vs relative
      const pathParts = parts[0] === root.name ? parts.slice(1) : parts;

      for (let i = 0; i < pathParts.length - 1; i++) {
        const part = pathParts[i];
        let nextNode = currentNode.children.find(
          (child) => child.name === part && child.type === 'folder'
        ) as FolderNode | undefined;

        if (!nextNode) {
          nextNode = { name: part, type: 'folder', children: [] };
          currentNode.children.push(nextNode);
        }
        currentNode = nextNode;
      }

      // Add the file node if it doesn't exist
      const fileName = pathParts[pathParts.length - 1];
      if (currentNode && !currentNode.children.some((child) => child.name === fileName)) {
        currentNode.children.push({
          name: fileName,
          type: 'file',
          language: fileName.split('.').pop() || 'text',
        });
      }

      return { ...root };
    };
    
    let newFileTree = fileTree;
    files.forEach(file => {
      newFileTree = addNodeToTree(newFileTree, file.filePath);
    });
    setFileTree(newFileTree);

    const newFilesToOpen: OpenFileType[] = files.map(file => ({
      id: file.filePath.startsWith(fileTree.name) ? file.filePath : `${fileTree.name}/${file.filePath}`,
      name: file.filePath.split('/').pop() || 'untitled',
      language: file.filePath.split('.').pop() || 'text',
      content: file.fileContent,
    }));

    setOpenFiles(prevOpenFiles => {
      const updatedOpenFiles = [...prevOpenFiles];
      newFilesToOpen.forEach(newFile => {
        const existingFileIndex = updatedOpenFiles.findIndex(f => f.id === newFile.id);
        if (existingFileIndex !== -1) {
          updatedOpenFiles[existingFileIndex].content = newFile.content;
        } else {
          updatedOpenFiles.push(newFile);
        }
      });
      return updatedOpenFiles;
    });

    if (newFilesToOpen.length > 0) {
      setActiveTab(newFilesToOpen[newFilesToOpen.length - 1].id);
    }
  };

  return (
    <>
      <div className="flex h-full flex-col text-sm">
        <Navbar onNewProjectClick={() => setIsNewProjectModalOpen(true)} />
        <div className="flex-grow overflow-hidden">
          <ResizablePanelGroup direction="horizontal" className="!h-full">
            <ResizablePanel defaultSize={15} minSize={10} maxSize={25}>
              <FileNavigator fileTree={fileTree} onOpenFile={handleOpenFile} />
            </ResizablePanel>
            <ResizableHandle withHandle />
            <ResizablePanel defaultSize={60}>
              <ResizablePanelGroup direction="vertical">
                <ResizablePanel defaultSize={70}>
                  <MainView
                    openFiles={openFiles}
                    activeTab={activeTab}
                    setActiveTab={setActiveTab}
                    onCloseFile={handleCloseFile}
                  />
                </ResizablePanel>
                <ResizableHandle withHandle />
                <ResizablePanel defaultSize={30} minSize={10} maxSize={40}>
                  <BottomPanel />
                </ResizablePanel>
              </ResizablePanelGroup>
            </ResizablePanel>
            <ResizableHandle withHandle />
            <ResizablePanel defaultSize={25} minSize={15} maxSize={35}>
              <AiAssistant onFilesGenerated={handleAiGeneratedFiles} />
            </ResizablePanel>
          </ResizablePanelGroup>
        </div>
      </div>
      <NewProjectModal
        isOpen={isNewProjectModalOpen}
        onClose={() => setIsNewProjectModalOpen(false)}
        onCreateProject={handleCreateProject}
      />
    </>
  );
}


FILE: src/components/aethex/ai-assistant.tsx

"use client";

import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Send,
  Bot,
  Loader2,
  Copy,
  Code,
  Sparkles,
  MessageSquarePlus,
  FlaskConical,
  BookText,
} from "lucide-react";
import { AethexLogo } from "./icons";
import { useState, useRef, useEffect, memo } from "react";
import { aiHelpFromPrompt } from "@/ai/flows/ai-help-from-prompt";
import { cn } from "@/lib/utils";
import { marked } from "marked";
import SyntaxHighlighter from "react-syntax-highlighter";
import { atomOneDark } from "react-syntax-highlighter/dist/esm/styles/hljs";
import { useToast } from "@/hooks/use-toast";
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";

type Message = {
  id: string;
  role: "user" | "assistant" | "system";
  content: string;
};

const CodeBlock = memo(
  ({ language, code }: { language: string; code: string }) => {
    const { toast } = useToast();

    const handleCopy = () => {
      navigator.clipboard.writeText(code);
      toast({ title: "Code copied to clipboard!" });
    };

    const handleInsert = () => {
      toast({
        title: "Coming Soon!",
        description: "Inserting code into the editor is not yet implemented.",
      });
    };

    return (
      <div className="group relative my-2 rounded-md bg-background">
        <div className="flex items-center justify-between rounded-t-md bg-muted px-3 py-1.5 text-xs text-muted-foreground">
          <span>{language}</span>
          <div className="flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
            <TooltipProvider>
              <Tooltip>
                <TooltipTrigger asChild>
                  <Button
                    variant="ghost"
                    size="icon"
                    className="h-6 w-6"
                    onClick={handleInsert}
                  >
                    <Code className="h-3 w-3" />
                  </Button>
                </TooltipTrigger>
                <TooltipContent>
                  <p>Insert into editor</p>
                </TooltipContent>
              </Tooltip>
            </TooltipProvider>

            <TooltipProvider>
              <Tooltip>
                <TooltipTrigger asChild>
                  <Button
                    variant="ghost"
                    size="icon"
                    className="h-6 w-6"
                    onClick={handleCopy}
                  >
                    <Copy className="h-3 w-3" />
                  </Button>
                </TooltipTrigger>
                <TooltipContent>
                  <p>Copy code</p>
                </TooltipContent>
              </Tooltip>
            </TooltipProvider>
          </div>
        </div>
        <SyntaxHighlighter
          language={language}
          style={atomOneDark}
          customStyle={{
            padding: "1rem",
            margin: 0,
            borderBottomLeftRadius: "0.375rem",
            borderBottomRightRadius: "0.375rem",
          }}
          PreTag="div"
        >
          {code}
        </SyntaxHighlighter>
      </div>
    );
  }
);
CodeBlock.displayName = "CodeBlock";

const ChatMessage = memo(({ message }: { message: Message }) => {
  if (message.role === "system") {
    return (
      <div className="text-center text-xs text-muted-foreground">
        {message.content}
      </div>
    );
  }

  const isUser = message.role === "user";
  const parts = message.content
    .split(/(\`\`\`(?:[a-zA-Z0-9-]*)\n[\s\S]+?\n\`\`\`)/g)
    .filter(Boolean);

  return (
    <div
      className={cn(
        "flex w-full items-start gap-3",
        !isUser && "justify-end"
      )}
    >
      {isUser && (
        <Avatar className="h-8 w-8">
          <AvatarFallback>U</AvatarFallback>
        </Avatar>
      )}
      <div
        className={cn(
          "max-w-[85%] space-y-2 rounded-lg p-3 text-sm",
          isUser
            ? "bg-primary text-primary-foreground"
            : "border border-primary bg-card"
        )}
      >
        {parts.map((part, index) => {
          const codeBlockMatch = part.match(
            /\`\`\`(.*?)\n([\s\S]+?)\n\`\`\`/
          );
          if (codeBlockMatch) {
            const language = codeBlockMatch[1] || "text";
            const code = codeBlockMatch[2];
            return <CodeBlock key={index} language={language} code={code} />;
          } else {
            return (
              <div
                key={index}
                className="prose prose-sm prose-invert max-w-none prose-p:my-0"
                dangerouslySetInnerHTML={{
                  __html: marked(part, { gfm: true, breaks: true }),
                }}
              />
            );
          }
        })}
      </div>
      {!isUser && (
        <Avatar className="h-8 w-8 border">
          <AvatarFallback className="bg-transparent">
            <AethexLogo className="h-5 w-5" />
          </AvatarFallback>
        </Avatar>
      )}
    </div>
  );
});
ChatMessage.displayName = "ChatMessage";

type AiAssistantProps = {
  onFilesGenerated: (files: { filePath: string, fileContent: string }[]) => void;
};

export function AiAssistant({ onFilesGenerated }: AiAssistantProps) {
  const [messages, setMessages] = useState<Message[]>([
    {
      id: "1",
      role: "assistant",
      content:
        "Hello! I'm your AI assistant. How can I help you with your project today? You can ask me to explain code, generate tests, or even create a new project structure.",
    },
  ]);
  const [input, setInput] = useState("");
  const [loading, setLoading] = useState(false);
  const scrollAreaRef = useRef<HTMLDivElement>(null);
  const { toast } = useToast();

  useEffect(() => {
    if (scrollAreaRef.current) {
      scrollAreaRef.current.scrollTo({
        top: scrollAreaRef.current.scrollHeight,
        behavior: "smooth",
      });
    }
  }, [messages]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!input.trim() || loading) return;

    const userMessage: Message = {
      id: Date.now().toString(),
      role: "user",
      content: input,
    };
    setMessages((prev) => [...prev, userMessage]);
    const currentInput = input;
    setInput("");
    setLoading(true);

    try {
      const result = await aiHelpFromPrompt({ prompt: currentInput });

      let assistantContent = result.explanation;

      if (result.suggestedFiles && result.suggestedFiles.length > 0) {
        onFilesGenerated(result.suggestedFiles);
        assistantContent += `\n\nHere are the files I've generated for you:\n`;
        result.suggestedFiles.forEach((file) => {
          const lang = file.filePath.split(".").pop() || "";
          assistantContent += `\n**${file.filePath}**\n\`\`\`${lang}\n${file.fileContent}\n\`\`\``;
        });
        const systemMessage: Message = {
          id: Date.now().toString() + "-system",
          role: "system",
          content: "File suggestions have been opened in the editor for you to review.",
        };
        setMessages((prev) => [...prev, systemMessage]);
      }

      const assistantMessage: Message = {
        id: Date.now().toString(),
        role: "assistant",
        content: assistantContent,
      };
      setMessages((prev) => [...prev, assistantMessage]);
    } catch (error) {
      console.error("AI assistant error:", error);
      const errorMessage: Message = {
        id: Date.now().toString(),
        role: "assistant",
        content:
          "Sorry, I encountered an issue while processing your request. Please try again.",
      };
      setMessages((prev) => [...prev, errorMessage]);
    } finally {
      setLoading(false);
    }
  };

  const handleQuickAction = (action: string) => {
    toast({
      title: "Coming Soon!",
      description: `The "${action}" feature is not yet implemented.`,
    });
  };

  const quickActions = [
    { label: "Explain selected code", icon: BookText, action: "Explain selected code" },
    { label: "Add comments", icon: MessageSquarePlus, action: "Add comments" },
    { label: "Convert to cross-platform", icon: Sparkles, action: "Convert to cross-platform" },
    { label: "Generate tests", icon: FlaskConical, action: "Generate tests" },
  ]

  return (
    <div className="flex h-full flex-col bg-card">
      <div className="flex items-center justify-between border-b p-3">
        <div className="flex items-center gap-2">
          <Bot className="h-6 w-6 text-primary" />
          <h2 className="font-headline text-lg font-semibold">AI Assistant</h2>
        </div>
        <div className="flex items-center gap-2">
          <div className="text-right text-xs">
            <p className="text-muted-foreground">Token Usage</p>
            <p className="font-medium">12.5K / 500K</p>
          </div>
          <Select defaultValue="claude-sonnet">
            <SelectTrigger className="w-[150px]">
              <SelectValue placeholder="Select a model" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="claude-sonnet">Claude 3.5 Sonnet</SelectItem>
              <SelectItem value="gpt-4o" disabled>GPT-4o</SelectItem>
            </SelectContent>
          </Select>
        </div>
      </div>

      <ScrollArea className="flex-1" viewportRef={scrollAreaRef}>
        <div className="space-y-6 p-4">
          {messages.map((message) => (
            <ChatMessage key={message.id} message={message} />
          ))}
          {loading && (
            <div className="flex w-full items-start gap-3">
              <Avatar className="h-8 w-8">
                <AvatarFallback>U</AvatarFallback>
              </Avatar>
              <div className="flex items-center space-x-2 rounded-lg bg-primary p-3 text-primary-foreground">
                <Loader2 className="h-4 w-4 animate-spin" />
                <span>Waiting for response...</span>
              </div>
            </div>
          )}
        </div>
      </ScrollArea>

      <div className="border-t p-3">
        <div className="mb-2 flex flex-wrap gap-2">
            {quickActions.map(({label, icon: Icon, action}) => (
                <Button key={label} size="sm" variant="outline" onClick={() => handleQuickAction(action)}>
                    <Icon className="mr-2 h-3.5 w-3.5" />
                    {label}
                </Button>
            ))}
        </div>
        <form onSubmit={handleSubmit} className="relative">
          <Textarea
            value={input}
            onChange={(e) => setInput(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === "Enter" && !e.shiftKey) {
                e.preventDefault();
                handleSubmit(e);
              }
            }}
            placeholder="Ask the AI assistant, or describe what you want to build..."
            className="min-h-[60px] pr-12"
            disabled={loading}
          />
          <div className="absolute bottom-2 right-1 flex flex-col items-center gap-1">
            <Button
              variant="ghost"
              size="icon"
              type="submit"
              disabled={loading || !input.trim()}
            >
              <Send className="h-4 w-4" />
              <span className="sr-only">Send message</span>
            </Button>
          </div>
        </form>
      </div>
    </div>
  );
}


FILE: src/components/aethex/bottom-panel.tsx

"use client";

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { consoleLogs } from "@/lib/aethex-data";
import { ChevronRight, HardDrive } from "lucide-react";

export function BottomPanel() {
  return (
    <div className="flex h-full flex-col">
      <Tabs defaultValue="console" className="flex h-full flex-col">
        <TabsList className="mx-2 mt-2 self-start rounded-md">
          <TabsTrigger value="console">Console</TabsTrigger>
          <TabsTrigger value="terminal">Terminal</TabsTrigger>
        </TabsList>
        <TabsContent value="console" className="flex-1 overflow-auto p-4 text-xs">
          <div className="font-code">
            {consoleLogs.map((log, index) => (
              <div
                key={index}
                className={`flex items-start gap-2 border-b border-border/50 py-1 ${
                  log.type === "error"
                    ? "text-destructive"
                    : log.type === "warn"
                    ? "text-yellow-400"
                    : "text-muted-foreground"
                }`}
              >
                <span className="w-20 shrink-0 text-foreground/50">
                  {log.timestamp}
                </span>
                <span
                  className={`w-12 shrink-0 font-bold ${
                    log.platform === "Roblox"
                      ? "text-red-500"
                      : log.platform === "Web"
                      ? "text-blue-500"
                      : "text-green-500"
                  }`}
                >
                  [{log.platform}]
                </span>
                <p className="flex-1 whitespace-pre-wrap">{log.message}</p>
              </div>
            ))}
          </div>
        </TabsContent>
        <TabsContent value="terminal" className="h-full">
            <div className="flex h-full flex-col bg-background p-4 font-code text-xs">
                <p>AeThex Terminal</p>
                <p>Copyright (c) 2024. All rights reserved.</p>
                <div className="mt-4 flex items-center gap-2">
                    <HardDrive className="h-3 w-3 text-accent" />
                    <span className="text-accent">~/aethex-project</span>
                    <ChevronRight className="h-3 w-3" />
                    <span className="flex-1"></span>
                </div>
            </div>
        </TabsContent>
      </Tabs>
    </div>
  );
}


FILE: src/components/aethex/code-editor.tsx

"use client";

import type { Dispatch, SetStateAction } from "react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Button } from "@/components/ui/button";
import { X } from "lucide-react";
import { ScrollArea } from "@/components/ui/scroll-area";
import type { OpenFileType } from "./aethex-studio";

type CodeEditorProps = {
  openFiles: OpenFileType[];
  activeTab: string;
  setActiveTab: Dispatch<SetStateAction<string>>;
  onCloseFile: (fileId: string) => void;
};

export function CodeEditor({
  openFiles,
  activeTab,
  setActiveTab,
  onCloseFile,
}: CodeEditorProps) {

  const handleCloseTab = (
    e: React.MouseEvent<HTMLButtonElement>,
    fileId: string
  ) => {
    e.stopPropagation();
    onCloseFile(fileId);
  };
  
  if (openFiles.length === 0) {
    return (
      <div className="flex h-full items-center justify-center bg-card text-muted-foreground">
        <p>No files open. Select a file from the navigator.</p>
      </div>
    );
  }

  return (
    <Tabs
      value={activeTab}
      onValueChange={setActiveTab}
      className="flex h-full flex-col"
    >
      <TabsList className="m-0 flex h-auto justify-start rounded-none border-b bg-transparent p-0">
        {openFiles.map((file) => (
          <TabsTrigger
            key={file.id}
            value={file.id}
            className="group relative h-10 rounded-none border-r border-t-2 border-t-transparent bg-card px-4 py-2 text-muted-foreground shadow-none data-[state=active]:border-t-primary data-[state=active]:bg-background data-[state=active]:text-foreground"
          >
            {file.name}
            <Button
              variant="ghost"
              size="icon"
              className="absolute right-1 top-1/2 h-5 w-5 -translate-y-1/2 opacity-0 group-hover:opacity-100"
              onClick={(e) => handleCloseTab(e, file.id)}
            >
              <X className="h-3 w-3" />
            </Button>
          </TabsTrigger>
        ))}
      </TabsList>
      {openFiles.map((file) => (
        <TabsContent
          key={file.id}
          value={file.id}
          className="m-0 flex-1 overflow-hidden"
        >
          <ScrollArea className="h-full">
            <pre className="p-4 font-code text-sm">
              <code
                dangerouslySetInnerHTML={{ __html: file.content }}
              ></code>
            </pre>
          </ScrollArea>
        </TabsContent>
      ))}
    </Tabs>
  );
}


FILE: src/components/aethex/cross-platform-view.tsx

"use client";

import Image from "next/image";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import {
  platformCode,
  crossPlatformState,
} from "@/lib/aethex-data";
import { PlaceHolderImages } from "@/lib/placeholder-images";
import { MobileIcon, RobloxIcon, WebIcon } from "./icons";
import {
  AlertCircle,
  CheckCircle2,
  Bot,
  Loader2,
  ServerCrash,
  ChevronsUpDown,
} from "lucide-react";
import { Button } from "../ui/button";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { ScrollArea } from "../ui/scroll-area";
import { useState } from "react";
import {
  aiSuggestedSyncConflictResolution,
  AISuggestedSyncConflictResolutionOutput,
} from "@/ai/flows/ai-suggested-sync-conflict-resolution";

export function CrossPlatformView() {
  const robloxViewport = PlaceHolderImages.find((p) => p.id === "roblox-vp");
  const webViewport = PlaceHolderImages.find((p) => p.id === "web-vp");
  const mobileViewport = PlaceHolderImages.find((p) => p.id === "mobile-vp");

  return (
    <ResizablePanelGroup direction="vertical" className="h-full w-full">
      <ResizablePanel defaultSize={50} minSize={30}>
        <div className="grid h-full grid-cols-3 gap-2 p-2">
          {robloxViewport && (
            <Viewport
              platform="Roblox"
              icon={<RobloxIcon />}
              imageUrl={robloxViewport.imageUrl}
              imageHint={robloxViewport.imageHint}
            />
          )}
          {webViewport && (
            <Viewport
              platform="Web"
              icon={<WebIcon />}
              imageUrl={webViewport.imageUrl}
              imageHint={webViewport.imageHint}
            />
          )}
          {mobileViewport && (
            <Viewport
              platform="Mobile"
              icon={<MobileIcon />}
              imageUrl={mobileViewport.imageUrl}
              imageHint={mobileViewport.imageHint}
            />
          )}
        </div>
      </ResizablePanel>
      <ResizableHandle withHandle />
      <ResizablePanel defaultSize={50} minSize={30}>
        <div className="grid h-full grid-cols-3 gap-2 p-2">
          <div className="col-span-2">
            <PlatformCodeEditor />
          </div>
          <div className="flex flex-col">
            <StateInspector />
          </div>
        </div>
      </ResizablePanel>
    </ResizablePanelGroup>
  );
}

function Viewport({
  platform,
  icon,
  imageUrl,
  imageHint,
}: {
  platform: string;
  icon: React.ReactNode;
  imageUrl: string;
  imageHint: string;
}) {
  return (
    <Card className="flex flex-col">
      <CardHeader className="flex flex-row items-center justify-between p-3">
        <div className="flex items-center gap-2">
          {icon}
          <CardTitle className="text-base font-headline">{platform}</CardTitle>
        </div>
        <div className="flex items-center gap-1.5 text-green-400">
          <CheckCircle2 className="h-3 w-3" />
          <span className="text-xs">Synced</span>
        </div>
      </CardHeader>
      <CardContent className="flex-1 p-0">
        <div className="relative h-full w-full">
          <Image
            src={imageUrl}
            alt={`${platform} viewport`}
            fill
            className="object-cover"
            data-ai-hint={imageHint}
          />
        </div>
      </CardContent>
    </Card>
  );
}

function PlatformCodeEditor() {
  return (
    <Card className="h-full">
      <Tabs defaultValue="lua" className="flex h-full flex-col">
        <TabsList className="m-0 flex h-auto justify-start rounded-none border-b bg-card p-0">
          {Object.entries(platformCode).map(([lang, { name }]) => (
            <TabsTrigger
              key={lang}
              value={lang}
              className="relative h-10 rounded-none border-r border-t-2 border-t-transparent bg-card px-4 py-2 text-muted-foreground shadow-none data-[state=active]:border-t-accent data-[state=active]:bg-background data-[state=active]:text-foreground"
            >
              {name}
            </TabsTrigger>
          ))}
        </TabsList>
        {Object.entries(platformCode).map(([lang, { code }]) => (
          <TabsContent
            key={lang}
            value={lang}
            className="m-0 flex-1 overflow-hidden"
          >
            <ScrollArea className="h-full">
              <pre className="p-4 font-code text-sm">
                <code>{code}</code>
              </pre>
            </ScrollArea>
          </TabsContent>
        ))}
      </Tabs>
    </Card>
  );
}

function StateInspector() {
  return (
    <Card className="flex-1">
      <CardHeader className="p-3">
        <CardTitle className="text-base font-headline">
          State Inspector
        </CardTitle>
        <CardDescription className="text-xs">
          Real-time variable synchronization.
        </CardDescription>
      </CardHeader>
      <CardContent className="p-0">
        <ScrollArea className="h-[calc(100%-70px)]">
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead className="pl-3">Variable</TableHead>
                <TableHead>Value</TableHead>
                <TableHead className="pr-3 text-right">Status</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {crossPlatformState.map((item) => (
                <StateTableRow key={item.variable} item={item} />
              ))}
            </TableBody>
          </Table>
        </ScrollArea>
      </CardContent>
    </Card>
  );
}

function StateTableRow({
  item,
}: {
  item: (typeof crossPlatformState)[0];
}) {
  const [isOpen, setIsOpen] = useState(false);
  const [suggestion, setSuggestion] =
    useState<AISuggestedSyncConflictResolutionOutput | null>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fetchSuggestion = async () => {
    if (isLoading) return;
    setIsLoading(true);
    setError(null);
    setSuggestion(null);
    try {
      const result = await aiSuggestedSyncConflictResolution({
        robloxCode: platformCode.lua.code,
        webCode: platformCode.javascript.code,
        mobileCode: platformCode.typescript.code,
        sharedState: JSON.stringify(
          Object.fromEntries(
            crossPlatformState.map((i) => [i.variable, i.web])
          ),
          null,
          2
        ),
      });
      setSuggestion(result);
    } catch (e) {
      setError("Failed to get AI suggestion. Please try again.");
      console.error(e);
    } finally {
      setIsLoading(false);
    }
  };

  const renderStatus = () => {
    switch (item.status) {
      case "synced":
        return (
          <div className="flex items-center justify-end gap-1.5 text-green-400">
            <CheckCircle2 className="h-3 w-3" />
            <span className="text-xs">Synced</span>
          </div>
        );
      case "syncing":
        return (
          <div className="flex items-center justify-end gap-1.5 text-yellow-400">
            <Loader2 className="h-3 w-3 animate-spin" />
            <span className="text-xs">Syncing</span>
          </div>
        );
      case "conflict":
        return (
          <AlertDialog open={isOpen} onOpenChange={setIsOpen}>
            <AlertDialogTrigger asChild>
              <Button
                variant="ghost"
                size="sm"
                onClick={fetchSuggestion}
                disabled={isLoading}
                className="h-auto p-1 text-red-500 hover:bg-red-500/10 hover:text-red-500"
              >
                <AlertCircle className="h-3 w-3" />
                <span className="ml-1.5 text-xs">Conflict</span>
              </Button>
            </AlertDialogTrigger>
            <AlertDialogContent className="max-w-2xl">
              <AlertDialogHeader>
                <AlertDialogTitle className="flex items-center gap-2 font-headline">
                  <Bot /> AI Conflict Resolution
                </AlertDialogTitle>
                {isLoading && (
                  <div className="flex items-center justify-center p-12">
                    <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
                  </div>
                )}
                {error && (
                  <div className="flex flex-col items-center justify-center p-12 text-center">
                    <ServerCrash className="h-8 w-8 text-destructive" />
                    <p className="mt-4 text-destructive">{error}</p>
                  </div>
                )}
                {suggestion && (
                  <AlertDialogDescription>
                    {suggestion.explanation}
                  </AlertDialogDescription>
                )}
              </AlertDialogHeader>
              {suggestion?.suggestedSolutions &&
                suggestion.suggestedSolutions.length > 0 && (
                  <div className="my-4 rounded-md border bg-muted/50 p-4">
                    <h4 className="mb-2 font-semibold">Suggested Solutions:</h4>
                    <ul className="list-disc space-y-2 pl-5 font-code text-xs">
                      {suggestion.suggestedSolutions.map((solution, i) => (
                        <li key={i}>{solution}</li>
                      ))}
                    </ul>
                  </div>
                )}
              {suggestion && (
                <AlertDialogFooter>
                  <AlertDialogCancel>Cancel</AlertDialogCancel>
                  <AlertDialogAction>Apply Suggestion</AlertDialogAction>
                </AlertDialogFooter>
              )}
            </AlertDialogContent>
          </AlertDialog>
        );
    }
  };

  return (
    <TableRow>
      <TableCell className="pl-3 font-code text-xs font-medium">
        {item.variable}
      </TableCell>
      <TableCell>
        <Popover>
          <PopoverTrigger asChild>
            <Button
              variant="outline"
              size="sm"
              className="h-auto w-full justify-between p-1.5 font-code text-xs"
            >
              <span className="truncate">{JSON.stringify(item.web)}</span>
              <ChevronsUpDown className="ml-2 h-3 w-3 shrink-0" />
            </Button>
          </PopoverTrigger>
          <PopoverContent className="w-auto p-3 font-code text-xs">
            <div className="grid grid-cols-[auto_1fr] gap-x-2">
              <span className="text-red-500">Roblox:</span>
              <span className="text-purple-400">
                {JSON.stringify(item.roblox)}
              </span>
              <span className="text-blue-500">Web:</span>
              <span className="text-purple-400">
                {JSON.stringify(item.web)}
              </span>
              <span className="text-green-500">Mobile:</span>
              <span className="text-purple-400">
                {JSON.stringify(item.mobile)}
              </span>
            </div>
          </PopoverContent>
        </Popover>
      </TableCell>
      <TableCell className="pr-3 text-right">{renderStatus()}</TableCell>
    </TableRow>
  );
}


FILE: src/components/aethex/dashboard-page.tsx

"use client";

import { useState, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Gamepad2, Plus } from "lucide-react";
import { WorkspaceCard } from "./workspace-card";
import { WorkspaceCardSkeleton } from "./workspace-card-skeleton";
import { workspaces as initialWorkspaces } from "@/lib/workspaces";
import { NewProjectModal } from "./new-project-modal";
import { ProjectTemplate } from "@/lib/templates";
import { NewProjectFormValues } from "./new-project-modal";
import { MobileIcon, RobloxIcon, WebIcon } from "./icons";

type Workspace = typeof initialWorkspaces[0];

export function DashboardPage() {
  const [workspaces, setWorkspaces] =
    useState<Workspace[]>(initialWorkspaces);
  const [loading, setLoading] = useState(true);
  const [isNewProjectModalOpen, setIsNewProjectModalOpen] = useState(false);

  useEffect(() => {
    const timer = setTimeout(() => {
      setLoading(false);
    }, 1500);
    return () => clearTimeout(timer);
  }, []);

  const handleCreateProject = (
    template: ProjectTemplate,
    config: NewProjectFormValues
  ) => {
    // This is a mock implementation. In a real app, this would involve
    // an API call to create a new project in the backend.
    const newWorkspace: Workspace = {
      id: `proj-${Date.now()}`,
      name: config.projectName,
      lastModified: "Just now",
      platforms: config.platforms.map((p) => {
        if (p === "roblox") return RobloxIcon;
        if (p === "web") return WebIcon;
        return MobileIcon;
      }),
      thumbnailUrlId: "workspace-thumb-4",
      thumbnailImageHint: "futuristic city",
    };
    setWorkspaces((prev) => [newWorkspace, ...prev]);
    setIsNewProjectModalOpen(false);
  };

  const renderContent = () => {
    if (loading) {
      return (
        <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
          {Array.from({ length: 3 }).map((_, i) => (
            <WorkspaceCardSkeleton key={i} />
          ))}
        </div>
      );
    }

    if (workspaces.length === 0) {
      return (
        <div className="text-center">
          <div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-primary/10">
            <Gamepad2 className="h-6 w-6 text-primary" />
          </div>
          <h3 className="mt-4 text-lg font-semibold text-foreground">
            No projects yet
          </h3>
          <p className="mt-1 text-sm text-muted-foreground">
            Get started by creating a new project.
          </p>
          <div className="mt-6">
            <Button onClick={() => setIsNewProjectModalOpen(true)}>
              <Plus className="-ml-0.5 mr-1.5 h-5 w-5" />
              New Project
            </Button>
          </div>
        </div>
      );
    }

    return (
      <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
        {workspaces.map((ws) => (
          <WorkspaceCard key={ws.id} workspace={ws} />
        ))}
      </div>
    );
  };

  return (
    <>
      <div className="min-h-screen bg-background">
        <div className="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
          <header className="mb-8 flex items-center justify-between">
            <h1 className="font-headline text-3xl font-bold text-foreground">
              My Workspaces
            </h1>
            <Button onClick={() => setIsNewProjectModalOpen(true)}>
              <Plus className="-ml-1 mr-2" /> New Workspace
            </Button>
          </header>
          <main>{renderContent()}</main>
        </div>
      </div>
      <NewProjectModal
        isOpen={isNewProjectModalOpen}
        onClose={() => setIsNewProjectModalOpen(false)}
        onCreateProject={handleCreateProject}
      />
    </>
  );
}


FILE: src/components/aethex/file-navigator.tsx

"use client";

import React from "react";
import {
  File,
  Folder,
  ChevronRight,
  FolderPlus,
  FilePlus,
} from "lucide-react";
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { FileNode, FolderNode, File as OpenFileType } from "@/lib/aethex-data";
import { generateFileContent } from "@/lib/templates";

type FileNavigatorProps = {
  onOpenFile: (file: OpenFileType) => void;
  fileTree: FolderNode;
};

export function FileNavigator({ onOpenFile, fileTree }: FileNavigatorProps) {
  return (
    <div className="flex h-full flex-col bg-card">
      <div className="flex items-center justify-between border-b p-3">
        <h2 className="font-headline text-lg font-semibold">Explorer</h2>
        <div className="flex items-center gap-1">
          <Button variant="ghost" size="icon" className="h-7 w-7">
            <FilePlus className="h-4 w-4" />
          </Button>
          <Button variant="ghost" size="icon" className="h-7 w-7">
            <FolderPlus className="h-4 w-4" />
          </Button>
        </div>
      </div>
      <div className="flex-1 overflow-auto p-2">
        <FileTree aKey="root" node={fileTree} onOpenFile={onOpenFile} path="" />
      </div>
      <div className="border-t p-2">
        <Input placeholder="Search files..." />
      </div>
    </div>
  );
}

type FileTreeProps = {
  node: FolderNode | FileNode;
  aKey: string;
  onOpenFile: (file: OpenFileType) => void;
  path: string;
};

function FileTree({ node, aKey, onOpenFile, path }: FileTreeProps) {
  const handleFileClick = () => {
    if (node.type === "file") {
      const filePath = path ? `${path}/${node.name}` : node.name;
      onOpenFile({
        id: filePath,
        name: node.name,
        language: (node as FileNode).language,
        content: generateFileContent(node.name, (node as FileNode).language),
      });
    }
  };

  if (node.type === "file") {
    return (
      <div
        className="ml-5 flex cursor-pointer items-center justify-between gap-2 rounded-md py-1 pr-2 hover:bg-muted"
        onClick={handleFileClick}
      >
        <div className="flex items-center gap-2 truncate pl-1">
          <File className="h-4 w-4 shrink-0 text-muted-foreground" />
          <span className="truncate text-sm">{node.name}</span>
        </div>
      </div>
    );
  }

  const currentPath = path ? `${path}/${node.name}` : node.name;

  return (
    <Collapsible defaultOpen={aKey === "root" || node.name === "roblox"}>
      <CollapsibleTrigger asChild>
        <div className="group flex cursor-pointer items-center justify-between gap-2 rounded-md p-1 pr-2 hover:bg-muted">
          <div className="flex items-center gap-2 truncate">
            <ChevronRight className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200 group-data-[state=open]:rotate-90" />
            <Folder className="h-4 w-4 shrink-0 text-muted-foreground" />
            <span className="truncate font-semibold text-sm">{node.name}</span>
          </div>
        </div>
      </CollapsibleTrigger>
      <CollapsibleContent>
        <div className="pl-4">
          {node.children.map((child, index) => (
            <FileTree
              key={index}
              aKey={child.name}
              node={child}
              onOpenFile={onOpenFile}
              path={currentPath}
            />
          ))}
        </div>
      </CollapsibleContent>
    </Collapsible>
  );
}


FILE: src/components/aethex/icons.tsx

import type { SVGProps } from "react";

export function AethexLogo(props: SVGProps<SVGSVGElement>) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="M14.5 13.03a3 3 0 1 0-3.5-3.53" />
      <path d="M12 2a10 10 0 1 0 10 10" />
    </svg>
  );
}

export function RobloxIcon(props: SVGProps<SVGSVGElement>) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      className="h-4 w-4 text-red-500"
      {...props}
    >
      <path d="m11.9 2.7-8.2 3.4 3.4 8.2 8.2-3.4Z" />
      <path d="m13.4 7.2-5.7 2.4" />
      <path d="m19.2 8.5-8.2 3.4-3.4-8.2 8.2-3.4Z" />
    </svg>
  );
}

export function WebIcon(props: SVGProps<SVGSVGElement>) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      className="h-4 w-4 text-blue-500"
      {...props}
    >
      <circle cx="12" cy="12" r="10" />
      <path d="M2 12h20" />
      <path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
    </svg>
  );
}

export function MobileIcon(props: SVGProps<SVGSVGElement>) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      className="h-4 w-4 text-green-500"
      {...props}
    >
      <rect width="14" height="20" x="5" y="2" rx="2" ry="2" />
      <path d="M12 18h.01" />
    </svg>
  );
}

export function GoogleIcon(props: SVGProps<SVGSVGElement>) {
    return (
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px" {...props}>
            <path fill="#FFC107" d="M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"/>
            <path fill="#FF3D00" d="M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"/>
            <path fill="#4CAF50" d="M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"/>
            <path fill="#1976D2" d="M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.574l6.19,5.238C39.99,36.596,44,30.85,44,24C44,22.659,43.862,21.35,43.611,20.083z"/>
        </svg>
    )
}


FILE: src/components/aethex/login-page.tsx

"use client";

import Link from "next/link";
import Image from "next/image";
import { AethexLogo, GoogleIcon } from "@/components/aethex/icons";
import { Button } from "@/components/ui/button";
import { Github } from "lucide-react";
import { PlaceHolderImages } from "@/lib/placeholder-images";

export function LoginPage() {
  const loginIllustration = PlaceHolderImages.find(
    (p) => p.id === "login-illustration"
  );

  return (
    <div className="flex min-h-screen w-full bg-background">
      <div className="flex flex-1 flex-col justify-center px-4 py-12 sm:px-6 lg:flex-none lg:px-20 xl:px-24">
        <div className="mx-auto w-full max-w-sm lg:w-96">
          <div>
            <AethexLogo className="h-10 w-auto text-primary" />
            <h1 className="mt-6 font-headline text-3xl font-bold tracking-tight text-foreground">
              Welcome to AeThex Studio
            </h1>
            <p className="mt-2 text-sm text-muted-foreground">
              The Next-Generation Cross-Platform IDE.
            </p>
          </div>

          <div className="mt-8">
            <div className="space-y-3">
              <Link href="/dashboard" passHref>
                <Button
                  size="lg"
                  className="w-full bg-gradient-to-r from-primary via-purple-500 to-fuchsia-500 text-primary-foreground transition-all hover:opacity-90"
                >
                  Sign in with AeThex Passport
                </Button>
              </Link>
              <Link href="/dashboard" passHref>
                <Button size="lg" variant="outline" className="w-full">
                  <GoogleIcon className="mr-3 h-5 w-5" />
                  Sign in with Google
                </Button>
              </Link>
              <Link href="/dashboard" passHref>
                <Button size="lg" variant="outline" className="w-full">
                  <Github className="mr-3 h-5 w-5" />
                  Sign in with GitHub
                </Button>
              </Link>
            </div>
          </div>
        </div>
      </div>
      <div className="relative hidden w-0 flex-1 lg:block">
        {loginIllustration && (
          <Image
            className="absolute inset-0 h-full w-full object-cover"
            src={loginIllustration.imageUrl}
            alt="Cross-platform game development illustration"
            data-ai-hint={loginIllustration.imageHint}
            fill
            priority
          />
        )}
      </div>
    </div>
  );
}


FILE: src/components/aethex/main-view.tsx

"use client";

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { CodeEditor } from "./code-editor";
import { CrossPlatformView } from "./cross-platform-view";
import type { Dispatch, SetStateAction } from "react";
import type { OpenFileType } from "./aethex-studio";

type MainViewProps = {
  openFiles: OpenFileType[];
  activeTab: string;
  setActiveTab: Dispatch<SetStateAction<string>>;
  onCloseFile: (fileId: string) => void;
};

export function MainView({ openFiles, activeTab, setActiveTab, onCloseFile }: MainViewProps) {
  return (
    <div className="h-full bg-background">
      <Tabs defaultValue="editor" className="flex h-full flex-col">
        <TabsList className="ml-2 mt-2 h-auto self-start rounded-md bg-card p-1">
          <TabsTrigger value="editor">Editor</TabsTrigger>
          <TabsTrigger value="cross-platform">Cross-Platform View</TabsTrigger>
        </TabsList>
        <TabsContent value="editor" className="m-0 flex-1 overflow-hidden">
          <CodeEditor 
            openFiles={openFiles}
            activeTab={activeTab}
            setActiveTab={setActiveTab}
            onCloseFile={onCloseFile}
          />
        </TabsContent>
        <TabsContent
          value="cross-platform"
          className="m-0 flex-1 overflow-hidden"
        >
          <CrossPlatformView />
        </TabsContent>
      </Tabs>
    </div>
  );
}


FILE: src/components/aethex/navbar.tsx

"use client";

import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { Check, FilePlus, Loader, Play, Bot } from "lucide-react";
import { AethexLogo, MobileIcon, RobloxIcon, WebIcon } from "./icons";
import { cn } from "@/lib/utils";

type NavbarProps = {
  onNewProjectClick: () => void;
};

export function Navbar({ onNewProjectClick }: NavbarProps) {
  const [saveStatus, setSaveStatus] = useState("Saved");
  const [syncStatus, setSyncStatus] = useState("synced");

  useEffect(() => {
    const interval = setInterval(() => {
      setSaveStatus("Saving...");
      setTimeout(() => setSaveStatus("Saved"), 1000);
    }, 5000);
    return () => clearInterval(interval);
  }, []);

  useEffect(() => {
    const statuses = ["synced", "syncing", "error"];
    let i = 0;
    const interval = setInterval(() => {
      i = (i + 1) % statuses.length;
      setSyncStatus(statuses[i]);
    }, 7000);
    return () => clearInterval(interval);
  }, []);

  return (
    <header className="flex h-12 shrink-0 items-center justify-between border-b bg-card px-4">
      <div className="flex items-center gap-4">
        <div className="flex items-center gap-2">
          <AethexLogo className="h-6 w-6 text-primary" />
          <h1 className="font-headline text-xl font-bold">AeThex Studio</h1>
        </div>
        <Button variant="outline" size="sm" onClick={onNewProjectClick}>
          <FilePlus className="mr-2 h-4 w-4" />
          New Project
        </Button>
        <div className="flex items-center gap-2 text-xs text-muted-foreground">
          {saveStatus === "Saving..." ? (
            <>
              <Loader className="h-3 w-3 animate-spin" />
              <span>Saving...</span>
            </>
          ) : (
            <>
              <Check className="h-3 w-3" />
              <span>Auto-Saved</span>
            </>
          )}
        </div>
      </div>

      <div className="flex items-center gap-4">
        <Button variant="secondary" size="sm">
          <Bot className="mr-2 h-4 w-4" />
          AI Actions
        </Button>
        <div
          className="flex items-center gap-2"
          title={`Status: ${syncStatus}`}
        >
          <span className="text-xs text-muted-foreground">Sync Status</span>
          <div
            className={cn("h-2.5 w-2.5 rounded-full", {
              "bg-green-500": syncStatus === "synced",
              "animate-pulse bg-yellow-500": syncStatus === "syncing",
              "bg-red-500": syncStatus === "error",
            })}
          />
        </div>
        <div className="flex items-center gap-2">
          <Button variant="outline" size="sm">
            <RobloxIcon className="mr-2" />
            Deploy
          </Button>
          <Button variant="outline" size="sm">
            <WebIcon className="mr-2" />
            Deploy
          </Button>
          <Button variant="outline" size="sm">
            <MobileIcon className="mr-2" />
            Deploy
          </Button>
        </div>
        <Button size="sm">
          <Play className="mr-2 h-4 w-4" />
          Run All
        </Button>
      </div>
    </header>
  );
}


FILE: src/components/aethex/new-project-modal.tsx

"use client";

import { useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
  DialogDescription,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Stepper } from "@/components/ui/stepper";
import {
  Card,
  CardContent,
  CardHeader,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Checkbox } from "@/components/ui/checkbox";
import { Switch } from "@/components/ui/switch";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { projectTemplates, ProjectTemplate } from "@/lib/templates";
import { cn } from "@/lib/utils";
import { Crosshair, Fingerprint } from "lucide-react";

const steps = [
  { label: "Choose Template" },
  { label: "Configure" },
  { label: "Review & Create" },
];

const formSchema = z.object({
  projectName: z.string().min(1, "Project name is required."),
  platforms: z.array(z.string()).refine((value) => value.some((item) => item), {
    message: "You have to select at least one platform.",
  }),
  enableNexus: z.boolean(),
  enablePassport: z.boolean(),
});

export type NewProjectFormValues = z.infer<typeof formSchema>;

type NewProjectModalProps = {
  isOpen: boolean;
  onClose: () => void;
  onCreateProject: (
    template: ProjectTemplate,
    config: NewProjectFormValues
  ) => void;
};

export function NewProjectModal({
  isOpen,
  onClose,
  onCreateProject,
}: NewProjectModalProps) {
  const [currentStep, setCurrentStep] = useState(1);
  const [selectedTemplate, setSelectedTemplate] =
    useState<ProjectTemplate | null>(null);

  const form = useForm<NewProjectFormValues>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      projectName: "",
      platforms: ["web"],
      enableNexus: true,
      enablePassport: false,
    },
  });

  const handleNext = () => {
    if (currentStep === 1 && selectedTemplate) {
      form.setValue(
        "projectName",
        selectedTemplate.id === "blank"
          ? ""
          : selectedTemplate.name.toLowerCase().replace(/\s/g, "-")
      );
      setCurrentStep(2);
    } else if (currentStep === 2) {
      form.trigger().then((isValid) => {
        if (isValid) {
          setCurrentStep(3);
        }
      });
    }
  };

  const handleBack = () => {
    if (currentStep > 1) {
      setCurrentStep(currentStep - 1);
    }
  };

  const handleCreate = () => {
    if (selectedTemplate) {
      onCreateProject(selectedTemplate, form.getValues());
      resetAndClose();
    }
  };

  const resetAndClose = () => {
    form.reset();
    setCurrentStep(1);
    setSelectedTemplate(null);
    onClose();
  };

  const platforms = [
    { id: "roblox", label: "Roblox" },
    { id: "web", label: "Web" },
    { id: "mobile", label: "Mobile" },
  ];

  return (
    <Dialog open={isOpen} onOpenChange={resetAndClose}>
      <DialogContent className="max-w-4xl">
        <DialogHeader>
          <DialogTitle>Create New Project</DialogTitle>
          <DialogDescription>
            Start a new project from a template or from scratch.
          </DialogDescription>
        </DialogHeader>
        <div className="my-6">
          <Stepper steps={steps} currentStep={currentStep} />
        </div>

        {currentStep === 1 && (
          <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
            {projectTemplates.map((template) => (
              <Card
                key={template.id}
                onClick={() => setSelectedTemplate(template)}
                className={cn(
                  "cursor-pointer hover:border-primary",
                  selectedTemplate?.id === template.id &&
                    "border-2 border-primary"
                )}
              >
                <CardHeader>
                  <div className="flex items-center justify-between">
                    <template.icon className="h-8 w-8 text-primary" />
                    {template.isPopular && (
                      <Badge variant="secondary">Popular</Badge>
                    )}
                  </div>
                </CardHeader>
                <CardContent>
                  <h3 className="font-semibold">{template.name}</h3>
                  <p className="text-sm text-muted-foreground">
                    {template.description}
                  </p>
                </CardContent>
              </Card>
            ))}
          </div>
        )}

        {currentStep === 2 && (
          <Form {...form}>
            <form className="space-y-8">
              <FormField
                control={form.control}
                name="projectName"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Project Name</FormLabel>
                    <FormControl>
                      <Input placeholder="my-awesome-project" {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />

              <FormField
                control={form.control}
                name="platforms"
                render={() => (
                  <FormItem>
                    <FormLabel>Target Platforms</FormLabel>
                    <div className="flex items-center space-x-4 pt-2">
                      {platforms.map((item) => (
                        <FormField
                          key={item.id}
                          control={form.control}
                          name="platforms"
                          render={({ field }) => {
                            return (
                              <FormItem
                                key={item.id}
                                className="flex flex-row items-start space-x-3 space-y-0"
                              >
                                <FormControl>
                                  <Checkbox
                                    checked={field.value?.includes(item.id)}
                                    onCheckedChange={(checked) => {
                                      return checked
                                        ? field.onChange([
                                            ...field.value,
                                            item.id,
                                          ])
                                        : field.onChange(
                                            field.value?.filter(
                                              (value) => value !== item.id
                                            )
                                          );
                                    }}
                                  />
                                </FormControl>
                                <FormLabel className="font-normal">
                                  {item.label}
                                </FormLabel>
                              </FormItem>
                            );
                          }}
                        />
                      ))}
                    </div>
                    <FormMessage />
                  </FormItem>
                )}
              />

              <div className="space-y-4">
                <FormLabel>Add-on Features</FormLabel>
                <p className="text-sm text-muted-foreground">
                  Enhance your project with powerful AeThex services.
                </p>
                <div className="grid grid-cols-1 gap-4 pt-2 md:grid-cols-2">
                  <FormField
                    control={form.control}
                    name="enableNexus"
                    render={({ field }) => (
                      <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
                        <div className="space-y-0.5">
                          <FormLabel className="flex items-center gap-2">
                            <Crosshair className="h-4 w-4 text-accent" />
                            Enable Nexus Engine
                          </FormLabel>
                          <p className="text-xs text-muted-foreground">
                            Real-time state synchronization.
                          </p>
                        </div>
                        <FormControl>
                          <Switch
                            checked={field.value}
                            onCheckedChange={field.onChange}
                          />
                        </FormControl>
                      </FormItem>
                    )}
                  />
                  <FormField
                    control={form.control}
                    name="enablePassport"
                    render={({ field }) => (
                      <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
                        <div className="space-y-0.5">
                          <FormLabel className="flex items-center gap-2">
                            <Fingerprint className="h-4 w-4 text-accent" />
                            Enable Passport Auth
                          </FormLabel>
                          <p className="text-xs text-muted-foreground">
                            Unified identity across platforms.
                          </p>
                        </div>
                        <FormControl>
                          <Switch
                            checked={field.value}
                            onCheckedChange={field.onChange}
                          />
                        </FormControl>
                      </FormItem>
                    )}
                  />
                </div>
              </div>
            </form>
          </Form>
        )}

        {currentStep === 3 && selectedTemplate && (
          <div className="space-y-4">
            <h3 className="text-lg font-semibold">Review your project</h3>
            <Card>
              <CardContent className="grid grid-cols-1 gap-y-6 p-6 sm:grid-cols-2 sm:gap-x-8">
                <div>
                  <p className="text-sm font-semibold text-muted-foreground">
                    Project Name
                  </p>
                  <p className="font-medium">
                    {form.getValues("projectName")}
                  </p>
                </div>
                <div>
                  <p className="text-sm font-semibold text-muted-foreground">
                    Template
                  </p>
                  <p className="font-medium">{selectedTemplate.name}</p>
                </div>
                <div>
                  <p className="text-sm font-semibold text-muted-foreground">
                    Platforms
                  </p>
                  <p className="font-medium">
                    {form.getValues("platforms").join(", ")}
                  </p>
                </div>
                <div>
                  <p className="text-sm font-semibold text-muted-foreground">
                    Features
                  </p>
                  <div className="flex flex-col gap-2 pt-1">
                    {form.getValues("enableNexus") && (
                      <span className="flex items-center gap-2 font-medium">
                        <Crosshair className="h-4 w-4 text-accent" /> Nexus
                        Engine
                      </span>
                    )}
                    {form.getValues("enablePassport") && (
                      <span className="flex items-center gap-2 font-medium">
                        <Fingerprint className="h-4 w-4 text-accent" /> Passport
                        Auth
                      </span>
                    )}
                    {!form.getValues("enableNexus") &&
                      !form.getValues("enablePassport") && (
                        <p className="font-medium text-muted-foreground">
                          None
                        </p>
                      )}
                  </div>
                </div>
              </CardContent>
            </Card>
          </div>
        )}

        <DialogFooter>
          {currentStep > 1 && (
            <Button variant="outline" onClick={handleBack}>
              Back
            </Button>
          )}
          {currentStep < 3 && (
            <Button
              onClick={handleNext}
              disabled={currentStep === 1 && !selectedTemplate}
            >
              Next
            </Button>
          )}
          {currentStep === 3 && (
            <Button onClick={handleCreate}>Create Project</Button>
          )}
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}


FILE: src/components/aethex/workspace-card-skeleton.tsx

"use client";

import {
  Card,
  CardContent,
  CardFooter,
  CardHeader,
} from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";

export function WorkspaceCardSkeleton() {
  return (
    <Card className="overflow-hidden">
      <CardHeader className="p-0">
        <Skeleton className="aspect-[4/3] w-full" />
      </CardHeader>
      <CardContent className="p-4">
        <Skeleton className="h-6 w-3/4" />
        <Skeleton className="mt-2 h-3 w-1/2" />
      </CardContent>
      <CardFooter className="flex items-center justify-between p-4 pt-0">
        <div className="flex -space-x-2">
          <Skeleton className="h-6 w-6 rounded-full" />
          <Skeleton className="h-6 w-6 rounded-full" />
        </div>
        <Skeleton className="h-8 w-8" />
      </CardFooter>
    </Card>
  );
}


FILE: src/components/aethex/workspace-card.tsx

"use client";

import Link from "next/link";
import Image from "next/image";
import {
  Card,
  CardContent,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { MoreHorizontal } from "lucide-react";
import type { Workspace } from "@/lib/workspaces";
import { PlaceHolderImages } from "@/lib/placeholder-images";

type WorkspaceCardProps = {
  workspace: Workspace;
};

export function WorkspaceCard({ workspace }: WorkspaceCardProps) {
  const thumbnail = PlaceHolderImages.find(
    (p) => p.id === workspace.thumbnailUrlId
  );

  return (
    <Card className="overflow-hidden transition-all hover:shadow-lg hover:shadow-primary/10">
      <CardHeader className="p-0">
        <Link href="/ide" className="block aspect-[4/3] w-full">
          <div className="relative h-full w-full">
            {thumbnail && (
              <Image
                src={thumbnail.imageUrl}
                alt={workspace.name}
                fill
                className="object-cover"
                data-ai-hint={thumbnail.imageHint}
              />
            )}
            <div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
          </div>
        </Link>
      </CardHeader>
      <CardContent className="p-4">
        <CardTitle className="text-lg font-bold tracking-normal">
          <Link href="/ide" className="hover:text-primary">
            {workspace.name}
          </Link>
        </CardTitle>
        <p className="text-xs text-muted-foreground">
          Last modified {workspace.lastModified}
        </p>
      </CardContent>
      <CardFooter className="flex items-center justify-between p-4 pt-0">
        <div className="flex -space-x-2">
          {workspace.platforms.map((Icon, index) => (
            <div
              key={index}
              className="z-10 flex h-6 w-6 items-center justify-center rounded-full border-2 border-card bg-card"
            >
              <Icon className="h-4 w-4" />
            </div>
          ))}
        </div>
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button variant="ghost" size="icon" className="h-8 w-8">
              <MoreHorizontal className="h-4 w-4" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end">
            <DropdownMenuItem>Rename</DropdownMenuItem>
            <DropdownMenuItem>Share</DropdownMenuItem>
            <DropdownMenuItem className="text-destructive focus:text-destructive">
              Delete
            </DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      </CardFooter>
    </Card>
  );
}


FILE: src/components/ui/accordion.tsx

"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<typeof AccordionPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
  <AccordionPrimitive.Item
    ref={ref}
    className={cn("border-b", className)}
    {...props}
  />
))
AccordionItem.displayName = "AccordionItem"

const AccordionTrigger = React.forwardRef<
  React.ElementRef<typeof AccordionPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
  <AccordionPrimitive.Header className="flex">
    <AccordionPrimitive.Trigger
      ref={ref}
      className={cn(
        "flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
        className
      )}
      {...props}
    >
      {children}
      <ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200" />
    </AccordionPrimitive.Trigger>
  </AccordionPrimitive.Header>
))
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName

const AccordionContent = React.forwardRef<
  React.ElementRef<typeof AccordionPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
  <AccordionPrimitive.Content
    ref={ref}
    className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
    {...props}
  >
    <div className={cn("pb-4 pt-0", className)}>{children}</div>
  </AccordionPrimitive.Content>
))

AccordionContent.displayName = AccordionPrimitive.Content.displayName

export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }


FILE: src/components/ui/alert-dialog.tsx

"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<typeof AlertDialogPrimitive.Overlay>,
  React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
  <AlertDialogPrimitive.Overlay
    className={cn(
      "fixed inset-0 z-50 bg-black/80  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
      className
    )}
    {...props}
    ref={ref}
  />
))
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName

const AlertDialogContent = React.forwardRef<
  React.ElementRef<typeof AlertDialogPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
>(({ className, ...props }, ref) => (
  <AlertDialogPortal>
    <AlertDialogOverlay />
    <AlertDialogPrimitive.Content
      ref={ref}
      className={cn(
        "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
        className
      )}
      {...props}
    />
  </AlertDialogPortal>
))
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName

const AlertDialogHeader = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div
    className={cn(
      "flex flex-col space-y-2 text-center sm:text-left",
      className
    )}
    {...props}
  />
)
AlertDialogHeader.displayName = "AlertDialogHeader"

const AlertDialogFooter = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div
    className={cn(
      "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
      className
    )}
    {...props}
  />
)
AlertDialogFooter.displayName = "AlertDialogFooter"

const AlertDialogTitle = React.forwardRef<
  React.ElementRef<typeof AlertDialogPrimitive.Title>,
  React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
>(({ className, ...props }, ref) => (
  <AlertDialogPrimitive.Title
    ref={ref}
    className={cn("text-lg font-semibold", className)}
    {...props}
  />
))
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName

const AlertDialogDescription = React.forwardRef<
  React.ElementRef<typeof AlertDialogPrimitive.Description>,
  React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
>(({ className, ...props }, ref) => (
  <AlertDialogPrimitive.Description
    ref={ref}
    className={cn("text-sm text-muted-foreground", className)}
    {...props}
  />
))
AlertDialogDescription.displayName =
  AlertDialogPrimitive.Description.displayName

const AlertDialogAction = React.forwardRef<
  React.ElementRef<typeof AlertDialogPrimitive.Action>,
  React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
>(({ className, ...props }, ref) => (
  <AlertDialogPrimitive.Action
    ref={ref}
    className={cn(buttonVariants(), className)}
    {...props}
  />
))
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName

const AlertDialogCancel = React.forwardRef<
  React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
  React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
>(({ className, ...props }, ref) => (
  <AlertDialogPrimitive.Cancel
    ref={ref}
    className={cn(
      buttonVariants({ variant: "outline" }),
      "mt-2 sm:mt-0",
      className
    )}
    {...props}
  />
))
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName

export {
  AlertDialog,
  AlertDialogPortal,
  AlertDialogOverlay,
  AlertDialogTrigger,
  AlertDialogContent,
  AlertDialogHeader,
  AlertDialogFooter,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogAction,
  AlertDialogCancel,
}


FILE: src/components/ui/alert.tsx

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<HTMLDivElement> & VariantProps<typeof alertVariants>
>(({ className, variant, ...props }, ref) => (
  <div
    ref={ref}
    role="alert"
    className={cn(alertVariants({ variant }), className)}
    {...props}
  />
))
Alert.displayName = "Alert"

const AlertTitle = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
  <h5
    ref={ref}
    className={cn("mb-1 font-medium leading-none tracking-tight", className)}
    {...props}
  />
))
AlertTitle.displayName = "AlertTitle"

const AlertDescription = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("text-sm [&_p]:leading-relaxed", className)}
    {...props}
  />
))
AlertDescription.displayName = "AlertDescription"

export { Alert, AlertTitle, AlertDescription }


FILE: src/components/ui/avatar.tsx

"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<typeof AvatarPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
>(({ className, ...props }, ref) => (
  <AvatarPrimitive.Root
    ref={ref}
    className={cn(
      "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
      className
    )}
    {...props}
  />
))
Avatar.displayName = AvatarPrimitive.Root.displayName

const AvatarImage = React.forwardRef<
  React.ElementRef<typeof AvatarPrimitive.Image>,
  React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
>(({ className, ...props }, ref) => (
  <AvatarPrimitive.Image
    ref={ref}
    className={cn("aspect-square h-full w-full", className)}
    {...props}
  />
))
AvatarImage.displayName = AvatarPrimitive.Image.displayName

const AvatarFallback = React.forwardRef<
  React.ElementRef<typeof AvatarPrimitive.Fallback>,
  React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
>(({ className, ...props }, ref) => (
  <AvatarPrimitive.Fallback
    ref={ref}
    className={cn(
      "flex h-full w-full items-center justify-center rounded-full bg-muted",
      className
    )}
    {...props}
  />
))
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName

export { Avatar, AvatarImage, AvatarFallback }


FILE: src/components/ui/badge.tsx

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<HTMLDivElement>,
    VariantProps<typeof badgeVariants> {}

function Badge({ className, variant, ...props }: BadgeProps) {
  return (
    <div className={cn(badgeVariants({ variant }), className)} {...props} />
  )
}

export { Badge, badgeVariants }


FILE: src/components/ui/button.tsx

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<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : "button"
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    )
  }
)
Button.displayName = "Button"

export { Button, buttonVariants }


FILE: src/components/ui/calendar.tsx

"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<typeof DayPicker>

function Calendar({
  className,
  classNames,
  showOutsideDays = true,
  ...props
}: CalendarProps) {
  return (
    <DayPicker
      showOutsideDays={showOutsideDays}
      className={cn("p-3", className)}
      classNames={{
        months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
        month: "space-y-4",
        caption: "flex justify-center pt-1 relative items-center",
        caption_label: "text-sm font-medium",
        nav: "space-x-1 flex items-center",
        nav_button: cn(
          buttonVariants({ variant: "outline" }),
          "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
        ),
        nav_button_previous: "absolute left-1",
        nav_button_next: "absolute right-1",
        table: "w-full border-collapse space-y-1",
        head_row: "flex",
        head_cell:
          "text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
        row: "flex w-full mt-2",
        cell: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
        day: cn(
          buttonVariants({ variant: "ghost" }),
          "h-9 w-9 p-0 font-normal aria-selected:opacity-100"
        ),
        day_range_end: "day-range-end",
        day_selected:
          "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
        day_today: "bg-accent text-accent-foreground",
        day_outside:
          "day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground",
        day_disabled: "text-muted-foreground opacity-50",
        day_range_middle:
          "aria-selected:bg-accent aria-selected:text-accent-foreground",
        day_hidden: "invisible",
        ...classNames,
      }}
      components={{
        IconLeft: ({ className, ...props }) => (
          <ChevronLeft className={cn("h-4 w-4", className)} {...props} />
        ),
        IconRight: ({ className, ...props }) => (
          <ChevronRight className={cn("h-4 w-4", className)} {...props} />
        ),
      }}
      {...props}
    />
  )
}
Calendar.displayName = "Calendar"

export { Calendar }


FILE: src/components/ui/card.tsx

import * as React from "react"

import { cn } from "@/lib/utils"

const Card = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn(
      "rounded-lg border bg-card text-card-foreground shadow-sm",
      className
    )}
    {...props}
  />
))
Card.displayName = "Card"

const CardHeader = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("flex flex-col space-y-1.5 p-6", className)}
    {...props}
  />
))
CardHeader.displayName = "CardHeader"

const CardTitle = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn(
      "text-2xl font-semibold leading-none tracking-tight",
      className
    )}
    {...props}
  />
))
CardTitle.displayName = "CardTitle"

const CardDescription = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("text-sm text-muted-foreground", className)}
    {...props}
  />
))
CardDescription.displayName = "CardDescription"

const CardContent = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"

const CardFooter = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn("flex items-center p-6 pt-0", className)}
    {...props}
  />
))
CardFooter.displayName = "CardFooter"

export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }


"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<typeof useEmblaCarousel>
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<typeof useEmblaCarousel>[0]
  api: ReturnType<typeof useEmblaCarousel>[1]
  scrollPrev: () => void
  scrollNext: () => void
  canScrollPrev: boolean
  canScrollNext: boolean
} & CarouselProps

const CarouselContext = React.createContext<CarouselContextProps | null>(null)

function useCarousel() {
  const context = React.useContext(CarouselContext)

  if (!context) {
    throw new Error("useCarousel must be used within a <Carousel />")
  }

  return context
}

const Carousel = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement> & 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<HTMLDivElement>) => {
        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 (
      <CarouselContext.Provider
        value={{
          carouselRef,
          api: api,
          opts,
          orientation:
            orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
          scrollPrev,
          scrollNext,
          canScrollPrev,
          canScrollNext,
        }}
      >
        <div
          ref={ref}
          onKeyDownCapture={handleKeyDown}
          className={cn("relative", className)}
          role="region"
          aria-roledescription="carousel"
          {...props}
        >
          {children}
        </div>
      </CarouselContext.Provider>
    )
  }
)
Carousel.displayName = "Carousel"

const CarouselContent = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
  const { carouselRef, orientation } = useCarousel()

  return (
    <div ref={carouselRef} className="overflow-hidden">
      <div
        ref={ref}
        className={cn(
          "flex",
          orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
          className
        )}
        {...props}
      />
    </div>
  )
})
CarouselContent.displayName = "CarouselContent"

const CarouselItem = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
  const { orientation } = useCarousel()

  return (
    <div
      ref={ref}
      role="group"
      aria-roledescription="slide"
      className={cn(
        "min-w-0 shrink-0 grow-0 basis-full",
        orientation === "horizontal" ? "pl-4" : "pt-4",
        className
      )}
      {...props}
    />
  )
})
CarouselItem.displayName = "CarouselItem"

const CarouselPrevious = React.forwardRef<
  HTMLButtonElement,
  React.ComponentProps<typeof Button>
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
  const { orientation, scrollPrev, canScrollPrev } = useCarousel()

  return (
    <Button
      ref={ref}
      variant={variant}
      size={size}
      className={cn(
        "absolute  h-8 w-8 rounded-full",
        orientation === "horizontal"
          ? "-left-12 top-1/2 -translate-y-1/2"
          : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
        className
      )}
      disabled={!canScrollPrev}
      onClick={scrollPrev}
      {...props}
    >
      <ArrowLeft className="h-4 w-4" />
      <span className="sr-only">Previous slide</span>
    </Button>
  )
})
CarouselPrevious.displayName = "CarouselPrevious"

const CarouselNext = React.forwardRef<
  HTMLButtonElement,
  React.ComponentProps<typeof Button>
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
  const { orientation, scrollNext, canScrollNext } = useCarousel()

  return (
    <Button
      ref={ref}
      variant={variant}
      size={size}
      className={cn(
        "absolute h-8 w-8 rounded-full",
        orientation === "horizontal"
          ? "-right-12 top-1/2 -translate-y-1/2"
          : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
        className
      )}
      disabled={!canScrollNext}
      onClick={scrollNext}
      {...props}
    >
      <ArrowRight className="h-4 w-4" />
      <span className="sr-only">Next slide</span>
    </Button>
  )
})
CarouselNext.displayName = "CarouselNext"

export {
  type CarouselApi,
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselPrevious,
  CarouselNext,
}


FILE: src/components/ui/chart.tsx

"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<keyof typeof THEMES, string> }
  )
}

type ChartContextProps = {
  config: ChartConfig
}

const ChartContext = React.createContext<ChartContextProps | null>(null)

function useChart() {
  const context = React.useContext(ChartContext)

  if (!context) {
    throw new Error("useChart must be used within a <ChartContainer />")
  }

  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 (
    <ChartContext.Provider value={{ config }}>
      <div
        data-chart={chartId}
        ref={ref}
        className={cn(
          "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
          className
        )}
        {...props}
      >
        <ChartStyle id={chartId} config={config} />
        <RechartsPrimitive.ResponsiveContainer>
          {children}
        </RechartsPrimitive.ResponsiveContainer>
      </div>
    </ChartContext.Provider>
  )
})
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 (
    <style
      dangerouslySetInnerHTML={{
        __html: Object.entries(THEMES)
          .map(
            ([theme, prefix]) => `
${prefix} [data-chart=${id}] {
${colorConfig
  .map(([key, itemConfig]) => {
    const color =
      itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
      itemConfig.color
    return color ? `  --color-${key}: ${color};` : null
  })
  .join("\n")}
}
`
          )
          .join("\n"),
      }}
    />
  )
}

const ChartTooltip = RechartsPrimitive.Tooltip

const ChartTooltipContent = React.forwardRef<
  HTMLDivElement,
  React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
    React.ComponentProps<"div"> & {
      hideLabel?: boolean
      hideIndicator?: boolean
      indicator?: "line" | "dot" | "dashed"
      nameKey?: string
      labelKey?: string
    }
>(
  (
    {
      active,
      payload,
      className,
      indicator = "dot",
      hideLabel = false,
      hideIndicator = false,
      label,
      labelFormatter,
      labelClassName,
      formatter,
      color,
      nameKey,
      labelKey,
    },
    ref
  ) => {
    const { config } = useChart()

    const tooltipLabel = React.useMemo(() => {
      if (hideLabel || !payload?.length) {
        return null
      }

      const [item] = payload
      const key = `${labelKey || item.dataKey || item.name || "value"}`
      const itemConfig = getPayloadConfigFromPayload(config, item, key)
      const value =
        !labelKey && typeof label === "string"
          ? config[label as keyof typeof config]?.label || label
          : itemConfig?.label

      if (labelFormatter) {
        return (
          <div className={cn("font-medium", labelClassName)}>
            {labelFormatter(value, payload)}
          </div>
        )
      }

      if (!value) {
        return null
      }

      return <div className={cn("font-medium", labelClassName)}>{value}</div>
    }, [
      label,
      labelFormatter,
      payload,
      hideLabel,
      labelClassName,
      config,
      labelKey,
    ])

    if (!active || !payload?.length) {
      return null
    }

    const nestLabel = payload.length === 1 && indicator !== "dot"

    return (
      <div
        ref={ref}
        className={cn(
          "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
          className
        )}
      >
        {!nestLabel ? tooltipLabel : null}
        <div className="grid gap-1.5">
          {payload.map((item, index) => {
            const key = `${nameKey || item.name || item.dataKey || "value"}`
            const itemConfig = getPayloadConfigFromPayload(config, item, key)
            const indicatorColor = color || item.payload.fill || item.color

            return (
              <div
                key={item.dataKey}
                className={cn(
                  "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
                  indicator === "dot" && "items-center"
                )}
              >
                {formatter && item?.value !== undefined && item.name ? (
                  formatter(item.value, item.name, item, index, item.payload)
                ) : (
                  <>
                    {itemConfig?.icon ? (
                      <itemConfig.icon />
                    ) : (
                      !hideIndicator && (
                        <div
                          className={cn(
                            "shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
                            {
                              "h-2.5 w-2.5": indicator === "dot",
                              "w-1": indicator === "line",
                              "w-0 border-[1.5px] border-dashed bg-transparent":
                                indicator === "dashed",
                              "my-0.5": nestLabel && indicator === "dashed",
                            }
                          )}
                          style={
                            {
                              "--color-bg": indicatorColor,
                              "--color-border": indicatorColor,
                            } as React.CSSProperties
                          }
                        />
                      )
                    )}
                    <div
                      className={cn(
                        "flex flex-1 justify-between leading-none",
                        nestLabel ? "items-end" : "items-center"
                      )}
                    >
                      <div className="grid gap-1.5">
                        {nestLabel ? tooltipLabel : null}
                        <span className="text-muted-foreground">
                          {itemConfig?.label || item.name}
                        </span>
                      </div>
                      {item.value && (
                        <span className="font-mono font-medium tabular-nums text-foreground">
                          {item.value.toLocaleString()}
                        </span>
                      )}
                    </div>
                  </>
                )}
              </div>
            )
          })}
        </div>
      </div>
    )
  }
)
ChartTooltipContent.displayName = "ChartTooltip"

const ChartLegend = RechartsPrimitive.Legend

const ChartLegendContent = React.forwardRef<
  HTMLDivElement,
  React.ComponentProps<"div"> &
    Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
      hideIcon?: boolean
      nameKey?: string
    }
>(
  (
    { className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
    ref
  ) => {
    const { config } = useChart()

    if (!payload?.length) {
      return null
    }

    return (
      <div
        ref={ref}
        className={cn(
          "flex items-center justify-center gap-4",
          verticalAlign === "top" ? "pb-3" : "pt-3",
          className
        )}
      >
        {payload.map((item) => {
          const key = `${nameKey || item.dataKey || "value"}`
          const itemConfig = getPayloadConfigFromPayload(config, item, key)

          return (
            <div
              key={item.value}
              className={cn(
                "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
              )}
            >
              {itemConfig?.icon && !hideIcon ? (
                <itemConfig.icon />
              ) : (
                <div
                  className="h-2 w-2 shrink-0 rounded-[2px]"
                  style={{
                    backgroundColor: item.color,
                  }}
                />
              )}
              {itemConfig?.label}
            </div>
          )
        })}
      </div>
    )
  }
)
ChartLegendContent.displayName = "ChartLegend"

// Helper to extract item config from a payload.
function getPayloadConfigFromPayload(
  config: ChartConfig,
  payload: unknown,
  key: string
) {
  if (typeof payload !== "object" || payload === null) {
    return undefined
  }

  const payloadPayload =
    "payload" in payload &&
    typeof payload.payload === "object" &&
    payload.payload !== null
      ? payload.payload
      : undefined

  let configLabelKey: string = key

  if (
    key in payload &&
    typeof payload[key as keyof typeof payload] === "string"
  ) {
    configLabelKey = payload[key as keyof typeof payload] as string
  } else if (
    payloadPayload &&
    key in payloadPayload &&
    typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
  ) {
    configLabelKey = payloadPayload[
      key as keyof typeof payloadPayload
    ] as string
  }

  return configLabelKey in config
    ? config[configLabelKey]
    : config[key as keyof typeof config]
}

export {
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  ChartLegend,
  ChartLegendContent,
  ChartStyle,
}


FILE: src/components/ui/checkbox.tsx

"use client"

import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { Check } from "lucide-react"

import { cn } from "@/lib/utils"

const Checkbox = React.forwardRef<
  React.ElementRef<typeof CheckboxPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, ...props }, ref) => (
  <CheckboxPrimitive.Root
    ref={ref}
    className={cn(
      "peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
      className
    )}
    {...props}
  >
    <CheckboxPrimitive.Indicator
      className={cn("flex items-center justify-center text-current")}
    >
      <Check className="h-4 w-4" />
    </CheckboxPrimitive.Indicator>
  </CheckboxPrimitive.Root>
))
Checkbox.displayName = CheckboxPrimitive.Root.displayName

export { Checkbox }


FILE: src/components/ui/collapsible.tsx

"use client"

import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"

const Collapsible = CollapsiblePrimitive.Root

const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger

const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent

export { Collapsible, CollapsibleTrigger, CollapsibleContent }


FILE: src/components/ui/dialog.tsx

"use client"

import * as React from "react"
import * as DialogPrimitive from "@radix-ui/react-dialog"
import { X } from "lucide-react"

import { cn } from "@/lib/utils"

const Dialog = DialogPrimitive.Root

const DialogTrigger = DialogPrimitive.Trigger

const DialogPortal = DialogPrimitive.Portal

const DialogClose = DialogPrimitive.Close

const DialogOverlay = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Overlay>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
  <DialogPrimitive.Overlay
    ref={ref}
    className={cn(
      "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
      className
    )}
    {...props}
  />
))
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName

const DialogContent = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
  <DialogPortal>
    <DialogOverlay />
    <DialogPrimitive.Content
      ref={ref}
      className={cn(
        "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
        className
      )}
      {...props}
    >
      {children}
      <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
        <X className="h-4 w-4" />
        <span className="sr-only">Close</span>
      </DialogPrimitive.Close>
    </DialogPrimitive.Content>
  </DialogPortal>
))
DialogContent.displayName = DialogPrimitive.Content.displayName

const DialogHeader = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div
    className={cn(
      "flex flex-col space-y-1.5 text-center sm:text-left",
      className
    )}
    {...props}
  />
)
DialogHeader.displayName = "DialogHeader"

const DialogFooter = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div
    className={cn(
      "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
      className
    )}
    {...props}
  />
)
DialogFooter.displayName = "DialogFooter"

const DialogTitle = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Title>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
  <DialogPrimitive.Title
    ref={ref}
    className={cn(
      "text-lg font-semibold leading-none tracking-tight",
      className
    )}
    {...props}
  />
))
DialogTitle.displayName = DialogPrimitive.Title.displayName

const DialogDescription = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Description>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
  <DialogPrimitive.Description
    ref={ref}
    className={cn("text-sm text-muted-foreground", className)}
    {...props}
  />
))
DialogDescription.displayName = DialogPrimitive.Description.displayName

export {
  Dialog,
  DialogPortal,
  DialogOverlay,
  DialogClose,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogFooter,
  DialogTitle,
  DialogDescription,
}


FILE: src/components/ui/dropdown-menu.tsx

"use client"

import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import { Check, ChevronRight, Circle } from "lucide-react"

import { cn } from "@/lib/utils"

const DropdownMenu = DropdownMenuPrimitive.Root

const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger

const DropdownMenuGroup = DropdownMenuPrimitive.Group

const DropdownMenuPortal = DropdownMenuPrimitive.Portal

const DropdownMenuSub = DropdownMenuPrimitive.Sub

const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup

const DropdownMenuSubTrigger = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
    inset?: boolean
  }
>(({ className, inset, children, ...props }, ref) => (
  <DropdownMenuPrimitive.SubTrigger
    ref={ref}
    className={cn(
      "flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
      inset && "pl-8",
      className
    )}
    {...props}
  >
    {children}
    <ChevronRight className="ml-auto" />
  </DropdownMenuPrimitive.SubTrigger>
))
DropdownMenuSubTrigger.displayName =
  DropdownMenuPrimitive.SubTrigger.displayName

const DropdownMenuSubContent = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
>(({ className, ...props }, ref) => (
  <DropdownMenuPrimitive.SubContent
    ref={ref}
    className={cn(
      "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
      className
    )}
    {...props}
  />
))
DropdownMenuSubContent.displayName =
  DropdownMenuPrimitive.SubContent.displayName

const DropdownMenuContent = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
  <DropdownMenuPrimitive.Portal>
    <DropdownMenuPrimitive.Content
      ref={ref}
      sideOffset={sideOffset}
      className={cn(
        "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
        className
      )}
      {...props}
    />
  </DropdownMenuPrimitive.Portal>
))
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName

const DropdownMenuItem = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
    inset?: boolean
  }
>(({ className, inset, ...props }, ref) => (
  <DropdownMenuPrimitive.Item
    ref={ref}
    className={cn(
      "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
      inset && "pl-8",
      className
    )}
    {...props}
  />
))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName

const DropdownMenuCheckboxItem = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
>(({ className, children, checked, ...props }, ref) => (
  <DropdownMenuPrimitive.CheckboxItem
    ref={ref}
    className={cn(
      "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
      className
    )}
    checked={checked}
    {...props}
  >
    <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
      <DropdownMenuPrimitive.ItemIndicator>
        <Check className="h-4 w-4" />
      </DropdownMenuPrimitive.ItemIndicator>
    </span>
    {children}
  </DropdownMenuPrimitive.CheckboxItem>
))
DropdownMenuCheckboxItem.displayName =
  DropdownMenuPrimitive.CheckboxItem.displayName

const DropdownMenuRadioItem = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
  <DropdownMenuPrimitive.RadioItem
    ref={ref}
    className={cn(
      "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
      className
    )}
    {...props}
  >
    <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
      <DropdownMenuPrimitive.ItemIndicator>
        <Circle className="h-2 w-2 fill-current" />
      </DropdownMenuPrimitive.ItemIndicator>
    </span>
    {children}
  </DropdownMenuPrimitive.RadioItem>
))
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName

const DropdownMenuLabel = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.Label>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
    inset?: boolean
  }
>(({ className, inset, ...props }, ref) => (
  <DropdownMenuPrimitive.Label
    ref={ref}
    className={cn(
      "px-2 py-1.5 text-sm font-semibold",
      inset && "pl-8",
      className
    )}
    {...props}
  />
))
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName

const DropdownMenuSeparator = React.forwardRef<
  React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
  <DropdownMenuPrimitive.Separator
    ref={ref}
    className={cn("-mx-1 my-1 h-px bg-muted", className)}
    {...props}
  />
))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName

const DropdownMenuShortcut = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
  return (
    <span
      className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
      {...props}
    />
  )
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"

export {
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuCheckboxItem,
  DropdownMenuRadioItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuShortcut,
  DropdownMenuGroup,
  DropdownMenuPortal,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuRadioGroup,
}


FILE: src/components/ui/form.tsx

"use client"

import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { Slot } from "@radix-ui/react-slot"
import {
  Controller,
  FormProvider,
  useFormContext,
  type ControllerProps,
  type FieldPath,
  type FieldValues,
} from "react-hook-form"

import { cn } from "@/lib/utils"
import { Label } from "@/components/ui/label"

const Form = FormProvider

type FormFieldContextValue<
  TFieldValues extends FieldValues = FieldValues,
  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
> = {
  name: TName
}

const FormFieldContext = React.createContext<FormFieldContextValue>(
  {} as FormFieldContextValue
)

const FormField = <
  TFieldValues extends FieldValues = FieldValues,
  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
>({
  ...props
}: ControllerProps<TFieldValues, TName>) => {
  return (
    <FormFieldContext.Provider value={{ name: props.name }}>
      <Controller {...props} />
    </FormFieldContext.Provider>
  )
}

const useFormField = () => {
  const fieldContext = React.useContext(FormFieldContext)
  const itemContext = React.useContext(FormItemContext)
  const { getFieldState, formState } = useFormContext()

  const fieldState = getFieldState(fieldContext.name, formState)

  if (!fieldContext) {
    throw new Error("useFormField should be used within <FormField>")
  }

  const { id } = itemContext

  return {
    id,
    name: fieldContext.name,
    formItemId: `${id}-form-item`,
    formDescriptionId: `${id}-form-item-description`,
    formMessageId: `${id}-form-item-message`,
    ...fieldState,
  }
}

type FormItemContextValue = {
  id: string
}

const FormItemContext = React.createContext<FormItemContextValue>(
  {} as FormItemContextValue
)

const FormItem = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
  const id = React.useId()

  return (
    <FormItemContext.Provider value={{ id }}>
      <div ref={ref} className={cn("space-y-2", className)} {...props} />
    </FormItemContext.Provider>
  )
})
FormItem.displayName = "FormItem"

const FormLabel = React.forwardRef<
  React.ElementRef<typeof LabelPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => {
  const { error, formItemId } = useFormField()

  return (
    <Label
      ref={ref}
      className={cn(error && "text-destructive", className)}
      htmlFor={formItemId}
      {...props}
    />
  )
})
FormLabel.displayName = "FormLabel"

const FormControl = React.forwardRef<
  React.ElementRef<typeof Slot>,
  React.ComponentPropsWithoutRef<typeof Slot>
>(({ ...props }, ref) => {
  const { error, formItemId, formDescriptionId, formMessageId } = useFormField()

  return (
    <Slot
      ref={ref}
      id={formItemId}
      aria-describedby={
        !error
          ? `${formDescriptionId}`
          : `${formDescriptionId} ${formMessageId}`
      }
      aria-invalid={!!error}
      {...props}
    />
  )
})
FormControl.displayName = "FormControl"

const FormDescription = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => {
  const { formDescriptionId } = useFormField()

  return (
    <p
      ref={ref}
      id={formDescriptionId}
      className={cn("text-sm text-muted-foreground", className)}
      {...props}
    />
  )
})
FormDescription.displayName = "FormDescription"

const FormMessage = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLParagraphElement>
>(({ className, children, ...props }, ref) => {
  const { error, formMessageId } = useFormField()
  const body = error ? String(error?.message ?? "") : children

  if (!body) {
    return null
  }

  return (
    <p
      ref={ref}
      id={formMessageId}
      className={cn("text-sm font-medium text-destructive", className)}
      {...props}
    >
      {body}
    </p>
  )
})
FormMessage.displayName = "FormMessage"

export {
  useFormField,
  Form,
  FormItem,
  FormLabel,
  FormControl,
  FormDescription,
  FormMessage,
  FormField,
}


FILE: src/components/ui/input.tsx

import * as React from "react"

import { cn } from "@/lib/utils"

const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
  ({ className, type, ...props }, ref) => {
    return (
      <input
        type={type}
        className={cn(
          "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
          className
        )}
        ref={ref}
        {...props}
      />
    )
  }
)
Input.displayName = "Input"

export { Input }


FILE: src/components/ui/label.tsx

"use client"

import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const labelVariants = cva(
  "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)

const Label = React.forwardRef<
  React.ElementRef<typeof LabelPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
    VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
  <LabelPrimitive.Root
    ref={ref}
    className={cn(labelVariants(), className)}
    {...props}
  />
))
Label.displayName = LabelPrimitive.Root.displayName

export { Label }


FILE: src/components/ui/menubar.tsx

"use client"

import * as React from "react"
import * as MenubarPrimitive from "@radix-ui/react-menubar"
import { Check, ChevronRight, Circle } from "lucide-react"

import { cn } from "@/lib/utils"

function MenubarMenu({
  ...props
}: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
  return <MenubarPrimitive.Menu {...props} />
}

function MenubarGroup({
  ...props
}: React.ComponentProps<typeof MenubarPrimitive.Group>) {
  return <MenubarPrimitive.Group {...props} />
}

function MenubarPortal({
  ...props
}: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
  return <MenubarPrimitive.Portal {...props} />
}

function MenubarRadioGroup({
  ...props
}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
  return <MenubarPrimitive.RadioGroup {...props} />
}

function MenubarSub({
  ...props
}: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
  return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />
}

const Menubar = React.forwardRef<
  React.ElementRef<typeof MenubarPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>
>(({ className, ...props }, ref) => (
  <MenubarPrimitive.Root
    ref={ref}
    className={cn(
      "flex h-10 items-center space-x-1 rounded-md border bg-background p-1",
      className
    )}
    {...props}
  />
))
Menubar.displayName = MenubarPrimitive.Root.displayName

const MenubarTrigger = React.forwardRef<
  React.ElementRef<typeof MenubarPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>
>(({ className, ...props }, ref) => (
  <MenubarPrimitive.Trigger
    ref={ref}
    className={cn(
      "flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
      className
    )}
    {...props}
  />
))
MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName

const MenubarSubTrigger = React.forwardRef<
  React.ElementRef<typeof MenubarPrimitive.SubTrigger>,
  React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & {
    inset?: boolean
  }
>(({ className, inset, children, ...props }, ref) => (
  <MenubarPrimitive.SubTrigger
    ref={ref}
    className={cn(
      "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
      inset && "pl-8",
      className
    )}
    {...props}
  >
    {children}
    <ChevronRight className="ml-auto h-4 w-4" />
  </MenubarPrimitive.SubTrigger>
))
MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName

const MenubarSubContent = React.forwardRef<
  React.ElementRef<typeof MenubarPrimitive.SubContent>,
  React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubContent>
>(({ className, ...props }, ref) => (
  <MenubarPrimitive.SubContent
    ref={ref}
    className={cn(
      "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
      className
    )}
    {...props}
  />
))
MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName

const MenubarContent = React.forwardRef<
  React.ElementRef<typeof MenubarPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>
>(
  (
    { className, align = "start", alignOffset = -4, sideOffset = 8, ...props },
    ref
  ) => (
    <MenubarPrimitive.Portal>
      <MenubarPrimitive.Content
        ref={ref}
        align={align}
        alignOffset={alignOffset}
        sideOffset={sideOffset}
        className={cn(
          "z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
          className
        )}
        {...props}
      />
    </MenubarPrimitive.Portal>
  )
)
MenubarContent.displayName = MenubarPrimitive.Content.displayName

const MenubarItem = React.forwardRef<
  React.ElementRef<typeof MenubarPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {
    inset?: boolean
  }
>(({ className, inset, ...props }, ref) => (
  <MenubarPrimitive.Item
    ref={ref}
    className={cn(
      "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
      inset && "pl-8",
      className
    )}
    {...props}
  />
))
MenubarItem.displayName = MenubarPrimitive.Item.displayName

const MenubarCheckboxItem = React.forwardRef<
  React.ElementRef<typeof MenubarPrimitive.CheckboxItem>,
  React.ComponentPropsWithoutRef<typeof MenubarPrimitive.CheckboxItem>
>(({ className, children, checked, ...props }, ref) => (
  <MenubarPrimitive.CheckboxItem
    ref={ref}
    className={cn(
      "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
      className
    )}
    checked={checked}
    {...props}
  >
    <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
      <MenubarPrimitive.ItemIndicator>
        <Check className="h-4 w-4" />
      </MenubarPrimitive.ItemIndicator>
    </span>
    {children}
  </MenubarPrimitive.CheckboxItem>
))
MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName

const MenubarRadioItem = React.forwardRef<
  React.ElementRef<typeof MenubarPrimitive.RadioItem>,
  React.ComponentPropsWithoutRef<typeof MenubarPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
  <MenubarPrimitive.RadioItem
    ref={ref}
    className={cn(
      "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
      className
    )}
    {...props}
  >
    <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
      <MenubarPrimitive.ItemIndicator>
        <Circle className="h-2 w-2 fill-current" />
      </MenubarPrimitive.ItemIndicator>
    </span>
    {children}
  </MenubarPrimitive.RadioItem>
))
MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName

const MenubarLabel = React.forwardRef<
  React.ElementRef<typeof MenubarPrimitive.Label>,
  React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & {
    inset?: boolean
  }
>(({ className, inset, ...props }, ref) => (
  <MenubarPrimitive.Label
    ref={ref}
    className={cn(
      "px-2 py-1.5 text-sm font-semibold",
      inset && "pl-8",
      className
    )}
    {...props}
  />
))
MenubarLabel.displayName = MenubarPrimitive.Label.displayName

const MenubarSeparator = React.forwardRef<
  React.ElementRef<typeof MenubarPrimitive.Separator>,
  React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>
>(({ className, ...props }, ref) => (
  <MenubarPrimitive.Separator
    ref={ref}
    className={cn("-mx-1 my-1 h-px bg-muted", className)}
    {...props}
  />
))
MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName

const MenubarShortcut = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
  return (
    <span
      className={cn(
        "ml-auto text-xs tracking-widest text-muted-foreground",
        className
      )}
      {...props}
    />
  )
}
MenubarShortcut.displayname = "MenubarShortcut"

export {
  Menubar,
  MenubarMenu,
  MenubarTrigger,
  MenubarContent,
  MenubarItem,
  MenubarSeparator,
  MenubarLabel,
  MenubarCheckboxItem,
  MenubarRadioGroup,
  MenubarRadioItem,
  MenubarPortal,
  MenubarSubContent,
  MenubarSubTrigger,
  MenubarGroup,
  MenubarSub,
  MenubarShortcut,
}


FILE: src/components/ui/popover.tsx

"use client"

import * as React from "react"
import * as PopoverPrimitive from "@radix-ui/react-popover"

import { cn } from "@/lib/utils"

const Popover = PopoverPrimitive.Root

const PopoverTrigger = PopoverPrimitive.Trigger

const PopoverContent = React.forwardRef<
  React.ElementRef<typeof PopoverPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
  <PopoverPrimitive.Portal>
    <PopoverPrimitive.Content
      ref={ref}
      align={align}
      sideOffset={sideOffset}
      className={cn(
        "z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
        className
      )}
      {...props}
    />
  </PopoverPrimitive.Portal>
))
PopoverContent.displayName = PopoverPrimitive.Content.displayName

export { Popover, PopoverTrigger, PopoverContent }


FILE: src/components/ui/progress.tsx

"use client"

import * as React from "react"
import * as ProgressPrimitive from "@radix-ui/react-progress"

import { cn } from "@/lib/utils"

const Progress = React.forwardRef<
  React.ElementRef<typeof ProgressPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
>(({ className, value, ...props }, ref) => (
  <ProgressPrimitive.Root
    ref={ref}
    className={cn(
      "relative h-4 w-full overflow-hidden rounded-full bg-secondary",
      className
    )}
    {...props}
  >
    <ProgressPrimitive.Indicator
      className="h-full w-full flex-1 bg-primary transition-all"
      style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
    />
  </ProgressPrimitive.Root>
))
Progress.displayName = ProgressPrimitive.Root.displayName

export { Progress }


FILE: src/components/ui/radio-group.tsx

"use client"

import * as React from "react"
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
import { Circle } from "lucide-react"

import { cn } from "@/lib/utils"

const RadioGroup = React.forwardRef<
  React.ElementRef<typeof RadioGroupPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
>(({ className, ...props }, ref) => {
  return (
    <RadioGroupPrimitive.Root
      className={cn("grid gap-2", className)}
      {...props}
      ref={ref}
    />
  )
})
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName

const RadioGroupItem = React.forwardRef<
  React.ElementRef<typeof RadioGroupPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
>(({ className, ...props }, ref) => {
  return (
    <RadioGroupPrimitive.Item
      ref={ref}
      className={cn(
        "aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
        className
      )}
      {...props}
    >
      <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
        <Circle className="h-2.5 w-2.5 fill-current text-current" />
      </RadioGroupPrimitive.Indicator>
    </RadioGroupPrimitive.Item>
  )
})
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName

export { RadioGroup, RadioGroupItem }


FILE: src/components/ui/resizable.tsx

"use client";

import { cn } from "@/lib/utils";
import { GripVertical } from "lucide-react";
import * as React from "react";

type Direction = "horizontal" | "vertical";

type ResizablePanelGroupContextType = {
  direction: Direction;
  sizes: number[];
  setSizes: (sizes: number[]) => void;
  minSizes: number[];
  maxSizes: number[];
};

const ResizablePanelGroupContext = React.createContext<ResizablePanelGroupContextType | null>(null);

const useResizablePanelGroup = () => {
  const context = React.useContext(ResizablePanelGroupContext);
  if (!context) {
    throw new Error("useResizablePanelGroup must be used within a ResizablePanelGroup");
  }
  return context;
};

export const ResizablePanelGroup = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement> & {
    direction: Direction;
  }
>(({ direction, children, className, ...props }, ref) => {
  const [sizes, setSizes] = React.useState<number[]>([]);
  const [minSizes, setMinSizes] = React.useState<number[]>([]);
  const [maxSizes, setMaxSizes] = React.useState<number[]>([]);

  React.useEffect(() => {
    const panels = React.Children.toArray(children).filter(
      (child) => React.isValidElement(child) && child.type === ResizablePanel
    );
    const panelCount = panels.length;

    if (panelCount > 0) {
      const initialSizes = panels.map(
        (child) => (React.isValidElement(child) && child.props.defaultSize ? child.props.defaultSize : 100 / panelCount)
      );
      
      const sum = initialSizes.reduce((a, b) => a + b, 0);
      
      if (sum > 100.1 || sum < 99.9) {
        const factor = 100 / sum;
        setSizes(initialSizes.map(s => s * factor));
      } else {
        setSizes(initialSizes);
      }

      setMinSizes(panels.map(
        (child) => (React.isValidElement(child) ? child.props.minSize || 0 : 0)
      ));
      setMaxSizes(panels.map(
        (child) => (React.isValidElement(child) ? child.props.maxSize || 100 : 100)
      ));
    }
  }, [children]);

  let panelIndex = 0;
  const childrenWithInjectedProps = React.Children.map(children, (child) => {
    if (React.isValidElement(child)) {
      if (child.type === ResizablePanel) {
        const index = panelIndex;
        panelIndex++;
        return React.cloneElement(child, { panelIndex: index });
      }
      if (child.type === ResizableHandle) {
        return React.cloneElement(child, { handleIndex: panelIndex - 1 });
      }
    }
    return child;
  });

  return (
    <ResizablePanelGroupContext.Provider value={{ direction, sizes, setSizes, minSizes, maxSizes }}>
      <div
        ref={ref}
        className={cn(
          "flex w-full h-full",
          direction === "vertical" && "flex-col",
          className
        )}
        {...props}
      >
        {childrenWithInjectedProps}
      </div>
    </ResizablePanelGroupContext.Provider>
  );
});
ResizablePanelGroup.displayName = "ResizablePanelGroup";

export const ResizablePanel = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement> & {
    defaultSize?: number;
    minSize?: number;
    maxSize?: number;
    panelIndex?: number; // Injected prop
  }
>(({ className, children, style, panelIndex, ...props }, ref) => {
  const { direction, sizes } = useResizablePanelGroup();
  const size = (panelIndex !== undefined && sizes[panelIndex]) ? sizes[panelIndex] : undefined;
  
  if (size === undefined) {
    return null;
  }

  return (
    <div
      ref={ref}
      className={cn("overflow-hidden", className)}
      style={{
        ...style,
        flexGrow: size,
        flexShrink: 1,
        flexBasis: 0,
      }}
      {...props}
    >
      {children}
    </div>
  );
});
ResizablePanel.displayName = "ResizablePanel";

export const ResizableHandle = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement> & {
    withHandle?: boolean;
    handleIndex?: number; // Injected prop
  }
>(({ className, withHandle, handleIndex, ...props }, ref) => {
  const { direction, sizes, setSizes, minSizes, maxSizes } = useResizablePanelGroup();
  const [isDragging, setIsDragging] = React.useState(false);
  const handleRef = (ref as React.RefObject<HTMLDivElement>) || React.createRef<HTMLDivElement>();

  const onDrag = React.useCallback(
    (e: MouseEvent | TouchEvent) => {
      if (!isDragging || handleIndex === undefined) return;
      
      const clientX = 'touches' in e ? e.touches[0].clientX : e.clientX;
      const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY;

      const groupElement = handleRef.current?.parentElement;
      if (!groupElement) return;

      const { left, top, width, height } = groupElement.getBoundingClientRect();
      
      const cursorPosition = direction === 'horizontal' ? clientX - left : clientY - top;
      const groupSize = direction === 'horizontal' ? width : height;
      const cursorPercentage = (cursorPosition / groupSize) * 100;
      
      const prevPanelsSize = sizes.slice(0, handleIndex + 1).reduce((sum, s) => sum + s, 0);

      const delta = cursorPercentage - prevPanelsSize;

      let prevPanelSize = sizes[handleIndex];
      let nextPanelSize = sizes[handleIndex + 1];

      let newPrevSize = prevPanelSize + delta;
      let newNextSize = nextPanelSize - delta;

      const minPrev = minSizes[handleIndex];
      const maxPrev = maxSizes[handleIndex];
      const minNext = minSizes[handleIndex + 1];
      const maxNext = maxSizes[handleIndex + 1];
      
      if (newPrevSize < minPrev) {
        newPrevSize = minPrev;
        newNextSize = prevPanelSize + nextPanelSize - newPrevSize;
      } else if (newNextSize < minNext) {
        newNextSize = minNext;
        newPrevSize = prevPanelSize + nextPanelSize - newNextSize;
      } else if (newPrevSize > maxPrev) {
        newPrevSize = maxPrev;
        newNextSize = prevPanelSize + nextPanelSize - newPrevSize;
      } else if (newNextSize > maxNext) {
        newNextSize = maxNext;
        newPrevSize = prevPanelSize + nextPanelSize - newNextSize;
      }

      const newSizes = [...sizes];
      newSizes[handleIndex] = newPrevSize;
      newSizes[handleIndex + 1] = newNextSize;
      
      setSizes(newSizes);
    },
    [isDragging, direction, sizes, handleIndex, setSizes, minSizes, maxSizes, handleRef]
  );
  
  React.useEffect(() => {
    const stopDragging = () => setIsDragging(false);

    const ownerDocument = handleRef.current?.ownerDocument || document;

    if (isDragging) {
      ownerDocument.addEventListener("mousemove", onDrag);
      ownerDocument.addEventListener("touchmove", onDrag);
      ownerDocument.addEventListener("mouseup", stopDragging);
      ownerDocument.addEventListener("touchend", stopDragging);
      ownerDocument.body.style.cursor = direction === 'horizontal' ? 'col-resize' : 'row-resize';
      ownerDocument.body.style.userSelect = 'none';
    }
    
    return () => {
      ownerDocument.removeEventListener("mousemove", onDrag);
      ownerDocument.removeEventListener("touchmove", onDrag);
      ownerDocument.removeEventListener("mouseup", stopDragging);
      ownerDocument.removeEventListener("touchend", stopDragging);
      ownerDocument.body.style.cursor = '';
      ownerDocument.body.style.userSelect = '';
    };
  }, [isDragging, onDrag, direction, handleRef]);

  return (
    <div
      ref={handleRef}
      onMouseDown={(e) => { e.preventDefault(); setIsDragging(true); }}
      onTouchStart={(e) => { e.preventDefault(); setIsDragging(true); }}
      className={cn(
        "relative flex-shrink-0 items-center justify-center bg-transparent transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
        direction === "horizontal"
          ? "w-2 mx-[-1px] cursor-col-resize"
          : "h-2 my-[-1px] cursor-row-resize",
        className
      )}
      {...props}
    >
      <div
        className={cn(
          "z-10 bg-border transition-colors",
          direction === "horizontal" ? "h-full w-[1px]" : "w-full h-[1px]",
          isDragging && "bg-primary"
        )}
      />
      {withHandle && (
        <div className="z-20 absolute flex items-center justify-center rounded-full border bg-card p-1 shadow-sm">
          <GripVertical
            className={cn(
              "h-2.5 w-2.5 text-muted-foreground",
              direction === "vertical" && "rotate-90"
            )}
          />
        </div>
      )}
    </div>
  );
});
ResizableHandle.displayName = "ResizableHandle";


FILE: src/components/ui/scroll-area.tsx

"use client"

import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"

import { cn } from "@/lib/utils"

const ScrollArea = React.forwardRef<
  React.ElementRef<typeof ScrollAreaPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
  <ScrollAreaPrimitive.Root
    ref={ref}
    className={cn("relative overflow-hidden", className)}
    {...props}
  >
    <ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
      {children}
    </ScrollAreaPrimitive.Viewport>
    <ScrollBar />
    <ScrollAreaPrimitive.Corner />
  </ScrollAreaPrimitive.Root>
))
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName

const ScrollBar = React.forwardRef<
  React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
  React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
>(({ className, orientation = "vertical", ...props }, ref) => (
  <ScrollAreaPrimitive.ScrollAreaScrollbar
    ref={ref}
    orientation={orientation}
    className={cn(
      "flex touch-none select-none transition-colors",
      orientation === "vertical" &&
        "h-full w-2.5 border-l border-l-transparent p-[1px]",
      orientation === "horizontal" &&
        "h-2.5 flex-col border-t border-t-transparent p-[1px]",
      className
    )}
    {...props}
  >
    <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
  </ScrollAreaPrimitive.ScrollAreaScrollbar>
))
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName

export { ScrollArea, ScrollBar }


FILE: src/components/ui/select.tsx

"use client"

import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select"
import { Check, ChevronDown, ChevronUp } from "lucide-react"

import { cn } from "@/lib/utils"

const Select = SelectPrimitive.Root

const SelectGroup = SelectPrimitive.Group

const SelectValue = SelectPrimitive.Value

const SelectTrigger = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
  <SelectPrimitive.Trigger
    ref={ref}
    className={cn(
      "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
      className
    )}
    {...props}
  >
    {children}
    <SelectPrimitive.Icon asChild>
      <ChevronDown className="h-4 w-4 opacity-50" />
    </SelectPrimitive.Icon>
  </SelectPrimitive.Trigger>
))
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName

const SelectScrollUpButton = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
  <SelectPrimitive.ScrollUpButton
    ref={ref}
    className={cn(
      "flex cursor-default items-center justify-center py-1",
      className
    )}
    {...props}
  >
    <ChevronUp className="h-4 w-4" />
  </SelectPrimitive.ScrollUpButton>
))
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName

const SelectScrollDownButton = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
  <SelectPrimitive.ScrollDownButton
    ref={ref}
    className={cn(
      "flex cursor-default items-center justify-center py-1",
      className
    )}
    {...props}
  >
    <ChevronDown className="h-4 w-4" />
  </SelectPrimitive.ScrollDownButton>
))
SelectScrollDownButton.displayName =
  SelectPrimitive.ScrollDownButton.displayName

const SelectContent = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
  <SelectPrimitive.Portal>
    <SelectPrimitive.Content
      ref={ref}
      className={cn(
        "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
        position === "popper" &&
          "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
        className
      )}
      position={position}
      {...props}
    >
      <SelectScrollUpButton />
      <SelectPrimitive.Viewport
        className={cn(
          "p-1",
          position === "popper" &&
            "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
        )}
      >
        {children}
      </SelectPrimitive.Viewport>
      <SelectScrollDownButton />
    </SelectPrimitive.Content>
  </SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName

const SelectLabel = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Label>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
  <SelectPrimitive.Label
    ref={ref}
    className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
    {...props}
  />
))
SelectLabel.displayName = SelectPrimitive.Label.displayName

const SelectItem = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
  <SelectPrimitive.Item
    ref={ref}
    className={cn(
      "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
      className
    )}
    {...props}
  >
    <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
      <SelectPrimitive.ItemIndicator>
        <Check className="h-4 w-4" />
      </SelectPrimitive.ItemIndicator>
    </span>

    <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
  </SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName

const SelectSeparator = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Separator>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
  <SelectPrimitive.Separator
    ref={ref}
    className={cn("-mx-1 my-1 h-px bg-muted", className)}
    {...props}
  />
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName

export {
  Select,
  SelectGroup,
  SelectValue,
  SelectTrigger,
  SelectContent,
  SelectLabel,
  SelectItem,
  SelectSeparator,
  SelectScrollUpButton,
  SelectScrollDownButton,
}


FILE: src/components/ui/separator.tsx

"use client"

import * as React from "react"
import * as SeparatorPrimitive from "@radix-ui/react-separator"

import { cn } from "@/lib/utils"

const Separator = React.forwardRef<
  React.ElementRef<typeof SeparatorPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(
  (
    { className, orientation = "horizontal", decorative = true, ...props },
    ref
  ) => (
    <SeparatorPrimitive.Root
      ref={ref}
      decorative={decorative}
      orientation={orientation}
      className={cn(
        "shrink-0 bg-border",
        orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
        className
      )}
      {...props}
    />
  )
)
Separator.displayName = SeparatorPrimitive.Root.displayName

export { Separator }


FILE: src/components/ui/sheet.tsx

"use client"

import * as React from "react"
import * as SheetPrimitive from "@radix-ui/react-dialog"
import { cva, type VariantProps } from "class-variance-authority"
import { X } from "lucide-react"

import { cn } from "@/lib/utils"

const Sheet = SheetPrimitive.Root

const SheetTrigger = SheetPrimitive.Trigger

const SheetClose = SheetPrimitive.Close

const SheetPortal = SheetPrimitive.Portal

const SheetOverlay = React.forwardRef<
  React.ElementRef<typeof SheetPrimitive.Overlay>,
  React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
  <SheetPrimitive.Overlay
    className={cn(
      "fixed inset-0 z-50 bg-black/80  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
      className
    )}
    {...props}
    ref={ref}
  />
))
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName

const sheetVariants = cva(
  "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
  {
    variants: {
      side: {
        top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
        bottom:
          "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
        left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
        right:
          "inset-y-0 right-0 h-full w-3/4  border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
      },
    },
    defaultVariants: {
      side: "right",
    },
  }
)

interface SheetContentProps
  extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
    VariantProps<typeof sheetVariants> {}

const SheetContent = React.forwardRef<
  React.ElementRef<typeof SheetPrimitive.Content>,
  SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
  <SheetPortal>
    <SheetOverlay />
    <SheetPrimitive.Content
      ref={ref}
      className={cn(sheetVariants({ side }), className)}
      {...props}
    >
      {children}
      <SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
        <X className="h-4 w-4" />
        <span className="sr-only">Close</span>
      </SheetPrimitive.Close>
    </SheetPrimitive.Content>
  </SheetPortal>
))
SheetContent.displayName = SheetPrimitive.Content.displayName

const SheetHeader = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div
    className={cn(
      "flex flex-col space-y-2 text-center sm:text-left",
      className
    )}
    {...props}
  />
)
SheetHeader.displayName = "SheetHeader"

const SheetFooter = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => (
  <div
    className={cn(
      "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
      className
    )}
    {...props}
  />
)
SheetFooter.displayName = "SheetFooter"

const SheetTitle = React.forwardRef<
  React.ElementRef<typeof SheetPrimitive.Title>,
  React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
  <SheetPrimitive.Title
    ref={ref}
    className={cn("text-lg font-semibold text-foreground", className)}
    {...props}
  />
))
SheetTitle.displayName = SheetPrimitive.Title.displayName

const SheetDescription = React.forwardRef<
  React.ElementRef<typeof SheetPrimitive.Description>,
  React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
  <SheetPrimitive.Description
    ref={ref}
    className={cn("text-sm text-muted-foreground", className)}
    {...props}
  />
))
SheetDescription.displayName = SheetPrimitive.Description.displayName

export {
  Sheet,
  SheetPortal,
  SheetOverlay,
  SheetTrigger,
  SheetClose,
  SheetContent,
  SheetHeader,
  SheetFooter,
  SheetTitle,
  SheetDescription,
}


FILE: src/components/ui/skeleton.tsx

import { cn } from "@/lib/utils"

function Skeleton({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) {
  return (
    <div
      className={cn("animate-pulse rounded-md bg-muted", className)}
      {...props}
    />
  )
}

export { Skeleton }


FILE: src/components/ui/slider.tsx

"use client"

import * as React from "react"
import * as SliderPrimitive from "@radix-ui/react-slider"

import { cn } from "@/lib/utils"

const Slider = React.forwardRef<
  React.ElementRef<typeof SliderPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, ...props }, ref) => (
  <SliderPrimitive.Root
    ref={ref}
    className={cn(
      "relative flex w-full touch-none select-none items-center",
      className
    )}
    {...props}
  >
    <SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
      <SliderPrimitive.Range className="absolute h-full bg-primary" />
    </SliderPrimitive.Track>
    <SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background 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" />
  </SliderPrimitive.Root>
))
Slider.displayName = SliderPrimitive.Root.displayName

export { Slider }


FILE: src/components/ui/stepper.tsx

"use client";

import * as React from "react";
import { cn } from "@/lib/utils";
import { Check } from "lucide-react";

interface Step {
  label: string;
}

interface StepperProps {
  steps: Step[];
  currentStep: number;
}

export function Stepper({ steps, currentStep }: StepperProps) {
  return (
    <div className="flex w-full items-center justify-center">
      {steps.map((step, index) => {
        const stepNumber = index + 1;
        const isActive = stepNumber === currentStep;
        const isCompleted = stepNumber < currentStep;

        return (
          <React.Fragment key={index}>
            <div className="flex flex-col items-center">
              <div
                className={cn(
                  "flex h-8 w-8 items-center justify-center rounded-full border-2 text-sm font-semibold",
                  isActive
                    ? "border-primary bg-primary text-primary-foreground"
                    : isCompleted
                    ? "border-primary bg-primary text-primary-foreground"
                    : "border-border bg-card"
                )}
              >
                {isCompleted ? <Check className="h-5 w-5" /> : stepNumber}
              </div>
              <p
                className={cn(
                  "mt-2 w-24 text-center text-xs",
                  isActive ? "font-semibold text-primary" : "text-muted-foreground",
                  isCompleted ? "font-semibold" : ""
                )}
              >
                {step.label}
              </p>
            </div>
            {index < steps.length - 1 && (
              <div className="mb-6 h-px w-full flex-1 bg-border" />
            )}
          </React.Fragment>
        );
      })}
    </div>
  );
}


FILE: src/components/ui/switch.tsx

"use client"

import * as React from "react"
import * as SwitchPrimitives from "@radix-ui/react-switch"

import { cn } from "@/lib/utils"

const Switch = React.forwardRef<
  React.ElementRef<typeof SwitchPrimitives.Root>,
  React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
  <SwitchPrimitives.Root
    className={cn(
      "peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
      className
    )}
    {...props}
    ref={ref}
  >
    <SwitchPrimitives.Thumb
      className={cn(
        "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
      )}
    />
  </SwitchPrimitives.Root>
))
Switch.displayName = SwitchPrimitives.Root.displayName

export { Switch }


FILE: src/components/ui/table.tsx

import * as React from "react"

import { cn } from "@/lib/utils"

const Table = React.forwardRef<
  HTMLTableElement,
  React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
  <div className="relative w-full overflow-auto">
    <table
      ref={ref}
      className={cn("w-full caption-bottom text-sm", className)}
      {...props}
    />
  </div>
))
Table.displayName = "Table"

const TableHeader = React.forwardRef<
  HTMLTableSectionElement,
  React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
  <thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
))
TableHeader.displayName = "TableHeader"

const TableBody = React.forwardRef<
  HTMLTableSectionElement,
  React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
  <tbody
    ref={ref}
    className={cn("[&_tr:last-child]:border-0", className)}
    {...props}
  />
))
TableBody.displayName = "TableBody"

const TableFooter = React.forwardRef<
  HTMLTableSectionElement,
  React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
  <tfoot
    ref={ref}
    className={cn(
      "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
      className
    )}
    {...props}
  />
))
TableFooter.displayName = "TableFooter"

const TableRow = React.forwardRef<
  HTMLTableRowElement,
  React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
  <tr
    ref={ref}
    className={cn(
      "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
      className
    )}
    {...props}
  />
))
TableRow.displayName = "TableRow"

const TableHead = React.forwardRef<
  HTMLTableCellElement,
  React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
  <th
    ref={ref}
    className={cn(
      "h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
      className
    )}
    {...props}
  />
))
TableHead.displayName = "TableHead"

const TableCell = React.forwardRef<
  HTMLTableCellElement,
  React.TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
  <td
    ref={ref}
    className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
    {...props}
  />
))
TableCell.displayName = "TableCell"

const TableCaption = React.forwardRef<
  HTMLTableCaptionElement,
  React.HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => (
  <caption
    ref={ref}
    className={cn("mt-4 text-sm text-muted-foreground", className)}
    {...props}
  />
))
TableCaption.displayName = "TableCaption"

export {
  Table,
  TableHeader,
  TableBody,
  TableFooter,
  TableHead,
  TableRow,
  TableCell,
  TableCaption,
}


FILE: src/components/ui/tabs.tsx

"use client"

import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"

import { cn } from "@/lib/utils"

const Tabs = TabsPrimitive.Root

const TabsList = React.forwardRef<
  React.ElementRef<typeof TabsPrimitive.List>,
  React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
  <TabsPrimitive.List
    ref={ref}
    className={cn(
      "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
      className
    )}
    {...props}
  />
))
TabsList.displayName = TabsPrimitive.List.displayName

const TabsTrigger = React.forwardRef<
  React.ElementRef<typeof TabsPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
  <TabsPrimitive.Trigger
    ref={ref}
    className={cn(
      "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
      className
    )}
    {...props}
  />
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName

const TabsContent = React.forwardRef<
  React.ElementRef<typeof TabsPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
  <TabsPrimitive.Content
    ref={ref}
    className={cn(
      "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
      className
    )}
    {...props}
  />
))
TabsContent.displayName = TabsPrimitive.Content.displayName

export { Tabs, TabsList, TabsTrigger, TabsContent }


FILE: src/components/ui/textarea.tsx

import * as React from 'react';

import {cn} from '@/lib/utils';

const Textarea = React.forwardRef<HTMLTextAreaElement, React.ComponentProps<'textarea'>>(
  ({className, ...props}, ref) => {
    return (
      <textarea
        className={cn(
          'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
          className
        )}
        ref={ref}
        {...props}
      />
    );
  }
);
Textarea.displayName = 'Textarea';

export {Textarea};


FILE: src/components/ui/toast.tsx

"use client"

import * as React from "react"
import * as ToastPrimitives from "@radix-ui/react-toast"
import { cva, type VariantProps } from "class-variance-authority"
import { X } from "lucide-react"

import { cn } from "@/lib/utils"

const ToastProvider = ToastPrimitives.Provider

const ToastViewport = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Viewport>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
>(({ className, ...props }, ref) => (
  <ToastPrimitives.Viewport
    ref={ref}
    className={cn(
      "fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
      className
    )}
    {...props}
  />
))
ToastViewport.displayName = ToastPrimitives.Viewport.displayName

const toastVariants = cva(
  "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
  {
    variants: {
      variant: {
        default: "border bg-background text-foreground",
        destructive:
          "destructive group border-destructive bg-destructive text-destructive-foreground",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
)

const Toast = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Root>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
    VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
  return (
    <ToastPrimitives.Root
      ref={ref}
      className={cn(toastVariants({ variant }), className)}
      {...props}
    />
  )
})
Toast.displayName = ToastPrimitives.Root.displayName

const ToastAction = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Action>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
>(({ className, ...props }, ref) => (
  <ToastPrimitives.Action
    ref={ref}
    className={cn(
      "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
      className
    )}
    {...props}
  />
))
ToastAction.displayName = ToastPrimitives.Action.displayName

const ToastClose = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Close>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
>(({ className, ...props }, ref) => (
  <ToastPrimitives.Close
    ref={ref}
    className={cn(
      "absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
      className
    )}
    toast-close=""
    {...props}
  >
    <X className="h-4 w-4" />
  </ToastPrimitives.Close>
))
ToastClose.displayName = ToastPrimitives.Close.displayName

const ToastTitle = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Title>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
>(({ className, ...props }, ref) => (
  <ToastPrimitives.Title
    ref={ref}
    className={cn("text-sm font-semibold", className)}
    {...props}
  />
))
ToastTitle.displayName = ToastPrimitives.Title.displayName

const ToastDescription = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Description>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
>(({ className, ...props }, ref) => (
  <ToastPrimitives.Description
    ref={ref}
    className={cn("text-sm opacity-90", className)}
    {...props}
  />
))
ToastDescription.displayName = ToastPrimitives.Description.displayName

type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>

type ToastActionElement = React.ReactElement<typeof ToastAction>

export {
  type ToastProps,
  type ToastActionElement,
  ToastProvider,
  ToastViewport,
  Toast,
  ToastTitle,
  ToastDescription,
  ToastClose,
  ToastAction,
}


FILE: src/components/ui/toaster.tsx

"use client"

import { useToast } from "@/hooks/use-toast"
import {
  Toast,
  ToastClose,
  ToastDescription,
  ToastProvider,
  ToastTitle,
  ToastViewport,
} from "@/components/ui/toast"

export function Toaster() {
  const { toasts } = useToast()

  return (
    <ToastProvider>
      {toasts.map(function ({ id, title, description, action, ...props }) {
        return (
          <Toast key={id} {...props}>
            <div className="grid gap-1">
              {title && <ToastTitle>{title}</ToastTitle>}
              {description && (
                <ToastDescription>{description}</ToastDescription>
              )}
            </div>
            {action}
            <ToastClose />
          </Toast>
        )
      })}
      <ToastViewport />
    </ToastProvider>
  )
}


FILE: src/components/ui/tooltip.tsx

"use client"

import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"

import { cn } from "@/lib/utils"

const TooltipProvider = TooltipPrimitive.Provider

const Tooltip = TooltipPrimitive.Root

const TooltipTrigger = TooltipPrimitive.Trigger

const TooltipContent = React.forwardRef<
  React.ElementRef<typeof TooltipPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
  <TooltipPrimitive.Content
    ref={ref}
    sideOffset={sideOffset}
    className={cn(
      "z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
      className
    )}
    {...props}
  />
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName

export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }


FILE: src/hooks/use-toast.ts

"use client"

// Inspired by react-hot-toast library
import * as React from "react"

import type {
  ToastActionElement,
  ToastProps,
} from "@/components/ui/toast"

const TOAST_LIMIT = 1
const TOAST_REMOVE_DELAY = 1000000

type ToasterToast = ToastProps & {
  id: string
  title?: React.ReactNode
  description?: React.ReactNode
  action?: ToastActionElement
}

const actionTypes = {
  ADD_TOAST: "ADD_TOAST",
  UPDATE_TOAST: "UPDATE_TOAST",
  DISMISS_TOAST: "DISMISS_TOAST",
  REMOVE_TOAST: "REMOVE_TOAST",
} as const

let count = 0

function genId() {
  count = (count + 1) % Number.MAX_SAFE_INTEGER
  return count.toString()
}

type ActionType = typeof actionTypes

type Action =
  | {
      type: ActionType["ADD_TOAST"]
      toast: ToasterToast
    }
  | {
      type: ActionType["UPDATE_TOAST"]
      toast: Partial<ToasterToast>
    }
  | {
      type: ActionType["DISMISS_TOAST"]
      toastId?: ToasterToast["id"]
    }
  | {
      type: ActionType["REMOVE_TOAST"]
      toastId?: ToasterToast["id"]
    }

interface State {
  toasts: ToasterToast[]
}

const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()

const addToRemoveQueue = (toastId: string) => {
  if (toastTimeouts.has(toastId)) {
    return
  }

  const timeout = setTimeout(() => {
    toastTimeouts.delete(toastId)
    dispatch({
      type: "REMOVE_TOAST",
      toastId: toastId,
    })
  }, TOAST_REMOVE_DELAY)

  toastTimeouts.set(toastId, timeout)
}

export const reducer = (state: State, action: Action): State => {
  switch (action.type) {
    case "ADD_TOAST":
      return {
        ...state,
        toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
      }

    case "UPDATE_TOAST":
      return {
        ...state,
        toasts: state.toasts.map((t) =>
          t.id === action.toast.id ? { ...t, ...action.toast } : t
        ),
      }

    case "DISMISS_TOAST": {
      const { toastId } = action

      // ! Side effects ! - This could be extracted into a dismissToast() action,
      // but I'll keep it here for simplicity
      if (toastId) {
        addToRemoveQueue(toastId)
      } else {
        state.toasts.forEach((toast) => {
          addToRemoveQueue(toast.id)
        })
      }

      return {
        ...state,
        toasts: state.toasts.map((t) =>
          t.id === toastId || toastId === undefined
            ? {
                ...t,
                open: false,
              }
            : t
        ),
      }
    }
    case "REMOVE_TOAST":
      if (action.toastId === undefined) {
        return {
          ...state,
          toasts: [],
        }
      }
      return {
        ...state,
        toasts: state.toasts.filter((t) => t.id !== action.toastId),
      }
  }
}

const listeners: Array<(state: State) => void> = []

let memoryState: State = { toasts: [] }

function dispatch(action: Action) {
  memoryState = reducer(memoryState, action)
  listeners.forEach((listener) => {
    listener(memoryState)
  })
}

type Toast = Omit<ToasterToast, "id">

function toast({ ...props }: Toast) {
  const id = genId()

  const update = (props: ToasterToast) =>
    dispatch({
      type: "UPDATE_TOAST",
      toast: { ...props, id },
    })
  const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })

  dispatch({
    type: "ADD_TOAST",
    toast: {
      ...props,
      id,
      open: true,
      onOpenChange: (open) => {
        if (!open) dismiss()
      },
    },
  })

  return {
    id: id,
    dismiss,
    update,
  }
}

function useToast() {
  const [state, setState] = React.useState<State>(memoryState)

  React.useEffect(() => {
    listeners.push(setState)
    return () => {
      const index = listeners.indexOf(setState)
      if (index > -1) {
        listeners.splice(index, 1)
      }
    }
  }, [state])

  return {
    ...state,
    toast,
    dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
  }
}

export { useToast, toast }


FILE: src/lib/aethex-data.ts

export type FileNode = { name: string; type: "file"; language: string };
export type FolderNode = {
  name: string;
  type: "folder";
  children: (FileNode | FolderNode)[];
};
export type File = {
    id: string;
    name: string;
    language: string;
    content: string;
};
export type { File as OpenFileType };


export const fileTree: FolderNode = {
  name: "aethex-project",
  type: "folder",
  children: [
    {
      name: "roblox",
      type: "folder",
      children: [
        { name: "main.lua", type: "file", language: "lua" },
        { name: "player.lua", type: "file", language: "lua" },
      ],
    },
    {
      name: "web",
      type: "folder",
      children: [
        { name: "index.js", type: "file", language: "javascript" },
        { name: "style.css", type: "file", language: "css" },
      ],
    },
    {
      name: "mobile",
      type: "folder",
      children: [{ name: "App.tsx", type: "file", language: "typescript" }],
    },
    { name: "README.md", type: "file", language: "markdown" },
  ],
};

export const openFiles: File[] = [
  {
    id: "aethex-project/roblox/main.lua",
    name: "main.lua",
    language: "lua",
    content: `-- Roblox main script
local Players = game:GetService("Players")

local function onPlayerAdded(player)
    print("Player " .. player.Name .. " has joined the game.")
    -- Initialize player data
end

Players.PlayerAdded:Connect(onPlayerAdded)
`,
  },
  {
    id: "aethex-project/web/index.js",
    name: "index.js",
    language: "javascript",
    content: `// Web client entry point
document.addEventListener('DOMContentLoaded', () => {
    const app = document.getElementById('app');
    app.innerHTML = '<h1>Welcome to AeThex on the Web!</h1>';
    console.log('Web client initialized.');
});
`,
  },
  {
    id: "aethex-project/mobile/App.tsx",
    name: "App.tsx",
    language: "typescript",
    content: `// React Native App Component
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const App = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>AeThex Mobile</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 24,
  },
});

export default App;
`,
  },
];

export const consoleLogs = [
    { timestamp: "14:02:10.112", platform: "Web", type: "log", message: "Web client initialized." },
    { timestamp: "14:02:10.453", platform: "Roblox", type: "log", message: "Player AeThexDev has joined the game." },
    { timestamp: "14:02:11.231", platform: "Mobile", type: "log", message: "React Native running in development mode." },
    { timestamp: "14:02:15.899", platform: "Roblox", type: "warn", message: "DeprecationWarning: Use 'Task.Wait' instead of 'wait'." },
    { timestamp: "14:02:18.050", platform: "Web", type: "error", message: "Uncaught TypeError: Cannot read properties of null (reading 'innerHTML')" },
    { timestamp: "14:02:20.333", platform: "Mobile", type: "log", message: "User tapped the screen." },
];

export const platformCode = {
  lua: {
    name: "player.lua",
    code: `local PlayerState = {
  position = Vector3.new(0, 5, 0),
  health = 100,
  inventory = {}
}

-- Other Lua code...
`,
  },
  javascript: {
    name: "player.js",
    code: `let playerState = {
  position: { x: 0, y: 5, z: 0 },
  health: 100,
  inventory: []
}

// Other JS code...
`,
  },
  typescript: {
    name: "player.ts",
    code: `interface PlayerState {
  position: { x: number; y: number; z: number };
  health: number;
  inventory: string[];
}

const playerState: PlayerState = {
  position: { x: 0, y: 5, z: 0 },
  health: 100,
  inventory: []
};
// Other RN/TS code...
`,
  },
};

export const sharedState = {
  playerScore: 1250,
  gameTime: "15:32",
  levelName: "CyberCity",
  isActive: true,
};

export const crossPlatformState = [
    { variable: 'playerScore', roblox: 1250, web: 1250, mobile: 1250, status: 'synced' as const },
    { variable: 'gameTime', roblox: '15:32', web: '15:33', mobile: '15:32', status: 'syncing' as const },
    { variable: 'levelName', roblox: 'CyberCity', web: 'CyberCity', mobile: 'CyberCity', status: 'synced' as const },
    { variable: 'isActive', roblox: true, web: true, mobile: true, status: 'synced' as const },
    { variable: 'inventory', roblox: 'table', web: 'any[]', mobile: 'string[]', status: 'conflict' as const },
];


export const aiConflictResolutionSuggestion = {
    conflictDetected: true,
    suggestedSolutions: [
      "In `player.lua`, change `inventory = {}` to an array-like table to match JS/TS.",
      "In `player.js`, add type checks or use a class to ensure `inventory` items are strings like in `player.ts`.",
      "Unify the `position` object/Vector3 structure across all platforms. Suggest using a simple `{x, y, z}` object in the shared state and converting to platform-specific types like `Vector3` within each environment."
    ],
    explanation: "A synchronization conflict was detected in the `inventory` field of the player state. The TypeScript definition expects an array of strings (`string[]`), while the Lua code initializes it as a generic table (`{}`), and the JavaScript code as a generic array (`[]`). This can lead to runtime errors when synchronizing state. It is recommended to enforce consistent data types across all platforms."
}


FILE: src/lib/nexus.ts

export type Position = { x: number; y: number; z: number };

/**
 * Generates platform-specific code snippets to sync player position.
 * This is a mock implementation for the "Nexus Engine".
 * @param position - The new position of the player.
 * @returns An object with code snippets for each platform.
 */
export const syncPlayerPosition = (position: Position) => {
  console.log("NEXUS ENGINE: Syncing player position", position);

  return {
    roblox: `-- Sync position for player
player.Character.HumanoidRootPart.CFrame = CFrame.new(${position.x}, ${position.y}, ${position.z})`,
    web: `// Sync position for web
playerState.position = { x: ${position.x}, y: ${position.y}, z: ${position.z} };
updatePlayerOnMap(playerState.position);`,
    mobile: `// Sync position for mobile
setPlayerState(prevState => ({
  ...prevState,
  position: { x: ${position.x}, y: ${position.y}, z: ${position.z} },
}));`,
  };
};


FILE: src/lib/placeholder-images.json

{
  "placeholderImages": [
    {
      "id": "roblox-vp",
      "description": "A futuristic cityscape rendered in a blocky, stylized aesthetic typical of Roblox games.",
      "imageUrl": "https://images.unsplash.com/photo-1675326570919-946d728e9a25?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3NDE5ODJ8MHwxfHNlYXJjaHwyfHxmdXR1cmlzdGljJTIwY2l0eXxlbnwwfHx8fDE3Njg1NTM4OTl8MA&ixlib=rb-4.1.0&q=80&w=1080",
      "imageHint": "futuristic city"
    },
    {
      "id": "web-vp",
      "description": "A sleek, modern web interface with glowing neon elements and a dark theme, showing a game dashboard.",
      "imageUrl": "https://images.unsplash.com/photo-1722834228772-01d16b9bf83b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3NDE5ODJ8MHwxfHNlYXJjaHwzfHxuZW9uJTIwaW50ZXJmYWNlfGVufDB8fHx8MTc2ODYxNDYwOHww&ixlib=rb-4.1.0&q=80&w=1080",
      "imageHint": "neon interface"
    },
    {
      "id": "mobile-vp",
      "description": "A mobile game screen with touch controls overlaid on a vibrant, abstract world.",
      "imageUrl": "https://images.unsplash.com/photo-1565870100382-f0a510db3cd1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3NDE5ODJ8MHwxfHNlYXJjaHw0fHxtb2JpbGUlMjBnYW1lfGVufDB8fHx8MTc2ODU2MjY4MHww&ixlib=rb-4.1.0&q=80&w=1080",
      "imageHint": "mobile game"
    },
    {
      "id": "login-illustration",
      "description": "An abstract visualization of cross-platform code and interfaces.",
      "imageUrl": "https://images.unsplash.com/photo-1681130315503-f0709a634ee3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3NDE5ODJ8MHwxfHNlYXJjaHw4fHxjcm9zcy1wbGF0Zm9ybSUyMGRldmVsb3BtZW50fGVufDB8fHx8MTc2ODYxNjg3M3ww&ixlib=rb-4.1.0&q=80&w=1080",
      "imageHint": "cross-platform development"
    },
    {
      "id": "workspace-thumb-1",
      "description": "Abstract neon lights in a dark environment.",
      "imageUrl": "https://images.unsplash.com/photo-1642538302053-ad49ca70936d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3NDE5ODJ8MHwxfHNlYXJjaHw1fHxhYnN0cmFjdCUyMG5lb258ZW58MHx8fHwxNzY4NTQ0NzIwfDA&ixlib=rb-4.1.0&q=80&w=1080",
      "imageHint": "abstract neon"
    },
    {
      "id": "workspace-thumb-2",
      "description": "A vast and strange sci-fi landscape under a colorful sky.",
      "imageUrl": "https://images.unsplash.com/photo-1641200658067-b5a56ebba866?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3NDE5ODJ8MHwxfHNlYXJjaHw2fHxzY2ktZmklMjBsYW5kc2NhcGV8ZW58MHx8fHwxNzY4NTUyNTAzfDA&ixlib=rb-4.1.0&q=80&w=1080",
      "imageHint": "sci-fi landscape"
    },
    {
      "id": "workspace-thumb-3",
      "description": "A cluster of glowing cubes in a digital space.",
      "imageUrl": "https://images.unsplash.com/photo-1758775212970-30458a9df7ae?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3NDE5ODJ8MHwxfHNlYXJjaHwzfHxnbG93aW5nJTIwY3ViZXN8ZW58MHx8fHwxNzY4NjE2ODczfDA&ixlib=rb-4.1.0&q=80&w=1080",
      "imageHint": "glowing cubes"
    },
    {
      "id": "workspace-thumb-4",
      "description": "A neon-lit futuristic city at night.",
      "imageUrl": "https://images.unsplash.com/photo-1536768139911-e290a59011e4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3NDE5ODJ8MHwxfHNlYXJjaHwxMHx8ZnV0dXJpc3RpYyUyMGNpdHl8ZW58MHx8fHwxNzY4NTUzODk5fDA&ixlib=rb-4.1.0&q=80&w=1080",
      "imageHint": "futuristic city"
    }
  ]
}

FILE: src/lib/placeholder-images.ts

import data from './placeholder-images.json';

export type ImagePlaceholder = {
  id: string;
  description: string;
  imageUrl: string;
  imageHint: string;
};

export const PlaceHolderImages: ImagePlaceholder[] = data.placeholderImages;


FILE: src/lib/templates.ts

import { Gamepad2, Users, Film, FileCode } from "lucide-react";
import type { FolderNode, FileNode } from "./aethex-data";
import type { ElementType } from "react";

export interface ProjectTemplate {
  id: string;
  name: string;
  description: string;
  icon: ElementType;
  isPopular?: boolean;
  fileTree: FolderNode;
  mainFile: string;
}

const fileContents: Record<string, string> = {
  "main.server.lua": `-- Roblox Server Script\nprint("Hello from the server!")`,
  "player.client.lua": `-- Roblox Client Script\nprint("Hello from the client!")`,
  "main.lua": `-- Roblox main script
local Players = game:GetService("Players")

local function onPlayerAdded(player)
    print("Player " .. player.Name .. " has joined the game.")
    -- Initialize player data
end

Players.PlayerAdded:Connect(onPlayerAdded)
`,
  "player.lua": `-- Player script for Roblox`,
  "index.js": `// Web client entry point
document.addEventListener('DOMContentLoaded', () => {
    const app = document.getElementById('app');
    app.innerHTML = '<h1>Welcome to your new AeThex Project!</h1>';
    console.log('Web client initialized.');
});
`,
  "style.css": `/* Add your web styles here */
body {
    background-color: #1a1a1a;
    color: #fafafa;
    font-family: sans-serif;
    display: grid;
    place-content: center;
    min-height: 100vh;
}`,
  "App.tsx": `// React Native App Component
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const App = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Welcome to your AeThex Project!</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#1a1a1a',
  },
  text: {
    fontSize: 24,
    color: '#fafafa',
  },
});

export default App;
`,
  "README.md": `# New Project

Welcome to your new AeThex Studio project!

This project was generated by AeThex Studio. Start by exploring the files in the explorer.
`,
  "story.json": `{
  "title": "My Awesome Story",
  "author": "",
  "chapters": [
    {
      "id": "chapter-1",
      "title": "The Beginning",
      "scenes": []
    }
  ]
}
`,
  "viewer.js": `// Story viewer for web
document.addEventListener('DOMContentLoaded', () => {
    console.log('Story viewer initialized.');
});
`,
};

export function generateFileContent(fileName: string, language: string): string {
  return fileContents[fileName] || `// ${fileName} - ${language} file`;
}

export const projectTemplates: ProjectTemplate[] = [
  {
    id: "roblox-starter",
    name: "Roblox Game Starter",
    description: "A basic setup for a new Roblox game with player scripts.",
    icon: Gamepad2,
    fileTree: {
      name: "roblox-game",
      type: "folder",
      children: [
        {
          name: "roblox",
          type: "folder",
          children: [
            { name: "main.server.lua", type: "file", language: "lua" },
            { name: "player.client.lua", type: "file", language: "lua" },
          ],
        },
        { name: "README.md", type: "file", language: "markdown" },
      ],
    },
    mainFile: "main.server.lua",
  },
  {
    id: "cross-platform-multiplayer",
    name: "Cross-Platform Multiplayer",
    description: "Multiplayer game structure for Roblox, Web, and Mobile.",
    icon: Users,
    isPopular: true,
    fileTree: {
      name: "multiplayer-project",
      type: "folder",
      children: [
        {
          name: "roblox",
          type: "folder",
          children: [
            { name: "main.lua", type: "file", language: "lua" },
            { name: "player.lua", type: "file", language: "lua" },
          ],
        },
        {
          name: "web",
          type: "folder",
          children: [
            { name: "index.js", type: "file", language: "javascript" },
            { name: "style.css", type: "file", language: "css" },
          ],
        },
        {
          name: "mobile",
          type: "folder",
          children: [{ name: "App.tsx", type: "file", language: "typescript" }],
        },
        { name: "README.md", type: "file", language: "markdown" },
      ],
    },
    mainFile: "README.md",
  },
  {
    id: "transmedia-story",
    name: "Transmedia Story Project",
    description: "A project for interactive stories across multiple platforms.",
    icon: Film,
    fileTree: {
      name: "story-project",
      type: "folder",
      children: [
        { name: "story.json", type: "file", language: "json" },
        {
          name: "web",
          type: "folder",
          children: [
            { name: "viewer.js", type: "file", language: "javascript" },
          ],
        },
        { name: "README.md", type: "file", language: "markdown" },
      ],
    },
    mainFile: "story.json",
  },
  {
    id: "blank",
    name: "Blank Project",
    description: "Start fresh with an empty project directory.",
    icon: FileCode,
    fileTree: {
      name: "blank-project",
      type: "folder",
      children: [{ name: "README.md", type: "file", language: "markdown" }],
    },
    mainFile: "README.md",
  },
];


FILE: src/lib/utils.ts

import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}


FILE: src/lib/workspaces.ts

import {
  MobileIcon,
  RobloxIcon,
  WebIcon,
} from "@/components/aethex/icons";
import type { ElementType } from "react";

export type Workspace = {
  id: string;
  name: string;
  lastModified: string;
  platforms: ElementType[];
  thumbnailUrlId: string;
  thumbnailImageHint: string;
};

export const workspaces: Workspace[] = [
  {
    id: "proj-1",
    name: "Cyber Runner",
    lastModified: "2 days ago",
    platforms: [RobloxIcon, WebIcon, MobileIcon],
    thumbnailUrlId: "workspace-thumb-1",
    thumbnailImageHint: "abstract neon",
  },
  {
    id: "proj-2",
    name: "Project Chimera",
    lastModified: "5 days ago",
    platforms: [RobloxIcon, WebIcon],
    thumbnailUrlId: "workspace-thumb-2",
    thumbnailImageHint: "sci-fi landscape",
  },
  {
    id: "proj-3",
    name: "Story-Verse",
    lastModified: "1 week ago",
    platforms: [WebIcon],
    thumbnailUrlId: "workspace-thumb-3",
    thumbnailImageHint: "glowing cubes",
  },
];


FILE: tailwind.config.ts

import type {Config} from 'tailwindcss';

export default {
  darkMode: ['class'],
  content: [
    './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
    './src/components/**/*.{js,ts,jsx,tsx,mdx}',
    './src/app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      fontFamily: {
        body: ['Inter', 'sans-serif'],
        headline: ['Space Grotesk', 'sans-serif'],
        code: ['Source Code Pro', 'monospace'],
      },
      colors: {
        background: 'hsl(var(--background))',
        foreground: 'hsl(var(--foreground))',
        card: {
          DEFAULT: 'hsl(var(--card))',
          foreground: 'hsl(var(--card-foreground))',
        },
        popover: {
          DEFAULT: 'hsl(var(--popover))',
          foreground: 'hsl(var(--popover-foreground))',
        },
        primary: {
          DEFAULT: 'hsl(var(--primary))',
          foreground: 'hsl(var(--primary-foreground))',
        },
        secondary: {
          DEFAULT: 'hsl(var(--secondary))',
          foreground: 'hsl(var(--secondary-foreground))',
        },
        muted: {
          DEFAULT: 'hsl(var(--muted))',
          foreground: 'hsl(var(--muted-foreground))',
        },
        accent: {
          DEFAULT: 'hsl(var(--accent))',
          foreground: 'hsl(var(--accent-foreground))',
        },
        destructive: {
          DEFAULT: 'hsl(var(--destructive))',
          foreground: 'hsl(var(--destructive-foreground))',
        },
        border: 'hsl(var(--border))',
        input: 'hsl(var(--input))',
        ring: 'hsl(var(--ring))',
        chart: {
          '1': 'hsl(var(--chart-1))',
          '2': 'hsl(var(--chart-2))',
          '3': 'hsl(var(--chart-3))',
          '4': 'hsl(var(--chart-4))',
          '5': 'hsl(var(--chart-5))',
        },
        sidebar: {
          DEFAULT: 'hsl(var(--sidebar-background))',
          foreground: 'hsl(var(--sidebar-foreground))',
          primary: 'hsl(var(--sidebar-primary))',
          'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
          accent: 'hsl(var(--sidebar-accent))',
          'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
          border: 'hsl(var(--sidebar-border))',
          ring: 'hsl(var(--sidebar-ring))',
        },
      },
      borderRadius: {
        lg: 'var(--radius)',
        md: 'calc(var(--radius) - 2px)',
        sm: 'calc(var(--radius) - 4px)',
      },
      keyframes: {
        'accordion-down': {
          from: {
            height: '0',
          },
          to: {
            height: 'var(--radix-accordion-content-height)',
          },
        },
        'accordion-up': {
          from: {
            height: 'var(--radix-accordion-content-height)',
          },
          to: {
            height: '0',
          },
        },
      },
      animation: {
        'accordion-down': 'accordion-down 0.2s ease-out',
        'accordion-up': 'accordion-up 0.2s ease-out',
      },
    },
  },
  plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')],
} satisfies Config;


FILE: tsconfig.json

{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}