Bjo53 commited on
Commit
74186dd
Β·
verified Β·
1 Parent(s): 9ff8ef2

Upload static/index.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. static/index.html +119 -7
static/index.html CHANGED
@@ -29,8 +29,31 @@
29
  }
30
  #pass-screen .err { color: #ff5f56; font-size: 12px; }
31
 
32
- #terminal-container { width: 100%; height: 100%; }
 
 
 
 
 
 
 
 
 
 
 
 
33
  .xterm { padding: 4px; height: 100%; }
 
 
 
 
 
 
 
 
 
 
 
34
  </style>
35
  </head>
36
  <body>
@@ -41,10 +64,27 @@
41
  <div class="err" id="pass-err"></div>
42
  </div>
43
 
44
- <div id="terminal-container" style="display:none;"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
  <script>
47
  const PASS_HASH = "opencode";
 
 
48
 
49
  document.getElementById("pass-btn").onclick = () => unlock();
50
  document.getElementById("pass-input").addEventListener("keydown", e => { if (e.key === "Enter") unlock(); });
@@ -53,6 +93,7 @@
53
  const val = document.getElementById("pass-input").value;
54
  if (val === PASS_HASH) {
55
  document.getElementById("pass-screen").classList.add("hidden");
 
56
  document.getElementById("terminal-container").style.display = "block";
57
  initTerminal();
58
  } else {
@@ -60,15 +101,14 @@
60
  }
61
  }
62
 
63
- let ws = null;
64
-
65
  function initTerminal() {
66
- const term = new Terminal({
67
  cursorBlink: true,
68
  fontSize: 14,
69
  fontFamily: "'JetBrains Mono', monospace",
70
- scrollback: 5000,
71
- theme: { background: '#0d1117', foreground: '#e6edf3', cursor: '#27c93f' }
 
72
  });
73
 
74
  const fitAddon = new FitAddon.FitAddon();
@@ -105,6 +145,78 @@
105
  window.addEventListener("resize", () => { fitAddon.fit(); });
106
  connect();
107
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  </script>
109
  </body>
110
  </html>
 
29
  }
30
  #pass-screen .err { color: #ff5f56; font-size: 12px; }
31
 
32
+ #toolbar {
33
+ display: none; background: #161b22; padding: 6px 12px; border-bottom: 1px solid #30363d;
34
+ gap: 8px; align-items: center;
35
+ }
36
+ #toolbar button {
37
+ background: #27c93f22; border: 1px solid #27c93f55; border-radius: 6px;
38
+ color: #27c93f; font-size: 11px; padding: 5px 12px; cursor: pointer;
39
+ font-family: 'JetBrains Mono', monospace;
40
+ }
41
+ #toolbar button:hover { background: #27c93f44; }
42
+ #toolbar .sep { width: 1px; height: 20px; background: #30363d; }
43
+
44
+ #terminal-container { width: 100%; height: calc(100% - 36px); display: none; }
45
  .xterm { padding: 4px; height: 100%; }
46
+
47
+ #ctx-menu {
48
+ display: none; position: fixed; background: #1c2128; border: 1px solid #30363d;
49
+ border-radius: 8px; padding: 4px; z-index: 9999; min-width: 160px;
50
+ }
51
+ #ctx-menu button {
52
+ display: block; width: 100%; background: none; border: none; color: #e6edf3;
53
+ padding: 8px 12px; text-align: left; cursor: pointer; border-radius: 4px;
54
+ font-family: 'JetBrains Mono', monospace; font-size: 12px;
55
+ }
56
+ #ctx-menu button:hover { background: #27c93f22; color: #27c93f; }
57
  </style>
58
  </head>
59
  <body>
 
64
  <div class="err" id="pass-err"></div>
65
  </div>
66
 
67
+ <div id="toolbar">
68
+ <button id="btn-copy">πŸ“‹ Copy</button>
69
+ <button id="btn-paste">πŸ“„ Paste</button>
70
+ <button id="btn-selectall">πŸ“ Select All</button>
71
+ <div class="sep"></div>
72
+ <button id="btn-clear">πŸ—‘ Clear</button>
73
+ </div>
74
+
75
+ <div id="terminal-container"></div>
76
+
77
+ <div id="ctx-menu">
78
+ <button id="ctx-copy">πŸ“‹ Copy</button>
79
+ <button id="ctx-paste">πŸ“„ Paste</button>
80
+ <button id="ctx-selectall">πŸ“ Select All</button>
81
+ <button id="ctx-clear">πŸ—‘ Clear</button>
82
+ </div>
83
 
