diff --git a/handlers/chat.go b/handlers/chat.go
index e9210a9..5f2bda3 100644
--- a/handlers/chat.go
+++ b/handlers/chat.go
@@ -83,9 +83,10 @@ func init() {
}
type IncomingChatMessage struct {
- Type string `json:"type"`
- Content string `json:"content"`
- ReplyTo int `json:"replyTo"`
+ Type string `json:"type"`
+ Content string `json:"content"`
+ ReplyTo int `json:"replyTo"`
+ Username string `json:"username"`
}
func ChatHandler(app *App) http.HandlerFunc {
@@ -170,7 +171,19 @@ func ChatHandler(app *App) http.HandlerFunc {
continue
}
- if chatMsg.Type == "message" {
+ if chatMsg.Type == "typing" {
+ // Broadcast typing indicator to other clients
+ typingMsg := map[string]interface{}{
+ "type": "typing",
+ "username": chatMsg.Username,
+ }
+ typingJSON, _ := json.Marshal(typingMsg)
+ for c := range hub.clients {
+ if c.boardID == boardID && c.userID != userID {
+ c.conn.WriteMessage(websocket.TextMessage, typingJSON)
+ }
+ }
+ } else if chatMsg.Type == "message" {
if err := models.CreateChatMessage(app.DB, boardID, userID, chatMsg.Content, chatMsg.ReplyTo); err != nil {
log.Printf("Error saving chat message: %v", err)
continue
@@ -237,4 +250,4 @@ func ChatHandler(app *App) http.HandlerFunc {
return
}
}
-}
\ No newline at end of file
+}
diff --git a/templates/pages/chat.html b/templates/pages/chat.html
index 86196f7..922916e 100644
--- a/templates/pages/chat.html
+++ b/templates/pages/chat.html
@@ -34,6 +34,126 @@
padding: 10px;
text-align: center;
border-bottom: 1px solid #001858;
+ position: relative;
+ }
+ .connection-status {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 0.85em;
+ padding: 4px 10px;
+ border-radius: 12px;
+ background-color: rgba(0,0,0,0.1);
+ }
+ .connection-dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ animation: pulse 2s ease-in-out infinite;
+ }
+ .connection-dot.connected {
+ background-color: #4ade80;
+ }
+ .connection-dot.connecting {
+ background-color: #fbbf24;
+ }
+ .connection-dot.disconnected {
+ background-color: #f87171;
+ animation: none;
+ }
+ @keyframes pulse {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.5; }
+ }
+ .typing-indicator {
+ padding: 8px 12px;
+ background-color: #f3d2c1;
+ border-radius: 5px;
+ font-size: 0.85em;
+ font-style: italic;
+ color: #001858;
+ margin-bottom: 8px;
+ display: none;
+ }
+ .typing-indicator.visible {
+ display: block;
+ }
+ .typing-dots {
+ display: inline-block;
+ margin-left: 4px;
+ }
+ .typing-dots span {
+ animation: typing-blink 1.4s infinite;
+ display: inline-block;
+ }
+ .typing-dots span:nth-child(2) {
+ animation-delay: 0.2s;
+ }
+ .typing-dots span:nth-child(3) {
+ animation-delay: 0.4s;
+ }
+ @keyframes typing-blink {
+ 0%, 60%, 100% { opacity: 0.3; }
+ 30% { opacity: 1; }
+ }
+ .jump-to-bottom {
+ position: absolute;
+ bottom: 70px;
+ right: 20px;
+ background-color: #001858;
+ color: #fef6e4;
+ border: 2px solid #001858;
+ border-radius: 50%;
+ width: 45px;
+ height: 45px;
+ cursor: pointer;
+ display: none;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.3em;
+ box-shadow: 0px 4px 12px rgba(0,0,0,0.3);
+ transition: transform 0.2s ease;
+ z-index: 100;
+ }
+ .jump-to-bottom.visible {
+ display: flex;
+ }
+ .jump-to-bottom:hover {
+ transform: translateY(2px);
+ background-color: #8bd3dd;
+ }
+ .jump-to-bottom .unread-badge {
+ position: absolute;
+ top: -5px;
+ right: -5px;
+ background-color: #f582ae;
+ color: #fef6e4;
+ border-radius: 50%;
+ width: 20px;
+ height: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 0.7em;
+ font-weight: bold;
+ }
+ .message-status {
+ font-size: 0.7em;
+ color: #666;
+ margin-left: 8px;
+ }
+ .message-status.sending {
+ color: #fbbf24;
+ }
+ .message-status.sent {
+ color: #4ade80;
+ }
+ .message-status.failed {
+ color: #f87171;
+ cursor: pointer;
}
.chat-breadcrumb {
background-color: #f3d2c1;
@@ -221,6 +341,18 @@
.chat-breadcrumb a {
color: #fef6e4;
}
+ .typing-indicator {
+ background-color: #555;
+ color: #fef6e4;
+ }
+ .jump-to-bottom {
+ background-color: #fef6e4;
+ color: #001858;
+ border-color: #fef6e4;
+ }
+ .jump-to-bottom:hover {
+ background-color: #8bd3dd;
+ }
.chat-header {
border-color: #fef6e4;
}
@@ -293,10 +425,17 @@
{{.Board.Name}}
{{.Board.Description}}{{.Board.Name}}