modified: src/lib/templates.ts
This commit is contained in:
parent
0fdaefdc8d
commit
42a1e2c3e6
6 changed files with 129 additions and 156 deletions
206
src/App.tsx
206
src/App.tsx
|
|
@ -460,122 +460,101 @@ end)`,
|
||||||
email: 'demo@aethex.com',
|
email: 'demo@aethex.com',
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="h-screen flex flex-col bg-background text-foreground">
|
<div className="h-screen w-screen flex flex-col bg-background text-foreground">
|
||||||
<Toolbar
|
{/* Top Bar */}
|
||||||
code={currentCode}
|
<div className="flex items-center h-12 px-4 bg-card border-b border-border shadow-sm z-20">
|
||||||
currentPlatform={currentPlatform}
|
<span className="text-xl font-bold tracking-tight select-none">
|
||||||
onPlatformChange={setCurrentPlatform}
|
Ae<span className="text-accent">Thex</span>
|
||||||
onTranslateClick={() => setShowTranslation(true)}
|
</span>
|
||||||
onTemplatesClick={() => setShowTemplates(true)}
|
<span className="ml-2 text-sm text-muted-foreground font-medium select-none">Studio</span>
|
||||||
onPreviewClick={() => setShowPreview(true)}
|
<div className="flex-1" />
|
||||||
onNewProjectClick={() => setShowNewProject(true)}
|
<Toolbar
|
||||||
/>
|
code={currentCode}
|
||||||
|
currentPlatform={currentPlatform}
|
||||||
|
onPlatformChange={setCurrentPlatform}
|
||||||
|
onTranslateClick={() => setShowTranslation(true)}
|
||||||
|
onTemplatesClick={() => setShowTemplates(true)}
|
||||||
|
onPreviewClick={() => setShowPreview(true)}
|
||||||
|
onNewProjectClick={() => setShowNewProject(true)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 overflow-hidden flex flex-col">
|
{/* Main Content Area */}
|
||||||
{isMobile ? (
|
<div className="flex flex-1 min-h-0 min-w-0 overflow-hidden">
|
||||||
<Tabs defaultValue="editor" className="h-full flex flex-col">
|
{/* Activity Bar */}
|
||||||
<TabsList className="w-full rounded-none border-b border-border">
|
<div className="flex flex-col items-center w-12 bg-muted border-r border-border py-2 gap-2 z-10">
|
||||||
<TabsTrigger value="files" className="flex-1">Files</TabsTrigger>
|
{/* Example activity icons, replace with real navigation/actions */}
|
||||||
<TabsTrigger value="editor" className="flex-1">Editor</TabsTrigger>
|
<button className="w-8 h-8 rounded flex items-center justify-center hover:bg-accent/20 text-accent" title="Files">
|
||||||
<TabsTrigger value="ai" className="flex-1">AI</TabsTrigger>
|
<svg width="20" height="20" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><path d="M4 4h16v16H4z" /></svg>
|
||||||
<TabsTrigger value="education" className="flex-1">Learn</TabsTrigger>
|
</button>
|
||||||
</TabsList>
|
<button className="w-8 h-8 rounded flex items-center justify-center hover:bg-accent/20 text-accent" title="AI">
|
||||||
<TabsContent value="files" className="flex-1 m-0">
|
<svg width="20" height="20" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8" /></svg>
|
||||||
<FileTree
|
</button>
|
||||||
files={files || []}
|
<button className="w-8 h-8 rounded flex items-center justify-center hover:bg-accent/20 text-accent" title="Learn">
|
||||||
onFileSelect={handleFileSelect}
|
<svg width="20" height="20" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" /></svg>
|
||||||
onFileCreate={handleFileCreate}
|
</button>
|
||||||
onFileRename={handleFileRename}
|
</div>
|
||||||
onFileDelete={handleFileDelete}
|
|
||||||
onFileMove={handleFileMove}
|
{/* Main Panels */}
|
||||||
selectedFileId={activeFileId}
|
<div className="flex-1 flex flex-col min-h-0 min-w-0">
|
||||||
/>
|
<div className="flex-1 min-h-0 min-w-0 overflow-hidden">
|
||||||
</TabsContent>
|
<ResizablePanelGroup orientation="horizontal">
|
||||||
<TabsContent value="editor" className="flex-1 m-0 flex flex-col">
|
<ResizablePanel defaultSize={16} minSize={10} maxSize={25}>
|
||||||
<FileTabs
|
<FileTree
|
||||||
openFiles={openFiles || []}
|
files={files || []}
|
||||||
activeFileId={activeFileId}
|
onFileSelect={handleFileSelect}
|
||||||
onFileSelect={handleFileSelect}
|
onFileCreate={handleFileCreate}
|
||||||
onFileClose={handleFileClose}
|
onFileRename={handleFileRename}
|
||||||
/>
|
onFileDelete={handleFileDelete}
|
||||||
<div className="flex-1">
|
onFileMove={handleFileMove}
|
||||||
<CodeEditor onCodeChange={handleCodeChange} platform={currentPlatform} />
|
selectedFileId={activeFileId}
|
||||||
</div>
|
/>
|
||||||
</TabsContent>
|
</ResizablePanel>
|
||||||
<TabsContent value="ai" className="flex-1 m-0">
|
<ResizableHandle className="w-1 bg-border hover:bg-accent transition-colors" />
|
||||||
<AIChat currentCode={currentCode} />
|
<ResizablePanel defaultSize={54} minSize={30}>
|
||||||
</TabsContent>
|
<div className="h-full flex flex-col">
|
||||||
<TabsContent value="education" className="flex-1 m-0">
|
<FileTabs
|
||||||
<Suspense fallback={<div className="flex items-center justify-center h-full"><LoadingSpinner /></div>}>
|
openFiles={openFiles || []}
|
||||||
<EducationPanel />
|
activeFileId={activeFileId}
|
||||||
</Suspense>
|
|
||||||
</TabsContent>
|
|
||||||
</Tabs>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div className="flex-1 overflow-hidden">
|
|
||||||
<ResizablePanelGroup orientation="horizontal">
|
|
||||||
<ResizablePanel defaultSize={15} minSize={10} maxSize={25}>
|
|
||||||
<FileTree
|
|
||||||
files={files || []}
|
|
||||||
onFileSelect={handleFileSelect}
|
onFileSelect={handleFileSelect}
|
||||||
onFileCreate={handleFileCreate}
|
onFileClose={handleFileClose}
|
||||||
onFileRename={handleFileRename}
|
|
||||||
onFileDelete={handleFileDelete}
|
|
||||||
onFileMove={handleFileMove}
|
|
||||||
selectedFileId={activeFileId}
|
|
||||||
/>
|
/>
|
||||||
</ResizablePanel>
|
<div className="flex-1">
|
||||||
|
<CodeEditor onCodeChange={setCurrentCode} platform={currentPlatform} />
|
||||||
<ResizableHandle className="w-1 bg-border hover:bg-accent transition-colors" />
|
|
||||||
|
|
||||||
<ResizablePanel defaultSize={55} minSize={30}>
|
|
||||||
<div className="h-full flex flex-col">
|
|
||||||
<FileTabs
|
|
||||||
openFiles={openFiles || []}
|
|
||||||
activeFileId={activeFileId}
|
|
||||||
onFileSelect={handleFileSelect}
|
|
||||||
onFileClose={handleFileClose}
|
|
||||||
/>
|
|
||||||
<div className="flex-1">
|
|
||||||
<CodeEditor onCodeChange={setCurrentCode} platform={currentPlatform} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</ResizablePanel>
|
</div>
|
||||||
|
</ResizablePanel>
|
||||||
<ResizableHandle className="w-1 bg-border hover:bg-accent transition-colors" />
|
<ResizableHandle className="w-1 bg-border hover:bg-accent transition-colors" />
|
||||||
|
<ResizablePanel defaultSize={15} minSize={10}>
|
||||||
<ResizablePanel defaultSize={20} minSize={15}>
|
<AIChat currentCode={currentCode} />
|
||||||
<EducationPanel />
|
</ResizablePanel>
|
||||||
</ResizablePanel>
|
<ResizableHandle className="w-1 bg-border hover:bg-accent transition-colors" />
|
||||||
|
<ResizablePanel defaultSize={15} minSize={10}>
|
||||||
<ResizablePanel defaultSize={15} minSize={10}>
|
<EducationPanel />
|
||||||
<AIChat currentCode={currentCode} />
|
</ResizablePanel>
|
||||||
</ResizablePanel>
|
</ResizablePanelGroup>
|
||||||
</ResizablePanelGroup>
|
</div>
|
||||||
</div>
|
<ConsolePanel
|
||||||
<ConsolePanel
|
collapsed={consoleCollapsed}
|
||||||
collapsed={consoleCollapsed}
|
onToggle={() => setConsoleCollapsed(!consoleCollapsed)}
|
||||||
onToggle={() => setConsoleCollapsed(!consoleCollapsed)}
|
currentCode={currentCode}
|
||||||
currentCode={currentCode}
|
currentFile={activeFileId ? (openFiles || []).find(f => f.id === activeFileId)?.name : undefined}
|
||||||
currentFile={activeFileId ? (openFiles || []).find(f => f.id === activeFileId)?.name : undefined}
|
files={files || []}
|
||||||
files={files || []}
|
onCodeChange={setCurrentCode}
|
||||||
onCodeChange={setCurrentCode}
|
/>
|
||||||
/>
|
<SearchInFilesPanel
|
||||||
<SearchInFilesPanel
|
files={files || []}
|
||||||
files={files || []}
|
onFileSelect={handleFileSelect}
|
||||||
onFileSelect={handleFileSelect}
|
isOpen={showSearchInFiles}
|
||||||
isOpen={showSearchInFiles}
|
onClose={() => setShowSearchInFiles(false)}
|
||||||
onClose={() => setShowSearchInFiles(false)}
|
/>
|
||||||
/>
|
<div className="w-full border-t border-border mt-2">
|
||||||
</>
|
<ExtraTabs user={demoUser} />
|
||||||
)}
|
</div>
|
||||||
{/* Unified feature tabs for all major panels */}
|
|
||||||
<div className="w-full border-t border-border mt-4">
|
|
||||||
<ExtraTabs user={demoUser} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Modals and overlays */}
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
{showTemplates && (
|
{showTemplates && (
|
||||||
<TemplatesDrawer
|
<TemplatesDrawer
|
||||||
|
|
@ -585,7 +564,6 @@ end)`,
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
<PreviewModal
|
<PreviewModal
|
||||||
open={showPreview}
|
open={showPreview}
|
||||||
|
|
@ -593,7 +571,6 @@ end)`,
|
||||||
code={currentCode}
|
code={currentCode}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
<NewProjectModal
|
<NewProjectModal
|
||||||
open={showNewProject}
|
open={showNewProject}
|
||||||
|
|
@ -601,7 +578,6 @@ end)`,
|
||||||
onCreateProject={handleCreateProject}
|
onCreateProject={handleCreateProject}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
{showTranslation && (
|
{showTranslation && (
|
||||||
<TranslationPanel
|
<TranslationPanel
|
||||||
|
|
@ -612,20 +588,15 @@ end)`,
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
<WelcomeDialog />
|
<WelcomeDialog />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
||||||
{/* File Search Modal (Cmd/Ctrl+P) */}
|
|
||||||
<FileSearchModal
|
<FileSearchModal
|
||||||
open={showFileSearch}
|
open={showFileSearch}
|
||||||
onClose={() => setShowFileSearch(false)}
|
onClose={() => setShowFileSearch(false)}
|
||||||
files={files || []}
|
files={files || []}
|
||||||
onFileSelect={handleFileSelect}
|
onFileSelect={handleFileSelect}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Command Palette (Cmd/Ctrl+K) */}
|
|
||||||
<CommandPalette
|
<CommandPalette
|
||||||
open={showCommandPalette}
|
open={showCommandPalette}
|
||||||
onClose={() => setShowCommandPalette(false)}
|
onClose={() => setShowCommandPalette(false)}
|
||||||
|
|
@ -655,7 +626,6 @@ end)`,
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!user && (
|
{!user && (
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ end)
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-full bg-background border-l border-border flex flex-col">
|
<div className="h-full w-full bg-background border border-border shadow-md rounded-md flex flex-col">
|
||||||
<div className="flex-1 min-h-0">
|
<div className="flex-1 min-h-0">
|
||||||
<Editor
|
<Editor
|
||||||
height="100%"
|
height="100%"
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ export function ConsolePanel({ collapsed, onToggle, currentCode = '', currentFil
|
||||||
|
|
||||||
if (collapsed) {
|
if (collapsed) {
|
||||||
return (
|
return (
|
||||||
<div className="h-8 bg-card border-t border-border flex items-center justify-between px-4 cursor-pointer" onClick={onToggle}>
|
<div className="h-8 bg-card border-t border-border flex items-center justify-between px-4 cursor-pointer shadow-sm" onClick={onToggle}>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Terminal size={16} />
|
<Terminal size={16} />
|
||||||
<span className="text-sm font-semibold">Console</span>
|
<span className="text-sm font-semibold">Console</span>
|
||||||
|
|
@ -101,8 +101,8 @@ export function ConsolePanel({ collapsed, onToggle, currentCode = '', currentFil
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-[200px] bg-card border-t border-border flex flex-col">
|
<div className="h-[200px] bg-card border-t border-border flex flex-col shadow-lg rounded-t-md">
|
||||||
<div className="flex items-center justify-between px-4 py-2 border-b border-border">
|
<div className="flex items-center justify-between px-4 py-2 border-b border-border bg-muted/40 rounded-t-md">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Terminal size={18} />
|
<Terminal size={18} />
|
||||||
<span className="text-sm font-semibold">Console</span>
|
<span className="text-sm font-semibold">Console</span>
|
||||||
|
|
|
||||||
|
|
@ -58,38 +58,38 @@ export function FileTree({
|
||||||
if (next.has(id)) {
|
if (next.has(id)) {
|
||||||
next.delete(id);
|
next.delete(id);
|
||||||
} else {
|
} else {
|
||||||
next.add(id);
|
return (
|
||||||
}
|
<ScrollArea className="flex-1 bg-muted/40 border-r border-border min-w-[180px] max-w-[260px]">
|
||||||
return next;
|
<div className="p-2">
|
||||||
});
|
{files.map((node) => (
|
||||||
}, []);
|
<FileNodeComponent
|
||||||
|
key={node.id}
|
||||||
const startRename = useCallback((file: FileNode) => {
|
node={node}
|
||||||
setEditingId(file.id);
|
expandedFolders={expandedFolders}
|
||||||
setEditingName(file.name);
|
toggleFolder={toggleFolder}
|
||||||
}, []);
|
onFileSelect={onFileSelect}
|
||||||
|
onFileCreate={onFileCreate}
|
||||||
const finishRename = useCallback((id: string) => {
|
onFileRename={onFileRename}
|
||||||
if (editingName.trim() && editingName !== '') {
|
onFileDelete={onFileDelete}
|
||||||
onFileRename(id, editingName.trim());
|
onFileMove={onFileMove}
|
||||||
toast.success('File renamed');
|
selectedFileId={selectedFileId}
|
||||||
}
|
startRename={startRename}
|
||||||
setEditingId(null);
|
finishRename={finishRename}
|
||||||
setEditingName('');
|
editingId={editingId}
|
||||||
}, [editingName, onFileRename]);
|
editingName={editingName}
|
||||||
|
setEditingName={setEditingName}
|
||||||
const handleDelete = useCallback((file: FileNode) => {
|
handleDelete={handleDelete}
|
||||||
if (confirm(`Delete ${file.name}?`)) {
|
handleDragStart={handleDragStart}
|
||||||
onFileDelete(file.id);
|
handleDragOver={handleDragOver}
|
||||||
toast.success('File deleted');
|
handleDragLeave={handleDragLeave}
|
||||||
}
|
handleDrop={handleDrop}
|
||||||
}, [onFileDelete]);
|
draggedId={draggedId}
|
||||||
|
dropTargetId={dropTargetId}
|
||||||
const handleDragStart = useCallback((e: React.DragEvent, node: FileNode) => {
|
/>
|
||||||
e.stopPropagation();
|
))}
|
||||||
setDraggedId(node.id);
|
</div>
|
||||||
e.dataTransfer.effectAllowed = 'move';
|
</ScrollArea>
|
||||||
e.dataTransfer.setData('text/plain', node.id);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleDragOver = useCallback((e: React.DragEvent, node: FileNode) => {
|
const handleDragOver = useCallback((e: React.DragEvent, node: FileNode) => {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ function DialogOverlay({
|
||||||
<DialogPrimitive.Overlay
|
<DialogPrimitive.Overlay
|
||||||
data-slot="dialog-overlay"
|
data-slot="dialog-overlay"
|
||||||
className={cn(
|
className={cn(
|
||||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/70 backdrop-blur-sm",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -55,7 +55,7 @@ function DialogContent({
|
||||||
<DialogPrimitive.Content
|
<DialogPrimitive.Content
|
||||||
data-slot="dialog-content"
|
data-slot="dialog-content"
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
|
"bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-2xl border-2 border-accent/60 p-8 shadow-2xl duration-200 sm:max-w-lg",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
export function getTemplatesForPlatform(platform: PlatformId): ScriptTemplate[] {
|
export function getTemplatesForPlatform(platform: PlatformId): ScriptTemplate[] {
|
||||||
return templates.filter(t => t.platform === platform);
|
return templates.filter(t => t.platform === platform);
|
||||||
}
|
}
|
||||||
|
export function getTemplatesForPlatform(platform: PlatformId): ScriptTemplate[] {
|
||||||
|
return templates.filter(t => t.platform === platform);
|
||||||
|
}
|
||||||
import { PlatformId } from './platforms';
|
import { PlatformId } from './platforms';
|
||||||
import { uefnTemplates } from './templates-uefn';
|
import { uefnTemplates } from './templates-uefn';
|
||||||
import { spatialTemplates } from './templates-spatial';
|
import { spatialTemplates } from './templates-spatial';
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue