ada-web

Ada AI is a specialized coding...
Log | Files | Refs | README | LICENSE

indexbackup_21-01-2026_01.html (97222B)


      1 <!DOCTYPE html>
      2 <html lang="en" class="dark">
      3 <head>
      4     <meta charset="UTF-8">
      5     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
      6     <title>Ada AI</title>
      7 <link rel="icon" type="image/png" href="logo.png">
      8 
      9     
     10     <!-- Tailwind CSS -->
     11     <script src="https://cdn.tailwindcss.com"></script>
     12     <script>
     13         tailwind.config = {
     14             darkMode: 'class',
     15             theme: {
     16                 extend: {
     17                     colors: {
     18                         gemini: {
     19                             bg: '#131314',        // Deepest charcoal
     20                             surface: '#1E1F20',   // Sidebar/Panels
     21                             surfaceHover: '#28292A',
     22                             accent: '#444746',    // Borders/Icons
     23                             text: '#E3E3E3',      // Primary text
     24                             textSecondary: '#C4C7C5',
     25                             blue: '#A8C7FA',      // Google Blue
     26                             purple: '#D0BCFF'     // Google Purple
     27                         }
     28                     },
     29                     fontFamily: {
     30                         sans: ['Inter', 'sans-serif'],
     31                         mono: ['JetBrains Mono', 'monospace'],
     32                     },
     33                     animation: {
     34                         'fade-in': 'fadeIn 0.4s ease-out forwards',
     35                         'slide-up': 'slideUp 0.5s cubic-bezier(0.2, 0.0, 0, 1.0) forwards',
     36                         'spin-slow-entry': 'spinSlowEntry 1.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards',
     37                         'shimmer': 'shimmer 2s linear infinite',
     38                     },
     39                     keyframes: {
     40                         fadeIn: {
     41                             '0%': { opacity: '0' },
     42                             '100%': { opacity: '1' },
     43                         },
     44                         slideUp: {
     45                             '0%': { opacity: '0', transform: 'translateY(20px)' },
     46                             '100%': { opacity: '1', transform: 'translateY(0)' },
     47                         },
     48                         spinSlowEntry: {
     49                             '0%': { opacity: '0', transform: 'rotate(-180deg) scale(0.5)' },
     50                             '100%': { opacity: '1', transform: 'rotate(0deg) scale(1)' }
     51                         },
     52                         shimmer: {
     53                             '0%': { backgroundPosition: '-1000px 0' },
     54                             '100%': { backgroundPosition: '1000px 0' }
     55                         }
     56                     }
     57                 }
     58             }
     59         }
     60     </script>
     61 
     62     <!-- Google Fonts -->
     63     <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
     64     
     65     <!-- Icons -->
     66     <script src="https://unpkg.com/lucide@latest"></script>
     67     <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
     68 
     69     <!-- CodeMirror (Editor) -->
     70     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css">
     71     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/theme/dracula.min.css">
     72     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js"></script>
     73     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/javascript/javascript.min.js"></script>
     74     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/python/python.min.js"></script>
     75     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/xml/xml.min.js"></script>
     76     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/css/css.min.js"></script>
     77 
     78     <!-- Firebase SDKs -->
     79     <script src="https://www.gstatic.com/firebasejs/10.7.1/firebase-app-compat.js"></script>
     80     <script src="https://www.gstatic.com/firebasejs/10.7.1/firebase-auth-compat.js"></script>
     81     <script src="https://www.gstatic.com/firebasejs/10.7.1/firebase-firestore-compat.js"></script>
     82 
     83     <style>
     84         body {
     85             background-color: #131314;
     86             color: #E3E3E3;
     87             font-family: 'Inter', sans-serif;
     88             overflow: hidden;
     89             -webkit-font-smoothing: antialiased;
     90         }
     91 
     92         /* Custom Scrollbar */
     93         ::-webkit-scrollbar { width: 6px; height: 6px; }
     94         ::-webkit-scrollbar-track { background: transparent; }
     95         ::-webkit-scrollbar-thumb { background: #444746; border-radius: 3px; }
     96         ::-webkit-scrollbar-thumb:hover { background: #5E5E5E; }
     97 
     98         /* Prose / Markdown Styles */
     99         .prose p { margin-bottom: 0.8rem; line-height: 1.6; color: #E3E3E3; font-weight: 300; }
    100         .prose strong { color: #fff; font-weight: 600; }
    101         .prose ul { list-style-type: disc; padding-left: 1.5rem; margin-bottom: 1rem; }
    102         .prose ol { list-style-type: decimal; padding-left: 1.5rem; margin-bottom: 1rem; }
    103         .prose code {
    104             font-family: 'JetBrains Mono', monospace;
    105             background: #28292A;
    106             padding: 2px 6px;
    107             border-radius: 4px;
    108             color: #A8C7FA;
    109             font-size: 0.85em;
    110         }
    111         .prose pre { display: none; } /* Hidden in chat, shown in Artifact Panel */
    112         .prose h1, .prose h2, .prose h3 { margin-top: 1.5rem; margin-bottom: 0.5rem; font-weight: 500; color: white; }
    113         .prose a { color: #A8C7FA; text-decoration: none; }
    114         .prose a:hover { text-decoration: underline; }
    115 
    116         /* Message Bubbles */
    117         .msg-user {
    118             background-color: #28292A;
    119             color: #E3E3E3;
    120             border-radius: 20px;
    121             padding: 12px 20px;
    122             max-width: 80%;
    123             font-weight: 400;
    124         }
    125         .msg-ai {
    126             background: transparent;
    127             color: #E3E3E3;
    128             padding: 0;
    129             max-width: 100%;
    130         }
    131 
    132         /* Code Block Card in Chat */
    133         .code-card {
    134             background: #1E1F20;
    135             border: 1px solid #444746;
    136             border-radius: 12px;
    137             overflow: hidden;
    138             margin: 1rem 0;
    139             transition: all 0.2s;
    140             cursor: pointer;
    141             position: relative;
    142         }
    143         .code-card:hover { 
    144             border-color: #A8C7FA; 
    145             transform: translateY(-1px);
    146         }
    147 
    148         /* CodeMirror Customization */
    149         .CodeMirror {
    150             height: 100% !important;
    151             font-family: 'JetBrains Mono', monospace;
    152             font-size: 14px;
    153             background-color: #1e1e1e !important;
    154         }
    155         .cm-s-dracula.CodeMirror {
    156             background-color: #1e1e1e !important;
    157         }
    158 
    159         /* Typing Indicator */
    160         .typing-dot {
    161             width: 6px; height: 6px;
    162             background: #E3E3E3;
    163             border-radius: 50%;
    164             animation: bounce 1.4s infinite ease-in-out both;
    165         }
    166         .typing-dot:nth-child(1) { animation-delay: -0.32s; }
    167         .typing-dot:nth-child(2) { animation-delay: -0.16s; }
    168         @keyframes bounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } }
    169 
    170         /* Mobile Height Fix */
    171         .mobile-height { height: 100vh; height: calc(var(--vh, 1vh) * 100); }
    172 
    173         /* Hide Scrollbar for Inputs */
    174         .no-scrollbar::-webkit-scrollbar { display: none; }
    175         .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
    176 
    177         /* Drawer Transitions */
    178         .drawer { transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); }
    179         
    180         /* Custom Ada Icon Animation */
    181         .ada-icon path { transform-origin: center; }
    182 
    183         /* Shimmer Effect for Skeletons */
    184         .skeleton-shimmer {
    185             background: #1E1F20;
    186             background-image: linear-gradient(to right, #1E1F20 0%, #28292A 20%, #1E1F20 40%, #1E1F20 100%);
    187             background-repeat: no-repeat;
    188             background-size: 1000px 100%;
    189             animation: shimmer 1.5s infinite linear forwards;
    190         }
    191 
    192         /* Context Menu */
    193         .context-menu {
    194             position: fixed; /* Changed from absolute to fixed for better mobile handling */
    195             background: #28292A;
    196             border: 1px solid #444746;
    197             border-radius: 12px; /* Slightly more rounded */
    198             padding: 4px;
    199             z-index: 9999;
    200             box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
    201             min-width: 180px;
    202             animation: menuFadeIn 0.15s ease-out;
    203         }
    204         @keyframes menuFadeIn {
    205             from { opacity: 0; transform: scale(0.95); }
    206             to { opacity: 1; transform: scale(1); }
    207         }
    208         .context-menu-item {
    209             display: flex;
    210             align-items: center;
    211             gap: 12px;
    212             padding: 12px 16px; /* Larger tap targets for mobile */
    213             cursor: pointer;
    214             border-radius: 8px;
    215             color: #E3E3E3;
    216             font-size: 14px;
    217             transition: background 0.2s;
    218         }
    219         .context-menu-item:hover {
    220             background: #3C4043;
    221         }
    222         .context-menu-item.danger { color: #ff8b8b; }
    223         .context-menu-item.danger:hover { background: rgba(255, 139, 139, 0.1); }
    224 
    225         /* Custom Switch (From Uiverse.io by Galahhad) */
    226         .switch {
    227             /* switch */
    228             --switch-width: 46px;
    229             --switch-height: 24px;
    230             --switch-bg: rgb(68, 71, 70);
    231             --switch-checked-bg: #A8C7FA;
    232             --switch-offset: calc((var(--switch-height) - var(--circle-diameter)) / 2);
    233             --switch-transition: all .2s cubic-bezier(0.27, 0.2, 0.25, 1.51);
    234             /* circle */
    235             --circle-diameter: 18px;
    236             --circle-bg: #fff;
    237             --circle-shadow: 1px 1px 2px rgba(146, 146, 146, 0.45);
    238             --circle-checked-shadow: -1px 1px 2px rgba(163, 163, 163, 0.45);
    239             --circle-transition: var(--switch-transition);
    240             /* icon */
    241             --icon-transition: all .2s cubic-bezier(0.27, 0.2, 0.25, 1.51);
    242             --icon-cross-color: var(--switch-bg);
    243             --icon-cross-size: 6px;
    244             --icon-checkmark-color: var(--switch-checked-bg);
    245             --icon-checkmark-size: 10px;
    246             /* effect line */
    247             --effect-width: calc(var(--circle-diameter) / 2);
    248             --effect-height: calc(var(--effect-width) / 2 - 1px);
    249             --effect-bg: var(--circle-bg);
    250             --effect-border-radius: 1px;
    251             --effect-transition: all .2s ease-in-out;
    252             
    253             display: inline-block;
    254             position: relative;
    255         }
    256 
    257         .switch input { display: none; }
    258 
    259         .switch svg {
    260             -webkit-transition: var(--icon-transition);
    261             -o-transition: var(--icon-transition);
    262             transition: var(--icon-transition);
    263             position: absolute;
    264             height: auto;
    265         }
    266 
    267         .switch .checkmark {
    268             width: var(--icon-checkmark-size);
    269             color: var(--icon-checkmark-color);
    270             -webkit-transform: scale(0);
    271             -ms-transform: scale(0);
    272             transform: scale(0);
    273         }
    274 
    275         .switch .cross {
    276             width: var(--icon-cross-size);
    277             color: var(--icon-cross-color);
    278         }
    279 
    280         .slider {
    281             -webkit-box-sizing: border-box;
    282             box-sizing: border-box;
    283             width: var(--switch-width);
    284             height: var(--switch-height);
    285             background: var(--switch-bg);
    286             border-radius: 999px;
    287             display: -webkit-box;
    288             display: -ms-flexbox;
    289             display: flex;
    290             -webkit-box-align: center;
    291             -ms-flex-align: center;
    292             align-items: center;
    293             position: relative;
    294             -webkit-transition: var(--switch-transition);
    295             -o-transition: var(--switch-transition);
    296             transition: var(--switch-transition);
    297             cursor: pointer;
    298         }
    299 
    300         .circle {
    301             width: var(--circle-diameter);
    302             height: var(--circle-diameter);
    303             background: var(--circle-bg);
    304             border-radius: inherit;
    305             -webkit-box-shadow: var(--circle-shadow);
    306             box-shadow: var(--circle-shadow);
    307             display: -webkit-box;
    308             display: -ms-flexbox;
    309             display: flex;
    310             -webkit-box-align: center;
    311             -ms-flex-align: center;
    312             align-items: center;
    313             -webkit-box-pack: center;
    314             -ms-flex-pack: center;
    315             justify-content: center;
    316             -webkit-transition: var(--circle-transition);
    317             -o-transition: var(--circle-transition);
    318             transition: var(--circle-transition);
    319             z-index: 1;
    320             position: absolute;
    321             left: var(--switch-offset);
    322         }
    323 
    324         .slider::before {
    325             content: "";
    326             position: absolute;
    327             width: var(--effect-width);
    328             height: var(--effect-height);
    329             left: calc(var(--switch-offset) + (var(--effect-width) / 2));
    330             background: var(--effect-bg);
    331             border-radius: var(--effect-border-radius);
    332             -webkit-transition: var(--effect-transition);
    333             -o-transition: var(--effect-transition);
    334             transition: var(--effect-transition);
    335         }
    336 
    337         .switch input:checked+.slider {
    338             background: var(--switch-checked-bg);
    339         }
    340 
    341         .switch input:checked+.slider .checkmark {
    342             -webkit-transform: scale(1);
    343             -ms-transform: scale(1);
    344             transform: scale(1);
    345         }
    346 
    347         .switch input:checked+.slider .cross {
    348             -webkit-transform: scale(0);
    349             -ms-transform: scale(0);
    350             transform: scale(0);
    351         }
    352 
    353         .switch input:checked+.slider::before {
    354             left: calc(100% - var(--effect-width) - (var(--effect-width) / 2) - var(--switch-offset));
    355         }
    356 
    357         .switch input:checked+.slider .circle {
    358             left: calc(100% - var(--circle-diameter) - var(--switch-offset));
    359             -webkit-box-shadow: var(--circle-checked-shadow);
    360             box-shadow: var(--circle-checked-shadow);
    361         }
    362         
    363         /* Command Palette */
    364         #command-palette {
    365             transition: opacity 0.15s ease-out;
    366         }
    367         .cmd-item {
    368             display: flex;
    369             align-items: center;
    370             justify-content: space-between;
    371             padding: 10px 16px;
    372             cursor: pointer;
    373             border-radius: 8px;
    374             color: #E3E3E3;
    375         }
    376         .cmd-item:hover, .cmd-item.selected {
    377             background: #28292A;
    378         }
    379         .cmd-shortcut {
    380             font-size: 10px;
    381             background: #3C4043;
    382             padding: 2px 6px;
    383             border-radius: 4px;
    384             color: #C4C7C5;
    385             font-family: sans-serif;
    386         }
    387     </style>
    388 </head>
    389 <body class="mobile-height flex text-sm selection:bg-gemini-blue selection:text-black bg-gemini-bg">
    390 
    391     <!-- SVG Definitions -->
    392     <svg style="display: none;">
    393         <symbol id="icon-ada" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
    394             <defs>
    395                 <linearGradient id="ada-gradient" x1="0" y1="0" x2="24" y2="24" gradientUnits="userSpaceOnUse">
    396                     <stop offset="0%" stop-color="#4facfe" />
    397                     <stop offset="50%" stop-color="#00f2fe" />
    398                     <stop offset="100%" stop-color="#a8c7fa" />
    399                 </linearGradient>
    400             </defs>
    401             <path d="M12 2L14.4 9.6L22 12L14.4 14.4L12 22L9.6 14.4L2 12L9.6 9.6L12 2Z" fill="url(#ada-gradient)" />
    402             <path d="M12 6L13.2 10.8L18 12L13.2 13.2L12 18L10.8 13.2L6 12L10.8 10.8L12 6Z" fill="white" fill-opacity="0.3" />
    403         </symbol>
    404     </svg>
    405 
    406     <!-- Full Screen Loading/Verifying Overlay -->
    407     <div id="loading-overlay" class="fixed inset-0 z-[200] flex flex-col items-center justify-center bg-[#131314] transition-opacity duration-500">
    408         <div class="w-16 h-16 mb-4 relative">
    409             <div class="absolute inset-0 bg-blue-500/20 blur-xl rounded-full"></div>
    410             <svg class="w-full h-full animate-spin-slow-entry"><use href="#icon-ada"></use></svg>
    411         </div>
    412         <p class="text-gemini-textSecondary text-sm font-medium animate-pulse">Verifying Identity...</p>
    413     </div>
    414 
    415     <!-- Command Palette -->
    416     <div id="command-palette" class="fixed inset-0 z-[150] bg-black/50 backdrop-blur-sm hidden flex items-start justify-center pt-24 opacity-0 pointer-events-none">
    417         <div class="bg-gemini-surface w-full max-w-lg rounded-xl shadow-2xl border border-gemini-surfaceHover overflow-hidden flex flex-col max-h-[60vh]">
    418             <div class="p-4 border-b border-gemini-surfaceHover flex items-center gap-3">
    419                 <i data-lucide="search" class="w-5 h-5 text-gemini-textSecondary"></i>
    420                 <input type="text" id="cmd-input" class="bg-transparent border-none outline-none text-white w-full placeholder-gemini-textSecondary/50" placeholder="Type a command...">
    421                 <span class="text-xs text-gemini-textSecondary border border-gemini-surfaceHover px-1.5 py-0.5 rounded">ESC</span>
    422             </div>
    423             <div id="cmd-list" class="p-2 overflow-y-auto">
    424                 <!-- Commands injected via JS -->
    425             </div>
    426         </div>
    427     </div>
    428 
    429     <!-- Confirm Dialog -->
    430     <div id="confirm-modal" class="fixed inset-0 z-[210] flex items-center justify-center bg-black/70 backdrop-blur-sm hidden opacity-0 transition-opacity">
    431         <div class="bg-gemini-surface p-6 rounded-2xl w-full max-w-sm border border-gemini-surfaceHover transform scale-95 transition-transform" id="confirm-modal-content">
    432             <h3 class="text-lg font-semibold text-white mb-2" id="confirm-title">Confirm</h3>
    433             <p class="text-gemini-textSecondary text-sm mb-4" id="confirm-message">Are you sure?</p>
    434             
    435             <div id="confirm-input-container" class="hidden mb-4">
    436                 <label class="block text-xs text-gemini-textSecondary mb-1">Type <span class="font-mono text-white select-all" id="confirm-match-text"></span> to confirm:</label>
    437                 <input type="text" id="confirm-input" class="w-full bg-[#131314] border border-gemini-surfaceHover rounded-lg p-2 text-white text-sm focus:outline-none focus:border-gemini-blue" placeholder="">
    438             </div>
    439 
    440             <div class="flex justify-end gap-3">
    441                 <button onclick="closeConfirmModal()" class="px-4 py-2 rounded-lg text-gemini-textSecondary hover:text-white hover:bg-gemini-surfaceHover transition-colors">Cancel</button>
    442                 <button id="confirm-action-btn" class="px-4 py-2 rounded-lg bg-red-500/10 text-red-400 hover:bg-red-500/20 transition-colors font-medium">Confirm</button>
    443             </div>
    444         </div>
    445     </div>
    446 
    447     <!-- Toast Notification (Custom Popups) -->
    448     <div id="toast" class="fixed bottom-24 md:bottom-10 left-1/2 -translate-x-1/2 bg-gemini-surface border border-gemini-surfaceHover text-white px-6 py-3 rounded-full shadow-2xl z-[220] transition-all duration-300 transform translate-y-20 opacity-0 pointer-events-none flex items-center gap-2">
    449         <i data-lucide="info" class="w-4 h-4 text-gemini-blue"></i>
    450         <span id="toast-message" class="text-sm font-medium">Notification</span>
    451     </div>
    452 
    453     <!-- Auth Modal (Updated for Multi-Auth) -->
    454     <div id="auth-modal" class="fixed inset-0 z-[100] flex items-center justify-center bg-[#131314] transition-opacity duration-300 hidden opacity-0 pointer-events-none">
    455         <div class="w-full max-w-md p-8 text-center bg-[#131314] rounded-2xl md:bg-[#131314] md:border-none relative max-h-[90vh] overflow-y-auto">
    456             <div class="mx-auto w-20 h-20 mb-6 rounded-full bg-gemini-surface flex items-center justify-center relative overflow-hidden group">
    457                 <div class="absolute inset-0 bg-gradient-to-tr from-blue-500/20 to-purple-500/20 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
    458                 <svg class="w-10 h-10 animate-spin-slow-entry drop-shadow-lg"><use href="#icon-ada"></use></svg>
    459             </div>
    460             <h1 class="text-3xl font-medium text-white mb-3">Welcome to Ada</h1>
    461             <p class="text-gemini-textSecondary mb-8">Sign in to access your coding workspace.</p>
    462             
    463             
    464             <!-- Google -->
    465             <button onclick="signInWithGoogle()" class="w-full bg-white text-[#131314] hover:bg-gray-100 font-medium py-3 px-6 rounded-full flex items-center justify-center gap-3 transition-colors mb-3">
    466                 <img src="https://www.google.com/favicon.ico" class="w-5 h-5" alt="G">
    467                 <span>Sign In with Google</span>
    468             </button>
    469             <br>
    470 <!-- Divider -->
    471             <div class="relative mb-6">
    472                 <div class="absolute inset-0 flex items-center"><div class="w-full border-t border-gemini-surfaceHover"></div></div>
    473                 <div class="relative flex justify-center text-sm"><span class="px-2 bg-[#131314] text-gemini-textSecondary">Or continue with</span></div>
    474             </div>
    475             <!-- Guest -->
    476             <button onclick="signInAsGuest()" class="w-full bg-[#3C4043] text-white hover:bg-[#494c50] font-medium py-3 px-6 rounded-full flex items-center justify-center gap-3 transition-colors">
    477                 <i data-lucide="user" class="w-5 h-5"></i>
    478                 <span>Continue as Guest</span>
    479             </button>
    480         </div>
    481     </div>
    482 
    483     <!-- Profile Modal -->
    484     <div id="profile-modal" onclick="toggleProfileModal()" class="fixed inset-0 z-[110] flex items-center justify-center bg-black/60 backdrop-blur-sm transition-opacity duration-300 hidden opacity-0 pointer-events-none">
    485         <div onclick="event.stopPropagation()" class="w-full max-w-sm bg-gemini-surface p-6 rounded-2xl shadow-2xl border border-gemini-surfaceHover transform scale-95 transition-transform duration-300" id="profile-modal-content">
    486             <div class="flex flex-col items-center">
    487                 <div class="w-20 h-20 rounded-full bg-gradient-to-tr from-blue-500 to-purple-500 flex items-center justify-center text-2xl font-bold text-white mb-4 overflow-hidden border-4 border-gemini-surfaceHover relative shadow-lg">
    488                     <img id="profile-avatar" class="w-full h-full object-cover hidden" src="" alt="User">
    489                     <span id="profile-initial">U</span>
    490                 </div>
    491                 <h2 id="profile-name" class="text-xl font-semibold text-white">User Name</h2>
    492                 <p id="profile-email" class="text-sm text-gemini-textSecondary mb-6 break-all text-center">user@example.com</p>
    493                 
    494                 <div class="w-full grid grid-cols-2 gap-3 mb-6">
    495                     <div class="bg-gemini-bg p-3 rounded-xl border border-gemini-surfaceHover text-center">
    496                         <span class="block text-xs text-gemini-textSecondary uppercase tracking-wider mb-1">Status</span>
    497                         <span class="text-sm text-white font-medium">Free</span>
    498                     </div>
    499                     <div class="bg-gemini-bg p-3 rounded-xl border border-gemini-surfaceHover text-center">
    500                         <span class="block text-xs text-gemini-textSecondary uppercase tracking-wider mb-1">Joined</span>
    501                         <span class="text-sm text-white font-medium">Jan '26</span>
    502                     </div>
    503                 </div>
    504 
    505                 <button onclick="confirmSignOut()" class="w-full bg-[#3C4043] hover:bg-[#494c50] text-white py-2.5 rounded-full flex items-center justify-center gap-2 transition-colors font-medium">
    506                     <i data-lucide="log-out" class="w-4 h-4"></i>
    507                     Sign Out
    508                 </button>
    509             </div>
    510         </div>
    511     </div>
    512 
    513     <!-- Settings Modal -->
    514     <div id="settings-modal" onclick="toggleSettingsModal()" class="fixed inset-0 z-[110] flex items-center justify-center bg-black/60 backdrop-blur-sm transition-opacity duration-300 hidden opacity-0 pointer-events-none">
    515         <div onclick="event.stopPropagation()" class="w-full max-w-md bg-gemini-surface p-6 rounded-2xl shadow-2xl border border-gemini-surfaceHover transform scale-95 transition-transform duration-300 max-h-[85vh] overflow-y-auto" id="settings-modal-content">
    516             <div class="flex items-center justify-between mb-6 border-b border-gemini-surfaceHover pb-4">
    517                 <h2 class="text-xl font-semibold text-white">Settings</h2>
    518                 <button onclick="toggleSettingsModal()" class="text-gemini-textSecondary hover:text-white p-1 rounded-full hover:bg-gemini-surfaceHover transition-colors">
    519                     <i data-lucide="x" class="w-5 h-5"></i>
    520                 </button>
    521             </div>
    522             
    523             <div class="space-y-2">
    524                 <!-- Chat Sharing -->
    525                 <div class="p-3 hover:bg-gemini-surfaceHover rounded-xl transition-colors cursor-pointer flex items-center justify-between group">
    526                     <div class="flex items-center gap-3">
    527                         <div class="p-2 bg-purple-500/10 rounded-lg text-purple-400 group-hover:bg-purple-500/20"><i data-lucide="share-2" class="w-4 h-4"></i></div>
    528                         <div>
    529                             <h3 class="text-white text-sm font-medium">Chat Sharing</h3>
    530                             <p class="text-xs text-gemini-textSecondary">Allow public links</p>
    531                         </div>
    532                     </div>
    533                     <!-- Custom Toggle UI -->
    534                     <label class="switch">
    535                         <input type="checkbox" id="share-toggle-checkbox" onchange="toggleShareSetting(this)">
    536                         <div class="slider">
    537                             <div class="circle">
    538                                 <svg class="cross" xml:space="preserve" style="enable-background:new 0 0 512 512" viewBox="0 0 365.696 365.696" y="0" x="0" height="6" width="6" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns="http://www.w3.org/2000/svg">
    539                                     <g>
    540                                         <path data-original="#000000" fill="currentColor" d="M243.188 182.86 356.32 69.726c12.5-12.5 12.5-32.766 0-45.247L341.238 9.398c-12.504-12.503-32.77-12.503-45.25 0L182.86 122.528 69.727 9.374c-12.5-12.5-32.766-12.5-45.247 0L9.375 24.457c-12.5 12.504-12.5 32.77 0 45.25l113.152 113.152L9.398 295.99c-12.503 12.503-12.503 32.769 0 45.25L24.48 356.32c12.5 12.5 32.766 12.5 45.247 0l113.132-113.132L295.99 356.32c12.503 12.5 32.769 12.5 45.25 0l15.081-15.082c12.5-12.504 12.5-32.77 0-45.25zm0 0"></path>
    541                                     </g>
    542                                 </svg>
    543                                 <svg class="checkmark" xml:space="preserve" style="enable-background:new 0 0 512 512" viewBox="0 0 24 24" y="0" x="0" height="10" width="10" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns="http://www.w3.org/2000/svg">
    544                                     <g>
    545                                         <path class="" data-original="#000000" fill="currentColor" d="M9.707 19.121a.997.997 0 0 1-1.414 0l-5.646-5.647a1.5 1.5 0 0 1 0-2.121l.707-.707a1.5 1.5 0 0 1 2.121 0L9 14.171l9.525-9.525a1.5 1.5 0 0 1 2.121 0l.707.707a1.5 1.5 0 0 1 0 2.121z"></path>
    546                                     </g>
    547                                 </svg>
    548                             </div>
    549                         </div>
    550                     </label>
    551                 </div>
    552 
    553                 <!-- Font Size -->
    554                 <div class="p-3 hover:bg-gemini-surfaceHover rounded-xl transition-colors flex items-center justify-between group">
    555                     <div class="flex items-center gap-3">
    556                         <div class="p-2 bg-gray-500/10 rounded-lg text-gray-400 group-hover:bg-gray-500/20"><i data-lucide="type" class="w-4 h-4"></i></div>
    557                         <div>
    558                             <h3 class="text-white text-sm font-medium">Font Size</h3>
    559                             <p class="text-xs text-gemini-textSecondary">Adjust readability</p>
    560                         </div>
    561                     </div>
    562                     <div class="flex items-center gap-2 bg-gemini-bg p-1 rounded-lg border border-gemini-surfaceHover">
    563                         <button onclick="changeFontSize(-1)" class="p-1 hover:bg-gemini-surfaceHover rounded text-gemini-textSecondary hover:text-white"><i data-lucide="minus" class="w-3 h-3"></i></button>
    564                         <span id="font-size-display" class="text-xs font-mono w-4 text-center">14</span>
    565                         <button onclick="changeFontSize(1)" class="p-1 hover:bg-gemini-surfaceHover rounded text-gemini-textSecondary hover:text-white"><i data-lucide="plus" class="w-3 h-3"></i></button>
    566                     </div>
    567                 </div>
    568 
    569                 <div class="h-px bg-gemini-surfaceHover my-2"></div>
    570 
    571                 <!-- Help & Support -->
    572                 <a href="https://github.com/notamitgamer/ada-web/issues" target="_blank" class="p-3 hover:bg-gemini-surfaceHover rounded-xl transition-colors cursor-pointer flex items-center gap-3 group">
    573                     <div class="p-2 bg-green-500/10 rounded-lg text-green-400 group-hover:bg-green-500/20"><i data-lucide="help-circle" class="w-4 h-4"></i></div>
    574                     <div>
    575                         <h3 class="text-white text-sm font-medium">Help & Support</h3>
    576                         <p class="text-xs text-gemini-textSecondary">Report bugs or request features</p>
    577                     </div>
    578                     <i data-lucide="external-link" class="w-4 h-4 text-gemini-textSecondary ml-auto"></i>
    579                 </a>
    580 
    581                 <!-- Contribute -->
    582                 <a href="https://github.com/notamitgamer/ada-web" target="_blank" class="p-3 hover:bg-gemini-surfaceHover rounded-xl transition-colors cursor-pointer flex items-center gap-3 group">
    583                     <div class="p-2 bg-orange-500/10 rounded-lg text-orange-400 group-hover:bg-orange-500/20"><i data-lucide="git-branch" class="w-4 h-4"></i></div>
    584                     <div>
    585                         <h3 class="text-white text-sm font-medium">Contribute</h3>
    586                         <p class="text-xs text-gemini-textSecondary">Fork repo & submit PRs</p>
    587                     </div>
    588                     <i data-lucide="external-link" class="w-4 h-4 text-gemini-textSecondary ml-auto"></i>
    589                 </a>
    590 
    591                 <!-- Developer Contact -->
    592                 <a href="mailto:amitdutta4255@gmail.com?subject=Ada%20AI%20Critical%20Support" class="p-3 hover:bg-gemini-surfaceHover rounded-xl transition-colors cursor-pointer flex items-center gap-3 group">
    593                     <div class="p-2 bg-red-500/10 rounded-lg text-red-400 group-hover:bg-red-500/20"><i data-lucide="alert-circle" class="w-4 h-4"></i></div>
    594                     <div>
    595                         <h3 class="text-white text-sm font-medium">Critical Support</h3>
    596                         <p class="text-xs text-gemini-textSecondary">Contact developer directly</p>
    597                     </div>
    598                 </a>
    599 
    600                 <!-- General Feedback -->
    601                 <a href="mailto:mail@amit.is-a.dev?subject=Ada%20AI%20Feedback" class="p-3 hover:bg-gemini-surfaceHover rounded-xl transition-colors cursor-pointer flex items-center gap-3 group">
    602                     <div class="p-2 bg-yellow-500/10 rounded-lg text-yellow-400 group-hover:bg-yellow-500/20"><i data-lucide="message-square" class="w-4 h-4"></i></div>
    603                     <div>
    604                         <h3 class="text-white text-sm font-medium">Send Feedback</h3>
    605                         <p class="text-xs text-gemini-textSecondary">Suggestions & improvements</p>
    606                     </div>
    607                 </a>
    608 
    609                 <div class="h-px bg-gemini-surfaceHover my-2"></div>
    610 
    611                 <!-- Terms -->
    612                 <a href="/terms.html" class="p-3 hover:bg-gemini-surfaceHover rounded-xl transition-colors cursor-pointer flex items-center gap-3 group">
    613                     <div class="p-2 bg-gray-500/10 rounded-lg text-gray-400 group-hover:bg-gray-500/20"><i data-lucide="file-text" class="w-4 h-4"></i></div>
    614                     <div>
    615                         <h3 class="text-white text-sm font-medium">Terms & Conditions</h3>
    616                         <p class="text-xs text-gemini-textSecondary">Usage policies</p>
    617                     </div>
    618                 </a>
    619 		<!-- Docs -->
    620                 <a href="/docs.html" class="p-3 hover:bg-gemini-surfaceHover rounded-xl transition-colors cursor-pointer flex items-center gap-3 group">
    621                     <div class="p-2 bg-gray-500/10 rounded-lg text-gray-400 group-hover:bg-gray-500/20"><i data-lucide="file-text" class="w-4 h-4"></i></div>
    622                     <div>
    623                         <h3 class="text-white text-sm font-medium">Docs</h3>
    624                         <p class="text-xs text-gemini-textSecondary">Service Documentation</p>
    625                     </div>
    626                 </a>
    627 
    628                 <!-- Delete History -->
    629                 <button onclick="confirmClearHistory()" class="w-full p-3 hover:bg-red-500/10 rounded-xl transition-colors cursor-pointer flex items-center gap-3 group text-left">
    630                     <div class="p-2 bg-red-500/10 rounded-lg text-red-400 group-hover:bg-red-500/20"><i data-lucide="trash-2" class="w-4 h-4"></i></div>
    631                     <div>
    632                         <h3 class="text-red-400 text-sm font-medium">Clear Activity</h3>
    633                         <p class="text-xs text-gemini-textSecondary">Remove local session data</p>
    634                     </div>
    635                 </button>
    636 
    637                 <p class="text-center text-xs text-gemini-textSecondary pt-4 font-mono">Ada AI v1.4.0 • <a href="https://github.com/notamitgamer" class="hover:text-white underline">@notamitgamer</a></p>
    638             </div>
    639         </div>
    640     </div>
    641 
    642     <!-- Sidebar (Collapsible Drawer on ALL screens) -->
    643     <aside id="sidebar" class="bg-gemini-surface w-[280px] flex-shrink-0 flex flex-col border-r border-gemini-surfaceHover fixed inset-y-0 left-0 transform -translate-x-full z-[60] drawer shadow-2xl">
    644         <!-- Sidebar Header -->
    645         <div class="h-16 flex items-center justify-between px-4">
    646             <button onclick="toggleSidebar()" class="p-2 text-gemini-textSecondary hover:text-white hover:bg-gemini-surfaceHover rounded-full transition-colors">
    647                 <i data-lucide="menu" class="w-5 h-5"></i>
    648             </button>
    649             <span id="history-label" class="text-gemini-textSecondary text-xs font-medium uppercase tracking-wider">History</span>
    650             
    651             <div id="history-search-container" class="relative w-full max-w-[140px] ml-4">
    652                <input type="text" id="history-search" placeholder="Search..." oninput="filterHistory(this.value)" class="w-full bg-[#131314] text-xs text-white border border-gemini-surfaceHover rounded-md px-2 py-1 focus:outline-none focus:border-gemini-blue">
    653                <i data-lucide="search" class="absolute right-2 top-1.5 w-3 h-3 text-gemini-textSecondary"></i>
    654             </div>
    655         </div>
    656 
    657         <!-- New Chat Button -->
    658         <div class="px-3 mb-2">
    659             <button onclick="startNewChat()" class="w-full bg-gemini-surfaceHover hover:bg-[#333537] text-gemini-textSecondary hover:text-white py-3 px-4 rounded-full flex items-center gap-3 transition-colors text-sm font-medium">
    660                 <i data-lucide="plus" class="w-5 h-5"></i>
    661                 <span>New chat</span>
    662             </button>
    663         </div>
    664 
    665         <!-- Chat History List -->
    666         <div id="chat-history-list" class="flex-1 overflow-y-auto px-2 py-2 space-y-1">
    667             <!-- Skeleton Loader injected via JS -->
    668         </div>
    669 
    670         <!-- User Profile (Bottom) -->
    671         <div class="p-4 border-t border-gemini-surfaceHover space-y-1">
    672             <button onclick="toggleSettingsModal()" class="w-full flex items-center gap-3 p-2 hover:bg-gemini-surfaceHover rounded-lg transition-colors text-left text-gemini-textSecondary hover:text-white">
    673                 <i data-lucide="settings" class="w-4 h-4"></i>
    674                 <span class="text-sm font-medium">Settings</span>
    675             </button>
    676             
    677             <button onclick="toggleProfileModal()" class="w-full flex items-center gap-3 p-2 hover:bg-gemini-surfaceHover rounded-lg transition-colors text-left group mt-1">
    678                 <div class="w-7 h-7 rounded-full bg-gradient-to-tr from-blue-500 to-purple-500 flex items-center justify-center text-[10px] font-bold text-white overflow-hidden">
    679                     <img id="user-avatar" class="w-full h-full object-cover hidden" src="" alt="User">
    680                     <span id="user-initial">U</span>
    681                 </div>
    682                 <div class="flex-1 min-w-0">
    683                     <p id="user-email" class="text-xs text-gemini-textSecondary truncate">Not signed in</p>
    684                 </div>
    685             </button>
    686         </div>
    687     </aside>
    688 
    689     <!-- Overlay for Sidebar -->
    690     <div id="sidebar-overlay" onclick="toggleSidebar()" class="fixed inset-0 bg-black/50 z-[55] hidden backdrop-blur-sm transition-opacity"></div>
    691 
    692     <!-- Main Content Area -->
    693     <main class="flex-1 flex flex-col relative w-full h-full min-w-0 bg-gemini-bg">
    694         
    695         <!-- Top Bar (Fixed) -->
    696         <header class="h-16 flex items-center justify-between px-4 md:px-6 sticky top-0 z-30 bg-gemini-bg/80 backdrop-blur-md border-b border-transparent transition-colors">
    697             <div class="flex items-center gap-2">
    698                 <button onclick="toggleSidebar()" class="p-2 -ml-2 text-gemini-textSecondary hover:text-white hover:bg-gemini-surfaceHover rounded-full transition-colors" title="Toggle History">
    699                     <i data-lucide="menu" class="w-6 h-6"></i>
    700                 </button>
    701                 <span class="text-lg font-medium text-white tracking-tight flex items-center gap-2">
    702                     <span class="flex items-center gap-2">
    703                         Ada <span class="text-gemini-blue text-xs font-normal border border-gemini-surfaceHover px-2 py-0.5 rounded-full bg-gemini-surface">Beta</span>
    704                     </span>
    705                 </span>
    706             </div>
    707             
    708             <!-- Code Viewer Toggle & Login Trigger for Shared View -->
    709             <div class="flex items-center gap-2">
    710                 <button id="shared-login-btn" onclick="signInWithGoogle()" class="hidden px-4 py-2 bg-white text-black rounded-full text-sm font-medium hover:bg-gray-200 transition-colors">
    711                     Sign In to Save
    712                 </button>
    713                 
    714                 <button onclick="toggleArtifactPanel()" class="p-2 text-gemini-textSecondary hover:text-gemini-blue relative rounded-full hover:bg-gemini-surfaceHover transition-colors" title="Toggle Code Viewer">
    715                     <i data-lucide="panel-right" class="w-6 h-6"></i>
    716                     <span id="artifact-indicator" class="absolute top-2 right-2 w-2.5 h-2.5 bg-gemini-blue border-2 border-gemini-bg rounded-full hidden shadow-glow"></span>
    717                 </button>
    718             </div>
    719         </header>
    720 
    721         <!-- Chat Container -->
    722         <div id="chat-container" class="flex-1 overflow-y-auto px-4 md:px-0 pb-32 pt-4 scroll-smooth">
    723             <div class="max-w-3xl mx-auto flex flex-col gap-6">
    724                 <!-- Welcome Message -->
    725                 <div id="welcome-message" class="flex flex-col items-start justify-center min-h-[50vh] space-y-8 animate-slide-up px-2">
    726                     <div class="space-y-2 w-full">
    727                         <div class="w-12 h-12 mb-4 animate-spin-slow-entry">
    728                             <svg class="w-full h-full drop-shadow-[0_0_15px_rgba(168,199,250,0.5)]"><use href="#icon-ada"></use></svg>
    729                         </div>
    730                         <h1 class="text-4xl md:text-5xl font-medium text-transparent bg-clip-text bg-gradient-to-r from-[#4285F4] via-[#9B72CB] to-[#D96570] pb-2">
    731                             Hello, <span id="welcome-name" class="text-white truncate block md:inline max-w-[200px] md:max-w-none">Student</span>
    732                         </h1>
    733                         <!-- UPDATED COLOR -->
    734                         <h2 class="text-3xl md:text-5xl font-medium text-gemini-textSecondary/30">How can I help you code today?</h2>
    735                     </div>
    736 
    737                     <!-- Suggestion Chips (Hidden on Mobile) -->
    738                     <div class="hidden md:flex flex-wrap gap-3 w-full" id="suggestion-chips">
    739                         <button onclick="setPrompt('Debug this Python script')" class="group bg-gemini-surface hover:bg-gemini-surfaceHover text-gemini-text px-5 py-4 rounded-2xl text-sm font-medium transition-all text-left flex-1 min-w-[200px] border border-transparent hover:border-gemini-surfaceHover">
    740                             <span class="block mb-1 text-gemini-blue group-hover:translate-x-1 transition-transform"><i data-lucide="bug" class="w-4 h-4 inline mr-1"></i> Debug</span>
    741                             Find errors in code
    742                         </button>
    743                         <button onclick="setPrompt('Explain this concept')" class="group bg-gemini-surface hover:bg-gemini-surfaceHover text-gemini-text px-5 py-4 rounded-2xl text-sm font-medium transition-all text-left flex-1 min-w-[200px] border border-transparent hover:border-gemini-surfaceHover">
    744                             <span class="block mb-1 text-gemini-purple group-hover:translate-x-1 transition-transform"><i data-lucide="book-open" class="w-4 h-4 inline mr-1"></i> Explain</span>
    745                             Understand algorithms
    746                         </button>
    747                         <button onclick="setPrompt('Refactor this function')" class="group bg-gemini-surface hover:bg-gemini-surfaceHover text-gemini-text px-5 py-4 rounded-2xl text-sm font-medium transition-all text-left flex-1 min-w-[200px] border border-transparent hover:border-gemini-surfaceHover">
    748                             <span class="block mb-1 text-green-400 group-hover:translate-x-1 transition-transform"><i data-lucide="wand-2" class="w-4 h-4 inline mr-1"></i> Refactor</span>
    749                             Optimize performance
    750                         </button>
    751                     </div>
    752                 </div>
    753             </div>
    754         </div>
    755 
    756         <!-- Input Area (Fixed Bottom) -->
    757         <div class="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-gemini-bg via-gemini-bg to-transparent z-20" id="input-area">
    758             <div class="max-w-3xl mx-auto">
    759                 <form id="chat-form" onsubmit="handleFormSubmit(event)" class="bg-gemini-surface rounded-[28px] flex items-end p-2 border border-gemini-surfaceHover focus-within:bg-gemini-surfaceHover focus-within:border-gemini-textSecondary/20 transition-all shadow-xl">
    760                     <!-- ADDED: transition-all duration-200 for smooth growth -->
    761                     <textarea 
    762                         id="user-input"
    763                         class="w-full bg-transparent text-white placeholder-gemini-textSecondary py-3.5 px-4 max-h-48 min-h-[52px] resize-none focus:outline-none text-base no-scrollbar transition-all duration-200 ease-in-out"
    764                         placeholder="Enter a prompt here"
    765                         rows="1"
    766                         oninput="autoResize(this)"
    767                         onkeydown="handleEnter(event)"
    768                         enterkeyhint="send"
    769                     ></textarea>
    770                     
    771                     <button type="submit" id="send-btn" class="p-3 text-gemini-textSecondary hover:text-white disabled:opacity-50 disabled:cursor-not-allowed transition-colors rounded-full">
    772                         <i data-lucide="send-horizontal" class="w-6 h-6"></i>
    773                     </button>
    774                 </form>
    775                 <div class="text-center mt-3 text-xs text-gemini-textSecondary/60">
    776                     Ada may display inaccurate info, including about people, so double-check its responses.
    777                 </div>
    778             </div>
    779         </div>
    780     </main>
    781 
    782     <!-- Right Artifact Panel (Drawer on ALL screens) -->
    783     <aside id="artifact-panel" class="fixed inset-y-0 right-0 z-[70] w-full md:w-[600px] bg-[#1e1e1e] border-l border-[#333] transform translate-x-full drawer shadow-2xl flex flex-col">
    784         <!-- Panel Header -->
    785         <div class="h-14 flex-shrink-0 flex items-center justify-between px-4 bg-[#252526] border-b border-[#333]">
    786             <div class="flex items-center gap-3">
    787                 <span class="text-xs uppercase tracking-wide text-[#969696] font-medium">Workspace</span>
    788                 <span id="lang-display" class="text-xs text-[#cccccc] bg-[#3c3c3c] px-2 py-0.5 rounded">PLAINTEXT</span>
    789             </div>
    790             <div class="flex gap-2">
    791                 <button onclick="copyArtifact()" class="p-2 text-[#cccccc] hover:text-white hover:bg-[#3c3c3c] rounded transition-colors" title="Copy Code">
    792                     <i data-lucide="copy" class="w-4 h-4"></i>
    793                 </button>
    794                 <button onclick="toggleArtifactPanel()" class="p-2 text-[#cccccc] hover:text-white hover:bg-[#3c3c3c] rounded transition-colors" title="Close">
    795                     <i data-lucide="x" class="w-5 h-5"></i>
    796                 </button>
    797             </div>
    798         </div>
    799 
    800         <!-- Editor Content -->
    801         <div class="flex-1 overflow-hidden relative bg-[#1e1e1e]">
    802             <textarea id="artifact-editor" class="w-full h-full"></textarea>
    803         </div>
    804 
    805         <!-- ADDED: Status Bar -->
    806         <div class="h-6 bg-[#007acc] text-white flex items-center px-3 text-xs justify-end gap-4 select-none">
    807             <div class="flex items-center gap-1">
    808                 <i data-lucide="code" class="w-3 h-3"></i>
    809                 <span id="status-lang">JavaScript</span>
    810             </div>
    811             <div class="flex items-center gap-1">
    812                 <span id="status-cursor">Ln 1, Col 1</span>
    813             </div>
    814             <div>UTF-8</div>
    815         </div>
    816     </aside>
    817 
    818     <script>
    819         // --- CONFIGURATION ---
    820         const API_BASE_URL = "https://ada-web.onrender.com/api"; 
    821         
    822         const firebaseConfig = {
    823             apiKey: "AIzaSyAhyoNYUSXWIxdBiTxwSDcU7HkhhLEVlOc",
    824             authDomain: "ada-ai-aranag.firebaseapp.com",
    825             projectId: "ada-ai-aranag",
    826             storageBucket: "ada-ai-aranag.firebasestorage.app",
    827             messagingSenderId: "865895114061",
    828             appId: "1:865895114061:web:5fd4493b0e388727e6c304"
    829         };
    830         
    831         // --- STATE & INIT ---
    832         let auth, db;
    833         let state = {
    834             messages: [],
    835             isTyping: false,
    836             currentChatId: null,
    837             user: null,
    838             isSharedView: false
    839         };
    840         let editor = null;
    841         let settings = {
    842             allowSharing: localStorage.getItem('ada_allow_sharing') === 'true',
    843             fontSize: parseInt(localStorage.getItem('ada_font_size')) || 14
    844         };
    845 
    846         // --- COMMAND PALETTE DATA ---
    847         const commands = [
    848             { name: "New Chat", icon: "plus", action: startNewChat, shortcut: "N" },
    849             { name: "Toggle Sidebar", icon: "sidebar", action: toggleSidebar, shortcut: "Ctrl+/" },
    850             { name: "Clear History", icon: "trash-2", action: confirmClearHistory, shortcut: "" },
    851             { name: "Settings", icon: "settings", action: toggleSettingsModal, shortcut: "" },
    852             { name: "Sign Out", icon: "log-out", action: confirmSignOut, shortcut: "" }
    853         ];
    854 
    855         function initApp() {
    856             lucide.createIcons();
    857             
    858             // Set initial settings
    859             applyFontSize(settings.fontSize);
    860             
    861             const shareToggle = document.getElementById('share-toggle-checkbox');
    862             if(shareToggle) shareToggle.checked = settings.allowSharing;
    863 
    864             // Check for Shared URL param
    865             const urlParams = new URLSearchParams(window.location.search);
    866             const sharedChatId = urlParams.get('chat');
    867             if (sharedChatId) {
    868                 state.isSharedView = true;
    869                 state.currentChatId = sharedChatId;
    870                 enterSharedMode(sharedChatId);
    871             }
    872             
    873             // Initialize CodeMirror (Standard setup)
    874             editor = CodeMirror.fromTextArea(document.getElementById("artifact-editor"), {
    875                 lineNumbers: true,
    876                 mode: "javascript",
    877                 theme: "dracula",
    878                 readOnly: true, // Read-only as it's an output viewer primarily
    879                 lineWrapping: true
    880             });
    881 
    882             // ADDED: Cursor Activity Listener for Status Bar
    883             editor.on("cursorActivity", () => {
    884                 const pos = editor.getCursor();
    885                 document.getElementById('status-cursor').innerText = `Ln ${pos.line + 1}, Col ${pos.ch + 1}`;
    886             });
    887 
    888             // Initialize Firebase
    889             try {
    890                 firebase.initializeApp(firebaseConfig);
    891                 auth = firebase.auth();
    892                 db = firebase.firestore();
    893                 if (!state.isSharedView) checkAuth();
    894                 else checkAuthShared();
    895             } catch (e) {
    896                 console.error("Init Failed:", e);
    897                 document.getElementById('loading-overlay').classList.add('opacity-0', 'pointer-events-none');
    898             }
    899 
    900             // Mobile Height Fix
    901             const setVh = () => {
    902                 let vh = window.innerHeight * 0.01;
    903                 document.documentElement.style.setProperty('--vh', `${vh}px`);
    904             };
    905             window.addEventListener('resize', setVh);
    906             setVh();
    907 
    908             // Context Menu Listener
    909             document.addEventListener('click', (e) => {
    910                 const menu = document.querySelector('.context-menu');
    911                 if (menu) menu.remove();
    912             });
    913 
    914             // ADDED: Global Keyboard Shortcuts
    915             document.addEventListener('keydown', handleGlobalKeydown);
    916 
    917             // ADDED: Swipe Gestures
    918             initSwipeGestures();
    919         }
    920 
    921         function autoResize(textarea) {
    922             textarea.style.height = 'auto';
    923             textarea.style.height = Math.min(textarea.scrollHeight, 200) + 'px';
    924         }
    925 
    926         // ADDED: Swipe Gesture Logic
    927         function initSwipeGestures() {
    928             let touchStartX = 0;
    929             let touchStartY = 0;
    930             
    931             document.addEventListener('touchstart', e => {
    932                 touchStartX = e.changedTouches[0].screenX;
    933                 touchStartY = e.changedTouches[0].screenY;
    934             }, {passive: true});
    935 
    936             document.addEventListener('touchend', e => {
    937                 const touchEndX = e.changedTouches[0].screenX;
    938                 const touchEndY = e.changedTouches[0].screenY;
    939                 
    940                 handleSwipe(touchStartX, touchStartY, touchEndX, touchEndY);
    941             }, {passive: true});
    942         }
    943 
    944         function handleSwipe(startX, startY, endX, endY) {
    945             const diffX = endX - startX;
    946             const diffY = endY - startY;
    947 
    948             // Only trigger if horizontal swipe is dominant and significant
    949             if (Math.abs(diffX) > Math.abs(diffY) && Math.abs(diffX) > 50) {
    950                 const sidebar = document.getElementById('sidebar');
    951                 const isClosed = sidebar.classList.contains('-translate-x-full');
    952 
    953                 // Swipe Right (Open) - Only works from left edge area (first 30px)
    954                 if (diffX > 0 && startX < 30 && isClosed) {
    955                     toggleSidebar();
    956                 }
    957                 
    958                 // Swipe Left (Close)
    959                 if (diffX < 0 && !isClosed) {
    960                     toggleSidebar();
    961                 }
    962             }
    963         }
    964 
    965         // ADDED: Keyboard Shortcuts Handler
    966         function handleGlobalKeydown(e) {
    967             // Toggle Sidebar: Ctrl + / (or Cmd + /)
    968             if ((e.ctrlKey || e.metaKey) && e.key === '/') {
    969                 e.preventDefault();
    970                 toggleSidebar();
    971             }
    972 
    973             // Command Palette: Ctrl + K (or Cmd + K)
    974             if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
    975                 e.preventDefault();
    976                 toggleCommandPalette();
    977             }
    978 
    979             // Close Palette on ESC
    980             if (e.key === 'Escape') {
    981                 const cmd = document.getElementById('command-palette');
    982                 if (!cmd.classList.contains('hidden')) {
    983                     toggleCommandPalette();
    984                 }
    985             }
    986         }
    987 
    988         // ADDED: Command Palette Logic
    989         function toggleCommandPalette() {
    990             const palette = document.getElementById('command-palette');
    991             const input = document.getElementById('cmd-input');
    992             const list = document.getElementById('cmd-list');
    993 
    994             if (palette.classList.contains('hidden')) {
    995                 // Show
    996                 palette.classList.remove('hidden', 'pointer-events-none');
    997                 requestAnimationFrame(() => palette.classList.remove('opacity-0'));
    998                 input.value = '';
    999                 input.focus();
   1000                 renderCommands(commands);
   1001             } else {
   1002                 // Hide
   1003                 palette.classList.add('opacity-0');
   1004                 setTimeout(() => palette.classList.add('hidden', 'pointer-events-none'), 150);
   1005             }
   1006 
   1007             input.oninput = (e) => {
   1008                 const val = e.target.value.toLowerCase();
   1009                 const filtered = commands.filter(c => c.name.toLowerCase().includes(val));
   1010                 renderCommands(filtered);
   1011             };
   1012         }
   1013 
   1014         function renderCommands(cmds) {
   1015             const list = document.getElementById('cmd-list');
   1016             list.innerHTML = '';
   1017             
   1018             if (cmds.length === 0) {
   1019                 list.innerHTML = `<div class="text-gemini-textSecondary text-xs p-3 text-center">No commands found</div>`;
   1020                 return;
   1021             }
   1022 
   1023             cmds.forEach(cmd => {
   1024                 const div = document.createElement('div');
   1025                 div.className = 'cmd-item group';
   1026                 div.onclick = () => {
   1027                     cmd.action();
   1028                     toggleCommandPalette();
   1029                 };
   1030                 div.innerHTML = `
   1031                     <div class="flex items-center gap-3">
   1032                         <i data-lucide="${cmd.icon}" class="w-4 h-4 text-gemini-textSecondary group-hover:text-white"></i>
   1033                         <span class="text-sm">${cmd.name}</span>
   1034                     </div>
   1035                     ${cmd.shortcut ? `<span class="cmd-shortcut">${cmd.shortcut}</span>` : ''}
   1036                 `;
   1037                 list.appendChild(div);
   1038             });
   1039             lucide.createIcons();
   1040         }
   1041 
   1042         // --- SETTINGS ---
   1043         function changeFontSize(delta) {
   1044             settings.fontSize = Math.max(10, Math.min(24, settings.fontSize + delta));
   1045             localStorage.setItem('ada_font_size', settings.fontSize);
   1046             applyFontSize(settings.fontSize);
   1047         }
   1048 
   1049         function applyFontSize(size) {
   1050             document.getElementById('font-size-display').innerText = size;
   1051             if(editor) {
   1052                 editor.getWrapperElement().style.fontSize = `${size}px`;
   1053                 editor.refresh();
   1054             }
   1055         }
   1056 
   1057         // --- SHARED MODE LOGIC ---
   1058         async function enterSharedMode(chatId) {
   1059             document.getElementById('sidebar').classList.add('hidden');
   1060             const inputArea = document.getElementById('input-area');
   1061             const sidebarToggle = document.querySelector('header button[title="Toggle History"]');
   1062             
   1063             inputArea.classList.add('hidden');
   1064             if(sidebarToggle) sidebarToggle.style.display = 'none';
   1065         }
   1066 
   1067         function checkAuthShared() {
   1068              auth.onAuthStateChanged(user => {
   1069                 const loadingOverlay = document.getElementById('loading-overlay');
   1070                 loadingOverlay.classList.add('opacity-0', 'pointer-events-none');
   1071 
   1072                 if (user) {
   1073                     state.user = user;
   1074                     document.getElementById('sidebar').classList.remove('hidden');
   1075                     document.getElementById('input-area').classList.remove('hidden');
   1076                     const sidebarToggle = document.querySelector('header button[title="Toggle History"]');
   1077                     if(sidebarToggle) sidebarToggle.style.display = 'block';
   1078                     document.getElementById('shared-login-btn').classList.add('hidden');
   1079 
   1080                     fetchChats();
   1081                     loadChat(state.currentChatId);
   1082                 } else {
   1083                     state.user = null;
   1084                     document.getElementById('shared-login-btn').classList.remove('hidden');
   1085                     loadChatReadOnly(state.currentChatId);
   1086                 }
   1087             });
   1088         }
   1089         
   1090         async function loadChatReadOnly(chatId) {
   1091              const container = document.querySelector('#chat-container > div');
   1092              container.innerHTML = `
   1093                 <div class="flex flex-col items-center justify-center min-h-[50vh] text-center p-6">
   1094                     <div class="p-4 bg-gemini-surface rounded-2xl border border-gemini-surfaceHover mb-4">
   1095                         <i data-lucide="lock" class="w-8 h-8 text-gemini-textSecondary mx-auto mb-2"></i>
   1096                         <p class="text-white font-medium">Shared Chat</p>
   1097                     </div>
   1098                     <p class="text-gemini-textSecondary max-w-md">To view and continue this conversation, please sign in. The chat will be saved to your history.</p>
   1099                 </div>
   1100              `;
   1101              lucide.createIcons();
   1102         }
   1103 
   1104         // --- UI TOGGLES & HELPERS ---
   1105         function showToast(message, type = 'info') {
   1106             const toast = document.getElementById('toast');
   1107             const icon = toast.querySelector('i');
   1108             document.getElementById('toast-message').innerText = message;
   1109             
   1110             if (type === 'error') {
   1111                 icon.setAttribute('data-lucide', 'alert-circle');
   1112                 icon.className = 'w-4 h-4 text-red-400';
   1113             } else if (type === 'success') {
   1114                 icon.setAttribute('data-lucide', 'check-circle');
   1115                 icon.className = 'w-4 h-4 text-green-400';
   1116             } else {
   1117                 icon.setAttribute('data-lucide', 'info');
   1118                 icon.className = 'w-4 h-4 text-gemini-blue';
   1119             }
   1120             lucide.createIcons();
   1121 
   1122             toast.classList.remove('opacity-0', 'pointer-events-none', 'translate-y-20');
   1123             setTimeout(() => {
   1124                 toast.classList.add('opacity-0', 'pointer-events-none', 'translate-y-20');
   1125             }, 3000);
   1126         }
   1127 
   1128         function toggleShareSetting(checkbox) {
   1129             settings.allowSharing = checkbox.checked;
   1130             localStorage.setItem('ada_allow_sharing', settings.allowSharing);
   1131         }
   1132 
   1133         function toggleSidebar() {
   1134             const sb = document.getElementById('sidebar');
   1135             const overlay = document.getElementById('sidebar-overlay');
   1136             const isClosed = sb.classList.contains('-translate-x-full');
   1137             
   1138             if (isClosed) {
   1139                 sb.classList.remove('-translate-x-full');
   1140                 overlay.classList.remove('hidden');
   1141             } else {
   1142                 sb.classList.add('-translate-x-full');
   1143                 overlay.classList.add('hidden');
   1144             }
   1145         }
   1146 
   1147         function toggleArtifactPanel() {
   1148             const panel = document.getElementById('artifact-panel');
   1149             const isClosed = panel.classList.contains('translate-x-full');
   1150             
   1151             if (isClosed) {
   1152                 panel.classList.remove('translate-x-full');
   1153                 document.getElementById('artifact-indicator').classList.add('hidden');
   1154                 setTimeout(() => editor.refresh(), 300); 
   1155             } else {
   1156                 panel.classList.add('translate-x-full');
   1157             }
   1158         }
   1159         
   1160         function toggleProfileModal() {
   1161             const modal = document.getElementById('profile-modal');
   1162             const content = document.getElementById('profile-modal-content');
   1163             
   1164             if (modal.classList.contains('hidden')) {
   1165                 modal.classList.remove('hidden', 'pointer-events-none');
   1166                 requestAnimationFrame(() => {
   1167                     modal.classList.remove('opacity-0');
   1168                     content.classList.remove('scale-95');
   1169                     content.classList.add('scale-100');
   1170                 });
   1171                 
   1172                 if (state.user) {
   1173                      // Handle Guest / User Display
   1174                      if (state.user.isAnonymous) {
   1175                          document.getElementById('profile-name').innerText = "Guest User";
   1176                          document.getElementById('profile-email').innerText = "Anonymous Session";
   1177                          document.getElementById('profile-initial').innerText = "G";
   1178                          document.getElementById('profile-avatar').classList.add('hidden');
   1179                          document.getElementById('profile-initial').classList.remove('hidden');
   1180                      } else {
   1181                          document.getElementById('profile-name').innerText = state.user.displayName || 'User';
   1182                          document.getElementById('profile-email').innerText = state.user.email || '';
   1183                          const initial = document.getElementById('profile-initial');
   1184                          const avatar = document.getElementById('profile-avatar');
   1185                          
   1186                          if (state.user.photoURL) {
   1187                              avatar.src = state.user.photoURL;
   1188                              avatar.classList.remove('hidden');
   1189                              initial.classList.add('hidden');
   1190                          } else {
   1191                              initial.innerText = (state.user.displayName || 'U')[0];
   1192                              avatar.classList.add('hidden');
   1193                              initial.classList.remove('hidden');
   1194                          }
   1195                      }
   1196                 }
   1197             } else {
   1198                 modal.classList.add('opacity-0');
   1199                 content.classList.remove('scale-100');
   1200                 content.classList.add('scale-95');
   1201                 setTimeout(() => modal.classList.add('hidden', 'pointer-events-none'), 300);
   1202             }
   1203         }
   1204 
   1205         function toggleSettingsModal() {
   1206             const modal = document.getElementById('settings-modal');
   1207             const content = document.getElementById('settings-modal-content');
   1208             
   1209             if (modal.classList.contains('hidden')) {
   1210                 modal.classList.remove('hidden', 'pointer-events-none');
   1211                 requestAnimationFrame(() => {
   1212                     modal.classList.remove('opacity-0');
   1213                     content.classList.remove('scale-95');
   1214                     content.classList.add('scale-100');
   1215                 });
   1216             } else {
   1217                 modal.classList.add('opacity-0');
   1218                 content.classList.remove('scale-100');
   1219                 content.classList.add('scale-95');
   1220                 setTimeout(() => modal.classList.add('hidden', 'pointer-events-none'), 300);
   1221             }
   1222         }
   1223 
   1224         // --- FEATURES IMPLEMENTATION ---
   1225 
   1226         // 1. History Search
   1227         function filterHistory(query) {
   1228             const list = document.getElementById('chat-history-list');
   1229             const items = list.querySelectorAll('div[onclick]');
   1230             query = query.toLowerCase();
   1231             
   1232             items.forEach(item => {
   1233                 const text = item.querySelector('span').innerText.toLowerCase();
   1234                 if (text.includes(query)) {
   1235                     item.style.display = 'flex';
   1236                 } else {
   1237                     item.style.display = 'none';
   1238                 }
   1239             });
   1240         }
   1241 
   1242         // --- CONFIRM MODALS ---
   1243         let confirmCallback = null;
   1244 
   1245         function showConfirmModal(title, message, callback, matchText = null) {
   1246             const modal = document.getElementById('confirm-modal');
   1247             const content = document.getElementById('confirm-modal-content');
   1248             
   1249             document.getElementById('confirm-title').innerText = title;
   1250             document.getElementById('confirm-message').innerText = message;
   1251             
   1252             const inputContainer = document.getElementById('confirm-input-container');
   1253             const input = document.getElementById('confirm-input');
   1254             const btn = document.getElementById('confirm-action-btn');
   1255 
   1256             if (matchText) {
   1257                 inputContainer.classList.remove('hidden');
   1258                 document.getElementById('confirm-match-text').innerText = matchText;
   1259                 input.value = '';
   1260                 input.oninput = () => {
   1261                     if (input.value === matchText) {
   1262                         btn.disabled = false;
   1263                         btn.classList.remove('opacity-50', 'cursor-not-allowed');
   1264                     } else {
   1265                         btn.disabled = true;
   1266                         btn.classList.add('opacity-50', 'cursor-not-allowed');
   1267                     }
   1268                 };
   1269                 btn.disabled = true;
   1270                 btn.classList.add('opacity-50', 'cursor-not-allowed');
   1271             } else {
   1272                 inputContainer.classList.add('hidden');
   1273                 btn.disabled = false;
   1274                 btn.classList.remove('opacity-50', 'cursor-not-allowed');
   1275             }
   1276 
   1277             confirmCallback = callback;
   1278             
   1279             modal.classList.remove('hidden');
   1280             requestAnimationFrame(() => {
   1281                 modal.classList.remove('opacity-0');
   1282                 content.classList.remove('scale-95');
   1283                 content.classList.add('scale-100');
   1284             });
   1285             
   1286             btn.onclick = () => {
   1287                  closeConfirmModal();
   1288                  if (confirmCallback) confirmCallback();
   1289             };
   1290         }
   1291 
   1292         function closeConfirmModal() {
   1293             const modal = document.getElementById('confirm-modal');
   1294             const content = document.getElementById('confirm-modal-content');
   1295             modal.classList.add('opacity-0');
   1296             content.classList.remove('scale-100');
   1297             content.classList.add('scale-95');
   1298             setTimeout(() => modal.classList.add('hidden'), 300);
   1299         }
   1300 
   1301         function confirmSignOut() {
   1302             toggleProfileModal(); 
   1303             showConfirmModal('Sign Out', 'Are you sure you want to sign out?', signOutUser);
   1304         }
   1305 
   1306         function confirmClearHistory() {
   1307             toggleSettingsModal();
   1308             if (!state.user || !state.user.email) return;
   1309             showConfirmModal(
   1310                 'Clear Activity', 
   1311                 'This will permanently delete all your chat history. Type your email to confirm.', 
   1312                 clearHistory, 
   1313                 state.user.email
   1314             );
   1315         }
   1316 
   1317         async function clearHistory() {
   1318             if (!state.user) return;
   1319             const loading = document.getElementById('loading-overlay');
   1320             loading.classList.remove('opacity-0', 'pointer-events-none');
   1321             
   1322             try {
   1323                 // FIXED: Use correct path users/{uid}/chats
   1324                 const chatsRef = db.collection('users').doc(state.user.uid).collection('chats');
   1325                 const snapshot = await chatsRef.get();
   1326                 
   1327                 const batch = db.batch();
   1328                 snapshot.docs.forEach((doc) => {
   1329                     batch.delete(doc.ref);
   1330                 });
   1331                 await batch.commit();
   1332                 
   1333                 location.reload();
   1334             } catch (error) {
   1335                 console.error("Error clearing history:", error);
   1336                 loading.classList.add('opacity-0', 'pointer-events-none');
   1337                 showToast("Failed to clear history.", "error");
   1338             }
   1339         }
   1340 
   1341         function confirmDeleteChat(chatId) {
   1342             showConfirmModal('Delete Chat', 'This action cannot be undone.', () => deleteChat(chatId));
   1343         }
   1344 
   1345         async function deleteChat(chatId) {
   1346             if (!state.user) return;
   1347             try {
   1348                 // FIXED: Use correct path users/{uid}/chats/{chatId}
   1349                 await db.collection('users').doc(state.user.uid).collection('chats').doc(chatId).delete();
   1350                 
   1351                 if (state.currentChatId === chatId) {
   1352                     location.reload();
   1353                 } else {
   1354                     fetchChats(); 
   1355                     showToast("Chat deleted.", "success");
   1356                 }
   1357             } catch (e) {
   1358                 console.error("Delete Error:", e);
   1359                 showToast("Failed to delete chat.", "error");
   1360             }
   1361         }
   1362 
   1363         // --- CONTEXT MENU & EXPORT ---
   1364         function showChatContextMenu(e, chatId, chatTitle) {
   1365             e.preventDefault();
   1366             e.stopPropagation();
   1367 
   1368             const existing = document.querySelector('.context-menu');
   1369             if (existing) existing.remove();
   1370 
   1371             const menu = document.createElement('div');
   1372             menu.className = 'context-menu';
   1373             
   1374             // Share Option
   1375             if (settings.allowSharing) {
   1376                 const shareBtn = document.createElement('div');
   1377                 shareBtn.className = 'context-menu-item';
   1378                 shareBtn.innerHTML = `<i data-lucide="link" class="w-4 h-4"></i> Share Chat`;
   1379                 shareBtn.onclick = async () => {
   1380                     const url = `${window.location.origin}?chat=${chatId}`;
   1381                     if (navigator.share) {
   1382                         try {
   1383                             await navigator.share({ title: 'Ada Chat', url: url });
   1384                         } catch (err) { /* Share cancelled */ }
   1385                     } else {
   1386                         navigator.clipboard.writeText(url).then(() => showToast('Link copied!', 'success'));
   1387                     }
   1388                     menu.remove();
   1389                 };
   1390                 menu.appendChild(shareBtn);
   1391             }
   1392 
   1393             // Export Options (Expanded)
   1394             const jsonBtn = document.createElement('div');
   1395             jsonBtn.className = 'context-menu-item';
   1396             jsonBtn.innerHTML = `<i data-lucide="file-json" class="w-4 h-4"></i> Export JSON`;
   1397             jsonBtn.onclick = () => {
   1398                 downloadChat(chatId, chatTitle, 'json');
   1399                 menu.remove();
   1400             };
   1401             menu.appendChild(jsonBtn);
   1402 
   1403             const mdBtn = document.createElement('div');
   1404             mdBtn.className = 'context-menu-item';
   1405             mdBtn.innerHTML = `<i data-lucide="file-text" class="w-4 h-4"></i> Export Markdown`;
   1406             mdBtn.onclick = () => {
   1407                 downloadChat(chatId, chatTitle, 'md');
   1408                 menu.remove();
   1409             };
   1410             menu.appendChild(mdBtn);
   1411 
   1412             // Delete Option
   1413             const delBtn = document.createElement('div');
   1414             delBtn.className = 'context-menu-item danger';
   1415             delBtn.innerHTML = `<i data-lucide="trash-2" class="w-4 h-4"></i> Delete Chat`;
   1416             delBtn.onclick = () => {
   1417                 confirmDeleteChat(chatId);
   1418                 menu.remove();
   1419             };
   1420             menu.appendChild(delBtn);
   1421 
   1422             document.body.appendChild(menu);
   1423             
   1424             // Position
   1425             const rect = e.target.getBoundingClientRect();
   1426             const menuWidth = 180;
   1427             const menuHeight = 200;
   1428             
   1429             let left = rect.left;
   1430             let top = rect.bottom + 5;
   1431 
   1432             if (left + menuWidth > window.innerWidth) left = window.innerWidth - menuWidth - 16;
   1433             if (left < 16) left = 16;
   1434             if (top + menuHeight > window.innerHeight) top = rect.top - menuHeight - 5;
   1435 
   1436             menu.style.top = `${top}px`;
   1437             menu.style.left = `${left}px`;
   1438             
   1439             lucide.createIcons();
   1440         }
   1441 
   1442         async function downloadChat(chatId, title, format) {
   1443              try {
   1444                 const token = await state.user.getIdToken();
   1445                 const res = await fetch(`${API_BASE_URL}/chats/${chatId}`, { headers: { 'Authorization': `Bearer ${token}` } });
   1446                 const data = await res.json();
   1447                 
   1448                 let content, type, ext;
   1449                 if (format === 'json') {
   1450                     content = JSON.stringify(data, null, 2);
   1451                     type = 'application/json';
   1452                     ext = 'json';
   1453                 } else {
   1454                     // Markdown conversion
   1455                     content = `# ${title}\n\n`;
   1456                     data.messages.forEach(msg => {
   1457                         content += `### ${msg.role === 'user' ? 'User' : 'Ada AI'}\n${msg.content}\n\n`;
   1458                     });
   1459                     type = 'text/markdown';
   1460                     ext = 'md';
   1461                 }
   1462                 
   1463                 const blob = new Blob([content], { type: type });
   1464                 const url = URL.createObjectURL(blob);
   1465                 const a = document.createElement('a');
   1466                 a.href = url;
   1467                 a.download = `ada_chat_${title.replace(/\s+/g, '_')}.${ext}`;
   1468                 document.body.appendChild(a);
   1469                 a.click();
   1470                 document.body.removeChild(a);
   1471                 URL.revokeObjectURL(url);
   1472                 showToast("Chat exported.", "success");
   1473              } catch(e) { 
   1474                  console.error(e);
   1475                  showToast("Export failed.", "error");
   1476              }
   1477         }
   1478 
   1479         // --- AUTH & FIREBASE ---
   1480         function checkAuth() {
   1481             auth.onAuthStateChanged(user => {
   1482                 const loadingOverlay = document.getElementById('loading-overlay');
   1483                 const authModal = document.getElementById('auth-modal');
   1484                 
   1485                 if (user) {
   1486                     state.user = user;
   1487                     localStorage.setItem('ada_user_cached', 'true');
   1488                     
   1489                     loadingOverlay.classList.add('opacity-0', 'pointer-events-none');
   1490                     authModal.classList.add('hidden');
   1491 
   1492                     // --- SIDEBAR VISIBILITY LOGIC (Guest vs User) ---
   1493                     const historyLabel = document.getElementById('history-label');
   1494                     const historySearch = document.getElementById('history-search-container');
   1495                     const historyList = document.getElementById('chat-history-list');
   1496 
   1497                     if (user.isAnonymous) {
   1498                         // GUEST: Hide History
   1499                         if(historyLabel) historyLabel.classList.add('hidden');
   1500                         if(historySearch) historySearch.classList.add('hidden');
   1501                         if(historyList) historyList.classList.add('hidden');
   1502                         
   1503                         document.getElementById('user-email').innerText = 'Guest Mode';
   1504                         document.getElementById('user-initial').innerText = 'G';
   1505                         document.getElementById('user-initial').classList.remove('hidden');
   1506                         document.getElementById('user-avatar').classList.add('hidden');
   1507                     } else {
   1508                         // USER: Show History
   1509                         if(historyLabel) historyLabel.classList.remove('hidden');
   1510                         if(historySearch) historySearch.classList.remove('hidden');
   1511                         if(historyList) historyList.classList.remove('hidden');
   1512 
   1513                         document.getElementById('user-email').innerText = user.email || '';
   1514                         document.getElementById('user-initial').innerText = (user.displayName || 'U')[0];
   1515                         
   1516                         if (user.photoURL) {
   1517                             const img = document.getElementById('user-avatar');
   1518                             img.src = user.photoURL;
   1519                             img.classList.remove('hidden');
   1520                             document.getElementById('user-initial').classList.add('hidden');
   1521                         }
   1522                     }
   1523                     
   1524                     const welcomeName = document.getElementById('welcome-name');
   1525                     if (welcomeName) {
   1526                         const name = user.isAnonymous ? 'Guest' : (user.email || user.displayName || 'Student');
   1527                         welcomeName.innerText = name;
   1528                         welcomeName.title = name;
   1529                     }
   1530 
   1531                     if(!state.currentChatId) state.currentChatId = 'session_' + Date.now();
   1532                     
   1533                     // Only fetch history if not guest
   1534                     if (!user.isAnonymous) {
   1535                         fetchChats();
   1536                     }
   1537                 } else {
   1538                     state.user = null;
   1539                     localStorage.removeItem('ada_user_cached');
   1540                     loadingOverlay.classList.add('opacity-0', 'pointer-events-none');
   1541                     authModal.classList.remove('hidden', 'opacity-0', 'pointer-events-none');
   1542                 }
   1543             });
   1544         }
   1545 
   1546         // --- AUTH HANDLERS ---
   1547 
   1548         function signInWithGoogle() {
   1549             const provider = new firebase.auth.GoogleAuthProvider();
   1550             auth.signInWithPopup(provider).catch(e => {
   1551                 console.error(e);
   1552                 showToast("Sign in failed.", "error");
   1553             });
   1554         }
   1555         
   1556         function signInAsGuest() {
   1557             auth.signInAnonymously().catch(e => {
   1558                 console.error(e);
   1559                 showToast("Guest login failed.", "error");
   1560             });
   1561         }
   1562 
   1563         function handleEmailSignIn() {
   1564             const email = document.getElementById('auth-email').value;
   1565             const pass = document.getElementById('auth-password').value;
   1566             if(!email || !pass) {
   1567                 showToast("Please enter email and password", "error");
   1568                 return;
   1569             }
   1570             auth.signInWithEmailAndPassword(email, pass).catch(e => {
   1571                 showToast(e.message, "error");
   1572             });
   1573         }
   1574 
   1575         function handleEmailSignUp() {
   1576             const email = document.getElementById('auth-email').value;
   1577             const pass = document.getElementById('auth-password').value;
   1578             if(!email || !pass) {
   1579                 showToast("Please enter email and password", "error");
   1580                 return;
   1581             }
   1582             auth.createUserWithEmailAndPassword(email, pass).catch(e => {
   1583                 showToast(e.message, "error");
   1584             });
   1585         }
   1586 
   1587         function signOutUser() {
   1588             auth.signOut().then(() => {
   1589                 localStorage.removeItem('ada_user_cached');
   1590                 location.reload();
   1591             });
   1592         }
   1593 
   1594         // ADDED: Skeleton Loader Generator
   1595         function renderSkeletonLoader() {
   1596              const list = document.getElementById('chat-history-list');
   1597              list.innerHTML = '';
   1598              for(let i=0; i<5; i++) {
   1599                  list.innerHTML += `
   1600                     <div class="flex items-center gap-3 p-2.5 rounded-full skeleton-shimmer opacity-50 mb-1">
   1601                         <div class="w-4 h-4 bg-gemini-surfaceHover rounded-full"></div>
   1602                         <div class="h-4 bg-gemini-surfaceHover rounded w-24"></div>
   1603                     </div>
   1604                  `;
   1605              }
   1606         }
   1607 
   1608         async function fetchChats() {
   1609             if (!state.user || state.user.isAnonymous) return;
   1610             try {
   1611                 // USE SKELETON LOADER
   1612                 renderSkeletonLoader();
   1613                 
   1614                 const token = await state.user.getIdToken();
   1615                 const res = await fetch(`${API_BASE_URL}/chats`, { headers: { 'Authorization': `Bearer ${token}` } });
   1616                 const data = await res.json();
   1617                 
   1618                 const list = document.getElementById('chat-history-list');
   1619                 list.innerHTML = '';
   1620                 
   1621                 if (data.chats && data.chats.length > 0) {
   1622                     data.chats.forEach(chat => {
   1623                         const div = document.createElement('div');
   1624                         const isActive = chat.id === state.currentChatId;
   1625                         div.className = `group relative p-2.5 rounded-full cursor-pointer text-sm flex items-center gap-3 transition-colors truncate ${isActive ? 'bg-[#004A77] text-white font-medium' : 'text-gemini-textSecondary hover:bg-gemini-surfaceHover hover:text-white'}`;
   1626                         div.onclick = () => loadChat(chat.id);
   1627                         
   1628                         let pressTimer;
   1629                         div.ontouchstart = (e) => {
   1630                              pressTimer = setTimeout(() => showChatContextMenu(e, chat.id, chat.title), 500);
   1631                         };
   1632                         div.ontouchend = () => clearTimeout(pressTimer);
   1633                         div.oncontextmenu = (e) => showChatContextMenu(e, chat.id, chat.title);
   1634 
   1635                         div.innerHTML = `
   1636                             <i data-lucide="message-square" class="w-4 h-4 flex-shrink-0"></i>
   1637                             <span class="truncate flex-1">${chat.title}</span>
   1638                             <button class="opacity-0 group-hover:opacity-100 p-1 hover:bg-white/10 rounded-full transition-opacity" onclick="showChatContextMenu(event, '${chat.id}', '${chat.title}')">
   1639                                 <i data-lucide="more-vertical" class="w-3 h-3"></i>
   1640                             </button>
   1641                         `;
   1642                         list.appendChild(div);
   1643                     });
   1644                 } else {
   1645                     list.innerHTML = `<div class="p-4 text-center text-xs text-gemini-textSecondary">No recent chats</div>`;
   1646                 }
   1647                 lucide.createIcons();
   1648             } catch (e) { console.error(e); }
   1649         }
   1650 
   1651         async function loadChat(chatId) {
   1652             if (state.isTyping) return;
   1653             state.currentChatId = chatId;
   1654             
   1655             // Skeleton Loading for Main Chat
   1656             const container = document.querySelector('#chat-container > div');
   1657             container.innerHTML = `
   1658                 <div class="flex flex-col space-y-6 p-4">
   1659                     <div class="flex justify-end"><div class="h-10 w-2/3 rounded-2xl skeleton-shimmer"></div></div>
   1660                     <div class="flex justify-start gap-4">
   1661                         <div class="w-8 h-8 rounded-full skeleton-shimmer flex-shrink-0"></div>
   1662                         <div class="h-24 w-3/4 rounded-2xl skeleton-shimmer"></div>
   1663                     </div>
   1664                     <div class="flex justify-end"><div class="h-10 w-1/2 rounded-2xl skeleton-shimmer"></div></div>
   1665                 </div>`;
   1666             
   1667             try {
   1668                 const token = await state.user.getIdToken();
   1669                 const res = await fetch(`${API_BASE_URL}/chats/${chatId}`, { headers: { 'Authorization': `Bearer ${token}` } });
   1670                 const data = await res.json();
   1671                 
   1672                 state.messages = [];
   1673                 container.innerHTML = '';
   1674 
   1675                 if (data.messages && data.messages.length > 0) {
   1676                     data.messages.forEach(msg => {
   1677                         const role = msg.role === 'model' ? 'ai' : 'user';
   1678                         state.messages.push({ role, content: msg.content });
   1679                         renderMessage(role, msg.content);
   1680                     });
   1681                 } else {
   1682                     container.innerHTML = `<div class="text-center p-8 text-gemini-textSecondary">Start conversation...</div>`;
   1683                 }
   1684                 
   1685                 // Only refresh history if NOT shared view AND NOT guest
   1686                 if(!state.isSharedView && state.user && !state.user.isAnonymous) fetchChats();
   1687             } catch (e) { 
   1688                 console.error(e); 
   1689                 container.innerHTML = `<div class="text-center text-red-400 p-4">Failed to load chat.</div>`;
   1690             }
   1691         }
   1692 
   1693         function setPrompt(text) {
   1694             const input = document.getElementById('user-input');
   1695             if(input) {
   1696                 input.value = text;
   1697                 input.focus();
   1698                 autoResize(input);
   1699             }
   1700         }
   1701 
   1702         function scrollToBottom() {
   1703             const container = document.getElementById('chat-container');
   1704             container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
   1705         }
   1706 
   1707         function renderMessage(role, content) {
   1708             const container = document.querySelector('#chat-container > div');
   1709             const welcome = document.getElementById('welcome-message');
   1710             if (welcome) welcome.remove();
   1711 
   1712             let wrapper = container.lastElementChild;
   1713             let bubble = null;
   1714             
   1715             if (role === 'ai' && wrapper && wrapper.dataset.role === 'ai' && state.isTyping) {
   1716                  bubble = wrapper.querySelector('.prose');
   1717             } else {
   1718                  wrapper = document.createElement('div');
   1719                  wrapper.className = `flex gap-4 w-full animate-fade-in ${role === 'user' ? 'justify-end' : 'justify-start group'}`;
   1720                  wrapper.dataset.role = role;
   1721                  
   1722                  if (role === 'user') {
   1723                      wrapper.innerHTML = `<div class="msg-user text-sm md:text-base">${content}</div>`;
   1724                  } else {
   1725                      wrapper.innerHTML = `
   1726                         <div class="flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center mt-1">
   1727                             <svg class="w-6 h-6 animate-spin-slow-entry"><use href="#icon-ada"></use></svg>
   1728                         </div>
   1729                         <div class="flex-1 min-w-0 py-1">
   1730                             <div class="prose prose-invert max-w-none text-sm md:text-base"></div>
   1731                         </div>
   1732                      `;
   1733                      bubble = wrapper.querySelector('.prose');
   1734                  }
   1735                  container.appendChild(wrapper);
   1736             }
   1737 
   1738             if (role === 'ai') {
   1739                 if(!bubble) bubble = wrapper.querySelector('.prose');
   1740                 
   1741                 const customTagRegex = /<<<CODE_START>>>([\s\S]*?)<<<CODE_END>>>/g;
   1742                 const markdownRegex = /```(\w*)([\s\S]*?)```/g;
   1743                 
   1744                 let processedContent = content;
   1745                 let extractedCode = "";
   1746                 let lang = "PLAINTEXT";
   1747 
   1748                 const cardReplacement = (code, language) => {
   1749                     extractedCode = code.trim();
   1750                     if(language) lang = language.toUpperCase();
   1751                     return `<div class="code-card group" onclick="toggleArtifactPanel()">
   1752                                 <div class="px-4 py-3 bg-[#252526] border-b border-[#333] flex items-center justify-between">
   1753                                     <div class="flex items-center gap-2">
   1754                                         <i data-lucide="code-2" class="w-4 h-4 text-gemini-blue"></i>
   1755                                         <span class="text-xs font-mono text-[#cccccc]">Generated Code</span>
   1756                                     </div>
   1757                                     <span class="text-xs text-gemini-blue group-hover:underline">View Code &rarr;</span>
   1758                                 </div>
   1759                                 <div class="px-4 py-3 text-xs font-mono text-gray-400 bg-[#1e1e1e]">
   1760                                     // Code extracted to workspace...
   1761                                 </div>
   1762                             </div>`;
   1763                 };
   1764 
   1765                 processedContent = processedContent.replace(customTagRegex, (m, c) => cardReplacement(c));
   1766                 processedContent = processedContent.replace(markdownRegex, (m, l, c) => cardReplacement(c, l));
   1767 
   1768                 try {
   1769                     bubble.innerHTML = marked.parse(processedContent);
   1770                 } catch (e) {
   1771                     bubble.innerText = content;
   1772                 }
   1773 
   1774                 if (extractedCode) {
   1775                     updateArtifactPanel(extractedCode, lang);
   1776                     const indicator = document.getElementById('artifact-indicator');
   1777                     if(indicator) indicator.classList.remove('hidden');
   1778                     
   1779                     if (window.innerWidth >= 1280) {
   1780                         const panel = document.getElementById('artifact-panel');
   1781                         if (panel.classList.contains('translate-x-full')) {
   1782                             toggleArtifactPanel();
   1783                         }
   1784                     }
   1785                 }
   1786             }
   1787 
   1788             scrollToBottom();
   1789             lucide.createIcons();
   1790         }
   1791 
   1792         function renderTypingIndicator() {
   1793             const container = document.querySelector('#chat-container > div');
   1794             const wrapper = document.createElement('div');
   1795             wrapper.id = 'typing-indicator';
   1796             wrapper.className = 'flex gap-4 w-full justify-start animate-fade-in';
   1797             wrapper.innerHTML = `
   1798                 <div class="flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center mt-1">
   1799                     <svg class="w-6 h-6 animate-pulse"><use href="#icon-ada"></use></svg>
   1800                 </div>
   1801                 <div class="py-3">
   1802                     <div class="flex gap-1">
   1803                         <div class="typing-dot"></div>
   1804                         <div class="typing-dot"></div>
   1805                         <div class="typing-dot"></div>
   1806                     </div>
   1807                 </div>
   1808             `;
   1809             container.appendChild(wrapper);
   1810             scrollToBottom();
   1811             lucide.createIcons();
   1812         }
   1813 
   1814         function removeTypingIndicator() {
   1815             const el = document.getElementById('typing-indicator');
   1816             if (el) el.remove();
   1817         }
   1818 
   1819         function updateArtifactPanel(code, lang) {
   1820             const langDisplay = document.getElementById('lang-display');
   1821             const statusLang = document.getElementById('status-lang'); // Update status bar
   1822             if(lang) {
   1823                 langDisplay.innerText = lang;
   1824                 statusLang.innerText = lang; // Sync status bar
   1825                 const modeMap = {
   1826                     'PYTHON': 'python',
   1827                     'JAVASCRIPT': 'javascript',
   1828                     'JS': 'javascript',
   1829                     'HTML': 'xml',
   1830                     'CSS': 'css'
   1831                 };
   1832                 if(editor) editor.setOption("mode", modeMap[lang] || "javascript");
   1833             }
   1834             
   1835             if(editor) {
   1836                 editor.setValue(code);
   1837                 setTimeout(() => editor.refresh(), 100);
   1838             }
   1839         }
   1840         
   1841         function copyArtifact() {
   1842             if(editor) {
   1843                 const content = editor.getValue();
   1844                 navigator.clipboard.writeText(content);
   1845                 showToast("Code copied to clipboard!", "success");
   1846             }
   1847         }
   1848 
   1849         function handleEnter(e) {
   1850             if (e.key === 'Enter' && !e.shiftKey) {
   1851                 e.preventDefault();
   1852                 handleFormSubmit(e);
   1853             }
   1854         }
   1855 
   1856         async function handleFormSubmit(e) {
   1857             if (e) e.preventDefault();
   1858             const input = document.getElementById('user-input');
   1859             const message = input.value.trim();
   1860             if (!message || state.isTyping || !state.user) return;
   1861 
   1862             // UI Updates
   1863             renderMessage('user', message);
   1864             input.value = '';
   1865             autoResize(input);
   1866             state.isTyping = true;
   1867             renderTypingIndicator();
   1868             
   1869             try {
   1870                 const token = await state.user.getIdToken();
   1871                 const response = await fetch(`${API_BASE_URL}/chat`, {
   1872                     method: 'POST',
   1873                     headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
   1874                     body: JSON.stringify({ 
   1875                         message: message, 
   1876                         history: state.messages.map(m => ({ user: m.role === 'user' ? m.content : '', model: m.role === 'ai' ? m.content : '' })),
   1877                         sessionId: state.currentChatId
   1878                     })
   1879                 });
   1880 
   1881                 if (!response.ok) throw new Error("API Error");
   1882 
   1883                 removeTypingIndicator();
   1884                 const reader = response.body.getReader();
   1885                 const decoder = new TextDecoder();
   1886                 let fullText = "";
   1887                 renderMessage('ai', '');
   1888 
   1889                 while (true) {
   1890                     const { done, value } = await reader.read();
   1891                     if (done) break;
   1892                     fullText += decoder.decode(value);
   1893                     renderMessage('ai', fullText);
   1894                 }
   1895 
   1896                 state.messages.push({ role: 'user', content: message });
   1897                 state.messages.push({ role: 'ai', content: fullText });
   1898                 
   1899                 // Only refresh history if not guest
   1900                 if (!state.user.isAnonymous) {
   1901                     setTimeout(fetchChats, 1500);
   1902                 }
   1903 
   1904             } catch (error) {
   1905                 removeTypingIndicator();
   1906                 renderMessage('ai', "I'm having trouble connecting right now.");
   1907                 showToast("Error generating response", "error");
   1908             } finally {
   1909                 state.isTyping = false;
   1910             }
   1911         }
   1912         
   1913         function startNewChat() {
   1914             state.messages = [];
   1915             state.currentChatId = 'session_' + Date.now();
   1916             
   1917             const userName = (state.user && !state.user.isAnonymous) ? (state.user.email || state.user.displayName || 'Student') : 'Guest';
   1918             
   1919             const container = document.querySelector('#chat-container > div');
   1920             container.innerHTML = `
   1921                 <div id="welcome-message" class="flex flex-col items-start justify-center min-h-[50vh] space-y-8 animate-slide-up px-2">
   1922                     <div class="space-y-2 w-full">
   1923                         <div class="w-12 h-12 mb-4 animate-spin-slow-entry">
   1924                             <svg class="w-full h-full drop-shadow-[0_0_15px_rgba(168,199,250,0.5)]"><use href="#icon-ada"></use></svg>
   1925                         </div>
   1926                         <h1 class="text-4xl md:text-5xl font-medium text-transparent bg-clip-text bg-gradient-to-r from-[#4285F4] via-[#9B72CB] to-[#D96570] pb-2">
   1927                             Hello, <span id="welcome-name" class="text-white truncate block md:inline max-w-[200px] md:max-w-none">${userName}</span>
   1928                         </h1>
   1929                         <!-- UPDATED COLOR -->
   1930                         <h2 class="text-3xl md:text-5xl font-medium text-gemini-textSecondary/5">How can I help you code today?</h2>
   1931                     </div>
   1932                     <div class="hidden md:flex flex-wrap gap-3 w-full">
   1933                         <button onclick="setPrompt('Debug this Python script')" class="group bg-gemini-surface hover:bg-gemini-surfaceHover text-gemini-text px-5 py-4 rounded-2xl text-sm font-medium transition-all text-left flex-1 min-w-[200px] border border-transparent hover:border-gemini-surfaceHover">
   1934                             <span class="block mb-1 text-gemini-blue group-hover:translate-x-1 transition-transform"><i data-lucide="bug" class="w-4 h-4 inline mr-1"></i> Debug</span>
   1935                         </button>
   1936                         <button onclick="setPrompt('Explain this concept')" class="group bg-gemini-surface hover:bg-gemini-surfaceHover text-gemini-text px-5 py-4 rounded-2xl text-sm font-medium transition-all text-left flex-1 min-w-[200px] border border-transparent hover:border-gemini-surfaceHover">
   1937                             <span class="block mb-1 text-gemini-purple group-hover:translate-x-1 transition-transform"><i data-lucide="book-open" class="w-4 h-4 inline mr-1"></i> Explain</span>
   1938                         </button>
   1939                         <button onclick="setPrompt('Refactor this function')" class="group bg-gemini-surface hover:bg-gemini-surfaceHover text-gemini-text px-5 py-4 rounded-2xl text-sm font-medium transition-all text-left flex-1 min-w-[200px] border border-transparent hover:border-gemini-surfaceHover">
   1940                             <span class="block mb-1 text-green-400 group-hover:translate-x-1 transition-transform"><i data-lucide="wand-2" class="w-4 h-4 inline mr-1"></i> Refactor</span>
   1941                         </button>
   1942                     </div>
   1943                 </div>`;
   1944             lucide.createIcons();
   1945             if (state.user && !state.user.isAnonymous) fetchChats();
   1946         }
   1947 
   1948         window.onload = initApp;
   1949 
   1950     </script>
   1951 </body>
   1952 </html>
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror