← back to Lifestyle Asset Intel
yolo tick #2: portfolio nav link + view styling
ea1adfbe3f148f1e11c108b7bd2f276ed98b1018 · 2026-05-09 23:50:44 -0700 · Steve Abrams
Add /portfolio to the hamburger nav (was previously only reachable via
direct URL) and an /api/sources/api/health pair as external-link buttons.
Active-state highlighting works for the indices and portfolio sections,
not just the console root.
Wire CSS for the classes the portfolio.ejs view was already emitting but
that had no rules: pl-pos/pl-neg coloring (good/bad CSS vars), flash
banners (ok/err with color-mix tinting), owner-form + holding-form grid
layouts, inline-remove link button, and a thicker top border on the
table totals row. color-mix in srgb keeps the tints theme-aware in both
light and dark.
21/21 tests still green. /portfolio renders with active nav state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files touched
M public/css/app.cssM views/partials/head.ejs
Diff
commit ea1adfbe3f148f1e11c108b7bd2f276ed98b1018
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat May 9 23:50:44 2026 -0700
yolo tick #2: portfolio nav link + view styling
Add /portfolio to the hamburger nav (was previously only reachable via
direct URL) and an /api/sources/api/health pair as external-link buttons.
Active-state highlighting works for the indices and portfolio sections,
not just the console root.
Wire CSS for the classes the portfolio.ejs view was already emitting but
that had no rules: pl-pos/pl-neg coloring (good/bad CSS vars), flash
banners (ok/err with color-mix tinting), owner-form + holding-form grid
layouts, inline-remove link button, and a thicker top border on the
table totals row. color-mix in srgb keeps the tints theme-aware in both
light and dark.
21/21 tests still green. /portfolio renders with active nav state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
public/css/app.css | 35 +++++++++++++++++++++++++++++++++++
views/partials/head.ejs | 8 ++++----
2 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/public/css/app.css b/public/css/app.css
index e2d4084..58d5a80 100644
--- a/public/css/app.css
+++ b/public/css/app.css
@@ -137,3 +137,38 @@ pre.json { background: var(--card); border: 1px solid var(--line); border-radius
/* sparkline + trend section (v0.2) */
.spark { color: var(--accent); }
.trend { margin: 1.4rem 0; }
+
+/* portfolio page (v0.2) */
+.pl-pos { color: var(--good); font-weight: 600; }
+.pl-neg { color: var(--bad); font-weight: 600; }
+
+.flash { padding: 0.55rem 0.8rem; border-radius: 8px; margin: 0.8rem 0; font-size: 0.92em; }
+.flash.ok { background: color-mix(in srgb, var(--good) 12%, var(--card)); color: var(--good); border: 1px solid color-mix(in srgb, var(--good) 35%, var(--line)); }
+.flash.err { background: color-mix(in srgb, var(--bad) 12%, var(--card)); color: var(--bad); border: 1px solid color-mix(in srgb, var(--bad) 35%, var(--line)); }
+
+.owner-form, .holding-form {
+ display: grid; gap: 0.55rem; max-width: 520px; margin: 0.6rem 0 1.4rem;
+ padding: 0.9rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--card);
+}
+.owner-form input, .holding-form input, .holding-form textarea {
+ font: inherit; padding: 0.45rem 0.6rem; border: 1px solid var(--line);
+ border-radius: 6px; background: var(--bg); color: var(--fg); width: 100%;
+}
+.owner-form button, .holding-form button {
+ justify-self: start; padding: 0.5rem 0.9rem; border: 1px solid var(--accent); background: var(--accent);
+ color: var(--accent-fg); border-radius: 6px; font: inherit; font-weight: 600; cursor: pointer;
+}
+.holding-form .row { display: flex; flex-direction: column; gap: 0.25rem; }
+.holding-form label { font-size: 0.75em; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
+
+.inline-remove { display: inline; }
+.inline-remove .link-btn {
+ background: none; border: none; color: var(--muted); padding: 0; cursor: pointer;
+ font: inherit; font-size: 0.85em; text-decoration: underline;
+}
+.inline-remove .link-btn:hover { color: var(--bad); }
+
+tfoot tr.totals th, tfoot tr.totals td {
+ border-top: 2px solid var(--line); border-bottom: none; padding-top: 0.6rem;
+ font-weight: 600; color: var(--fg);
+}
diff --git a/views/partials/head.ejs b/views/partials/head.ejs
index 51acdfd..8ac4fac 100644
--- a/views/partials/head.ejs
+++ b/views/partials/head.ejs
@@ -20,10 +20,10 @@
<a class="brand" href="/">LAI <span class="brand-sub">Lifestyle Asset Intel</span></a>
<nav class="topnav" id="topnav">
<a href="/" class="<%= path === '/' ? 'active' : '' %>">Console</a>
- <a href="/indices/birkin-30-togo-neutral">Indices</a>
- <a href="/api/sources" target="_blank">Sources</a>
- <a href="/api/portfolio?owner=demo@example.com" target="_blank">Portfolio</a>
- <a href="/api/health" target="_blank">API</a>
+ <a href="/indices/birkin-30-togo-neutral" class="<%= path && path.indexOf('/indices') === 0 ? 'active' : '' %>">Indices</a>
+ <a href="/portfolio" class="<%= path && path.indexOf('/portfolio') === 0 ? 'active' : '' %>">Portfolio</a>
+ <a href="/api/sources" target="_blank" rel="noopener">Sources</a>
+ <a href="/api/health" target="_blank" rel="noopener">API</a>
</nav>
<button class="theme-toggle" id="themeToggle" aria-label="Toggle dark mode" title="Toggle dark mode">
<svg class="icon-sun" viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
← 1d24570 yolo tick #1: enforce transactions natural-key + seed idempo
·
back to Lifestyle Asset Intel
·
yolo tick #3: live liquidity_score + expected_dts (no more c 9b63e84 →