mirror of
https://github.com/thegeneralist01/archivr
synced 2026-10-09 21:03:17 +02:00
feat(frontend): render Summary rail section + provider selector
New "Summary" rail section between the URL/Preview controls and .meta-list.
A completed summary renders as bold tl;dr, body paragraph, tag chips, and a
provider · model footer; missing or failed shows Generate; pending/running
shows an inline spinner and polls GET every 1500 ms until terminal.
- api.js: fetchEntrySummary + requestEntrySummary. The POST helper unwraps
ApiError's { "error": ... } body so the missing-env-var message reaches
the user verbatim rather than as a bare status code.
- ContextRail.jsx: state seeds from detail.latest_summary so the section
renders immediately on selection. Polling is anchored on the summary
status rather than started inside the click handler, so a job still
running when the user navigates away and back is picked up again. A
transient poll failure is swallowed — the next tick retries, and a real
failure arrives as status === 'failed'.
- Regenerate passes force:true only when a completed summary is already
shown; otherwise the request can take the server's 200 cache-hit path.
- Provider choice persists in sessionStorage under archivr:summary:provider,
with try/catch around both accessors for private-mode browsers.
- Public sessions never see the selector or the Generate button, and the
section renders at all only when a completed summary made it through the
server's visibility gate.
- styles.css: .rail-summary-* only; spacing and the action button reuse
.rail-section and .rail-rearchive-btn. The spinner honours
prefers-reduced-motion — the text alone conveys the state.
- AGENTS.md: document the summary env vars alongside the existing
external-tool convention.
Smoke-tested end to end against a scratch archive with a seeded markdown
entry: claude_cli produced a real summary (pending → running → completed in
~11s); a local mock server exercised the openai_compatible transport and
confirmed the Bearer header, model, and system/user role split on the wire;
unconfigured providers return 400 naming the exact variable; a video entry
returns 400 "v1 unsupported"; a repeat POST returns 200 from cache without
adding a row.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
19f3ea41c1
commit
77e8cf41a7
8 changed files with 340 additions and 51 deletions
|
|
@ -3118,3 +3118,64 @@ body.has-audio-bar { padding-bottom: 56px; }
|
|||
cursor: pointer;
|
||||
}
|
||||
.capture-sync-row input[type=checkbox] { cursor: pointer; }
|
||||
|
||||
/* ── Summary rail section ────────────────────────────────────────────────── */
|
||||
/* Reuses .rail-section spacing and .rail-rearchive-btn for the action button;
|
||||
only the summary-specific typography and the provider row are new here. */
|
||||
.rail-summary-body { margin-bottom: 10px; }
|
||||
.rail-summary-tldr {
|
||||
margin: 0 0 8px;
|
||||
font-size: 13.5px;
|
||||
font-weight: 600;
|
||||
color: var(--ink);
|
||||
line-height: 1.45;
|
||||
}
|
||||
.rail-summary-text {
|
||||
margin: 0 0 8px;
|
||||
font-size: 13px;
|
||||
color: var(--ink);
|
||||
line-height: 1.55;
|
||||
}
|
||||
.rail-summary-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 8px; }
|
||||
.rail-summary-tag {
|
||||
font-size: 11px;
|
||||
padding: 2px 7px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 999px;
|
||||
color: var(--muted);
|
||||
}
|
||||
.rail-summary-provider {
|
||||
margin: 0;
|
||||
font-size: 11px;
|
||||
color: var(--muted-2);
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.rail-summary-status {
|
||||
display: flex; align-items: center; gap: 7px;
|
||||
margin: 0 0 8px;
|
||||
font-size: 12.5px;
|
||||
color: var(--muted);
|
||||
}
|
||||
.rail-summary-spinner {
|
||||
width: 11px; height: 11px;
|
||||
border: 1.5px solid var(--line);
|
||||
border-top-color: var(--muted);
|
||||
border-radius: 50%;
|
||||
animation: rail-summary-spin 0.7s linear infinite;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@keyframes rail-summary-spin { to { transform: rotate(360deg); } }
|
||||
/* Respect a reduced-motion preference: the text alone still conveys the state. */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.rail-summary-spinner { animation: none; }
|
||||
}
|
||||
.rail-summary-controls { display: flex; flex-direction: column; gap: 6px; }
|
||||
.rail-summary-select {
|
||||
width: 100%;
|
||||
padding: 5px 8px;
|
||||
font-size: 12.5px;
|
||||
color: var(--ink);
|
||||
background: var(--paper);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue