import React, { useState } from 'react'; import { Toaster } from './components/ui/sonner'; import { CodeEditor } from './components/CodeEditor'; import { AIChat } from './components/AIChat'; import { Toolbar } from './components/Toolbar'; import { TemplatesDrawer } from './components/TemplatesDrawer'; import { WelcomeDialog } from './components/WelcomeDialog'; import { FileTree, FileNode } from './components/FileTree'; import { FileTabs } from './components/FileTabs'; import { PreviewModal } from './components/PreviewModal'; import { NewProjectModal, ProjectConfig } from './components/NewProjectModal'; import { ConsolePanel } from './components/ConsolePanel'; import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from './components/ui/resizable'; import { useIsMobile } from './hooks/use-mobile'; import { Tabs, TabsContent, TabsList, TabsTrigger } from './components/ui/tabs'; import { toast } from 'sonner'; import { EducationPanel } from './components/EducationPanel'; import { ExtraTabs } from './components/ui/tabs-extra'; import { PassportLogin } from './components/PassportLogin'; import { Button } from './components/ui/button'; import { initPostHog, captureEvent } from './lib/posthog'; import { initSentry, captureError } from './lib/sentry'; function App() { const [currentCode, setCurrentCode] = useState(''); const [showTemplates, setShowTemplates] = useState(false); const [showPreview, setShowPreview] = useState(false); const [showNewProject, setShowNewProject] = useState(false); const [code, setCode] = useState(''); const isMobile = useIsMobile(); const [showPassportLogin, setShowPassportLogin] = useState(false); const [user, setUser] = useState<{ login: string; avatarUrl: string; email: string } | null>(() => { const stored = typeof window !== 'undefined' ? localStorage.getItem('aethex-user') : null; return stored ? JSON.parse(stored) : null; }); React.useEffect(() => { initPostHog(); initSentry(); }, []); const handleLoginSuccess = (user: { login: string; avatarUrl: string; email: string }) => { setUser(user); localStorage.setItem('aethex-user', JSON.stringify(user)); captureEvent('login', { user }); }; const handleSignOut = () => { setUser(null); localStorage.removeItem('aethex-user'); }; const [files, setFiles] = useState([ { id: 'root', name: 'src', type: 'folder', children: [ { id: 'file-1', name: 'script.lua', type: 'file', content: `-- Welcome to AeThex Studio! -- Write your Roblox Lua code here local Players = game:GetService("Players") Players.PlayerAdded:Connect(function(player) print(player.Name .. " joined the game!") local leaderstats = Instance.new("Folder") leaderstats.Name = "leaderstats" leaderstats.Parent = player local coins = Instance.new("IntValue") coins.Name = "Coins" coins.Value = 0 coins.Parent = leaderstats end)`, }, ], }, ]); const [openFiles, setOpenFiles] = useState([]); const [activeFileId, setActiveFileId] = useState('file-1'); const handleTemplateSelect = (templateCode: string) => { setCode(templateCode); setCurrentCode(templateCode); }; const handleFileSelect = (file: FileNode) => { if (file.type === 'file') { setActiveFileId(file.id); if (!(openFiles || []).find((f) => f.id === file.id)) { setOpenFiles((prev) => [...(prev || []), file]); } setCode(file.content || ''); setCurrentCode(file.content || ''); } captureEvent('file_select', { fileId: file.id }); }; const handleFileCreate = (name: string, parentId?: string) => { const newFile: FileNode = { id: `file-${Date.now()}`, name: name.endsWith('.lua') ? name : `${name}.lua`, type: 'file', content: '-- New file\n', }; setFiles((prev) => { const addToFolder = (nodes: FileNode[]): FileNode[] => { return nodes.map((node) => { if (node.id === 'root' && !parentId) { return { ...node, children: [...(node.children || []), newFile], }; } if (node.id === parentId && node.type === 'folder') { return { ...node, children: [...(node.children || []), newFile], }; } if (node.children) { return { ...node, children: addToFolder(node.children) }; } return node; }); }; return addToFolder(prev || []); }); captureEvent('file_create', { name, parentId }); toast.success(`Created ${newFile.name}`); }; const handleFileRename = (id: string, newName: string) => { setFiles((prev) => { const rename = (nodes: FileNode[]): FileNode[] => { return nodes.map((node) => { if (node.id === id) { return { ...node, name: newName }; } if (node.children) { return { ...node, children: rename(node.children) }; } return node; }); }; return rename(prev || []); }); }; const handleFileDelete = (id: string) => { setFiles((prev) => { const deleteNode = (nodes: FileNode[]): FileNode[] => { return nodes.filter((node) => { if (node.id === id) return false; if (node.children) { node.children = deleteNode(node.children); } return true; }); }; return deleteNode(prev || []); }); setOpenFiles((prev) => (prev || []).filter((f) => f.id !== id)); if (activeFileId === id) { setActiveFileId((openFiles || [])[0]?.id || ''); } captureEvent('file_delete', { id }); }; const handleFileClose = (id: string) => { setOpenFiles((prev) => (prev || []).filter((f) => f.id !== id)); if (activeFileId === id) { const remaining = (openFiles || []).filter((f) => f.id !== id); setActiveFileId(remaining[0]?.id || ''); } }; const handleCreateProject = (config: ProjectConfig) => { const projectFiles: FileNode[] = [ { id: 'root', name: config.name, type: 'folder', children: [ { id: `file-${Date.now()}`, name: 'main.lua', type: 'file', content: `-- ${config.name}\n-- Template: ${config.template}\n\nprint("Project initialized!")`, }, ], }, ]; setFiles(projectFiles); setOpenFiles([]); setActiveFileId(''); }; // Example user stub for profile const demoUser = user || { login: 'demo-user', avatarUrl: 'https://avatars.githubusercontent.com/u/1?v=4', email: 'demo@aethex.com', }; return (
setShowTemplates(true)} onPreviewClick={() => setShowPreview(true)} onNewProjectClick={() => setShowNewProject(true)} />
{isMobile ? ( Files Editor AI Learn
) : ( <>
)} {/* Unified feature tabs for all major panels */}
{showTemplates && ( setShowTemplates(false)} /> )} setShowPreview(false)} code={currentCode} /> setShowNewProject(false)} onCreateProject={handleCreateProject} /> {!user && ( )} {user && (
{user.login} {user.login}
)} setShowPassportLogin(false)} onLoginSuccess={handleLoginSuccess} />
); } export default App;