. Adjust chat layout dimensions and remove context indicator
Reduced footer height from 90px to 75px and adjusted related spacing throughout
This commit is contained in:
parent
8c2b17c615
commit
564ad32417
5 changed files with 76 additions and 99 deletions
|
|
@ -199,7 +199,7 @@ body::before {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
bottom: 100px;
|
bottom: 75px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
padding: 80px 20px 40px;
|
padding: 80px 20px 40px;
|
||||||
|
|
@ -208,6 +208,7 @@ body::before {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
|
height: calc(100vh - 75px);
|
||||||
}
|
}
|
||||||
.message-container {
|
.message-container {
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
|
|
@ -322,7 +323,7 @@ footer {
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(20px);
|
||||||
height: 90px;
|
height: 75px;
|
||||||
}
|
}
|
||||||
.suggestions-container {
|
.suggestions-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -424,7 +425,7 @@ footer {
|
||||||
}
|
}
|
||||||
.scroll-to-bottom {
|
.scroll-to-bottom {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 80px;
|
bottom: 85px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
@ -476,37 +477,6 @@ footer {
|
||||||
color: var(--bg);
|
color: var(--bg);
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
}
|
}
|
||||||
.context-indicator {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 130px;
|
|
||||||
right: 20px;
|
|
||||||
width: 120px;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 10px;
|
|
||||||
text-align: center;
|
|
||||||
z-index: 90;
|
|
||||||
background: var(--bg);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
display: none;
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
}
|
|
||||||
.context-indicator.visible {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.context-progress {
|
|
||||||
height: 3px;
|
|
||||||
background: var(--glass);
|
|
||||||
border-radius: 2px;
|
|
||||||
margin-top: 6px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.context-progress-bar {
|
|
||||||
height: 100%;
|
|
||||||
background: var(--accent);
|
|
||||||
border-radius: 2px;
|
|
||||||
transition: width 0.3s;
|
|
||||||
}
|
|
||||||
.connection-status {
|
.connection-status {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
|
|
@ -706,7 +676,8 @@ footer {
|
||||||
#messages {
|
#messages {
|
||||||
padding: 80px 16px 40px;
|
padding: 80px 16px 40px;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 100px;
|
bottom: 75px;
|
||||||
|
height: calc(100vh - 75px);
|
||||||
}
|
}
|
||||||
.float-menu {
|
.float-menu {
|
||||||
left: 12px;
|
left: 12px;
|
||||||
|
|
@ -721,12 +692,7 @@ footer {
|
||||||
.scroll-to-bottom {
|
.scroll-to-bottom {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
bottom: 70px;
|
bottom: 85px;
|
||||||
right: 12px;
|
right: 12px;
|
||||||
}
|
}
|
||||||
.context-indicator {
|
|
||||||
bottom: 120px;
|
|
||||||
right: 12px;
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,15 +16,4 @@
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<button class="scroll-to-bottom" id="scrollToBottom">↓</button>
|
<button class="scroll-to-bottom" id="scrollToBottom">↓</button>
|
||||||
<div class="context-indicator" id="contextIndicator">
|
|
||||||
<div>Context</div></div>
|
|
||||||
<div id="contextPercentage">0%</div>
|
|
||||||
<div class="context-progress">
|
|
||||||
<div
|
|
||||||
class="context-progress-bar"
|
|
||||||
id="contextProgressBar"
|
|
||||||
style="width: 0%"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,6 @@ function chatApp() {
|
||||||
sidebar,
|
sidebar,
|
||||||
themeBtn,
|
themeBtn,
|
||||||
scrollToBottomBtn,
|
scrollToBottomBtn,
|
||||||
contextIndicator,
|
|
||||||
contextPercentage,
|
|
||||||
contextProgressBar,
|
|
||||||
sidebarTitle;
|
sidebarTitle;
|
||||||
|
|
||||||
marked.setOptions({ breaks: true, gfm: true });
|
marked.setOptions({ breaks: true, gfm: true });
|
||||||
|
|
@ -194,9 +191,6 @@ function chatApp() {
|
||||||
sidebar = document.getElementById("sidebar");
|
sidebar = document.getElementById("sidebar");
|
||||||
themeBtn = document.getElementById("themeBtn");
|
themeBtn = document.getElementById("themeBtn");
|
||||||
scrollToBottomBtn = document.getElementById("scrollToBottom");
|
scrollToBottomBtn = document.getElementById("scrollToBottom");
|
||||||
contextIndicator = document.getElementById("contextIndicator");
|
|
||||||
contextPercentage = document.getElementById("contextPercentage");
|
|
||||||
contextProgressBar = document.getElementById("contextProgressBar");
|
|
||||||
sidebarTitle = document.getElementById("sidebarTitle");
|
sidebarTitle = document.getElementById("sidebarTitle");
|
||||||
|
|
||||||
// Theme initialization and focus
|
// Theme initialization and focus
|
||||||
|
|
@ -250,14 +244,6 @@ function chatApp() {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateContextUsage(u) {
|
|
||||||
contextUsage = u;
|
|
||||||
const p = Math.min(100, Math.round(u * 100));
|
|
||||||
contextPercentage.textContent = `${p}%`;
|
|
||||||
contextProgressBar.style.width = `${p}%`;
|
|
||||||
contextIndicator.classList.remove("visible");
|
|
||||||
},
|
|
||||||
|
|
||||||
flashScreen() {
|
flashScreen() {
|
||||||
gsap.to(flashOverlay, {
|
gsap.to(flashOverlay, {
|
||||||
opacity: 0.15,
|
opacity: 0.15,
|
||||||
|
|
@ -355,7 +341,6 @@ function chatApp() {
|
||||||
this.loadSessions();
|
this.loadSessions();
|
||||||
messagesDiv.innerHTML = "";
|
messagesDiv.innerHTML = "";
|
||||||
this.clearSuggestions();
|
this.clearSuggestions();
|
||||||
this.updateContextUsage(0);
|
|
||||||
if (isVoiceMode) {
|
if (isVoiceMode) {
|
||||||
await this.stopVoiceSession();
|
await this.stopVoiceSession();
|
||||||
isVoiceMode = false;
|
isVoiceMode = false;
|
||||||
|
|
@ -469,9 +454,6 @@ function chatApp() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.context_usage !== undefined) {
|
|
||||||
this.updateContextUsage(r.context_usage);
|
|
||||||
}
|
|
||||||
if (r.suggestions && r.suggestions.length > 0) {
|
if (r.suggestions && r.suggestions.length > 0) {
|
||||||
this.handleSuggestions(r.suggestions);
|
this.handleSuggestions(r.suggestions);
|
||||||
}
|
}
|
||||||
|
|
@ -516,7 +498,7 @@ function chatApp() {
|
||||||
this.showWarning(d.message);
|
this.showWarning(d.message);
|
||||||
break;
|
break;
|
||||||
case "context_usage":
|
case "context_usage":
|
||||||
this.updateContextUsage(d.usage);
|
// Context usage removed
|
||||||
break;
|
break;
|
||||||
case "change_theme":
|
case "change_theme":
|
||||||
if (d.color1) themeColor1 = d.color1;
|
if (d.color1) themeColor1 = d.color1;
|
||||||
|
|
@ -632,10 +614,8 @@ function chatApp() {
|
||||||
m.className = "message-container";
|
m.className = "message-container";
|
||||||
if (role === "user") {
|
if (role === "user") {
|
||||||
m.innerHTML = `<div class="user-message"><div class="user-message-content">${this.escapeHtml(content)}</div></div>`;
|
m.innerHTML = `<div class="user-message"><div class="user-message-content">${this.escapeHtml(content)}</div></div>`;
|
||||||
this.updateContextUsage(contextUsage + 0.05);
|
|
||||||
} else if (role === "assistant") {
|
} else if (role === "assistant") {
|
||||||
m.innerHTML = `<div class="assistant-message"><div class="assistant-avatar"></div><div class="assistant-message-content markdown-content" id="${msgId || ""}">${streaming ? "" : marked.parse(content)}</div></div>`;
|
m.innerHTML = `<div class="assistant-message"><div class="assistant-avatar"></div><div class="assistant-message-content markdown-content" id="${msgId || ""}">${streaming ? "" : marked.parse(content)}</div></div>`;
|
||||||
this.updateContextUsage(contextUsage + 0.03);
|
|
||||||
} else if (role === "voice") {
|
} else if (role === "voice") {
|
||||||
m.innerHTML = `<div class="assistant-message"><div class="assistant-avatar">🎤</div><div class="assistant-message-content">${content}</div></div>`;
|
m.innerHTML = `<div class="assistant-message"><div class="assistant-avatar">🎤</div><div class="assistant-message-content">${content}</div></div>`;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -728,10 +708,6 @@ function chatApp() {
|
||||||
ws.send(JSON.stringify(s));
|
ws.send(JSON.stringify(s));
|
||||||
});
|
});
|
||||||
await pendingContextChange;
|
await pendingContextChange;
|
||||||
const x = document.getElementById("contextIndicator");
|
|
||||||
if (x) {
|
|
||||||
document.getElementById("contextPercentage").textContent = c;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
console.warn("WebSocket não está conectado. Tentando reconectar...");
|
console.warn("WebSocket não está conectado. Tentando reconectar...");
|
||||||
this.connectWebSocket();
|
this.connectWebSocket();
|
||||||
|
|
@ -948,7 +924,6 @@ function chatApp() {
|
||||||
toggleSidebar: toggleSidebar,
|
toggleSidebar: toggleSidebar,
|
||||||
toggleTheme: toggleTheme,
|
toggleTheme: toggleTheme,
|
||||||
applyTheme: applyTheme,
|
applyTheme: applyTheme,
|
||||||
updateContextUsage: updateContextUsage,
|
|
||||||
flashScreen: flashScreen,
|
flashScreen: flashScreen,
|
||||||
updateConnectionStatus: updateConnectionStatus,
|
updateConnectionStatus: updateConnectionStatus,
|
||||||
getWebSocketUrl: getWebSocketUrl,
|
getWebSocketUrl: getWebSocketUrl,
|
||||||
|
|
@ -979,6 +954,16 @@ function chatApp() {
|
||||||
startVoiceRecording: startVoiceRecording,
|
startVoiceRecording: startVoiceRecording,
|
||||||
simulateVoiceTranscription: simulateVoiceTranscription,
|
simulateVoiceTranscription: simulateVoiceTranscription,
|
||||||
scrollToBottom: scrollToBottom,
|
scrollToBottom: scrollToBottom,
|
||||||
|
cleanup: function () {
|
||||||
|
// Cleanup WebSocket connection
|
||||||
|
if (ws) {
|
||||||
|
ws.close();
|
||||||
|
ws = null;
|
||||||
|
}
|
||||||
|
// Clear any pending timeouts/intervals
|
||||||
|
isConnecting = false;
|
||||||
|
isInitialized = false;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cache and return the singleton instance
|
// Cache and return the singleton instance
|
||||||
|
|
@ -988,3 +973,14 @@ function chatApp() {
|
||||||
|
|
||||||
// Initialize the app
|
// Initialize the app
|
||||||
chatApp().init();
|
chatApp().init();
|
||||||
|
|
||||||
|
// Listen for section changes to cleanup when leaving chat
|
||||||
|
document.addEventListener("section-hidden", function (e) {
|
||||||
|
if (
|
||||||
|
e.target.id === "section-chat" &&
|
||||||
|
chatAppInstance &&
|
||||||
|
chatAppInstance.cleanup
|
||||||
|
) {
|
||||||
|
chatAppInstance.cleanup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,8 @@
|
||||||
.logo-wrapper {
|
.logo-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 8px 12px;
|
padding: 8px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
background: rgba(255, 255, 255, 0.9);
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
|
@ -67,8 +66,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo-icon {
|
.logo-icon {
|
||||||
width: 32px;
|
width: 36px;
|
||||||
height: 32px;
|
height: 36px;
|
||||||
background: url("https://pragmatismo.com.br/icons/general-bots.svg")
|
background: url("https://pragmatismo.com.br/icons/general-bots.svg")
|
||||||
center/contain no-repeat;
|
center/contain no-repeat;
|
||||||
}
|
}
|
||||||
|
|
@ -298,7 +297,6 @@
|
||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<div class="logo-wrapper" onclick="window.location.reload()">
|
<div class="logo-wrapper" onclick="window.location.reload()">
|
||||||
<div class="logo-icon"></div>
|
<div class="logo-icon"></div>
|
||||||
<div class="logo-text">General Bots</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -344,18 +342,6 @@
|
||||||
<div class="app-icon">✉</div>
|
<div class="app-icon">✉</div>
|
||||||
<span>Mail</span>
|
<span>Mail</span>
|
||||||
</a>
|
</a>
|
||||||
<a
|
|
||||||
class="app-item"
|
|
||||||
href="#calendar"
|
|
||||||
data-section="calendar"
|
|
||||||
>
|
|
||||||
<div class="app-icon">📅</div>
|
|
||||||
<span>Calendar</span>
|
|
||||||
</a>
|
|
||||||
<a class="app-item" href="#notes" data-section="notes">
|
|
||||||
<div class="app-icon">📝</div>
|
|
||||||
<span>Notes</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-avatar" id="userAvatar" title="User Account">
|
<div class="user-avatar" id="userAvatar" title="User Account">
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,20 @@ async function loadSectionHTML(path) {
|
||||||
async function switchSection(section) {
|
async function switchSection(section) {
|
||||||
const mainContent = document.getElementById("main-content");
|
const mainContent = document.getElementById("main-content");
|
||||||
|
|
||||||
|
// Validate section exists
|
||||||
|
if (!sections[section]) {
|
||||||
|
console.warn(`Section "${section}" does not exist, defaulting to chat`);
|
||||||
|
section = "chat";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up any existing WebSocket connections from chat
|
||||||
|
if (
|
||||||
|
window.chatAppInstance &&
|
||||||
|
typeof window.chatAppInstance.cleanup === "function"
|
||||||
|
) {
|
||||||
|
window.chatAppInstance.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const htmlPath = sections[section];
|
const htmlPath = sections[section];
|
||||||
console.log("Loading section:", section, "from", htmlPath);
|
console.log("Loading section:", section, "from", htmlPath);
|
||||||
|
|
@ -78,6 +92,11 @@ async function switchSection(section) {
|
||||||
});
|
});
|
||||||
targetDiv.style.display = "block";
|
targetDiv.style.display = "block";
|
||||||
} else {
|
} else {
|
||||||
|
// Remove any existing loading divs first
|
||||||
|
container.querySelectorAll(".loading").forEach((div) => {
|
||||||
|
div.remove();
|
||||||
|
});
|
||||||
|
|
||||||
// Show loading placeholder inside the container
|
// Show loading placeholder inside the container
|
||||||
const loadingDiv = document.createElement("div");
|
const loadingDiv = document.createElement("div");
|
||||||
loadingDiv.className = "loading";
|
loadingDiv.className = "loading";
|
||||||
|
|
@ -95,15 +114,22 @@ async function switchSection(section) {
|
||||||
// Hide any existing sections
|
// Hide any existing sections
|
||||||
container.querySelectorAll(".section").forEach((div) => {
|
container.querySelectorAll(".section").forEach((div) => {
|
||||||
div.style.display = "none";
|
div.style.display = "none";
|
||||||
|
// Dispatch a custom event to notify sections they're being hidden
|
||||||
|
div.dispatchEvent(new CustomEvent("section-hidden"));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove loading placeholder
|
// Remove loading placeholder if it still exists
|
||||||
|
if (loadingDiv && loadingDiv.parentNode) {
|
||||||
container.removeChild(loadingDiv);
|
container.removeChild(loadingDiv);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the new section to the container and cache it
|
// Add the new section to the container and cache it
|
||||||
container.appendChild(wrapper);
|
container.appendChild(wrapper);
|
||||||
sectionCache[section] = wrapper;
|
sectionCache[section] = wrapper;
|
||||||
|
|
||||||
|
// Dispatch a custom event to notify the section it's being shown
|
||||||
|
wrapper.dispatchEvent(new CustomEvent("section-shown"));
|
||||||
|
|
||||||
// Ensure the new section is visible with a fast GSAP fade-in
|
// Ensure the new section is visible with a fast GSAP fade-in
|
||||||
gsap.fromTo(
|
gsap.fromTo(
|
||||||
wrapper,
|
wrapper,
|
||||||
|
|
@ -178,13 +204,27 @@ function getInitialSection() {
|
||||||
window.addEventListener("DOMContentLoaded", () => {
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
// Small delay to ensure all resources are loaded
|
// Small delay to ensure all resources are loaded
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
switchSection(getInitialSection());
|
const section = getInitialSection();
|
||||||
|
// Ensure valid section
|
||||||
|
if (!sections[section]) {
|
||||||
|
window.location.hash = "#chat";
|
||||||
|
switchSection("chat");
|
||||||
|
} else {
|
||||||
|
switchSection(section);
|
||||||
|
}
|
||||||
}, 50);
|
}, 50);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle browser back/forward navigation
|
// Handle browser back/forward navigation
|
||||||
window.addEventListener("popstate", () => {
|
window.addEventListener("popstate", () => {
|
||||||
switchSection(getInitialSection());
|
const section = getInitialSection();
|
||||||
|
// Ensure valid section
|
||||||
|
if (!sections[section]) {
|
||||||
|
window.location.hash = "#chat";
|
||||||
|
switchSection("chat");
|
||||||
|
} else {
|
||||||
|
switchSection(section);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make switchSection globally accessible
|
// Make switchSection globally accessible
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue