commit 1ac75c67092a59094fc4b74cbe15b1371d580bfa
parent 2ef94defbe8e552c2c0a9f652f97ceee9cfc7812
Author: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Date: Sun, 18 Jan 2026 07:25:22 +0000
Fix final code review issues: sidebar structure, event handling, and Firestore query
Co-authored-by: notamitgamer <199483577+notamitgamer@users.noreply.github.com>
Diffstat:
2 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/backend.py b/backend.py
@@ -6,7 +6,6 @@ from flask_cors import CORS
import google.generativeai as genai
import firebase_admin
from firebase_admin import credentials, auth, firestore
-from google.cloud.firestore_v1 import FieldFilter, Query
# --- INIT APP & CONFIG ---
app = Flask(__name__)
@@ -241,7 +240,8 @@ def get_chats():
try:
chats_ref = db.collection('users').document(user_uid).collection('chats')
- docs = chats_ref.order_by('updatedAt', direction=Query.DESCENDING).stream()
+ # Order by updatedAt descending (most recent first)
+ docs = chats_ref.order_by('updatedAt', direction='DESCENDING').stream()
chats = []
for doc in docs:
diff --git a/index.html b/index.html
@@ -255,9 +255,25 @@
</div>
</div>
- <!-- HISTORY SIDEBAR (Off-canvas on mobile) -->
- <div id="sidebar" class="absolute inset-y-0 left-0 w-64 bg-black border-r border-white/10 transform -translate-x-full transition-transform duration-300 z-40 md:relative md:translate-x-0 md:w-0 md:border-none md:hidden overflow-hidden">
- <!-- Populated via JS -->
+ <!-- SIDEBAR (Desktop: always visible, Mobile: off-canvas) -->
+ <div id="sidebar" class="fixed inset-y-0 left-0 w-64 bg-[var(--bg-secondary)] border-r border-[var(--border)] transform -translate-x-full transition-transform duration-300 z-40 md:relative md:translate-x-0 md:flex md:flex-col">
+ <!-- Sidebar Header -->
+ <div class="p-4 border-b border-[var(--border)] md:flex hidden">
+ <button onclick="newChat()" class="w-full flex items-center justify-center gap-2 bg-[var(--accent-primary)] text-white py-2 px-4 rounded-lg hover:bg-[var(--accent-secondary)] transition-smooth font-medium text-sm">
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path></svg>
+ New Chat
+ </button>
+ </div>
+
+ <!-- Search -->
+ <div class="p-4 border-b border-[var(--border)] hidden md:block">
+ <input type="text" id="search-chats" placeholder="Search chats..." class="w-full bg-[var(--bg-tertiary)] border border-[var(--border)] rounded-lg px-3 py-2 text-sm text-[var(--text-primary)] placeholder-[var(--text-secondary)] focus:border-[var(--accent-primary)] outline-none transition-smooth">
+ </div>
+
+ <!-- Chat History List -->
+ <div id="chat-history" class="flex-1 overflow-y-auto p-2">
+ <!-- Populated via JS -->
+ </div>
</div>
<!-- CHAT AREA -->
@@ -492,7 +508,7 @@
<div class="code-block-header">
<span class="code-block-lang">${language}</span>
<div class="code-block-actions">
- <button class="code-block-btn" onclick="copyCodeBlock('${codeId}')">
+ <button class="code-block-btn" onclick="copyCodeBlock('${codeId}', event)">
<svg class="w-3 h-3 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
Copy
</button>
@@ -513,7 +529,7 @@
marked.setOptions({ renderer: renderer });
// Code block utility functions
- window.copyCodeBlock = async function(codeId) {
+ window.copyCodeBlock = async function(codeId, event) {
const codeElement = document.getElementById(codeId);
if (!codeElement) return;
@@ -521,14 +537,16 @@
try {
await navigator.clipboard.writeText(code);
// Show success feedback
- const btn = event.target.closest('button');
- const originalText = btn.innerHTML;
- btn.innerHTML = '<svg class="w-3 h-3 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>Copied!';
- btn.classList.add('success');
- setTimeout(() => {
- btn.innerHTML = originalText;
- btn.classList.remove('success');
- }, 2000);
+ const btn = event ? event.target.closest('button') : null;
+ if (btn) {
+ const originalText = btn.innerHTML;
+ btn.innerHTML = '<svg class="w-3 h-3 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>Copied!';
+ btn.classList.add('success');
+ setTimeout(() => {
+ btn.innerHTML = originalText;
+ btn.classList.remove('success');
+ }, 2000);
+ }
} catch (err) {
console.error('Failed to copy:', err);
}