visuals: frosted-glass terminal/msgflow, row fade-in, badge pulses
agent terminal-wrap + dashboard msgflow get a translucent bg with backdrop-filter blur+saturate so page-bg glow softens behind them. new rows in the live panel and the dashboard message flow fade in with a 4px slide-up. unread badge pulses; pending-operator-questions section pulses its glow. history-backfilled rows skip the animation (.no-anim) so the page doesn't stagger 100 fade-ins on load.
This commit is contained in:
parent
3f2aba4adc
commit
fd39226883
3 changed files with 49 additions and 5 deletions
|
|
@ -125,9 +125,14 @@ pre.diff {
|
||||||
max-height: 30em;
|
max-height: 30em;
|
||||||
}
|
}
|
||||||
/* Terminal-ish wrapper holding the live output + prompt input as one
|
/* Terminal-ish wrapper holding the live output + prompt input as one
|
||||||
unit. Crust as bg (almost-black), slightly inset, mauve phosphor glow. */
|
unit. Crust as bg (almost-black), slightly inset, mauve phosphor glow.
|
||||||
|
Frosted-glass backdrop blur: the page bg behind the wrap gets softened,
|
||||||
|
so anything that bleeds through (page banner glow, scroll position)
|
||||||
|
reads as out-of-focus depth instead of sharp competing detail. */
|
||||||
.terminal-wrap {
|
.terminal-wrap {
|
||||||
background: #11111b;
|
background: rgba(17, 17, 27, 0.78);
|
||||||
|
-webkit-backdrop-filter: blur(8px) saturate(120%);
|
||||||
|
backdrop-filter: blur(8px) saturate(120%);
|
||||||
border: 1px solid var(--purple-dim);
|
border: 1px solid var(--purple-dim);
|
||||||
box-shadow: inset 0 0 24px rgba(0, 0, 0, 0.7);
|
box-shadow: inset 0 0 24px rgba(0, 0, 0, 0.7);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
@ -191,6 +196,26 @@ pre.diff {
|
||||||
margin-left: 0.6em;
|
margin-left: 0.6em;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
text-shadow: 0 0 6px rgba(250, 179, 135, 0.55);
|
text-shadow: 0 0 6px rgba(250, 179, 135, 0.55);
|
||||||
|
animation: badge-pulse 1.4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
@keyframes badge-pulse {
|
||||||
|
0%, 100% { opacity: 1; text-shadow: 0 0 6px rgba(250, 179, 135, 0.55); }
|
||||||
|
50% { opacity: 0.7; text-shadow: 0 0 14px rgba(250, 179, 135, 0.95); }
|
||||||
|
}
|
||||||
|
/* Per-event fade-in slide-up. Applied to every row the live panel
|
||||||
|
appends; the `.no-anim` modifier lets history-backfill skip the
|
||||||
|
animation (we don't want 100 rows fading in at once on page load). */
|
||||||
|
.live .row,
|
||||||
|
.live details.row {
|
||||||
|
animation: row-fade-in 220ms ease-out both;
|
||||||
|
}
|
||||||
|
.live .row.no-anim,
|
||||||
|
.live details.row.no-anim {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
@keyframes row-fade-in {
|
||||||
|
from { opacity: 0; transform: translateY(4px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
}
|
}
|
||||||
details.row {
|
details.row {
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
|
|
|
||||||
|
|
@ -250,10 +250,13 @@
|
||||||
function clearPlaceholder() {
|
function clearPlaceholder() {
|
||||||
if (placeholder) { log.innerHTML = ''; placeholder = null; }
|
if (placeholder) { log.innerHTML = ''; placeholder = null; }
|
||||||
}
|
}
|
||||||
|
// Backfill replays mark rows .no-anim so we don't stagger 100 fade-ins
|
||||||
|
// on page load. Set via `currentNoAnim` before the row helpers fire.
|
||||||
|
let currentNoAnim = false;
|
||||||
function row(cls, text) {
|
function row(cls, text) {
|
||||||
clearPlaceholder();
|
clearPlaceholder();
|
||||||
const e = document.createElement('div');
|
const e = document.createElement('div');
|
||||||
e.className = 'row ' + (cls || '');
|
e.className = 'row ' + (cls || '') + (currentNoAnim ? ' no-anim' : '');
|
||||||
e.textContent = text;
|
e.textContent = text;
|
||||||
log.appendChild(e);
|
log.appendChild(e);
|
||||||
log.scrollTop = log.scrollHeight;
|
log.scrollTop = log.scrollHeight;
|
||||||
|
|
@ -262,7 +265,7 @@
|
||||||
function details(cls, summary, body) {
|
function details(cls, summary, body) {
|
||||||
clearPlaceholder();
|
clearPlaceholder();
|
||||||
const d = document.createElement('details');
|
const d = document.createElement('details');
|
||||||
d.className = 'row ' + (cls || '');
|
d.className = 'row ' + (cls || '') + (currentNoAnim ? ' no-anim' : '');
|
||||||
const s = document.createElement('summary');
|
const s = document.createElement('summary');
|
||||||
s.textContent = summary;
|
s.textContent = summary;
|
||||||
d.appendChild(s);
|
d.appendChild(s);
|
||||||
|
|
@ -394,11 +397,13 @@
|
||||||
if (!resp.ok) return;
|
if (!resp.ok) return;
|
||||||
const events = await resp.json();
|
const events = await resp.json();
|
||||||
let openTurns = 0;
|
let openTurns = 0;
|
||||||
|
currentNoAnim = true;
|
||||||
for (const ev of events) {
|
for (const ev of events) {
|
||||||
handle(ev, { fromHistory: true });
|
handle(ev, { fromHistory: true });
|
||||||
if (ev.kind === 'turn_start') openTurns += 1;
|
if (ev.kind === 'turn_start') openTurns += 1;
|
||||||
else if (ev.kind === 'turn_end') openTurns = Math.max(0, openTurns - 1);
|
else if (ev.kind === 'turn_end') openTurns = Math.max(0, openTurns - 1);
|
||||||
}
|
}
|
||||||
|
currentNoAnim = false;
|
||||||
for (let i = 0; i < openTurns; i++) setBannerActive(true);
|
for (let i = 0; i < openTurns; i++) setBannerActive(true);
|
||||||
if (events.length) row('note', '─── live (older above) ───');
|
if (events.length) row('note', '─── live (older above) ───');
|
||||||
else setPlaceholder('(connected — waiting for events)');
|
else setPlaceholder('(connected — waiting for events)');
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,11 @@ summary:hover { color: var(--purple); }
|
||||||
border: 1px solid var(--amber);
|
border: 1px solid var(--amber);
|
||||||
box-shadow: 0 0 12px -4px var(--amber);
|
box-shadow: 0 0 12px -4px var(--amber);
|
||||||
padding: 0.6em 0.9em;
|
padding: 0.6em 0.9em;
|
||||||
|
animation: questions-pulse 2.4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
@keyframes questions-pulse {
|
||||||
|
0%, 100% { box-shadow: 0 0 12px -4px rgba(250, 179, 135, 0.55); }
|
||||||
|
50% { box-shadow: 0 0 22px -2px rgba(250, 179, 135, 0.95); }
|
||||||
}
|
}
|
||||||
.questions li.question {
|
.questions li.question {
|
||||||
padding: 0.4em 0;
|
padding: 0.4em 0;
|
||||||
|
|
@ -261,7 +266,9 @@ summary:hover { color: var(--purple); }
|
||||||
.inbox .msg-sep { color: var(--muted); }
|
.inbox .msg-sep { color: var(--muted); }
|
||||||
.inbox .msg-body { color: var(--fg); white-space: pre-wrap; word-break: break-word; }
|
.inbox .msg-body { color: var(--fg); white-space: pre-wrap; word-break: break-word; }
|
||||||
.msgflow {
|
.msgflow {
|
||||||
background: var(--bg-elev);
|
background: rgba(24, 24, 37, 0.78);
|
||||||
|
-webkit-backdrop-filter: blur(8px) saturate(120%);
|
||||||
|
backdrop-filter: blur(8px) saturate(120%);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
padding: 0.8em;
|
padding: 0.8em;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
|
|
@ -269,6 +276,13 @@ summary:hover { color: var(--purple); }
|
||||||
max-height: 32em;
|
max-height: 32em;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
.msgflow .msgrow {
|
||||||
|
animation: row-fade-in 220ms ease-out both;
|
||||||
|
}
|
||||||
|
@keyframes row-fade-in {
|
||||||
|
from { opacity: 0; transform: translateY(4px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
.msgrow { display: grid; grid-template-columns: auto auto auto auto auto 1fr; gap: 0.6em; align-items: baseline; padding: 0.1em 0; }
|
.msgrow { display: grid; grid-template-columns: auto auto auto auto auto 1fr; gap: 0.6em; align-items: baseline; padding: 0.1em 0; }
|
||||||
.msgrow.sent .msg-arrow { color: var(--cyan); }
|
.msgrow.sent .msg-arrow { color: var(--cyan); }
|
||||||
.msgrow.delivered .msg-arrow { color: var(--green); }
|
.msgrow.delivered .msg-arrow { color: var(--green); }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue