diff --git a/containers/libreportal/frontend/components/apps/core/html/apps-unified-layout.html b/containers/libreportal/frontend/components/apps/core/html/apps-unified-layout.html index 824647a..f96260f 100755 --- a/containers/libreportal/frontend/components/apps/core/html/apps-unified-layout.html +++ b/containers/libreportal/frontend/components/apps/core/html/apps-unified-layout.html @@ -317,6 +317,13 @@
+ +
+

🔀 Migrate

+

Move apps in from another LibrePortal, and manage the peers you share backup locations with.

+
diff --git a/containers/libreportal/frontend/components/apps/overview/css/overview.css b/containers/libreportal/frontend/components/apps/overview/css/overview.css index 051c7d4..a9dbc51 100644 --- a/containers/libreportal/frontend/components/apps/overview/css/overview.css +++ b/containers/libreportal/frontend/components/apps/overview/css/overview.css @@ -135,7 +135,8 @@ /* The Backups tab mounts the real BackupPage. Its own page-header replaces the generic fleet header, and its left sidebar is restyled into a horizontal nested tab strip so the whole thing reads as tabs-within-tabs. */ -#overview-view.ov-backups-active .overview-header { display: none; } +#overview-view.ov-backups-active .overview-header, +#overview-view.ov-migrate-active .overview-header { display: none; } #overview-view #ov-pane-backups .backup-layout { display: block; } #overview-view #ov-pane-backups .backup-layout > .sidebar { @@ -164,7 +165,7 @@ min-width: 0; align-items: center; justify-content: center; - gap: 8px; + gap: 6px; margin: 0; padding: 12px 14px; white-space: nowrap; diff --git a/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js b/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js index d87c4d3..0a76f7f 100644 --- a/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js +++ b/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js @@ -117,10 +117,15 @@ class OverviewManager { _applyTab(id) { if (this.tabs) this.tabs.switch(id); - // The Backups tab embeds the full backup center, which brings its own header - // and a nested sub-tab strip — hide the generic fleet header for it. + // Backups embeds the full backup center (its own header + nested sub-tab + // strip) and Migrate carries its own in-content .config-title header above + // its sub-tabs — both supply their own heading, so hide the generic fleet + // header for them. const root = document.getElementById('overview-view'); - if (root) root.classList.toggle('ov-backups-active', id === 'backups'); + if (root) { + root.classList.toggle('ov-backups-active', id === 'backups'); + root.classList.toggle('ov-migrate-active', id === 'migrate'); + } this.updateHeader(id); this.renderTab(id); this.current = id; diff --git a/containers/libreportal/frontend/core/theme/css/base.css b/containers/libreportal/frontend/core/theme/css/base.css index c9dee56..5026085 100755 --- a/containers/libreportal/frontend/core/theme/css/base.css +++ b/containers/libreportal/frontend/core/theme/css/base.css @@ -526,7 +526,14 @@ html[data-theme="nebula"]::after { min-width: 0; text-align: center; white-space: nowrap; + /* Lay the icon + label out as flex children with a fixed gap so spacing is + identical whether or not the markup has whitespace between the two spans + (the per-app Config sub-tabs rely on source whitespace; the Migrate + sub-tabs don't — this makes both render the same). */ + display: flex; + align-items: center; justify-content: center; + gap: 6px; } /* Task Status Indicator */