diff --git a/frontends/nextjs/src/components/editors/lua/BlockListView.tsx b/frontends/nextjs/src/components/editors/lua/BlockListView.tsx new file mode 100644 index 000000000..9176fba4e --- /dev/null +++ b/frontends/nextjs/src/components/editors/lua/BlockListView.tsx @@ -0,0 +1,95 @@ +import type { MouseEvent } from 'react' +import { Box, Button, Card, CardContent, CardHeader, Stack, TextField, Typography } from '@mui/material' +import { Add as AddIcon } from '@mui/icons-material' +import type { LuaScript } from '@/lib/level-types' +import type { BlockDefinition, BlockSlot, LuaBlock, LuaBlockType } from './types' +import { BlockList } from './blocks/BlockList' +import styles from './LuaBlocksEditor.module.scss' + +interface BlockListViewProps { + activeBlocks: LuaBlock[] + blockDefinitionMap: Map + onRequestAddBlock: ( + event: MouseEvent, + target: { parentId: string | null; slot: BlockSlot } + ) => void + onMoveBlock: (blockId: string, direction: 'up' | 'down') => void + onDuplicateBlock: (blockId: string) => void + onRemoveBlock: (blockId: string) => void + onUpdateField: (blockId: string, fieldName: string, value: string) => void + onUpdateScript: (updates: Partial) => void + selectedScript: LuaScript | null +} + +export function BlockListView({ + activeBlocks, + blockDefinitionMap, + onRequestAddBlock, + onMoveBlock, + onDuplicateBlock, + onRemoveBlock, + onUpdateField, + onUpdateScript, + selectedScript, +}: BlockListViewProps) { + return ( + + } + onClick={(event) => onRequestAddBlock(event, { parentId: null, slot: 'root' })} + disabled={!selectedScript} + > + Add block + + } + /> + + {!selectedScript ? ( + + Select a script to start building blocks. + + ) : ( + + + onUpdateScript({ name: event.target.value })} + fullWidth + /> + onUpdateScript({ description: event.target.value })} + fullWidth + /> + + + {activeBlocks.length > 0 ? ( + + ) : ( + Add a block to start building Lua logic. + )} + + + Blocks are saved in the script as metadata, so you can reload them later. + + + )} + + + ) +} diff --git a/frontends/nextjs/src/components/editors/lua/CodePreview.tsx b/frontends/nextjs/src/components/editors/lua/CodePreview.tsx new file mode 100644 index 000000000..c83746fdb --- /dev/null +++ b/frontends/nextjs/src/components/editors/lua/CodePreview.tsx @@ -0,0 +1,73 @@ +import { Box, Button, Card, CardContent, CardHeader, Stack, Tooltip } from '@mui/material' +import { ContentCopy, Refresh as RefreshIcon, Save as SaveIcon } from '@mui/icons-material' +import type { LuaScript } from '@/lib/level-types' +import styles from './LuaBlocksEditor.module.scss' + +interface CodePreviewProps { + generatedCode: string + onApplyCode: () => void + onCopyCode: () => void + onReloadFromCode: () => void + selectedScript: LuaScript | null +} + +export function CodePreview({ + generatedCode, + onApplyCode, + onCopyCode, + onReloadFromCode, + selectedScript, +}: CodePreviewProps) { + return ( + + + + + + + + + + + + + + + } + /> + + +
{generatedCode}
+
+
+
+ ) +} diff --git a/frontends/nextjs/src/components/editors/lua/LuaBlocksEditor.tsx b/frontends/nextjs/src/components/editors/lua/LuaBlocksEditor.tsx index 212f840ba..58b2534f7 100644 --- a/frontends/nextjs/src/components/editors/lua/LuaBlocksEditor.tsx +++ b/frontends/nextjs/src/components/editors/lua/LuaBlocksEditor.tsx @@ -5,27 +5,21 @@ import { CardContent, CardHeader, Divider, + IconButton, List, ListItemButton, ListItemText, Paper, Stack, - TextField, Tooltip, Typography, } from '@mui/material' -import { - Add as AddIcon, - ContentCopy, - Delete as DeleteIcon, - Refresh as RefreshIcon, - Save as SaveIcon, -} from '@mui/icons-material' +import { Add as AddIcon, Delete as DeleteIcon } from '@mui/icons-material' import type { LuaScript } from '@/lib/level-types' -import { BlockList } from './blocks/BlockList' import { BlockMenu } from './blocks/BlockMenu' -import { useBlockDefinitions } from './hooks/useBlockDefinitions' -import { useLuaBlocksState } from './hooks/useLuaBlocksState' +import { BlockListView } from './BlockListView' +import { CodePreview } from './CodePreview' +import { useLuaBlockEditorState } from './hooks/useLuaBlockEditorState' import styles from './LuaBlocksEditor.module.scss' interface LuaBlocksEditorProps { @@ -34,18 +28,11 @@ interface LuaBlocksEditorProps { } export function LuaBlocksEditor({ scripts, onScriptsChange }: LuaBlocksEditorProps) { - const { - blockDefinitions, - blockDefinitionMap, - blocksByCategory, - createBlock, - cloneBlock, - buildLuaFromBlocks, - decodeBlocksMetadata, - } = useBlockDefinitions() - const { activeBlocks, + blockDefinitionMap, + blockDefinitions, + blocksByCategory, generatedCode, handleAddBlock, handleAddScript, @@ -64,173 +51,7 @@ export function LuaBlocksEditor({ scripts, onScriptsChange }: LuaBlocksEditorPro selectedScript, selectedScriptId, setSelectedScriptId, - } = useLuaBlocksState({ - scripts, - onScriptsChange, - buildLuaFromBlocks, - createBlock, - cloneBlock, - decodeBlocksMetadata, - }) - - const renderBlockLibrary = () => ( - - - - - {Object.entries(blocksByCategory).map(([category, blocks]) => ( - - - {category} - - - {blocks.map((block) => ( - handleAddBlock(block.type, { parentId: null, slot: 'root' })} - > - - - {block.label} - {block.description} - - - - - ))} - - - ))} - - - - ) - - const renderWorkspace = () => ( - - } - onClick={(event) => handleRequestAddBlock(event, { parentId: null, slot: 'root' })} - disabled={!selectedScript} - > - Add block - - } - /> - - {!selectedScript ? ( - - Select a script to start building blocks. - - ) : ( - - - handleUpdateScript({ name: event.target.value })} - fullWidth - /> - handleUpdateScript({ description: event.target.value })} - fullWidth - /> - - - {activeBlocks.length > 0 ? ( - - ) : ( - Add a block to start building Lua logic. - )} - - - Blocks are saved in the script as metadata, so you can reload them later. - - - )} - - - ) - - const renderScriptList = () => ( - - - - - - - - {scripts.length === 0 && ( - - No scripts yet. Create a block script to begin. - - )} - {scripts.map((script) => ( - setSelectedScriptId(script.id)} - sx={{ - borderRadius: 2, - mb: 1, - alignItems: 'flex-start', - }} - > - - - { - event.stopPropagation() - handleDeleteScript(script.id) - }} - > - - - - - ))} - - - - - ) + } = useLuaBlockEditorState({ scripts, onScriptsChange }) return ( @@ -242,55 +63,121 @@ export function LuaBlocksEditor({ scripts, onScriptsChange }: LuaBlocksEditorPro }} > - {renderScriptList()} - {renderBlockLibrary()} + + + + + + + + {scripts.length === 0 && ( + + No scripts yet. Create a block script to begin. + + )} + {scripts.map((script) => ( + setSelectedScriptId(script.id)} + sx={{ + borderRadius: 2, + mb: 1, + alignItems: 'flex-start', + }} + > + + + { + event.stopPropagation() + handleDeleteScript(script.id) + }} + > + + + + + ))} + + + + + + + + + + {Object.entries(blocksByCategory).map(([category, blocks]) => ( + + + {category} + + + {blocks.map((block) => ( + handleAddBlock(block.type, { parentId: null, slot: 'root' })} + > + + + {block.label} + {block.description} + + + + + ))} + + + ))} + + + - {renderWorkspace()} + - - - - - - - - - - - - - - - - - - - } - /> - - -
{generatedCode}
-
-
- +
diff --git a/frontends/nextjs/src/components/editors/lua/hooks/useLuaBlockEditorState.ts b/frontends/nextjs/src/components/editors/lua/hooks/useLuaBlockEditorState.ts new file mode 100644 index 000000000..618b5f491 --- /dev/null +++ b/frontends/nextjs/src/components/editors/lua/hooks/useLuaBlockEditorState.ts @@ -0,0 +1,26 @@ +import type { LuaScript } from '@/lib/level-types' +import { useBlockDefinitions } from './useBlockDefinitions' +import { useLuaBlocksState } from './useLuaBlocksState' + +interface UseLuaBlockEditorStateProps { + scripts: LuaScript[] + onScriptsChange: (scripts: LuaScript[]) => void +} + +export function useLuaBlockEditorState({ scripts, onScriptsChange }: UseLuaBlockEditorStateProps) { + const blockDefinitionState = useBlockDefinitions() + + const luaBlockState = useLuaBlocksState({ + scripts, + onScriptsChange, + buildLuaFromBlocks: blockDefinitionState.buildLuaFromBlocks, + createBlock: blockDefinitionState.createBlock, + cloneBlock: blockDefinitionState.cloneBlock, + decodeBlocksMetadata: blockDefinitionState.decodeBlocksMetadata, + }) + + return { + ...blockDefinitionState, + ...luaBlockState, + } +}