package ui import ( "fmt" "github.com/ryanhamamura/c4/snake" "github.com/ryanhamamura/via/h" ) type ChatMessage struct { Nickname string `json:"nickname"` Slot int `json:"slot"` Message string `json:"message"` Time int64 `json:"time"` } func SnakeChat(messages []ChatMessage, msgBind, sendClick, sendKeyDown h.H) h.H { var msgEls []h.H for _, m := range messages { color := "#666" if m.Slot >= 0 && m.Slot < len(snake.SnakeColors) { color = snake.SnakeColors[m.Slot] } msgEls = append(msgEls, h.Div(h.Class("snake-chat-msg"), h.Span( h.Attr("style", fmt.Sprintf("color:%s;font-weight:bold;", color)), h.Text(m.Nickname+": "), ), h.Span(h.Text(m.Message)), )) } // Auto-scroll chat history to bottom on new messages autoScroll := h.Script(h.Text(` (function(){ var el = document.querySelector('.snake-chat-history'); if (!el) return; el.scrollTop = el.scrollHeight; new MutationObserver(function(){ el.scrollTop = el.scrollHeight; }) .observe(el, {childList:true, subtree:true}); })(); `)) historyAttrs := []h.H{h.Class("snake-chat-history")} historyAttrs = append(historyAttrs, msgEls...) historyAttrs = append(historyAttrs, autoScroll) return h.Div(h.Class("snake-chat"), h.Div(historyAttrs...), h.Div(h.Class("snake-chat-input"), h.Input( h.Type("text"), h.Attr("placeholder", "Chat..."), h.Attr("autocomplete", "off"), // Prevent key events from bubbling to the game's window-level handler h.Attr("onkeydown", "event.stopPropagation()"), msgBind, sendKeyDown, ), h.Button(h.Type("button"), h.Text("Send"), sendClick), ), ) }