ada-web

Ada AI is a specialized coding assistant designed for developers and students. Powered by Google Gemini 3.1, it provides real-time, streamin...

git clone https://github.com/notamitgamer/ada-web.git
· rebuilt hourlyOpen on GitHub
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:
Mbackend.py | 4++--
Mindex.html | 44+++++++++++++++++++++++++++++++-------------
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); }