feat(web): immediate summarize + status poll + ASCII tapir spinner
Clicking "Summarize" now runs the summary in the background (when a Processor is
wired) instead of only queuing it. The handler flips the DB flag, kicks off the
work on a detached context, and returns an animated "processing" card that polls
GET /v/{id}/status every 2s via HTMX. Status returns the summary card once it
lands (no poll → polling stops), the animation while in-flight, or the Queued
card otherwise. Queue-only behaviour is unchanged when no Processor is set.
The spinner is a CSS-only cross-fade of three ASCII tapir frames — no JS, honours
prefers-reduced-motion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -140,6 +140,39 @@ templ VideoCard(r store.SummaryRow) {
|
||||
</li>
|
||||
}
|
||||
|
||||
// TapirSpinner is the summarizing animation: three ASCII tapir frames stacked
|
||||
// and cross-faded by CSS keyframes (no JS), with a muted "Summarizing…" label.
|
||||
// The art is aria-hidden — it is decorative; the label carries the meaning.
|
||||
templ TapirSpinner() {
|
||||
<div class="tapir-spin" aria-hidden="true">
|
||||
<pre>{ tapirFrame1 }</pre>
|
||||
<pre>{ tapirFrame2 }</pre>
|
||||
<pre>{ tapirFrame3 }</pre>
|
||||
</div>
|
||||
<p class="tapir-label" role="status" aria-live="polite"><em>Summarizing…</em></p>
|
||||
}
|
||||
|
||||
// processingCard is the in-flight summarization card. It replaces the Summarize
|
||||
// button card and polls /v/{id}/status every 2s, swapping itself (outerHTML, same
|
||||
// id as VideoCard) for whatever state comes back: it keeps polling while still
|
||||
// processing, and the summary/queued card it is eventually replaced by carries no
|
||||
// poll, so polling stops on its own when the fragment changes.
|
||||
templ processingCard(r store.SummaryRow) {
|
||||
<li
|
||||
class="card card-processing"
|
||||
id={ "video-" + r.VideoID }
|
||||
hx-get={ string(statusURL(r.VideoID)) }
|
||||
hx-trigger="every 2s"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
<div class="card-title">{ displayTitle(r) }</div>
|
||||
if cardMeta(r) != "" {
|
||||
<div class="card-meta">{ cardMeta(r) }</div>
|
||||
}
|
||||
@TapirSpinner()
|
||||
</li>
|
||||
}
|
||||
|
||||
// DetailPage is the full summary view: text, highlights, takeaways, metadata,
|
||||
// and the action button group.
|
||||
templ DetailPage(r store.SummaryRow) {
|
||||
|
||||
Reference in New Issue
Block a user