File size: 35,448 Bytes
ac5ebc8 fe77b2f ac5ebc8 fe77b2f ac5ebc8 fe77b2f e0581b4 fe77b2f e0581b4 58bd7e3 e0581b4 fe77b2f 58bd7e3 e0581b4 58bd7e3 fe77b2f e0581b4 fe77b2f e0581b4 fe77b2f 58bd7e3 fe77b2f 58bd7e3 fe77b2f a2d424a 58bd7e3 fe77b2f 58bd7e3 fe77b2f 58bd7e3 fe77b2f a2d424a fe77b2f a2d424a fe77b2f a2d424a fe77b2f 58bd7e3 fe77b2f 58bd7e3 fe77b2f 58bd7e3 fe77b2f c0f04fe fe77b2f c0f04fe fe77b2f ac5ebc8 fe77b2f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
<!DOCTYPE html>
<html lang="en" class="h-full">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AI Chat — Tailwind (Dribbble-inspired)</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
border: 'hsl(240 5% 84%)',
background: 'hsl(0 0% 100%)',
foreground: 'hsl(222 47% 11%)',
}
}
}
}
</script>
<style>
.scrollbar-thin{scrollbar-width:thin} .scrollbar-thin::-webkit-scrollbar{height:8px;width:8px} .scrollbar-thin::-webkit-scrollbar-thumb{border-radius:9999px;background-color:#c7c7d0} .scrollbar-thin::-webkit-scrollbar-track{background-color:transparent}
</style>
</head>
<body class="h-full bg-white text-slate-900 antialiased dark:bg-zinc-900 dark:text-zinc-100">
<div id="app" class="flex h-dvh w-full flex-col">
<!-- Top Bar -->
<header class="flex items-center gap-2 border-b border-zinc-200 px-3 py-2 dark:border-zinc-800">
<button id="btn-open-left" class="lg:hidden inline-flex h-9 w-9 items-center justify-center rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800" aria-label="Open left panel">
<!-- panel-left -->
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 4v16"/><path d="M7 4v16"/><path d="M11 6h10"/><path d="M11 12h10"/><path d="M11 18h10"/></svg>
</button>
<div class="flex items-center gap-2">
<div class="h-7 w-7 rounded-xl bg-gradient-to-tr from-indigo-500/80 to-indigo-600"></div>
<div class="text-sm font-semibold tracking-tight">Nova AI</div>
</div>
<div class="mx-2 hidden h-6 w-px bg-zinc-200 lg:block dark:bg-zinc-800"></div>
<!-- Search -->
<div class="relative hidden max-w-lg flex-1 lg:block">
<svg class="pointer-events-none absolute left-3 top-2.5 h-4 w-4 text-zinc-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
<input type="text" placeholder="Search messages, files, prompts…" class="w-full rounded-md border border-zinc-200 bg-white pl-9 pr-3 py-2 text-sm outline-none ring-indigo-500 transition focus:border-indigo-500 dark:border-zinc-800 dark:bg-zinc-900" />
</div>
<div class="ml-auto flex items-center gap-1">
<!-- Model Dropdown -->
<div class="relative" id="model-dd">
<button class="inline-flex items-center gap-2 rounded-md border border-zinc-200 px-3 py-1.5 text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-800" data-dd-trigger>
<span id="current-model-name">Qwen 3 Coder 30B</span>
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
</button>
<div class="absolute right-0 z-40 mt-2 hidden w-64 overflow-hidden rounded-md border border-zinc-200 bg-white p-1 text-sm shadow-lg dark:border-zinc-800 dark:bg-zinc-900" data-dd-menu>
<div class="px-2 py-1 text-xs font-medium text-zinc-500">Dostupné modely</div>
<button class="model-option flex w-full items-center gap-3 rounded-md px-2 py-2 hover:bg-zinc-100 dark:hover:bg-zinc-800" data-model-id="qwen-coder-3-30b">
<span class="w-2 h-2 bg-green-500 rounded-full flex-shrink-0"></span>
<div class="flex-1 text-left">
<div class="font-medium">Qwen 3 Coder 30B</div>
<div class="text-xs text-zinc-500">Výkonný model pro programování</div>
</div>
</button>
<button class="model-option flex w-full items-center gap-3 rounded-md px-2 py-2 hover:bg-zinc-100 dark:hover:bg-zinc-800" data-model-id="qwen-4b-thinking">
<span class="w-2 h-2 bg-blue-500 rounded-full flex-shrink-0"></span>
<div class="flex-1 text-left">
<div class="font-medium">Qwen 4B Thinking</div>
<div class="text-xs text-zinc-500">Rychlejší odlehčený model</div>
</div>
</button>
<div class="my-1 h-px bg-zinc-200 dark:bg-zinc-800"></div>
<div class="px-2 py-1 text-xs text-zinc-400">
<div class="flex items-center gap-1">
<svg class="h-3 w-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
<span id="model-response-time">Response time: ~2-5s</span>
</div>
</div>
</div>
</div>
<!-- Theme toggle -->
<button id="btn-theme" class="inline-flex h-9 w-9 items-center justify-center rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800" aria-label="Toggle theme">
<span class="sr-only">Toggle theme</span>
<svg id="icon-sun" class="h-5 w-5 hidden" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>
<svg id="icon-moon" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
<!-- Right panel button (mobile) -->
<button id="btn-open-right" class="lg:hidden inline-flex h-9 w-9 items-center justify-center rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800" aria-label="Open right panel">
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M15 3v18"/></svg>
</button>
<button class="hidden sm:inline-flex items-center gap-2 rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-indigo-700"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>New</button>
<button class="hidden sm:inline-flex items-center gap-2 rounded-md border border-zinc-200 px-3 py-1.5 text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-800"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v2"/><path d="M12 19v2"/><rect x="4" y="7" width="16" height="10" rx="2"/></svg>Settings</button>
</div>
</header>
<div class="flex min-h-0 flex-1">
<!-- Left Sidebar (desktop) -->
<aside class="hidden w-72 flex-col border-r border-zinc-200 lg:flex dark:border-zinc-800" id="left-desktop">
<div class="p-3">
<button class="inline-flex w-full items-center gap-2 rounded-md border border-zinc-200 px-3 py-2 text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-800"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>New chat</button>
</div>
<div class="px-3 pb-2">
<div class="relative">
<svg class="absolute left-2 top-2.5 h-4 w-4 text-zinc-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
<input class="w-full rounded-md border border-zinc-200 bg-white pl-8 pr-3 py-2 text-sm outline-none ring-indigo-500 transition focus:border-indigo-500 dark:border-zinc-800 dark:bg-zinc-900" placeholder="Search chats" />
</div>
</div>
<div class="h-px bg-zinc-200 dark:bg-zinc-800"></div>
<div class="flex-1 overflow-y-auto p-2 scrollbar-thin">
<!-- chat list
<button class="group flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left hover:bg-zinc-100 dark:hover:bg-zinc-800">
<svg class="h-4 w-4 text-zinc-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 12c2 0 4 1 5 3-1 2-3 3-5 3s-4-1-5-3c1-2 3-3 5-3Z"/><circle cx="12" cy="8" r="3"/></svg>
<div class="min-w-0 flex-1"><div class="truncate text-sm font-medium">Build Tailwind Navbar</div><div class="truncate text-xs text-zinc-500">Today</div></div>
<svg class="h-4 w-4 opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg>
</button>
<button class="group flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left hover:bg-zinc-100 dark:hover:bg-zinc-800">
<svg class="h-4 w-4 text-zinc-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 12c2 0 4 1 5 3-1 2-3 3-5 3s-4-1-5-3c1-2 3-3 5-3Z"/><circle cx="12" cy="8" r="3"/></svg>
<div class="min-w-0 flex-1"><div class="truncate text-sm font-medium">Optimize React hooks</div><div class="truncate text-xs text-zinc-500">Today</div></div>
<svg class="h-4 w-4 opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg>
</button>
<button class="group flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left hover:bg-zinc-100 dark:hover:bg-zinc-800">
<svg class="h-4 w-4 text-zinc-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 12c2 0 4 1 5 3-1 2-3 3-5 3s-4-1-5-3c1-2 3-3 5-3Z"/><circle cx="12" cy="8" r="3"/></svg>
<div class="min-w-0 flex-1"><div class="truncate text-sm font-medium">Write SQL for analytics</div><div class="truncate text-xs text-zinc-500">Yesterday</div></div>
<svg class="h-4 w-4 opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg>
</button>
-->
</div>
<div class="h-px bg-zinc-200 dark:bg-zinc-800"></div>
<div class="flex items-center justify-between p-3">
<div class="flex items-center gap-2">
<div class="h-8 w-8 overflow-hidden rounded-full bg-zinc-200 dark:bg-zinc-700"></div>
<div>
<div class="text-sm font-medium">You</div>
<div class="text-xs text-zinc-500">Free plan</div>
</div>
</div>
<button class="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800" aria-label="Account">
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v2"/><path d="M12 19v2"/><rect x="4" y="7" width="16" height="10" rx="2"/></svg>
</button>
</div>
</aside>
<!-- Mobile Left Sheet -->
<aside id="left-sheet" class="fixed inset-y-0 left-0 z-50 w-72 -translate-x-full transform border-r border-zinc-200 bg-white transition-transform duration-200 ease-out dark:border-zinc-800 dark:bg-zinc-900 lg:hidden">
<div class="flex h-full flex-col">
<div class="flex items-center justify-between border-b border-zinc-200 p-3 dark:border-zinc-800">
<div class="text-sm font-semibold">Conversations</div>
<button id="btn-close-left" class="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800" aria-label="Close">
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
</div>
<div class="flex-1 overflow-y-auto p-2 scrollbar-thin">
<!-- reuse simple list -->
<button class="group flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left hover:bg-zinc-100 dark:hover:bg-zinc-800">
<svg class="h-4 w-4 text-zinc-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 12c2 0 4 1 5 3-1 2-3 3-5 3s-4-1-5-3c1-2 3-3 5-3Z"/><circle cx="12" cy="8" r="3"/></svg>
<div class="min-w-0 flex-1"><div class="truncate text-sm font-medium">Design prompt library</div><div class="truncate text-xs text-zinc-500">Today</div></div>
<svg class="h-4 w-4 opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg>
</button>
</div>
</div>
</aside>
<div id="left-overlay" class="fixed inset-0 z-40 hidden bg-black/40 opacity-0 transition-opacity lg:hidden"></div>
<!-- Main Column -->
<main class="flex min-w-0 flex-1 flex-col">
<!-- Chat header -->
<div class="flex items-center gap-3 border-b border-zinc-200 px-4 py-3 sm:px-6 dark:border-zinc-800">
<div class="flex h-9 w-9 items-center justify-center rounded-xl bg-indigo-600/10 text-indigo-600 dark:text-indigo-400">
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 12c2 0 4 1 5 3-1 2-3 3-5 3s-4-1-5-3c1-2 3-3 5-3Z"/><circle cx="12" cy="8" r="3"/></svg>
</div>
<div class="min-w-0">
<div class="truncate text-sm font-semibold" id="chat-title">New Chat</div>
<div class="truncate text-xs text-zinc-500 dark:text-zinc-400">Using Qwen 3 Coder • Ready to help</div>
</div>
<div class="ml-auto flex items-center gap-2">
<span class="hidden rounded-md border border-zinc-200 px-2 py-1 text-xs sm:inline-flex dark:border-zinc-800">/chat</span>
<button class="inline-flex items-center gap-2 rounded-md border border-zinc-200 px-3 py-1.5 text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-800"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12v7a1 1 0 0 0 1 1h7"/><path d="m21 3-9 9"/><path d="M15 3h6v6"/></svg>Share</button>
<div class="relative" id="chat-more">
<button class="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800" data-dd-trigger aria-label="More"><svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg></button>
<div class="absolute right-0 z-30 mt-2 hidden w-40 overflow-hidden rounded-md border border-zinc-200 bg-white p-1 text-sm shadow-lg dark:border-zinc-800 dark:bg-zinc-900" data-dd-menu>
<button class="flex w-full items-center gap-2 rounded-md px-2 py-1.5 hover:bg-zinc-100 dark:hover:bg-zinc-800"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 17l-5-5 5-5"/><path d="M19 17l-5-5 5-5"/></svg>Pin</button>
<button class="flex w-full items-center gap-2 rounded-md px-2 py-1.5 hover:bg-zinc-100 text-red-600 dark:hover:bg-zinc-800 dark:text-red-400"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M10 11v6"/><path d="M14 11v6"/></svg>Delete</button>
</div>
</div>
</div>
</div>
<!-- Messages -->
<div id="msg-scroll" class="flex-1 overflow-y-auto">
<div id="messages" class="mx-auto w-full max-w-3xl">
<!-- assistant message 1 -->
<div class="relative flex items-start gap-3 px-4 py-5 sm:px-6">
<div class="mt-1 h-8 w-8 shrink-0 overflow-hidden rounded-full bg-zinc-200"></div>
<div class="min-w-0 flex-1">
<div class="mb-1 flex items-baseline gap-2"><div class="text-sm font-medium">Ava</div><div class="text-xs text-zinc-500">19:04</div></div>
<div class="prose prose-sm max-w-none rounded-2xl border border-zinc-200 bg-zinc-50 p-4 dark:prose-invert dark:border-zinc-800 dark:bg-zinc-800/60">
<p>Ahoj! 👋 Jsem tvůj AI asistent. Jaký úkol dnes řešíš?</p>
<div class="mt-3 flex flex-wrap gap-2">
<span class="inline-flex cursor-pointer select-none items-center rounded-md bg-zinc-100 px-2.5 py-1 text-xs ring-1 ring-inset ring-zinc-200 dark:bg-zinc-800 dark:ring-zinc-700" data-suggest>Refactor code</span>
<span class="inline-flex cursor-pointer select-none items-center rounded-md bg-zinc-100 px-2.5 py-1 text-xs ring-1 ring-inset ring-zinc-200 dark:bg-zinc-800 dark:ring-zinc-700" data-suggest>Generate unit tests</span>
<span class="inline-flex cursor-pointer select-none items-center rounded-md bg-zinc-100 px-2.5 py-1 text-xs ring-1 ring-inset ring-zinc-200 dark:bg-zinc-800 dark:ring-zinc-700" data-suggest>Explain this snippet</span>
<span class="inline-flex cursor-pointer select-none items-center rounded-md bg-zinc-100 px-2.5 py-1 text-xs ring-1 ring-inset ring-zinc-200 dark:bg-zinc-800 dark:ring-zinc-700" data-suggest>Create README</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Composer -->
<div class="border-t border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900">
<div class="mx-auto max-w-3xl px-4 py-4 sm:px-6">
<div class="rounded-2xl border border-zinc-200 bg-white p-3 shadow-sm dark:border-zinc-800 dark:bg-zinc-900">
<div class="flex items-center gap-2 px-1">
<button class="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800" title="Attach file"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05 12 20.5a6 6 0 1 1-8.49-8.49l9.19-9.19A4 4 0 0 1 19.86 8l-9.19 9.19a2 2 0 1 1-2.83-2.83L16.34 6.66"/></svg></button>
<button class="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800" title="Insert image"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L7 20"/></svg></button>
<button class="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800" title="Voice"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 1v11a3 3 0 0 1-6 0V1"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><path d="M12 19v4"/></svg></button>
<div class="ml-auto flex items-center gap-2 text-xs text-zinc-500">
<span class="rounded bg-zinc-100 px-2 py-0.5 dark:bg-zinc-800">Web</span>
<span class="rounded border px-2 py-0.5 dark:border-zinc-700">Files</span>
<span class="rounded border px-2 py-0.5 dark:border-zinc-700">Code</span>
</div>
</div>
<textarea id="composer" placeholder="Ask anything…" class="mt-2 w-full min-h-[96px] max-h-40 resize-y border-0 bg-transparent p-0 text-sm outline-none focus:ring-0"></textarea>
<div class="mt-2 flex items-center justify-between">
<div class="text-xs text-zinc-500">Shift+Enter = new line</div>
<div class="flex items-center gap-2">
<button id="btn-stop" class="inline-flex items-center gap-2 rounded-md border border-zinc-200 px-3 py-1.5 text-sm hover:bg-zinc-50 dark:border-zinc-800 dark:hover:bg-zinc-800 hidden"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="20" rx="2"/><path d="M12 8v8"/><path d="M8 12h8"/></svg>Stop</button>
<button id="btn-send" class="inline-flex items-center gap-2 rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 2 11 13"/><path d="M22 2 15 22 11 13 2 9 22 2z"/></svg>Send</button>
</div>
</div>
</div>
<div class="mt-2 flex flex-wrap gap-2 text-xs text-zinc-500"><span class="cursor-pointer rounded border px-2 py-0.5 dark:border-zinc-700">/summarize</span><span class="cursor-pointer rounded border px-2 py-0.5 dark:border-zinc-700">/translate</span><span class="cursor-pointer rounded border px-2 py-0.5 dark:border-zinc-700">/fix</span></div>
</div>
</div>
</main>
<!-- Right Panel (desktop) -->
<aside class="hidden w-80 flex-col border-l border-zinc-200 lg:flex dark:border-zinc-800">
<div class="p-4">
<div class="mb-2 text-sm font-semibold">Quick actions</div>
<div class="grid gap-2">
<button class="inline-flex items-center rounded-md bg-zinc-100 px-3 py-2 text-sm hover:bg-zinc-200 dark:bg-zinc-700 dark:hover:bg-zinc-600"><svg class="mr-2 h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v20"/><path d="M5 7h14"/></svg>Summarize this page</button>
<button class="inline-flex items-center rounded-md bg-zinc-100 px-3 py-2 text-sm hover:bg-zinc-200 dark:bg-zinc-700 dark:hover:bg-zinc-600"><svg class="mr-2 h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16v4H4z"/><path d="M4 12h16v8H4z"/></svg>Draft an email</button>
<button class="inline-flex items-center rounded-md bg-zinc-100 px-3 py-2 text-sm hover:bg-zinc-200 dark:bg-zinc-700 dark:hover:bg-zinc-600"><svg class="mr-2 h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>Explain like I'm 5</button>
<button class="inline-flex items-center rounded-md bg-zinc-100 px-3 py-2 text-sm hover:bg-zinc-200 dark:bg-zinc-700 dark:hover:bg-zinc-600"><svg class="mr-2 h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M3 12h18"/><path d="M3 18h18"/></svg>Create tasks</button>
</div>
</div>
<div class="h-px bg-zinc-200 dark:bg-zinc-800"></div>
<div class="p-4">
<div class="mb-2 text-sm font-semibold">Tools</div>
<div class="space-y-3 text-sm">
<div class="flex items-center justify-between"><div class="flex items-center gap-2"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Web browsing</div><label class="relative inline-flex cursor-pointer items-center"><input type="checkbox" class="peer sr-only" checked><div class="peer h-5 w-9 rounded-full bg-zinc-300 after:absolute after:left-0.5 after:top-0.5 after:h-4 after:w-4 after:rounded-full after:bg-white after:transition peer-checked:bg-indigo-600 peer-checked:after:translate-x-4"></div></label></div>
<div class="flex items-center justify-between"><div class="flex items-center gap-2"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 22h16"/><path d="M4 2h16"/><path d="M4 2v20"/><path d="M20 2v20"/><path d="M7 7h10"/><path d="M7 12h10"/><path d="M7 17h10"/></svg>Files</div><label class="relative inline-flex cursor-pointer items-center"><input type="checkbox" class="peer sr-only"><div class="peer h-5 w-9 rounded-full bg-zinc-300 after:absolute after:left-0.5 after:top-0.5 after:h-4 after:w-4 after:rounded-full after:bg-white after:transition peer-checked:bg-indigo-600 peer-checked:after:translate-x-4"></div></label></div>
<div class="flex items-center justify-between"><div class="flex items-center gap-2"><svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="M7 15h0"/><path d="M2 9h20"/></svg>Code interpreter</div><label class="relative inline-flex cursor-pointer items-center"><input type="checkbox" class="peer sr-only"><div class="peer h-5 w-9 rounded-full bg-zinc-300 after:absolute after:left-0.5 after:top-0.5 after:h-4 after:w-4 after:rounded-full after:bg-white after:transition peer-checked:bg-indigo-600 peer-checked:after:translate-x-4"></div></label></div>
</div>
</div>
<div class="h-px bg-zinc-200 dark:bg-zinc-800"></div>
<div class="p-4">
<div class="mb-2 text-sm font-semibold">Shortcuts</div>
<div class="flex flex-wrap gap-2 text-xs text-zinc-500"><span class="rounded border px-2 py-0.5 dark:border-zinc-700">⌘K</span><span class="rounded border px-2 py-0.5 dark:border-zinc-700">/help</span><span class="rounded border px-2 py-0.5 dark:border-zinc-700">⌘/</span></div>
</div>
</aside>
<!-- Right sheet (mobile) -->
<aside id="right-sheet" class="fixed inset-y-0 right-0 z-50 w-80 translate-x-full transform border-l border-zinc-200 bg-white transition-transform duration-200 ease-out dark:border-zinc-800 dark:bg-zinc-900 lg:hidden">
<div class="flex items-center justify-between border-b border-zinc-200 p-3 dark:border-zinc-800"><div class="text-sm font-semibold">Actions & tools</div><button id="btn-close-right" class="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-800" aria-label="Close"><svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg></button></div>
<div class="p-4 space-y-4">
<div>
<div class="mb-2 text-sm font-semibold">Quick actions</div>
<div class="grid gap-2">
<button class="inline-flex items-center rounded-md bg-zinc-100 px-3 py-2 text-sm hover:bg-zinc-200 dark:bg-zinc-700 dark:hover:bg-zinc-600">Summarize this page</button>
<button class="inline-flex items-center rounded-md bg-zinc-100 px-3 py-2 text-sm hover:bg-zinc-200 dark:bg-zinc-700 dark:hover:bg-zinc-600">Draft an email</button>
<button class="inline-flex items-center rounded-md bg-zinc-100 px-3 py-2 text-sm hover:bg-zinc-200 dark:bg-zinc-700 dark:hover:bg-zinc-600">Explain like I'm 5</button>
<button class="inline-flex items-center rounded-md bg-zinc-100 px-3 py-2 text-sm hover:bg-zinc-200 dark:bg-zinc-700 dark:hover:bg-zinc-600">Create tasks</button>
</div>
</div>
</div>
</aside>
<div id="right-overlay" class="fixed inset-0 z-40 hidden bg-black/40 opacity-0 transition-opacity lg:hidden"></div>
</div>
</div>
<!-- Enhanced JavaScript for AI Chat Application -->
<script src="utils.js"></script>
<script src="i18n.js"></script>
<script src="app.js"></script>
<script>
// Theme toggle
const btnTheme = document.getElementById('btn-theme');
const iconSun = document.getElementById('icon-sun');
const iconMoon = document.getElementById('icon-moon');
function setDark(on){
document.documentElement.classList.toggle('dark', on);
iconSun.classList.toggle('hidden', !on);
iconMoon.classList.toggle('hidden', on);
}
setDark(document.documentElement.classList.contains('dark'))
btnTheme.addEventListener('click', ()=> setDark(!document.documentElement.classList.contains('dark')));
// Simple dropdowns (model + chat more)
document.querySelectorAll('[data-dd-trigger]').forEach(btn=>{
const root = btn.closest('div');
const menu = root.querySelector('[data-dd-menu]');
btn.addEventListener('click', (e)=>{ e.stopPropagation(); menu.classList.toggle('hidden'); });
document.addEventListener('click', ()=> menu.classList.add('hidden'));
});
// Left sheet
const leftSheet = document.getElementById('left-sheet');
const leftOverlay = document.getElementById('left-overlay');
document.getElementById('btn-open-left').addEventListener('click', ()=>{
leftSheet.classList.remove('-translate-x-full'); leftOverlay.classList.remove('hidden'); requestAnimationFrame(()=>leftOverlay.classList.add('opacity-100'));
});
document.getElementById('btn-close-left').addEventListener('click', closeLeft);
leftOverlay.addEventListener('click', closeLeft);
function closeLeft(){ leftSheet.classList.add('-translate-x-full'); leftOverlay.classList.remove('opacity-100'); setTimeout(()=>leftOverlay.classList.add('hidden'),150); }
// Right sheet
const rightSheet = document.getElementById('right-sheet');
const rightOverlay = document.getElementById('right-overlay');
document.getElementById('btn-open-right').addEventListener('click', ()=>{
rightSheet.classList.remove('translate-x-full'); rightOverlay.classList.remove('hidden'); requestAnimationFrame(()=>rightOverlay.classList.add('opacity-100'));
});
document.getElementById('btn-close-right').addEventListener('click', closeRight);
rightOverlay.addEventListener('click', closeRight);
function closeRight(){ rightSheet.classList.add('translate-x-full'); rightOverlay.classList.remove('opacity-100'); setTimeout(()=>rightOverlay.classList.add('hidden'),150); }
// Composer enable/disable and send
const ta = document.getElementById('composer');
const send = document.getElementById('btn-send');
const stop = document.getElementById('btn-stop');
const messages = document.getElementById('messages');
const scroller = document.getElementById('msg-scroll');
function autoResize(){ ta.style.height='auto'; ta.style.height=Math.min(ta.scrollHeight,160)+'px'; }
function sync(){
send.disabled = ta.value.trim().length===0;
// Don't show stop button here - let ChatApp handle it
}
ta.addEventListener('input', ()=>{ autoResize(); sync(); });
ta.addEventListener('keydown', (e)=>{ if(e.key==='Enter' && !e.shiftKey){ e.preventDefault(); if(!send.disabled) doSend(); }});
send.addEventListener('click', doSend);
// Stop button handler
stop.addEventListener('click', ()=>{
if (window.chatApp && window.chatApp.cancelCurrentMessage) {
window.chatApp.cancelCurrentMessage();
}
});
function bubble(role, text){
const wrap = document.createElement('div');
wrap.className = 'relative flex items-start gap-3 px-4 py-5 sm:px-6';
const avatar = document.createElement('div');
avatar.className = 'mt-1 h-8 w-8 shrink-0 overflow-hidden rounded-full '+(role==='user'?'bg-zinc-300 grid place-items-center text-[10px] font-medium':'bg-zinc-200');
if(role==='user') avatar.textContent='YOU';
const body = document.createElement('div'); body.className='min-w-0 flex-1';
const meta = document.createElement('div'); meta.className='mb-1 flex items-baseline gap-2'; meta.innerHTML = `<div class="text-sm font-medium">${role==='user'?'You':'Ava'}</div><div class="text-xs text-zinc-500">${new Date().toLocaleTimeString().slice(0,5)}</div>`;
const bubble = document.createElement('div');
bubble.className = (role==='user'?
'prose prose-sm max-w-none rounded-2xl border border-zinc-200 bg-white p-4 dark:prose-invert dark:border-zinc-800 dark:bg-zinc-900'
:'prose prose-sm max-w-none rounded-2xl border border-zinc-200 bg-zinc-50 p-4 dark:prose-invert dark:border-zinc-800 dark:bg-zinc-800/60');
bubble.textContent = text;
body.appendChild(meta); body.appendChild(bubble);
wrap.appendChild(avatar); wrap.appendChild(body);
messages.appendChild(wrap);
scroller.scrollTop = scroller.scrollHeight;
}
function doSend(){
const text = ta.value.trim(); if(!text) return;
// Don't use the old bubble function, let the ChatApp handle it
if (window.chatApp && window.chatApp.handleSendMessage) {
ta.value = text; // Set the value back for ChatApp to read
window.chatApp.handleSendMessage();
} else {
// Fallback if ChatApp not loaded yet
bubble('user', text);
ta.value='';
autoResize();
sync();
setTimeout(()=> bubble('assistant','⚠️ Chat system loading... Please wait.'), 400);
}
}
autoResize(); sync();
// Welcome pills → insert into composer
document.querySelectorAll('[data-suggest]').forEach(el=>{
el.addEventListener('click', ()=>{
ta.value = el.textContent.trim();
autoResize();
sync();
ta.focus();
// If ChatApp is loaded, update its composer too
if (window.chatApp && window.chatApp.elements && window.chatApp.elements.composer) {
window.chatApp.elements.composer.value = el.textContent.trim();
window.chatApp.autoResizeComposer();
window.chatApp.updateSendButtonState();
}
});
});
</script>
</body>
</html>
|