Merge claude/1

This commit is contained in:
librelad 2026-05-23 00:07:38 +01:00
commit 5c6f4f4a2c
2 changed files with 55 additions and 1 deletions

View File

@ -840,6 +840,31 @@
min-width: 0; min-width: 0;
} }
/* Big amber alert icon so the warning reads at a glance. */
.backup-warning-banner-icon {
flex-shrink: 0;
color: #f59e0b;
}
/* Dismiss (×) in the banner's top-right corner. */
.backup-warning-banner-close {
flex-shrink: 0;
align-self: flex-start;
background: transparent;
border: none;
color: var(--text-secondary, rgba(var(--text-rgb), 0.6));
cursor: pointer;
padding: 2px;
border-radius: 6px;
line-height: 0;
transition: background 0.15s ease, color 0.15s ease;
}
.backup-warning-banner-close:hover {
background: rgba(var(--text-rgb), 0.1);
color: var(--text-primary);
}
.backup-warning-banner [data-action="export-passwords"] { .backup-warning-banner [data-action="export-passwords"] {
flex-shrink: 0; flex-shrink: 0;
white-space: nowrap; white-space: nowrap;

View File

@ -203,6 +203,16 @@ class BackupPage {
const exportBtn = e.target.closest('[data-action="export-passwords"]'); const exportBtn = e.target.closest('[data-action="export-passwords"]');
if (exportBtn) { this.exportRepositoryPasswords(exportBtn); return; } if (exportBtn) { this.exportRepositoryPasswords(exportBtn); return; }
const dismissWarn = e.target.closest('[data-action="dismiss-config-warning"]');
if (dismissWarn) {
localStorage.setItem('libreportal:backup-config-warning-dismissed', '1');
const banner = dismissWarn.closest('.backup-warning-banner');
const divider = banner?.nextElementSibling;
if (divider && divider.classList.contains('config-divider')) divider.remove();
banner?.remove();
return;
}
const saveBtn = e.target.closest('[data-backup-save]'); const saveBtn = e.target.closest('[data-backup-save]');
if (saveBtn) { if (saveBtn) {
this.saveSection(saveBtn.dataset.backupSave); this.saveSection(saveBtn.dataset.backupSave);
@ -783,8 +793,17 @@ class BackupPage {
const body = document.getElementById('backup-configuration-body'); const body = document.getElementById('backup-configuration-body');
if (!body) return; if (!body) return;
body.innerHTML = ` // The warning is a dismissible nudge, so its dismissed state lives in
// localStorage (per-browser) rather than server config. Banner + its
// divider are omitted entirely once dismissed.
const warningDismissed = localStorage.getItem('libreportal:backup-config-warning-dismissed') === '1';
const warningHTML = warningDismissed ? '' : `
<div class="backup-warning-banner"> <div class="backup-warning-banner">
<svg class="backup-warning-banner-icon" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>
<line x1="12" y1="9" x2="12" y2="13"></line>
<line x1="12" y1="17" x2="12.01" y2="17"></line>
</svg>
<div class="backup-warning-banner-text"> <div class="backup-warning-banner-text">
<strong>Keep your LibrePortal config backed up offline.</strong> <strong>Keep your LibrePortal config backed up offline.</strong>
<span>Repository passwords live inside the config directory. Without that backup, snapshots cannot be decrypted by anyone including you.</span> <span>Repository passwords live inside the config directory. Without that backup, snapshots cannot be decrypted by anyone including you.</span>
@ -797,8 +816,18 @@ class BackupPage {
</svg> </svg>
Export Repository Passwords Export Repository Passwords
</button> </button>
<button type="button" class="backup-warning-banner-close" data-action="dismiss-config-warning" title="Dismiss this warning" aria-label="Dismiss this warning">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div> </div>
<div class="config-divider"></div> <div class="config-divider"></div>
`;
body.innerHTML = `
${warningHTML}
<div id="config-section" class="backup-embedded-config"></div> <div id="config-section" class="backup-embedded-config"></div>
`; `;