This completes the integration of the cross-platform translation engine into the main application, making it fully functional. App.tsx Changes: - Added platform state management (currentPlatform: PlatformId) - Added translation panel state (showTranslation) - Integrated TranslationPanel component with lazy loading - Updated Toolbar with platform selector and translate button - Passed platform prop to TemplatesDrawer and CodeEditor - Connected all state management for seamless platform switching TemplatesDrawer Changes: - Now accepts currentPlatform prop - Filters templates by selected platform using getTemplatesForPlatform() - Shows platform icon and name in header - Displays template count for current platform - Ready for UEFN/Spatial/Core templates CodeEditor Changes: - Accepts optional platform prop (defaults to 'roblox') - Dynamically sets Monaco editor language based on platform: * roblox → lua * uefn → plaintext (Verse not yet in Monaco) * spatial → typescript * core → lua - Maintains backward compatibility with existing code Functional Features: ✅ Platform switching in toolbar ✅ Templates filter by platform automatically ✅ Editor language changes with platform ✅ Translation panel opens with "Translate" button ✅ Side-by-side code comparison ✅ Mock translation working ✅ All state connected and reactive Next: Phase 3 (Create UEFN templates) or Phase 4 (Claude API integration)
105 lines
3 KiB
TypeScript
105 lines
3 KiB
TypeScript
import Editor from '@monaco-editor/react';
|
|
import { useKV } from '@github/spark/hooks';
|
|
import { useEffect, useMemo } from 'react';
|
|
import { LoadingSpinner } from './ui/loading-spinner';
|
|
import { toast } from 'sonner';
|
|
import { PlatformId } from '@/lib/platforms';
|
|
|
|
interface CodeEditorProps {
|
|
onCodeChange?: (code: string) => void;
|
|
platform?: PlatformId;
|
|
}
|
|
|
|
export function CodeEditor({ onCodeChange, platform = 'roblox' }: CodeEditorProps) {
|
|
const languageMap: Record<PlatformId, string> = useMemo(() => ({
|
|
roblox: 'lua',
|
|
uefn: 'plaintext', // Verse not yet supported by Monaco, use plaintext
|
|
spatial: 'typescript',
|
|
core: 'lua',
|
|
}), []);
|
|
|
|
const editorLanguage = languageMap[platform];
|
|
const [code, setCode] = useKV('aethex-current-code', `-- 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)
|
|
`);
|
|
|
|
useEffect(() => {
|
|
try {
|
|
if (onCodeChange && code) {
|
|
onCodeChange(code);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to update code:', error);
|
|
}
|
|
}, [code, onCodeChange]);
|
|
|
|
const handleEditorChange = (value: string | undefined) => {
|
|
try {
|
|
setCode(value || '');
|
|
} catch (error) {
|
|
console.error('Failed to save code:', error);
|
|
toast.error('Failed to save changes. Please try again.');
|
|
}
|
|
};
|
|
|
|
const handleEditorMount = () => {
|
|
console.log('Monaco editor mounted successfully');
|
|
};
|
|
|
|
const handleEditorError = (error: Error) => {
|
|
console.error('Monaco editor error:', error);
|
|
toast.error('Editor failed to load. Please refresh the page.');
|
|
};
|
|
|
|
return (
|
|
<div className="h-full w-full bg-background border-l border-border flex flex-col">
|
|
<div className="flex-1 min-h-0">
|
|
<Editor
|
|
height="100%"
|
|
language={editorLanguage}
|
|
theme="vs-dark"
|
|
value={code}
|
|
onChange={handleEditorChange}
|
|
onMount={handleEditorMount}
|
|
loading={
|
|
<div className="h-full flex items-center justify-center">
|
|
<LoadingSpinner />
|
|
</div>
|
|
}
|
|
options={{
|
|
minimap: { enabled: typeof window !== 'undefined' && window.innerWidth >= 768 },
|
|
fontSize: 13,
|
|
lineNumbers: 'on',
|
|
automaticLayout: true,
|
|
scrollBeyondLastLine: false,
|
|
wordWrap: 'on',
|
|
fontFamily: 'JetBrains Mono, monospace',
|
|
fontLigatures: true,
|
|
cursorBlinking: 'smooth',
|
|
smoothScrolling: true,
|
|
padding: { top: 8, bottom: 8 },
|
|
scrollbar: {
|
|
verticalScrollbarSize: 6,
|
|
horizontalScrollbarSize: 6,
|
|
},
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|