package web
import (
"fmt"
"time"
"git.d-ma.be/mathias/tapir/internal/domain"
"git.d-ma.be/mathias/tapir/internal/uploads"
)
// UploadsPage is the upload form plus the caller's own uploads (ADR-033).
templ UploadsPage(v uploadsView) {
@Layout("Tapir — Upload a recording") {
Upload a recording
Audio only. Up to { fmt.Sprintf("%d MB", v.Limits.MaxBytes>>20) } and
{ uploads.FormatDuration(v.Limits.MaxDuration) }. The transcript is private to you;
the audio is deleted once it has been transcribed.
if v.Error != "" {
{ v.Error }
}
if len(v.Rows) > 0 {
Your recordings
for _, u := range v.Rows {
-
{ u.Title }
{ string(u.Status) }
}
}
}
}
// UploadPage is one upload's page: its title and the polling status region.
templ UploadPage(u domain.UploadedTranscript, chatEnabled bool) {
@Layout("Tapir — " + u.Title) {
{ u.Title }
@uploadStatus(u, chatEnabled)
All recordings
}
}
// uploadStatus is the region HTMX polls. Unfinished states carry hx-trigger so the
// page re-asks; done and failed render without it, so nothing polls forever.
templ uploadStatus(u domain.UploadedTranscript, chatEnabled bool) {
switch u.Status {
case domain.UploadDone:
@videoNotice(u.HadVideo)
Transcribed { uploads.FormatDuration(time.Duration(u.AudioSeconds * float64(time.Second))) }
of audio by { u.Endpoint }.
if chatEnabled {
Ask about this recording
}
Transcript
{ u.Content }
case domain.UploadFailed:
@videoNotice(u.HadVideo)
{ uploadFailureMessage(u.ErrorKind) }
default:
@videoNotice(u.HadVideo)
if u.Status == domain.UploadTranscribing {
Transcribing… a long recording takes a few minutes.
} else {
Queued — waiting for its turn to be transcribed.
}
}
}
// UploadChatPage is the no-JS full page for chatting with an uploaded transcript:
// the same chat panel as a video's (ADR-027), scoped to this recording.
templ UploadChatPage(u domain.UploadedTranscript, v chatView) {
@Layout("Tapir — Ask about " + u.Title) {
{ u.Title }
Ask about this recording
Answers come only from this recording's transcript, which is private to you.
@chatPanel(v)
Back to the transcript
}
}
// videoNotice tells the user a video track was present and what became of it. A
// Teams meeting with the camera off is still a video file; it is accepted, only the
// audio is transcribed, and the picture is thrown away — so say so, in every state,
// instead of leaving the user to wonder (ADR-033).
templ videoNotice(hadVideo bool) {
if hadVideo {
This file contained a video track. Only its audio was used; the video was discarded and nothing from it was kept.
}
}