JavaRunner / index.html
parthmax's picture
Update index.html
a40fdda verified
raw
history blame
10.1 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaRunner — Learn & Run Java Online</title>
<meta name="description" content="JavaRunner is a mobile-friendly online Java IDE. Write, run, save, and download Java code. Perfect for beginners like Ragini Didi.">
<meta name="keywords" content="Java IDE, Online Java compiler, JavaRunner, Learn Java, Java code editor, mobile-friendly IDE, Ragini Didi">
<meta name="author" content="Saksham Pathak">
<meta name="robots" content="index, follow">
<!-- Open Graph for SEO & social -->
<meta property="og:title" content="JavaRunner — Learn & Run Java Online">
<meta property="og:description" content="JavaRunner is a mobile-friendly online Java IDE. Write, run, save, and download Java code. Perfect for beginners like Ragini Didi.">
<meta property="og:type" content="website">
<!-- Font -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap" rel="stylesheet">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<!-- CodeMirror -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/clike/clike.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/edit/closebrackets.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/edit/matchbrackets.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/edit/indentation.min.js"></script>
<style>
:root {
--bg:#0b1b2b;
--glass: rgba(255,255,255,0.05);
--glass-hover: rgba(255,255,255,0.08);
--accent:#6c8cff;
--accent-light:#8be5d0;
--text:#e6eef8;
--muted:#9aa4b2;
--radius:14px;
--shadow:0 8px 30px rgba(2,6,23,0.6);
}
*{box-sizing:border-box;}
body{
margin:0;
font-family: 'Inter', sans-serif;
background: linear-gradient(180deg, #071227, #0d1a2b);
color:var(--text);
min-height:100vh;
display:flex;
flex-direction:column;
align-items:center;
padding:10px;
}
h1,h2,h3,h4,h5{margin:0;padding:0;}
a{text-decoration:none;color:var(--accent);}
a:hover{color:var(--accent-light);}
/* App container */
.app{
display:flex;
flex-direction:row;
gap:12px;
width:100%;
max-width:1200px;
flex:1;
}
.panel{
background: var(--glass);
backdrop-filter: blur(12px) saturate(1.1);
border-radius: var(--radius);
padding:12px;
box-shadow: var(--shadow);
border:1px solid rgba(255,255,255,0.08);
transition: transform .2s ease, box-shadow .2s ease;
}
.panel:hover{transform:translateY(-3px);box-shadow:0 16px 40px rgba(8,14,40,0.5);}
/* Sidebar */
.sidebar{
flex:0 0 240px;
display:flex;
flex-direction:column;
gap:10px;
height:calc(100vh - 40px);
}
.sidebar-header{
display:flex;
justify-content:space-between;
align-items:center;
margin-bottom:8px;
}
.brand{
font-weight:700;
font-size:18px;
color:var(--accent);
display:flex;
align-items:center;
gap:8px;
}
.brand i{font-size:20px;}
.file-list{
flex:1;
overflow-y:auto;
display:flex;
flex-direction:column;
gap:6px;
}
.file-item{
display:flex;
justify-content:space-between;
align-items:center;
padding:6px 8px;
border-radius:10px;
cursor:pointer;
background: rgba(255,255,255,0.02);
transition:0.15s ease;
}
.file-item:hover{background:var(--glass-hover);}
.file-item.active{background:rgba(108,140,255,0.12);color:#fff;}
.file-actions{display:flex;gap:6px;align-items:center;}
/* Editor area */
.editor-area{
flex:1;
display:flex;
flex-direction:column;
gap:8px;
min-height:400px;
}
.cm-wrap{border-radius:12px;overflow:hidden;border:1px solid rgba(255,255,255,0.04);}
.CodeMirror{height:calc(100vh - 240px);background: rgba(2,6,23,0.7); color:#e8f1ff; font-size:13px;}
/* Buttons */
.btn{
background: rgba(255,255,255,0.03);
border:1px solid rgba(255,255,255,0.08);
color:var(--muted);
padding:6px 10px;
border-radius:10px;
cursor:pointer;
display:inline-flex;
align-items:center;
gap:6px;
transition:all .15s ease;
}
.btn:hover{color:#fff;transform:translateY(-2px);background:var(--glass-hover);}
.btn-primary{
background: linear-gradient(90deg,var(--accent),var(--accent-light));
color:#04253b;
padding:10px 14px;
font-weight:700;
border:none;
}
.console{
margin-top:6px;
background: rgba(0,0,0,0.5);
border-radius:10px;
padding:12px;
font-family:monospace;
color:#cfe7ff;
min-height:120px;
overflow:auto;
}
/* Footer */
footer{
text-align:center;
color:var(--muted);
font-size:14px;
padding:12px 0 4px 0;
}
footer .note{color:#c7d7ff;font-weight:600;}
/* Responsive */
@media (max-width:900px){
.app{flex-direction:column;}
.sidebar{width:100%;height:auto;order:2;}
.editor-area{order:1;}
.CodeMirror{height:300px;}
}
@media (max-width:480px){
body{padding:6px;}
.brand{font-size:16px;}
.btn{padding:5px 8px;font-size:13px;}
.btn-primary{padding:8px 10px;font-size:14px;}
}
</style>
</head>
<body>
<header class="sidebar-header">
<div class="brand"><i class="fa-solid fa-rocket"></i> JavaRunner</div>
</header>
<div class="app">
<!-- Sidebar -->
<div class="panel sidebar">
<div class="sidebar-header">
<button class="btn" id="newBtn"><i class="fa-solid fa-file-circle-plus"></i> New</button>
<button class="btn" id="importBtn"><i class="fa-solid fa-file-import"></i> Import</button>
</div>
<input type="text" placeholder="Search files..." id="searchFile" style="width:100%;padding:6px;border-radius:8px;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.08);color:var(--muted);margin-bottom:6px;">
<div class="file-list" id="fileList"></div>
</div>
<!-- Editor -->
<div class="panel editor-area">
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;">
<div>Active File: <span id="activeFile"></span></div>
<div style="display:flex;gap:6px;flex-wrap:wrap;">
<button class="btn-primary" id="runBtn"><i class="fa-solid fa-play"></i> Run</button>
<button class="btn" id="saveBtn"><i class="fa-solid fa-floppy-disk"></i> Save</button>
<button class="btn" id="downloadBtn"><i class="fa-solid fa-download"></i> Download</button>
<button class="btn" id="formatBtn"><i class="fa-solid fa-align-left"></i> Format</button>
<button class="btn" id="cutBtn"><i class="fa-solid fa-cut"></i></button>
<button class="btn" id="copyBtn"><i class="fa-solid fa-copy"></i></button>
<button class="btn" id="pasteBtn"><i class="fa-solid fa-clipboard"></i></button>
<button class="btn" id="deleteBtn"><i class="fa-solid fa-trash"></i></button>
</div>
</div>
<div class="cm-wrap" id="cmWrap"><div id="editor"></div></div>
<div class="console" id="console">Console output will appear here.</div>
</div>
</div>
<footer>
Made with ❤️ for <span class="note">Ragini Didi</span>
</footer>
<input type="file" id="fileInput" accept=".java" style="display:none">
<script>
// ---------- Editor setup ----------
const editor = CodeMirror(document.getElementById('editor'),{
mode:"text/x-java",
lineNumbers:true,
tabSize:4,
indentUnit:4,
autoCloseBrackets:true,
matchBrackets:true,
value:"class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello Ragini!\");\n }\n}"
});
// Resize editor for mobile
function resizeEditor(){
const wrap=document.querySelector('.CodeMirror');
if(!wrap) return;
let vh=window.innerHeight;
wrap.style.height=(vh - 280)+'px';
editor.refresh();
}
window.addEventListener('resize',resizeEditor);
setTimeout(resizeEditor,200);
// ---------- Local storage ----------
let files=JSON.parse(localStorage.getItem('javaRunner_files')||'{}');
let active=localStorage.getItem('javaRunner_active')||null;
const fileListEl=document.getElementById('fileList');
const activeFileEl=document.getElementById('activeFile');
const consoleEl=document.getElementById('console');
function saveToStorage(){localStorage.setItem('javaRunner_files',JSON.stringify(files));}
function setActive(name){
active=name;
localStorage.setItem('javaRunner_active',active);
activeFileEl.innerText=name||'—';
renderFiles();
if(active && files[active]) editor.setValue(files[active]);
}
function renderFiles(filter=''){
fileListEl.innerHTML='';
const names=Object.keys(files).filter(n=>n.toLowerCase().includes(filter.toLowerCase())).sort();
if(names.length===0){fileListEl.innerHTML='<div style="color:'+ 'var(--muted)' +';padding:10px;font-size:13px">No files yet.</div>';return;}
names.forEach(name=>{
const div=document.createElement('div');
div.className='file-item'+(name===active?' active':'');
div.innerHTML=`<div>${name}</div><div style="display:flex;gap:6px;">
<button class="btn" onclick="openFile('${name}')"><i class="fa-solid fa-folder-open"></i></button></div>`;
fileListEl.appendChild(div);
});
}
function newFile(){
let name=prompt('Filename (end with .java)','Main.java');
if(!name) return;if(!name.endsWith('.java')){alert('Filename must end with .java');return;}
if(files[name]){alert('File exists');return;}
const classname=name.replace('.java','').replace(/[^A-Za-z0-9_]/g,'')||'Main';
files[name]=`class ${classname} {\n public static void main(String[] args) {\