Merge pull request #12 from JBB0807/monaco-editor-page

Add Monaco Editor page
This commit is contained in:
JB Balahadia 2025-05-02 10:09:24 -07:00 committed by GitHub
commit bf1836b867
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 209 additions and 119 deletions

View file

@ -3,14 +3,32 @@ import Editor from '@monaco-editor/react';
export default function EditorPanel({ code, onChange }) { export default function EditorPanel({ code, onChange }) {
return ( return (
<div className="editor-panel"> <div style={{
border: '1px solid #444',
borderRadius: '8px',
backgroundColor: '#1e1e1e',
height: '400px',
boxShadow: '0 0 10px rgba(255, 0, 255, 0.2)',
overflow: 'hidden',
}}>
<Editor <Editor
height="100%" height="100%"
defaultLanguage="python" defaultLanguage="python"
value={code} value={code}
onChange={v => onChange(v || '')} onChange={v => onChange(v || '')}
theme="vs-dark" theme="vs-dark"
options={{
fontSize: 16,
padding: { top: 10, bottom: 10 },
minimap: { enabled: false },
scrollbar: {
verticalScrollbarSize: 8,
horizontalScrollbarSize: 8,
},
lineNumbers: 'on',
scrollBeyondLastLine: false,
}}
/> />
</div> </div>
); );
} }

View file

