Files
ai-app-ckg/index.html

122 lines
6.4 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" />
<title>BitSage - CS Learning Companion</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
primary: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
}
},
animation: {
'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
'fade-in': 'fadeIn 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards',
'slide-up': 'slideUp 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards',
'bounce-in': 'bounceIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideUp: {
'0%': { transform: 'translateY(20px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
bounceIn: {
'0%': { transform: 'scale(0.9)', opacity: '0' },
'100%': { transform: 'scale(1)', opacity: '1' },
}
}
}
}
}
</script>
<!-- Direct Favicon Link -->
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232563eb' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z'/%3E%3Cpath d='M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z'/%3E%3C/svg%3E" />
<!-- PWA Manifest -->
<link rel="manifest" href="data:application/json;base64,ewogICJuYW1lIjogIkJpdFNhZ2UgLSBDUyBMZWFybmluZyBDb21wYW5pb24iLAogICJzaG9ydF9uYW1lIjogIkJpdFNhZ2UiLAogICJzdGFydF91cmwiOiAiLyIsCiAgImRpc3BsYXkiOiAiYnJvd3NlciIsCiAgImJhY2tncm91bmRfY29xvciI6ICIjZmZmZmZmIiwKICAidGhlbWVfY29xvciI6ICIjMjU2M2ViIiwKICAiaWNvbnMiOiBbCiAgICB7CiAgICAgICJzcmMiOiAiZGF0YTppbWFnZS9zdmcreG1sLCUzQ3N2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAyNCAyNCcgZmlsbD0nbm9uZScgc3Ryb2tlPSclMjMyNTYzZWInIHN0cm9rZS13aWR0aD0nMicgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJyBzdHJva2UtbGluZWpvaW49J3JvdW5kJ%2BJTNDcGF0aCBkPSdNOS41IDJBMi41IDIuNSAwIDAgMSAxMiA0LjV2MTVhMi41IDIuNSAwIDAgMS00Ljk2LjQ0IDIuNSAyLjUgMCAwIDEtMi45Ni0zLjA4IDMgMyAwIDAgMS0uMzQtNS41OCAyLjUgMi41IDAgMCAxIDEuMzItNC4yNCAyLjUgMi41IDAgMCAxIDEuMzItNC4yNCAyLjUgMi41IDAgMCAxIDEuOTgtM0EyLjUgMi41IDAgMCAxIDkuNSAyWicvJTNFJTNDcGF0aCBkPSdNMTQuNSAyQTIuNSAyLjUgMCAwIDAgMTIgNC41djE1YTIuNSAyLjUgMCAwIDAgNC45Ni40NCAyLjUgMi41IDAgMCAwIDIuOTYtMy4wOCAzIDMgMCAwIDAgLjM0LTUuNTggMi41IDIuNSAwIDAgMC0xLjMyLTQuMjQgMi41IDIuNSAwIDAgMC0xLjk4LTNBMi41IDIuNSAwIDAgMCAxNC41IDJaJy8lM0UlM0Mvc3ZnJTNFLg0KIiwKICAgICAgInR5cGUiOiAiaW1hZ2Uvc3ZnK3htbCIsCiAgICAgICJzaXplcyI6ICIxOTJ4MTkyIDUxMng1MTIiCiAgICB9CiAgXQp9" />
<style>
/* Custom scrollbar for webkit */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 3px; }
.dark ::-webkit-scrollbar-thumb { background: #475569; }
/* Markdown content styles */
.markdown-body p { margin-bottom: 0.75em; line-height: 1.6; }
.markdown-body ul { list-style-type: disc; padding-left: 1.5em; margin-bottom: 0.75em; }
.markdown-body ol { list-style-type: decimal; padding-left: 1.5em; margin-bottom: 0.75em; }
.markdown-body pre { background: #f1f5f9; padding: 1em; border-radius: 0.5em; overflow-x: auto; margin-bottom: 1em; }
.dark .markdown-body pre { background: #1e293b; }
.markdown-body code { font-family: monospace; background: #e2e8f0; padding: 0.1em 0.3em; border-radius: 0.25em; font-size: 0.9em; }
.dark .markdown-body code { background: #334155; color: #e2e8f0; }
.markdown-body pre code { background: transparent; padding: 0; color: inherit; }
.markdown-body h1, .markdown-body h2, .markdown-body h3 { font-weight: 700; margin-top: 1.5em; margin-bottom: 0.5em; }
.markdown-body h1 { font-size: 1.5em; }
.markdown-body h2 { font-size: 1.25em; }
.markdown-body a { color: #3b82f6; text-decoration: underline; }
/* Typing Indicator Animation */
.typing-indicator {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 0;
}
.typing-indicator span {
display: inline-block;
width: 6px;
height: 6px;
background-color: #94a3b8; /* slate-400 */
border-radius: 50%;
animation: typingBounce 1.4s infinite ease-in-out both;
}
.typing-indicator span:nth-child(1) { animation-delay: -0.32s; }
.typing-indicator span:nth-child(2) { animation-delay: -0.16s; }
@keyframes typingBounce {
0%, 80%, 100% { transform: scale(0); opacity: 0.6; }
40% { transform: scale(1); opacity: 1; }
}
</style>
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@^19.2.3",
"react-dom/": "https://esm.sh/react-dom@^19.2.3/",
"react/": "https://esm.sh/react@^19.2.3/",
"@google/genai": "https://esm.sh/@google/genai@^1.34.0",
"lucide-react": "https://esm.sh/lucide-react@^0.562.0",
"react-markdown": "https://esm.sh/react-markdown@^10.1.0",
"remark-gfm": "https://esm.sh/remark-gfm@^4.0.1",
"html2canvas": "https://esm.sh/html2canvas@^1.4.1",
"vite": "https://esm.sh/vite@^7.3.0",
"@vitejs/plugin-react": "https://esm.sh/@vitejs/plugin-react@^5.1.2"
}
}
</script>
</head>
<body class="bg-gray-50 dark:bg-slate-900 text-gray-900 dark:text-gray-100 h-[100dvh] overflow-hidden">
<div id="root" class="h-full"></div>
<script type="module" src="/index.tsx"></script>
</body>
</html>