Prompt suggestions on the new-chat screen
A blank composer is the least helpful thing a chat client can show someone who has just installed one. Three cards now sit under the empty state, and an administrator manages them at /admin/suggestions. Clicking a card fills the composer and stops there. It deliberately does not send: every default ends mid-sentence, because a card is a starting point rather than a question somebody already asked, and the caret lands where the person has to start typing. Seeding is guarded by a settings flag, not by "is the table empty" -- otherwise an administrator who decided against them would get all three back on every restart. Capped at twelve, six shown: past a dozen this is a menu, and a menu on the empty screen is a worse blank page than a blank page. The cards are gated on there being no chat at all, not on the thread being empty. An empty chat someone opened on purpose already has a model and a prompt chosen. Also fixes a pre-existing bug the position test caught. Both this and _refresh_models wrote `coalesce(max(position), -1) or -1`, and position 0 is falsy -- so the second row landed back on 0 on top of the first. The coalesce was already doing that job; the `or` was undoing it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -167,6 +167,43 @@
|
||||
.reasoning__summary::-webkit-details-marker { display: none; }
|
||||
.reasoning__summary:hover { color: var(--ink); background: var(--surface-hover); }
|
||||
|
||||
/* --- Suggestions -----------------------------------------------------------
|
||||
Starting points on the empty screen. Cards rather than a list, because they
|
||||
are things to press.
|
||||
*/
|
||||
.suggestions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
|
||||
gap: var(--sp-3);
|
||||
width: 100%;
|
||||
max-width: 40rem;
|
||||
margin-top: var(--sp-6);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.suggestion {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-1);
|
||||
padding: var(--sp-3) var(--sp-4);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition: background var(--transition-fast), border-color var(--transition-fast);
|
||||
}
|
||||
.suggestion:hover { background: var(--surface-hover); border-color: var(--border-strong); }
|
||||
.suggestion:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
||||
|
||||
.suggestion__name { font-weight: 600; font-size: var(--text-sm); }
|
||||
.suggestion__note {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--ink-muted);
|
||||
line-height: var(--leading-normal);
|
||||
}
|
||||
|
||||
/* --- Metrics ---------------------------------------------------------------
|
||||
What a reply cost, under the bubble. Quiet by default: it is reference, not
|
||||
something to read every time.
|
||||
|
||||
@@ -384,6 +384,21 @@
|
||||
return;
|
||||
}
|
||||
|
||||
/* A suggestion card fills the composer and stops there. It deliberately
|
||||
does not submit: the prompts end mid-sentence, because a card is a
|
||||
starting point rather than a question somebody already asked. */
|
||||
var suggestion = event.target.closest("[data-suggestion]");
|
||||
if (suggestion) {
|
||||
event.preventDefault();
|
||||
var input = document.querySelector("[data-composer-input]");
|
||||
if (!input) return;
|
||||
input.value = suggestion.dataset.suggestion;
|
||||
autosize(input);
|
||||
input.focus();
|
||||
input.setSelectionRange(input.value.length, input.value.length);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Show/hide a panel by selector, so templates do not each carry their own
|
||||
inline toggle script. */
|
||||
var toggle = event.target.closest("[data-toggle]");
|
||||
|
||||
Reference in New Issue
Block a user