Qwen3 / public /index.html
Semnykcz's picture
Upload 18 files
e0581b4 verified
<!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 &amp; 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>