add scrolling

This commit is contained in:
KingKDot
2026-06-27 19:38:10 -05:00
parent 84de7050fb
commit d3ded9f877
3 changed files with 83 additions and 12 deletions
+41 -10
View File
@@ -22,6 +22,7 @@ const scriptsLink = document.getElementById("scripts-link");
const pluginsLink = document.getElementById("plugins-link"); const pluginsLink = document.getElementById("plugins-link");
const rawServerListCheckbox = document.getElementById("raw-server-list"); const rawServerListCheckbox = document.getElementById("raw-server-list");
const serverUrlInput = document.getElementById("server-url"); const serverUrlInput = document.getElementById("server-url");
const serverUrlCurrentBtn = document.getElementById("server-url-current-btn");
const solMemoCheckbox = document.getElementById("sol-memo"); const solMemoCheckbox = document.getElementById("sol-memo");
const solSettings = document.getElementById("sol-settings"); const solSettings = document.getElementById("sol-settings");
const profileSelect = document.getElementById("build-profile-select"); const profileSelect = document.getElementById("build-profile-select");
@@ -70,13 +71,25 @@ async function loadServerVersion() {
function getDefaultServerUrlPlaceholder(isRawList) { function getDefaultServerUrlPlaceholder(isRawList) {
if (isRawList) { if (isRawList) {
const isHttps = window.location.protocol === "https:"; return getCurrentRawServerListUrl();
const host = window.location.host;
return `${isHttps ? "https" : "http"}://${host}/list.txt`;
} }
return ""; return "";
} }
function getCurrentServerHost() {
return window.location.host || window.location.hostname || "";
}
function getCurrentRawServerListUrl() {
const protocol = window.location.protocol === "https:" ? "https" : "http";
const host = getCurrentServerHost();
return host ? `${protocol}://${host}/list.txt` : "";
}
function getCurrentServerUrlForMode() {
return getCurrentServerHost();
}
function stripServerUrlPrefix(value) { function stripServerUrlPrefix(value) {
return String(value || "").replace(/^\s*(wss?|https?):\/\//i, "").trimStart(); return String(value || "").replace(/^\s*(wss?|https?):\/\//i, "").trimStart();
} }
@@ -93,9 +106,17 @@ function updateServerUrlPlaceholder() {
if (!serverUrlInput) return; if (!serverUrlInput) return;
const isRaw = rawServerListCheckbox?.checked ?? false; const isRaw = rawServerListCheckbox?.checked ?? false;
serverUrlInput.placeholder = getDefaultServerUrlPlaceholder(isRaw); serverUrlInput.placeholder = getDefaultServerUrlPlaceholder(isRaw);
updateServerUrlCurrentButton();
updateServerUrlHintMode(); updateServerUrlHintMode();
} }
function updateServerUrlCurrentButton() {
if (!serverUrlCurrentBtn) return;
const isRaw = rawServerListCheckbox?.checked ?? false;
serverUrlCurrentBtn.classList.toggle("hidden", isRaw);
serverUrlCurrentBtn.disabled = isRaw;
}
let isBuilding = false; let isBuilding = false;
function initAccordions() { function initAccordions() {
@@ -563,8 +584,7 @@ function applyFormSettings(settings) {
solSettings.classList.toggle("hidden", !solMemoCheckbox.checked); solSettings.classList.toggle("hidden", !solMemoCheckbox.checked);
} }
if (serverUrlInput && rawServerListCheckbox) { if (serverUrlInput && rawServerListCheckbox) {
serverUrlInput.placeholder = getDefaultServerUrlPlaceholder(rawServerListCheckbox.checked); updateServerUrlPlaceholder();
updateServerUrlHintMode();
} }
applyCryptableMode(document.getElementById("cryptable-mode")?.checked || false); applyCryptableMode(document.getElementById("cryptable-mode")?.checked || false);
} }
@@ -836,10 +856,23 @@ if (rawServerListCheckbox && serverUrlInput) {
// Non-raw mode: bare domain only. The agent prepends wss:// itself. // Non-raw mode: bare domain only. The agent prepends wss:// itself.
serverUrlInput.value = stripServerUrlPrefix(current); serverUrlInput.value = stripServerUrlPrefix(current);
} }
serverUrlInput.placeholder = getDefaultServerUrlPlaceholder(isRaw); updateServerUrlPlaceholder();
updateServerUrlHintMode();
}); });
if (serverUrlCurrentBtn) {
serverUrlCurrentBtn.addEventListener("click", () => {
if (solMemoCheckbox?.checked) {
solMemoCheckbox.checked = false;
if (solSettings) solSettings.classList.add("hidden");
}
serverUrlInput.value = getCurrentServerUrlForMode();
serverUrlInput.dispatchEvent(new Event("input", { bubbles: true }));
serverUrlInput.dispatchEvent(new Event("change", { bubbles: true }));
saveFormSettings();
serverUrlInput.focus();
});
}
// Live-strip protocol prefixes in non-raw mode so the field stays clean and // Live-strip protocol prefixes in non-raw mode so the field stays clean and
// the user sees their typo corrected immediately. // the user sees their typo corrected immediately.
serverUrlInput.addEventListener("input", () => { serverUrlInput.addEventListener("input", () => {
@@ -891,9 +924,7 @@ if (solMemoCheckbox && solSettings) {
if (isSol && rawServerListCheckbox) { if (isSol && rawServerListCheckbox) {
rawServerListCheckbox.checked = false; rawServerListCheckbox.checked = false;
if (serverUrlInput) { updateServerUrlPlaceholder();
serverUrlInput.placeholder = getDefaultServerUrlPlaceholder(false);
}
} }
if (isSol) { if (isSol) {
+33
View File
@@ -74,6 +74,10 @@ menuStyle.textContent = `
border-radius: 8px; border-radius: 8px;
padding: 4px; padding: 4px;
min-width: 196px; min-width: 196px;
max-height: calc(100vh - 16px);
overflow-y: auto;
overflow-x: hidden;
overscroll-behavior: contain;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1px; gap: 1px;
@@ -92,6 +96,27 @@ menuStyle.textContent = `
flex-direction: column; flex-direction: column;
gap: 1px; gap: 1px;
z-index: 1; z-index: 1;
max-height: calc(100vh - 16px);
overflow-y: auto;
overflow-x: hidden;
overscroll-behavior: contain;
}
#ctx-main, #ctx-sub {
scrollbar-width: thin;
scrollbar-color: rgba(148,163,184,0.35) transparent;
}
#ctx-main::-webkit-scrollbar,
#ctx-sub::-webkit-scrollbar {
width: 8px;
}
#ctx-main::-webkit-scrollbar-thumb,
#ctx-sub::-webkit-scrollbar-thumb {
background: rgba(148,163,184,0.28);
border-radius: 999px;
}
#ctx-main::-webkit-scrollbar-thumb:hover,
#ctx-sub::-webkit-scrollbar-thumb:hover {
background: rgba(148,163,184,0.45);
} }
.ctx-row { .ctx-row {
display: flex; display: flex;
@@ -221,6 +246,8 @@ menuStyle.textContent = `
} }
#ctx-main, #ctx-sub { #ctx-main, #ctx-sub {
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.7); box-shadow: 0 8px 40px rgba(0, 0, 0, 0.7);
max-height: none;
overflow: visible;
} }
#ctx-sub { position: static; margin-top: 0; min-width: 0; width: 100%; border-radius: 0 0 8px 8px; border-top: 1px solid rgba(148,163,184,0.08); left: auto; right: auto; } #ctx-sub { position: static; margin-top: 0; min-width: 0; width: 100%; border-radius: 0 0 8px 8px; border-top: 1px solid rgba(148,163,184,0.08); left: auto; right: auto; }
#ctx-main { border-radius: 8px 8px 0 0; } #ctx-main { border-radius: 8px 8px 0 0; }
@@ -290,12 +317,16 @@ function showSubmenu(groupId, rowEl) {
const mainRect = ctxMain.getBoundingClientRect(); const mainRect = ctxMain.getBoundingClientRect();
let offsetY = rowRect.top - mainRect.top; let offsetY = rowRect.top - mainRect.top;
ctxSub.style.maxHeight = "calc(100vh - 16px)";
const subH = ctxSub.offsetHeight; const subH = ctxSub.offsetHeight;
const menuTop = parseFloat(menu.style.top) || 0; const menuTop = parseFloat(menu.style.top) || 0;
if (menuTop + offsetY + subH > window.innerHeight - 8) { if (menuTop + offsetY + subH > window.innerHeight - 8) {
offsetY = Math.max(0, window.innerHeight - 8 - subH - menuTop); offsetY = Math.max(0, window.innerHeight - 8 - subH - menuTop);
} }
ctxSub.style.top = offsetY + "px"; ctxSub.style.top = offsetY + "px";
const subTop = menuTop + offsetY;
ctxSub.style.maxHeight = Math.max(120, window.innerHeight - subTop - 8) + "px";
ctxSub.scrollTop = 0;
// Flip to left if submenu overflows right edge // Flip to left if submenu overflows right edge
const subW = ctxSub.offsetWidth; const subW = ctxSub.offsetWidth;
@@ -396,6 +427,8 @@ export function openMenu(clientId, x, y, setContext, options = {}) {
menu.style.top = "-9999px"; menu.style.top = "-9999px";
menu.style.display = "flex"; menu.style.display = "flex";
menu.setAttribute("aria-hidden", "false"); menu.setAttribute("aria-hidden", "false");
ctxMain.scrollTop = 0;
ctxSub.scrollTop = 0;
requestAnimationFrame(() => { requestAnimationFrame(() => {
const mw = menu.offsetWidth; const mw = menu.offsetWidth;
+9 -2
View File
@@ -350,8 +350,15 @@
<div> <div>
<label class="block text-sm font-medium text-slate-300 mb-2" for="server-url">Server URL</label> <label class="block text-sm font-medium text-slate-300 mb-2" for="server-url">Server URL</label>
<input type="text" id="server-url" name="server-url" <div class="flex gap-2">
class="w-full px-3 py-2 bg-slate-800/60 border border-slate-700 rounded-lg focus:outline-none focus:border-blue-500 transition-colors" /> <input type="text" id="server-url" name="server-url"
class="min-w-0 flex-1 px-3 py-2 bg-slate-800/60 border border-slate-700 rounded-lg focus:outline-none focus:border-blue-500 transition-colors" />
<button type="button" id="server-url-current-btn" aria-label="Use current website host"
title="Use current website host"
class="shrink-0 w-10 h-10 inline-flex items-center justify-center rounded-lg bg-slate-800/70 border border-slate-700 text-slate-300 hover:text-blue-300 hover:border-blue-500 transition-colors">
<i class="fa-solid fa-globe"></i>
</button>
</div>
<p id="server-url-hint" class="text-xs text-slate-500 mt-1"> <p id="server-url-hint" class="text-xs text-slate-500 mt-1">
Just enter your domain or IP:PORT — no <code class="text-slate-400">wss://</code>, <code class="text-slate-400">https://</code>, or any other prefix. Just enter your domain or IP:PORT — no <code class="text-slate-400">wss://</code>, <code class="text-slate-400">https://</code>, or any other prefix.
</p> </p>