package views
import "git.b0b.be/bdeb/localchat/internal/chat"
// Page is the full chat screen.
templ Page(title string, msgs []chat.Message) {
{ title }
{ title }
@Health(HealthInfo{Checking: true})
@Messages(msgs)
}
// Messages renders a whole conversation, or the empty state.
templ Messages(msgs []chat.Message) {
if len(msgs) == 0 {
Hi! đź‘‹
Everything you type stays on this machine. The model runs locally.
}
for _, m := range msgs {
if m.Role == "assistant" && m.State != chat.Done {
@StreamingReply(m)
} else {
@MessageView(m)
}
}
}
// Exchange is returned after sending: the user's message plus a reply that
// streams in over server-sent events.
templ Exchange(user, reply chat.Message) {
@MessageView(user)
@StreamingReply(reply)
}
// MessageView renders a finished message.
templ MessageView(m chat.Message) {
if m.Role == "assistant" {
@Markdown(m.Content)
if m.Err != "" {
⚠️ { m.Err }
}
} else {
{ m.Content }
}
}
// StreamingReply opens an SSE connection. "token" events append text as it
// arrives; the final "done" event swaps in the rendered Markdown and closes
// the connection.
templ StreamingReply(m chat.Message) {
}
// Token is one streamed chunk of text.
templ Token(text string) {
{ text }
}
// HealthInfo describes the model server status shown in the header.
type HealthInfo struct {
Checking bool
OK bool
Model string
Err string
}
templ Health(h HealthInfo) {
if h.Checking {
connecting…
} else if h.OK {
{ h.Model }
} else {
model offline
}