diff --git a/app/sovran_systemsos_web/static/css/header.css b/app/sovran_systemsos_web/static/css/header.css index 4ec98f0..37105c0 100644 --- a/app/sovran_systemsos_web/static/css/header.css +++ b/app/sovran_systemsos_web/static/css/header.css @@ -56,49 +56,6 @@ .search-box input::placeholder { color: var(--text-3); } -/* ── Network chip — LAN + WAN always on one line ────────────────── */ - -.net-chip { - display: flex; - align-items: center; - gap: 10px; - padding: 8px 17px; - border-radius: 99px; - background: var(--card); - border: 1px solid var(--border); - font-family: var(--mono); - font-size: 0.73rem; - color: var(--text-3); - white-space: nowrap; - order: 4; -} - -.net-chip svg { width: 15px; height: 15px; color: var(--text-3); flex-shrink: 0; } -.net-chip .int-wrap, .net-chip .ext-wrap { display: inline-flex; align-items: center; gap: 7px; } - -.net-chip .ip-label { - font-size: 0.6rem; - font-weight: 800; - letter-spacing: 0.08em; - color: var(--text-3); - margin-right: 7px; -} - -.net-chip .ip-value { - color: var(--text); - font-weight: 600; - font-family: var(--mono); -} - -.net-separator { - width: 1px; - height: 15px; - background: var(--border-strong); - margin: 0 3px; - flex-shrink: 0; - color: transparent; -} - .top-actions { display: flex; gap: 9px; @@ -106,17 +63,6 @@ order: 5; } -/* Below 1160px the chip wraps to its own full-width topbar row — - it never stacks LAN over WAN and never hides the external IP. */ -@media (max-width: 1160px) { - .topbar { flex-wrap: wrap; row-gap: 10px; } - .net-chip { - order: 6; - flex-basis: 100%; - justify-content: center; - } -} - /* ── Legacy badges (still used inside dialogs) ──────────────────── */ .role-badge { diff --git a/app/sovran_systemsos_web/static/css/layout.css b/app/sovran_systemsos_web/static/css/layout.css index 4e26ab1..6e3596d 100644 --- a/app/sovran_systemsos_web/static/css/layout.css +++ b/app/sovran_systemsos_web/static/css/layout.css @@ -204,30 +204,131 @@ .sidebar-spacer { flex: 1; min-height: 18px; } -.sidebar-footer { - border-top: 1px solid var(--border); - padding-top: 14px; +/* ── Welcome dashboard (default view) ───────────────────────────── */ + +.welcome { + position: relative; + max-width: 1040px; + margin: 0 auto; + padding: 44px 8px 24px; + overflow: hidden; + min-height: 100%; } -.host-note { - text-align: center; - font-size: 0.66rem; +/* Soft drifting glow — calm, GPU-cheap (transforms only) */ +.welcome-bg { + position: absolute; + inset: 0; + pointer-events: none; +} + +.orb { + position: absolute; + border-radius: 50%; + will-change: transform; +} + +.orb-a { + width: 560px; height: 560px; + left: -140px; top: -180px; + background: radial-gradient(circle, rgba(62, 207, 142, 0.10), transparent 70%); + animation: orb-drift-a 26s ease-in-out infinite alternate; +} + +.orb-b { + width: 680px; height: 680px; + right: -200px; top: 20%; + background: radial-gradient(circle, rgba(120, 174, 237, 0.07), transparent 70%); + animation: orb-drift-b 34s ease-in-out infinite alternate; +} + +.orb-c { + width: 460px; height: 460px; + left: 34%; bottom: -200px; + background: radial-gradient(circle, rgba(66, 243, 154, 0.06), transparent 70%); + animation: orb-drift-c 42s ease-in-out infinite alternate; +} + +@keyframes orb-drift-a { to { transform: translate(70px, 50px) scale(1.14); } } +@keyframes orb-drift-b { to { transform: translate(-60px, -70px) scale(1.10); } } +@keyframes orb-drift-c { to { transform: translate(50px, -40px) scale(1.18); } } + +@media (prefers-reduced-motion: reduce) { + .orb { animation: none; } + .welcome-inner { animation: none; } +} + +.welcome-inner { + position: relative; + animation: welcome-in 0.5s ease both; +} + +@keyframes welcome-in { + from { opacity: 0; transform: translateY(14px); } +} + +.welcome-greeting { + font-size: 0.98rem; + font-weight: 650; + color: var(--text-2); +} + +.welcome-title { + margin-top: 6px; + font-size: clamp(1.7rem, 2.8vw, 2.25rem); + font-weight: 800; + letter-spacing: -0.02em; + line-height: 1.18; +} + +.welcome-title em { font-style: normal; color: var(--accent); } + +.welcome-meta { + margin-top: 12px; + font-size: 0.8rem; color: var(--text-3); font-family: var(--mono); - margin-top: 9px; } -/* ── Widgets row (dashboard.js) ─────────────────────────────────── */ +.welcome-meta-sep { margin: 0 8px; opacity: 0.6; } -.widgets { +.welcome-cards { display: grid; - grid-template-columns: 1.1fr 1.45fr; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; - margin-bottom: 32px; + margin-top: 34px; } -@media (max-width: 900px) { - .widgets { grid-template-columns: 1fr; } +/* wrappers whose children become grid items */ +.welcome-dyn { display: contents; } + +.w-network .net-row { + display: flex; + align-items: baseline; + gap: 10px; + margin-top: 6px; + font-family: var(--mono); +} + +.w-network .net-k { + font-size: 0.6rem; + font-weight: 800; + letter-spacing: 0.08em; + color: var(--text-3); + width: 30px; + flex-shrink: 0; +} + +.w-network .ip-value { + font-size: 0.82rem; + font-weight: 600; + color: var(--text); +} + +.w-network .sub { margin-top: 8px; } + +.welcome-browse { + margin-top: 26px; } .widget { @@ -275,6 +376,10 @@ background: linear-gradient(160deg, #f7931a, #b96a0a); } +.widget-chip.chip-amber { + background: linear-gradient(160deg, #b98426, #8a5f16); +} + .widget-chip.chip-sovran { background: linear-gradient(160deg, #42f39a, #1aa45d); } diff --git a/app/sovran_systemsos_web/static/css/modals.css b/app/sovran_systemsos_web/static/css/modals.css index 83f972a..0ec3792 100644 --- a/app/sovran_systemsos_web/static/css/modals.css +++ b/app/sovran_systemsos_web/static/css/modals.css @@ -1505,6 +1505,15 @@ margin-top: 5px; } +.sysprefs { + padding: 0 24px 20px; + border-top: 1px solid var(--border); + margin-top: 16px; + padding-top: 14px; +} + +.sysprefs .autolaunch-section .feature-card { padding: 2px 0 0; } + .sysfineprint { font-size: 0.72rem; color: var(--text-3); diff --git a/app/sovran_systemsos_web/static/js/dashboard.js b/app/sovran_systemsos_web/static/js/dashboard.js index 632ecf2..ad7448d 100644 --- a/app/sovran_systemsos_web/static/js/dashboard.js +++ b/app/sovran_systemsos_web/static/js/dashboard.js @@ -1,23 +1,29 @@ "use strict"; /* ── The Hub dashboard chrome ────────────────────────────────────── - Category navigation, service search, status widgets, and the - Systems Operational modal (router ports 80/443 + the live domain - diagnostics checklist). + Welcome dashboard (default view), category navigation, service + search, status cards, and the Systems Operational modal. - Everything lives in an IIFE so no globals leak into the other - Hub scripts; tiles.js calls window.dashboardServicesUpdated() - whenever the service list refreshes. */ + Everything lives in an IIFE so no globals leak into the other Hub + scripts; tiles.js calls window.dashboardServicesUpdated() whenever + the service list refreshes. */ (function () { var $nav = document.getElementById("sidebar-nav"); var $pageTitle = document.getElementById("page-title"); - var $widgets = document.getElementById("widgets"); var $search = document.getElementById("search-input"); var $sysModal = document.getElementById("systems-modal"); var $sysBody = document.getElementById("systems-body"); + var $welcome = document.getElementById("welcome-view"); + var $tilesArea = document.getElementById("tiles-area"); + var $wcSystems = document.getElementById("wc-systems"); + var $wcMore = document.getElementById("wc-more"); + var $greeting = document.getElementById("welcome-greeting"); + var $welcomeRole = document.getElementById("welcome-role"); + var $browseBtn = document.getElementById("welcome-browse-btn"); + var _view = "dashboard"; // "dashboard" | "services" var _cat = "all"; var _query = ""; @@ -65,7 +71,42 @@ }); } - /* ── Category navigation ─────────────────────────────────────── */ + /* ── Views ────────────────────────────────────────────────────── */ + + function setTitle(t) { + if ($pageTitle) $pageTitle.textContent = t; + } + + function syncNav() { + if (!$nav) return; + $nav.querySelectorAll(".nav-item").forEach(function (b) { + var isActive; + if (b.dataset.cat === "__dash") isActive = (_view === "dashboard"); + else isActive = (_view === "services" && b.dataset.cat === _cat); + b.classList.toggle("active", isActive); + }); + } + + function showDashboard() { + _view = "dashboard"; + _cat = "all"; + if ($welcome) $welcome.style.display = ""; + if ($tilesArea) $tilesArea.style.display = "none"; + setTitle("Dashboard"); + syncNav(); + } + + function showServices(cat) { + _view = "services"; + if (cat) _cat = cat; + if ($welcome) $welcome.style.display = "none"; + if ($tilesArea) $tilesArea.style.display = ""; + setTitle(_cat === "all" ? "All services" : catLabel(_cat)); + syncNav(); + applyFilter(); + } + + /* ── Category navigation ──────────────────────────────────────── */ function renderNav() { if (!$nav) return; @@ -79,7 +120,12 @@ }); var total = visibleServices().length; - var html = ''; + var html = ''; + html += ''; + html += ''; html += navItem("all", "All services", total); order.forEach(function (cat) { html += navItem(cat, catLabel(cat), counts[cat]); @@ -88,20 +134,14 @@ $nav.querySelectorAll(".nav-item").forEach(function (btn) { btn.addEventListener("click", function () { - _cat = btn.dataset.cat; - $nav.querySelectorAll(".nav-item").forEach(function (b) { - b.classList.toggle("active", b === btn); - }); - if ($pageTitle) { - $pageTitle.textContent = _cat === "all" ? "Dashboard" : catLabel(_cat); - } - applyFilter(); + if (btn.dataset.cat === "__dash") showDashboard(); + else showServices(btn.dataset.cat); }); }); } function navItem(cat, label, count) { - return ' @@ -213,10 +205,36 @@
- - + +
+ +
+
Hello
+

Welcome to Your Sovereign Digital & Financial Life

+
Sovran_SystemsOS v{{ sovran_version }}·
+
+
+
+
+
+

Network

+
LAN
+
WAN
+
sovransystemsos.local
+
+
+
+
+ +
+
-
+ +