84
  <script>
85
  const PASS_HASH = "opencode";
86
+ let term = null;
87
+ let ws = null;
88
 
89
  document.getElementById("pass-btn").onclick = () => unlock();
90
  document.getElementById("pass-input").addEventListener("keydown", e => { if (e.key === "Enter") unlock(); });
 
93
  const val = document.getElementById("pass-input").value;
94
  if (val === PASS_HASH) {
95
  document.getElementById("pass-screen").classList.add("hidden");
96
+ document.getElementById("toolbar").style.display = "flex";
97
  document.getElementById("terminal-container").style.display = "block";
98
  initTerminal();
99
  } else {
 
101
  }
102
  }
103
 
 
 
104
  function initTerminal() {
105
+ term = new Terminal({
106
  cursorBlink: true,
107
  fontSize: 14,
108
  fontFamily: "'JetBrains Mono', monospace",
109
+ scrollback: 10000,
110
+ allowProposedApi: true,
111
+ theme: { background: '#0d1117', foreground: '#e6edf3', cursor: '#27c93f', selectionBackground: '#27c93f44' }
112
  });
113
 
114
  const fitAddon = new FitAddon.FitAddon();
 
145
  window.addEventListener("resize", () => { fitAddon.fit(); });
146
  connect();
147
  }
148
+
149
+ // Toolbar buttons
150
+ document.getElementById("btn-copy").onclick = () => {
151
+ const sel = term.getSelection();
152
+ if (sel) navigator.clipboard.writeText(sel);
153
+ };
154
+
155
+ document.getElementById("btn-paste").onclick = async () => {
156
+ try {
157
+ const text = await navigator.clipboard.readText();
158
+ if (text && ws && ws.readyState === WebSocket.OPEN) {
159
+ ws.send(JSON.stringify({ type: "input", data: text }));
160
+ }
161
+ } catch(e) {}
162
+ };
163
+
164
+ document.getElementById("btn-selectall").onclick = () => {
165
+ term.selectAll();
166
+ };
167
+
168
+ document.getElementById("btn-clear").onclick = () => {
169
+ term.clear();
170
+ };
171
+
172
+ // Context menu
173
+ const ctxMenu = document.getElementById("ctx-menu");
174
+ document.getElementById("terminal-container").addEventListener("contextmenu", (e) => {
175
+ e.preventDefault();
176
+ ctxMenu.style.display = "block";
177
+ ctxMenu.style.left = `${e.pageX}px`;
178
+ ctxMenu.style.top = `${e.pageY}px`;
179
+ });
180
+
181
+ document.addEventListener("click", () => { ctxMenu.style.display = "none"; });
182
+
183
+ document.getElementById("ctx-copy").onclick = () => {
184
+ const sel = term.getSelection();
185
+ if (sel) navigator.clipboard.writeText(sel);
186
+ };
187
+
188
+ document.getElementById("ctx-paste").onclick = async () => {
189
+ try {
190
+ const text = await navigator.clipboard.readText();
191
+ if (text && ws && ws.readyState === WebSocket.OPEN) {
192
+ ws.send(JSON.stringify({ type: "input", data: text }));
193
+ }
194
+ } catch(e) {}
195
+ };
196
+
197
+ document.getElementById("ctx-selectall").onclick = () => { term.selectAll(); };
198
+ document.getElementById("ctx-clear").onclick = () => { term.clear(); };
199
+
200
+ // Keyboard shortcuts
201
+ document.addEventListener("keydown", (e) => {
202
+ if (!term) return;
203
+ if (e.ctrlKey && e.key === "c") {
204
+ const sel = term.getSelection();
205
+ if (sel) { navigator.clipboard.writeText(sel); e.preventDefault(); }
206
+ }
207
+ if (e.ctrlKey && e.key === "v") {
208
+ e.preventDefault();
209
+ navigator.clipboard.readText().then(text => {
210
+ if (text && ws && ws.readyState === WebSocket.OPEN) {
211
+ ws.send(JSON.stringify({ type: "input", data: text }));
212
+ }
213
+ });
214
+ }
215
+ if (e.ctrlKey && e.key === "a") {
216
+ e.preventDefault();
217
+ term.selectAll();
218
+ }
219
+ });
220
  </script>
221
  </body>
222
  </html>