Refactor chat module to use unified theme system
Rewrites chat.css to use centralized CSS variables from app.css instead of maintaining its own theme definitions. Moves all theme variables (colors, spacing, shadows, transitions) to app.css as the single source of truth. Improves chat UI consistency, adds better connection status indicators, and enhances responsive design.
This commit is contained in:
parent
cdfeabf0c7
commit
7b322d952b
5 changed files with 989 additions and 1040 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -16,4 +16,5 @@
|
|||
</div>
|
||||
</footer>
|
||||
<button class="scroll-to-bottom" id="scrollToBottom">↓</button>
|
||||
<div class="flash-overlay" id="flashOverlay"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -187,11 +187,15 @@ function chatApp() {
|
|||
connectionStatus = document.getElementById("connectionStatus");
|
||||
flashOverlay = document.getElementById("flashOverlay");
|
||||
suggestionsContainer = document.getElementById("suggestions");
|
||||
floatLogo = document.getElementById("floatLogo");
|
||||
sidebar = document.getElementById("sidebar");
|
||||
themeBtn = document.getElementById("themeBtn");
|
||||
scrollToBottomBtn = document.getElementById("scrollToBottom");
|
||||
sidebarTitle = document.getElementById("sidebarTitle");
|
||||
|
||||
console.log("Chat DOM elements initialized:", {
|
||||
messagesDiv: !!messagesDiv,
|
||||
messageInputEl: !!messageInputEl,
|
||||
sendBtn: !!sendBtn,
|
||||
voiceBtn: !!voiceBtn,
|
||||
connectionStatus: !!connectionStatus,
|
||||
});
|
||||
|
||||
// Theme initialization and focus
|
||||
const savedTheme = localStorage.getItem("gb-theme") || "auto";
|
||||
|
|
@ -231,10 +235,15 @@ function chatApp() {
|
|||
});
|
||||
}
|
||||
|
||||
sendBtn.onclick = () => this.sendMessage();
|
||||
messageInputEl.addEventListener("keypress", (e) => {
|
||||
if (e.key === "Enter") this.sendMessage();
|
||||
});
|
||||
if (sendBtn) {
|
||||
sendBtn.onclick = () => this.sendMessage();
|
||||
}
|
||||
|
||||
if (messageInputEl) {
|
||||
messageInputEl.addEventListener("keypress", (e) => {
|
||||
if (e.key === "Enter") this.sendMessage();
|
||||
});
|
||||
}
|
||||
|
||||
// Don't auto-reconnect on focus in browser to prevent multiple connections
|
||||
// Tauri doesn't fire focus events the same way
|
||||
|
|
@ -263,7 +272,14 @@ function chatApp() {
|
|||
},
|
||||
|
||||
updateConnectionStatus(s) {
|
||||
if (!connectionStatus) return;
|
||||
connectionStatus.className = `connection-status ${s}`;
|
||||
const statusText = {
|
||||
connected: "Connected",
|
||||
connecting: "Connecting...",
|
||||
disconnected: "Disconnected",
|
||||
};
|
||||
connectionStatus.innerHTML = `<span>${statusText[s] || s}</span>`;
|
||||
},
|
||||
|
||||
getWebSocketUrl() {
|
||||
|
|
@ -513,9 +529,6 @@ function chatApp() {
|
|||
if (d.color2) themeColor2 = d.color2;
|
||||
if (d.logo_url) customLogoUrl = d.logo_url;
|
||||
if (d.title) document.title = d.title;
|
||||
if (d.logo_text) {
|
||||
sidebarTitle.textContent = d.logo_text;
|
||||
}
|
||||
this.applyTheme();
|
||||
break;
|
||||
}
|
||||
|
|
@ -526,40 +539,28 @@ function chatApp() {
|
|||
const t = document.createElement("div");
|
||||
t.id = "thinking-indicator";
|
||||
t.className = "message-container";
|
||||
t.innerHTML = `<div class="assistant-message"><div class="assistant-avatar"></div><div class="thinking-indicator"><div class="typing-dots"><div class="typing-dot"></div><div class="typing-dot"></div><div class="typing-dot"></div></div></div></div>`;
|
||||
messagesDiv.appendChild(t);
|
||||
gsap.to(t, { opacity: 1, y: 0, duration: 0.3, ease: "power2.out" });
|
||||
if (!isUserScrolling) {
|
||||
this.scrollToBottom();
|
||||
t.innerHTML = `<div class="assistant-message"><div class="assistant-avatar"></div><div class="thinking-indicator"><div class="thinking-dot"></div><div class="thinking-dot"></div><div class="thinking-dot"></div></div></div>`;
|
||||
if (messagesDiv) {
|
||||
messagesDiv.appendChild(t);
|
||||
if (!isUserScrolling) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
}
|
||||
isThinking = true;
|
||||
|
||||
thinkingTimeout = setTimeout(() => {
|
||||
if (isThinking) {
|
||||
this.hideThinkingIndicator();
|
||||
this.showWarning(
|
||||
"O servidor pode estar ocupado. A resposta está demorando demais.",
|
||||
);
|
||||
this.showWarning("A resposta está demorando mais que o esperado...");
|
||||
}
|
||||
}, 60000);
|
||||
isThinking = true;
|
||||
}, 30000);
|
||||
},
|
||||
|
||||
hideThinkingIndicator() {
|
||||
if (!isThinking) return;
|
||||
const t = document.getElementById("thinking-indicator");
|
||||
if (t) {
|
||||
gsap.to(t, {
|
||||
opacity: 0,
|
||||
duration: 0.2,
|
||||
onComplete: () => {
|
||||
if (t.parentNode) {
|
||||
t.remove();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
if (thinkingTimeout) {
|
||||
clearTimeout(thinkingTimeout);
|
||||
thinkingTimeout = null;
|
||||
if (t && t.parentNode) {
|
||||
t.remove();
|
||||
}
|
||||
isThinking = false;
|
||||
},
|
||||
|
|
@ -568,30 +569,28 @@ function chatApp() {
|
|||
const w = document.createElement("div");
|
||||
w.className = "warning-message";
|
||||
w.innerHTML = `⚠️ ${m}`;
|
||||
messagesDiv.appendChild(w);
|
||||
gsap.from(w, { opacity: 0, y: 20, duration: 0.4, ease: "power2.out" });
|
||||
if (!isUserScrolling) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (w.parentNode) {
|
||||
gsap.to(w, {
|
||||
opacity: 0,
|
||||
duration: 0.3,
|
||||
onComplete: () => w.remove(),
|
||||
});
|
||||
if (messagesDiv) {
|
||||
messagesDiv.appendChild(w);
|
||||
if (!isUserScrolling) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
}, 5000);
|
||||
setTimeout(() => {
|
||||
if (w.parentNode) {
|
||||
w.remove();
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
},
|
||||
|
||||
showContinueButton() {
|
||||
const c = document.createElement("div");
|
||||
c.className = "message-container";
|
||||
c.innerHTML = `<div class="assistant-message"><div class="assistant-avatar"></div><div class="assistant-message-content"><p>A conexão foi interrompida. Clique em "Continuar" para tentar recuperar a resposta.</p><button class="continue-button" onclick="this.parentElement.parentElement.parentElement.remove();">Continuar</button></div></div>`;
|
||||
messagesDiv.appendChild(c);
|
||||
gsap.to(c, { opacity: 1, y: 0, duration: 0.5, ease: "power2.out" });
|
||||
if (!isUserScrolling) {
|
||||
this.scrollToBottom();
|
||||
if (messagesDiv) {
|
||||
messagesDiv.appendChild(c);
|
||||
if (!isUserScrolling) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -629,10 +628,11 @@ function chatApp() {
|
|||
} else {
|
||||
m.innerHTML = `<div class="assistant-message"><div class="assistant-avatar"></div><div class="assistant-message-content">${content}</div></div>`;
|
||||
}
|
||||
messagesDiv.appendChild(m);
|
||||
gsap.to(m, { opacity: 1, y: 0, duration: 0.5, ease: "power2.out" });
|
||||
if (!isUserScrolling) {
|
||||
this.scrollToBottom();
|
||||
if (messagesDiv) {
|
||||
messagesDiv.appendChild(m);
|
||||
if (!isUserScrolling) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -680,9 +680,13 @@ function chatApp() {
|
|||
b.className = "suggestion-button";
|
||||
b.onclick = () => {
|
||||
this.setContext(v.context);
|
||||
messageInputEl.value = "";
|
||||
if (messageInputEl) {
|
||||
messageInputEl.value = "";
|
||||
}
|
||||
};
|
||||
suggestionsContainer.appendChild(b);
|
||||
if (suggestionsContainer) {
|
||||
suggestionsContainer.appendChild(b);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -16,8 +16,8 @@
|
|||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Helvetica, Arial, sans-serif;
|
||||
background: #ffffff;
|
||||
color: #202124;
|
||||
background: var(--primary-bg);
|
||||
color: var(--primary-fg);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
|
@ -55,14 +55,14 @@
|
|||
padding: 8px;
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.logo-wrapper:hover {
|
||||
background: rgba(255, 255, 255, 1);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
background: var(--bg-hover);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
|
|
@ -75,7 +75,7 @@
|
|||
.logo-text {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #202124;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* Right side - Apps menu and avatar */
|
||||
|
|
@ -97,20 +97,20 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s;
|
||||
color: #5f6368;
|
||||
color: var(--text-secondary);
|
||||
position: relative;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
background: var(--glass-bg);
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.apps-menu-btn:hover {
|
||||
background: rgba(255, 255, 255, 1);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
background: var(--bg-hover);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.apps-menu-btn:active {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
background: var(--bg-active);
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
|
|
@ -120,11 +120,9 @@
|
|||
top: 60px;
|
||||
right: 80px;
|
||||
width: 320px;
|
||||
background: white;
|
||||
background: var(--glass-bg);
|
||||
border-radius: 16px;
|
||||
box-shadow:
|
||||
0 1px 2px 0 rgba(60, 64, 67, 0.3),
|
||||
0 2px 6px 2px rgba(60, 64, 67, 0.15);
|
||||
box-shadow: var(--shadow-xl);
|
||||
padding: 20px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue