Spaces:
Sleeping
Sleeping
| <html lang="en" class="dark"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>{% block title %}Multi-RAG Studio{% endblock %}</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="{{ url_for('static', path='/js/main.js') }}"></script> | |
| {% block extra_head %}{% endblock %} | |
| </head> | |
| <body class="bg-slate-950 text-slate-100 flex flex-col min-h-screen relative overflow-x-hidden selection:bg-indigo-600 selection:text-white"> | |
| <!-- Ambient background glows --> | |
| <div class="absolute top-0 left-1/4 w-[500px] h-[500px] bg-indigo-900/20 rounded-full blur-[120px] pointer-events-none -z-10 animate-pulse" style="animation-duration: 10s;"></div> | |
| <div class="absolute bottom-0 right-1/4 w-[600px] h-[600px] bg-purple-900/10 rounded-full blur-[150px] pointer-events-none -z-10 animate-pulse" style="animation-duration: 15s;"></div> | |
| <!-- Grid Overlay (Radial Dots grid using Tailwind-friendly inline styles) --> | |
| <div class="absolute inset-0 pointer-events-none -z-20 opacity-20" style="background-image: radial-gradient(rgba(255,255,255,0.15) 1px, transparent 1px); background-size: 24px 24px;"></div> | |
| <nav class="sticky top-0 z-50 bg-slate-950/45 backdrop-blur-md border-b border-white/5 shadow-lg"> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div class="flex items-center justify-between h-16"> | |
| <div class="flex items-center space-x-3 cursor-pointer group"> | |
| <div class="relative"> | |
| <div class="absolute inset-0 bg-indigo-500 rounded-lg blur-md opacity-70 group-hover:opacity-100 transition-opacity"></div> | |
| <div class="relative bg-gradient-to-tr from-indigo-600 to-purple-600 p-2 rounded-lg text-white font-extrabold tracking-wider text-sm shadow-lg"> | |
| M-RAG | |
| </div> | |
| </div> | |
| <span class="font-extrabold text-xl bg-gradient-to-r from-white via-slate-200 to-slate-400 bg-clip-text text-transparent group-hover:to-white transition-all"> | |
| Multi-RAG <span class="text-xs font-bold text-indigo-400 uppercase tracking-widest ml-1 bg-indigo-500/10 px-2 py-0.5 rounded-full border border-indigo-500/20">Studio</span> | |
| </span> | |
| </div> | |
| <div class="hidden md:flex space-x-8 text-sm font-semibold"> | |
| <a href="/" class="text-indigo-400 border-b-2 border-indigo-500 px-1 py-5 transition-all">Home</a> | |
| <a href="#" class="text-slate-400 hover:text-white transition duration-200 px-1 py-5">Knowledge Base</a> | |
| <a href="#" class="text-slate-400 hover:text-white transition duration-200 px-1 py-5">Analytics</a> | |
| <a href="#" class="text-slate-400 hover:text-white transition duration-200 px-1 py-5">Settings</a> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <a href="#" class="text-slate-400 hover:text-white transition text-sm font-semibold hidden sm:inline-block">Docs</a> | |
| <!-- Global session countdown timer (hidden until a session starts) --> | |
| <div id="global-timer-wrapper" class="hidden"> | |
| <div id="global-timer-badge" | |
| class="inline-flex items-center space-x-1.5 px-3 py-1.5 rounded-lg bg-indigo-500/20 border border-indigo-500/30 text-indigo-400 text-sm font-extrabold tabular-nums tracking-wide"> | |
| <svg class="w-3.5 h-3.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"> | |
| <circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/> | |
| </svg> | |
| <span>--:--</span> | |
| </div> | |
| </div> | |
| <button class="relative group overflow-hidden bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-500 hover:to-purple-500 text-white px-5 py-2 rounded-lg text-sm font-bold shadow-lg shadow-indigo-500/25 transition-all duration-300"> | |
| <span class="relative z-10">New Chat</span> | |
| <div class="absolute inset-0 bg-white/10 opacity-0 group-hover:opacity-100 transition-opacity"></div> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </nav> | |
| <main class="flex-grow max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 py-10 relative z-10"> | |
| {% block main %} | |
| I am the main body | |
| {% endblock %} | |
| </main> | |
| <footer class="bg-slate-950/45 backdrop-blur-md border-t border-white/5 py-8 text-sm text-slate-500 mt-auto"> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col sm:flex-row items-center justify-between space-y-4 sm:space-y-0"> | |
| <div class="flex items-center space-x-2"> | |
| <span class="font-bold text-slate-400">Multi-RAG Studio</span> | |
| <span class="text-slate-600">|</span> | |
| <span>© 2026. All rights reserved.</span> | |
| </div> | |
| <div class="flex space-x-6 text-slate-400 font-medium"> | |
| <a href="#" class="hover:text-indigo-400 transition duration-150">Documentation</a> | |
| <a href="#" class="hover:text-indigo-400 transition duration-150">API Reference</a> | |
| <a href="#" class="hover:text-indigo-400 transition duration-150">Privacy Policy</a> | |
| </div> | |
| </div> | |
| </footer> | |
| {% block extra_scripts %}{% endblock %} | |
| <!-- βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| GLOBAL SESSION TIMER β runs on every page | |
| Reads from localStorage so it survives navigation. | |
| Upload page saves: multirag_session_start (epoch ms) | |
| multirag_session_duration (seconds) | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <script> | |
| (function () { | |
| const STORAGE_START = 'multirag_session_start'; // epoch ms when login happened | |
| const STORAGE_DURATION = 'multirag_session_duration'; // total session seconds | |
| const wrapper = document.getElementById('global-timer-wrapper'); | |
| const badge = document.getElementById('global-timer-badge'); | |
| const badgeSpan = badge ? badge.querySelector('span') : null; | |
| function fmtTime(s) { | |
| if (s <= 0) return '00:00'; | |
| const h = Math.floor(s / 3600); | |
| const m = Math.floor((s % 3600) / 60); | |
| const sec = s % 60; | |
| if (h > 0) | |
| return h + ':' + String(m).padStart(2,'0') + ':' + String(sec).padStart(2,'0'); | |
| return String(m).padStart(2,'0') + ':' + String(sec).padStart(2,'0'); | |
| } | |
| function startNavTimer() { | |
| const start = parseInt(localStorage.getItem(STORAGE_START), 10); | |
| const duration = parseInt(localStorage.getItem(STORAGE_DURATION), 10); | |
| if (!start || !duration) return; // no session saved yet | |
| const expiresAt = start + duration * 1000; // epoch ms | |
| if (wrapper) wrapper.classList.remove('hidden'); | |
| let interval; | |
| function tick() { | |
| const remaining = Math.max(0, Math.round((expiresAt - Date.now()) / 1000)); | |
| if (badgeSpan) badgeSpan.textContent = fmtTime(remaining); | |
| if (remaining <= 60) { | |
| badge.classList.remove('bg-indigo-500/20','text-indigo-400','border-indigo-500/30'); | |
| badge.classList.add('bg-red-500/20','text-red-400','border-red-500/40'); | |
| } | |
| if (remaining <= 0) { | |
| clearInterval(interval); | |
| if (badgeSpan) badgeSpan.textContent = 'EXPIRED'; | |
| badge.classList.add('opacity-60'); | |
| // clean up storage so timer doesn't haunt the next session | |
| localStorage.removeItem(STORAGE_START); | |
| localStorage.removeItem(STORAGE_DURATION); | |
| } | |
| } | |
| tick(); | |
| interval = setInterval(tick, 1000); | |
| } | |
| // Auto-start on every page as soon as DOM is ready | |
| startNavTimer(); | |
| // Also expose so upload.html can call it after saving to localStorage | |
| window.__startNavTimer = startNavTimer; | |
| })(); | |
| </script> | |
| </body> | |
| </html> |