feat(chat): save by default + share anonymously — auto-saved chats, guest-facing Share, success toast, action row
This commit is contained in:
+77
-43
@@ -308,44 +308,18 @@ html::after {
|
||||
whole control below 640px. */
|
||||
.new-chat-btn svg { width: 16px; height: 16px; display: none; }
|
||||
|
||||
/* Phase 50 (owner-locked 2026-08-29, TODO.md L5): the "Save" pill — the
|
||||
EXACT visual family of .new-chat-btn (same declarations, so the two
|
||||
chat-shell actions always read as a pair): solid brand pill, --bg text
|
||||
on --brand (5.2:1, WCAG AA), borderless, ≥44px target, hover lightens
|
||||
the brand fill, focus-visible via the global 3px rule. Shipped hidden
|
||||
in index.html — app.js reveals it for admin only (phase 16
|
||||
absent-not-hidden); ≤640px overrides below mirror the New chat ones
|
||||
(label stays visible in .chat-shell, icon hidden). */
|
||||
.save-chat-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
min-height: 44px;
|
||||
padding: 0.5rem 0.9rem;
|
||||
border-radius: 999px;
|
||||
border: 0;
|
||||
background: var(--brand);
|
||||
color: var(--bg);
|
||||
font: inherit;
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
.save-chat-btn:hover { background: #f55a72; color: var(--bg); }
|
||||
/* The save mark is hidden on desktop (the label carries the pill); it is
|
||||
the whole control below 640px (mirrored in the ≤640 block below). */
|
||||
.save-chat-btn svg { width: 16px; height: 16px; display: none; }
|
||||
/* Phase 55 (owner-locked A2, 2026-08-31): the phase-50 Save-pill rules
|
||||
are GONE with the pill — every conversation auto-saves (app.js);
|
||||
the chat-shell actions are New chat + Share only.
|
||||
|
||||
/* Phase 51 (owner-locked 2026-08-29, TODO.md L6): the "Share" pill —
|
||||
the EXACT visual family of .save-chat-btn (same declarations, so the
|
||||
Phase 51 (owner-locked 2026-08-29, TODO.md L6): the "Share" pill —
|
||||
the EXACT visual family of .new-chat-btn (same declarations, so the
|
||||
chat-shell actions always read as a pair): solid brand pill, --bg
|
||||
text on --brand (5.2:1, WCAG AA), borderless, ≥44px target, hover
|
||||
lightens the brand fill, focus-visible via the global 3px rule.
|
||||
Shipped hidden in index.html — app.js reveals it for admin only
|
||||
(phase 16 absent-not-hidden); ≤640px overrides below mirror the
|
||||
Save ones (label stays visible in .chat-shell, icon hidden there). */
|
||||
(phase 16 absent-not-hidden); ≤640px overrides below mirror the New
|
||||
chat ones (label stays visible in .chat-shell, icon hidden there). */
|
||||
.share-chat-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -430,6 +404,24 @@ html::after {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Phase 55 (task 05, 2026-08-31, TODO.md L6, owner-locked A5): the
|
||||
chat-actions row — New chat + Share share ONE .chat-actions element
|
||||
(a normal .chat-shell column child). As a flex ITEM of the column it
|
||||
spans the column width, but as a flex ROW with align-items: center
|
||||
(not the column default stretch) each pill keeps its INTRINSIC
|
||||
content width — two pills side by side, left-aligned in the column,
|
||||
on desktop. The ≤640px block flips this to a vertical stack
|
||||
(flex-direction: column + align-items: stretch — full-width pills,
|
||||
New chat above Share; the existing ≤640px pill rules apply to the
|
||||
stacked pills unchanged). The 46rem column contract is untouched
|
||||
(PLAN §7). */
|
||||
.chat-actions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
/* Phase 52 (owner revision 2026-08-30): `flex-grow` is the other half of
|
||||
the pin. `position: sticky` only ever pulls a box UP toward the
|
||||
viewport bottom — it can never push a box DOWN to meet it — so on an
|
||||
@@ -1304,6 +1296,49 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
.stale-regenerate:disabled { opacity: 0.6; cursor: wait; }
|
||||
.stale-regenerate svg { width: 16px; height: 16px; display: block; }
|
||||
|
||||
/* Phase 55 (task 04): the share-success toast (TODO.md L5). Top-right,
|
||||
just under the sticky header (--header-h + a small offset — the
|
||||
variable already steps 64px → 58px at ≤640px), z-index 1000 (the
|
||||
modal overlay contract — above the header's 20 and the skip-link's
|
||||
100). VISUAL ONLY (A4 owner-locked): the node ships aria-hidden
|
||||
from app.js — #send-status stays the a11y announcer (no double
|
||||
screen-reader read). Solid brand fill: --bg text on --brand = 5.2:1
|
||||
(AA — the .new-chat-btn family); rounded, shadowed, one line of
|
||||
text that wraps under the small max-width. Hidden by default
|
||||
(opacity 0 + pointer-events: none — it never intercepts clicks when
|
||||
idle); .toast.is-visible (toggled by showToast) runs the entry:
|
||||
slide-down + fade (translateY(-8px) → 0, 200ms). */
|
||||
.toast {
|
||||
position: fixed;
|
||||
top: calc(var(--header-h) + 0.75rem);
|
||||
right: 1rem;
|
||||
z-index: 1000;
|
||||
max-width: min(22rem, calc(100vw - 2rem));
|
||||
padding: 0.6rem 1rem;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--brand);
|
||||
color: var(--bg);
|
||||
font-size: 0.92rem;
|
||||
font-weight: 600;
|
||||
box-shadow: var(--shadow);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transform: translateY(-8px);
|
||||
transition: opacity 200ms ease, transform 200ms ease;
|
||||
}
|
||||
.toast.is-visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
/* No slide: BOTH states rest at transform: none (the .is-visible
|
||||
rule would otherwise out-specify the bare .toast); the opacity
|
||||
fade remains (120ms). */
|
||||
.toast,
|
||||
.toast.is-visible { transform: none; }
|
||||
.toast { transition: opacity 120ms ease; }
|
||||
}
|
||||
|
||||
/* ---------- Login page (phase 16) ---------- */
|
||||
/* Centered card in the standard frame: one admin, one password. */
|
||||
.login-shell {
|
||||
@@ -2586,7 +2621,7 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
designated clip target, pills squeeze next). */
|
||||
.nav-link { padding: 0.4rem 0.5rem; font-size: 0.85rem; }
|
||||
.app-nav { gap: 0.15rem; }
|
||||
.new-chat-btn, .save-chat-btn, .auth-link { padding: 0.45rem 0.5rem; }
|
||||
.new-chat-btn, .auth-link { padding: 0.45rem 0.5rem; }
|
||||
}
|
||||
|
||||
/* ---------- Responsive (mobile-first adjustments) ---------- */
|
||||
@@ -2689,13 +2724,8 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
.new-chat-btn { padding: 0.4rem 0.3rem; }
|
||||
.new-chat-label { display: none; }
|
||||
.new-chat-btn svg { display: block; }
|
||||
/* Phase 50: the Save pill squeezes with New chat (same family, same
|
||||
rules — the chat-shell overrides below keep both labels visible). */
|
||||
.save-chat-btn { padding: 0.4rem 0.3rem; }
|
||||
.save-chat-label { display: none; }
|
||||
.save-chat-btn svg { display: block; }
|
||||
/* Phase 51: the Share pill squeezes with Save (same family, same
|
||||
rules — the chat-shell overrides below keep both labels visible). */
|
||||
/* Phase 51: the Share pill squeezes with New chat (same family, same
|
||||
rules — the chat-shell override below keeps the label visible). */
|
||||
.share-chat-btn { padding: 0.4rem 0.3rem; }
|
||||
.share-chat-label { display: none; }
|
||||
.share-chat-btn svg { display: block; }
|
||||
@@ -2703,10 +2733,14 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
|
||||
hide the icon (the button lives inside .chat-shell, not the navbar). */
|
||||
.chat-shell .new-chat-label { display: inline; }
|
||||
.chat-shell .new-chat-btn svg { display: none; }
|
||||
.chat-shell .save-chat-label { display: inline; }
|
||||
.chat-shell .save-chat-btn svg { display: none; }
|
||||
.chat-shell .share-chat-label { display: inline; }
|
||||
.chat-shell .share-chat-btn svg { display: none; }
|
||||
/* Phase 55 (task 05, TODO.md L6, A5): the action row flips to a
|
||||
vertical stack at the phone breakpoint — full-width pills, New
|
||||
chat above Share. The pill rules above (padding, the
|
||||
icon/label handling, the .chat-shell label overrides) apply to
|
||||
the stacked pills unchanged. */
|
||||
.chat-actions { flex-direction: column; align-items: stretch; gap: 0.5rem; }
|
||||
/* Phase 53: the stale banner's row wraps at phone width (message
|
||||
above, action below) — the pill takes a full-width comfortable
|
||||
row instead of squeezing into the text. */
|
||||
|
||||
Reference in New Issue
Block a user