feat: add snake multiplayer chat as sidebar with vivid player colors
Move chat to the right of the board using a flex wrapper that stacks vertically on narrow screens. Restore original snake player colors by removing the desaturation filter added with the dark theme.
This commit is contained in:
66
main.go
66
main.go
@@ -6,9 +6,12 @@ import (
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/joho/godotenv"
|
||||
@@ -588,8 +591,51 @@ func main() {
|
||||
}
|
||||
})
|
||||
|
||||
chatMsg := c.Signal("")
|
||||
var chatMessages []ui.ChatMessage
|
||||
var chatMu sync.Mutex
|
||||
|
||||
sendChat := c.Action(func() {
|
||||
msg := chatMsg.String()
|
||||
if msg == "" || si == nil {
|
||||
return
|
||||
}
|
||||
slot := si.GetPlayerSlot(playerID)
|
||||
if slot < 0 {
|
||||
return
|
||||
}
|
||||
cm := ui.ChatMessage{
|
||||
Nickname: si.GetGame().Players[slot].Nickname,
|
||||
Slot: slot,
|
||||
Message: msg,
|
||||
Time: time.Now().UnixMilli(),
|
||||
}
|
||||
data, err := json.Marshal(cm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.Publish("snake.chat."+gameID, data)
|
||||
chatMsg.SetValue("")
|
||||
})
|
||||
|
||||
if gameExists {
|
||||
c.Subscribe("snake."+gameID, func(data []byte) { c.Sync() })
|
||||
|
||||
if si.GetGame().Mode == snake.ModeMultiplayer {
|
||||
c.Subscribe("snake.chat."+gameID, func(data []byte) {
|
||||
var cm ui.ChatMessage
|
||||
if err := json.Unmarshal(data, &cm); err != nil {
|
||||
return
|
||||
}
|
||||
chatMu.Lock()
|
||||
chatMessages = append(chatMessages, cm)
|
||||
if len(chatMessages) > 50 {
|
||||
chatMessages = chatMessages[len(chatMessages)-50:]
|
||||
}
|
||||
chatMu.Unlock()
|
||||
c.Sync()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-join if nickname exists
|
||||
@@ -638,7 +684,25 @@ func main() {
|
||||
)
|
||||
|
||||
if sg.Status == snake.StatusInProgress || sg.Status == snake.StatusFinished {
|
||||
content = append(content, ui.SnakeBoard(sg))
|
||||
board := ui.SnakeBoard(sg)
|
||||
|
||||
if sg.Mode == snake.ModeMultiplayer {
|
||||
chatMu.Lock()
|
||||
msgs := make([]ui.ChatMessage, len(chatMessages))
|
||||
copy(msgs, chatMessages)
|
||||
chatMu.Unlock()
|
||||
chat := ui.SnakeChat(msgs, chatMsg.Bind(), sendChat.OnClick(), sendChat.OnKeyDown("Enter"))
|
||||
content = append(content, h.Div(h.Class("snake-game-area"), board, chat))
|
||||
} else {
|
||||
content = append(content, board)
|
||||
}
|
||||
} else if sg.Mode == snake.ModeMultiplayer {
|
||||
// Show chat even before game starts (waiting/countdown)
|
||||
chatMu.Lock()
|
||||
msgs := make([]ui.ChatMessage, len(chatMessages))
|
||||
copy(msgs, chatMessages)
|
||||
chatMu.Unlock()
|
||||
content = append(content, ui.SnakeChat(msgs, chatMsg.Bind(), sendChat.OnClick(), sendChat.OnKeyDown("Enter")))
|
||||
}
|
||||
|
||||
// Only show invite link for multiplayer games
|
||||
|
||||
Reference in New Issue
Block a user