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 }
}