106 lines
3.8 KiB
TypeScript
106 lines
3.8 KiB
TypeScript
"use client";
|
|
|
|
import React from 'react';
|
|
import dynamic from 'next/dynamic';
|
|
import { useEditorStore } from '@/store/editor-store';
|
|
import { FileTabs } from './FileTabs';
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
import { useAppStore } from '@/store/app-store';
|
|
import { CrossPlatformPreview } from './CrossPlatformPreview';
|
|
import { NexusSyncMonitor } from './NexusSyncMonitor';
|
|
|
|
const MonacoEditor = dynamic(() => import('@monaco-editor/react'), { ssr: false });
|
|
|
|
export function CodeEditor() {
|
|
const { openFiles, activeFileId, updateFileContent, saveFile } = useEditorStore();
|
|
const { editorTab, setEditorTab } = useAppStore();
|
|
const activeFile = openFiles.find((f: any) => f.id === activeFileId);
|
|
|
|
React.useEffect(() => {
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
if ((e.metaKey || e.ctrlKey) && e.key === 's') {
|
|
e.preventDefault();
|
|
if (activeFileId) {
|
|
saveFile(activeFileId);
|
|
}
|
|
}
|
|
};
|
|
|
|
window.addEventListener('keydown', handleKeyDown);
|
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
}, [activeFileId, saveFile]);
|
|
|
|
if (!activeFile && editorTab === 'editor') {
|
|
return (
|
|
<div className="flex-1 flex items-center justify-center bg-background text-gray-400">
|
|
<div className="text-center">
|
|
<div className="text-6xl mb-4">📂</div>
|
|
<p className="text-lg mb-2">No file open</p>
|
|
<p className="text-sm">Select a file from the explorer to start editing</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="flex-1 flex flex-col bg-background">
|
|
<Tabs value={editorTab} onValueChange={(v) => setEditorTab(v as any)} className="flex-1 flex flex-col">
|
|
<div className="border-b border-gray-800 bg-surface">
|
|
<TabsList className="bg-transparent border-none h-auto p-0">
|
|
<TabsTrigger
|
|
value="editor"
|
|
className="data-[state=active]:bg-background data-[state=active]:border-b-2 data-[state=active]:border-primary rounded-none px-4 py-2"
|
|
>
|
|
Editor
|
|
</TabsTrigger>
|
|
<TabsTrigger
|
|
value="preview"
|
|
className="data-[state=active]:bg-background data-[state=active]:border-b-2 data-[state=active]:border-primary rounded-none px-4 py-2"
|
|
>
|
|
Cross-Platform Preview
|
|
</TabsTrigger>
|
|
<TabsTrigger
|
|
value="nexus-monitor"
|
|
className="data-[state=active]:bg-background data-[state=active]:border-b-2 data-[state=active]:border-primary rounded-none px-4 py-2"
|
|
>
|
|
Nexus Sync Monitor
|
|
</TabsTrigger>
|
|
</TabsList>
|
|
</div>
|
|
|
|
<TabsContent value="editor" className="flex-1 flex flex-col m-0">
|
|
<FileTabs />
|
|
{activeFile && (
|
|
<div className="flex-1">
|
|
<MonacoEditor
|
|
height="100%"
|
|
language={activeFile.language}
|
|
value={activeFile.content}
|
|
onChange={(value: string | undefined) => updateFileContent(activeFile.id, value || '')}
|
|
theme="vs-dark"
|
|
options={{
|
|
minimap: { enabled: true },
|
|
fontSize: 14,
|
|
lineNumbers: 'on',
|
|
rulers: [80, 120],
|
|
wordWrap: 'on',
|
|
automaticLayout: true,
|
|
tabSize: 2,
|
|
insertSpaces: true,
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
</TabsContent>
|
|
|
|
<TabsContent value="preview" className="flex-1 m-0">
|
|
<CrossPlatformPreview />
|
|
</TabsContent>
|
|
|
|
<TabsContent value="nexus-monitor" className="flex-1 m-0">
|
|
<NexusSyncMonitor />
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
);
|
|
}
|