FastAPI HTTP server with auth, static files, and reverse proxy to brain/db services. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
145 lines
7.9 KiB
HTML
145 lines
7.9 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<meta name="theme-color" content="#1e1033">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<title>Egregore</title>
|
|
<link rel="manifest" href="/static/manifest.json">
|
|
<link rel="icon" type="image/svg+xml" href="/static/icon.svg">
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11/styles/github-dark.min.css">
|
|
<script src="https://cdn.jsdelivr.net/npm/highlight.js@11"></script>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
</head>
|
|
<body class="bg-purple-950 text-gray-100 h-screen flex flex-col">
|
|
<input type="hidden" id="model-select" value="claude-sonnet-4-20250514">
|
|
|
|
<!-- Header (mobile) -->
|
|
<header class="bg-purple-900 border-b border-purple-800 px-4 py-3 flex items-center justify-between shrink-0">
|
|
<h1 class="text-lg font-semibold">Egregore</h1>
|
|
<div class="flex items-center gap-1">
|
|
<button id="notify-btn" class="p-2 hover:bg-purple-800 rounded-lg" title="Notifications">
|
|
<svg id="notify-icon" class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path>
|
|
</svg>
|
|
</button>
|
|
<button id="search-btn" class="p-2 hover:bg-purple-800 rounded-lg" title="Search">
|
|
<svg class="w-5 h-5 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Search Modal -->
|
|
<div id="search-modal" class="hidden fixed inset-0 z-50 bg-black/70 backdrop-blur-sm">
|
|
<div class="flex flex-col h-full max-w-2xl mx-auto p-4">
|
|
<div class="flex items-center gap-3 bg-purple-900 rounded-xl p-3 border border-purple-700">
|
|
<svg class="w-5 h-5 text-gray-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
</svg>
|
|
<input
|
|
type="text"
|
|
id="search-input"
|
|
class="flex-1 bg-transparent focus:outline-none placeholder-gray-500"
|
|
placeholder="Search messages..."
|
|
autocomplete="off"
|
|
>
|
|
<button id="search-close" class="p-1 hover:bg-purple-800 rounded">
|
|
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<div id="search-results" class="flex-1 overflow-y-auto mt-4 space-y-2">
|
|
<div id="search-empty" class="text-center text-gray-500 mt-8">
|
|
<p>Type to search</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Context Menu (Desktop only) -->
|
|
<div id="context-menu" class="hidden fixed z-50 bg-purple-900 rounded-lg border border-purple-700 py-1 shadow-xl min-w-[140px]">
|
|
<button id="ctx-copy" class="w-full px-4 py-2 text-left text-sm hover:bg-purple-800 flex items-center gap-2">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="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>
|
|
</div>
|
|
|
|
<!-- Mobile Menu (Full screen) -->
|
|
<div id="mobile-menu" class="hidden fixed inset-0 z-50 bg-purple-950/95 backdrop-blur-sm flex flex-col">
|
|
<div class="flex-1 flex flex-col items-center justify-center gap-4 p-8">
|
|
<div id="mobile-menu-preview" class="text-gray-400 text-sm text-center max-w-xs mb-4 line-clamp-3"></div>
|
|
<button id="mobile-copy" class="w-full max-w-xs bg-purple-800 hover:bg-purple-700 rounded-xl py-4 px-6 flex items-center justify-center gap-3 text-lg">
|
|
<svg class="w-6 h-6" 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 Message
|
|
</button>
|
|
</div>
|
|
<button id="mobile-menu-close" class="p-6 text-gray-400 text-center">
|
|
Tap anywhere to close
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Messages -->
|
|
<main id="messages-scroll" class="flex-1 overflow-y-auto flex flex-col-reverse">
|
|
<div id="messages" class="p-4 space-y-4"></div>
|
|
</main>
|
|
|
|
<!-- Typing Indicator -->
|
|
<div id="typing-indicator" class="hidden px-4 py-2 text-sm text-gray-500">
|
|
<div class="flex items-center gap-2">
|
|
<div class="typing-dots flex gap-1">
|
|
<span></span><span></span><span></span>
|
|
</div>
|
|
<span>Egregore is thinking...</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Input Footer -->
|
|
<footer class="bg-purple-900 border-t border-purple-800 p-3 shrink-0">
|
|
<form id="chat-form" class="flex gap-2 items-end">
|
|
<button
|
|
type="button"
|
|
id="voice-btn"
|
|
class="bg-purple-800 hover:bg-purple-700 rounded-full p-3 transition-colors relative shrink-0"
|
|
title="Voice input"
|
|
>
|
|
<svg id="mic-icon" class="w-5 h-5 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path>
|
|
</svg>
|
|
<div id="mic-pulse" class="hidden absolute inset-0 rounded-full bg-red-500 animate-pulse opacity-50"></div>
|
|
</button>
|
|
<textarea
|
|
id="message-input"
|
|
class="flex-1 bg-purple-800 rounded-2xl px-4 py-3 resize-none focus:outline-none focus:ring-2 focus:ring-purple-400 placeholder-purple-400 text-base"
|
|
placeholder="Message..."
|
|
rows="1"
|
|
autofocus
|
|
></textarea>
|
|
<button
|
|
type="submit"
|
|
id="send-btn"
|
|
class="bg-purple-600 hover:bg-purple-500 disabled:bg-purple-900 disabled:cursor-not-allowed rounded-full p-3 transition-colors shrink-0"
|
|
>
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
|
|
</svg>
|
|
</button>
|
|
</form>
|
|
</footer>
|
|
|
|
<!-- Toast Container -->
|
|
<div id="toast-container" class="fixed bottom-24 left-1/2 -translate-x-1/2 z-50 flex flex-col gap-2 pointer-events-none"></div>
|
|
|
|
<script src="/static/app.js"></script>
|
|
</body>
|
|
</html>
|