frontend: extract themed dialogs + async-form handler to shared, wire agent UI
The dashboard has a themed modal/dialog system (modal.js: themedToast/ themedConfirm/themedPrompt) and a data-async form submit interceptor (bindAsyncForms) that every dashboard action routes through. The per-agent UI never adopted either — it had its own more primitive data-async handler using native window.confirm()/alert() (8 call sites) and a duplicated el() DOM helper. - Moved el() out of dashboard/common.js into shared/src/dom.js. - Moved modal.js + modal.css from dashboard/src/ to shared/src/, updating its internal el import. - Moved bindAsyncForms from dashboard/common.js into shared/forms.js, alongside the asyncBtn primitive it's built on. - Updated every dashboard file's imports to the new shared locations (no re-export shims). - agent.css now @imports shared/modal.css so the dialogs render themed there too. - agent/app.js: dropped its local el()/data-async duplicate, wired bindAsyncForms(), and replaced all 8 window.confirm() sites with themedConfirm (async, wrapped in a fire-and-forget IIFE where the call site needs a synchronous boolean return, e.g. the slash-command dispatcher). Closes hyperhive#2791. Verified with a full frontend build (npm run build) — both dashboard and agent bundles compile clean and agent.css picks up the .tc-* dialog styles it previously lacked.
This commit is contained in:
parent
a1263a9ed6
commit
7110a25cf6
19 changed files with 206 additions and 193 deletions
|
|
@ -1,111 +0,0 @@
|
|||
/* modal.css — themed dialog component styles.
|
||||
Pairs with modal.js (themedConfirm / themedPrompt / themedToast). The
|
||||
dialogs are raised from common.js's data-async / data-confirm handler,
|
||||
which every page loads, so common.css @imports this to keep the styles
|
||||
present wherever a dialog can fire — not just the main dashboard.
|
||||
(Previously these rules lived in dashboard.css, so dialogs rendered
|
||||
unstyled on standalone pages such as /core.) */
|
||||
|
||||
.tc-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1em;
|
||||
background: color-mix(in srgb, var(--crust) 60%, transparent);
|
||||
-webkit-backdrop-filter: blur(2px);
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
.tc-box {
|
||||
background: var(--bg-elev);
|
||||
border: 1px solid var(--purple-dim);
|
||||
box-shadow: 0 8px 40px -8px var(--crust);
|
||||
padding: 1.2em 1.4em;
|
||||
max-width: min(32em, 92vw);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.9em;
|
||||
}
|
||||
.tc-title {
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--subtext0);
|
||||
}
|
||||
.tc-message { color: var(--fg); line-height: 1.45; }
|
||||
.tc-checks { display: flex; flex-direction: column; gap: 0.4em; }
|
||||
.tc-checkrow {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.5em;
|
||||
cursor: pointer;
|
||||
color: var(--subtext0);
|
||||
font-size: 0.92em;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.tc-checkrow .tc-check { margin-top: 0.2em; flex: 0 0 auto; }
|
||||
.tc-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.6em;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
.tc-cancel { color: var(--subtext0); }
|
||||
.tc-confirm { color: var(--green); }
|
||||
.tc-confirm.tc-danger { color: var(--red); }
|
||||
|
||||
/* themedPrompt input field */
|
||||
.tc-promptfield { display: flex; flex-direction: column; gap: 0.4em; }
|
||||
.tc-promptlabel { color: var(--subtext0); font-size: 0.9em; }
|
||||
.tc-input {
|
||||
font-family: inherit;
|
||||
font-size: 1em;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: var(--crust);
|
||||
color: var(--fg);
|
||||
border: 1px solid var(--purple-dim);
|
||||
padding: 0.4em 0.6em;
|
||||
}
|
||||
.tc-input:focus { outline: 1px solid var(--green); }
|
||||
/* themedPrompt's field is always a resizable textarea (Enter submits,
|
||||
Shift+Enter inserts a newline) — sensible min-height, wrapped output. */
|
||||
.tc-textarea {
|
||||
resize: vertical;
|
||||
min-height: 4.5em;
|
||||
line-height: 1.4;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* themedToast — non-blocking transient notifications (errors/info/ok) */
|
||||
.tc-toasts {
|
||||
position: fixed;
|
||||
top: 1em;
|
||||
right: 1em;
|
||||
z-index: 1100;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5em;
|
||||
max-width: min(28em, 92vw);
|
||||
pointer-events: none;
|
||||
}
|
||||
.tc-toast {
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
background: var(--bg-elev);
|
||||
border: 1px solid var(--purple-dim);
|
||||
border-left-width: 3px;
|
||||
box-shadow: 0 4px 20px -6px var(--crust);
|
||||
padding: 0.6em 0.9em;
|
||||
font-size: 0.9em;
|
||||
color: var(--fg);
|
||||
white-space: pre-wrap;
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
.tc-toast-out { opacity: 0; transform: translateX(0.5em); }
|
||||
.tc-toast-error { border-left-color: var(--red); }
|
||||
.tc-toast-info { border-left-color: var(--purple-dim); }
|
||||
.tc-toast-ok { border-left-color: var(--green); }
|
||||
Loading…
Reference in a new issue