@ -1,131 +1,203 @@
// Page - Code Editor
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import CodeMirror from "@uiw/react-codemirror";
import { javascript } from "@codemirror/lang-javascript";
import { html } from "@codemirror/lang-html";
import { css } from "@codemirror/lang-css";
import { vscodeDark } from "@uiw/codemirror-theme-vscode";
import EditorPanel from "../components/EditorPanel"; import EditorPanel from "../components/EditorPanel";
import PreviewPanel from "../components/PreviewPanel";
const PageCodeEditor = () => { const PageCodeEditor = () => {
const [code, setCode] = useState(`# Write your Battlesnake code here\ndef move(board):\n return { 'move': 'up' }`); const [code, setCode] = useState(`# Write your Battlesnake code here\ndef move(board):\n return { 'move': 'up' }`);
// State for storing code in different tabs
const [htmlCode, setHtmlCode] = useState(
"<div>\n <h1>Hello World</h1>\n <p>Start editing to see some magic happen!</p>\n</div>"
);
const [cssCode, setCssCode] = useState(
"h1 {\n color: #0070f3;\n}\n\np {\n color: #444;\n}"
);
const [jsCode, setJsCode] = useState(
'// JavaScript goes here\nconsole.log("Hello from the editor!");'
);
// State for active tab
const [activeTab, setActiveTab] = useState("html");
// Combined code for preview
const combinedCode = `
<html>
<head>
<style>${cssCode}</style>
</head>
<body>
${htmlCode}
<script>${jsCode}</script>
</body>
</html>
`;
useEffect(() => { useEffect(() => {
document.title = "Code Editor"; document.title = "Snake Brain Editor";
}, []); }, []);
// Function to handle which editor to show based on active tab
const renderEditor = () => {
switch (activeTab) {
case "html":
return (
<CodeMirror
value={htmlCode}
height="100%"
theme={vscodeDark}
extensions={[html()]}
onChange={(value) => setHtmlCode(value)}
/>
);
case "css":
return (
<CodeMirror
value={cssCode}
height="100%"
theme={vscodeDark}
extensions={[css()]}
onChange={(value) => setCssCode(value)}
/>
);
case "js":
return (
<CodeMirror
value={jsCode}
height="100%"
theme={vscodeDark}
extensions={[javascript()]}
onChange={(value) => setJsCode(value)}
/>
);
default:
return null;
}
};
return ( return (
<main className="code-editor-page"> <main className="code-editor-page" style={{ paddingTop: '70px' }}>
<div
<div className="editor-section"> className="editor-page-layout"
<EditorPanel code={code} onChange={setCode} /> style={{
</div> display: 'flex',
<div className="preview-section"> gap: '2rem',
<PreviewPanel code={code} /> padding: '2rem',
</div> fontFamily: "'Fira Code', 'Courier New', monospace",
}}
<div className="editor-container"> >
<div className="editor-tabs"> {/* python editor */}
<button <div
className={`tab ${activeTab === "html" ? "active" : ""}`} className="box-panel"
onClick={() => setActiveTab("html")} style={{
> flex: 2,
HTML background: 'linear-gradient(145deg, #0d0221, #1a1a1a)',
</button> borderRadius: '12px',
<button boxShadow: '0 0 15px #05d9e8, 0 0 30px #ff2a6d',
className={`tab ${activeTab === "css" ? "active" : ""}`} border: '1px solid #ff2a6d',
onClick={() => setActiveTab("css")} padding: '1rem',
> color: '#eee',
CSS }}
</button> >
<button <div
className={`tab ${activeTab === "js" ? "active" : ""}`} style={{
onClick={() => setActiveTab("js")} backgroundColor: '#ff2a6d',
> height: '6px',
JavaScript borderRadius: '3px 3px 0 0',
</button> marginBottom: '0.5rem',
</div> }}
<div className="editor-content">{renderEditor()}</div>
</div>
<div className="preview-container">
<div className="preview-header">
<h3>Preview</h3>
</div>
<div className="preview-content">
<iframe
title="code-preview"
srcDoc={combinedCode}
sandbox="allow-scripts"
width="100%"
height="100%"
/> />
<h3
className="panel-heading"
style={{
fontSize: '1.2rem',
color: '#05d9e8',
textShadow: '0 0 5px #05d9e8',
marginBottom: '1rem',
}}
>
🐍 Snake Brain (Python)
</h3>
<EditorPanel code={code} onChange={setCode} />
</div>
{/* live arena */}
<div
className="box-panel"
style={{
flex: 1,
background: '#1a1a1a',
borderRadius: '12px',
boxShadow: '0 0 15px #d300c5, 0 0 25px #ff2a6d',
border: '1px solid #d300c5',
padding: '1rem',
color: '#eee',
}}
>
<div
style={{
backgroundColor: '#d300c5',
height: '6px',
borderRadius: '3px 3px 0 0',
marginBottom: '0.5rem',
}}
/>
<h3
style={{
fontSize: '1.2rem',
color: '#d300c5',
textShadow: '0 0 5px #d300c5',
marginBottom: '1rem',
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
}}
>
🎯 Live Arena Output
</h3>
<h4 style={{ color: '#fff', textAlign: 'center', marginBottom: '1rem' }}>
Battlesnake Preview
</h4>
{/* game url*/}
<div
style={{
background: 'rgba(255,255,255,0.05)',
border: '1px solid #ff2a6d',
borderRadius: '8px',
padding: '1rem',
marginBottom: '1rem',
textAlign: 'center',
}}
>
<input
type="text"
placeholder="Game URL"
style={{
background: 'transparent',
border: 'none',
color: '#fff',
width: '100%',
textAlign: 'center',
fontFamily: "'Fira Code', monospace",
outline: 'none',
}}
/>
<button
style={{
backgroundColor: '#ff2a6d',
color: '#fff',
padding: '0.5rem 1rem',
border: 'none',
borderRadius: '20px',
marginTop: '0.5rem',
cursor: 'pointer',
width: '100%',
fontWeight: 'bold',
}}
>
FETCH BOARD
</button>
</div>
{/* snake api */}
<div
style={{
background: 'rgba(255,255,255,0.05)',
border: '1px solid #ff2a6d',
borderRadius: '8px',
padding: '1rem',
marginBottom: '1rem',
textAlign: 'center',
}}
>
<input
type="text"
placeholder="Your Snake API URL"
style={{
background: 'transparent',
border: 'none',
color: '#fff',
width: '100%',
textAlign: 'center',
fontFamily: "'Fira Code', monospace",
outline: 'none',
}}
/>
<button
style={{
backgroundColor: '#ff2a6d',
color: '#fff',
padding: '0.5rem 1rem',
border: 'none',
borderRadius: '20px',
marginTop: '0.5rem',
cursor: 'pointer',
width: '100%',
fontWeight: 'bold',
}}
>
CONNECT SNAKE API
</button>
</div>
{/* test move button */}
<div
style={{
display: 'flex',
justifyContent: 'center',
marginTop: '2rem',
}}
>
<button
style={{
backgroundColor: '#ff2a6d',
color: '#fff',
padding: '0.5rem 2rem',
border: 'none',
borderRadius: '20px',
fontWeight: 'bold',
cursor: 'pointer',
boxShadow: '0 0 10px #ff2a6d',
}}
>
TEST MOVE
</button>
</div>
</div> </div>
</div> </div>
</main> </main>