-
Notifications
You must be signed in to change notification settings - Fork 0
Add Terminal component with ANSI parser support #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
05f0d4c
7e14062
6fec437
f956928
566a2d6
11506a3
b73db26
0e6debc
32b9632
8514fde
50a767a
54b344a
79c1e0f
d38122d
d09b78d
89450e9
b6fb5ea
dd242bb
bb04476
02f576b
b328a32
0efe956
8416261
446673e
3b1aeaa
29b5b81
ecbbaa9
12ed030
70e14be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,16 +6,17 @@ import { | |
| PlaygroundHeader, | ||
| PlaygroundPanel, | ||
| ResizablePanel, | ||
| } from '@setemiojo/playground-react' | ||
| } from "@setemiojo/playground-react"; | ||
| import { useState } from "react"; | ||
| // import { reactTemplate as newTemp } from "./react.ts"; | ||
| import { | ||
| nodeTemplate, | ||
| reactTemplate, | ||
| vanillaTemplate, | ||
| vueTemplate, | ||
| } from '@setemiojo/playground-templates' | ||
| import { useState } from 'react' | ||
| import './playground.css' | ||
| import './App.css' | ||
| import "./playground.css"; | ||
| import "./App.css"; | ||
|
|
||
| const templates: Record<string, Template> = { | ||
| vanilla: vanillaTemplate, | ||
|
|
@@ -25,30 +26,30 @@ const templates: Record<string, Template> = { | |
| } | ||
|
|
||
| export default function App() { | ||
| const [selectedTemplate, setSelectedTemplate] = useState<string>('react') | ||
| const [showSidebar, setShowSidebar] = useState(false) | ||
| const [selectedTemplate, setSelectedTemplate] = useState<string>("react"); | ||
| const [showSidebar, setShowSidebar] = useState(false); | ||
| const template = templates[selectedTemplate] | ||
|
|
||
| const getTitle = () => { | ||
| switch (selectedTemplate) { | ||
| case 'react': | ||
| return 'React Playground' | ||
| case 'vue': | ||
| return 'Vue Playground' | ||
| case 'node': | ||
| return 'Node.js Playground' | ||
| case "react": | ||
| return "React Playground"; | ||
| case "vue": | ||
| return "Vue Playground"; | ||
| case "node": | ||
| return "Node.js Playground"; | ||
| default: | ||
| return 'JavaScript Playground' | ||
| return "JavaScript Playground"; | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="app"> | ||
| <div className="template-bar"> | ||
| <select | ||
| disabled | ||
| value={selectedTemplate} | ||
| onChange={e => setSelectedTemplate(e.target.value)} | ||
| onChange={(e) => setSelectedTemplate(e.target.value)} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Satisfy arrow-parens and jsx-wrap-multilines rules. Lint requires removing unnecessary parens for single-arg arrows and wrapping multiline JSX expressions. 🛠️ Proposed fix- onChange={(e) => setSelectedTemplate(e.target.value)}
+ onChange={e => setSelectedTemplate(e.target.value)}
@@
- <ResizablePanel
- firstPanel={
- <div className="playground-editor-section">
- <PlaygroundEditor />
- </div>
- }
- secondPanel={
- <div className="playground-preview-section">
- <PlaygroundPanel />
- </div>
- }
+ <ResizablePanel
+ firstPanel={(
+ <div className="playground-editor-section">
+ <PlaygroundEditor />
+ </div>
+ )}
+ secondPanel={(
+ <div className="playground-preview-section">
+ <PlaygroundPanel />
+ </div>
+ )}Also applies to: 82-91 🧰 Tools🪛 ESLint[error] 52-52: Unexpected parentheses around single function argument having a body with no curly braces. (style/arrow-parens) 🤖 Prompt for AI Agents |
||
| > | ||
| <option value="vanilla">Vanilla JS</option> | ||
| <option value="react">React</option> | ||
|
|
@@ -78,16 +79,16 @@ export default function App() { | |
| </aside> | ||
| )} | ||
| <ResizablePanel | ||
| firstPanel={( | ||
| firstPanel={ | ||
| <div className="playground-editor-section"> | ||
| <PlaygroundEditor /> | ||
| </div> | ||
| )} | ||
| secondPanel={( | ||
| } | ||
| secondPanel={ | ||
| <div className="playground-preview-section"> | ||
| <PlaygroundPanel /> | ||
| </div> | ||
| )} | ||
| } | ||
| direction="horizontal" | ||
| responsive | ||
| responsiveBreakpoint={768} | ||
|
|
@@ -103,5 +104,5 @@ export default function App() { | |
| </Playground> | ||
| </main> | ||
| </div> | ||
| ) | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -92,9 +92,11 @@ | |||||||
|
|
||||||||
| .editor-container { | ||||||||
| flex: 1; | ||||||||
| overflow: auto; | ||||||||
| position: relative; | ||||||||
| overflow: hidden; | ||||||||
| } | ||||||||
|
|
||||||||
| /* CodeMirror Editor Styles */ | ||||||||
| .editor-container .cm-editor { | ||||||||
| height: 100%; | ||||||||
| } | ||||||||
|
|
@@ -105,6 +107,56 @@ | |||||||
| line-height: 1.6; | ||||||||
| } | ||||||||
|
|
||||||||
| /* Monaco Editor Styles */ | ||||||||
| .editor-container .monaco-editor { | ||||||||
| width: 100% !important; | ||||||||
| height: 100% !important; | ||||||||
| position: absolute !important; | ||||||||
| top: 0; | ||||||||
| left: 0; | ||||||||
| --monaco-monospace-font: 'JetBrains Mono', 'Fira Code', Menlo, Monaco, 'Courier New', monospace; | ||||||||
| --vscode-editor-background: var(--editor-bg); | ||||||||
| --vscode-editorGutter-background: var(--editor-bg); | ||||||||
| } | ||||||||
|
|
||||||||
| .editor-container .monaco-editor .overflow-guard { | ||||||||
| width: 100% !important; | ||||||||
| height: 100% !important; | ||||||||
| } | ||||||||
|
|
||||||||
| /* Fix Monaco textarea/input area */ | ||||||||
| .editor-container .monaco-editor .inputarea { | ||||||||
| min-width: 0 !important; | ||||||||
| width: auto !important; | ||||||||
| } | ||||||||
|
|
||||||||
| .editor-container .monaco-editor .lines-content { | ||||||||
| min-width: 100% !important; | ||||||||
| } | ||||||||
|
|
||||||||
| .editor-container .monaco-editor .view-lines { | ||||||||
| min-width: 100% !important; | ||||||||
| } | ||||||||
|
|
||||||||
| /* Ensure editor scrollable element works correctly */ | ||||||||
| .editor-container .monaco-editor .monaco-scrollable-element.editor-scrollable { | ||||||||
| width: 100% !important; | ||||||||
| } | ||||||||
|
|
||||||||
| /* Monaco Editor Links */ | ||||||||
| .editor-container .monaco-editor a { | ||||||||
| border-bottom: none; | ||||||||
| } | ||||||||
|
|
||||||||
| .editor-container .monaco-editor a:hover { | ||||||||
| border-bottom: none; | ||||||||
| } | ||||||||
|
|
||||||||
| /* Monaco fixed widgets */ | ||||||||
| .editor-container .monaco-editor .overflowingContentWidgets { | ||||||||
| z-index: 100; | ||||||||
| } | ||||||||
|
|
||||||||
| /* Preview Panel */ | ||||||||
| .playground-panel { | ||||||||
| flex: 1; | ||||||||
|
|
@@ -199,15 +251,17 @@ | |||||||
| } | ||||||||
|
|
||||||||
| .playground-panel-result, | ||||||||
| .playground-panel-console { | ||||||||
| .playground-panel-console, | ||||||||
| .playground-panel-terminal { | ||||||||
| position: absolute; | ||||||||
| inset: 0; | ||||||||
| display: none; | ||||||||
| overflow: auto; | ||||||||
| } | ||||||||
|
|
||||||||
| .playground-panel-result.active, | ||||||||
| .playground-panel-console.active { | ||||||||
| .playground-panel-console.active, | ||||||||
| .playground-panel-terminal.active { | ||||||||
| display: block; | ||||||||
| } | ||||||||
|
|
||||||||
|
|
@@ -300,6 +354,30 @@ | |||||||
| color: #dcdcaa; | ||||||||
| } | ||||||||
|
|
||||||||
| /* Terminal (xterm.js) */ | ||||||||
| .playground-panel-terminal { | ||||||||
| background: var(--terminal-bg); | ||||||||
| overflow: hidden; | ||||||||
| } | ||||||||
|
|
||||||||
| .playground-panel-terminal .playground-terminal-container { | ||||||||
| width: 100%; | ||||||||
| height: 100%; | ||||||||
| } | ||||||||
|
|
||||||||
| /* xterm.js overrides for better integration */ | ||||||||
| .playground-panel-terminal .xterm { | ||||||||
| padding: 8px; | ||||||||
| } | ||||||||
|
|
||||||||
| .playground-panel-terminal .xterm-viewport { | ||||||||
| overflow-y: auto !important; | ||||||||
| } | ||||||||
|
|
||||||||
| .playground-panel-terminal .xterm-screen { | ||||||||
| width: 100% !important; | ||||||||
| } | ||||||||
|
|
||||||||
| .playground-console-message.info { | ||||||||
| color: #75beff; | ||||||||
| } | ||||||||
|
Comment on lines
381
to
383
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate CSS rule for This rule (lines 329-331) duplicates the one at lines 286-289. This appears to be an artifact from inserting the terminal styles. Consider removing the duplicate. Proposed fix .playground-panel-terminal .xterm-screen {
width: 100% !important;
}
-
-.playground-console-message.info {
- color: `#75beff`;
-}
/* Legacy Preview (keep for compatibility) */📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| import type { Template } from '@setemiojo/playground-core' | ||
|
|
||
| export const reactTemplate: Template = { | ||
| id: 'react', | ||
| name: 'React', | ||
| description: 'React 19 with Vite', | ||
| files: { | ||
| 'package.json': { | ||
| file: { | ||
| contents: JSON.stringify( | ||
| { | ||
| name: 'react-playground', | ||
| type: 'module', | ||
| scripts: { | ||
| dev: 'vite', | ||
| build: 'vite build', | ||
| }, | ||
| dependencies: { | ||
| 'react': '^19.2.3', | ||
| 'react-dom': '^19.2.3', | ||
| }, | ||
| devDependencies: { | ||
| '@types/react': '^19.2.8', | ||
| '@types/react-dom': '^19.2.3', | ||
| '@vitejs/plugin-react': '^5.1.2', | ||
| 'vite': '^7.3.1', | ||
| }, | ||
| }, | ||
| null, | ||
| 2, | ||
| ), | ||
| }, | ||
| }, | ||
| 'vite.config.js': { | ||
| file: { | ||
| contents: `import { defineConfig } from 'vite'; | ||
| import react from '@vitejs/plugin-react'; | ||
|
|
||
| export default defineConfig({ | ||
| plugins: [react()], | ||
| });`, | ||
| }, | ||
| }, | ||
| 'index.html': { | ||
| file: { | ||
| contents: `<!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <title>React Playground</title> | ||
| </head> | ||
| <body> | ||
| <div id="root"></div> | ||
| <script type="module" src="/src/main.jsx"></script> | ||
| </body> | ||
| </html>`, | ||
| }, | ||
| }, | ||
| 'src': { | ||
| directory: { | ||
| 'main.jsx': { | ||
| file: { | ||
| contents: `import React from 'react'; | ||
| import ReactDOM from 'react-dom/client'; | ||
| import App from './App'; | ||
| import './index.css'; | ||
|
|
||
| ReactDOM.createRoot(document.getElementById('root')).render( | ||
| <React.StrictMode> | ||
| <App /> | ||
| </React.StrictMode> | ||
| );`, | ||
| }, | ||
| }, | ||
| 'App.jsx': { | ||
| file: { | ||
| contents: `import { useState } from 'react'; | ||
| import './App.css'; | ||
|
|
||
| function App() { | ||
| const [count, setCount] = useState(0); | ||
|
|
||
| return ( | ||
| <div className="App"> | ||
| <h1>React Playground</h1> | ||
| <p>Edit src/App.jsx to see changes instantly.</p> | ||
|
|
||
| <div className="card"> | ||
| <button onClick={() => setCount((count) => count + 1)}> | ||
| Count is {count} | ||
| </button> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| export default App;`, | ||
| }, | ||
| }, | ||
| 'App.css': { | ||
| file: { | ||
| contents: `.App { | ||
| text-align: center; | ||
| padding: 40px; | ||
| } | ||
|
|
||
| h1 { | ||
| color: #333; | ||
| margin-bottom: 20px; | ||
| } | ||
|
|
||
| .card { | ||
| padding: 20px; | ||
| } | ||
|
|
||
| button { | ||
| background: #007bff; | ||
| color: white; | ||
| border: none; | ||
| padding: 10px 20px; | ||
| border-radius: 4px; | ||
| cursor: pointer; | ||
| font-size: 16px; | ||
| } | ||
|
|
||
| button:hover { | ||
| background: #0056b3; | ||
| }`, | ||
| }, | ||
| }, | ||
| 'index.css': { | ||
| file: { | ||
| contents: `body { | ||
| margin: 0; | ||
| font-family: system-ui, -apple-system, sans-serif; | ||
| -webkit-font-smoothing: antialiased; | ||
| -moz-osx-font-smoothing: grayscale; | ||
| }`, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| dependencies: { | ||
| 'react': '^19.2.3', | ||
| 'react-dom': '^19.2.3', | ||
| }, | ||
| devDependencies: { | ||
| '@types/react': '^19.2.8', | ||
| '@types/react-dom': '^19.2.3', | ||
| '@vitejs/plugin-react': '^5.1.2', | ||
| 'vite': '^7.3.1', | ||
| }, | ||
| commands: { | ||
| dev: 'npm run dev', | ||
| }, | ||
| entryFile: '/src/App.jsx', | ||
| // Example: hide config files from the file tree | ||
| hiddenFiles: ['/vite.config.js', '/package.json'], | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove extra semicolons in component body.
style/semiis erroring on the state declarations, switch returns, and component return.🛠️ Proposed fix
Also applies to: 107-107
🧰 Tools
🪛 ESLint
[error] 29-29: Extra semicolon.
(style/semi)
[error] 30-30: Extra semicolon.
(style/semi)
[error] 36-36: Extra semicolon.
(style/semi)
[error] 38-38: Extra semicolon.
(style/semi)
[error] 40-40: Extra semicolon.
(style/semi)
[error] 42-42: Extra semicolon.
(style/semi)
[error] 44-44: Extra semicolon.
(style/semi)
🤖 Prompt for AI Agents