79 lines
2.3 KiB
Plaintext
79 lines
2.3 KiB
Plaintext
package components
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/ryanhamamura/games/chat"
|
|
"github.com/starfederation/datastar-go/datastar"
|
|
)
|
|
|
|
// ColorFunc resolves a player slot to a CSS color string.
|
|
type ColorFunc func(slot int) string
|
|
|
|
// Config holds the game-specific settings for rendering a chat component.
|
|
type Config struct {
|
|
// CSSPrefix is used for element IDs and CSS classes (e.g. "c4" or "snake").
|
|
CSSPrefix string
|
|
// PostURL is the URL to POST chat messages to (e.g. "/games/{id}/chat").
|
|
PostURL string
|
|
// Color resolves a player slot to a CSS color string.
|
|
Color ColorFunc
|
|
// StopKeyPropagation adds data-on:keydown.stop="" to the input to prevent
|
|
// key events from propagating (needed for snake to avoid steering while typing).
|
|
StopKeyPropagation bool
|
|
}
|
|
|
|
// ChatMessage renders a single chat message. Used for appending new messages via SSE.
|
|
templ ChatMessage(m chat.Message, cfg Config) {
|
|
<div class={ cfg.CSSPrefix + "-chat-msg" }>
|
|
<span style={ fmt.Sprintf("color:%s;font-weight:bold;", cfg.Color(m.Slot)) }>
|
|
{ m.Nickname + ": " }
|
|
</span>
|
|
<span>{ m.Message }</span>
|
|
</div>
|
|
}
|
|
|
|
templ Chat(messages []chat.Message, cfg Config) {
|
|
<div id={ cfg.CSSPrefix + "-chat" } class={ cfg.CSSPrefix + "-chat" }>
|
|
<div id={ cfg.CSSPrefix + "-chat-history" } class={ cfg.CSSPrefix + "-chat-history" }>
|
|
for _, m := range messages {
|
|
@ChatMessage(m, cfg)
|
|
}
|
|
</div>
|
|
<div class={ cfg.CSSPrefix + "-chat-input" } data-morph-ignore>
|
|
if cfg.StopKeyPropagation {
|
|
<input
|
|
type="text"
|
|
placeholder="Chat..."
|
|
autocomplete="off"
|
|
data-bind="chatMsg"
|
|
data-on:keydown__stop={ "evt.key === 'Enter' && " + datastar.PostSSE("%s", cfg.PostURL) }
|
|
/>
|
|
} else {
|
|
<input
|
|
type="text"
|
|
placeholder="Chat..."
|
|
autocomplete="off"
|
|
data-bind="chatMsg"
|
|
data-on:keydown={ "evt.key === 'Enter' && " + datastar.PostSSE("%s", cfg.PostURL) }
|
|
/>
|
|
}
|
|
<button
|
|
type="button"
|
|
data-on:click={ datastar.PostSSE("%s", cfg.PostURL) }
|
|
>
|
|
Send
|
|
</button>
|
|
</div>
|
|
@chatAutoScroll(cfg.CSSPrefix)
|
|
</div>
|
|
}
|
|
|
|
script chatAutoScroll(cssPrefix string) {
|
|
var el = document.querySelector('.' + cssPrefix + '-chat-history');
|
|
if (!el) return;
|
|
el.scrollTop = el.scrollHeight;
|
|
new MutationObserver(function(){ el.scrollTop = el.scrollHeight; })
|
|
.observe(el, {childList:true, subtree:true});
|
|
}
|