|
|
@@ -9,41 +9,104 @@
|
|
|
<link rel="stylesheet" as="style" onload="this.rel='stylesheet'"
|
|
|
href="https://fonts.googleapis.com/css2?display=swap&family=Noto+Sans:wght@400;500;700;900&family=Spline+Sans:wght@400;500;700">
|
|
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
|
|
-
|
|
|
+ <!--Tailwind-->
|
|
|
+ <script>
|
|
|
+ tailwind.config = {
|
|
|
+ theme: {
|
|
|
+ extend: {
|
|
|
+ colors: {
|
|
|
+ 'custom-dark': '#101419',
|
|
|
+ 'custom-dark-hover': '#37404a',
|
|
|
+ 'gray-50': '#f9fafb',
|
|
|
+ 'gray-100': '#f3f4f6',
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ </script>
|
|
|
<!-- Markdown -->
|
|
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
|
-
|
|
|
- <!-- Lógica principal -->
|
|
|
<script src="js/app.js" type="module"></script>
|
|
|
<link rel="stylesheet" href="styles.css">
|
|
|
+ <!-- Animaciones -->
|
|
|
<style>
|
|
|
- @keyframes slideIn {from {transform:translateY(-8px); opacity:0;} to {transform:translateY(0); opacity:1;}}
|
|
|
- @keyframes slideOut {from {transform:translateY(0); opacity:1;} to {transform:translateY(-8px); opacity:0;}}
|
|
|
+ @keyframes slideRight {
|
|
|
+ from {
|
|
|
+ transform: translateX(0%);
|
|
|
+ position:absolute;
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ transform: translateX(100%);
|
|
|
+ position:absolute;
|
|
|
+ } }
|
|
|
+ @keyframes slideRightIn {
|
|
|
+ from {
|
|
|
+ transform: translateX(100%);
|
|
|
+ position:absolute;
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ transform: translateX(0%);
|
|
|
+ position:absolute;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @keyframes slideLeft {
|
|
|
+ from {
|
|
|
+ transform: translateX(0%);
|
|
|
+ position:absolute;
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ transform: translateX(-100%);
|
|
|
+ position:absolute;
|
|
|
+ } }
|
|
|
+ @keyframes slideLeftIn {
|
|
|
+ from {
|
|
|
+ transform: translateX(-100%);
|
|
|
+ position:absolute;
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ transform: translateX(-0%);
|
|
|
+ position:absolute;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @keyframes popup {
|
|
|
+ 0% {
|
|
|
+ transform: scale(0) translateX(-50%);
|
|
|
+ }
|
|
|
+ 15% {
|
|
|
+ transform: scale(1) translateX(-50%);
|
|
|
+ }
|
|
|
+ 85% {
|
|
|
+ transform: scale(1) translateX(-50%);
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ transform: scale(0) translateX(-50%);
|
|
|
+ }
|
|
|
+ }
|
|
|
</style>
|
|
|
</head>
|
|
|
|
|
|
-<body class="min-h-screen flex flex-col bg-gray-50 overflow-x-hidden"
|
|
|
+<body class="h-[100dvh] max-h-[100dvh] flex flex-col bg-gray-50 overflow-x-hidden"
|
|
|
style='font-family:"Spline Sans","Noto Sans",sans-serif;'>
|
|
|
|
|
|
<!-- ---------- HEADER ---------- -->
|
|
|
- <header class="fixed top-0 inset-x-0 z-10 bg-gray-50 p-4 flex justify-center items-center border-b border-gray-200">
|
|
|
- <h1 class="text-[26px] font-bold text-[#101419] tracking-tight">
|
|
|
- Biergarten Klein
|
|
|
+ <header class="flex-col top-0 inset-x-0 z-10 bg-gray-50 p-2 flex justify-center items-center border-b border-gray-200">
|
|
|
+ <h1 id="mainTitle" class="text-[26px] font-bold text-[#101419] tracking-tight">
|
|
|
+ KleinBot
|
|
|
</h1>
|
|
|
</header>
|
|
|
|
|
|
<!-- ---------- MAIN ---------- -->
|
|
|
- <main class="flex-1 pt-16 pb-20">
|
|
|
+ <main class="relative flex-1 flex flex-col min-h-0 overflow-x-hidden">
|
|
|
<!-- ===== MENÚ tab ===== -->
|
|
|
- <section id="menuTab" data-tab>
|
|
|
- <div class="px-4 pt-4 pb-3 "></div>
|
|
|
- <h2 class="text-[22px] mx-4 font-bold text-[#101419]">
|
|
|
- PIDE TU SHOP EXPRESS ⚡🍺
|
|
|
+ <section id="menuTab" data-index="0" class=" min-h-0 overflow-y-auto h-full" data-tab>
|
|
|
+ <div class="pt-4 pb-3 ">
|
|
|
+ <h2 class="text-[19px] mx-4 font-bold text-[#101419]">
|
|
|
+ Pide tu shop express 🍺
|
|
|
</h2>
|
|
|
<p class="product-type mx-4 text-[#58728d] text-sm pb-4 mb-4 border-b border-gray-200">*solo lo más vendido</p>
|
|
|
</div>
|
|
|
- <div class="px-4">
|
|
|
- <ul id="productList" class="space-y-6"></ul>
|
|
|
+ <div class="px-4 overflow-y-auto">
|
|
|
+ <ul id="productList" class="space-y-6"></ul>
|
|
|
</div>
|
|
|
|
|
|
<template id="product-card-template">
|
|
|
@@ -74,24 +137,62 @@
|
|
|
<div class="product-image flex-1 aspect-video bg-cover bg-center rounded-xl"></div>
|
|
|
</li>
|
|
|
</template>
|
|
|
- </section>
|
|
|
+ </section>
|
|
|
|
|
|
<!-- ===== CHAT ===== -->
|
|
|
- <section id="chatTab" data-tab class="hidden flex flex-col h-full">
|
|
|
- <div id="chatMessages" class="flex-1 overflow-y-auto p-4 space-y-3 text-sm leading-relaxed"></div>
|
|
|
- <div id="aiLoadingIndicator" class="hidden px-4 py-2 text-center text-xs text-gray-500">Pensando…</div>
|
|
|
- <form class="flex gap-2 p-3 border-t border-gray-200" onsubmit="event.preventDefault();">
|
|
|
- <input id="chatInput" class="flex-1 text-sm px-3 py-2 rounded-md border border-gray-300 focus:outline-none text-neutral-800" autocomplete="off"
|
|
|
- placeholder="Escribe tu mensaje...">
|
|
|
- <button id="sendChatButton"
|
|
|
- class="bg-[#101419] hover:bg-[#37404a] text-white px-3 py-2 rounded-md text-sm">
|
|
|
- Enviar
|
|
|
- </button>
|
|
|
- </form>
|
|
|
+ <section id="chatTab" data-index="2" data-tab class="flex hidden flex-col flex-1 min-h-0">
|
|
|
+ <!-- Contenedor de mensajes que puede crecer y hacer scroll -->
|
|
|
+ <div id="chatMessages" class="flex-1 overflow-y-auto px-5 md:px-8 py-4 flex flex-col gap-4">
|
|
|
+ <!-- Sugerencias y Bajada -->
|
|
|
+ <div class="text-center text-gray-600 px-5 text-sm leading-relaxed max-w-full">
|
|
|
+ <h2 class="text-md text-gray-500 mt-5">Conversa con nuestro asistente IA: descubre nuestras cervezas 🍻 y sugiere mejoras para nuestra app ✨<span class="mx-0.5">🍻</span></h2>
|
|
|
+ <!-- Ideas de mensajes -->
|
|
|
+ <div id="chatSuggestions" class="grid grid-cols-1 gap-3 max-w-2xl mx-auto mt-5">
|
|
|
+ <div class="bg-white border border-gray-200 rounded-xl p-4 cursor-pointer hover:border-gray-300 hover:shadow-sm transition-all duration-200 text-left flex items-center gap-4">
|
|
|
+ <div class="text-lg mb-1">🍺</div>
|
|
|
+ <div class="chat-suggestion text-gray-400 font-medium text-xs">¿Que me puedes contar de la burlesque?</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="bg-white border border-gray-200 rounded-xl p-4 cursor-pointer hover:border-gray-300 hover:shadow-sm transition-all duration-200 text-left flex items-center gap-4">
|
|
|
+ <div class="text-lg mb-1">⁉️</div>
|
|
|
+ <div class="chat-suggestion text-gray-400 font-medium text-xs">Mi sugerencia para la aplicacion es...</div>
|
|
|
+ </div>
|
|
|
+ <div class="bg-white border border-gray-200 rounded-xl p-4 cursor-pointer hover:border-gray-300 hover:shadow-sm transition-all duration-200 text-left flex items-center gap-4">
|
|
|
+ <div class="text-lg mb-1">🍕</div>
|
|
|
+ <div class="chat-suggestion text-gray-400 font-medium text-xs">¿Qué pizza queda bien con la hoppy mosh?</div>
|
|
|
+ </div>
|
|
|
+ <div class="bg-white border border-gray-200 rounded-xl p-4 cursor-pointer hover:border-gray-300 hover:shadow-sm transition-all duration-200 text-left flex items-center gap-4">
|
|
|
+ <div class="text-lg mb-1">📱</div>
|
|
|
+ <div class="chat-suggestion text-gray-400 font-medium text-xs">La orden no se envio bien</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Indicador de carga - FIJO arriba del input -->
|
|
|
+ <div id="aiLoadingIndicator" class="hidden flex px-5 py-3 text-left text-sm text-gray-500 italic flex-shrink-0">
|
|
|
+ Pensando
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Input del chat - FIJO en la parte inferior -->
|
|
|
+ <div class="px-4 py-4 md:px-5 md:py-5 bg-white border-t border-gray-200 flex-shrink-0">
|
|
|
+ <form id="chatForm" class="flex items-center bg-gray-50 border border-gray-300 rounded-3xl px-5 py-1 transition-colors focus-within:border-gray-400">
|
|
|
+ <input
|
|
|
+ id="chatInput"
|
|
|
+ class="flex-1 sticky flex-shrink-0 bg-transparent border-none outline-none text-gray-900 text-sm py-3 placeholder-gray-500"
|
|
|
+ autocomplete="off"
|
|
|
+ placeholder="Pregunta lo que quieras"
|
|
|
+ maxlength="2000"
|
|
|
+ >
|
|
|
+ <button id="sendChatButton" type="submit" class="bg-custom-dark hover:bg-custom-dark-hover text-white border-none rounded-2xl px-4 py-2.5 text-sm transition-colors ml-2 disabled:bg-gray-400 disabled:cursor-not-allowed">
|
|
|
+ Enviar
|
|
|
+ </button>
|
|
|
+ </form>
|
|
|
+ </div>
|
|
|
</section>
|
|
|
|
|
|
<!-- ===== CARRITO ===== -->
|
|
|
- <section id="cartTab" data-tab class="hidden flex flex-col h-full">
|
|
|
+ <section id="cartTab" data-tab data-index="1" class="flex flex-col hidden flex-1 min-h-0">
|
|
|
<header class="p-4 border-b border-gray-200">
|
|
|
<h3 class="text-lg font-bold text-[#101419]">Tu pedido</h3>
|
|
|
</header>
|
|
|
@@ -106,33 +207,22 @@
|
|
|
</div>
|
|
|
<button id="checkoutButton"
|
|
|
class="w-full bg-[#101419] hover:bg-[#37404a] disabled:opacity-50 text-white py-2 rounded-md"
|
|
|
+ onclick="processOrder()"
|
|
|
disabled>
|
|
|
- Finalizar Pedido
|
|
|
+ Envia tu orden
|
|
|
</button>
|
|
|
</footer>
|
|
|
</section>
|
|
|
</main>
|
|
|
|
|
|
<!-- ---------- NAVBAR ---------- -->
|
|
|
- <footer class="fixed bottom-0 inset-x-0 z-10 border-t border-gray-200 bg-gray-50 px-4 py-2">
|
|
|
+ <footer class="inset-x-0 z-10 border-t border-gray-200 bg-gray-50 px-4 py-2">
|
|
|
<nav class="flex gap-2">
|
|
|
- <button data-target="chatTab" class="tab-btn flex-1 flex flex-col items-center text-[#58728d]">
|
|
|
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor"
|
|
|
- viewBox="0 0 256 256" class="h-8">
|
|
|
- <path
|
|
|
- d="M140,128a12,12,0,1,1-12-12A12,12,0,0,1,140,128ZM84,116a12,12,0,1,0,12,12A12,12,0,0,0,84,116Zm88,0a12,12,0,1,0,12,12A12,12,0,0,0,172,116Zm60,12A104,104,0,0,1,79.12,219.82L45.07,231.17a16,16,0,0,1-20.24-20.24l11.35-34.05A104,104,0,1,1,232,128Z" />
|
|
|
- </svg>
|
|
|
- <span class="text-xs font-medium">Chat</span>
|
|
|
+ <button data-target="menuTab" data-title="Biergarten Klein" class="active tab-btn flex-1 flex flex-col items-center text-[#58728d]">
|
|
|
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-8"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l-2 0l9 -9l9 9l-2 0" /><path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7" /><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" /></svg><span class="text-xs font-medium">Inicio</span>
|
|
|
</button>
|
|
|
- <button data-target="menuTab" class="tab-btn flex-1 flex flex-col items-center text-[#101419]">
|
|
|
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor"
|
|
|
- viewBox="0 0 256 256" class="h-8">
|
|
|
- <path
|
|
|
- d="M56,128a16,16,0,1,1-16-16A16,16,0,0,1,56,128ZM40,48A16,16,0,1,0,56,64,16,16,0,0,0,40,48Zm0,128a16,16,0,1,0,16,16A16,16,0,0,0,40,176Zm176-64H88a8,8,0,0,0-8,8v16a8,8,0,0,0,8,8H216a8,8,0,0,0,8-8V120A8,8,0,0,0,216,112Zm0-64H88a8,8,0,0,0-8,8V72a8,8,0,0,0,8,8H216a8,8,0,0,0,8-8V56A8,8,0,0,0,216,48Zm0,128H88a8,8,0,0,0-8,8v16a8,8,0,0,0,8,8H216a8,8,0,0,0,8-8V184A8,8,0,0,0,216,176Z" />
|
|
|
- </svg>
|
|
|
- <span class="text-xs font-medium">Menú</span>
|
|
|
- </button>
|
|
|
- <button data-target="cartTab" class="tab-btn flex-1 flex flex-col items-center text-[#58728d]">
|
|
|
+
|
|
|
+ <button data-target="cartTab" data-title="Carrito Klein" class="tab-btn flex-1 flex flex-col items-center text-[#58728d]">
|
|
|
<div id="cartIcon">
|
|
|
<span id="cartCount">0</span>
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor"
|
|
|
@@ -143,18 +233,25 @@
|
|
|
</div>
|
|
|
<span class="text-xs font-medium">Carrito</span>
|
|
|
</button>
|
|
|
+ <button data-target="chatTab" data-title="KleinBot" class="tab-btn flex-1 flex flex-col items-center text-[#58728d]">
|
|
|
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-8"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M8 9h8" /><path d="M8 13h6" /><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12z" /></svg>
|
|
|
+ <span class="text-xs font-medium">Chat IA</span>
|
|
|
+ </button>
|
|
|
+
|
|
|
</nav>
|
|
|
</footer>
|
|
|
|
|
|
<!-- ---------- TOAST ---------- -->
|
|
|
<div id="toastCart"
|
|
|
class="fixed top-4 left-1/2 -translate-x-1/2 bg-[#101419] text-white text-sm
|
|
|
- rounded-md px-4 py-2 shadow-lg opacity-0 pointer-events-none z-50"></div>
|
|
|
+ rounded-md px-4 py-2 shadow-lg opacity-0 pointer-events-none z-50
|
|
|
+ origin-left">
|
|
|
+ </div>
|
|
|
|
|
|
|
|
|
<!-- === MODAL INICIO DE SESIÓN === -->
|
|
|
<div id="sessionModal"
|
|
|
- class="fixed inset-0 bg-black/70 flex items-center justify-center z-50">
|
|
|
+ class="fixed hidden inset-0 bg-black/70 flex items-center justify-center z-50">
|
|
|
<div class="bg-white w-full max-w-sm p-6 rounded-lg space-y-4 text-center">
|
|
|
<h2 class="text-xl font-bold">¡Bienvenido!</h2>
|
|
|
<p class="text-sm text-gray-600">
|
|
|
@@ -179,13 +276,69 @@
|
|
|
|
|
|
<!-- ---------- JS: conmutar tabs + toast ---------- -->
|
|
|
<script>
|
|
|
+
|
|
|
+ const animation_time = 200
|
|
|
+ let transitioning = false;
|
|
|
// conmutar pestañas
|
|
|
- document.querySelectorAll('.tab-btn').forEach(btn => {
|
|
|
+ const buttons = document.querySelectorAll('.tab-btn')
|
|
|
+ buttons.forEach(btn => {
|
|
|
btn.addEventListener('click', () => {
|
|
|
const target = btn.dataset.target;
|
|
|
- document.querySelectorAll('[data-tab]').forEach(tab => {
|
|
|
- tab.classList.toggle('hidden', tab.id !== target);
|
|
|
+ const active = document.querySelector(':not(.hidden)[data-tab]');
|
|
|
+ const activeIndex = active.dataset.index;
|
|
|
+ const to = document.querySelector(`#${target}[data-tab]`);
|
|
|
+ const toIndex = to.dataset.index;
|
|
|
+ const height = to.offsetHeight;
|
|
|
+
|
|
|
+ if (activeIndex === toIndex || transitioning) return;
|
|
|
+ buttons.forEach(button => {
|
|
|
+ button.classList.remove('active')
|
|
|
+ })
|
|
|
+ btn.classList.add('active')
|
|
|
+
|
|
|
+ active.style.height = "100%";
|
|
|
+ active.style.width = "100vw"
|
|
|
+ to.style.height = "100%";
|
|
|
+ to.style.width = "100vw"
|
|
|
+ to.style.zIndex = "1";
|
|
|
+ active.style.zIndex = "0";
|
|
|
+ transitioning = true;
|
|
|
+ const otherTabs = document.querySelectorAll('[data-tab]');
|
|
|
+ otherTabs.forEach(tab => {
|
|
|
+ if (tab !== active && tab !== to) {
|
|
|
+ tab.classList.add('hidden');
|
|
|
+ tab.classList.remove(`animate-[slideLeft_${animation_time}ms_ease-out]`, `animate-[slideRight_${animation_time}ms_ease-out]`);
|
|
|
+ tab.classList.remove(`animate-[slideLeftIn_${animation_time}ms_ease-out]`, `animate-[slideRightIn_${animation_time}ms_ease-out]`);
|
|
|
+ }
|
|
|
});
|
|
|
+ to.classList.remove('hidden');
|
|
|
+ // Animate tab transition
|
|
|
+ if (activeIndex < toIndex) {
|
|
|
+ // Slide left
|
|
|
+ active.classList.add(`animate-[slideLeft_${animation_time}ms_ease-out]`);
|
|
|
+ to.classList.add(`animate-[slideRightIn_${animation_time}ms_ease-out]`);
|
|
|
+ } else if (activeIndex > toIndex) {
|
|
|
+ // Slide right
|
|
|
+ active.classList.add(`animate-[slideRight_${animation_time}ms_ease-out]`);
|
|
|
+ to.classList.add(`animate-[slideLeftIn_${animation_time}ms_ease-out]`);
|
|
|
+ }
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ active.classList.remove(`animate-[slideLeft_${animation_time}ms_ease-out]`, `animate-[slideRight_${animation_time}ms_ease-out]`);
|
|
|
+ active.classList.add('hidden');
|
|
|
+ to.classList.remove(`animate-[slideLeftIn_${animation_time}ms_ease-out]`, `animate-[slideRightIn_${animation_time}ms_ease-out]`);
|
|
|
+ transitioning = false;
|
|
|
+ }, animation_time);
|
|
|
+
|
|
|
+ // Update header title if needed
|
|
|
+ const title = btn.dataset.title;
|
|
|
+ if (title) {
|
|
|
+ document.getElementById('mainTitle').textContent = title;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
});
|
|
|
});
|
|
|
|
|
|
@@ -196,8 +349,12 @@
|
|
|
toast.style.animation = 'none'; // reset
|
|
|
void toast.offsetWidth; // reflow
|
|
|
toast.style.opacity = '1';
|
|
|
- toast.style.animation = 'slideIn 0.2s ease-out, slideOut 0.2s ease-in 0.8s forwards';
|
|
|
+ toast.style.animation = 'popup 1s ease-out';
|
|
|
+ toast.addEventListener('animationend', () => {
|
|
|
+ toast.style.animation = 'none';
|
|
|
+ toast.style.opacity = '0';
|
|
|
+ });
|
|
|
};
|
|
|
</script>
|
|
|
</body>
|
|
|
-</html>
|
|
|
+</html>
|