diff --git a/containers/libreportal/frontend/components/admin/config/js/catalog-manager.js b/containers/libreportal/frontend/components/admin/config/js/catalog-manager.js
index 45ba8f4..d04f6ce 100644
--- a/containers/libreportal/frontend/components/admin/config/js/catalog-manager.js
+++ b/containers/libreportal/frontend/components/admin/config/js/catalog-manager.js
@@ -25,10 +25,10 @@ class CatalogManager {
`;
}
- // The pinned official row (source #1). Renders the official URL in a read-only
- // input — same element (and height) as the third-party rows — with the badge
- // overlaid. The hidden CFG_CATALOG_OFFICIAL_ENABLED input carries its on/off
- // state so it saves with the rest on "Save Config".
+ // The pinned official row (source #1). Read-only URL input (same element/height
+ // as the third-party rows) with the badge overlaid. It can be hidden from
+ // browsing via the × (opens a clear ✓/✗ confirmation); the hidden
+ // CFG_CATALOG_OFFICIAL_ENABLED input carries that state so it saves on "Save".
_officialRow(base, enabled) {
const url = base || '';
const off = enabled === false;
@@ -193,14 +193,32 @@ window.officialCatalogActionHTML = function (enabled) {
window.deleteOfficialCatalog = function () {
const apply = () => window._setOfficialCatalog(false);
+ const body = `
+
⚠️
-
${this.escapeHtml(message)}
+
${messageHtml || this.escapeHtml(message)}
${showDataLossCheckbox ? `
@@ -142,12 +142,12 @@ function initConfirmationDialog() {
// initConfirmationDialog() will be called centrally
// Global function
-window.showConfirmation = (title, message, onConfirm, confirmText, cancelText, confirmClass, showDataLossCheckbox, checkboxText) => {
+window.showConfirmation = (title, message, onConfirm, confirmText, cancelText, confirmClass, showDataLossCheckbox, checkboxText, messageHtml) => {
// Ensure dialog is initialized
initConfirmationDialog();
if (confirmationDialog) {
- confirmationDialog.show(title, message, onConfirm, confirmText, cancelText, confirmClass, showDataLossCheckbox, checkboxText);
+ confirmationDialog.show(title, message, onConfirm, confirmText, cancelText, confirmClass, showDataLossCheckbox, checkboxText, messageHtml);
} else {
// Fallback to native confirm
if (confirm(message)) {
diff --git a/containers/libreportal/frontend/core/theme/css/base.css b/containers/libreportal/frontend/core/theme/css/base.css
index 2e14cc2..18d0ca5 100755
--- a/containers/libreportal/frontend/core/theme/css/base.css
+++ b/containers/libreportal/frontend/core/theme/css/base.css
@@ -935,6 +935,45 @@ html[data-theme="nebula"]::after {
flex: 1;
}
+/* Structured ✓/✗ effect list for confirmations (e.g. hiding the official catalog). */
+.catalog-effects-lead {
+ margin: 0 0 12px;
+ color: var(--text-primary, #fff);
+}
+.catalog-effects {
+ display: grid;
+ gap: 10px;
+ text-align: left;
+}
+.catalog-effect-group {
+ background: rgba(0, 0, 0, 0.20);
+ border: 1px solid var(--border-color);
+ border-left: 3px solid var(--border-color);
+ border-radius: 8px;
+ padding: 8px 12px;
+}
+.catalog-effect-group.ok { border-left-color: #2ecc71; }
+.catalog-effect-group.no { border-left-color: var(--status-warning); }
+.catalog-effect-title {
+ font-weight: 700;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ margin-bottom: 4px;
+}
+.catalog-effect-group.ok .catalog-effect-title { color: #2ecc71; }
+.catalog-effect-group.ok .catalog-effect-title::before { content: "✓ "; }
+.catalog-effect-group.no .catalog-effect-title { color: var(--status-warning); }
+.catalog-effect-group.no .catalog-effect-title::before { content: "✕ "; }
+.catalog-effects ul {
+ margin: 0;
+ padding-left: 18px;
+ font-size: 13px;
+ line-height: 1.5;
+ color: var(--text-secondary, rgba(255, 255, 255, 0.8));
+}
+.catalog-effects li { margin: 2px 0; }
+
.confirmation-checkbox {
padding-top: 15px;
border-top: 1px solid var(--border-strong);