From 8cb466e7220967644bcdc91ee76798fdecbc05c9 Mon Sep 17 00:00:00 2001
From: "Jokob @NetAlertX" <96159884+jokob-sk@users.noreply.github.com>
Date: Sat, 20 Jun 2026 00:40:01 +0000
Subject: [PATCH 1/5] feat: Implement settings loading skeleton and enhance UI
elements
---
front/css/app.css | 180 +++++++++++++++++++++-
front/css/dark-patch.css | 13 ++
front/css/system-dark-patch.css | 15 +-
front/js/common.js | 12 +-
front/js/settings_utils.js | 2 +-
front/php/templates/header.php | 2 +-
front/php/templates/settings_skeleton.php | 106 +++++++++++++
front/settings.php | 34 ++--
8 files changed, 338 insertions(+), 26 deletions(-)
create mode 100644 front/php/templates/settings_skeleton.php
diff --git a/front/css/app.css b/front/css/app.css
index ef8f2ddf..e5ef9890 100755
--- a/front/css/app.css
+++ b/front/css/app.css
@@ -1083,6 +1083,7 @@ height: 50px;
.settingswrap
{
margin-bottom: 100px;
+ padding-top: 0px;
}
.settingswrap .metadata
@@ -1178,8 +1179,10 @@ height: 50px;
/* Settings */
#settingsPage .overview-setting-value{
- display:unset;
-
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-size: smaller;
}
.overview-setting-value-wrap
@@ -1228,7 +1231,7 @@ height: 50px;
}
#settingsPage .panel-heading:hover{
- background-color: #272c30;
+ background-color: #e8e8e8;
}
.settings-expand-icon {
@@ -2256,7 +2259,7 @@ textarea[readonly],
----------------------------------------------------------------------------- */
#loadingSpinner {
position: fixed;
- z-index: 1000;
+ z-index: 9999;
/* top: 0; */
/* left: 0; */
/* width: 100%; */
@@ -2265,7 +2268,6 @@ textarea[readonly],
transition: opacity 0.3s ease-in-out;
pointer-events: none;
display: block;
- z-index: 800;
}
.fa-spinner
@@ -2587,4 +2589,170 @@ table.dataTable tbody > tr.selected
.input-group-addon.text-muted {
color: #8c8c8c;
background-color: rgba(140, 140, 140, 0.05);
-}
\ No newline at end of file
+}
+
+/* ===== Settings Page Loading Skeleton ===== */
+
+:root {
+ --skel-base: #e2e2e2;
+ --skel-shine: #f0f0f0;
+ --skel-section: #d4d4d4;
+ --skel-panel-bg: #f5f5f5;
+ --skel-border: #ddd;
+ --skel-bg: #ecf0f5;
+}
+
+@keyframes settingsShimmer {
+ 0% { background-position: -600px 0; }
+ 100% { background-position: 600px 0; }
+}
+
+#settingsPage {
+ position: relative;
+}
+
+#settings-skeleton {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 50;
+ background-color: var(--skel-bg);
+ padding-top: 50px;
+ padding-left: 20px;
+ padding-right: 20px;
+ min-height: 500px;
+}
+
+.skel-shimmer {
+ background: linear-gradient(
+ 90deg,
+ var(--skel-base) 25%,
+ var(--skel-shine) 50%,
+ var(--skel-base) 75%
+ );
+ background-size: 600px 100%;
+ animation: settingsShimmer 1.5s infinite linear;
+ border-radius: 3px;
+ display: inline-block;
+}
+
+/* Overview panel skeleton */
+.skel-overview-panel {
+ margin-bottom: 10px;
+ border-radius: 4px;
+ overflow: hidden;
+ border: 1px solid var(--skel-border);
+}
+
+.skel-overview-heading {
+ height: 44px;
+ background: var(--skel-section);
+ display: flex;
+ align-items: center;
+ padding: 0 15px;
+ gap: 12px;
+}
+
+.skel-overview-body {
+ padding: 12px;
+ background: var(--skel-panel-bg);
+ display: flex;
+ gap: 12px;
+ flex-wrap: wrap;
+}
+
+.skel-overview-card {
+ min-width: 100px;
+ height: 76px;
+ border-radius: 4px;
+}
+
+/* Section accordion skeleton */
+.skel-section {
+ margin-bottom: 8px;
+ border-radius: 4px;
+ overflow: hidden;
+ border: 1px solid var(--skel-border);
+}
+
+.skel-overview-header {
+ height: 44px;
+ padding: 0 15px;
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ background: var(--skel-panel-bg);
+}
+
+.skel-section-header {
+ height: 44px;
+ padding: 0 15px;
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ background: var(--skel-section);
+}
+
+/* Plugin block inside an open section */
+.skel-plugin-block {
+ margin: 8px;
+ border-radius: 4px;
+ overflow: hidden;
+ border: 1px solid var(--skel-border);
+}
+
+.skel-plugin-header {
+ height: 48px;
+ padding: 0 15px;
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ background: var(--skel-section);
+}
+
+.skel-plugin-body {
+ background: var(--skel-panel-bg);
+}
+
+.skel-setting-row {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 11px 15px;
+ border-bottom: 1px solid var(--skel-border);
+}
+
+.skel-setting-row:last-child {
+ border-bottom: none;
+}
+
+/* Skeleton line / cell primitives */
+.skel-line {
+ height: 14px;
+ flex-shrink: 0;
+}
+
+.skel-icon-block {
+ width: 22px;
+ height: 16px;
+ flex-shrink: 0;
+}
+
+.skel-cell-name {
+ width: 20%;
+ height: 14px;
+ flex-shrink: 0;
+}
+
+.skel-cell-desc {
+ width: 36%;
+ height: 14px;
+ flex-shrink: 0;
+}
+
+.skel-cell-input {
+ flex: 1;
+ height: 32px;
+}
+/* ===== /Settings Page Loading Skeleton ===== */
\ No newline at end of file
diff --git a/front/css/dark-patch.css b/front/css/dark-patch.css
index dbda3801..9dcda157 100755
--- a/front/css/dark-patch.css
+++ b/front/css/dark-patch.css
@@ -516,6 +516,9 @@ textarea[readonly],
border: 1px solid #353c42;
color: #bec5cb;
}
+#settingsPage .panel-heading:hover {
+ background-color: #272c30;
+}
.box.box-solid.box-info,
.box.box-solid.box-info > .box-header {
color: #bec5cb;
@@ -754,4 +757,14 @@ table.dataTable tbody tr.selected, table.dataTable tbody tr .selected
font-family: 'Courier New', monospace;
font-size: .85em;
cursor: pointer;
+}
+
+/* Settings skeleton - dark theme */
+:root {
+ --skel-base: #2e3540;
+ --skel-shine: #3d4555;
+ --skel-section: #252c38;
+ --skel-panel-bg: #1e242e;
+ --skel-border: #2a323e;
+ --skel-bg: #353c42;
}
\ No newline at end of file
diff --git a/front/css/system-dark-patch.css b/front/css/system-dark-patch.css
index 06121b02..74171a1e 100755
--- a/front/css/system-dark-patch.css
+++ b/front/css/system-dark-patch.css
@@ -512,6 +512,9 @@
border: 1px solid #353c42;
color: #bec5cb;
}
+ #settingsPage .panel-heading:hover {
+ background-color: #272c30;
+ }
.box.box-solid.box-info,
.box.box-solid.box-info > .box-header {
color: #bec5cb;
@@ -731,4 +734,14 @@
font-family: 'Courier New', monospace;
font-size: .85em;
cursor: pointer;
-}
\ No newline at end of file
+}
+
+ /* Settings skeleton - dark theme */
+ :root {
+ --skel-base: #2e3540;
+ --skel-shine: #3d4555;
+ --skel-section: #252c38;
+ --skel-panel-bg: #1e242e;
+ --skel-border: #2a323e;
+ --skel-bg: #353c42;
+ }
\ No newline at end of file
diff --git a/front/js/common.js b/front/js/common.js
index 3ae3803b..7c0762d3 100755
--- a/front/js/common.js
+++ b/front/js/common.js
@@ -957,8 +957,8 @@ let animationTime = 300
function showSpinner(stringKey = 'Loading') {
let text = isEmpty(stringKey) ? "Loading..." : getString(stringKey || "Loading");
- if (text == ""){
- text = "Loading"
+ if (!text || !text.trim()) {
+ text = "Loading..."
}
const spinner = $("#loadingSpinner");
@@ -978,7 +978,7 @@ function showSpinner(stringKey = 'Loading') {
left: offset.left,
width: width,
height: height,
- zIndex: 800
+ zIndex: 9999
});
} else {
// Fullscreen fallback
@@ -988,7 +988,7 @@ function showSpinner(stringKey = 'Loading') {
left: 0,
width: "100%",
height: "100%",
- zIndex: 800
+ zIndex: 9999
});
}
@@ -1018,7 +1018,7 @@ function hideSpinner() {
left: offset.left,
width: width,
height: height,
- zIndex: 800
+ zIndex: 9999
});
} else {
// Fullscreen fallback
@@ -1028,7 +1028,7 @@ function hideSpinner() {
left: 0,
width: "100%",
height: "100%",
- zIndex: 800
+ zIndex: 9999
});
}
diff --git a/front/js/settings_utils.js b/front/js/settings_utils.js
index 6cb01e62..11b1a12b 100755
--- a/front/js/settings_utils.js
+++ b/front/js/settings_utils.js
@@ -99,7 +99,7 @@ function pluginCards(prefixesOfEnabledPlugins, includeSettings) {
});
html += `
-