feat: chat avatars + dark theme fix + text overflow fix

Avatars:
- Robot icon (green circle) before each agent message
- Person icon (dark circle) before each user message
- New .chat-bubble wrapper with flex layout for avatar + message

Dark theme fixes:
- Panel background: #1e1e1e (not pure black)
- Agent bubbles: #2d2d2d with light text (not dark/invisible)
- Input area: #2d2d2d (not black)
- Header stays green (--accent-green) in both themes
- Chips, suggestions consistent with panel background

Text overflow:
- overflow-wrap + word-break on messages
- min-width: 0 prevents flex overflow
- User bubble properly right-aligned with avatar
This commit is contained in:
juanatsap
2026-04-08 17:31:07 +01:00
parent 5448c3cf7a
commit be5fdd03c4
3 changed files with 77 additions and 29 deletions
+4 -4
View File
@@ -222,14 +222,14 @@ func (h *Handler) HandleChat(w http.ResponseWriter, r *http.Request) {
return return
} }
// User message bubble // User message bubble with avatar
_, _ = fmt.Fprintf(w, `<div class="chat-message chat-user">%s</div>`, html.EscapeString(message)) _, _ = fmt.Fprintf(w, `<div class="chat-bubble chat-user"><div class="chat-avatar chat-avatar-user"><iconify-icon icon="mdi:account"></iconify-icon></div><div class="chat-message">%s</div></div>`, html.EscapeString(message))
// Agent response bubble // Agent response bubble with avatar
if response == "" { if response == "" {
response = "I couldn't find an answer to that. Try asking about experience, projects, skills, or education." response = "I couldn't find an answer to that. Try asking about experience, projects, skills, or education."
} }
_, _ = fmt.Fprintf(w, `<div class="chat-message chat-agent">%s</div>`, formatResponse(response)) _, _ = fmt.Fprintf(w, `<div class="chat-bubble chat-bot"><div class="chat-avatar chat-avatar-bot"><iconify-icon icon="mdi:robot-happy-outline"></iconify-icon></div><div class="chat-message">%s</div></div>`, formatResponse(response))
// Session ID via OOB swap // Session ID via OOB swap
_, _ = fmt.Fprintf(w, `<input type="hidden" id="chat-session-id" name="session_id" value="%s" form="chat-form" hx-swap-oob="true"/>`, sessionID) _, _ = fmt.Fprintf(w, `<input type="hidden" id="chat-session-id" name="session_id" value="%s" form="chat-form" hx-swap-oob="true"/>`, sessionID)
+70 -23
View File
@@ -201,17 +201,54 @@
min-height: 60px; min-height: 60px;
} }
/* Message Bubbles */ /* Chat Bubbles with Avatars */
.chat-bubble {
display: flex;
gap: 8px;
align-items: flex-start;
max-width: 95%;
}
.chat-bubble.chat-bot {
align-self: flex-start;
}
.chat-bubble.chat-user {
align-self: flex-end;
flex-direction: row-reverse;
}
.chat-avatar {
width: 26px;
height: 26px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.85rem;
flex-shrink: 0;
}
.chat-avatar-bot {
background: var(--accent-green, #27ae60);
color: #fff;
}
.chat-avatar-user {
background: var(--black-bar, #2b2b2b);
color: #fff;
}
/* Message content */
.chat-message { .chat-message {
padding: 8px 12px; padding: 8px 12px;
border-radius: 8px; border-radius: 8px;
font-size: 0.8rem; font-size: 0.8rem;
line-height: 1.5; line-height: 1.5;
max-width: 90%;
word-wrap: break-word; word-wrap: break-word;
overflow-wrap: break-word; overflow-wrap: break-word;
word-break: break-word; word-break: break-word;
overflow: hidden; min-width: 0;
} }
.chat-message p { .chat-message p {
@@ -231,17 +268,15 @@
margin-bottom: 2px; margin-bottom: 2px;
} }
.chat-agent { .chat-bot .chat-message {
background: var(--paper-secondary-bg, #f5f5f5); background: var(--paper-secondary-bg, #f5f5f5);
color: var(--text-secondary, #333333); color: var(--text-secondary, #333333);
align-self: flex-start;
border-bottom-left-radius: 2px; border-bottom-left-radius: 2px;
} }
.chat-user { .chat-user .chat-message {
background: var(--accent-green, #27ae60); background: var(--accent-green, #27ae60);
color: #fff; color: #fff;
align-self: flex-end;
border-bottom-right-radius: 2px; border-bottom-right-radius: 2px;
} }
@@ -252,6 +287,14 @@
font-style: italic; font-style: italic;
border: 1px solid #fecaca; border: 1px solid #fecaca;
font-size: 0.75rem; font-size: 0.75rem;
padding: 8px 12px;
border-radius: 8px;
}
.theme-clean .chat-error {
background: #3a1a1a;
color: #fca5a5;
border-color: #5a2a2a;
} }
/* ========================================================================== /* ==========================================================================
@@ -578,38 +621,42 @@
========================================================================== */ ========================================================================== */
.theme-clean .chat-panel { .theme-clean .chat-panel {
background: #1a1a1a; background: #1e1e1e;
border-color: #333333; border-color: #3a3a3a;
} }
.theme-clean .chat-header { .theme-clean .chat-header {
background: #166b3a; background: var(--accent-green, #27ae60);
} }
.theme-clean .chat-agent { .theme-clean .chat-bot .chat-message {
background: #2a2a2a; background: #2d2d2d;
color: #d0d0d0; color: #e0e0e0;
} }
.theme-clean .chat-user { .theme-clean .chat-user .chat-message {
background: #1e8c4c; background: #1e8c4c;
} }
.theme-clean .chat-error { .theme-clean .chat-avatar-bot {
background: #3a1010; background: #1e8c4c;
color: #fca5a5;
border-color: #5a1a1a;
} }
.theme-clean .chat-avatar-user {
background: #444444;
}
/* error styles consolidated above */
.theme-clean .chat-input-area { .theme-clean .chat-input-area {
border-top-color: #333333; border-top-color: #3a3a3a;
background: #1a1a1a; background: #1e1e1e;
} }
.theme-clean .chat-input { .theme-clean .chat-input {
background: #111111; background: #2d2d2d;
border-color: #333333; border-color: #3a3a3a;
color: #d0d0d0; color: #e0e0e0;
} }
.theme-clean .chat-suggestions { .theme-clean .chat-suggestions {
+3 -2
View File
@@ -28,8 +28,9 @@
</div> </div>
<div id="chat-messages" class="chat-messages"> <div id="chat-messages" class="chat-messages">
<div class="chat-message chat-agent"> <div class="chat-bubble chat-bot">
{{if eq .Lang "es"}}¡Hola! Pregúntame lo que quieras sobre este CV.{{else}}Hi! Ask me anything about this CV.{{end}} <div class="chat-avatar chat-avatar-bot"><iconify-icon icon="mdi:robot-happy-outline"></iconify-icon></div>
<div class="chat-message">{{if eq .Lang "es"}}¡Hola! Pregúntame lo que quieras sobre este CV.{{else}}Hi! Ask me anything about this CV.{{end}}</div>
</div> </div>
</div> </div>