feat(rag): global tuning manager — /tuning.html + PUT /api/steering/{id}: create, edit, list, delete steering notes without a chat
This commit is contained in:
@@ -714,6 +714,194 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
.steering-delete:disabled { opacity: 0.5; cursor: wait; }
|
||||
.steering-empty { margin: 0.65rem 0 0; color: var(--ink-soft); font-size: 0.88rem; }
|
||||
|
||||
/* ---------- Global tuning page (phase 27) ---------- */
|
||||
/* /tuning.html: create / edit / delete steering notes without a chat
|
||||
conversation. Same width discipline as the chat column — a centered,
|
||||
capped column on the 72rem frame; the form and the note list span its
|
||||
FULL width (no skinny lists). Every interactive target is >=44px;
|
||||
text pairs reuse the Phase-08 AA palette (dark ink on brand 5.2:1,
|
||||
brand-ink/brand-soft 6.9:1, ok 10.6:1, err 9.1:1, ink-soft >=6.9:1).
|
||||
No filter: blur, no CDN, system font stack. */
|
||||
.tuning-shell {
|
||||
max-width: 46rem;
|
||||
margin-inline: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.25rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Create form — the composer's surface as a vertical card: labeled
|
||||
textarea (visually-hidden label; the placeholder carries the visible
|
||||
hint) + the brand "Add note" button (dark ink on brand: 5.2:1 —
|
||||
never white on brand, 3.7:1, fails). */
|
||||
#tune-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.6rem;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
padding: 0.9rem 1rem 1rem;
|
||||
}
|
||||
#tune-form:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft), var(--shadow); }
|
||||
#tune-note {
|
||||
width: 100%;
|
||||
font: inherit;
|
||||
font-size: 0.95rem;
|
||||
color: var(--ink);
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0.2rem 0.1rem;
|
||||
resize: vertical;
|
||||
min-height: 4.6rem;
|
||||
}
|
||||
#tune-note::placeholder { color: var(--ink-soft); }
|
||||
#tune-save {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 44px;
|
||||
padding: 0.4rem 1.2rem;
|
||||
border: 0;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--brand);
|
||||
color: var(--bg); /* dark ink on brand: 5.2:1 */
|
||||
font: inherit;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
#tune-save:hover:not(:disabled) { background: #7d88f5; }
|
||||
#tune-save:disabled { opacity: 0.6; cursor: wait; }
|
||||
|
||||
/* Notes list — the phase-15 steering panel's language at full column
|
||||
width: rows are flex (text flexes + ellipsizes, actions shrink-0)
|
||||
with a bottom divider (the last row keeps none). */
|
||||
.tuning-panel {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--brand-soft);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
padding: 0.9rem 1.1rem 1rem;
|
||||
}
|
||||
.tuning-panel-title { margin: 0; font-size: 1rem; font-weight: 700; color: var(--ink); }
|
||||
.tuning-list {
|
||||
list-style: none;
|
||||
margin: 0.65rem 0 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.tuning-note {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
padding: 0.35rem 0;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.tuning-note:last-child { border-bottom: 0; }
|
||||
/* The note text is the row's flex citizen: it takes every spare pixel
|
||||
and ellipsizes (the full text is one Edit away — the inline form). */
|
||||
.tuning-note-text {
|
||||
color: var(--ink);
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.45;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
/* Row actions: icon + label, >=44px, shrink-0. Edit = brand pair on
|
||||
hover (brand-ink/brand-soft 6.9:1); Delete = err pair on hover
|
||||
(9.1:1), consistent with .steering-delete. */
|
||||
.tuning-edit,
|
||||
.tuning-delete {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.35rem;
|
||||
min-height: 44px;
|
||||
min-width: 44px;
|
||||
flex: 0 0 auto;
|
||||
padding: 0.35rem 0.7rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
background: transparent;
|
||||
color: var(--ink-soft);
|
||||
font: inherit;
|
||||
font-weight: 600;
|
||||
font-size: 0.82rem;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tuning-edit svg, .tuning-delete svg { width: 14px; height: 14px; display: block; }
|
||||
.tuning-edit:hover:not(:disabled) { background: var(--brand-soft); color: var(--brand-ink); border-color: var(--brand-soft); }
|
||||
.tuning-delete:hover:not(:disabled) { background: var(--err-bg); color: var(--err-ink); border-color: var(--err-line); }
|
||||
.tuning-edit:disabled, .tuning-delete:disabled { opacity: 0.5; cursor: wait; }
|
||||
|
||||
/* Inline edit: the row swaps to a vertical card — the text span is
|
||||
hidden and replaced by the .tuning-edit-form (textarea pre-filled +
|
||||
Save/Cancel, reusing the phase-15 .tune-save/.tune-cancel styles);
|
||||
the row-level Edit/Delete buttons step aside for the form's own. */
|
||||
.tuning-note.is-editing {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 0.5rem;
|
||||
background: #0d1120;
|
||||
border: 1px solid var(--brand-soft);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.6rem 0.7rem;
|
||||
}
|
||||
.tuning-note.is-editing .tuning-note-text,
|
||||
.tuning-note.is-editing .tuning-edit,
|
||||
.tuning-note.is-editing .tuning-delete { display: none; }
|
||||
.tuning-edit-form { display: flex; flex-direction: column; gap: 0.5rem; width: 100%; }
|
||||
.tuning-edit-input {
|
||||
font: inherit;
|
||||
font-size: 0.9rem;
|
||||
color: var(--ink);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.5rem 0.6rem;
|
||||
resize: vertical;
|
||||
min-height: 2.6rem;
|
||||
}
|
||||
.tuning-edit-input::placeholder { color: var(--ink-soft); }
|
||||
.tuning-edit-form-actions { display: flex; gap: 0.5rem; }
|
||||
|
||||
/* Per-action status pills (role=status / role=alert), the phase-15
|
||||
pairs: ok 10.6:1, err 9.1:1. */
|
||||
.tuning-saved {
|
||||
background: var(--ok-bg);
|
||||
color: var(--ok-ink);
|
||||
border: 1px solid rgb(110 231 168 / 0.35);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.45rem 0.8rem;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.tuning-error {
|
||||
background: var(--err-bg);
|
||||
color: var(--err-ink);
|
||||
border: 1px solid var(--err-line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.45rem 0.8rem;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#tune-empty {
|
||||
margin: 0.65rem 0 0;
|
||||
color: var(--ink-soft);
|
||||
font-size: 0.88rem;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* typing indicator */
|
||||
.typing { display: inline-flex; gap: 5px; padding: 0.9rem 1rem; }
|
||||
.typing span {
|
||||
@@ -1416,6 +1604,11 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
}
|
||||
.steering-note { padding: 0.3rem 0.3rem 0.3rem 0.7rem; }
|
||||
.tune-btn { min-height: 44px; }
|
||||
/* Phase 27: the tuning page squeezes like the other cards — the row
|
||||
padding tightens; the icon+label actions keep their 44px floor and
|
||||
the note text ellipsizes (min-width: 0). */
|
||||
.tuning-note { gap: 0.4rem; padding: 0.3rem; }
|
||||
.tuning-edit, .tuning-delete { padding: 0.35rem 0.5rem; }
|
||||
.msg-body { max-width: 92%; }
|
||||
.empty-state { padding: 1.75rem 1.1rem; margin-top: 0.25rem; }
|
||||
.empty-state-title { font-size: 1.25rem; }
|
||||
|
||||
Reference in New Issue
Block a user