ada-web

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

git clone https://github.com/notamitgamer/ada-web.git
· rebuilt hourlyOpen on GitHub
commit 117aef460e094308403a13517bea636863f67944
parent 736262f56a1ca26882e2cc893bb5d25d3758994a
Author: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Date:   Sun, 18 Jan 2026 07:20:00 +0000

Add enhanced code blocks with copy, compiler, and download functionality

Co-authored-by: notamitgamer <199483577+notamitgamer@users.noreply.github.com>

Diffstat:
Mindex.html | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest_backend.py | 13++++++++++++-
2 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/index.html b/index.html @@ -476,6 +476,112 @@ headerIds: false, mangle: false }); + + // Custom renderer for code blocks with copy/compiler/download buttons + const renderer = new marked.Renderer(); + renderer.code = function(code, lang) { + const language = lang || 'text'; + const escapedCode = code.replace(/</g, '&lt;').replace(/>/g, '&gt;'); + const codeId = 'code-' + Math.random().toString(36).substr(2, 9); + + return ` + <div class="code-block-wrapper"> + <div class="code-block-header"> + <span class="code-block-lang">${language}</span> + <div class="code-block-actions"> + <button class="code-block-btn" onclick="copyCodeBlock('${codeId}')"> + <svg class="w-3 h-3 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg> + Copy + </button> + <button class="code-block-btn" onclick="openInCompiler('${codeId}', '${language}')"> + <svg class="w-3 h-3 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path></svg> + Run + </button> + <button class="code-block-btn" onclick="downloadCodeBlock('${codeId}', '${language}')"> + <svg class="w-3 h-3 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg> + Download + </button> + </div> + </div> + <pre><code id="${codeId}" class="language-${language}">${escapedCode}</code></pre> + </div> + `; + }; + marked.setOptions({ renderer: renderer }); + + // Code block utility functions + window.copyCodeBlock = async function(codeId) { + const codeElement = document.getElementById(codeId); + if (!codeElement) return; + + const code = codeElement.textContent; + try { + await navigator.clipboard.writeText(code); + // Show success feedback + const btn = event.target.closest('button'); + const originalText = btn.innerHTML; + btn.innerHTML = '<svg class="w-3 h-3 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>Copied!'; + btn.classList.add('success'); + setTimeout(() => { + btn.innerHTML = originalText; + btn.classList.remove('success'); + }, 2000); + } catch (err) { + console.error('Failed to copy:', err); + } + } + + window.openInCompiler = function(codeId, language) { + const codeElement = document.getElementById(codeId); + if (!codeElement) return; + + const code = codeElement.textContent; + const compressed = LZString.compressToEncodedURIComponent(code); + + let urlLang = 'python'; + if (language === 'javascript' || language === 'js') urlLang = 'nodejs'; + else if (language === 'c' || language === 'cpp' || language === 'c++') urlLang = 'cpp'; + else if (language === 'java') urlLang = 'java'; + + window.open(`https://compiler.amit.is-a.dev/${urlLang}?code=${compressed}`, '_blank'); + } + + window.downloadCodeBlock = function(codeId, language) { + const codeElement = document.getElementById(codeId); + if (!codeElement) return; + + const code = codeElement.textContent; + const ext = getFileExtension(language); + const filename = `code.${ext}`; + + const blob = new Blob([code], { type: 'text/plain' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } + + function getFileExtension(language) { + const ext = { + 'python': 'py', + 'javascript': 'js', + 'java': 'java', + 'c': 'c', + 'cpp': 'cpp', + 'c++': 'cpp', + 'csharp': 'cs', + 'go': 'go', + 'rust': 'rs', + 'typescript': 'ts', + 'html': 'html', + 'css': 'css' + }; + return ext[language.toLowerCase()] || 'txt'; + } // --- AUTH LOGIC --- onAuthStateChanged(auth, (user) => { diff --git a/test_backend.py b/test_backend.py @@ -28,7 +28,18 @@ try: # Check if routes are defined routes = [rule.rule for rule in backend.app.url_map.iter_rules()] - expected_routes = ['/', '/api/chat', '/api/generate-title'] + expected_routes = [ + '/', + '/health', + '/api/chat', + '/api/generate-title', + '/api/profile', + '/api/chats', + '/api/chats/<chat_id>', + '/api/chats/<chat_id>/rename', + '/api/chats/<chat_id>/export', + '/api/chats/<chat_id>/pin' + ] for route in expected_routes: assert route in routes, f"Route {route} not found"