ada-web

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

indexbackup_20-01-2026_01.html (83066B)


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