package web
import (
"strings"
"gitea.d-ma.be/mathias/tapir/internal/adapters/store"
)
// Layout is the shared HTML shell. HTMX drives the progressive interactions
// (filters, action toggles); every interaction also degrades to a plain form
// POST/GET when JS is absent (ui-spec.md §4).
templ Layout(title string) {
{ title }
@templ.Raw(styleTag)
{ children... }
}
// ListPage is the full summary list with the filter form. HTMX swaps only the
// #summary-list region; a non-HTMX request renders the whole page.
templ ListPage(rows []store.SummaryRow, f Filter) {
@Layout("Tapir — Summaries") {
@filterForm(f)
@summaryList(rows)
}
}
templ filterForm(f Filter) {
}
// summaryList is the swappable list fragment: one card per summary (title link,
// channel · date meta, provider chip, fallback badge, action state). Cards
// reflow to a single column on mobile; an empty list shows a friendly first-run
// state instead of a blank table.
templ summaryList(rows []store.SummaryRow) {
if len(rows) == 0 {
No summaries yet
Summaries appear here as your subscriptions are processed — run tapir run to fetch and summarize new videos.
} else {
for _, r := range rows {
-
if cardMeta(r) != "" {
{ cardMeta(r) }
}
if p := previewText(r.Summary, 160); p != "" {
{ p }
}
}
}
}
// DetailPage is the full summary view: text, highlights, takeaways, metadata,
// and the action button group.
templ DetailPage(r store.SummaryRow) {
@Layout("Tapir — " + displayTitle(r)) {
{ displayTitle(r) }
if detailMeta(r) != "" {
{ detailMeta(r) }
}
if r.FallbackUsed {
fallback
}
if url, ok := embedURL(r.ProviderVideoID); ok {
}
if r.URL != "" {
watch on source ↗
}
@ActionButtons(r.VideoID, actionSet(r.Actions))
if len(r.Highlights) > 0 {
Highlights
for _, h := range r.Highlights {
- { h }
}
}
if len(r.Takeaways) > 0 {
Takeaways
for _, t := range r.Takeaways {
- { t }
}
}
}
}
// RegisterPage is the explicit registration step (ADR-012): an authenticated Dex
// subject with no tapir user picks a display name and accepts the terms to create
// their account. errMsg, when set, reports a validation problem on the prior POST.
templ RegisterPage(email, errMsg string) {
@Layout("Tapir — Register") {
Complete your registration
if email != "" {
Signed in as { email }.
}
Choose a display name to finish setting up your Tapir account.
if errMsg != "" {
{ errMsg }
}
}
}
// ActionButtons is the toggle group fragment returned by POST /v/{id}/action.
// Each button submits its verb; HTMX swaps this element in place (outerHTML),
// and without JS the form POSTs and the handler redirects back to the detail
// page. active marks the verbs currently set for (user, video).
templ ActionButtons(videoID string, active map[string]bool) {
}