| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Premium AI Notebook</title> |
| <style> |
| |
| *, *::before, *::after { box-sizing: border-box; } |
| body, html { margin: 0; padding: 0; height: 100%; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background-color: #1e1e1e; color: #d4d4d4; overflow: hidden; display: flex; flex-direction: column; } |
| |
| |
| .header { background-color: #252526; padding: 12px 20px; border-bottom: 1px solid #3c3c3c; display: flex; justify-content: space-between; align-items: center; z-index: 10; } |
| .header h2 { margin: 0; font-size: 16px; color: #cccccc; font-weight: 600; letter-spacing: 0.5px; } |
| .header-buttons button { background-color: #0e639c; color: white; border: none; padding: 6px 12px; cursor: pointer; border-radius: 2px; font-size: 13px; margin-left: 8px; } |
| .header-buttons button:hover { background-color: #1177bb; } |
| |
| |
| .main-container { display: flex; flex-direction: column; flex: 1; height: calc(100% - 45px); } |
| |
| |
| .notebook-panel { flex: 1; overflow-y: auto; padding: 20px; background-color: #1e1e1e; } |
| .cell { background: #1e1e1e; border: 1px solid #3c3c3c; border-radius: 2px; margin-bottom: 20px; display: flex; flex-direction: column; } |
| .cell-toolbar { background: #252526; padding: 6px 10px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #3c3c3c; } |
| .cell-title { font-size: 12px; color: #858585; font-family: monospace; } |
| .cell-actions button { background: transparent; color: #cccccc; border: 1px solid #3c3c3c; padding: 4px 8px; cursor: pointer; border-radius: 2px; font-size: 11px; margin-left: 5px; } |
| .cell-actions button.run-btn { background: #007acc; color: white; border-color: #007acc; } |
| .cell-actions button.run-btn:hover { background: #005f9e; } |
| .cell-actions button:hover:not(.run-btn) { background: #333333; } |
| |
| .code-input { width: 100%; height: 120px; background: #1e1e1e; color: #9cdcfe; border: none; padding: 12px; font-family: 'Consolas', monospace; font-size: 14px; resize: vertical; outline: none; line-height: 1.5; } |
| |
| |
| .input-data-row { background: #2d2d2d; border-top: 1px solid #3c3c3c; padding: 6px 12px; display: flex; align-items: center; } |
| .input-data-row label { font-size: 11px; color: #858585; margin-right: 10px; font-family: monospace; } |
| .input-data-field { flex: 1; background: #1e1e1e; border: 1px solid #3c3c3c; color: #d4d4d4; padding: 4px 8px; font-size: 12px; font-family: monospace; outline: none; border-radius: 2px; } |
| .input-data-field:focus { border-color: #007acc; } |
| |
| .code-output { background: #111111; color: #cecece; padding: 12px; font-family: 'Consolas', monospace; font-size: 13px; white-space: pre-wrap; border-top: 1px solid #3c3c3c; display: none; margin: 0; line-height: 1.5; } |
| |
| |
| .resizer { height: 5px; background-color: #252526; cursor: ns-resize; border-top: 1px solid #3c3c3c; border-bottom: 1px solid #3c3c3c; z-index: 10; transition: background 0.2s; } |
| .resizer:hover { background-color: #007acc; border-color: #007acc; } |
| |
| |
| .terminal-panel { height: 300px; background-color: #111111; display: flex; flex-direction: column; min-height: 100px; } |
| .terminal-header { background: #252526; color: #cccccc; padding: 6px 15px; font-size: 11px; font-family: sans-serif; border-bottom: 1px solid #3c3c3c; letter-spacing: 0.5px; } |
| .terminal-content { flex: 1; overflow-y: auto; padding: 10px; font-family: 'Consolas', monospace; font-size: 13px; color: #cccccc; } |
| .terminal-history { white-space: pre-wrap; margin-bottom: 5px; } |
| .terminal-input-wrapper { display: flex; align-items: center; } |
| .terminal-prompt { color: #4caf50; margin-right: 8px; } |
| .terminal-input { flex: 1; background: transparent; border: none; color: #ffffff; font-family: 'Consolas', monospace; font-size: 13px; outline: none; } |
| </style> |
| </head> |
| <body> |
|
|
| <div class="header"> |
| <h2>Priyanshu's Notebook</h2> |
| <div class="header-buttons"> |
| <button onclick="addCell()">+ Add Cell</button> |
| </div> |
| </div> |
|
|
| <div class="main-container"> |
| <div class="notebook-panel" id="notebook"></div> |
|
|
| <div class="resizer" id="dragMe"></div> |
|
|
| <div class="terminal-panel" id="terminalPanel"> |
| <div class="terminal-header">TERMINAL</div> |
| <div class="terminal-content" id="term-content" onclick="document.getElementById('term-in').focus()"> |
| <div class="terminal-history" id="term-history">bash v1.0 connected...</div> |
| <div class="terminal-input-wrapper"> |
| <span class="terminal-prompt">~/project$</span> |
| <input type="text" class="terminal-input" id="term-in" onkeydown="runTerminal(event)" autocomplete="off"> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| let cellCount = 0; |
| |
| function addCell() { |
| cellCount++; |
| const id = cellCount; |
| const cellHtml = ` |
| <div class="cell" id="cell-${id}"> |
| <div class="cell-toolbar"> |
| <span class="cell-title">Cell [${id}]</span> |
| <div class="cell-actions"> |
| <button onclick="clearOutput(${id})">Clear</button> |
| <button onclick="deleteCell(${id})">Delete</button> |
| <button class="run-btn" onclick="runCode(${id})">▶ Run</button> |
| </div> |
| </div> |
| <textarea class="code-input" id="code-${id}" placeholder="print('Hello World')"></textarea> |
| |
| <div class="input-data-row"> |
| <label>Expected input():</label> |
| <input type="text" class="input-data-field" id="inputs-${id}" placeholder="Comma separated values (e.g. Priyanshu, 25)"> |
| </div> |
| |
| <pre class="code-output" id="output-${id}"></pre> |
| </div> |
| `; |
| document.getElementById("notebook").insertAdjacentHTML('beforeend', cellHtml); |
| } |
| |
| function deleteCell(id) { |
| document.getElementById(`cell-${id}`).remove(); |
| } |
| |
| function clearOutput(id) { |
| const outputEl = document.getElementById(`output-${id}`); |
| outputEl.style.display = "none"; |
| outputEl.innerText = ""; |
| } |
| |
| async function runCode(id) { |
| const code = document.getElementById(`code-${id}`).value; |
| const inputText = document.getElementById(`inputs-${id}`).value; |
| const outputEl = document.getElementById(`output-${id}`); |
| |
| |
| const inputsArray = inputText ? inputText.split(',').map(item => item.trim()) : []; |
| |
| outputEl.style.display = "block"; |
| outputEl.innerText = "[*] Executing..."; |
| |
| try { |
| const res = await fetch("/run_code", { |
| method: "POST", |
| headers: { "Content-Type": "application/json" }, |
| body: JSON.stringify({ code: code, inputs: inputsArray }) |
| }); |
| const data = await res.json(); |
| outputEl.innerText = data.output || "[Done] No output."; |
| } catch (err) { |
| outputEl.innerText = "Execution Failed: " + err; |
| } |
| } |
| |
| async function runTerminal(e) { |
| if (e.key === "Enter") { |
| const cmd = e.target.value; |
| if (!cmd.trim()) return; |
| |
| const historyEl = document.getElementById("term-history"); |
| const contentEl = document.getElementById("term-content"); |
| |
| historyEl.innerText += `\n~/project$ ${cmd}`; |
| e.target.value = "Running..."; |
| e.target.disabled = true; |
| |
| try { |
| const res = await fetch("/run_terminal", { |
| method: "POST", |
| headers: { "Content-Type": "application/json" }, |
| body: JSON.stringify({ cmd }) |
| }); |
| const data = await res.json(); |
| if(data.output.trim() !== "") { |
| historyEl.innerText += `\n${data.output.trim()}`; |
| } |
| } catch (err) { |
| historyEl.innerText += `\nCommand error.`; |
| } |
| |
| e.target.value = ""; |
| e.target.disabled = false; |
| e.target.focus(); |
| contentEl.scrollTop = contentEl.scrollHeight; |
| } |
| } |
| |
| |
| const resizer = document.getElementById('dragMe'); |
| const terminalPanel = document.getElementById('terminalPanel'); |
| let isResizing = false; |
| |
| resizer.addEventListener('mousedown', function(e) { |
| isResizing = true; |
| document.body.style.cursor = 'ns-resize'; |
| }); |
| |
| document.addEventListener('mousemove', function(e) { |
| if (!isResizing) return; |
| const newHeight = window.innerHeight - e.clientY; |
| if (newHeight > 50 && newHeight < window.innerHeight - 100) { |
| terminalPanel.style.height = newHeight + 'px'; |
| } |
| }); |
| |
| document.addEventListener('mouseup', function() { |
| isResizing = false; |
| document.body.style.cursor = 'default'; |
| }); |
| |
| window.onload = addCell; |
| </script> |
| </body> |
| </html> |
|
|