diff --git a/README.md b/README.md index e286f2d..46dc575 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,19 @@ Network monitoring dashboard for the LotusGuild Proxmox cluster. Deployed on **LXC 157** (monitor-02 / 10.10.10.9), reachable at `gandalf.lotusguild.org`. +**Design System**: [web_template](https://code.lotusguild.org/LotusGuild/web_template) — shared CSS, JS, and layout patterns for all LotusGuild apps + +## Styling & Layout + +GANDALF uses the **LotusGuild Terminal Design System**. For all styling, component, and layout documentation see: + +- [`web_template/README.md`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/README.md) — full component reference, CSS variables, JS API +- [`web_template/base.css`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/base.css) — unified CSS (`.lt-*` classes) +- [`web_template/base.js`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/base.js) — `window.lt` utilities (toast, modal, auto-refresh, fetch helpers) +- [`web_template/aesthetic_diff.md`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/aesthetic_diff.md) — cross-app divergence analysis and convergence guide +- [`web_template/python/base.html`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/python/base.html) — Jinja2 base template +- [`web_template/python/auth.py`](https://code.lotusguild.org/LotusGuild/web_template/src/branch/main/python/auth.py) — `@require_auth` decorator pattern + --- ## Architecture diff --git a/static/app.js b/static/app.js index a91f389..42706e0 100644 --- a/static/app.js +++ b/static/app.js @@ -1,18 +1,11 @@ 'use strict'; -// ── Toast notifications ─────────────────────────────────────────────── +// ── Toast notifications — delegates to lt.toast from base.js ───────── function showToast(msg, type = 'success') { - let container = document.querySelector('.toast-container'); - if (!container) { - container = document.createElement('div'); - container.className = 'toast-container'; - document.body.appendChild(container); - } - const toast = document.createElement('div'); - toast.className = `toast toast-${type}`; - toast.textContent = msg; - container.appendChild(toast); - setTimeout(() => toast.remove(), 3500); + if (type === 'error') return lt.toast.error(msg); + if (type === 'warning') return lt.toast.warning(msg); + if (type === 'info') return lt.toast.info(msg); + return lt.toast.success(msg); } // ── Dashboard auto-refresh ──────────────────────────────────────────── diff --git a/static/base.css b/static/base.css new file mode 120000 index 0000000..f5d1c39 --- /dev/null +++ b/static/base.css @@ -0,0 +1 @@ +/root/code/web_template/base.css \ No newline at end of file diff --git a/static/base.js b/static/base.js new file mode 120000 index 0000000..1d09a6a --- /dev/null +++ b/static/base.js @@ -0,0 +1 @@ +/root/code/web_template/base.js \ No newline at end of file diff --git a/static/style.css b/static/style.css index 4b9c9db..a45fae1 100644 --- a/static/style.css +++ b/static/style.css @@ -35,11 +35,27 @@ --font: 'Courier New','Consolas','Monaco','Menlo',monospace; - --glow: 0 0 5px #00ff41, 0 0 10px rgba(0,255,65,.4); - --glow-xl: 0 0 8px #00ff41, 0 0 20px rgba(0,255,65,.35); - --glow-amber: 0 0 5px #ffb000, 0 0 10px rgba(255,176,0,.4); + --glow: 0 0 5px #00ff41, 0 0 10px #00ff41, 0 0 15px #00ff41; + --glow-xl: 0 0 8px #00ff41, 0 0 16px #00ff41, 0 0 24px #00ff41, 0 0 32px rgba(0,255,65,.5); + --glow-amber: 0 0 5px #ffb000, 0 0 10px #ffb000, 0 0 15px #ffb000; --glow-red: 0 0 5px #ff4444, 0 0 10px rgba(255,68,68,.4); --glow-cyan: 0 0 5px #00ffff, 0 0 10px rgba(0,255,255,.35); + + /* Unified naming aliases — matches base.css variable names */ + --bg-primary: var(--bg); + --bg-secondary: var(--bg2); + --bg-tertiary: var(--bg3); + --terminal-green: var(--green); + --terminal-green-dim: var(--green-dim); + --terminal-amber: var(--amber); + --terminal-amber-dim: var(--amber-dim); + --terminal-cyan: var(--cyan); + --terminal-red: var(--red); + --text-primary: var(--text); + --text-secondary: var(--text-dim); + --border-color: var(--border); + --glow-green: var(--glow); + --font-mono: var(--font); } /* ── Reset ────────────────────────────────────────────────────────── */ @@ -60,7 +76,7 @@ body { line-height: 1.5; min-height: 100vh; position: relative; - animation: flicker .25s ease-in-out 45s infinite; + animation: flicker .25s ease-in-out 30s infinite; } /* CRT scanline overlay */ @@ -70,7 +86,7 @@ body::before { inset: 0; background: repeating-linear-gradient( 0deg, - rgba(0,0,0,.13) 0px, rgba(0,0,0,.13) 1px, + rgba(0,0,0,0.15) 0px, rgba(0,0,0,0.15) 1px, transparent 1px, transparent 2px ); pointer-events: none; @@ -157,13 +173,20 @@ a:hover { text-decoration: underline; text-shadow: var(--glow-amber); } } .nav-link::before { content:'[ '; } .nav-link::after { content:' ]'; } -.nav-link:hover, .nav-link.active { +.nav-link:hover { color: var(--green); border-color: var(--border); background: var(--green-dim); text-shadow: var(--glow); text-decoration: none; } +.nav-link.active { + color: var(--amber); + border-color: var(--amber); + background: var(--amber-dim); + text-shadow: var(--glow-amber); + text-decoration: none; +} .header-right { display:flex; align-items:center; gap:10px; } .header-user { font-size: .78em; color: var(--text-muted); } @@ -193,7 +216,8 @@ a:hover { text-decoration: underline; text-shadow: var(--glow-amber); } text-transform: uppercase; letter-spacing: .1em; } -.section-title::before { content:'╠══ '; color:var(--green); text-shadow:var(--glow); } +.section-title::before { content:'╠═══ '; color:var(--green); text-shadow:var(--glow); } +.section-title::after { content:' ═══╣'; color:var(--green); text-shadow:var(--glow); } .section-badge { font-size: .72em; @@ -478,8 +502,8 @@ a:hover { text-decoration: underline; text-shadow: var(--glow-amber); } display: inline-flex; align-items: center; gap: 5px; - padding: 6px 14px; - border: 1px solid; + padding: 5px 12px; + border: 2px solid; cursor: pointer; font-family: var(--font); font-size: .8em; @@ -489,10 +513,13 @@ a:hover { text-decoration: underline; text-shadow: var(--glow-amber); } background: transparent; transition: all .15s; } -.btn:hover { transform: translateY(-1px); } +.btn::before { content: '[ '; } +.btn::after { content: ' ]'; } +.btn:hover { transform: translateY(-2px); } .btn-primary { color:var(--green); border-color:var(--green); text-shadow:var(--glow); } .btn-primary::before { content:'> '; color:var(--amber); } +.btn-primary::after { content:''; } .btn-primary:hover { background:var(--green-dim); box-shadow:var(--glow); } .btn-secondary { color:var(--text-dim); border-color:var(--border); } @@ -508,7 +535,7 @@ a:hover { text-decoration: underline; text-shadow: var(--glow-amber); } font-family: var(--font); font-size: .7em; font-weight: bold; - border: 1px solid; + border: 2px solid; cursor: pointer; background: transparent; letter-spacing: .04em; @@ -531,15 +558,15 @@ a:hover { text-decoration: underline; text-shadow: var(--glow-amber); } } .modal { background: var(--bg2); - border: 1px solid var(--green); - box-shadow: 0 0 30px rgba(0,255,65,.18); + border: 3px double var(--green); + box-shadow: 0 0 30px rgba(0,255,65,.2), 0 8px 40px rgba(0,0,0,.8); width: 480px; max-width: 95vw; padding: 20px; position: relative; } -.modal::before { content:'┌'; position:absolute; top:-1px; left:-1px; color:var(--green); text-shadow:var(--glow); font-size:.9rem; line-height:1; } -.modal::after { content:'┐'; position:absolute; top:-1px; right:-1px; color:var(--green); text-shadow:var(--glow); font-size:.9rem; line-height:1; } +.modal::before { content:'╔'; position:absolute; top:-1px; left:-1px; color:var(--green); text-shadow:var(--glow); font-size:.9rem; line-height:1; } +.modal::after { content:'╗'; position:absolute; top:-1px; right:-1px; color:var(--green); text-shadow:var(--glow); font-size:.9rem; line-height:1; } .modal-header { display: flex; @@ -600,7 +627,7 @@ a:hover { text-decoration: underline; text-shadow: var(--glow-amber); } .form-group input, .form-group select { padding: 6px 9px; - border: 1px solid var(--border); + border: 2px solid var(--border); font-family: var(--font); font-size: .8em; background: var(--bg3); diff --git a/templates/base.html b/templates/base.html index 7397bdd..61a27fd 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,9 +4,13 @@