d9f274ec1a
Filling the composer and waiting for Enter made the card a form to review rather than a thing to press. One click, one reply. That changes what a prompt has to be. The built-ins ended mid-sentence -- "My plan: " -- because nothing was sent until the person finished the thought; sent cold they are a model guessing at material nobody gave it. All three are rewritten to ask for what they need, so the first reply is the right question instead. There is a test that they end as complete sentences, since the failure is silent and only visible in the answer. requestSubmit, not submit: it fires the submit event, which is what htmx listens for. Same call the Enter key already makes. Version bumped because app.js is what changed, and the service worker caches it -- without the bump the first load after this would still only fill the box. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
121 lines
4.6 KiB
HTML
121 lines
4.6 KiB
HTML
{% extends "admin/_layout.html" %}
|
|
{% from "_macros.html" import icon %}
|
|
{% set section = "suggestions" %}
|
|
|
|
{% block title %}Suggestions - LLeMbas{% endblock %}
|
|
{% block heading %}Suggestions{% endblock %}
|
|
|
|
{% block admin_content %}
|
|
<p class="admin-lede">
|
|
Cards on the new-chat screen. Clicking one sends its prompt straight away, so
|
|
each has to work on its own — write one that asks for whatever it needs, and
|
|
the first reply becomes the right question rather than a guess. The first
|
|
{{ max_shown }} enabled ones are shown, in this order.
|
|
</p>
|
|
|
|
{% if saved %}
|
|
<div class="alert alert--success">{{ icon("check", "icon--sm") }} <span>{{ saved }}</span></div>
|
|
{% endif %}
|
|
|
|
{% for suggestion in suggestions %}
|
|
<form class="card" method="post" action="/admin/suggestions/{{ suggestion.id }}">
|
|
<div class="card__header">
|
|
<h2 class="card__title">
|
|
{{ suggestion.name }}
|
|
{% if not suggestion.enabled %}<span class="badge">hidden</span>{% endif %}
|
|
{% if loop.index > max_shown and suggestion.enabled %}
|
|
<span class="badge badge--warning" title="Only the first {{ max_shown }} are shown">
|
|
below the cut
|
|
</span>
|
|
{% endif %}
|
|
</h2>
|
|
<button class="btn btn--sm btn--danger" type="submit"
|
|
formaction="/admin/suggestions/{{ suggestion.id }}/delete"
|
|
data-confirm-button="Delete the suggestion “{{ suggestion.name }}”?"
|
|
data-confirm-title="Delete suggestion">
|
|
{{ icon("trash", "icon--sm") }}
|
|
</button>
|
|
</div>
|
|
|
|
<div class="grid grid--2">
|
|
<div class="field">
|
|
<label class="field__label" for="name-{{ suggestion.id }}">Name</label>
|
|
<input class="input" id="name-{{ suggestion.id }}" name="name"
|
|
value="{{ suggestion.name }}" maxlength="120">
|
|
<p class="field__hint">The heading on the card.</p>
|
|
</div>
|
|
<div class="field">
|
|
<label class="field__label" for="position-{{ suggestion.id }}">Position</label>
|
|
<input class="input" id="position-{{ suggestion.id }}" name="position" type="number"
|
|
min="1" value="{{ suggestion.position + 1 }}">
|
|
<p class="field__hint">Order on the screen, lowest first.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="field__label" for="description-{{ suggestion.id }}">Description</label>
|
|
<input class="input" id="description-{{ suggestion.id }}" name="description"
|
|
value="{{ suggestion.description }}" maxlength="300">
|
|
<p class="field__hint">One line under the name, saying what it is for.</p>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="field__label" for="prompt-{{ suggestion.id }}">Prompt</label>
|
|
<textarea class="textarea" id="prompt-{{ suggestion.id }}" name="prompt"
|
|
rows="4">{{ suggestion.prompt }}</textarea>
|
|
<p class="field__hint">
|
|
Sent as the first message. Nothing is added to it, so a prompt that needs
|
|
material should ask for it.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="field">
|
|
<label class="checkbox">
|
|
<input type="checkbox" name="enabled" value="true" {{ 'checked' if suggestion.enabled }}>
|
|
<span>Show this one</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="card__footer">
|
|
<button class="btn btn--primary btn--sm" type="submit">Save</button>
|
|
</div>
|
|
</form>
|
|
{% else %}
|
|
<div class="empty">
|
|
{{ icon("sparkle", "empty__mark") }}
|
|
<h2 class="empty__title">No suggestions</h2>
|
|
<p class="empty__text">The new-chat screen shows its empty state instead.</p>
|
|
</div>
|
|
{% endfor %}
|
|
|
|
{% if not at_limit %}
|
|
<form class="card" method="post" action="/admin/suggestions">
|
|
<h2 class="card__title">Add a suggestion</h2>
|
|
<div class="field">
|
|
<label class="field__label" for="new-name">Name</label>
|
|
<input class="input" id="new-name" name="name" maxlength="120"
|
|
placeholder="Summarise a document" required>
|
|
</div>
|
|
<div class="field">
|
|
<label class="field__label" for="new-description">Description</label>
|
|
<input class="input" id="new-description" name="description" maxlength="300"
|
|
placeholder="What it is for, in one line.">
|
|
</div>
|
|
<div class="field">
|
|
<label class="field__label" for="new-prompt">Prompt</label>
|
|
<textarea class="textarea" id="new-prompt" name="prompt" rows="4"
|
|
placeholder="Sent as the first message when the card is clicked."></textarea>
|
|
</div>
|
|
<div class="card__footer">
|
|
<button class="btn btn--primary" type="submit">Add</button>
|
|
</div>
|
|
</form>
|
|
{% else %}
|
|
<p class="admin-lede">
|
|
{{ max_suggestions }} is the limit. Delete one to add another — past a dozen
|
|
this is a menu, and a menu on the empty screen is a worse blank page than a
|
|
blank page.
|
|
</p>
|
|
{% endif %}
|
|
{% endblock %}
|