Skip to content

Commit 8a4727f

Browse files
authored
Add initial HTML structure for Browser IDE
1 parent 33cfd87 commit 8a4727f

1 file changed

Lines changed: 142 additions & 0 deletions

File tree

Browser IDE — Live GitHub Runner

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>Browser IDE — Live GitHub Runner</title>
6+
<style>
7+
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; margin: 0; display:flex; height:100vh; }
8+
#left { width: 50%; border-right: 1px solid #ddd; display:flex; flex-direction:column; }
9+
#right { width: 50%; display:flex; flex-direction:column; }
10+
header { padding:10px; background:#f6f6f6; border-bottom:1px solid #eaeaea; }
11+
textarea { flex:1; width:100%; padding:10px; box-sizing:border-box; font-family: monospace; font-size:13px; }
12+
#controls { padding:10px; display:flex; gap:8px; flex-wrap:wrap; }
13+
input, button, select { padding:6px; font-size:14px; }
14+
pre { margin:0; padding:10px; background:#111; color:#0f0; height:50vh; overflow:auto; font-family: monospace; font-size:12px; }
15+
</style>
16+
</head>
17+
<body>
18+
<div id="left">
19+
<header>
20+
<strong>Browser IDE (minimal)</strong>
21+
<div id="controls">
22+
<input id="token" placeholder="GitHub PAT" size="36" />
23+
<button id="connectBtn">Connect WS</button>
24+
<select id="workspaces"></select>
25+
</div>
26+
<div id="repoControls">
27+
<input id="owner" placeholder="owner" />
28+
<input id="repo" placeholder="repo" />
29+
<input id="branch" placeholder="branch (optional)" />
30+
<button id="cloneBtn">Clone</button>
31+
</div>
32+
</header>
33+
<textarea id="editor" placeholder="Open or create a file, edit, then Save to workspace"></textarea>
34+
<div style="padding:8px;display:flex;gap:8px;">
35+
<input id="filePath" placeholder="path/inside/repo.txt" style="flex:1"/>
36+
<button id="saveFileBtn">Save to workspace</button>
37+
<button id="commitBtn">Commit</button>
38+
<button id="pushBtn">Push</button>
39+
<button id="prBtn">Create PR</button>
40+
</div>
41+
</div>
42+
43+
<div id="right">
44+
<header><strong>Live Runner Console</strong></header>
45+
<pre id="console">disconnected</pre>
46+
</div>
47+
48+
<script>
49+
(function(){
50+
let ws;
51+
let token;
52+
let currentWorkspaceId = null;
53+
const consoleEl = document.getElementById('console');
54+
const workspacesSelect = document.getElementById('workspaces');
55+
56+
function log(level, text){
57+
const t = `[${new Date().toISOString()}] ${text}`;
58+
consoleEl.textContent += "\\n" + t;
59+
consoleEl.scrollTop = consoleEl.scrollHeight;
60+
}
61+
62+
document.getElementById('connectBtn').addEventListener('click', () => {
63+
token = document.getElementById('token').value.trim();
64+
if(!token) { alert('enter PAT'); return; }
65+
ws = new WebSocket(`ws://${location.host}`);
66+
ws.onopen = () => {
67+
consoleEl.textContent = '';
68+
log('info','ws open; sending auth');
69+
ws.send(JSON.stringify({ type: 'auth', token }));
70+
};
71+
ws.onmessage = (ev) => {
72+
try {
73+
const m = JSON.parse(ev.data);
74+
if(m.type === 'log') {
75+
log(m.level, m.text);
76+
} else if(m.type === 'result') {
77+
log('result', JSON.stringify(m.data));
78+
if(m.action === 'clone' && m.data.workspaceId){
79+
const opt = document.createElement('option');
80+
opt.value = m.data.workspaceId;
81+
opt.text = `${m.data.workspaceId} (${m.data.path})`;
82+
workspacesSelect.appendChild(opt);
83+
workspacesSelect.value = m.data.workspaceId;
84+
currentWorkspaceId = m.data.workspaceId;
85+
}
86+
} else if(m.type === 'error') {
87+
log('error', m.message);
88+
} else {
89+
log('info', JSON.stringify(m));
90+
}
91+
} catch(e){
92+
log('error', ev.data);
93+
}
94+
};
95+
ws.onclose = () => log('info','ws closed');
96+
ws.onerror = (e)=> log('error', 'ws error');
97+
});
98+
99+
document.getElementById('cloneBtn').addEventListener('click', () => {
100+
const owner = document.getElementById('owner').value.trim();
101+
const repo = document.getElementById('repo').value.trim();
102+
const branch = document.getElementById('branch').value.trim();
103+
if(!owner || !repo) { alert('owner & repo required'); return; }
104+
ws.send(JSON.stringify({ type:'run', action:'clone', payload: { owner, repo, branch } }));
105+
});
106+
107+
document.getElementById('saveFileBtn').addEventListener('click', () => {
108+
const filePath = document.getElementById('filePath').value.trim();
109+
const content = document.getElementById('editor').value;
110+
const wsId = workspacesSelect.value;
111+
if(!wsId) { alert('select workspace'); return; }
112+
ws.send(JSON.stringify({ type:'run', action:'write', payload: { workspaceId: wsId, path: filePath, content } }));
113+
});
114+
115+
document.getElementById('commitBtn').addEventListener('click', () => {
116+
const wsId = workspacesSelect.value;
117+
if(!wsId) { alert('select workspace'); return; }
118+
const msg = prompt('Commit message', 'update from web IDE');
119+
ws.send(JSON.stringify({ type:'run', action:'commit', payload: { workspaceId: wsId, message: msg } }));
120+
});
121+
122+
document.getElementById('pushBtn').addEventListener('click', () => {
123+
const wsId = workspacesSelect.value;
124+
const branch = prompt('Branch to push to (remote)', 'main');
125+
if(!wsId) { alert('select workspace'); return; }
126+
ws.send(JSON.stringify({ type:'run', action:'push', payload: { workspaceId: wsId, branch } }));
127+
});
128+
129+
document.getElementById('prBtn').addEventListener('click', () => {
130+
const wsId = workspacesSelect.value;
131+
if(!wsId) { alert('select workspace'); return; }
132+
const head = prompt('Head branch (your branch)', 'feature-branch');
133+
const base = prompt('Base branch', 'main');
134+
const title = prompt('PR title', 'Automated PR from web IDE');
135+
const body = prompt('PR body (optional)', '');
136+
ws.send(JSON.stringify({ type:'run', action:'pr', payload: { workspaceId: wsId, headBranch: head, baseBranch: base, title, body } }));
137+
});
138+
139+
})();
140+
</script>
141+
</body>
142+
</html>

0 commit comments

Comments
 (0)