// ...existing code... import React, { useState, lazy, Suspense } from 'react'; import { FileTree } from '../components/FileTree'; import { FileTabs } from '../components/FileTabs'; import { CodeEditor } from '../components/CodeEditor'; import { ConsolePanel } from '../components/ConsolePanel'; import { Toolbar } from './components/Toolbar'; import { AIAssistant } from '../components/AIAssistant'; import { CrossPlatformPreview } from '../components/CrossPlatformPreview'; import { NexusSyncMonitor } from '../components/NexusSyncMonitor'; import { Toaster } from './components/ui/sonner'; import { toast } from 'sonner'; import { useEditorStore } from '../store/editor-store'; import { FileNode } from '../store/editor-store'; import { captureEvent } from './lib/posthog'; import { captureError } from './lib/sentry'; import { useIsMobile } from './hooks/use-mobile'; const TemplatesDrawer = lazy(() => import('./components/TemplatesDrawer')); const PreviewModal = lazy(() => import('./components/PreviewModal')); const NewProjectModal = lazy(() => import('./components/NewProjectModal')); const PassportLogin = lazy(() => import('./components/PassportLogin')); const TranslationPanel = lazy(() => import('./components/TranslationPanel')); const CommandPalette = lazy(() => import('./components/CommandPalette')); const StudioSidebar = lazy(() => import('../components/StudioSidebar')); const StudioEditor = lazy(() => import('../components/StudioEditor')); // const StudioBottomPanel = lazy(() => import('../components/StudioBottomPanel')); const StudioRightPanel = lazy(() => import('../components/StudioRightPanel')); const StudioNetworkViz = lazy(() => import('../components/StudioNetworkViz')); function App() { // --- Error/Warning Banner State --- const [problemsExpanded, setProblemsExpanded] = useState(false); // --- Right Sidebar Tab State --- const [rightSidebarTab, setRightSidebarTab] = useState('Copilot'); // TODO: Connect to real error/warning data source const problems: Array<{ file: string; line: number; type: string; message: string }> = []; // ...existing state and hooks... // --- State --- const setFiles = useEditorStore((state) => state.setFiles); const [currentCode, setCurrentCode] = useState(''); const [showTemplates, setShowTemplates] = useState(false); const [showPreview, setShowPreview] = useState(false); const [showNewProject, setShowNewProject] = useState(false); const [showFileSearch, setShowFileSearch] = useState(false); const [showCommandPalette, setShowCommandPalette] = useState(false); const [showSearchInFiles, setShowSearchInFiles] = useState(false); const [showTranslation, setShowTranslation] = useState(false); const [code, setCode] = useState(''); const [currentPlatform, setCurrentPlatform] = useState('roblox'); const isMobile = useIsMobile(); const [showPassportLogin, setShowPassportLogin] = useState(false); const [consoleCollapsed, setConsoleCollapsed] = useState(isMobile); 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; }); const [openFiles, setOpenFiles] = useState([]); const [activeFileId, setActiveFileId] = useState(''); // --- Handlers --- const handleTemplateSelect = (templateCode: string) => { setCode(templateCode); setCurrentCode(templateCode); if (activeFileId) { handleCodeChange(templateCode); } }; const handleCodeChange = (newCode: string) => { setCurrentCode(newCode); setCode(newCode); if (activeFileId) { const files = useEditorStore.getState().files; const updateFileContent = (nodes: FileNode[]): FileNode[] => { return nodes.map((node) => { if (node.id === activeFileId) { return { ...node, content: newCode }; } if (node.children) { return { ...node, children: updateFileContent(node.children) }; } return node; }); }; setFiles(updateFileContent(files || [])); setOpenFiles((prev) => (prev || []).map((file) => file.id === activeFileId ? { ...file, content: newCode } : file)); } }; 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 handleFileClose = (id: string) => { setOpenFiles((prev) => (prev || []).filter((f) => f.id !== id)); }; const handleFileRename = (id: string, newName: string) => { if (!newName || newName.trim() === '') { toast.error('File name cannot be empty'); return; } const files = useEditorStore.getState().files; 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; }); }; setFiles(rename(files || [])); captureEvent('file_rename', { id, newName }); }; const handleFileDelete = (id: string) => { try { const files = useEditorStore.getState().files; 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; }); }; setFiles(deleteNode(files || [])); setOpenFiles((prev) => (prev || []).filter((f) => f.id !== id)); if (activeFileId === id) { setActiveFileId((openFiles || [])[0]?.id || ''); } captureEvent('file_delete', { id }); } catch (error) { console.error('Failed to delete file:', error); captureError(error as Error, { context: 'file_delete', id }); toast.error('Failed to delete file. Please try again.'); } }; const handleFileMove = (fileId: string, targetParentId: string) => { try { const files = useEditorStore.getState().files; let movedNode: FileNode | null = null; const removeNode = (nodes: FileNode[]): FileNode[] => { return nodes.filter((node) => { if (node.id === fileId) { movedNode = node; return false; } if (node.children) { node.children = removeNode(node.children); } return true; }); }; const addToTarget = (nodes: FileNode[]): FileNode[] => { return nodes.map((node) => { if (node.id === targetParentId && node.type === 'folder') { return { ...node, children: [...(node.children || []), movedNode!], }; } if (node.children) { return { ...node, children: addToTarget(node.children) }; } return node; }); }; const withoutMoved = removeNode(files || []); if (movedNode) { setFiles(addToTarget(withoutMoved)); } else { setFiles(files || []); } captureEvent('file_move', { fileId, targetParentId }); } catch (error) { console.error('Failed to move file:', error); captureError(error as Error, { context: 'file_move', fileId, targetParentId }); toast.error('Failed to move file. Please try again.'); } }; // --- Render --- return ( <>
{/* Left Sidebar: Vertical tabs + Explorer */}
Loading...
}>
{/* Center: Tabs + Editor + Preview */}
{/* File Tabs Row (no workspace tabs above) */}
{/* Main Editor/Preview Split */}
setShowTemplates(true)} /*...existing code...*/ />
{activeFileId ? ( ) : (
๐Ÿ“‚

Welcome to AeThex Studio

Select a file from the explorer to start editing, or use the quick actions below.

)}

