termbeam 1.11.1 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/public-react/assets/index-CTOb8Hzh.js +108 -0
- package/public-react/assets/index-DCDkIi8X.css +32 -0
- package/public-react/index.html +27 -0
- package/public-react/manifest.webmanifest +1 -0
- package/public-react/registerSW.js +1 -0
- package/public-react/sw.js +2 -0
- package/src/routes.js +24 -22
- package/src/websocket.js +19 -1
- package/public/css/themes.css +0 -217
- package/public/index.html +0 -1521
- package/public/js/keybar.js +0 -180
- package/public/js/search.js +0 -95
- package/public/js/shared.js +0 -39
- package/public/js/terminal-themes.js +0 -291
- package/public/js/themes.js +0 -54
- package/public/manifest.json +0 -14
- package/public/sw.js +0 -88
- package/public/terminal.html +0 -4837
- /package/{public → public-react}/icons/icon-192.png +0 -0
- /package/{public → public-react}/icons/icon-512.png +0 -0
- /package/{public → public-react}/icons/icon.svg +0 -0
package/public/js/keybar.js
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Key Bar — touch/mouse key-bar logic for the terminal UI.
|
|
3
|
-
*
|
|
4
|
-
* Depends on globals defined in terminal.html's inline script:
|
|
5
|
-
* - managed (Map of session objects)
|
|
6
|
-
* - activeId (current session ID)
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// ===== Key Bar =====
|
|
10
|
-
// Modifier state (shared with terminal onData)
|
|
11
|
-
let ctrlActive = false;
|
|
12
|
-
let shiftActive = false;
|
|
13
|
-
function clearModifiers() {
|
|
14
|
-
ctrlActive = false;
|
|
15
|
-
shiftActive = false;
|
|
16
|
-
const ctrlBtn = document.getElementById('ctrl-btn');
|
|
17
|
-
const shiftBtn = document.getElementById('shift-btn');
|
|
18
|
-
if (ctrlBtn) ctrlBtn.classList.remove('active');
|
|
19
|
-
if (shiftBtn) shiftBtn.classList.remove('active');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function setupKeyBar() {
|
|
23
|
-
const keyBar = document.getElementById('key-bar');
|
|
24
|
-
const ctrlBtn = document.getElementById('ctrl-btn');
|
|
25
|
-
const shiftBtn = document.getElementById('shift-btn');
|
|
26
|
-
let repeatTimer = null;
|
|
27
|
-
let repeatInterval = null;
|
|
28
|
-
|
|
29
|
-
function toggleModifier(which) {
|
|
30
|
-
if (which === 'ctrl') {
|
|
31
|
-
ctrlActive = !ctrlActive;
|
|
32
|
-
ctrlBtn.classList.toggle('active', ctrlActive);
|
|
33
|
-
} else {
|
|
34
|
-
shiftActive = !shiftActive;
|
|
35
|
-
shiftBtn.classList.toggle('active', shiftActive);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function applyModifiers(key) {
|
|
40
|
-
if (!ctrlActive && !shiftActive) return key;
|
|
41
|
-
// Modifier param: Shift=2, Ctrl=5, Ctrl+Shift=6
|
|
42
|
-
const mod = ctrlActive && shiftActive ? 6 : ctrlActive ? 5 : 2;
|
|
43
|
-
// Arrow keys: \x1b[X → \x1b[1;{mod}X
|
|
44
|
-
const csiMatch = key.match(/^\x1b\[([ABCD])$/);
|
|
45
|
-
if (csiMatch) return '\x1b[1;' + mod + csiMatch[1];
|
|
46
|
-
// Home/End: \x1bOH/\x1bOF → \x1b[1;{mod}H/F
|
|
47
|
-
const ssMatch = key.match(/^\x1bO([HF])$/);
|
|
48
|
-
if (ssMatch) return '\x1b[1;' + mod + ssMatch[1];
|
|
49
|
-
// Tab with Shift → reverse tab
|
|
50
|
-
if (key === '\x09' && shiftActive && !ctrlActive) return '\x1b[Z';
|
|
51
|
-
return key;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function flashBtn(btn) {
|
|
55
|
-
btn.classList.add('flash');
|
|
56
|
-
setTimeout(() => btn.classList.remove('flash'), 120);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function sendKey(btn) {
|
|
60
|
-
if (!btn || !btn.dataset.key) return;
|
|
61
|
-
flashBtn(btn);
|
|
62
|
-
let data =
|
|
63
|
-
btn.dataset.key === 'enter' ? '\r' : btn.dataset.key === 'tab' ? '\x09' : btn.dataset.key;
|
|
64
|
-
data = applyModifiers(data);
|
|
65
|
-
const ms = managed.get(activeId);
|
|
66
|
-
if (ms && ms.ws && ms.ws.readyState === 1) {
|
|
67
|
-
ms.ws.send(JSON.stringify({ type: 'input', data }));
|
|
68
|
-
}
|
|
69
|
-
clearModifiers();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function stopRepeat() {
|
|
73
|
-
clearTimeout(repeatTimer);
|
|
74
|
-
clearInterval(repeatInterval);
|
|
75
|
-
repeatTimer = null;
|
|
76
|
-
repeatInterval = null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function startRepeat(btn) {
|
|
80
|
-
stopRepeat();
|
|
81
|
-
sendKey(btn);
|
|
82
|
-
repeatTimer = setTimeout(() => {
|
|
83
|
-
repeatInterval = setInterval(() => sendKey(btn), 80);
|
|
84
|
-
}, 400);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
ctrlBtn.addEventListener('click', (e) => {
|
|
88
|
-
e.preventDefault();
|
|
89
|
-
e.stopPropagation();
|
|
90
|
-
toggleModifier('ctrl');
|
|
91
|
-
});
|
|
92
|
-
shiftBtn.addEventListener('click', (e) => {
|
|
93
|
-
e.preventDefault();
|
|
94
|
-
e.stopPropagation();
|
|
95
|
-
toggleModifier('shift');
|
|
96
|
-
});
|
|
97
|
-
ctrlBtn.addEventListener('mousedown', (e) => e.preventDefault());
|
|
98
|
-
shiftBtn.addEventListener('mousedown', (e) => e.preventDefault());
|
|
99
|
-
ctrlBtn.addEventListener(
|
|
100
|
-
'touchstart',
|
|
101
|
-
(e) => {
|
|
102
|
-
e.preventDefault();
|
|
103
|
-
keyBarTouched = true;
|
|
104
|
-
toggleModifier('ctrl');
|
|
105
|
-
},
|
|
106
|
-
{ passive: false },
|
|
107
|
-
);
|
|
108
|
-
shiftBtn.addEventListener(
|
|
109
|
-
'touchstart',
|
|
110
|
-
(e) => {
|
|
111
|
-
e.preventDefault();
|
|
112
|
-
keyBarTouched = true;
|
|
113
|
-
toggleModifier('shift');
|
|
114
|
-
},
|
|
115
|
-
{ passive: false },
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
let keyBarTouched = false;
|
|
119
|
-
keyBar.addEventListener('mousedown', (e) => {
|
|
120
|
-
if (keyBarTouched) {
|
|
121
|
-
keyBarTouched = false;
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
const btn = e.target.closest('.key-btn');
|
|
125
|
-
if (btn && btn.dataset.key) {
|
|
126
|
-
e.preventDefault();
|
|
127
|
-
startRepeat(btn);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
keyBar.addEventListener('mouseup', stopRepeat);
|
|
131
|
-
keyBar.addEventListener('mouseleave', stopRepeat);
|
|
132
|
-
|
|
133
|
-
// Touch handling: allow native scroll when swiping, fire key only on tap
|
|
134
|
-
const SWIPE_THRESHOLD = 10;
|
|
135
|
-
let touchStartX = 0;
|
|
136
|
-
let touchBtn = null;
|
|
137
|
-
let touchMoved = false;
|
|
138
|
-
|
|
139
|
-
keyBar.addEventListener(
|
|
140
|
-
'touchstart',
|
|
141
|
-
(e) => {
|
|
142
|
-
keyBarTouched = true;
|
|
143
|
-
touchBtn = e.target.closest('.key-btn');
|
|
144
|
-
touchMoved = false;
|
|
145
|
-
touchStartX = e.touches[0].clientX;
|
|
146
|
-
// Don't preventDefault — let the browser handle scroll
|
|
147
|
-
},
|
|
148
|
-
{ passive: true },
|
|
149
|
-
);
|
|
150
|
-
keyBar.addEventListener(
|
|
151
|
-
'touchmove',
|
|
152
|
-
(e) => {
|
|
153
|
-
if (Math.abs(e.touches[0].clientX - touchStartX) > SWIPE_THRESHOLD) {
|
|
154
|
-
touchMoved = true;
|
|
155
|
-
stopRepeat();
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
{ passive: true },
|
|
159
|
-
);
|
|
160
|
-
keyBar.addEventListener('touchend', (e) => {
|
|
161
|
-
if (!touchMoved && touchBtn && touchBtn.dataset.key) {
|
|
162
|
-
e.preventDefault();
|
|
163
|
-
sendKey(touchBtn);
|
|
164
|
-
}
|
|
165
|
-
stopRepeat();
|
|
166
|
-
touchBtn = null;
|
|
167
|
-
});
|
|
168
|
-
keyBar.addEventListener('touchcancel', () => {
|
|
169
|
-
stopRepeat();
|
|
170
|
-
touchBtn = null;
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
keyBar.addEventListener('click', (e) => {
|
|
174
|
-
const btn = e.target.closest('.key-btn');
|
|
175
|
-
if (btn) {
|
|
176
|
-
const ms = managed.get(activeId);
|
|
177
|
-
if (ms) ms.term.focus();
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
}
|
package/public/js/search.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Terminal search bar logic.
|
|
3
|
-
* Depends on globals defined in terminal.html:
|
|
4
|
-
* - managed (Map of session objects)
|
|
5
|
-
* - activeId (current active session ID)
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// ===== Terminal Search =====
|
|
9
|
-
const searchBar = document.getElementById('search-bar');
|
|
10
|
-
const searchInput = document.getElementById('search-input');
|
|
11
|
-
const searchCount = document.getElementById('search-count');
|
|
12
|
-
const searchRegexBtn = document.getElementById('search-regex');
|
|
13
|
-
let searchRegex = false;
|
|
14
|
-
let searchResultIndex = 0;
|
|
15
|
-
let searchResultTotal = 0;
|
|
16
|
-
|
|
17
|
-
function getActiveSearchAddon() {
|
|
18
|
-
if (!activeId) return null;
|
|
19
|
-
const ms = managed.get(activeId);
|
|
20
|
-
return ms ? ms.searchAddon : null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function updateSearchCount(idx, total) {
|
|
24
|
-
searchResultIndex = idx;
|
|
25
|
-
searchResultTotal = total;
|
|
26
|
-
searchCount.textContent = total > 0 ? idx + 1 + ' of ' + total : 'No results';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function doSearch(direction) {
|
|
30
|
-
const addon = getActiveSearchAddon();
|
|
31
|
-
if (!addon) return;
|
|
32
|
-
const query = searchInput.value;
|
|
33
|
-
if (!query) {
|
|
34
|
-
searchCount.textContent = '';
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const opts = {
|
|
38
|
-
regex: searchRegex,
|
|
39
|
-
caseSensitive: false,
|
|
40
|
-
incremental: direction === 'next',
|
|
41
|
-
};
|
|
42
|
-
let result;
|
|
43
|
-
if (direction === 'prev') {
|
|
44
|
-
result = addon.findPrevious(query, opts);
|
|
45
|
-
} else {
|
|
46
|
-
result = addon.findNext(query, opts);
|
|
47
|
-
}
|
|
48
|
-
// SearchAddon returns boolean; no match count API in v0.15
|
|
49
|
-
searchCount.textContent = result ? 'Found' : 'No results';
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function openSearchBar() {
|
|
53
|
-
searchBar.classList.add('visible');
|
|
54
|
-
searchInput.focus();
|
|
55
|
-
searchInput.select();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function closeSearchBar() {
|
|
59
|
-
searchBar.classList.remove('visible');
|
|
60
|
-
searchCount.textContent = '';
|
|
61
|
-
searchInput.value = '';
|
|
62
|
-
const addon = getActiveSearchAddon();
|
|
63
|
-
if (addon) addon.clearDecorations();
|
|
64
|
-
// Re-focus terminal
|
|
65
|
-
if (activeId) {
|
|
66
|
-
const ms = managed.get(activeId);
|
|
67
|
-
if (ms) ms.term.focus();
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
searchInput.addEventListener('input', () => doSearch('next'));
|
|
72
|
-
searchInput.addEventListener('keydown', (e) => {
|
|
73
|
-
if (e.key === 'Escape') {
|
|
74
|
-
closeSearchBar();
|
|
75
|
-
e.preventDefault();
|
|
76
|
-
} else if (e.key === 'Enter') {
|
|
77
|
-
e.preventDefault();
|
|
78
|
-
doSearch(e.shiftKey ? 'prev' : 'next');
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
document.getElementById('search-next').addEventListener('click', () => doSearch('next'));
|
|
82
|
-
document.getElementById('search-prev').addEventListener('click', () => doSearch('prev'));
|
|
83
|
-
document.getElementById('search-close').addEventListener('click', closeSearchBar);
|
|
84
|
-
document.getElementById('search-regex').addEventListener('click', () => {
|
|
85
|
-
searchRegex = !searchRegex;
|
|
86
|
-
searchRegexBtn.classList.toggle('active', searchRegex);
|
|
87
|
-
if (searchInput.value) doSearch('next');
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
document.addEventListener('keydown', (e) => {
|
|
91
|
-
if ((e.ctrlKey || e.metaKey) && e.key === 'f') {
|
|
92
|
-
e.preventDefault();
|
|
93
|
-
openSearchBar();
|
|
94
|
-
}
|
|
95
|
-
});
|
package/public/js/shared.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
// shared.js — utility functions shared across TermBeam pages
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Escape a string for safe insertion into HTML.
|
|
5
|
-
* Uses the DOM to handle entity encoding.
|
|
6
|
-
*/
|
|
7
|
-
function esc(str) {
|
|
8
|
-
const d = document.createElement('div');
|
|
9
|
-
d.textContent = str;
|
|
10
|
-
return d.innerHTML;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Textarea-based clipboard copy fallback for non-secure contexts (HTTP over LAN).
|
|
15
|
-
* Returns true if the copy succeeded, false otherwise.
|
|
16
|
-
*/
|
|
17
|
-
function copyToClipboardFallback(text) {
|
|
18
|
-
const ta = document.createElement('textarea');
|
|
19
|
-
ta.value = text;
|
|
20
|
-
ta.style.cssText = 'position:fixed;left:-9999px;top:-9999px';
|
|
21
|
-
document.body.appendChild(ta);
|
|
22
|
-
ta.focus();
|
|
23
|
-
ta.select();
|
|
24
|
-
let ok = false;
|
|
25
|
-
try {
|
|
26
|
-
ok = document.execCommand('copy');
|
|
27
|
-
} catch {}
|
|
28
|
-
document.body.removeChild(ta);
|
|
29
|
-
return ok;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Register the service worker if supported.
|
|
34
|
-
*/
|
|
35
|
-
function registerServiceWorker() {
|
|
36
|
-
if ('serviceWorker' in navigator) {
|
|
37
|
-
navigator.serviceWorker.register('/sw.js').catch(() => {});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
// Terminal color themes for xterm.js
|
|
2
|
-
const darkTermTheme = {
|
|
3
|
-
background: '#1e1e1e',
|
|
4
|
-
foreground: '#d4d4d4',
|
|
5
|
-
cursor: '#aeafad',
|
|
6
|
-
cursorAccent: '#1e1e1e',
|
|
7
|
-
selectionBackground: 'rgba(38, 79, 120, 0.5)',
|
|
8
|
-
black: '#000000',
|
|
9
|
-
red: '#cd3131',
|
|
10
|
-
green: '#0dbc79',
|
|
11
|
-
yellow: '#e5e510',
|
|
12
|
-
blue: '#2472c8',
|
|
13
|
-
magenta: '#bc3fbc',
|
|
14
|
-
cyan: '#11a8cd',
|
|
15
|
-
white: '#e5e5e5',
|
|
16
|
-
brightBlack: '#666666',
|
|
17
|
-
brightRed: '#f14c4c',
|
|
18
|
-
brightGreen: '#23d18b',
|
|
19
|
-
brightYellow: '#f5f543',
|
|
20
|
-
brightBlue: '#3b8eea',
|
|
21
|
-
brightMagenta: '#d670d6',
|
|
22
|
-
brightCyan: '#29b8db',
|
|
23
|
-
brightWhite: '#e5e5e5',
|
|
24
|
-
};
|
|
25
|
-
const lightTermTheme = {
|
|
26
|
-
background: '#ffffff',
|
|
27
|
-
foreground: '#1e1e1e',
|
|
28
|
-
cursor: '#000000',
|
|
29
|
-
cursorAccent: '#ffffff',
|
|
30
|
-
selectionBackground: 'rgba(0, 120, 215, 0.3)',
|
|
31
|
-
black: '#000000',
|
|
32
|
-
red: '#cd3131',
|
|
33
|
-
green: '#00bc7c',
|
|
34
|
-
yellow: '#949800',
|
|
35
|
-
blue: '#0451a5',
|
|
36
|
-
magenta: '#bc05bc',
|
|
37
|
-
cyan: '#0598bc',
|
|
38
|
-
white: '#555555',
|
|
39
|
-
brightBlack: '#666666',
|
|
40
|
-
brightRed: '#cd3131',
|
|
41
|
-
brightGreen: '#14ce14',
|
|
42
|
-
brightYellow: '#b5ba00',
|
|
43
|
-
brightBlue: '#0451a5',
|
|
44
|
-
brightMagenta: '#bc05bc',
|
|
45
|
-
brightCyan: '#0598bc',
|
|
46
|
-
brightWhite: '#a5a5a5',
|
|
47
|
-
};
|
|
48
|
-
const monokaiTermTheme = {
|
|
49
|
-
background: '#272822',
|
|
50
|
-
foreground: '#f8f8f2',
|
|
51
|
-
cursor: '#f8f8f0',
|
|
52
|
-
cursorAccent: '#272822',
|
|
53
|
-
selectionBackground: 'rgba(166, 226, 46, 0.3)',
|
|
54
|
-
black: '#272822',
|
|
55
|
-
red: '#f92672',
|
|
56
|
-
green: '#a6e22e',
|
|
57
|
-
yellow: '#f4bf75',
|
|
58
|
-
blue: '#66d9e8',
|
|
59
|
-
magenta: '#ae81ff',
|
|
60
|
-
cyan: '#a1efe4',
|
|
61
|
-
white: '#f8f8f2',
|
|
62
|
-
brightBlack: '#75715e',
|
|
63
|
-
brightRed: '#f92672',
|
|
64
|
-
brightGreen: '#a6e22e',
|
|
65
|
-
brightYellow: '#f4bf75',
|
|
66
|
-
brightBlue: '#66d9e8',
|
|
67
|
-
brightMagenta: '#ae81ff',
|
|
68
|
-
brightCyan: '#a1efe4',
|
|
69
|
-
brightWhite: '#f9f8f5',
|
|
70
|
-
};
|
|
71
|
-
const solarizedDarkTermTheme = {
|
|
72
|
-
background: '#002b36',
|
|
73
|
-
foreground: '#839496',
|
|
74
|
-
cursor: '#839496',
|
|
75
|
-
cursorAccent: '#002b36',
|
|
76
|
-
selectionBackground: 'rgba(7, 54, 66, 0.8)',
|
|
77
|
-
black: '#073642',
|
|
78
|
-
red: '#dc322f',
|
|
79
|
-
green: '#859900',
|
|
80
|
-
yellow: '#b58900',
|
|
81
|
-
blue: '#268bd2',
|
|
82
|
-
magenta: '#d33682',
|
|
83
|
-
cyan: '#2aa198',
|
|
84
|
-
white: '#eee8d5',
|
|
85
|
-
brightBlack: '#002b36',
|
|
86
|
-
brightRed: '#cb4b16',
|
|
87
|
-
brightGreen: '#586e75',
|
|
88
|
-
brightYellow: '#657b83',
|
|
89
|
-
brightBlue: '#839496',
|
|
90
|
-
brightMagenta: '#6c71c4',
|
|
91
|
-
brightCyan: '#93a1a1',
|
|
92
|
-
brightWhite: '#fdf6e3',
|
|
93
|
-
};
|
|
94
|
-
const solarizedLightTermTheme = {
|
|
95
|
-
background: '#fdf6e3',
|
|
96
|
-
foreground: '#657b83',
|
|
97
|
-
cursor: '#586e75',
|
|
98
|
-
cursorAccent: '#fdf6e3',
|
|
99
|
-
selectionBackground: 'rgba(238, 232, 213, 0.8)',
|
|
100
|
-
black: '#073642',
|
|
101
|
-
red: '#dc322f',
|
|
102
|
-
green: '#859900',
|
|
103
|
-
yellow: '#b58900',
|
|
104
|
-
blue: '#268bd2',
|
|
105
|
-
magenta: '#d33682',
|
|
106
|
-
cyan: '#2aa198',
|
|
107
|
-
white: '#eee8d5',
|
|
108
|
-
brightBlack: '#002b36',
|
|
109
|
-
brightRed: '#cb4b16',
|
|
110
|
-
brightGreen: '#586e75',
|
|
111
|
-
brightYellow: '#657b83',
|
|
112
|
-
brightBlue: '#839496',
|
|
113
|
-
brightMagenta: '#6c71c4',
|
|
114
|
-
brightCyan: '#93a1a1',
|
|
115
|
-
brightWhite: '#fdf6e3',
|
|
116
|
-
};
|
|
117
|
-
const nordTermTheme = {
|
|
118
|
-
background: '#2e3440',
|
|
119
|
-
foreground: '#d8dee9',
|
|
120
|
-
cursor: '#d8dee9',
|
|
121
|
-
cursorAccent: '#2e3440',
|
|
122
|
-
selectionBackground: 'rgba(67, 76, 94, 0.5)',
|
|
123
|
-
black: '#3b4252',
|
|
124
|
-
red: '#bf616a',
|
|
125
|
-
green: '#a3be8c',
|
|
126
|
-
yellow: '#ebcb8b',
|
|
127
|
-
blue: '#81a1c1',
|
|
128
|
-
magenta: '#b48ead',
|
|
129
|
-
cyan: '#88c0d0',
|
|
130
|
-
white: '#e5e9f0',
|
|
131
|
-
brightBlack: '#4c566a',
|
|
132
|
-
brightRed: '#bf616a',
|
|
133
|
-
brightGreen: '#a3be8c',
|
|
134
|
-
brightYellow: '#ebcb8b',
|
|
135
|
-
brightBlue: '#81a1c1',
|
|
136
|
-
brightMagenta: '#b48ead',
|
|
137
|
-
brightCyan: '#8fbcbb',
|
|
138
|
-
brightWhite: '#eceff4',
|
|
139
|
-
};
|
|
140
|
-
const draculaTermTheme = {
|
|
141
|
-
background: '#282a36',
|
|
142
|
-
foreground: '#f8f8f2',
|
|
143
|
-
cursor: '#f8f8f2',
|
|
144
|
-
cursorAccent: '#282a36',
|
|
145
|
-
selectionBackground: 'rgba(68, 71, 90, 0.7)',
|
|
146
|
-
black: '#21222c',
|
|
147
|
-
red: '#ff5555',
|
|
148
|
-
green: '#50fa7b',
|
|
149
|
-
yellow: '#f1fa8c',
|
|
150
|
-
blue: '#bd93f9',
|
|
151
|
-
magenta: '#ff79c6',
|
|
152
|
-
cyan: '#8be9fd',
|
|
153
|
-
white: '#f8f8f2',
|
|
154
|
-
brightBlack: '#6272a4',
|
|
155
|
-
brightRed: '#ff6e6e',
|
|
156
|
-
brightGreen: '#69ff94',
|
|
157
|
-
brightYellow: '#ffffa5',
|
|
158
|
-
brightBlue: '#d6acff',
|
|
159
|
-
brightMagenta: '#ff92df',
|
|
160
|
-
brightCyan: '#a4ffff',
|
|
161
|
-
brightWhite: '#ffffff',
|
|
162
|
-
};
|
|
163
|
-
const githubDarkTermTheme = {
|
|
164
|
-
background: '#0d1117',
|
|
165
|
-
foreground: '#c9d1d9',
|
|
166
|
-
cursor: '#c9d1d9',
|
|
167
|
-
cursorAccent: '#0d1117',
|
|
168
|
-
selectionBackground: 'rgba(56, 139, 253, 0.3)',
|
|
169
|
-
black: '#484f58',
|
|
170
|
-
red: '#ff7b72',
|
|
171
|
-
green: '#3fb950',
|
|
172
|
-
yellow: '#d29922',
|
|
173
|
-
blue: '#58a6ff',
|
|
174
|
-
magenta: '#bc8cff',
|
|
175
|
-
cyan: '#39c5cf',
|
|
176
|
-
white: '#c9d1d9',
|
|
177
|
-
brightBlack: '#6e7681',
|
|
178
|
-
brightRed: '#ffa198',
|
|
179
|
-
brightGreen: '#56d364',
|
|
180
|
-
brightYellow: '#e3b341',
|
|
181
|
-
brightBlue: '#79c0ff',
|
|
182
|
-
brightMagenta: '#d2a8ff',
|
|
183
|
-
brightCyan: '#56d4dd',
|
|
184
|
-
brightWhite: '#f0f6fc',
|
|
185
|
-
};
|
|
186
|
-
const oneDarkTermTheme = {
|
|
187
|
-
background: '#282c34',
|
|
188
|
-
foreground: '#abb2bf',
|
|
189
|
-
cursor: '#528bff',
|
|
190
|
-
cursorAccent: '#282c34',
|
|
191
|
-
selectionBackground: 'rgba(62, 68, 82, 0.7)',
|
|
192
|
-
black: '#3f4451',
|
|
193
|
-
red: '#e06c75',
|
|
194
|
-
green: '#98c379',
|
|
195
|
-
yellow: '#e5c07b',
|
|
196
|
-
blue: '#61afef',
|
|
197
|
-
magenta: '#c678dd',
|
|
198
|
-
cyan: '#56b6c2',
|
|
199
|
-
white: '#d7dae0',
|
|
200
|
-
brightBlack: '#4f5666',
|
|
201
|
-
brightRed: '#e06c75',
|
|
202
|
-
brightGreen: '#98c379',
|
|
203
|
-
brightYellow: '#e5c07b',
|
|
204
|
-
brightBlue: '#61afef',
|
|
205
|
-
brightMagenta: '#c678dd',
|
|
206
|
-
brightCyan: '#56b6c2',
|
|
207
|
-
brightWhite: '#ffffff',
|
|
208
|
-
};
|
|
209
|
-
const catppuccinTermTheme = {
|
|
210
|
-
background: '#1e1e2e',
|
|
211
|
-
foreground: '#cdd6f4',
|
|
212
|
-
cursor: '#f5e0dc',
|
|
213
|
-
cursorAccent: '#1e1e2e',
|
|
214
|
-
selectionBackground: 'rgba(88, 91, 112, 0.5)',
|
|
215
|
-
black: '#45475a',
|
|
216
|
-
red: '#f38ba8',
|
|
217
|
-
green: '#a6e3a1',
|
|
218
|
-
yellow: '#f9e2af',
|
|
219
|
-
blue: '#89b4fa',
|
|
220
|
-
magenta: '#f5c2e7',
|
|
221
|
-
cyan: '#94e2d5',
|
|
222
|
-
white: '#bac2de',
|
|
223
|
-
brightBlack: '#585b70',
|
|
224
|
-
brightRed: '#f38ba8',
|
|
225
|
-
brightGreen: '#a6e3a1',
|
|
226
|
-
brightYellow: '#f9e2af',
|
|
227
|
-
brightBlue: '#89b4fa',
|
|
228
|
-
brightMagenta: '#f5c2e7',
|
|
229
|
-
brightCyan: '#94e2d5',
|
|
230
|
-
brightWhite: '#a6adc8',
|
|
231
|
-
};
|
|
232
|
-
const gruvboxTermTheme = {
|
|
233
|
-
background: '#282828',
|
|
234
|
-
foreground: '#ebdbb2',
|
|
235
|
-
cursor: '#ebdbb2',
|
|
236
|
-
cursorAccent: '#282828',
|
|
237
|
-
selectionBackground: 'rgba(80, 73, 69, 0.7)',
|
|
238
|
-
black: '#282828',
|
|
239
|
-
red: '#cc241d',
|
|
240
|
-
green: '#98971a',
|
|
241
|
-
yellow: '#d79921',
|
|
242
|
-
blue: '#458588',
|
|
243
|
-
magenta: '#b16286',
|
|
244
|
-
cyan: '#689d6a',
|
|
245
|
-
white: '#a89984',
|
|
246
|
-
brightBlack: '#928374',
|
|
247
|
-
brightRed: '#fb4934',
|
|
248
|
-
brightGreen: '#b8bb26',
|
|
249
|
-
brightYellow: '#fabd2f',
|
|
250
|
-
brightBlue: '#83a598',
|
|
251
|
-
brightMagenta: '#d3869b',
|
|
252
|
-
brightCyan: '#8ec07c',
|
|
253
|
-
brightWhite: '#ebdbb2',
|
|
254
|
-
};
|
|
255
|
-
const nightOwlTermTheme = {
|
|
256
|
-
background: '#011627',
|
|
257
|
-
foreground: '#d6deeb',
|
|
258
|
-
cursor: '#80a4c2',
|
|
259
|
-
cursorAccent: '#011627',
|
|
260
|
-
selectionBackground: 'rgba(29, 59, 83, 0.7)',
|
|
261
|
-
black: '#010e1a',
|
|
262
|
-
red: '#ef5350',
|
|
263
|
-
green: '#22da6e',
|
|
264
|
-
yellow: '#addb67',
|
|
265
|
-
blue: '#82aaff',
|
|
266
|
-
magenta: '#c792ea',
|
|
267
|
-
cyan: '#21c7a8',
|
|
268
|
-
white: '#d6deeb',
|
|
269
|
-
brightBlack: '#575656',
|
|
270
|
-
brightRed: '#ef5350',
|
|
271
|
-
brightGreen: '#22da6e',
|
|
272
|
-
brightYellow: '#ffeb95',
|
|
273
|
-
brightBlue: '#82aaff',
|
|
274
|
-
brightMagenta: '#c792ea',
|
|
275
|
-
brightCyan: '#7fdbca',
|
|
276
|
-
brightWhite: '#ffffff',
|
|
277
|
-
};
|
|
278
|
-
const TERM_THEMES = {
|
|
279
|
-
dark: darkTermTheme,
|
|
280
|
-
light: lightTermTheme,
|
|
281
|
-
monokai: monokaiTermTheme,
|
|
282
|
-
'solarized-dark': solarizedDarkTermTheme,
|
|
283
|
-
'solarized-light': solarizedLightTermTheme,
|
|
284
|
-
nord: nordTermTheme,
|
|
285
|
-
dracula: draculaTermTheme,
|
|
286
|
-
'github-dark': githubDarkTermTheme,
|
|
287
|
-
'one-dark': oneDarkTermTheme,
|
|
288
|
-
catppuccin: catppuccinTermTheme,
|
|
289
|
-
gruvbox: gruvboxTermTheme,
|
|
290
|
-
'night-owl': nightOwlTermTheme,
|
|
291
|
-
};
|
package/public/js/themes.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// Shared theme switching logic for index.html and terminal.html
|
|
2
|
-
const THEMES = [
|
|
3
|
-
{ id: 'dark', name: 'Dark', bg: '#1e1e1e' },
|
|
4
|
-
{ id: 'light', name: 'Light', bg: '#f3f3f3' },
|
|
5
|
-
{ id: 'monokai', name: 'Monokai', bg: '#272822' },
|
|
6
|
-
{ id: 'solarized-dark', name: 'Solarized Dark', bg: '#002b36' },
|
|
7
|
-
{ id: 'solarized-light', name: 'Solarized Light', bg: '#fdf6e3' },
|
|
8
|
-
{ id: 'nord', name: 'Nord', bg: '#2e3440' },
|
|
9
|
-
{ id: 'dracula', name: 'Dracula', bg: '#282a36' },
|
|
10
|
-
{ id: 'github-dark', name: 'GitHub Dark', bg: '#0d1117' },
|
|
11
|
-
{ id: 'one-dark', name: 'One Dark', bg: '#282c34' },
|
|
12
|
-
{ id: 'catppuccin', name: 'Catppuccin', bg: '#1e1e2e' },
|
|
13
|
-
{ id: 'gruvbox', name: 'Gruvbox', bg: '#282828' },
|
|
14
|
-
{ id: 'night-owl', name: 'Night Owl', bg: '#011627' },
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
function getTheme() {
|
|
18
|
-
return localStorage.getItem('termbeam-theme') || 'dark';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function applyTheme(theme) {
|
|
22
|
-
document.documentElement.setAttribute('data-theme', theme);
|
|
23
|
-
const t = THEMES.find((x) => x.id === theme) || THEMES[0];
|
|
24
|
-
document.querySelector('meta[name="theme-color"]').content = t.bg;
|
|
25
|
-
localStorage.setItem('termbeam-theme', theme);
|
|
26
|
-
document.querySelectorAll('.theme-option').forEach((el) => {
|
|
27
|
-
el.classList.toggle('active', el.dataset.themeOption === theme);
|
|
28
|
-
});
|
|
29
|
-
if (typeof window.onThemeApplied === 'function') {
|
|
30
|
-
window.onThemeApplied(theme);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Theme toggle button
|
|
35
|
-
document.getElementById('theme-toggle').addEventListener('click', (e) => {
|
|
36
|
-
e.stopPropagation();
|
|
37
|
-
document.getElementById('theme-picker').classList.toggle('open');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// Close picker on outside click
|
|
41
|
-
document.addEventListener('click', () => {
|
|
42
|
-
document.getElementById('theme-picker').classList.remove('open');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Theme option click handlers
|
|
46
|
-
document.querySelectorAll('.theme-option').forEach((el) => {
|
|
47
|
-
el.addEventListener('click', (e) => {
|
|
48
|
-
e.stopPropagation();
|
|
49
|
-
applyTheme(el.dataset.themeOption);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// Apply saved theme on load
|
|
54
|
-
applyTheme(getTheme());
|
package/public/manifest.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "TermBeam",
|
|
3
|
-
"short_name": "TermBeam",
|
|
4
|
-
"description": "Beam your terminal to any device",
|
|
5
|
-
"start_url": "/",
|
|
6
|
-
"display": "standalone",
|
|
7
|
-
"background_color": "#1e1e1e",
|
|
8
|
-
"theme_color": "#1e1e1e",
|
|
9
|
-
"icons": [
|
|
10
|
-
{ "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
|
|
11
|
-
{ "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" },
|
|
12
|
-
{ "src": "/icons/icon.svg", "sizes": "any", "type": "image/svg+xml" }
|
|
13
|
-
]
|
|
14
|
-
}
|