st / index.html
fsalmansour's picture
✅ Current state of the prompt Area What’s already in the file Core layout Single-page dark UI (glassmorphism) with side-rail navigation, top bar, KPI cards, What-If, Models, Stores, AI charts, Integrations. Products module Bulk-import (CSV → array), live stock-badge (< 10 turns red), quick-add FAB ( wired to Add Modal), searchable via the command palette (add product, find SKU 123). Integrations Grid filtered by type (Ads, Stores, Email, Automation). Each card supports Connect / Disconnect via dynamic modal and saves state to localStorage. n8n Automations Table + actions (activate/deactivate, run, logs) backed by your /api/automations façade → n8n REST endpoints. Web-socket hooks are ready for live toasts. Command palette Global CMD-K with fuzzy actions for products, models, stores, automations. Accessibility & theming Keyboard-focusable, ARIA labels on floating buttons, custom accent color & theme persistence. Data persistence Everything (theme, lang, plugins, products, stock, workflows) stored or cached in localStorage until you wire a real backend. Charts Lazy-initialised Chart.js (bar + doughnut) and colour-synced to --accent. ⸻ 🔎 What’s left to make it production-ready Task Notes Backend endpoints /api/products, /api/stock-alerts, /api/automations, /api/plugins. Mocked now → swap with real API gateway / n8n proxy. Auth Add JWT / session handling around every fetch call (currently none). Validation & error UI Forms and connect modals assume success. Add try/catch + toast on failure. i18n cleanup Arabic bundle can be removed if you’ve decided on English-only. Security headers CSP, SRI for CDNs, referrer-policy, etc. Performance Purge unused Tailwind classes in build step (@tailwindcss/jit or content: purge). Unit tests Cypress/Playwright for the dashboard flows, Vitest for stores/models helpers. ⸻ 🚀 Next steps 1. Wire the real API • Drop-in replace the fake fetch calls with your gateway URLs. • Pass the n8n token server-side and expose only minimal routes to the browser. 2. Run an integration smoke-test • Import a CSV with 50 products → check badge colours. • Connect WooCommerce sandbox → verify webhook fires and appears in Automations. • Trigger a TikTok-Ads workflow via the dashboard and watch live logs. 3. Deploy preview • Build with tailwindcss -m and host on Vercel / Netlify for quick stakeholder review. ⸻ ℹ️ Anything else? If the checklist above looks good, yes, you’re done with the prompt and can move on to implementation. Need something tweaked or extra (PWA install, multi-tenant routing, light theme, etc.)? Just let me know and we’ll bolt it on before you cut code. - Initial Deployment
a85d356 verified
<!DOCTYPE html>
<html lang="en" x-data="storeAi" :dir="dir" :class="theme">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Store AI – Control Center</title>
=========== FLOATING ACTION CLUSTER ================== -->
<div class="fixed bottom-6 right-6 flex flex-col items-end space-y-3">
<button @click="openSettings=true" aria-label="Open settings"
class="glass p-3 rounded-full shadow-lg fab-shadow transition hover:scale-110 tooltip"
:title="t.settings">
<i class="fas fa-cog"></i>
<span class="tooltip-text" x-text="t.settings"></span>
</button>
<button @click="openAdd=true" aria-label="Add new integration"
class="glass p-4 rounded-full shadow-lg fab-shadow transition hover:scale-110 neon">
<i class="fas fa-plus"></i>
</button>
</div>
================== FLOATING ACTION CLUSTER ================== -->
<div class="fixed bottom-6 right-6 flex flex-col items-end space-y-3">
<button @click="openSettings=true" aria-label="Open settings"
class="glass p-3 rounded-full shadow-lg fab-shadow transition hover:scale-110 tooltip"
:title="t.settings">
<i class="fas fa-cog"></i>
<span class="tooltip-text" x-text="t.settings"></span>
</button>
<button @click="openAdd=true" aria-label="Add new integration"
class="glass p-4 rounded-full shadow-lg fab-shadow transition hover:scale-110 neon">
<i class="fas fa-plus"></i>
</button>
</div>
=======
<!-- ================== FLOATING ACTION CLUSTER ================== -->
<div class="fixed bottom-6 right-6 flex flex-col items-end space-y-3">
<button @click="openSettings=true" aria-label="Open settings"
class="glass p-3 rounded-full shadow-lg fab-shadow transition hover:scale-110 tooltip"
:title="t.settings">
<i class="fas fa-cog"></i>
<span class="tooltip-text" x-text="t.settings"></span>
</button>
<button @click="openProductModal=true" aria-label="Add product"
class="glass p-3 rounded-full shadow-lg fab-shadow transition hover:scale-110 tooltip"
:title="t.addProduct">
<i class="fas fa-box-open"></i>
<span class="tooltip-text" x-text="t.addProduct"></span>
</button>
<button @click="openAdd=true" aria-label="Add new integration"
class="glass p-4 rounded-full shadow-lg fab-shadow transition hover:scale-110 neon">
<i class="fas fa-plus"></i>
</button>
</div>
================== FLOATING ACTION CLUSTER ================== -->
<div class="fixed bottom-6 right-6 flex flex-col items-end space-y-3">
<button @click="openSettings=true" aria-label="Open settings"
class="glass p-3 rounded-full shadow-lg fab-shadow transition hover:scale-110 tooltip"
:title="t.settings">
<i class="fas fa-cog"></i>
<span class="tooltip-text" x-text="t.settings"></span>
</button>
<button @click="openAddProduct=true" aria-label="Add product"
class="glass p-3 rounded-full shadow-lg fab-shadow transition hover:scale-110 tooltip"
:title="t.addProduct">
<i class="fas fa-box-open"></i>
<span class="tooltip-text" x-text="t.addProduct"></span>
</button>
<button @click="openAdd=true" aria-label="Add new integration"
class="glass p-4 rounded-full shadow-lg fab-shadow transition hover:scale-110 neon">
<i class="fas fa-plus"></i>
</button>
</div>
TailwindCSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
accent: 'var(--accent)',
primary: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
}
}
}
}
}
</script>
<!-- Fonts & Icons -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"/>
<style>
:root {
--accent: #38bdf8;
}
body {
font-family: 'Inter', sans-serif;
background: #111827;
color: #e5e7eb;
}
.glass {
backdrop-filter: blur(25px) saturate(200%);
border: 1px solid rgba(255, 255, 255, 0.18);
background: rgba(30, 41, 59, 0.5);
}
.glass-light {
background: rgba(248, 250, 252, 0.6);
color: #0f172a;
}
.fab-shadow {
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}
.slide-enter {
animation: slide 0.3s ease-out forwards;
}
@keyframes slide {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
.kpi-card {
transition: transform 0.3s, box-shadow 0.3s;
}
.kpi-card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
}
.neon {
border: 1px solid var(--accent);
box-shadow: 0 0 6px var(--accent);
}
.progress-ring {
transform: rotate(-90deg);
}
.progress-ring-circle {
stroke-dasharray: 283;
stroke-dashoffset: 283;
transition: stroke-dashoffset 0.5s;
}
.tooltip {
position: relative;
}
.tooltip:hover .tooltip-text {
visibility: visible;
opacity: 1;
}
.tooltip-text {
visibility: hidden;
opacity: 0;
position: absolute;
z-index: 1;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: rgba(30, 41, 59, 0.9);
color: white;
padding: 0.5rem;
border-radius: 0.5rem;
font-size: 0.75rem;
white-space: nowrap;
transition: opacity 0.3s;
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.loading-bar {
position: relative;
overflow: hidden;
}
.loading-bar::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
animation: loading 1.5s infinite;
}
@keyframes loading {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
</style>
</head>
<body class="bg-slate-900 text-slate-200 antialiased overflow-x-hidden">
<!-- ================== APP BAR ================== -->
<header class="glass fixed top-0 left-0 right-0 z-50">
<div class="container mx-auto px-4 h-16 flex items-center justify-between">
<!-- logo -->
<div class="flex items-center space-x-3 rtl:space-x-reverse">
<div class="w-9 h-9 rounded-full bg-gradient-to-br from-indigo-500 to-cyan-400 flex items-center justify-center">
<i class="fas fa-brain text-white text-sm"></i>
</div>
<span class="font-extrabold text-lg hidden sm:inline">Store AI</span>
</div>
<!-- desktop command palette -->
<div class="hidden md:flex flex-1 max-w-xs mx-4">
<button @click="openCmdK = true"
class="w-full glass text-sm px-3 py-2 rounded-md flex items-center space-x-2 hover:bg-slate-700 transition">
<i class="fas fa-search text-xs"></i>
<span x-text="t.searchCmd"></span>
<kbd class="ml-auto text-xs px-2 py-1 bg-slate-700 rounded">⌘K</kbd>
</button>
</div>
<!-- nav icons -->
<div class="flex items-center space-x-3">
<button @click="toggleLang()"
class="text-sm font-semibold hover:opacity-80 transition"
:title="currentLang==='en'?'Switch to Arabic':'Switch to English'">
<span x-text="currentLang==='en'?'العربية':'EN'"></span>
</button>
<button @click="toggleTheme()"
class="p-1.5 rounded-full hover:bg-slate-700 transition tooltip"
:title="theme==='dark'?'Switch to Light Mode':'Switch to Dark Mode'">
<i class="fas text-yellow-300" :class="theme==='dark'?'fa-sun':'fa-moon'"></i>
<span class="tooltip-text" x-text="theme==='dark'?t.lightMode:t.darkMode"></span>
</button>
<button x-show="window.webkitSpeechRecognition" @click="startVoice()"
class="p-1.5 rounded-full hover:bg-slate-700 transition tooltip"
:title="t.voiceCommand">
<i class="fas fa-microphone text-red-400"></i>
<span class="tooltip-text" x-text="t.voiceCommand"></span>
</button>
<div class="relative">
<button @click="notificationsOpen = !notificationsOpen"
class="p-1.5 rounded-full hover:bg-slate-700 transition relative">
<i class="fas fa-bell"></i>
<span x-show="unreadNotifications > 0"
class="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full h-4 w-4 flex items-center justify-center">
<span x-text="unreadNotifications"></span>
</span>
</button>
<div x-show="notificationsOpen" @click.away="notificationsOpen = false"
class="absolute right-0 mt-2 w-72 glass rounded-lg shadow-lg z-50 max-h-96 overflow-y-auto">
<div class="p-3 border-b border-slate-700 flex justify-between items-center">
<h3 class="font-bold" x-text="t.notifications"></h3>
<button @click="markAllAsRead()" class="text-xs text-accent hover:underline" x-text="t.markAllRead"></button>
</div>
<template x-for="(note, index) in notifications" :key="index">
<div class="p-3 border-b border-slate-700 hover:bg-slate-700 cursor-pointer"
:class="{'bg-slate-700/50': !note.read}"
@click="markAsRead(index)">
<p class="text-sm" x-text="note.message"></p>
<p class="text-xs text-slate-400 mt-1" x-text="note.time"></p>
</div>
</template>
<div x-show="notifications.length === 0" class="p-4 text-center text-sm text-slate-400">
<p x-text="t.noNotifications"></p>
</div>
</div>
</div>
<div class="relative">
<button @click="profileOpen = !profileOpen"
class="flex items-center space-x-2 hover:bg-slate-700 transition rounded-full p-1">
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center">
<span class="text-xs font-bold">AI</span>
</div>
</button>
<div x-show="profileOpen" @click.away="profileOpen = false"
class="absolute right-0 mt-2 w-48 glass rounded-lg shadow-lg z-50">
<div class="p-3 border-b border-slate-700">
<p class="font-medium" x-text="user.name"></p>
<p class="text-xs text-slate-400" x-text="user.email"></p>
</div>
<div class="p-1">
<a href="#" class="block px-3 py-2 text-sm hover:bg-slate-700 rounded" x-text="t.profile"></a>
<a href="#" class="block px-3 py-2 text-sm hover:bg-slate-700 rounded" x-text="t.settings"></a>
<button @click="logout()" class="block w-full text-left px-3 py-2 text-sm hover:bg-slate-700 rounded text-red-400" x-text="t.logout"></button>
</div>
</div>
</div>
</div>
</div>
</header>
<!-- ================== SIDE RAIL ================== -->
<aside x-show="sideOpen" @click.away="sideOpen=false"
class="glass fixed inset-y-0 left-0 z-40 w-64 p-4 space-y-5 overflow-y-auto lg:relative lg:translate-x-0 transform transition-transform duration-300"
:class="sideOpen ? 'translate-x-0' : '-translate-x-full'">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center space-x-3">
<div class="w-9 h-9 rounded-full bg-gradient-to-br from-indigo-500 to-cyan-400 flex items-center justify-center">
<i class="fas fa-brain text-white text-sm"></i>
</div>
<span class="font-extrabold text-lg">Store AI</span>
</div>
<button @click="sideOpen = false" class="lg:hidden p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="mb-6">
<div class="glass rounded-lg p-3">
<div class="flex items-center justify-between mb-2">
<span class="text-xs font-medium" x-text="t.plan"></span>
<span class="text-xs px-2 py-1 bg-emerald-600/20 text-emerald-400 rounded-full" x-text="user.plan"></span>
</div>
<div class="w-full bg-slate-700 rounded-full h-1.5 mb-1">
<div class="bg-accent h-1.5 rounded-full" :style="'width: ' + user.usage + '%'"></div>
</div>
<div class="flex justify-between text-xs text-slate-400">
<span x-text="user.usage + '% ' + t.used"></span>
<span x-text="t.remaining + ' ' + (100 - user.usage) + '%'"></span>
</div>
</div>
</div>
<nav class="space-y-1">
<template x-for="(item,i) in navItems" :key="item.label">
<a :href="'#'+item.id"
@click="scrollToSection(item.id)"
class="flex items-center space-x-3 rtl:space-x-reverse px-3 py-2 rounded-md hover:bg-slate-700 transition"
:class="activeSection===item.id?'bg-slate-700/50':''">
<i :class="item.icon + ' text-sm w-5 text-center'"></i>
<span x-text="item.label"></span>
<span x-show="item.badge" class="ml-auto text-xs px-2 py-1 rounded-full bg-accent/20 text-accent" x-text="item.badge"></span>
</a>
</template>
</nav>
<div class="absolute bottom-4 left-4 right-4">
<div class="glass rounded-lg p-3 text-center">
<p class="text-xs mb-1" x-text="t.needHelp"></p>
<button @click="openSupport = true" class="text-xs text-accent font-medium hover:underline" x-text="t.contactSupport"></button>
</div>
</div>
</aside>
<!-- mobile hamburger -->
<button @click="sideOpen=!sideOpen"
class="glass fixed top-20 left-4 z-30 p-2 rounded-full lg:hidden fab-shadow">
<i class="fas fa-bars"></i>
</button>
<!-- ================== MAIN CONTENT ================== -->
<main class="pt-20 lg:pl-72 px-4 pb-16 space-y-16">
<!-- KPI SECTION -->
<section id="kpi" class="scroll-mt-20">
<div class="flex items-center justify-between mb-6">
<h2 class="text-2xl font-extrabold" x-text="t.dashboard"></h2>
<div class="flex items-center space-x-2">
<div class="relative">
<select x-model="timeRange" class="glass text-sm px-3 py-1.5 rounded appearance-none pr-7">
<option value="today" x-text="t.today"></option>
<option value="week" x-text="t.thisWeek"></option>
<option value="month" x-text="t.thisMonth"></option>
</select>
<i class="fas fa-chevron-down absolute right-2 top-1/2 transform -translate-y-1/2 text-xs pointer-events-none"></i>
</div>
<button @click="refreshData()" class="glass p-1.5 rounded hover:bg-slate-700 transition tooltip" :title="t.refresh">
<i class="fas fa-sync-alt text-sm" :class="{'animate-spin': isRefreshing}"></i>
<span class="tooltip-text" x-text="t.refresh"></span>
</button>
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<template x-for="(k,i) in kpis" :key="k.label">
<div class="kpi-card glass p-4 rounded-xl" :class="{'animate-pulse': k.loading}">
<div class="flex items-center justify-between mb-2">
<div class="flex items-center">
<div class="w-8 h-8 rounded-full bg-accent/10 flex items-center justify-center mr-2">
<i :class="k.icon + ' text-accent text-sm'"></i>
</div>
<span class="text-sm" x-text="k.label"></span>
</div>
<button @click="showKpiDetails(k)" class="text-xs text-slate-400 hover:text-accent">
<i class="fas fa-info-circle"></i>
</button>
</div>
<p class="text-2xl font-bold mb-1" x-text="k.value"></p>
<div class="flex items-center">
<span class="text-xs" :class="k.trend > 0 ? 'text-emerald-400' : 'text-red-400'">
<i :class="k.trend > 0 ? 'fas fa-caret-up' : 'fas fa-caret-down'"></i>
<span x-text="Math.abs(k.trend) + '%'"></span>
</span>
<span class="text-xs text-slate-400 ml-2" x-text="'vs ' + (timeRange === 'today' ? t.yesterday : timeRange === 'week' ? t.lastWeek : t.lastMonth)"></span>
</div>
</div>
</template>
</div>
<!-- Mini charts row -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4">
<div class="glass rounded-xl p-4">
<div class="flex items-center justify-between mb-2">
<span class="text-sm" x-text="t.conversionRate"></span>
<span class="text-xs px-2 py-1 bg-emerald-600/20 text-emerald-400 rounded-full" x-text="'+2.4%'"></span>
</div>
<div class="h-24">
<canvas id="miniChart1"></canvas>
</div>
</div>
<div class="glass rounded-xl p-4">
<div class="flex items-center justify-between mb-2">
<span class="text-sm" x-text="t.avgOrderValue"></span>
<span class="text-xs px-2 py-1 bg-red-600/20 text-red-400 rounded-full" x-text="'-1.2%'"></span>
</div>
<div class="h-24">
<canvas id="miniChart2"></canvas>
</div>
</div>
<div class="glass rounded-xl p-4">
<div class="flex items-center justify-between mb-2">
<span class="text-sm" x-text="t.newCustomers"></span>
<span class="text-xs px-2 py-1 bg-emerald-600/20 text-emerald-400 rounded-full" x-text="'+8.7%'"></span>
</div>
<div class="h-24">
<canvas id="miniChart3"></canvas>
</div>
</div>
</div>
</section>
<!-- WHAT-IF SIM -->
<section id="sim" class="scroll-mt-20">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-bold" x-text="t.whatIf"></h2>
<button @click="saveScenario()" class="text-sm glass px-3 py-1 rounded hover:bg-slate-700" x-text="t.saveScenario"></button>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div class="glass rounded-xl p-5">
<div class="space-y-4">
<div>
<label class="text-sm flex items-center justify-between">
<span x-text="t.discount"></span>
<span class="text-xs text-slate-400" x-text="'Current: ' + currentDiscount + '%'"></span>
</label>
<input type="range" min="0" max="50" x-model="discount" class="w-full accent-accent mb-1">
<div class="flex justify-between text-xs text-slate-400">
<span>0%</span>
<span x-text="discount + '%'"></span>
<span>50%</span>
</div>
</div>
<div>
<label class="text-sm flex items-center justify-between">
<span x-text="t.budget"></span>
<span class="text-xs text-slate-400" x-text="'Current: $' + currentBudget"></span>
</label>
<input type="range" min="0" max="2000" step="50" x-model="budget" class="w-full accent-accent mb-1">
<div class="flex justify-between text-xs text-slate-400">
<span>$0</span>
<span x-text="'$' + budget"></span>
<span>$2000</span>
</div>
</div>
</div>
</div>
<div class="glass rounded-xl p-5">
<h3 class="text-sm font-medium mb-3" x-text="t.projectedResults"></h3>
<div class="space-y-3">
<div class="flex items-center justify-between">
<span class="text-sm" x-text="t.revenue"></span>
<span class="font-medium" x-text="'$' + ((budget*2.15)-(discount*36)).toFixed(0)"></span>
</div>
<div class="flex items-center justify-between">
<span class="text-sm" x-text="t.profit"></span>
<span class="font-medium" x-text="'$' + ((budget*1.45)-(discount*28)).toFixed(0)"></span>
</div>
<div class="flex items-center justify-between">
<span class="text-sm" x-text="t.newCustomers"></span>
<span class="font-medium" x-text="Math.round(budget/25)"></span>
</div>
<div class="flex items-center justify-between">
<span class="text-sm" x-text="t.roi"></span>
<span class="font-medium" x-text="Math.round(((budget*1.45)-(discount*28))/budget*100) + '%'"></span>
</div>
</div>
</div>
<div class="glass rounded-xl p-5">
<h3 class="text-sm font-medium mb-3" x-text="t.savedScenarios"></h3>
<div class="space-y-2">
<template x-for="(scenario, index) in savedScenarios" :key="index">
<div class="flex items-center justify-between p-2 hover:bg-slate-700 rounded cursor-pointer" @click="loadScenario(index)">
<div>
<p class="text-sm font-medium" x-text="scenario.name"></p>
<p class="text-xs text-slate-400" x-text="'Discount: ' + scenario.discount + '% | Budget: $' + scenario.budget"></p>
</div>
<button @click.stop="deleteScenario(index)" class="text-red-400 hover:text-red-300 p-1">
<i class="fas fa-trash text-xs"></i>
</button>
</div>
</template>
<div x-show="savedScenarios.length === 0" class="text-center py-4 text-sm text-slate-400">
<p x-text="t.noScenarios"></p>
</div>
</div>
</div>
</div>
</section>
<!-- MODELS TABLE -->
<section id="models" class="scroll-mt-20">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-bold" x-text="t.models"></h2>
<div class="flex items-center space-x-2">
<button @click="openAddModel = true" class="text-sm glass px-3 py-1 rounded hover:bg-slate-700 flex items-center space-x-1">
<i class="fas fa-plus text-xs"></i>
<span x-text="t.addModel"></span>
</button>
<div class="relative">
<select x-model="modelFilter" class="glass text-sm px-3 py-1 rounded appearance-none pr-7">
<option value="all" x-text="t.allModels"></option>
<option value="active" x-text="t.active"></option>
<option value="inactive" x-text="t.inactive"></option>
</select>
<i class="fas fa-chevron-down absolute right-2 top-1/2 transform -translate-y-1/2 text-xs pointer-events-none"></i>
</div>
</div>
</div>
<div class="glass rounded-xl overflow-x-auto">
<table class="w-full text-sm">
<thead class="bg-slate-800">
<tr>
<th class="p-3 text-left" x-text="t.model"></th>
<th class="p-3 text-left">Provider</th>
<th class="p-3 text-left">Size</th>
<th class="p-3 text-left">Status</th>
<th class="p-3 text-left">Usage</th>
<th class="p-3" x-text="t.action"></th>
</tr>
</thead>
<tbody>
<template x-for="m in filteredModels" :key="m.name">
<tr class="border-t border-slate-700 hover:bg-slate-800/50">
<td class="p-3">
<div class="flex items-center space-x-2">
<i :class="m.icon + ' text-accent'"></i>
<span x-text="m.name"></span>
</div>
</td>
<td class="p-3" x-text="m.provider"></td>
<td class="p-3" x-text="m.size"></td>
<td class="p-3">
<span class="px-2 py-1 rounded-full text-xs"
:class="m.active ? 'bg-emerald-600/20 text-emerald-400' : 'bg-slate-700/50 text-slate-400'"
x-text="m.active ? t.active : t.inactive"></span>
</td>
<td class="p-3">
<div class="w-20 h-1.5 bg-slate-700 rounded-full overflow-hidden">
<div class="h-full bg-accent rounded-full" :style="'width: ' + m.usage + '%'"></div>
</div>
</td>
<td class="p-3">
<div class="flex items-center space-x-2">
<button @click="toggleModelStatus(m)"
class="text-xs px-2 py-1 rounded hover:bg-slate-700"
:class="m.active ? 'text-red-400' : 'text-emerald-400'"
x-text="m.active ? t.deactivate : t.activate"></button>
<button @click="removeModel(m)" class="text-xs px-2 py-1 rounded hover:bg-slate-700 text-slate-400" x-text="t.remove"></button>
</div>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</section>
<!-- STORES TABLE -->
<section id="stores" class="scroll-mt-20">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-bold" x-text="t.stores"></h2>
<div class="flex items-center space-x-2">
<button @click="openAddStore = true" class="text-sm glass px-3 py-1 rounded hover:bg-slate-700 flex items-center space-x-1">
<i class="fas fa-plus text-xs"></i>
<span x-text="t.addStore"></span>
</button>
<div class="relative">
<select x-model="storeFilter" class="glass text-sm px-3 py-1 rounded appearance-none pr-7">
<option value="all" x-text="t.allStores"></option>
<option value="healthy" x-text="t.healthy"></option>
<option value="warning" x-text="t.warning"></option>
<option value="critical" x-text="t.critical"></option>
</select>
<i class="fas fa-chevron-down absolute right-2 top-1/2 transform -translate-y-1/2 text-xs pointer-events-none"></i>
</div>
</div>
</div>
<div class="glass rounded-xl overflow-x-auto">
<table class="w-full text-sm">
<thead class="bg-slate-800">
<tr>
<th class="p-3 text-left" x-text="t.store"></th>
<th class="p-3 text-left">Platform</th>
<th class="p-3 text-left">Health</th>
<th class="p-3 text-left">Last Sync</th>
<th class="p-3" x-text="t.action"></th>
</tr>
</thead>
<tbody>
<template x-for="s in filteredStores" :key="s.name">
<tr class="border-t border-slate-700 hover:bg-slate-800/50">
<td class="p-3">
<div class="flex items-center space-x-2">
<i :class="s.icon + ' text-accent'"></i>
<span x-text="s.name"></span>
</div>
</td>
<td class="p-3" x-text="s.platform"></td>
<td class="p-3">
<div class="flex items-center space-x-2">
<div class="relative w-8 h-8">
<svg class="w-8 h-8 progress-ring" viewBox="0 0 100 100">
<circle class="text-slate-700" stroke-width="8" stroke="currentColor" fill="transparent" r="45" cx="50" cy="50" />
<circle class="progress-ring-circle"
stroke-width="8"
stroke-linecap="round"
stroke="currentColor"
fill="transparent"
r="45"
cx="50"
cy="50"
:stroke="s.health > 90 ? '#10b981' : s.health > 70 ? '#f59e0b' : '#ef4444'"
:stroke-dashoffset="283 - (283 * s.health / 100)" />
</svg>
<span class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-xs font-bold"
:class="s.health > 90 ? 'text-emerald-400' : s.health > 70 ? 'text-yellow-400' : 'text-red-400'"
x-text="s.health + '%'"></span>
</div>
<span class="text-xs" :class="s.health > 90 ? 'text-emerald-400' : s.health > 70 ? 'text-yellow-400' : 'text-red-400'">
<i :class="s.trend > 0 ? 'fas fa-caret-up' : 'fas fa-caret-down'"></i>
<span x-text="Math.abs(s.trend) + '%'"></span>
</span>
</div>
</td>
<td class="p-3 text-xs text-slate-400" x-text="formatDate(s.lastSync)"></td>
<td class="p-3">
<div class="flex items-center space-x-2">
<button @click="syncStore(s)" class="text-xs px-2 py-1 rounded hover:bg-slate-700 text-accent" x-text="t.sync"></button>
<button @click="inspectStore(s)" class="text-xs px-2 py-1 rounded hover:bg-slate-700" x-text="t.inspect"></button>
</div>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</section>
<!-- PRODUCTS TABLE -->
<section id="products" class="scroll-mt-20">
<h2 class="text-xl font-bold mb-4">Products</h2>
<!-- Bulk-Import Button -->
<div class="mb-3 flex items-center space-x-3">
<label class="glass px-3 py-1 rounded cursor-pointer text-sm">
<i class="fas fa-file-upload mr-1"></i> Import CSV
<input type="file" accept=".csv"
@change="importCSV($event)" class="hidden">
</label>
</div>
<div class="glass rounded-xl overflow-x-auto">
<table class="w-full text-sm">
<thead class="bg-slate-800">
<tr>
<th class="p-3 text-left">#</th>
<th class="p-3 text-left">Name</th>
<th class="p-3 text-left">SKU</th>
<th class="p-3 text-left">Price</th>
<th class="p-3 text-left">Stock</th>
<th class="p-3 text-left">Action</th>
</tr>
</thead>
<tbody>
<template x-for="p in products" :key="p.id">
<tr class="border-t border-slate-700">
<td class="p-3" x-text="p.id"></td>
<td class="p-3" x-text="p.name"></td>
<td class="p-3" x-text="p.sku"></td>
<td class="p-3" x-text="' <section id="ai" class="scroll-mt-20">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-bold">AI Usage</h2>
<div class="relative">
<select x-model="chartTimeRange" class="glass text-sm px-3 py-1 rounded appearance-none pr-7">
<option value="7d" x-text="t.last7Days"></option>
<option value="30d" x-text="t.last30Days"></option>
<option value="90d" x-text="t.last90Days"></option>
</select>
<i class="fas fa-chevron-down absolute right-2 top-1/2 transform -translate-y-1/2 text-xs pointer-events-none"></i>
</div>
</div>
<div class="grid md:grid-cols-2 gap-6">
<div class="glass rounded-xl p-4">
<div class="flex items-center justify-between mb-4">
<h3 class="font-medium" x-text="t.apiUsage"></h3>
<div class="flex items-center space-x-2">
<div class="flex items-center">
<div class="w-2 h-2 rounded-full bg-accent mr-1"></div>
<span class="text-xs" x-text="t.thisMonth"></span>
</div>
<div class="flex items-center">
<div class="w-2 h-2 rounded-full bg-slate-500 mr-1"></div>
<span class="text-xs" x-text="t.lastMonth"></span>
</div>
</div>
</div>
<canvas id="apiChart" height="250"></canvas>
</div>
<div class="glass rounded-xl p-4">
<div class="flex items-center justify-between mb-4">
<h3 class="font-medium" x-text="t.providerDistribution"></h3>
<div class="relative">
<select x-model="distributionFilter" class="glass text-xs px-2 py-1 rounded appearance-none pr-6">
<option value="requests" x-text="t.requests"></option>
<option value="cost" x-text="t.cost"></option>
<option value="tokens" x-text="t.tokens"></option>
</select>
<i class="fas fa-chevron-down absolute right-1 top-1/2 transform -translate-y-1/2 text-xs pointer-events-none"></i>
</div>
</div>
<canvas id="providerChart" height="250"></canvas>
</div>
</div>
<!-- Cost Summary -->
<div class="glass rounded-xl p-4 mt-6">
<h3 class="font-medium mb-4" x-text="t.costSummary"></h3>
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<div class="bg-slate-800/50 rounded-lg p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.thisMonth"></p>
<p class="text-xl font-bold" x-text="'$' + costs.current"></p>
</div>
<div class="bg-slate-800/50 rounded-lg p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.lastMonth"></p>
<p class="text-xl font-bold" x-text="'$' + costs.last"></p>
</div>
<div class="bg-slate-800/50 rounded-lg p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.change"></p>
<p class="text-xl font-bold" :class="costs.change > 0 ? 'text-emerald-400' : 'text-red-400'"
x-text="(costs.change > 0 ? '+' : '') + costs.change + '%'"></p>
</div>
<div class="bg-slate-800/50 rounded-lg p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.forecast"></p>
<p class="text-xl font-bold" x-text="'$' + costs.forecast"></p>
</div>
</div>
</div>
</section>
<!-- ADS INTEGRATIONS -->
<section id="ads" class="scroll-mt-20">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-bold" x-text="t.ads"></h2>
<button @click="openAddIntegration = true" class="text-sm glass px-3 py-1 rounded hover:bg-slate-700 flex items-center space-x-1">
<i class="fas fa-plus text-xs"></i>
<span x-text="t.addIntegration"></span>
</button>
</div>
<!-- Filter Buttons -->
<div class="flex flex-wrap gap-2 mb-4">
<template x-for="f in ['All','Ads','Stores','Email','Automation']" :key="f">
<button @click="filter=f.toLowerCase()"
class="px-3 py-1 rounded-md text-sm transition"
:class="filter===f.toLowerCase()?'bg-accent text-white':'glass hover:bg-slate-700'"
x-text="f"></button>
</template>
</div>
<!-- Plugins Grid -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
<template x-for="p in filteredPlugins" :key="p.id">
<div class="glass rounded-xl p-4 hover:bg-slate-700/50 transition cursor-pointer" @click="openConnectModal(p)">
<div class="flex items-start justify-between mb-3">
<div class="w-10 h-10 rounded-lg bg-accent/10 flex items-center justify-center">
<i :class="p.icon + ' text-accent text-lg'"></i>
</div>
<span class="text-xs px-2 py-1 rounded-full"
:class="p.connected ? 'bg-emerald-600/20 text-emerald-400' : 'bg-slate-700/50 text-slate-400'"
x-text="p.connected ? 'Connected' : 'Disconnected'"></span>
</div>
<p class="font-semibold mb-1" x-text="p.name"></p>
<p class="text-xs text-slate-400 mb-3" x-text="p.description"></p>
<div class="w-full bg-slate-700 rounded-full h-1.5 mb-1">
<div class="bg-accent h-1.5 rounded-full" :style="'width: ' + (p.connected ? '100' : '0') + '%'"></div>
</div>
<div class="flex justify-between text-xs text-slate-400">
<span x-text="p.connected ? 'Connected' : 'Not connected'"></span>
<span x-text="p.type === 'ads' ? 'Ads' : p.type === 'e-commerce' ? 'E-commerce' : p.type === 'email' ? 'Email' : 'Automation'"></span>
</div>
</div>
</template>
</div>
</section>
</main>
<!-- ================== FLOATING ACTION CLUSTER ================== -->
<div class="fixed bottom-6 right-6 flex flex-col items-end space-y-3">
<button @click="openSettings=true" aria-label="Open settings"
class="glass p-3 rounded-full shadow-lg fab-shadow transition hover:scale-110 tooltip"
:title="t.settings">
<i class="fas fa-cog"></i>
<span class="tooltip-text" x-text="t.settings"></span>
</button>
<button @click="openAdd=true" aria-label="Add new integration"
class="glass p-4 rounded-full shadow-lg fab-shadow transition hover:scale-110 neon">
<i class="fas fa-plus"></i>
</button>
</div>
<!-- ================== MODALS ================== -->
<!-- Command Palette -->
<div x-show="openCmdK" @click.away="openCmdK=false"
class="fixed inset-0 bg-black/50 z-50 flex items-start justify-center pt-20">
<div class="glass w-full max-w-lg rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex items-center">
<i class="fas fa-search text-sm mr-2 text-slate-400"></i>
<input type="search" placeholder="Type to search..."
class="w-full bg-transparent outline-none placeholder-slate-400"
x-ref="cmdInput"
@keydown.escape="openCmdK=false"
@keyup="filterCommands($event.target.value)">
</div>
<div class="max-h-96 overflow-y-auto">
<template x-for="cmd in filteredCommands" :key="cmd.label">
<button @click="executeCommand(cmd)"
class="w-full text-left p-3 hover:bg-slate-700 flex items-center space-x-3">
<i :class="cmd.icon + ' text-sm w-5 text-center text-slate-400'"></i>
<div>
<p x-text="cmd.label"></p>
<p class="text-xs text-slate-400" x-text="cmd.description"></p>
</div>
<kbd class="ml-auto text-xs px-2 py-1 bg-slate-700 rounded" x-text="cmd.shortcut"></kbd>
</button>
</template>
<div x-show="filteredCommands.length === 0" class="p-4 text-center text-sm text-slate-400">
<p x-text="t.noCommands"></p>
</div>
</div>
</div>
</div>
<!-- Add Modal -->
<div x-show="openAdd" @click.away="openAdd=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="t.addNew"></h3>
<button @click="openAdd=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 max-h-96 overflow-y-auto">
<div class="relative mb-4">
<i class="fas fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-sm text-slate-400"></i>
<input type="search" placeholder="Search integrations..."
class="w-full glass pl-9 pr-3 py-2 rounded outline-none"
x-model="integrationSearch">
</div>
<div class="space-y-2">
<template x-for="plugin in filteredAvailablePlugins" :key="plugin.id">
<button @click="addPlugin(plugin)"
class="w-full glass p-3 rounded text-left flex items-center space-x-3 hover:bg-slate-700">
<i :class="plugin.icon + ' text-accent'"></i>
<div>
<p x-text="plugin.name"></p>
<p class="text-xs text-slate-400" x-text="plugin.description"></p>
</div>
</button>
</template>
<div x-show="filteredAvailablePlugins.length === 0" class="p-4 text-center text-sm text-slate-400">
<p x-text="t.noIntegrations"></p>
</div>
</div>
</div>
</div>
</div>
<!-- Settings Modal -->
<div x-show="openSettings" @click.away="openSettings=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold">Settings</h3>
<button @click="openSettings=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 max-h-96 overflow-y-auto space-y-4">
<div>
<label class="block text-sm mb-2">Accent Color</label>
<input type="color" x-model="accent" @change="updateAccentColor" class="w-full h-10 rounded">
</div>
<div>
<label class="block text-sm mb-2">Theme</label>
<div class="flex space-x-2">
<button @click="theme='dark'" :class="theme==='dark'?'bg-accent text-white':'glass'" class="px-3 py-1.5 rounded text-sm">
Dark
</button>
<button @click="theme=''" :class="theme===''?'bg-accent text-white':'glass'" class="px-3 py-1.5 rounded text-sm">
Light
</button>
</div>
</div>
<div>
<label class="block text-sm mb-2">Language</label>
<div class="flex space-x-2">
<button @click="currentLang='en'" :class="currentLang==='en'?'bg-accent text-white':'glass'" class="px-3 py-1.5 rounded text-sm">
English
</button>
<button @click="currentLang='ar'" :class="currentLang==='ar'?'bg-accent text-white':'glass'" class="px-3 py-1.5 rounded text-sm">
العربية
</button>
</div>
</div>
<div>
<label class="block text-sm mb-2">Notifications</label>
<div class="space-y-2">
<label class="flex items-center space-x-2">
<input type="checkbox" x-model="settings.emailNotifications" class="rounded accent-accent">
<span class="text-sm" x-text="t.emailNotifications"></span>
</label>
<label class="flex items-center space-x-2">
<input type="checkbox" x-model="settings.pushNotifications" class="rounded accent-accent">
<span class="text-sm" x-text="t.pushNotifications"></span>
</label>
</div>
</div>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end">
<button @click="saveSettings()" class="px-4 py-2 bg-accent rounded text-white hover:bg-accent/90" x-text="t.save"></button>
</div>
</div>
</div>
<!-- Support Modal -->
<div x-show="openSupport" @click.away="openSupport=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="t.contactSupport"></h3>
<button @click="openSupport=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 space-y-4">
<div>
<label class="block text-sm mb-1" x-text="t.subject"></label>
<input type="text" x-model="support.subject" class="w-full glass px-3 py-2 rounded">
</div>
<div>
<label class="block text-sm mb-1" x-text="t.message"></label>
<textarea x-model="support.message" rows="5" class="w-full glass px-3 py-2 rounded"></textarea>
</div>
<div>
<label class="block text-sm mb-1" x-text="t.attachment"></label>
<div class="glass rounded p-3 text-center border-2 border-dashed border-slate-700 cursor-pointer hover:bg-slate-700/50">
<i class="fas fa-cloud-upload-alt text-2xl text-slate-400 mb-2"></i>
<p class="text-sm" x-text="t.uploadFile"></p>
<p class="text-xs text-slate-400" x-text="t.maxSize"></p>
</div>
</div>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end space-x-2">
<button @click="openSupport=false" class="px-4 py-2 glass rounded hover:bg-slate-700" x-text="t.cancel"></button>
<button @click="sendSupportRequest()" class="px-4 py-2 bg-accent rounded text-white hover:bg-accent/90" x-text="t.send"></button>
</div>
</div>
</div>
<!-- Add Model Modal -->
<div x-show="openAddModel" @click.away="openAddModel=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="t.addModel"></h3>
<button @click="openAddModel=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 space-y-4">
<div>
<label class="block text-sm mb-1" x-text="t.modelName"></label>
<input type="text" x-model="newModel.name" class="w-full glass px-3 py-2 rounded">
</div>
<div>
<label class="block text-sm mb-1" x-text="t.provider"></label>
<select x-model="newModel.provider" class="w-full glass px-3 py-2 rounded">
<option value="OpenAI">OpenAI</option>
<option value="Meta">Meta</option>
<option value="Google">Google</option>
<option value="Anthropic">Anthropic</option>
</select>
</div>
<div>
<label class="block text-sm mb-1" x-text="t.size"></label>
<input type="text" x-model="newModel.size" class="w-full glass px-3 py-2 rounded">
</div>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end space-x-2">
<button @click="openAddModel=false" class="px-4 py-2 glass rounded hover:bg-slate-700" x-text="t.cancel"></button>
<button @click="addNewModel()" class="px-4 py-2 bg-accent rounded text-white hover:bg-accent/90" x-text="t.add"></button>
</div>
</div>
</div>
<!-- Bulk Import Modal -->
<div x-show="openBulkImport" @click.away="openBulkImport=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="t.bulkImport"></h3>
<button @click="openBulkImport=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 space-y-4">
<div class="border-2 border-dashed border-slate-700 rounded-lg p-6 text-center cursor-pointer hover:bg-slate-700/20"
@click="$refs.csvInput.click()">
<i class="fas fa-file-csv text-3xl text-accent mb-2"></i>
<p class="text-sm" x-text="t.uploadCsv"></p>
<p class="text-xs text-slate-400" x-text="t.csvFormat"></p>
<input type="file" x-ref="csvInput" accept=".csv" class="hidden" @change="handleCsvUpload">
</div>
<div x-show="csvPreview.length > 0" class="glass rounded-lg p-3 max-h-64 overflow-y-auto">
<table class="w-full text-xs">
<thead>
<tr class="border-b border-slate-700">
<th class="p-1 text-left" x-text="t.sku"></th>
<th class="p-1 text-left" x-text="t.name"></th>
<th class="p-1 text-left" x-text="t.stock"></th>
</tr>
</thead>
<tbody>
<template x-for="(row, i) in csvPreview" :key="i">
<tr class="border-b border-slate-700">
<td class="p-1" x-text="row.sku"></td>
<td class="p-1" x-text="row.name"></td>
<td class="p-1" x-text="row.stock"></td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end space-x-2">
<button @click="openBulkImport=false" class="px-4 py-2 glass rounded hover:bg-slate-700" x-text="t.cancel"></button>
<button @click="importProducts()"
class="px-4 py-2 bg-accent rounded text-white hover:bg-accent/90"
:disabled="csvPreview.length === 0"
x-text="t.import"></button>
</div>
</div>
</div>
<!-- Product Modal -->
<div x-show="openProductModal" @click.away="openProductModal=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center">
<div class="glass w-full max-w-md rounded-xl p-6">
<h3 class="text-lg font-bold mb-4"
x-text="editingProduct ? 'Edit product' : 'Add product'"></h3>
<form @submit.prevent="saveProduct">
<input type="text" placeholder="Name" x-model="form.name"
class="w-full glass px-3 py-2 rounded mb-3" required>
<input type="text" placeholder="SKU" x-model="form.sku"
class="w-full glass px-3 py-2 rounded mb-3" required>
<input type="number" placeholder="Price" x-model.number="form.price"
class="w-full glass px-3 py-2 rounded mb-3" required>
<input type="number" placeholder="Stock" x-model.number="form.stock"
class="w-full glass px-3 py-2 rounded mb-4" required>
<button class="w-full glass p-2 rounded text-accent"
x-text="editingProduct ? 'Update' : 'Add'"></button>
</form>
</div>
</div>
<!-- Add Store Modal -->
<div x-show="openAddStore" @click.away="openAddStore=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="t.addStore"></h3>
<button @click="openAddStore=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 space-y-4">
<div>
<label class="block text-sm mb-1" x-text="t.storeName"></label>
<input type="text" x-model="newStore.name" class="w-full glass px-3 py-2 rounded">
</div>
<div>
<label class="block text-sm mb-1" x-text="t.platform"></label>
<select x-model="newStore.platform" class="w-full glass px-3 py-2 rounded">
<option value="Shopify">Shopify</option>
<option value="WooCommerce">WooCommerce</option>
<option value="BigCommerce">BigCommerce</option>
<option value="Magento">Magento</option>
</select>
</div>
<div>
<label class="block text-sm mb-1" x-text="t.storeUrl"></label>
<input type="url" x-model="newStore.url" class="w-full glass px-3 py-2 rounded" placeholder="https://">
</div>
<div>
<label class="block text-sm mb-1" x-text="t.apiKey"></label>
<input type="password" x-model="newStore.apiKey" class="w-full glass px-3 py-2 rounded">
</div>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end space-x-2">
<button @click="openAddStore=false" class="px-4 py-2 glass rounded hover:bg-slate-700" x-text="t.cancel"></button>
<button @click="addNewStore()" class="px-4 py-2 bg-accent rounded text-white hover:bg-accent/90" x-text="t.add"></button>
</div>
</div>
</div>
<!-- Connect Modal -->
<div x-show="selectedPlugin" @click.away="selectedPlugin=null"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="'Connect '+selectedPlugin?.name"></h3>
<button @click="selectedPlugin=null" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 space-y-4">
<!-- Ads -->
<template x-if="selectedPlugin?.type==='ads'">
<div>
<label class="text-sm mb-1 block" x-text="t.adAccountId"></label>
<input x-model="apiKey"
placeholder="Ad Account ID"
class="w-full glass px-3 py-2 rounded mb-3">
</div>
</template>
<!-- E-commerce -->
<template x-if="selectedPlugin?.type==='e-commerce'">
<div>
<label class="text-sm mb-1 block" x-text="t.storeUrl"></label>
<input x-model="apiKey"
placeholder="https://store.com"
class="w-full glass px-3 py-2 rounded mb-3">
<label class="text-sm mb-1 block" x-text="t.apiKey"></label>
<input x-model="apiSecret"
type="password"
placeholder="API Key"
class="w-full glass px-3 py-2 rounded">
</div>
</template>
<!-- Email -->
<template x-if="selectedPlugin?.type==='email'">
<div class="space-y-3">
<div>
<label class="text-sm mb-1 block" x-text="t.smtpHost"></label>
<input x-model="apiKey"
placeholder="smtp.example.com"
class="w-full glass px-3 py-2 rounded">
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="text-sm mb-1 block" x-text="t.username"></label>
<input x-model="emailUser"
placeholder="Username"
class="w-full glass px-3 py-2 rounded">
</div>
<div>
<label class="text-sm mb-1 block" x-text="t.password"></label>
<input x-model="emailPass"
type="password"
placeholder="Password"
class="w-full glass px-3 py-2 rounded">
</div>
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="text-sm mb-1 block" x-text="t.port"></label>
<input x-model="emailPort"
type="number"
placeholder="587"
class="w-full glass px-3 py-2 rounded">
</div>
<div>
<label class="text-sm mb-1 block" x-text="t.security"></label>
<select x-model="emailSecurity" class="w-full glass px-3 py-2 rounded">
<option value="tls">TLS</option>
<option value="ssl">SSL</option>
<option value="none">None</option>
</select>
</div>
</div>
</div>
</template>
<!-- Automation -->
<template x-if="selectedPlugin?.type==='automation'">
<div>
<label class="text-sm mb-1 block" x-text="t.webhookUrl"></label>
<input x-model="apiKey"
placeholder="https://n8n.hook.com"
class="w-full glass px-3 py-2 rounded mb-3">
<label class="text-sm mb-1 block" x-text="t.secretKey"></label>
<input x-model="apiSecret"
type="password"
placeholder="Secret Key"
class="w-full glass px-3 py-2 rounded">
</div>
</template>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end space-x-2">
<button @click="selectedPlugin=null" class="px-4 py-2 glass rounded hover:bg-slate-700" x-text="t.cancel"></button>
<button @click="connectPlugin(selectedPlugin)"
class="px-4 py-2 rounded text-white flex items-center space-x-2"
:class="selectedPlugin?.connected ? 'bg-red-500 hover:bg-red-600' : 'bg-accent hover:bg-accent/90'"
x-text="selectedPlugin?.connected ? t.disconnect : t.connect">
</button>
</div>
</div>
</div>
<!-- KPI Details Modal -->
<div x-show="selectedKpi" @click.away="selectedKpi=null"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="selectedKpi?.label"></h3>
<button @click="selectedKpi=null" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4">
<div class="flex items-center justify-between mb-4">
<div>
<p class="text-2xl font-bold" x-text="selectedKpi?.value"></p>
<p class="text-sm" :class="selectedKpi?.trend > 0 ? 'text-emerald-400' : 'text-red-400'">
<i :class="selectedKpi?.trend > 0 ? 'fas fa-caret-up' : 'fas fa-caret-down'"></i>
<span x-text="Math.abs(selectedKpi?.trend) + '%'"></span>
<span class="text-slate-400 ml-1" x-text="'vs ' + (timeRange === 'today' ? t.yesterday : timeRange === 'week' ? t.lastWeek : t.lastMonth)"></span>
</p>
</div>
<div class="w-16 h-16">
<canvas x-ref="kpiChart"></canvas>
</div>
</div>
<div class="h-48 mb-4">
<canvas x-ref="kpiDetailChart"></canvas>
</div>
<div class="grid grid-cols-2 gap-4">
<div class="glass rounded p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.avgDaily"></p>
<p class="font-medium" x-text="selectedKpi?.avgDaily"></p>
</div>
<div class="glass rounded p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.peakTime"></p>
<p class="font-medium" x-text="selectedKpi?.peakTime"></p>
</div>
</div>
</div>
</div>
</div>
<!-- ================== SCRIPTS ================== -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('storeAi', () => ({
/* state */
sideOpen: false,
openCmdK: false, openAdd: false, openSettings: false, openSupport: false,
openAddModel: false, openAddStore: false, openAddIntegration: false, openProductModal: false, openBulkImport: false,
editingProduct: false,
products: [
{ id: 1, name: 'Premium T-Shirt', sku: 'TSH-001', price: 29.99, stock: 42 },
{ id: 2, name: 'Wireless Earbuds', sku: 'AUD-001', price: 89.99, stock: 15 },
{ id: 3, name: 'Leather Wallet', sku: 'ACC-001', price: 49.99, stock: 8 }
],
form: {
id: null,
name: '',
sku: '',
price: 0,
stock: 0
},
csvPreview: [],
currentLang: localStorage.getItem('lang') || 'en',
theme: localStorage.getItem('theme') || 'dark',
accent: localStorage.getItem('accent') || '#38bdf8',
discount: 10, budget: 500, currentDiscount: 15, currentBudget: 750,
activeSection: 'kpi',
apiKey: '', apiSecret: '', emailUser: '', emailPass: '', emailPort: '', emailSecurity: 'tls',
selectedPlugin: null, selectedKpi: null,
filter: 'all', modelFilter: 'all', storeFilter: 'all', timeRange: 'today',
chartTimeRange: '7d', distributionFilter: 'requests',
integrationSearch: '',
notificationsOpen: false, profileOpen: false,
isRefreshing: false,
user: {
name: 'AI Admin',
email: 'admin@storeai.com',
plan: 'Pro',
usage: 65
},
settings: JSON.parse(localStorage.getItem('settings')) || {
emailNotifications: true,
pushNotifications: true
},
support: {
subject: '',
message: ''
},
newModel: {
name: '',
provider: 'OpenAI',
size: ''
},
newStore: {
name: '',
platform: 'Shopify',
url: '',
apiKey: ''
},
savedScenarios: JSON.parse(localStorage.getItem('scenarios')) || [],
notifications: [
{ message: 'New update available for Store AI', time: '2 min ago', read: false },
{ message: 'Your store FashionHub needs attention', time: '1 hour ago', read: false },
{ message: 'New model Llama-3 has been released', time: '3 hours ago', read: true },
{ message: 'Your subscription will renew in 7 days', time: '1 day ago', read: true }
],
commands: [
{ label: 'Refresh Data', description: 'Reload all dashboard data', icon: 'fas fa-sync-alt', shortcut: 'F5', action: 'refreshData' },
{ label: 'Open Settings', description: 'Open application settings', icon: 'fas fa-cog', shortcut: '⌘S', action: 'openSettings' },
{ label: 'Add Integration', description: 'Add a new integration', icon: 'fas fa-plus', shortcut: '⌘N', action: 'openAdd' },
{ label: 'View Dashboard', description: 'Go to dashboard overview', icon: 'fas fa-tachometer-alt', shortcut: '⌘1', action: 'scrollToSection', param: 'kpi' },
{ label: 'View Models', description: 'Go to AI models section', icon: 'fas fa-brain', shortcut: '⌘2', action: 'scrollToSection', param: 'models' },
{ label: 'View Stores', description: 'Go to stores section', icon: 'fas fa-store', shortcut: '⌘3', action: 'scrollToSection', param: 'stores' },
{ label: 'View Integrations', description: 'Go to integrations section', icon: 'fas fa-bullhorn', shortcut: '⌘4', action: 'scrollToSection', param: 'ads' }
],
filteredCommands: [],
kpis: [
{ label: 'Revenue', value: '$1,247', icon: 'fas fa-dollar-sign', trend: 5.2, loading: false,
avgDaily: '$415', peakTime: '2-4 PM' },
{ label: 'Orders', value: 28, icon: 'fas fa-shopping-cart', trend: -2.1, loading: false,
avgDaily: '9', peakTime: '12-2 PM' },
{ label: 'Conversion', value: '12.2%', icon: 'fas fa-chart-line', trend: 1.8, loading: false,
avgDaily: '10.5%', peakTime: '6-8 PM' },
{ label: 'Health', value: '97%', icon: 'fas fa-heartbeat', trend: 0.5, loading: false,
avgDaily: '96%', peakTime: 'All day' }
],
models: [
{ name: 'GPT-3.5', provider: 'OpenAI', size: '800 MB', icon: 'fas fa-robot', active: true, usage: 75 },
{ name: 'Llama-2', provider: 'Meta', size: '3.9 GB', icon: 'fab fa-meta', active: true, usage: 45 },
{ name: 'Claude', provider: 'Anthropic', size: '1.2 GB', icon: 'fas fa-user-astronaut', active: false, usage: 15 },
{ name: 'PaLM-2', provider: 'Google', size: '2.1 GB', icon: 'fab fa-google', active: true, usage: 30 }
],
stores: [
{ name: 'FashionHub', platform: 'Shopify', health: 94, trend: 2, lastSync: new Date(Date.now() - 3600000), icon: 'fas fa-tshirt' },
{ name: 'GadgetStore', platform: 'WooCommerce', health: 87, trend: -1, lastSync: new Date(Date.now() - 7200000), icon: 'fas fa-mobile-screen' },
{ name: 'BookNook', platform: 'Shopify', health: 72, trend: -5, lastSync: new Date(Date.now() - 86400000), icon: 'fas fa-book' },
{ name: 'HomeEssentials', platform: 'BigCommerce', health: 95, trend: 3, lastSync: new Date(Date.now() - 1800000), icon: 'fas fa-home' }
],
costs: {
current: 1245,
last: 1080,
change: 15.3,
forecast: 1450
},
navItems: [
{ id: 'kpi', label: 'Dashboard', icon: 'fas fa-tachometer-alt', badge: '3' },
{ id: 'sim', label: 'What-If', icon: 'fas fa-sliders-h' },
{ id: 'models', label: 'Models', icon: 'fas fa-brain' },
{ id: 'stores', label: 'Stores', icon: 'fas fa-store' },
{ id: 'products', label: 'Products', icon: 'fas fa-box' },
{ id: 'ai', label: 'AI', icon: 'fas fa-chart-bar' },
{ id: 'ads', label: 'Integrations', icon: 'fas fa-bullhorn', badge: '2' }
],
plugins: [],
allAvailablePlugins: [
{
id: 'woocommerce',
name: 'WooCommerce',
icon: 'fab fa-wordpress',
type: 'e-commerce',
connected: false,
description: 'Connect your WooCommerce store'
},
{
id: 'shopify',
name: 'Shopify',
icon: 'fab fa-shopify',
type: 'e-commerce',
connected: true,
description: 'Connect your Shopify store'
},
{
id: 'meta',
name: 'Meta Ads',
icon
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=fsalmansour/st" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>+p.price"></td>
<td class="p-3">
<span class="px-2 py-1 rounded-full text-xs"
:class="p.stock<10 ? 'bg-red-600' : 'bg-emerald-600'"
x-text="p.stock"></span>
</td>
<td class="p-3">
<button class="text-accent hover:underline"
@click="editProduct(p)">Edit</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</section>
<!-- CHARTS DECK -->
<section id="ai" class="scroll-mt-20">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-bold">AI Usage</h2>
<div class="relative">
<select x-model="chartTimeRange" class="glass text-sm px-3 py-1 rounded appearance-none pr-7">
<option value="7d" x-text="t.last7Days"></option>
<option value="30d" x-text="t.last30Days"></option>
<option value="90d" x-text="t.last90Days"></option>
</select>
<i class="fas fa-chevron-down absolute right-2 top-1/2 transform -translate-y-1/2 text-xs pointer-events-none"></i>
</div>
</div>
<div class="grid md:grid-cols-2 gap-6">
<div class="glass rounded-xl p-4">
<div class="flex items-center justify-between mb-4">
<h3 class="font-medium" x-text="t.apiUsage"></h3>
<div class="flex items-center space-x-2">
<div class="flex items-center">
<div class="w-2 h-2 rounded-full bg-accent mr-1"></div>
<span class="text-xs" x-text="t.thisMonth"></span>
</div>
<div class="flex items-center">
<div class="w-2 h-2 rounded-full bg-slate-500 mr-1"></div>
<span class="text-xs" x-text="t.lastMonth"></span>
</div>
</div>
</div>
<canvas id="apiChart" height="250"></canvas>
</div>
<div class="glass rounded-xl p-4">
<div class="flex items-center justify-between mb-4">
<h3 class="font-medium" x-text="t.providerDistribution"></h3>
<div class="relative">
<select x-model="distributionFilter" class="glass text-xs px-2 py-1 rounded appearance-none pr-6">
<option value="requests" x-text="t.requests"></option>
<option value="cost" x-text="t.cost"></option>
<option value="tokens" x-text="t.tokens"></option>
</select>
<i class="fas fa-chevron-down absolute right-1 top-1/2 transform -translate-y-1/2 text-xs pointer-events-none"></i>
</div>
</div>
<canvas id="providerChart" height="250"></canvas>
</div>
</div>
<!-- Cost Summary -->
<div class="glass rounded-xl p-4 mt-6">
<h3 class="font-medium mb-4" x-text="t.costSummary"></h3>
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<div class="bg-slate-800/50 rounded-lg p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.thisMonth"></p>
<p class="text-xl font-bold" x-text="'$' + costs.current"></p>
</div>
<div class="bg-slate-800/50 rounded-lg p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.lastMonth"></p>
<p class="text-xl font-bold" x-text="'$' + costs.last"></p>
</div>
<div class="bg-slate-800/50 rounded-lg p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.change"></p>
<p class="text-xl font-bold" :class="costs.change > 0 ? 'text-emerald-400' : 'text-red-400'"
x-text="(costs.change > 0 ? '+' : '') + costs.change + '%'"></p>
</div>
<div class="bg-slate-800/50 rounded-lg p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.forecast"></p>
<p class="text-xl font-bold" x-text="'$' + costs.forecast"></p>
</div>
</div>
</div>
</section>
<!-- ADS INTEGRATIONS -->
<section id="ads" class="scroll-mt-20">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-bold" x-text="t.ads"></h2>
<button @click="openAddIntegration = true" class="text-sm glass px-3 py-1 rounded hover:bg-slate-700 flex items-center space-x-1">
<i class="fas fa-plus text-xs"></i>
<span x-text="t.addIntegration"></span>
</button>
</div>
<!-- Filter Buttons -->
<div class="flex flex-wrap gap-2 mb-4">
<template x-for="f in ['All','Ads','Stores','Email','Automation']" :key="f">
<button @click="filter=f.toLowerCase()"
class="px-3 py-1 rounded-md text-sm transition"
:class="filter===f.toLowerCase()?'bg-accent text-white':'glass hover:bg-slate-700'"
x-text="f"></button>
</template>
</div>
<!-- Plugins Grid -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
<template x-for="p in filteredPlugins" :key="p.id">
<div class="glass rounded-xl p-4 hover:bg-slate-700/50 transition cursor-pointer" @click="openConnectModal(p)">
<div class="flex items-start justify-between mb-3">
<div class="w-10 h-10 rounded-lg bg-accent/10 flex items-center justify-center">
<i :class="p.icon + ' text-accent text-lg'"></i>
</div>
<span class="text-xs px-2 py-1 rounded-full"
:class="p.connected ? 'bg-emerald-600/20 text-emerald-400' : 'bg-slate-700/50 text-slate-400'"
x-text="p.connected ? 'Connected' : 'Disconnected'"></span>
</div>
<p class="font-semibold mb-1" x-text="p.name"></p>
<p class="text-xs text-slate-400 mb-3" x-text="p.description"></p>
<div class="w-full bg-slate-700 rounded-full h-1.5 mb-1">
<div class="bg-accent h-1.5 rounded-full" :style="'width: ' + (p.connected ? '100' : '0') + '%'"></div>
</div>
<div class="flex justify-between text-xs text-slate-400">
<span x-text="p.connected ? 'Connected' : 'Not connected'"></span>
<span x-text="p.type === 'ads' ? 'Ads' : p.type === 'e-commerce' ? 'E-commerce' : p.type === 'email' ? 'Email' : 'Automation'"></span>
</div>
</div>
</template>
</div>
</section>
</main>
<!-- ================== FLOATING ACTION CLUSTER ================== -->
<div class="fixed bottom-6 right-6 flex flex-col items-end space-y-3">
<button @click="openSettings=true" aria-label="Open settings"
class="glass p-3 rounded-full shadow-lg fab-shadow transition hover:scale-110 tooltip"
:title="t.settings">
<i class="fas fa-cog"></i>
<span class="tooltip-text" x-text="t.settings"></span>
</button>
<button @click="openAdd=true" aria-label="Add new integration"
class="glass p-4 rounded-full shadow-lg fab-shadow transition hover:scale-110 neon">
<i class="fas fa-plus"></i>
</button>
</div>
<!-- ================== MODALS ================== -->
<!-- Command Palette -->
<div x-show="openCmdK" @click.away="openCmdK=false"
class="fixed inset-0 bg-black/50 z-50 flex items-start justify-center pt-20">
<div class="glass w-full max-w-lg rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex items-center">
<i class="fas fa-search text-sm mr-2 text-slate-400"></i>
<input type="search" placeholder="Type to search..."
class="w-full bg-transparent outline-none placeholder-slate-400"
x-ref="cmdInput"
@keydown.escape="openCmdK=false"
@keyup="filterCommands($event.target.value)">
</div>
<div class="max-h-96 overflow-y-auto">
<template x-for="cmd in filteredCommands" :key="cmd.label">
<button @click="executeCommand(cmd)"
class="w-full text-left p-3 hover:bg-slate-700 flex items-center space-x-3">
<i :class="cmd.icon + ' text-sm w-5 text-center text-slate-400'"></i>
<div>
<p x-text="cmd.label"></p>
<p class="text-xs text-slate-400" x-text="cmd.description"></p>
</div>
<kbd class="ml-auto text-xs px-2 py-1 bg-slate-700 rounded" x-text="cmd.shortcut"></kbd>
</button>
</template>
<div x-show="filteredCommands.length === 0" class="p-4 text-center text-sm text-slate-400">
<p x-text="t.noCommands"></p>
</div>
</div>
</div>
</div>
<!-- Add Modal -->
<div x-show="openAdd" @click.away="openAdd=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="t.addNew"></h3>
<button @click="openAdd=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 max-h-96 overflow-y-auto">
<div class="relative mb-4">
<i class="fas fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-sm text-slate-400"></i>
<input type="search" placeholder="Search integrations..."
class="w-full glass pl-9 pr-3 py-2 rounded outline-none"
x-model="integrationSearch">
</div>
<div class="space-y-2">
<template x-for="plugin in filteredAvailablePlugins" :key="plugin.id">
<button @click="addPlugin(plugin)"
class="w-full glass p-3 rounded text-left flex items-center space-x-3 hover:bg-slate-700">
<i :class="plugin.icon + ' text-accent'"></i>
<div>
<p x-text="plugin.name"></p>
<p class="text-xs text-slate-400" x-text="plugin.description"></p>
</div>
</button>
</template>
<div x-show="filteredAvailablePlugins.length === 0" class="p-4 text-center text-sm text-slate-400">
<p x-text="t.noIntegrations"></p>
</div>
</div>
</div>
</div>
</div>
<!-- Settings Modal -->
<div x-show="openSettings" @click.away="openSettings=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold">Settings</h3>
<button @click="openSettings=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 max-h-96 overflow-y-auto space-y-4">
<div>
<label class="block text-sm mb-2">Accent Color</label>
<input type="color" x-model="accent" @change="updateAccentColor" class="w-full h-10 rounded">
</div>
<div>
<label class="block text-sm mb-2">Theme</label>
<div class="flex space-x-2">
<button @click="theme='dark'" :class="theme==='dark'?'bg-accent text-white':'glass'" class="px-3 py-1.5 rounded text-sm">
Dark
</button>
<button @click="theme=''" :class="theme===''?'bg-accent text-white':'glass'" class="px-3 py-1.5 rounded text-sm">
Light
</button>
</div>
</div>
<div>
<label class="block text-sm mb-2">Language</label>
<div class="flex space-x-2">
<button @click="currentLang='en'" :class="currentLang==='en'?'bg-accent text-white':'glass'" class="px-3 py-1.5 rounded text-sm">
English
</button>
<button @click="currentLang='ar'" :class="currentLang==='ar'?'bg-accent text-white':'glass'" class="px-3 py-1.5 rounded text-sm">
العربية
</button>
</div>
</div>
<div>
<label class="block text-sm mb-2">Notifications</label>
<div class="space-y-2">
<label class="flex items-center space-x-2">
<input type="checkbox" x-model="settings.emailNotifications" class="rounded accent-accent">
<span class="text-sm" x-text="t.emailNotifications"></span>
</label>
<label class="flex items-center space-x-2">
<input type="checkbox" x-model="settings.pushNotifications" class="rounded accent-accent">
<span class="text-sm" x-text="t.pushNotifications"></span>
</label>
</div>
</div>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end">
<button @click="saveSettings()" class="px-4 py-2 bg-accent rounded text-white hover:bg-accent/90" x-text="t.save"></button>
</div>
</div>
</div>
<!-- Support Modal -->
<div x-show="openSupport" @click.away="openSupport=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="t.contactSupport"></h3>
<button @click="openSupport=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 space-y-4">
<div>
<label class="block text-sm mb-1" x-text="t.subject"></label>
<input type="text" x-model="support.subject" class="w-full glass px-3 py-2 rounded">
</div>
<div>
<label class="block text-sm mb-1" x-text="t.message"></label>
<textarea x-model="support.message" rows="5" class="w-full glass px-3 py-2 rounded"></textarea>
</div>
<div>
<label class="block text-sm mb-1" x-text="t.attachment"></label>
<div class="glass rounded p-3 text-center border-2 border-dashed border-slate-700 cursor-pointer hover:bg-slate-700/50">
<i class="fas fa-cloud-upload-alt text-2xl text-slate-400 mb-2"></i>
<p class="text-sm" x-text="t.uploadFile"></p>
<p class="text-xs text-slate-400" x-text="t.maxSize"></p>
</div>
</div>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end space-x-2">
<button @click="openSupport=false" class="px-4 py-2 glass rounded hover:bg-slate-700" x-text="t.cancel"></button>
<button @click="sendSupportRequest()" class="px-4 py-2 bg-accent rounded text-white hover:bg-accent/90" x-text="t.send"></button>
</div>
</div>
</div>
<!-- Add Model Modal -->
<div x-show="openAddModel" @click.away="openAddModel=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="t.addModel"></h3>
<button @click="openAddModel=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 space-y-4">
<div>
<label class="block text-sm mb-1" x-text="t.modelName"></label>
<input type="text" x-model="newModel.name" class="w-full glass px-3 py-2 rounded">
</div>
<div>
<label class="block text-sm mb-1" x-text="t.provider"></label>
<select x-model="newModel.provider" class="w-full glass px-3 py-2 rounded">
<option value="OpenAI">OpenAI</option>
<option value="Meta">Meta</option>
<option value="Google">Google</option>
<option value="Anthropic">Anthropic</option>
</select>
</div>
<div>
<label class="block text-sm mb-1" x-text="t.size"></label>
<input type="text" x-model="newModel.size" class="w-full glass px-3 py-2 rounded">
</div>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end space-x-2">
<button @click="openAddModel=false" class="px-4 py-2 glass rounded hover:bg-slate-700" x-text="t.cancel"></button>
<button @click="addNewModel()" class="px-4 py-2 bg-accent rounded text-white hover:bg-accent/90" x-text="t.add"></button>
</div>
</div>
</div>
<!-- Bulk Import Modal -->
<div x-show="openBulkImport" @click.away="openBulkImport=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="t.bulkImport"></h3>
<button @click="openBulkImport=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 space-y-4">
<div class="border-2 border-dashed border-slate-700 rounded-lg p-6 text-center cursor-pointer hover:bg-slate-700/20"
@click="$refs.csvInput.click()">
<i class="fas fa-file-csv text-3xl text-accent mb-2"></i>
<p class="text-sm" x-text="t.uploadCsv"></p>
<p class="text-xs text-slate-400" x-text="t.csvFormat"></p>
<input type="file" x-ref="csvInput" accept=".csv" class="hidden" @change="handleCsvUpload">
</div>
<div x-show="csvPreview.length > 0" class="glass rounded-lg p-3 max-h-64 overflow-y-auto">
<table class="w-full text-xs">
<thead>
<tr class="border-b border-slate-700">
<th class="p-1 text-left" x-text="t.sku"></th>
<th class="p-1 text-left" x-text="t.name"></th>
<th class="p-1 text-left" x-text="t.stock"></th>
</tr>
</thead>
<tbody>
<template x-for="(row, i) in csvPreview" :key="i">
<tr class="border-b border-slate-700">
<td class="p-1" x-text="row.sku"></td>
<td class="p-1" x-text="row.name"></td>
<td class="p-1" x-text="row.stock"></td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end space-x-2">
<button @click="openBulkImport=false" class="px-4 py-2 glass rounded hover:bg-slate-700" x-text="t.cancel"></button>
<button @click="importProducts()"
class="px-4 py-2 bg-accent rounded text-white hover:bg-accent/90"
:disabled="csvPreview.length === 0"
x-text="t.import"></button>
</div>
</div>
</div>
<!-- Add Store Modal -->
<div x-show="openAddStore" @click.away="openAddStore=false"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="t.addStore"></h3>
<button @click="openAddStore=false" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 space-y-4">
<div>
<label class="block text-sm mb-1" x-text="t.storeName"></label>
<input type="text" x-model="newStore.name" class="w-full glass px-3 py-2 rounded">
</div>
<div>
<label class="block text-sm mb-1" x-text="t.platform"></label>
<select x-model="newStore.platform" class="w-full glass px-3 py-2 rounded">
<option value="Shopify">Shopify</option>
<option value="WooCommerce">WooCommerce</option>
<option value="BigCommerce">BigCommerce</option>
<option value="Magento">Magento</option>
</select>
</div>
<div>
<label class="block text-sm mb-1" x-text="t.storeUrl"></label>
<input type="url" x-model="newStore.url" class="w-full glass px-3 py-2 rounded" placeholder="https://">
</div>
<div>
<label class="block text-sm mb-1" x-text="t.apiKey"></label>
<input type="password" x-model="newStore.apiKey" class="w-full glass px-3 py-2 rounded">
</div>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end space-x-2">
<button @click="openAddStore=false" class="px-4 py-2 glass rounded hover:bg-slate-700" x-text="t.cancel"></button>
<button @click="addNewStore()" class="px-4 py-2 bg-accent rounded text-white hover:bg-accent/90" x-text="t.add"></button>
</div>
</div>
</div>
<!-- Connect Modal -->
<div x-show="selectedPlugin" @click.away="selectedPlugin=null"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="'Connect '+selectedPlugin?.name"></h3>
<button @click="selectedPlugin=null" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4 space-y-4">
<!-- Ads -->
<template x-if="selectedPlugin?.type==='ads'">
<div>
<label class="text-sm mb-1 block" x-text="t.adAccountId"></label>
<input x-model="apiKey"
placeholder="Ad Account ID"
class="w-full glass px-3 py-2 rounded mb-3">
</div>
</template>
<!-- E-commerce -->
<template x-if="selectedPlugin?.type==='e-commerce'">
<div>
<label class="text-sm mb-1 block" x-text="t.storeUrl"></label>
<input x-model="apiKey"
placeholder="https://store.com"
class="w-full glass px-3 py-2 rounded mb-3">
<label class="text-sm mb-1 block" x-text="t.apiKey"></label>
<input x-model="apiSecret"
type="password"
placeholder="API Key"
class="w-full glass px-3 py-2 rounded">
</div>
</template>
<!-- Email -->
<template x-if="selectedPlugin?.type==='email'">
<div class="space-y-3">
<div>
<label class="text-sm mb-1 block" x-text="t.smtpHost"></label>
<input x-model="apiKey"
placeholder="smtp.example.com"
class="w-full glass px-3 py-2 rounded">
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="text-sm mb-1 block" x-text="t.username"></label>
<input x-model="emailUser"
placeholder="Username"
class="w-full glass px-3 py-2 rounded">
</div>
<div>
<label class="text-sm mb-1 block" x-text="t.password"></label>
<input x-model="emailPass"
type="password"
placeholder="Password"
class="w-full glass px-3 py-2 rounded">
</div>
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="text-sm mb-1 block" x-text="t.port"></label>
<input x-model="emailPort"
type="number"
placeholder="587"
class="w-full glass px-3 py-2 rounded">
</div>
<div>
<label class="text-sm mb-1 block" x-text="t.security"></label>
<select x-model="emailSecurity" class="w-full glass px-3 py-2 rounded">
<option value="tls">TLS</option>
<option value="ssl">SSL</option>
<option value="none">None</option>
</select>
</div>
</div>
</div>
</template>
<!-- Automation -->
<template x-if="selectedPlugin?.type==='automation'">
<div>
<label class="text-sm mb-1 block" x-text="t.webhookUrl"></label>
<input x-model="apiKey"
placeholder="https://n8n.hook.com"
class="w-full glass px-3 py-2 rounded mb-3">
<label class="text-sm mb-1 block" x-text="t.secretKey"></label>
<input x-model="apiSecret"
type="password"
placeholder="Secret Key"
class="w-full glass px-3 py-2 rounded">
</div>
</template>
</div>
<div class="p-4 border-t border-slate-700 flex justify-end space-x-2">
<button @click="selectedPlugin=null" class="px-4 py-2 glass rounded hover:bg-slate-700" x-text="t.cancel"></button>
<button @click="connectPlugin(selectedPlugin)"
class="px-4 py-2 rounded text-white flex items-center space-x-2"
:class="selectedPlugin?.connected ? 'bg-red-500 hover:bg-red-600' : 'bg-accent hover:bg-accent/90'"
x-text="selectedPlugin?.connected ? t.disconnect : t.connect">
</button>
</div>
</div>
</div>
<!-- KPI Details Modal -->
<div x-show="selectedKpi" @click.away="selectedKpi=null"
class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
<div class="glass w-full max-w-md rounded-xl overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<h3 class="text-lg font-bold" x-text="selectedKpi?.label"></h3>
<button @click="selectedKpi=null" class="p-1 rounded-full hover:bg-slate-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4">
<div class="flex items-center justify-between mb-4">
<div>
<p class="text-2xl font-bold" x-text="selectedKpi?.value"></p>
<p class="text-sm" :class="selectedKpi?.trend > 0 ? 'text-emerald-400' : 'text-red-400'">
<i :class="selectedKpi?.trend > 0 ? 'fas fa-caret-up' : 'fas fa-caret-down'"></i>
<span x-text="Math.abs(selectedKpi?.trend) + '%'"></span>
<span class="text-slate-400 ml-1" x-text="'vs ' + (timeRange === 'today' ? t.yesterday : timeRange === 'week' ? t.lastWeek : t.lastMonth)"></span>
</p>
</div>
<div class="w-16 h-16">
<canvas x-ref="kpiChart"></canvas>
</div>
</div>
<div class="h-48 mb-4">
<canvas x-ref="kpiDetailChart"></canvas>
</div>
<div class="grid grid-cols-2 gap-4">
<div class="glass rounded p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.avgDaily"></p>
<p class="font-medium" x-text="selectedKpi?.avgDaily"></p>
</div>
<div class="glass rounded p-3">
<p class="text-sm text-slate-400 mb-1" x-text="t.peakTime"></p>
<p class="font-medium" x-text="selectedKpi?.peakTime"></p>
</div>
</div>
</div>
</div>
</div>
<!-- ================== SCRIPTS ================== -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('storeAi', () => ({
/* state */
sideOpen: false,
openCmdK: false, openAdd: false, openSettings: false, openSupport: false,
openAddModel: false, openAddStore: false, openAddIntegration: false, openAddProduct: false, openBulkImport: false,
csvPreview: [],
currentLang: localStorage.getItem('lang') || 'en',
theme: localStorage.getItem('theme') || 'dark',
accent: localStorage.getItem('accent') || '#38bdf8',
discount: 10, budget: 500, currentDiscount: 15, currentBudget: 750,
activeSection: 'kpi',
apiKey: '', apiSecret: '', emailUser: '', emailPass: '', emailPort: '', emailSecurity: 'tls',
selectedPlugin: null, selectedKpi: null,
filter: 'all', modelFilter: 'all', storeFilter: 'all', timeRange: 'today',
chartTimeRange: '7d', distributionFilter: 'requests',
integrationSearch: '',
notificationsOpen: false, profileOpen: false,
isRefreshing: false,
user: {
name: 'AI Admin',
email: 'admin@storeai.com',
plan: 'Pro',
usage: 65
},
settings: JSON.parse(localStorage.getItem('settings')) || {
emailNotifications: true,
pushNotifications: true
},
support: {
subject: '',
message: ''
},
newModel: {
name: '',
provider: 'OpenAI',
size: ''
},
newStore: {
name: '',
platform: 'Shopify',
url: '',
apiKey: ''
},
savedScenarios: JSON.parse(localStorage.getItem('scenarios')) || [],
notifications: [
{ message: 'New update available for Store AI', time: '2 min ago', read: false },
{ message: 'Your store FashionHub needs attention', time: '1 hour ago', read: false },
{ message: 'New model Llama-3 has been released', time: '3 hours ago', read: true },
{ message: 'Your subscription will renew in 7 days', time: '1 day ago', read: true }
],
commands: [
{ label: 'Refresh Data', description: 'Reload all dashboard data', icon: 'fas fa-sync-alt', shortcut: 'F5', action: 'refreshData' },
{ label: 'Open Settings', description: 'Open application settings', icon: 'fas fa-cog', shortcut: '⌘S', action: 'openSettings' },
{ label: 'Add Integration', description: 'Add a new integration', icon: 'fas fa-plus', shortcut: '⌘N', action: 'openAdd' },
{ label: 'View Dashboard', description: 'Go to dashboard overview', icon: 'fas fa-tachometer-alt', shortcut: '⌘1', action: 'scrollToSection', param: 'kpi' },
{ label: 'View Models', description: 'Go to AI models section', icon: 'fas fa-brain', shortcut: '⌘2', action: 'scrollToSection', param: 'models' },
{ label: 'View Stores', description: 'Go to stores section', icon: 'fas fa-store', shortcut: '⌘3', action: 'scrollToSection', param: 'stores' },
{ label: 'View Integrations', description: 'Go to integrations section', icon: 'fas fa-bullhorn', shortcut: '⌘4', action: 'scrollToSection', param: 'ads' }
],
filteredCommands: [],
kpis: [
{ label: 'Revenue', value: '$1,247', icon: 'fas fa-dollar-sign', trend: 5.2, loading: false,
avgDaily: '$415', peakTime: '2-4 PM' },
{ label: 'Orders', value: 28, icon: 'fas fa-shopping-cart', trend: -2.1, loading: false,
avgDaily: '9', peakTime: '12-2 PM' },
{ label: 'Conversion', value: '12.2%', icon: 'fas fa-chart-line', trend: 1.8, loading: false,
avgDaily: '10.5%', peakTime: '6-8 PM' },
{ label: 'Health', value: '97%', icon: 'fas fa-heartbeat', trend: 0.5, loading: false,
avgDaily: '96%', peakTime: 'All day' }
],
models: [
{ name: 'GPT-3.5', provider: 'OpenAI', size: '800 MB', icon: 'fas fa-robot', active: true, usage: 75 },
{ name: 'Llama-2', provider: 'Meta', size: '3.9 GB', icon: 'fab fa-meta', active: true, usage: 45 },
{ name: 'Claude', provider: 'Anthropic', size: '1.2 GB', icon: 'fas fa-user-astronaut', active: false, usage: 15 },
{ name: 'PaLM-2', provider: 'Google', size: '2.1 GB', icon: 'fab fa-google', active: true, usage: 30 }
],
stores: [
{ name: 'FashionHub', platform: 'Shopify', health: 94, trend: 2, lastSync: new Date(Date.now() - 3600000), icon: 'fas fa-tshirt' },
{ name: 'GadgetStore', platform: 'WooCommerce', health: 87, trend: -1, lastSync: new Date(Date.now() - 7200000), icon: 'fas fa-mobile-screen' },
{ name: 'BookNook', platform: 'Shopify', health: 72, trend: -5, lastSync: new Date(Date.now() - 86400000), icon: 'fas fa-book' },
{ name: 'HomeEssentials', platform: 'BigCommerce', health: 95, trend: 3, lastSync: new Date(Date.now() - 1800000), icon: 'fas fa-home' }
],
costs: {
current: 1245,
last: 1080,
change: 15.3,
forecast: 1450
},
navItems: [
{ id: 'kpi', label: 'Dashboard', icon: 'fas fa-tachometer-alt', badge: '3' },
{ id: 'sim', label: 'What-If', icon: 'fas fa-sliders-h' },
{ id: 'models', label: 'Models', icon: 'fas fa-brain' },
{ id: 'stores', label: 'Stores', icon: 'fas fa-store' },
{ id: 'products', label: 'Products', icon: 'fas fa-box' },
{ id: 'ai', label: 'AI', icon: 'fas fa-chart-bar' },
{ id: 'ads', label: 'Integrations', icon: 'fas fa-bullhorn', badge: '2' }
],
plugins: [],
allAvailablePlugins: [
{
id: 'woocommerce',
name: 'WooCommerce',
icon: 'fab fa-wordpress',
type: 'e-commerce',
connected: false,
description: 'Connect your WooCommerce store'
},
{
id: 'shopify',
name: 'Shopify',
icon: 'fab fa-shopify',
type: 'e-commerce',
connected: true,
description: 'Connect your Shopify store'
},
{
id: 'meta',
name: 'Meta Ads',
icon
</body>
</html>