Preview

{showPreview && (
)}

Sync Monitor

{showTranslation && (
)}
{/* ConsolePanel moved to top bar. */}
{/* Right Sidebar: Copilot, AI, Inspector, Trinity */}
Loading...
}>
{['Copilot', 'AI', 'Inspector', 'Trinity'].map(tab => ( ))}
{rightSidebarTab === 'Copilot' && } {rightSidebarTab === 'AI' && } {rightSidebarTab === 'Inspector' &&
Inspector/Properties coming soonโ€ฆ
} {rightSidebarTab === 'Trinity' && }
{/* Problems Details Floating Panel */} {problemsExpanded && (
Problems
    {problems.map((p, i) => (
  • {p.type === 'error' ? 'Error:' : 'Warning:'} {p.file}:{p.line} {p.message}
  • ))}
)} {/* Modals and Drawers */} Loadingโ€ฆ}> {showTemplates && setShowTemplates(false)} />} {showPreview && setShowPreview(false)} />} {showNewProject && setShowNewProject(false)} />} Loadingโ€ฆ}> {showTemplates && setShowTemplates(false)} />} {showPreview && setShowPreview(false)} />} {showNewProject && setShowNewProject(false)} onCreateProject={() => {}} />} {showTranslation && setShowTranslation(false)} currentCode={currentCode} currentPlatform={currentPlatform} />} {showPassportLogin && setShowPassportLogin(false)} onLoginSuccess={() => {}} />} setShowCommandPalette(false)} commands={[ { id: 'new-project', label: 'New Project', description: 'Create a new project', icon: '๐Ÿ“', action: () => setShowNewProject(true) }, { id: 'templates', label: 'Templates', description: 'Open templates drawer', icon: '๐Ÿ“„', action: () => setShowTemplates(true) }, { id: 'preview', label: 'Preview', description: 'Preview your code', icon: '๐Ÿ‘๏ธ', action: () => setShowPreview(true) }, { id: 'export', label: 'Export', description: 'Export your project', icon: 'โฌ‡๏ธ', action: () => toast.success('Exported!') }, { id: 'copy', label: 'Copy', description: 'Copy code', icon: '๐Ÿ“‹', action: () => toast.success('Copied!') }, ]} /> ); } export default App;