|
<!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"> |
|
|
|
<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"> |
|
|
|
<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> |
|
|
|
<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"> |
|
|
|
<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> |
|
|
|
<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> |
|
|
|
<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"> |
|
|
|
<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"> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</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> |
|
|
|
|
|
<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"> |
|
|
|
<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 class="flex min-w-0 flex-1 flex-col"> |
|
|
|
<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> |
|
|
|
|
|
<div id="msg-scroll" class="flex-1 overflow-y-auto"> |
|
<div id="messages" class="mx-auto w-full max-w-3xl"> |
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<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> |
|
|
|
|
|
<script src="utils.js"></script> |
|
<script src="i18n.js"></script> |
|
<script src="app.js"></script> |
|
<script> |
|
|
|
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'))); |
|
|
|
|
|
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')); |
|
}); |
|
|
|
|
|
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); } |
|
|
|
|
|
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); } |
|
|
|
|
|
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; |
|
|
|
} |
|
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.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; |
|
|
|
|
|
if (window.chatApp && window.chatApp.handleSendMessage) { |
|
ta.value = text; |
|
window.chatApp.handleSendMessage(); |
|
} else { |
|
|
|
bubble('user', text); |
|
ta.value=''; |
|
autoResize(); |
|
sync(); |
|
setTimeout(()=> bubble('assistant','⚠️ Chat system loading... Please wait.'), 400); |
|
} |
|
} |
|
autoResize(); sync(); |
|
|
|
|
|
document.querySelectorAll('[data-suggest]').forEach(el=>{ |
|
el.addEventListener('click', ()=>{ |
|
ta.value = el.textContent.trim(); |
|
autoResize(); |
|
sync(); |
|
ta.focus(); |
|
|
|
|
|
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> |
|
|