This commit is contained in:
Mateusz Gruszczyński committed 2026-11-09 23:55:03 +01:00
1 parent 358a4518d9
commit 2789991452
13 files changed
+215 -6

No files matched your search

+6 -2
View File
@@ -53,6 +53,7 @@ function translate() {
document.querySelectorAll("[data-i18n-placeholder]").forEach(e => e.placeholder = t(e.dataset.i18nPlaceholder));
document.querySelectorAll("[data-i18n-aria]").forEach(e => e.setAttribute("aria-label", t(e.dataset.i18nAria)));
document.querySelectorAll("[data-i18n-title]").forEach(e => { e.title = t(e.dataset.i18nTitle); });
window.rustProxySidebar?.refresh?.();
window.rustProxyAclProfiles?.refreshTranslations?.();
$("language").value = languagePreference === "auto" ? "auto" : language; setPanel(currentPanel, false); syncAuthForm(); renderSession();
window.rustProxyDrafts?.refresh();
@@ -511,10 +512,13 @@ async function activate(info) {
for (const id of ["password", "password-confirm", "setup-token"]) $(id).value = "";
$("login").hidden = true; $("workspace").hidden = false; $("logout").hidden = false;
renderSession();
document.documentElement.classList.remove("app-loading");
document.documentElement.classList.remove("app-startup-failed");
rustProxyRefresh.start();
const preferences = await loadAdminPreferences();
// Keep the startup screen until the account preferences (menu, layout, density)
// are applied, so the panel never appears first with defaults and then changes.
let preferences;
try { preferences = await loadAdminPreferences(); }
finally { document.documentElement.classList.remove("app-loading"); }
if (!authenticated || epoch !== authEpoch) return false;
window.rustProxyLogs?.applyPreferences(preferences);
window.rustProxyFileLogs?.applyPreferences(preferences);
+1 -1
View File
@@ -168,7 +168,7 @@ function uiIconForTarget(target) {
if (manual && UI_ICON_SHAPES[manual]) return manual;
if (target.matches(".chart-style-choice")) return null;
if (target.matches(".overview-inline-grip, .overview-inline-narrow, .overview-inline-widen, .overview-inline-up, .overview-inline-down, .overview-inline-hide, .overview-layout-narrow, .overview-layout-widen, .overview-layout-up, .overview-layout-down, .overview-layout-hide")) return null;
if (target.matches("#tunnels-open, .vhost-backend-protocol-badge, .config-history-day, .draft-dock-toggle, .mobile-menu-toggle")) return null;
if (target.matches("#tunnels-open, .vhost-backend-protocol-badge, .config-history-day, .draft-dock-toggle, .mobile-menu-toggle, .sidebar-collapse")) return null;
if (UI_GLYPH_LABEL.test(String(target.textContent || "").trim())) return null;
if (UI_ID_ICONS[target.id]) return UI_ID_ICONS[target.id];
if (target.matches("#web-service-preset-apply, [data-cache-memory-preset], [data-cache-cold-preset], [data-transform-preset]")) return "wand";
+3 -2
View File
@@ -14,7 +14,7 @@ const ADMIN_DEFAULT_HIDDEN_WIDGETS = Object.freeze([...new Set([
const ADMIN_APPEARANCE_DEFAULTS = Object.freeze({
theme: "dark", language: "auto", ui_scale: 100, time_format: "24h", chart_style: "default",
chart_axes: false, interface_icons: false, logo_animation: false,
button_style: "normal", corner_style: "default", table_density: "normal", dashboard_density: ADMIN_DASHBOARD_DEFAULTS.dashboard_density, dashboard_widgets: [...ADMIN_DASHBOARD_WIDGETS], dashboard_hidden_widgets: [...ADMIN_DEFAULT_HIDDEN_WIDGETS], dashboard_widget_sizes: null, dashboard_widget_heights: null, dashboard_auto_fit: true,
button_style: "normal", corner_style: "default", table_density: "normal", dashboard_density: ADMIN_DASHBOARD_DEFAULTS.dashboard_density, dashboard_widgets: [...ADMIN_DASHBOARD_WIDGETS], dashboard_hidden_widgets: [...ADMIN_DEFAULT_HIDDEN_WIDGETS], dashboard_widget_sizes: null, dashboard_widget_heights: null, dashboard_auto_fit: true, sidebar_collapsed: false,
});
const CHART_STYLE_KEYS = Object.freeze({ default: "chartStyleDefault", soft: "chartStyleSoft", technical: "chartStyleTechnical", high_contrast: "chartStyleHighContrast", neon: "chartStyleNeon", monochrome: "chartStyleMonochrome", warm: "chartStyleWarm", cool: "chartStyleCool", sunset: "chartStyleSunset", aurora: "chartStyleAurora", ocean: "chartStyleOcean", forest: "chartStyleForest", pastel: "chartStylePastel", terminal: "chartStyleTerminal", blueprint: "chartStyleBlueprint", colorblind: "chartStyleColorblind" });
let adminPreferences = null, adminPreferencesLoading = null, adminPreferencesWrite = Promise.resolve(), adminPreferencesUnavailable = false;
@@ -316,6 +316,7 @@ function applyAdminPreferences(value, cache = true) {
window.rustProxyStreams?.applyPreferences(normalized);
if (languagePacks.size) translate();
refreshAppearanceUi();
window.rustProxySidebar?.applyPreference?.(normalized.sidebar_collapsed === true);
window.rustProxyOverviewRows?.reveal?.();
return normalized;
}
@@ -357,7 +358,7 @@ function updateAdminPreferences(patch) {
next.refresh = normalizeRefreshPreferences(next.refresh);
next.theme = normalizeAdminTheme(next.theme); next.language = normalizeAdminLanguage(next.language); next.ui_scale = normalizeAdminUiScale(next.ui_scale);
next.time_format = normalizeAdminTimeFormat(next.time_format); next.chart_style = normalizeAdminChartStyle(next.chart_style); next.chart_axes = next.chart_axes === true; next.interface_icons = next.interface_icons === true; next.logo_animation = next.logo_animation === true; next.button_style = normalizeAdminButtonStyle(next.button_style); next.corner_style = normalizeAdminCornerStyle(next.corner_style); next.table_density = normalizeAdminDensity(next.table_density);
next.dashboard_density = normalizeAdminDensity(next.dashboard_density, "compact"); next.dashboard_widgets = normalizeDashboardWidgets(next.dashboard_widgets); next.dashboard_hidden_widgets = normalizeHiddenDashboardWidgets(next.dashboard_hidden_widgets); next.dashboard_widget_sizes = normalizeDashboardWidgetSizes(next.dashboard_widget_sizes); next.dashboard_widget_heights = normalizeDashboardWidgetHeights(next.dashboard_widget_heights); next.dashboard_auto_fit = next.dashboard_auto_fit !== false;
next.dashboard_density = normalizeAdminDensity(next.dashboard_density, "compact"); next.dashboard_widgets = normalizeDashboardWidgets(next.dashboard_widgets); next.dashboard_hidden_widgets = normalizeHiddenDashboardWidgets(next.dashboard_hidden_widgets); next.dashboard_widget_sizes = normalizeDashboardWidgetSizes(next.dashboard_widget_sizes); next.dashboard_widget_heights = normalizeDashboardWidgetHeights(next.dashboard_widget_heights); next.dashboard_auto_fit = next.dashboard_auto_fit !== false; next.sidebar_collapsed = next.sidebar_collapsed === true;
const saved = await api("/api/preferences", { method: "PUT", body: JSON.stringify(next) });
if (!authenticated || epoch !== authEpoch) return adminPreferences;
return applyAdminPreferences(saved);
+54
View File
@@ -0,0 +1,54 @@
// Collapsible left menu. On wide screens (above 1300 px) the account preference
// sidebar_collapsed shows the menu as a narrow rail (logo, section numbers or icons,
// status dot). Between 851 and 1300 px the menu is always a rail and the toggle
// opens it temporarily as an overlay (closed by choosing a section, clicking
// outside or Esc). At 850 px and below the existing mobile menu is used.
window.rustProxySidebar = (() => {
const root = document.documentElement;
const sidebar = document.querySelector(".sidebar");
const toggle = document.getElementById("sidebar-collapse-toggle");
if (!sidebar || !toggle) return { applyPreference() { }, refresh() { } };
const desktop = window.matchMedia("(min-width: 851px)");
const rail = window.matchMedia("(min-width: 851px) and (max-width: 1300px)");
const label = key => (typeof t === "function" ? t(key) : key);
let preferred = false, peek = false;
function render() {
if (!desktop.matches || !rail.matches) peek = false;
const collapsed = desktop.matches && (rail.matches ? !peek : preferred);
root.classList.toggle("sidebar-collapsed", collapsed);
root.classList.toggle("sidebar-peek", peek);
const key = collapsed ? "sidebarExpand" : "sidebarCollapse";
toggle.setAttribute("aria-expanded", String(!collapsed));
toggle.setAttribute("aria-label", label(key));
toggle.title = label(key);
toggle.querySelector(".sidebar-collapse-label").textContent = label(key);
toggle.querySelector(".sidebar-collapse-icon").textContent = collapsed ? "»" : "«";
for (const nav of sidebar.querySelectorAll(".nav")) {
if (collapsed) nav.title = nav.querySelector("b")?.textContent.replace(/\s+/g, " ").trim() || "";
else nav.removeAttribute("title");
}
}
function setPeek(open) {
if (peek === open) return;
peek = open;
render();
}
toggle.addEventListener("click", event => {
event.stopPropagation();
if (rail.matches) { setPeek(!peek); return; }
preferred = !preferred;
render();
window.rustProxyPreferences?.update?.({ sidebar_collapsed: preferred })?.catch?.(() => { });
});
sidebar.querySelectorAll(".nav, .brand").forEach(item => item.addEventListener("click", () => setPeek(false)));
document.addEventListener("click", event => { if (peek && !sidebar.contains(event.target)) setPeek(false); });
document.addEventListener("keydown", event => { if (event.key === "Escape" && peek) { setPeek(false); toggle.focus(); } });
desktop.addEventListener?.("change", render);
rail.addEventListener?.("change", render);
render();
return {
applyPreference(value) { preferred = value === true; render(); },
refresh: render,
};
})();