diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..0ea3a94 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.2.0 diff --git a/containers/libreportal/frontend/css/update-notifier.css b/containers/libreportal/frontend/css/update-notifier.css new file mode 100644 index 0000000..c05446f --- /dev/null +++ b/containers/libreportal/frontend/css/update-notifier.css @@ -0,0 +1,237 @@ +/* Update Notifier — topbar badge, dashboard banner, and details panel. + Driven by js/components/update-notifier.js. Colours come from the active + theme tokens (with safe fallbacks) so it tracks every palette. */ + +/* ---- Topbar badge -------------------------------------------------------- */ + +.update-badge { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 7px 12px; + border: 1px solid var(--status-warning, #e0a106); + border-radius: 6px; + background: rgba(var(--status-warning-rgb, 224, 161, 6), 0.14); + color: var(--status-warning, #e0a106); + font-weight: 600; + font-size: 0.85rem; + cursor: pointer; + transition: background 0.2s, transform 0.1s; + white-space: nowrap; +} + +.update-badge:hover { + background: rgba(var(--status-warning-rgb, 224, 161, 6), 0.24); +} + +.update-badge:active { transform: scale(0.97); } + +.update-badge-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--status-warning, #e0a106); + box-shadow: 0 0 0 0 rgba(var(--status-warning-rgb, 224, 161, 6), 0.6); + animation: update-badge-pulse 2s infinite; +} + +@keyframes update-badge-pulse { + 0% { box-shadow: 0 0 0 0 rgba(var(--status-warning-rgb, 224, 161, 6), 0.6); } + 70% { box-shadow: 0 0 0 7px rgba(var(--status-warning-rgb, 224, 161, 6), 0); } + 100% { box-shadow: 0 0 0 0 rgba(var(--status-warning-rgb, 224, 161, 6), 0); } +} + +@media (prefers-reduced-motion: reduce) { + .update-badge-dot { animation: none; } +} + +/* ---- Dashboard banner ---------------------------------------------------- */ + +.update-banner { + display: flex; + align-items: center; + gap: 16px; + margin-bottom: 20px; + padding: 16px 20px; + border: 1px solid var(--status-warning, #e0a106); + border-left-width: 4px; + border-radius: 10px; + background: rgba(var(--status-warning-rgb, 224, 161, 6), 0.1); + color: var(--text-primary, #fff); +} + +/* Subtle "up to date" / local-install variant of the banner. */ +.update-banner.update-banner-ok { + border-color: var(--border-color, rgba(255, 255, 255, 0.12)); + border-left-color: var(--status-success, #2ea043); + background: var(--surface-bg, rgba(255, 255, 255, 0.03)); +} + +.update-banner.update-banner-ok .update-banner-icon { color: var(--status-success, #2ea043); } + +.update-banner.update-banner-ok .update-banner-title { font-weight: 600; } + +.update-banner-icon { + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; + color: var(--status-warning, #e0a106); +} + +.update-banner-text { flex: 1 1 auto; min-width: 0; } + +.update-banner-title { font-weight: 700; font-size: 1rem; } + +.update-banner-sub { + margin-top: 2px; + font-size: 0.85rem; + color: var(--text-muted, #9aa); +} + +.update-banner-actions { + display: flex; + gap: 8px; + flex: 0 0 auto; +} + +/* ---- Shared action buttons ----------------------------------------------- */ + +.update-btn-primary, +.update-btn-secondary { + padding: 8px 16px; + border-radius: 6px; + font-weight: 600; + font-size: 0.85rem; + cursor: pointer; + transition: background 0.2s, border-color 0.2s; + border: 1px solid transparent; + white-space: nowrap; +} + +.update-btn-primary { + background: var(--primary-color, #4f7cff); + color: var(--text-on-accent, #fff); +} + +.update-btn-primary:hover { background: var(--primary-hover, var(--accent-hover, #3a63d8)); } + +.update-btn-secondary { + background: transparent; + border-color: var(--border-color, rgba(255, 255, 255, 0.2)); + color: var(--text-primary, #fff); +} + +.update-btn-secondary:hover { background: var(--surface-hover, rgba(255, 255, 255, 0.08)); } + +/* ---- Details panel (modal) ----------------------------------------------- */ + +.update-panel-overlay { + position: fixed; + inset: 0; + z-index: 10000; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + background: rgba(0, 0, 0, 0.55); + backdrop-filter: blur(2px); +} + +.update-panel { + width: 100%; + max-width: 440px; + border: 1px solid var(--card-border, var(--border-color, rgba(255, 255, 255, 0.15))); + border-radius: 12px; + background: var(--card-bg, var(--surface-bg-solid, #1b1f2a)); + box-shadow: var(--card-shadow, 0 20px 60px rgba(0, 0, 0, 0.45)); + color: var(--text-primary, #fff); + overflow: hidden; +} + +.update-panel-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 20px; + border-bottom: 1px solid var(--border-color, rgba(255, 255, 255, 0.1)); +} + +.update-panel-header h3 { margin: 0; font-size: 1.05rem; } + +.update-panel-close { + border: none; + background: transparent; + color: var(--text-muted, #9aa); + font-size: 1.5rem; + line-height: 1; + cursor: pointer; + padding: 0 4px; +} + +.update-panel-close:hover { color: var(--text-primary, #fff); } + +.update-panel-status { + padding: 14px 20px 0; + font-size: 0.9rem; + color: var(--text-secondary, var(--text-muted, #9aa)); +} + +.update-panel-status.is-outdated { + color: var(--status-warning, #e0a106); + font-weight: 600; +} + +.update-panel-error { + margin: 12px 20px 0; + padding: 8px 12px; + border-radius: 6px; + font-size: 0.82rem; + background: rgba(var(--status-danger-rgb, 220, 53, 69), 0.12); + color: var(--status-danger, #dc3545); +} + +.update-panel-rows { + margin: 14px 0 0; + padding: 0 20px; +} + +.update-panel-row { + display: flex; + justify-content: space-between; + gap: 16px; + padding: 8px 0; + border-bottom: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.06)); + font-size: 0.88rem; +} + +.update-panel-row:last-child { border-bottom: none; } + +.update-panel-row dt { color: var(--text-muted, #9aa); margin: 0; } + +.update-panel-row dd { + margin: 0; + font-weight: 600; + text-align: right; + word-break: break-word; +} + +.update-panel-note { + margin: 14px 20px 0; + font-size: 0.8rem; + color: var(--text-muted, #9aa); + line-height: 1.45; +} + +.update-panel-actions { + display: flex; + justify-content: flex-end; + gap: 8px; + padding: 18px 20px 20px; +} + +@media (max-width: 600px) { + .update-banner { flex-wrap: wrap; } + .update-banner-actions { width: 100%; } + .update-banner-actions button { flex: 1 1 auto; } +} diff --git a/containers/libreportal/frontend/index.html b/containers/libreportal/frontend/index.html index f09389e..6113cf0 100755 --- a/containers/libreportal/frontend/index.html +++ b/containers/libreportal/frontend/index.html @@ -32,6 +32,7 @@ +