Redesign dashboard: refined-minimal layout with product thumbnails
Move the dashboard from boxed glass cards to an airy, hairline-separated layout where type and whitespace carry the page, then surface listing images as the visual anchor. - Solid surfaces (drop backdrop-filter glass, per spec); calm flat field with a single cool top-glow replacing the drifting aurora and dot-grid. - Recent results / recent alerts are now product feeds with 52px thumbnails, listing titles, and price; image_url threaded through ResultRow/AlertRow (data already stored, just unsurfaced). - ListResults gains an OnlyAlerted filter so the alerts panel reuses its decryption path instead of a raw query. - Dashboard recent results capped at 8 for a balanced snapshot.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
/* Veola — Sega-blue palette and component overrides for Tailwind play CDN. */
|
||||
|
||||
:root {
|
||||
--bg: #1a2b6d;
|
||||
--surface: #1f3380;
|
||||
--surface-2: #243a93;
|
||||
--bg: #16224f;
|
||||
--surface: #243a93;
|
||||
--surface-2: #2c47ad;
|
||||
--accent: #00a4e4;
|
||||
--yellow: #f5c400;
|
||||
--text: #ffffff;
|
||||
@@ -25,59 +25,175 @@ html, body {
|
||||
a { color: var(--accent); }
|
||||
a:hover { text-decoration: underline; }
|
||||
|
||||
/* Solid surfaces, per the spec's "blue mode": no glassmorphism, no blur. A
|
||||
clear value gap between --bg and --surface is what lifts cards off the
|
||||
page; a 1px top highlight + soft blue shadow gives the cartridge edge. */
|
||||
.v-card {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(36, 58, 147, 0.82), rgba(31, 51, 128, 0.82));
|
||||
backdrop-filter: blur(10px) saturate(140%);
|
||||
-webkit-backdrop-filter: blur(10px) saturate(140%);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
box-shadow: var(--shadow);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 40, 0.25);
|
||||
transition:
|
||||
transform 180ms ease,
|
||||
box-shadow 180ms ease,
|
||||
border-color 180ms ease;
|
||||
}
|
||||
.v-card::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
padding: 1px;
|
||||
background: linear-gradient(135deg,
|
||||
rgba(0, 164, 228, 0.65) 0%,
|
||||
rgba(245, 196, 0, 0.30) 45%,
|
||||
rgba(255, 255, 255, 0.04) 100%);
|
||||
-webkit-mask:
|
||||
linear-gradient(#000 0 0) content-box,
|
||||
linear-gradient(#000 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
.v-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow:
|
||||
0 10px 28px rgba(0, 0, 80, 0.55),
|
||||
0 0 0 1px rgba(0, 164, 228, 0.30);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 40, 0.3);
|
||||
}
|
||||
|
||||
.v-card-flat {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(36, 58, 147, 0.70), rgba(31, 51, 128, 0.70));
|
||||
backdrop-filter: blur(8px) saturate(130%);
|
||||
-webkit-backdrop-filter: blur(8px) saturate(130%);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.v-divider { border-top: 1px solid var(--border); }
|
||||
|
||||
/* --- Console readout / page header system -------------------------------
|
||||
The dashboard's signature: a mono "terminal" kicker over a heavy display
|
||||
title, and the Spend/Saved pair styled as an arcade scoreboard readout.
|
||||
JetBrains Mono is the machine voice here (labels, counts); Outfit carries
|
||||
the title. */
|
||||
|
||||
.v-kicker {
|
||||
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.22em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent);
|
||||
}
|
||||
.v-kicker .v-kicker-sep { color: var(--text-2); opacity: 0.6; }
|
||||
.v-kicker .v-kicker-dim { color: var(--text-2); }
|
||||
|
||||
/* --- Refined header + metric system -------------------------------------
|
||||
Calm and spacious: type and whitespace carry the page. No glow, no
|
||||
uppercase-mono labels, no accent rules. Mono is reserved for the numbers
|
||||
themselves; Outfit carries everything else. */
|
||||
|
||||
.v-page-title {
|
||||
font-family: 'Outfit', system-ui, sans-serif;
|
||||
font-size: 1.9rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.015em;
|
||||
line-height: 1.1;
|
||||
text-shadow: none;
|
||||
}
|
||||
.v-page-sub {
|
||||
color: var(--text-2);
|
||||
font-size: 0.95rem;
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
/* Hero metric: a small quiet label over a large clean number. Presented in
|
||||
open space with a hairline, not a boxed card. */
|
||||
.v-metric-label {
|
||||
color: var(--text-2);
|
||||
font-size: 0.82rem;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
.v-metric-value {
|
||||
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
||||
font-size: clamp(2rem, 3.8vw, 2.75rem);
|
||||
font-weight: 600;
|
||||
line-height: 1.05;
|
||||
margin-top: 0.45rem;
|
||||
}
|
||||
.v-metric-value.v-price-deal { color: var(--success); }
|
||||
.v-metric-sub {
|
||||
color: var(--text-2);
|
||||
font-size: 0.82rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
/* Secondary stat: smaller label/number pair for the supporting counts. */
|
||||
.v-stat-label {
|
||||
color: var(--text-2);
|
||||
font-size: 0.78rem;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
.v-stat-value {
|
||||
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
/* Understated section heading for list panels — sized to sit below the page
|
||||
title, sentence case, no glow. */
|
||||
.v-section-title {
|
||||
font-family: 'Outfit', system-ui, sans-serif;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0;
|
||||
color: var(--text);
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
/* Hairline used to separate open sections instead of boxing them. */
|
||||
.v-rule {
|
||||
border: 0;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
/* Quiet empty-state line. */
|
||||
.v-empty {
|
||||
color: var(--text-2);
|
||||
font-size: 0.9rem;
|
||||
padding: 0.4rem 0;
|
||||
}
|
||||
|
||||
/* --- Product feed (thumbnails) ------------------------------------------
|
||||
Listing thumbnails are what give the data life. A square cropped image,
|
||||
the listing title as the line that earns its space, price on the right. */
|
||||
.v-thumb {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
flex: none;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
background: var(--surface-2);
|
||||
border: 1px solid var(--border);
|
||||
display: block;
|
||||
}
|
||||
.v-thumb-empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-2);
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.v-feed { display: block; }
|
||||
.v-feed-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.85rem;
|
||||
padding: 0.7rem 0;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
.v-feed-row:last-child { border-bottom: 0; }
|
||||
.v-feed-name {
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
color: var(--text);
|
||||
}
|
||||
a.v-feed-name:hover { color: var(--accent); text-decoration: none; }
|
||||
.v-feed-meta {
|
||||
color: var(--text-2);
|
||||
font-size: 0.8rem;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
.v-feed-price { flex: none; white-space: nowrap; }
|
||||
|
||||
.v-btn {
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
@@ -212,21 +328,22 @@ a:hover { text-decoration: underline; }
|
||||
table.v-table { width: 100%; border-collapse: collapse; }
|
||||
table.v-table th {
|
||||
text-align: left;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.74rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.01em;
|
||||
color: var(--text-2);
|
||||
padding: 0.6rem 0.75rem;
|
||||
padding: 0.5rem 0.75rem 0.7rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
table.v-table td {
|
||||
padding: 0.7rem 0.75rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* No zebra — hairline rows and a faint hover keep it calm but scannable. */
|
||||
table.v-table td { transition: background 140ms ease; }
|
||||
table.v-table tr { transition: transform 140ms ease; }
|
||||
table.v-table tbody tr:hover td { background: rgba(0, 164, 228, 0.08); }
|
||||
table.v-table tbody tr:last-child td { border-bottom: 0; }
|
||||
table.v-table tbody tr:hover td { background: rgba(255, 255, 255, 0.04); }
|
||||
|
||||
.v-error-text { color: var(--danger); font-size: 0.85rem; }
|
||||
.v-muted { color: var(--text-2); }
|
||||
|
||||
Reference in New Issue
Block a user