MerchFlow-AI / dashboard.html
Bhishaj
Update dashboard and main files, add landing page
3bf6f3c
<!DOCTYPE html>
<html class="dark" lang="en"><head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>MerchFlow AI Dashboard</title>
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<link href="https://fonts.googleapis.com" rel="preconnect"/>
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<script id="tailwind-config">
tailwind.config = {
darkMode: "class",
theme: {
extend: {
colors: {
"primary": "#f59e0b",
"primary-hover": "#d97706",
"glass-border": "rgba(255, 255, 255, 0.12)",
"glass-surface": "rgba(255, 255, 255, 0.03)",
"glass-surface-hover": "rgba(255, 255, 255, 0.07)",
"charcoal": "#0a0a0a",
"amber-accent": "#fbbf24"
},
fontFamily: {
"display": ["Plus Jakarta Sans", "sans-serif"],
"mono": ["monospace"]
},
borderRadius: { "DEFAULT": "1rem", "lg": "1.5rem", "xl": "2rem", "2xl": "3rem", "full": "9999px" },
backdropBlur: {
'xs': '2px',
},
screens: {
'xs': '480px',
},
animation: {
'pulse-slow': 'pulse-slow 3s infinite',
'glow-pulse': 'glow-pulse 3s infinite',
'copy-success': 'copy-success 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275)',
},
keyframes: {
'pulse-slow': {
'0%, 100%': { transform: 'scale(1)' },
'50%': { transform: 'scale(1.02)' },
},
'glow-pulse': {
'0%, 100%': { boxShadow: '0 0 0 0 rgba(245, 158, 11, 0.4)' },
'50%': { boxShadow: '0 0 20px 5px rgba(251, 191, 36, 0.5)' },
},
'copy-success': {
'0%': { transform: 'scale(0.8)', opacity: '0' },
'100%': { transform: 'scale(1)', opacity: '1' },
}
}
},
},
}
</script>
<style type="text/tailwindcss">
.custom-scrollbar::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: transparent;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.1);
border-radius: 99px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.2);
}
body {
background-color: #0a0a0a;
background-image:
radial-gradient(at 0% 0%, rgba(20, 20, 20, 1) 0, transparent 50%),
radial-gradient(at 50% -10%, rgba(217, 119, 6, 0.15) 0, transparent 60%),
radial-gradient(at 100% 0%, rgba(251, 191, 36, 0.1) 0, transparent 50%),
radial-gradient(at 80% 80%, rgba(217, 119, 6, 0.12) 0, transparent 50%);
background-attachment: fixed;
min-height: 100vh;
}
.glass-panel {
background: rgba(15, 15, 15, 0.75);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.08);
}
@media (max-width: 768px) {
.glass-panel {
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
background: rgba(10, 10, 10, 0.85);
}
}
.glass-card {
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.05);
backdrop-filter: blur(12px);
transition: all 0.3s ease;
}
@media (hover: hover) {
.glass-card:hover {
border-color: rgba(251, 191, 36, 0.3);
box-shadow: 0 0 25px rgba(245, 158, 11, 0.15);
background: rgba(255, 255, 255, 0.04);
}
}
.neon-textarea {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.08);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
transition: all 0.3s ease;
}
.neon-textarea:focus {
outline: none;
border-color: rgba(251, 191, 36, 0.5);
box-shadow: 0 0 15px rgba(245, 158, 11, 0.25), inset 0 0 5px rgba(245, 158, 11, 0.05);
background: rgba(255, 255, 255, 0.06);
}
.copy-active {
box-shadow: 0 0 15px rgba(251, 191, 36, 0.6) !important;
border-color: rgba(251, 191, 36, 0.4) !important;
background: rgba(251, 191, 36, 0.1) !important;
}
</style>
<style>
body {
min-height: max(884px, 100dvh);
}
</style>
</head>
<body class="font-display text-white antialiased overflow-x-hidden min-h-screen flex flex-col selection:bg-amber-500 selection:text-black">
<header class="flex-none z-30 px-4 py-3 lg:px-6 lg:py-4 border-b border-white/5 glass-panel sticky top-0">
<div class="max-w-[1600px] mx-auto flex items-center justify-between gap-4">
<div class="flex items-center gap-3 lg:gap-4 flex-1 min-w-0">
<div class="flex-none flex items-center justify-center size-9 lg:size-10 rounded-xl bg-gradient-to-br from-amber-400 to-amber-700 shadow-lg shadow-amber-900/20 text-white">
<span class="material-symbols-outlined text-xl lg:text-2xl">all_inclusive</span>
</div>
<div class="min-w-0">
<h2 class="text-white text-base lg:text-xl font-bold leading-tight tracking-tight truncate">MerchFlow AI</h2>
<div class="flex items-center gap-2">
<span class="size-1.5 rounded-full bg-amber-500 animate-pulse flex-none"></span>
<span class="text-[10px] text-amber-200/60 font-bold uppercase tracking-wider truncate">Enterprise Edition</span>
</div>
</div>
</div>
<a class="hidden sm:inline-flex flex-none items-center justify-center rounded-full h-9 lg:h-10 px-4 lg:px-5 bg-white/5 hover:bg-white/10 border border-white/10 text-white text-xs lg:text-sm font-bold transition-all" href="/">
<span class="material-symbols-outlined text-lg lg:mr-2">arrow_back</span>
<span class="hidden lg:inline">Back to Home</span>
</a>
<button class="group relative flex-none flex cursor-pointer items-center justify-center overflow-hidden rounded-full h-9 lg:h-10 px-4 lg:px-6 bg-gradient-to-r from-amber-600 to-amber-800 hover:from-amber-500 hover:to-amber-700 border border-white/10 shadow-[0_0_15px_rgba(245,158,11,0.3)] transition-all" id="deployBtn">
<div class="absolute inset-0 bg-white/10 opacity-0 group-hover:opacity-100 transition-opacity"></div>
<span class="material-symbols-outlined lg:mr-2 text-lg relative z-10">rocket_launch</span>
<span class="hidden lg:inline truncate text-sm font-bold tracking-wide relative z-10">Deploy</span>
</button>
</div>
</header>
<main class="flex-1 flex flex-col lg:flex-row relative z-10">
<div class="fixed top-1/4 -left-20 w-64 h-64 lg:w-96 lg:h-96 bg-amber-900/10 rounded-full blur-[120px] pointer-events-none z-0"></div>
<div class="fixed bottom-1/4 -right-20 w-64 h-64 lg:w-96 lg:h-96 bg-orange-900/5 rounded-full blur-[120px] pointer-events-none z-0"></div>
<div class="flex-none lg:flex-1 flex flex-col lg:border-r border-white/5 p-4 lg:p-8 bg-black/40 lg:overflow-y-auto lg:h-[calc(100vh-73px)] relative z-10">
<div class="max-w-xl w-full mx-auto flex flex-col gap-4 lg:gap-6 h-full">
<div class="flex items-center justify-between mb-2">
<h2 class="text-white text-xl lg:text-3xl font-bold tracking-tight">Input Data</h2>
<span class="bg-white/5 text-amber-200/80 px-2.5 py-1 rounded-full text-[10px] lg:text-xs font-semibold border border-white/10 backdrop-blur-sm">Step 1 of 2</span>
</div>
<div class="flex flex-col flex-none">
<input accept=".jpg,.jpeg,.png,.webp" class="hidden" id="fileInput" type="file"/>
<div class="group relative flex flex-col items-center justify-center gap-3 lg:gap-4 rounded-2xl lg:rounded-3xl border-2 border-dashed border-white/10 hover:border-amber-500/50 hover:bg-white/5 transition-all cursor-pointer min-h-[200px] lg:min-h-[260px] px-4 py-6 lg:px-6 lg:py-8 glass-card" id="dropZone">
<div class="absolute w-16 h-16 lg:w-20 lg:h-20 bg-amber-500/10 rounded-full blur-xl group-hover:bg-amber-500/20 transition-all"></div>
<div class="size-14 lg:size-16 relative z-10 rounded-2xl bg-gradient-to-br from-neutral-800 to-black border border-white/10 shadow-lg flex items-center justify-center transition-transform group-hover:scale-110 duration-300">
<span class="material-symbols-outlined text-2xl lg:text-3xl text-amber-500">cloud_upload</span>
</div>
<div class="flex flex-col items-center gap-1 relative z-10">
<p class="text-white text-base lg:text-lg font-bold leading-tight tracking-tight text-center">Drop Product Image Here</p>
<p class="text-neutral-500 text-xs lg:text-sm font-medium text-center">Supports JPG, PNG, WEBP</p>
</div>
<button class="mt-2 relative z-10 flex items-center justify-center rounded-full h-8 lg:h-9 px-4 lg:px-5 bg-white/5 hover:bg-white/10 border border-white/10 text-white text-[10px] lg:text-xs font-bold transition-all uppercase tracking-wide" id="browseBtn">
Browse Files
</button>
</div>
</div>
<div class="flex flex-col gap-2 lg:gap-3 flex-1">
<label class="flex items-center justify-between px-1">
<span class="text-white text-sm lg:text-base font-semibold">Raw Product Specs</span>
<span class="text-[10px] lg:text-xs text-neutral-500 font-medium bg-black/40 px-2 py-0.5 rounded border border-white/5">JSON or Plain Text</span>
</label>
<div class="relative w-full">
<textarea class="form-input w-full min-h-[140px] lg:h-full lg:min-h-[180px] resize-y lg:resize-none rounded-xl lg:rounded-2xl text-neutral-100 placeholder:text-neutral-600 neon-textarea p-4 lg:p-5 text-sm leading-relaxed font-mono shadow-inner transition-all duration-300" id="productSpecs" placeholder="// Enter fabric details, dimensions, and SKU..."></textarea>
</div>
</div>
<div class="pt-2 pb-6 lg:pb-0">
<button class="group relative w-full cursor-pointer overflow-hidden rounded-xl lg:rounded-2xl h-12 lg:h-14 bg-gradient-to-r from-amber-600 via-amber-700 to-amber-800 hover:from-amber-500 hover:to-amber-700 transition-all border border-white/10 animate-pulse-slow animate-glow-pulse" id="startBtn">
<div class="absolute inset-0 flex items-center justify-center gap-2 lg:gap-3 relative z-10">
<span class="text-white text-base lg:text-lg font-bold tracking-wide group-hover:scale-105 transition-transform">Start Agent Workflow</span>
<span class="material-symbols-outlined text-white text-lg lg:text-xl group-hover:translate-x-1 transition-transform">arrow_forward</span>
</div>
</button>
</div>
</div>
</div>
<div class="flex-none lg:flex-1 flex flex-col p-4 lg:p-8 bg-black/60 lg:overflow-y-auto lg:h-[calc(100vh-73px)] relative">
<div class="absolute inset-0 opacity-[0.02] pointer-events-none" style="background-image: linear-gradient(to right, #ffffff 1px, transparent 1px), linear-gradient(to bottom, #ffffff 1px, transparent 1px); background-size: 40px 40px;"></div>
<div class="max-w-3xl w-full mx-auto flex flex-col gap-4 lg:gap-6 h-full relative z-10 pb-8 lg:pb-0">
<div class="flex items-center justify-between mb-2">
<h2 class="text-white text-xl lg:text-3xl font-bold tracking-tight">Generated Output</h2>
<div class="flex items-center gap-2">
<span class="hidden xs:inline-block bg-white/5 text-amber-200 px-2.5 py-1 rounded-full text-[10px] lg:text-xs font-semibold border border-white/10 backdrop-blur-sm">Step 2 of 2</span>
<div class="hidden xs:block h-6 w-px bg-white/10 mx-1"></div>
<button class="size-8 lg:size-9 flex items-center justify-center hover:bg-white/10 rounded-lg text-neutral-500 hover:text-amber-400 transition-all duration-300 border border-transparent" id="copyBtn" title="Copy JSON">
<span class="material-symbols-outlined text-lg lg:text-xl transition-all duration-300" id="copyIcon">content_copy</span>
</button>
<button class="size-8 lg:size-9 flex items-center justify-center hover:bg-white/10 rounded-lg text-neutral-500 hover:text-amber-400 transition-colors" id="downloadBtn" title="Download JSON">
<span class="material-symbols-outlined text-lg lg:text-xl">download</span>
</button>
</div>
</div>
<div class="grid grid-cols-1 xs:grid-cols-3 gap-3">
<div class="flex items-center gap-3 p-3 lg:p-4 rounded-xl glass-card cursor-default group">
<div class="relative size-3 flex-none">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-amber-500 opacity-75"></span>
<span class="relative inline-flex rounded-full size-3 bg-amber-500 shadow-[0_0_10px_rgba(245,158,11,0.5)]"></span>
</div>
<div class="flex flex-col overflow-hidden min-w-0">
<span class="text-[9px] lg:text-[10px] uppercase tracking-wider text-neutral-500 truncate group-hover:text-amber-300 transition-colors">Vision Agent</span>
<span class="text-xs lg:text-sm font-bold text-white truncate">Gemini Pro 1.5</span>
</div>
</div>
<div class="flex items-center gap-3 p-3 lg:p-4 rounded-xl glass-card cursor-default group">
<div class="relative size-3 flex-none">
<span class="relative inline-flex rounded-full size-3 bg-amber-600 shadow-[0_0_10px_rgba(217,119,6,0.5)]"></span>
</div>
<div class="flex flex-col overflow-hidden min-w-0">
<span class="text-[9px] lg:text-[10px] uppercase tracking-wider text-neutral-500 truncate group-hover:text-amber-300 transition-colors">Reasoning Agent</span>
<span class="text-xs lg:text-sm font-bold text-white truncate">Llama 3 70B</span>
</div>
</div>
<div class="flex items-center gap-3 p-3 lg:p-4 rounded-xl glass-card cursor-default group">
<div class="relative size-3 flex-none">
<span class="relative inline-flex rounded-full size-3 bg-neutral-600 shadow-[0_0_10px_rgba(82,82,82,0.5)]"></span>
</div>
<div class="flex flex-col overflow-hidden min-w-0">
<span class="text-[9px] lg:text-[10px] uppercase tracking-wider text-neutral-500 truncate group-hover:text-amber-300 transition-colors">SEO Context</span>
<span class="text-xs lg:text-sm font-bold text-white truncate">Pinecone DB</span>
</div>
</div>
</div>
<div class="flex-none lg:flex-1 min-h-[400px] lg:min-h-0 rounded-xl lg:rounded-2xl bg-black/60 backdrop-blur-xl border border-white/5 flex flex-col overflow-hidden shadow-2xl relative glass-card group/output transition-all duration-500">
<div class="absolute top-0 right-0 w-64 h-64 bg-amber-500/5 rounded-full blur-[100px] pointer-events-none"></div>
<div class="flex items-center justify-between px-3 py-2.5 lg:px-4 lg:py-3 bg-white/5 border-b border-white/5">
<span class="text-[10px] lg:text-xs font-mono text-neutral-500 flex items-center gap-2">
<span class="material-symbols-outlined text-xs lg:text-sm">code</span>
output.json
</span>
<div class="flex gap-1.5">
<div class="size-2.5 lg:size-3 rounded-full bg-neutral-800 border border-white/10"></div>
<div class="size-2.5 lg:size-3 rounded-full bg-neutral-800 border border-white/10"></div>
<div class="size-2.5 lg:size-3 rounded-full bg-amber-500/20 border border-amber-500/30"></div>
</div>
</div>
<div class="flex-1 p-4 lg:p-5 overflow-auto custom-scrollbar font-mono text-xs lg:text-sm leading-6 lg:leading-7">
<pre><code class="language-json block" id="jsonOutput"><span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">01</span><span class="text-amber-400">{</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">02</span> <span class="text-amber-600">"product_analysis"</span><span class="text-neutral-400">:</span> <span class="text-amber-400">{</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">03</span> <span class="text-amber-600">"title"</span><span class="text-neutral-400">:</span> <span class="text-amber-200">"Noir Elite Series Artisan Timepiece"</span><span class="text-neutral-400">,</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">04</span> <span class="text-amber-600">"category"</span><span class="text-neutral-400">:</span> <span class="text-amber-200">"Luxury / Accessories"</span><span class="text-neutral-400">,</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">05</span> <span class="text-amber-600">"features"</span><span class="text-neutral-400">:</span> <span class="text-amber-400">[</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">06</span> <span class="text-amber-200">"Obsidian Finish"</span><span class="text-neutral-400">,</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">07</span> <span class="text-amber-200">"Golden Accents"</span><span class="text-neutral-400">,</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">08</span> <span class="text-amber-200">"Smart Haptic Interface"</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">09</span> <span class="text-amber-400">]</span><span class="text-neutral-400">,</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">10</span> <span class="text-amber-600">"seo_tags"</span><span class="text-neutral-400">:</span> <span class="text-amber-400">[</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">11</span> <span class="text-amber-200">"#luxurywear"</span><span class="text-neutral-400">,</span> <span class="text-amber-200">"#amberstyle"</span><span class="text-neutral-400">,</span> <span class="text-amber-200">"#premiumtech"</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">12</span> <span class="text-amber-400">]</span><span class="text-neutral-400">,</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">13</span> <span class="text-amber-600">"sentiment_score"</span><span class="text-neutral-400">:</span> <span class="text-amber-500">0.99</span><span class="text-neutral-400">,</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">14</span> <span class="text-amber-600">"market_fit"</span><span class="text-neutral-400">:</span> <span class="text-amber-200">"Exceptional"</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">15</span> <span class="text-amber-400">}</span><span class="text-neutral-400">,</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">16</span> <span class="text-amber-600">"deployment_status"</span><span class="text-neutral-400">:</span> <span class="text-amber-200">"Authorized"</span>
<span class="text-neutral-700 select-none mr-3 lg:mr-4 border-r border-neutral-800 pr-2">17</span><span class="text-amber-400">}</span></code></pre>
</div>
</div>
</div>
</div>
</main>
<footer class="flex-none flex items-center justify-center py-4 bg-black/80 border-t border-white/5 backdrop-blur-md z-10">
<span class="text-[10px] lg:text-xs text-neutral-600 font-medium tracking-wide">© 2026 Bhishaj Technologies — All Rights Reserved</span>
</footer>
<script>
tailwind.config.theme.extend.animation = { shine: 'shine 1.5s infinite' }
tailwind.config.theme.extend.keyframes = {
shine: { '0%': { left: '-100%' }, '100%': { left: '200%' } }
}
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const startBtn = document.getElementById('startBtn');
const jsonOutput = document.getElementById('jsonOutput');
const deployBtn = document.getElementById('deployBtn');
const copyBtn = document.getElementById('copyBtn');
const copyIcon = document.getElementById('copyIcon');
let selectedFile = null;
let isCatalogGenerated = false;
const defaultDropZoneContent = `
<div class="absolute w-16 h-16 lg:w-20 lg:h-20 bg-amber-500/10 rounded-full blur-xl group-hover:bg-amber-500/20 transition-all"></div>
<div class="size-14 lg:size-16 relative z-10 rounded-2xl bg-gradient-to-br from-neutral-800 to-black border border-white/10 shadow-lg flex items-center justify-center transition-transform group-hover:scale-110 duration-300">
<span class="material-symbols-outlined text-2xl lg:text-3xl text-amber-500">cloud_upload</span>
</div>
<div class="flex flex-col items-center gap-1 relative z-10">
<p class="text-white text-base lg:text-lg font-bold leading-tight tracking-tight text-center">Drop Product Image Here</p>
<p class="text-neutral-500 text-xs lg:text-sm font-medium text-center">Supports JPG, PNG, WEBP</p>
</div>
<button id="browseBtn" class="mt-2 relative z-10 flex items-center justify-center rounded-full h-8 lg:h-9 px-4 lg:px-5 bg-white/5 hover:bg-white/10 border border-white/10 text-white text-[10px] lg:text-xs font-bold transition-all uppercase tracking-wide">
Browse Files
</button>
`;
function initDropZone() {
const currentBrowseBtn = document.getElementById('browseBtn');
if (currentBrowseBtn) {
currentBrowseBtn.addEventListener('click', (e) => {
e.preventDefault(); e.stopPropagation(); fileInput.click();
});
}
}
initDropZone();
fileInput.addEventListener('change', (e) => {
if (e.target.files.length > 0) handleFile(e.target.files[0]);
});
dropZone.addEventListener('dragover', (e) => {
e.preventDefault(); dropZone.classList.add('border-amber-500', 'bg-amber-500/5');
});
dropZone.addEventListener('dragleave', (e) => {
e.preventDefault(); dropZone.classList.remove('border-amber-500', 'bg-amber-500/5');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault(); dropZone.classList.remove('border-amber-500', 'bg-amber-500/5');
if (e.dataTransfer.files.length > 0) {
fileInput.files = e.dataTransfer.files;
handleFile(e.dataTransfer.files[0]);
}
});
function handleFile(file) {
selectedFile = file;
dropZone.innerHTML = `
<div class="flex flex-col items-center justify-center gap-4 z-10">
<div class="size-14 lg:size-16 rounded-2xl bg-gradient-to-br from-neutral-800 to-black border border-white/10 shadow-lg flex items-center justify-center">
<span class="material-symbols-outlined text-2xl lg:text-3xl text-amber-500">check_circle</span>
</div>
<div class="flex flex-col items-center gap-1">
<p class="text-white text-base lg:text-lg font-bold text-center">${file.name}</p>
<p class="text-neutral-500 text-xs lg:text-sm text-center">${(file.size / 1024).toFixed(1)} KB</p>
</div>
<button id="removeFileBtn" class="mt-2 flex items-center justify-center gap-2 rounded-full h-8 lg:h-9 px-4 lg:px-5 bg-red-500/10 hover:bg-red-500/20 text-red-400 border border-red-500/20 transition-all text-[10px] lg:text-xs font-bold uppercase tracking-wide">
<span class="material-symbols-outlined text-sm lg:text-base">close</span>
<span>Remove File</span>
</button>
</div>
`;
document.getElementById('removeFileBtn').addEventListener('click', (e) => {
e.stopPropagation(); e.preventDefault(); resetUploadUI();
});
}
function resetUploadUI() {
selectedFile = null; fileInput.value = ""; dropZone.innerHTML = defaultDropZoneContent; initDropZone();
}
startBtn.addEventListener('click', async (e) => {
e.preventDefault();
if (!fileInput.files || fileInput.files.length === 0) {
alert("Please select or drop an image first."); return;
}
const originalBtnContent = startBtn.innerHTML;
startBtn.innerHTML = '<div class="absolute inset-0 flex items-center justify-center gap-2 lg:gap-3"><svg class="animate-spin h-4 w-4 lg:h-5 lg:w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg><span class="text-white text-base lg:text-lg font-bold tracking-wide">Synthesizing...</span></div>';
startBtn.disabled = true; startBtn.classList.remove('animate-pulse-slow', 'animate-glow-pulse');
try {
const formData = new FormData(); formData.append('file', fileInput.files[0]);
const response = await fetch('/generate-catalog', { method: 'POST', body: formData });
if (!response.ok) throw new Error("Server Error " + response.status);
const data = await response.json();
jsonOutput.textContent = JSON.stringify(data, null, 2);
isCatalogGenerated = true;
} catch (error) {
console.error("Agent Error:", error); alert("Pipeline failed: " + error.message);
} finally {
startBtn.innerHTML = originalBtnContent; startBtn.disabled = false; startBtn.classList.add('animate-pulse-slow', 'animate-glow-pulse');
}
});
copyBtn.addEventListener('click', () => {
navigator.clipboard.writeText(jsonOutput.innerText).then(() => {
const originalIcon = copyIcon.innerText; copyIcon.innerText = 'check'; copyIcon.classList.add('text-green-400');
setTimeout(() => { copyIcon.innerText = originalIcon; copyIcon.classList.remove('text-green-400'); }, 2000);
});
});
</script>
</body>
</html>