termites 1.0.32 → 1.0.34

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +45 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termites",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "description": "Local multi-terminal manager with web interface",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/server.js CHANGED
@@ -619,11 +619,13 @@ class TermitesServer {
619
619
  <head>
620
620
  <meta charset="UTF-8">
621
621
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
622
+ <meta name="color-scheme" content="light dark">
622
623
  <title>Termites</title>
623
624
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css">
624
625
  <style>
626
+ :root { color-scheme: light dark; }
625
627
  * { margin: 0; padding: 0; box-sizing: border-box; }
626
- html { height: 100%; overflow: hidden; }
628
+ html { height: 100%; overflow: hidden; background-color: inherit; }
627
629
  body { height: 100vh; height: 100dvh; display: flex; flex-direction: column; transition: background 0.3s; font-family: monospace; overflow: hidden; position: fixed; width: 100%; }
628
630
  .header {
629
631
  padding: 10px 12px; display: flex; align-items: center; gap: 12px;
@@ -946,6 +948,10 @@ class TermitesServer {
946
948
  const t = themes[themeName];
947
949
  if (!t) return;
948
950
  currentTheme = themeName;
951
+ // Set color-scheme to prevent browser auto dark mode
952
+ const isLightTheme = themeName === 'solarized-light';
953
+ document.documentElement.style.colorScheme = isLightTheme ? 'only light' : 'only dark';
954
+ document.documentElement.style.background = t.background;
949
955
  document.body.style.background = t.background;
950
956
  document.getElementById('terminal-container').style.background = t.background;
951
957
  const header = document.querySelector('.header');
@@ -1089,10 +1095,10 @@ class TermitesServer {
1089
1095
  };
1090
1096
 
1091
1097
  toolbar.querySelectorAll('button').forEach(btn => {
1092
- // Use touchstart to prevent losing focus on terminal
1093
- const handler = (e) => {
1094
- e.preventDefault();
1095
- e.stopPropagation();
1098
+ let repeatInterval = null;
1099
+ const isArrowKey = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(btn.dataset.key);
1100
+
1101
+ const sendKey = () => {
1096
1102
  const mod = btn.dataset.mod;
1097
1103
  const key = btn.dataset.key;
1098
1104
  const seq = btn.dataset.seq;
@@ -1100,7 +1106,6 @@ class TermitesServer {
1100
1106
  if (mod) {
1101
1107
  modifiers[mod] = !modifiers[mod];
1102
1108
  btn.classList.toggle('active', modifiers[mod]);
1103
- // Set timeout to auto-reset Ctrl after 10 seconds (for IME users)
1104
1109
  if (mod === 'ctrl' && modifiers.ctrl) {
1105
1110
  if (window.ctrlTimeout) clearTimeout(window.ctrlTimeout);
1106
1111
  window.ctrlTimeout = setTimeout(() => {
@@ -1108,7 +1113,6 @@ class TermitesServer {
1108
1113
  btn.classList.remove('active');
1109
1114
  }, 10000);
1110
1115
  }
1111
- // Don't focus terminal when toggling modifier, keep keyboard open
1112
1116
  return;
1113
1117
  }
1114
1118
 
@@ -1117,21 +1121,17 @@ class TermitesServer {
1117
1121
  data = seq;
1118
1122
  } else if (key) {
1119
1123
  if (modifiers.ctrl) {
1120
- // Ctrl + key
1121
1124
  if (ctrlKeyMap[key]) {
1122
1125
  data = ctrlKeyMap[key];
1123
1126
  } else if (key.length === 1) {
1124
- // Ctrl + letter (e.g., Ctrl+C = \\x03)
1125
1127
  data = String.fromCharCode(key.toUpperCase().charCodeAt(0) - 64);
1126
1128
  } else {
1127
1129
  data = keyMap[key] || '';
1128
1130
  }
1129
1131
  } else if (modifiers.alt) {
1130
- // Alt + key
1131
1132
  if (altKeyMap[key]) {
1132
1133
  data = altKeyMap[key];
1133
1134
  } else if (key.length === 1) {
1134
- // Alt + letter sends ESC + letter
1135
1135
  data = '\\x1b' + key;
1136
1136
  } else {
1137
1137
  data = keyMap[key] || '';
@@ -1143,17 +1143,47 @@ class TermitesServer {
1143
1143
 
1144
1144
  if (data && ws?.readyState === WebSocket.OPEN && selectedClientId) {
1145
1145
  ws.send(JSON.stringify({ type: 'input', clientId: selectedClientId, text: data }));
1146
- // Reset modifiers after use
1146
+ }
1147
+ };
1148
+
1149
+ const startRepeat = (e) => {
1150
+ e.preventDefault();
1151
+ e.stopPropagation();
1152
+ sendKey();
1153
+ // For arrow keys, start repeating after initial press
1154
+ if (isArrowKey && !btn.dataset.mod) {
1155
+ repeatInterval = setInterval(sendKey, 100);
1156
+ }
1157
+ // Reset modifiers after use (except for arrow keys during repeat)
1158
+ if (!isArrowKey) {
1159
+ modifiers.ctrl = false;
1160
+ modifiers.alt = false;
1161
+ if (window.ctrlTimeout) { clearTimeout(window.ctrlTimeout); window.ctrlTimeout = null; }
1162
+ toolbar.querySelectorAll('.mod-btn').forEach(b => b.classList.remove('active'));
1163
+ }
1164
+ };
1165
+
1166
+ const stopRepeat = () => {
1167
+ if (repeatInterval) {
1168
+ clearInterval(repeatInterval);
1169
+ repeatInterval = null;
1170
+ }
1171
+ // Reset modifiers after arrow key release
1172
+ if (isArrowKey) {
1147
1173
  modifiers.ctrl = false;
1148
1174
  modifiers.alt = false;
1149
1175
  if (window.ctrlTimeout) { clearTimeout(window.ctrlTimeout); window.ctrlTimeout = null; }
1150
1176
  toolbar.querySelectorAll('.mod-btn').forEach(b => b.classList.remove('active'));
1151
1177
  }
1152
- // Only focus terminal for non-modifier buttons
1153
1178
  term.focus();
1154
1179
  };
1155
- btn.addEventListener('touchstart', handler, { passive: false });
1156
- btn.addEventListener('click', handler);
1180
+
1181
+ btn.addEventListener('touchstart', startRepeat, { passive: false });
1182
+ btn.addEventListener('touchend', stopRepeat);
1183
+ btn.addEventListener('touchcancel', stopRepeat);
1184
+ btn.addEventListener('mousedown', startRepeat);
1185
+ btn.addEventListener('mouseup', stopRepeat);
1186
+ btn.addEventListener('mouseleave', stopRepeat);
1157
1187
  });
1158
1188
 
1159
1189
  // History button