custom autocomplete above input (replace datalist), custom files, version bump to v1.1.0

This commit is contained in:
2026-08-07 18:44:03 +03:00
parent ab13666126
commit 2a6a37e337
2 changed files with 90 additions and 6 deletions
+51 -6
View File
@@ -883,8 +883,10 @@
<div id="pysim-sub-cmd" class="hidden">
<div class="flex gap-2 items-center mb-2">
<input id="pysim-cmd" class="font-mono flex-1 border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-2.5 dark:bg-slate-800" placeholder="select MF" autocomplete="off" list="pysim-cmdlist" onkeydown="pysimCmdKeydown(event)" oninput="pysimCmdHint()">
<datalist id="pysim-cmdlist"></datalist>
<div class="relative flex-1">
<input id="pysim-cmd" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-3 py-2.5 dark:bg-slate-800" placeholder="select MF" autocomplete="off" onkeydown="pysimCmdKeydown(event)" oninput="pysimCmdInput()">
<div id="pysim-cmd-suggest" class="hidden absolute bottom-full left-0 right-0 mb-1 max-h-32 overflow-y-auto border border-gray-300 dark:border-slate-600 rounded bg-white dark:bg-slate-800 text-xs font-mono shadow-lg z-10"></div>
</div>
<button onclick="pysimExec()" class="px-4 py-2.5 bg-emerald-600 text-white text-sm font-medium rounded hover:bg-emerald-700">Execute</button>
</div>
<div id="pysim-cmd-hint" class="hidden mb-2 text-xs font-mono text-gray-500 dark:text-slate-400 border border-gray-200 dark:border-slate-700 rounded p-2 bg-gray-50 dark:bg-slate-800 whitespace-pre-wrap"></div>
@@ -2713,16 +2715,59 @@ async function pysimCmdHint() {
}, 300);
}
let pysimCmdList = [];
async function pysimLoadCommands() {
const list = document.getElementById('pysim-cmdlist');
try {
const data = await pysimFetch('/api/commands');
if (Array.isArray(data)) {
list.innerHTML = data.map(c => '<option value="' + esc(c) + '">').join('');
}
if (Array.isArray(data)) pysimCmdList = data;
} catch (e) {}
}
function pysimCmdInput() {
const input = document.getElementById('pysim-cmd');
const text = input.value;
const suggestEl = document.getElementById('pysim-cmd-suggest');
const hintEl = document.getElementById('pysim-cmd-hint');
if (text.includes(' ')) {
suggestEl.classList.add('hidden');
const cmd = text.split(/\s+/)[0];
if (cmd) {
clearTimeout(pysimCmdHintTimeout);
pysimCmdHintTimeout = setTimeout(async () => {
try {
const data = await pysimFetch('/api/help', { cmd });
if (data.usage) {
hintEl.textContent = data.usage;
hintEl.classList.remove('hidden');
} else {
hintEl.classList.add('hidden');
}
} catch (e) {
hintEl.classList.add('hidden');
}
}, 300);
return;
}
hintEl.classList.add('hidden');
return;
}
hintEl.classList.add('hidden');
if (!text) { suggestEl.classList.add('hidden'); return; }
const matches = pysimCmdList.filter(c => c.startsWith(text)).slice(0, 20);
if (matches.length === 0) { suggestEl.classList.add('hidden'); return; }
suggestEl.innerHTML = matches.map(c =>
'<div class="px-2 py-1 cursor-pointer hover:bg-gray-100 dark:hover:bg-slate-700" onclick="pysimCmdSelect(\'' + esc(c) + '\')">' + esc(c) + '</div>'
).join('');
suggestEl.classList.remove('hidden');
}
function pysimCmdSelect(cmd) {
document.getElementById('pysim-cmd').value = cmd;
document.getElementById('pysim-cmd-suggest').classList.add('hidden');
document.getElementById('pysim-cmd').focus();
}
// ===== pysim file browser =====
let pysimFsTreeRoot = null;
+39
View File
@@ -554,6 +554,30 @@ video {
display: none;
}
.absolute {
position: absolute;
}
.relative {
position: relative;
}
.bottom-full {
bottom: 100%;
}
.left-0 {
left: 0px;
}
.right-0 {
right: 0px;
}
.z-10 {
z-index: 10;
}
.mx-auto {
margin-left: auto;
margin-right: auto;
@@ -635,6 +659,10 @@ video {
height: 4rem;
}
.max-h-32 {
max-height: 8rem;
}
.min-h-20 {
min-height: 5rem;
}
@@ -1061,6 +1089,12 @@ video {
text-decoration-line: underline;
}
.shadow-lg {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
@@ -1079,6 +1113,11 @@ video {
background-color: rgb(4 120 87 / var(--tw-bg-opacity, 1));
}
.hover\:bg-gray-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));
}
.hover\:bg-gray-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1));