newtest / src /App.tsx
Eissa's picture
Upload 4 files
74b9b7d verified
Raw
History Blame Contribute Delete
16.1 kB
import { useState, useEffect } from "react";
import { initIndexedDB, DBService } from "./lib/db";
import { AuditLogItem } from "./types";
import ClonerTab from "./components/ClonerTab";
import MonitorTab from "./components/MonitorTab";
import KeysTab from "./components/KeysTab";
import EmailsTab from "./components/EmailsTab";
import SitesTab from "./components/SitesTab";
import AccountsTab from "./components/AccountsTab";
import StudioTab from "./components/StudioTab";
import WorkflowsTab from "./components/WorkflowsTab";
import DeployTab from "./components/DeployTab";
import AiAssistant from "./components/AiAssistant";
import BrowserViewport from "./components/BrowserViewport";
import {
Globe, Activity, Key, Mail, Compass, Shield, User,
Settings, Network, Zap, Volume2, VolumeX, Menu, X,
Bell, CheckCircle, Info, Terminal, RefreshCw, LayoutGrid
} from "lucide-react";
export default function App() {
const [activeTab, setActiveTab] = useState<string>("studio");
const [hapticEnabled, setHapticEnabled] = useState(true);
const [dbReady, setDbReady] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
// Custom toast notification system
const [toastMessage, setToastMessage] = useState<string | null>(null);
const [toastType, setToastType] = useState<"success" | "warn" | "info">("success");
// Dynamic status bar metrics
const [metricApis, setMetricApis] = useState("8/10 APIs");
const [metricWorkflows, setMetricWorkflows] = useState("3 workflows");
const [metricPingState, setMetricPingState] = useState("ู…ุชุตู„");
const [batteryLevel, setBatteryLevel] = useState("85%");
useEffect(() => {
// 1. Initialize IndexedDB local storage with fail-proof fallback
initIndexedDB()
.then(() => {
setDbReady(true);
showToast("โœ“ ุชู… ุชู‡ูŠุฆุฉ ู‚ุงุนุฏุฉ ุจูŠุงู†ุงุช IndexedDB ูˆุชูุนูŠู„ ูˆุถุน ุงู„ุฃูˆูู„ุงูŠู† ุจู†ุฌุงุญ", "success");
// Log setup successful in auditTrail
DBService.put("auditLog", {
id: "log_init_" + Date.now(),
timestamp: Date.now(),
action: "ุชู‡ูŠุฆุฉ ุงู„ู†ุธุงู…",
details: "SiteClone Pro v20.0.0 ุชู…ุช ุงู„ุชู‡ูŠุฆุฉ ุจู†ุฌุงุญ",
status: "success"
});
})
.catch((e) => {
console.warn("IndexedDB fallback activated:", e);
// Still set dbReady to true so the user can see the pages in sandboxed previews!
setDbReady(true);
showToast("โœ“ ุชู… ุชูุนูŠู„ ุงู„ุชุฎุฒูŠู† ุงู„ุณุญุงุจูŠ/ุงู„ู…ุญู„ูŠ ุจุงู„ูƒุงู…ู„ ุฏุงุฎู„ ุจูŠุฆุฉ ุงู„ู…ุนุงูŠู†ุฉ", "success");
});
// 2. Query dynamic system counts
updateStatusBarMetrics();
const intervalId = setInterval(() => {
updateStatusBarMetrics();
}, 10000);
return () => clearInterval(intervalId);
}, []);
const updateStatusBarMetrics = async () => {
try {
const keys = await DBService.getAll("keys");
const workflows = await DBService.getAll("workflows");
setMetricApis(`${keys.filter((k: any) => k.status === "active").length}/${keys.length} APIs`);
setMetricWorkflows(`${workflows.filter((w: any) => w.status === "active").length} workflows`);
} catch {
// Keep defaults during initial upgrades
}
};
const showToast = (msg: string, type: "success" | "warn" | "info") => {
setToastMessage(msg);
setToastType(type);
// Clear toast after 4s
const timer = setTimeout(() => {
setToastMessage(null);
}, 4000);
};
const triggerHaptic = () => {
if (!hapticEnabled) return;
try {
if (navigator.vibrate) {
navigator.vibrate([40]);
}
} catch {
// Ignored if blocked inside sandbox environment
}
};
// 10 layout tabs keys mapping
const tabsList = [
{ id: "studio", label: "ุงู„ุชุทุจูŠู‚ุงุช 50+", icon: <LayoutGrid className="w-4 h-4" />, arabic: "๐Ÿ“ฑ ุงู„ุชุทุจูŠู‚ุงุช (50+)" },
{ id: "monitors", label: "ู…ุฑุงู‚ุจุฉ ุงู„ู€ Web", icon: <Activity className="w-4 h-4" />, arabic: "๐Ÿ“ก ู…ุฑุงู‚ุจุฉ" },
{ id: "keys", label: "ุฎุฒู†ุฉ ุงู„ู…ูุงุชูŠุญ", icon: <Key className="w-4 h-4" />, arabic: "๐Ÿ” ุงู„ู…ูุงุชูŠุญ" },
{ id: "browser", label: "ุงู„ู…ู†ุธุงุฑ ุงู„ุขู…ู†", icon: <Globe className="w-4 h-4" />, arabic: "๐Ÿ›ก๏ธ ุงู„ู…ู†ุธุงุฑ " },
{ id: "emails", label: "ุฅุฏุงุฑุฉ ุงู„ุฅูŠู…ูŠู„ุงุช", icon: <Mail className="w-4 h-4" />, arabic: "๐Ÿ“ง ุงู„ุฅูŠู…ูŠู„ุงุช" },
{ id: "sites", label: "ุจู†ุงุก ุงู„ู…ูˆุงู‚ุน", icon: <Compass className="w-4 h-4" />, arabic: "๐ŸŒ ุงู„ู…ูˆุงู‚ุน" },
{ id: "accounts", label: "ุชุณุฌูŠู„ ุงู„ุฏุฎูˆู„", icon: <User className="w-4 h-4" />, arabic: "๐Ÿ‘ค ุญุณุงุจุงุชูŠ" },
{ id: "workflows", label: "ุณูŠุฑ ุงู„ุฃุชู…ุชุฉ", icon: <Network className="w-4 h-4" />, arabic: "โš™๏ธ workflows" },
{ id: "deploy", label: "ุงู„ู†ุดุฑ ูˆุงู„ุญุฏูˆุฏ", icon: <Zap className="w-4 h-4" />, arabic: "๐Ÿš€ ู†ุดุฑ" },
{ id: "clones", label: "ุฃุฏุงุฉ ุงู„ุงุณุชู†ุณุงุฎ", icon: <Globe className="w-4 h-4" />, arabic: "๐Ÿ”„ ุงุณุชู†ุณุงุฎ" }
];
return (
<div className="min-h-screen mesh-bg text-slate-900 flex flex-col relative pb-10">
{/* 1. Header/Navigation Tab Container (Fixed height, 56px approximation) */}
<header className="sticky top-0 z-40 bg-white/45 border-b border-sky-500/15 backdrop-blur-xl flex items-center h-14 px-4 sm:px-6 justify-between select-none">
{/* App Title */}
<div className="flex items-center gap-2">
<div className="bg-sky-600 text-white p-1.5 rounded-lg font-black tracking-tighter text-sm flex items-center justify-center">
SC20
</div>
<span className="font-extrabold text-sm sm:text-base tracking-tight text-sky-800">
SiteClone Pro v20
</span>
</div>
{/* Navigation items for Desktop/Tablet */}
<nav className="hidden lg:flex items-center gap-1">
{tabsList.map((tab) => (
<button
key={tab.id}
onClick={() => {
triggerHaptic();
setActiveTab(tab.id);
}}
className={`px-3 py-1.5 rounded-xl text-xs font-semibold flex items-center gap-1.5 transition-all outline-none ${
activeTab === tab.id
? "bg-sky-500/20 text-sky-800 border border-sky-500/40 shadow-sm shadow-sky-500/10 font-bold"
: "text-slate-600 hover:text-sky-900 hover:bg-sky-550/10"
}`}
>
{tab.icon}
<span>{tab.arabic}</span>
</button>
))}
</nav>
{/* Compact Right Header Widget */}
<div className="flex items-center gap-2">
{/* Vibration switcher */}
<button
onClick={() => {
const newState = !hapticEnabled;
setHapticEnabled(newState);
if (newState && navigator.vibrate) {
try { navigator.vibrate([60]); } catch (e) {}
}
showToast(newState ? "๐Ÿ“ณ ุชู… ุชูุนูŠู„ ุงู‡ุชุฒุงุฒ ุงู„ู„ู…ุณ ุงู„ุชูุงุนู„ูŠ" : "๐Ÿ”‡ ุชู… ุฅูŠู‚ุงู ุงู„ุงู‡ุชุฒุงุฒ", "info");
}}
className={`px-3 py-1.5 rounded-xl border text-xs font-semibold flex items-center gap-1.5 transition-all outline-none cursor-pointer ${
hapticEnabled
? "bg-emerald-550/15 border border-emerald-500/30 text-emerald-800 shadow-sm shadow-emerald-500/5 font-bold"
: "bg-white border-sky-500/10 text-slate-500 hover:text-slate-800"
}`}
title="ุชุจุฏูŠูŠู„ ุงู‡ุชุฒุงุฒ ุงู„ู„ู…ุณ ุงู„ุชูุงุนู„ูŠ (Vibrations)"
>
<span className="relative flex h-2 w-2">
<span className={`animate-ping absolute inline-flex h-full w-full rounded-full opacity-75 ${hapticEnabled ? "bg-emerald-450" : "bg-slate-400"}`}></span>
<span className={`relative inline-flex rounded-full h-2 w-2 ${hapticEnabled ? "bg-emerald-500" : "bg-slate-400"}`}></span>
</span>
<span className="hidden sm:inline">ุงู„ุงู‡ุชุฒุงุฒ:</span>
<span>{hapticEnabled ? "ู…ูุนู‘ู„ ๐Ÿ“ณ" : "ู…ุนุทู‘ู„ ๐Ÿ”‡"}</span>
</button>
{/* Hamburger toggle trigger for Phone */}
<button
onClick={() => {
triggerHaptic();
setIsMobileMenuOpen(!isMobileMenuOpen);
}}
className="lg:hidden p-2 bg-white border border-sky-500/20 rounded-xl text-sky-800 hover:bg-sky-500/10 flex items-center justify-center cursor-pointer"
>
{isMobileMenuOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
</button>
</div>
</header>
{/* Horizontal Scrollable Tabs bar for Mobile & Tablets (Direct Access) */}
<div className="lg:hidden sticky top-14 z-30 bg-white/45 border-b border-sky-500/15 backdrop-blur-xl flex items-center overflow-x-auto gap-2 px-4 py-2.5 scroll-smooth select-none [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]">
{tabsList.map((tab) => (
<button
key={tab.id}
onClick={() => {
triggerHaptic();
setActiveTab(tab.id);
}}
className={`px-3 py-1.5 rounded-xl text-xs font-semibold flex items-center gap-1.5 transition-all outline-none whitespace-nowrap border shrink-0 ${
activeTab === tab.id
? "bg-sky-500/25 text-sky-800 border-sky-500/30 shadow-sm shadow-sky-500/10 font-bold"
: "bg-white/60 border-sky-500/10 text-slate-600 hover:text-sky-900"
}`}
>
{tab.icon}
<span>{tab.arabic}</span>
</button>
))}
</div>
{/* Mobile Drawer */}
{isMobileMenuOpen && (
<div className="lg:hidden fixed inset-0 top-14 bg-white/95 text-slate-900 z-30 flex flex-col p-6 space-y-3 animate-fade-in backdrop-blur-md overflow-y-auto">
{/* Quick Vibration Toggle on Mobile */}
<div className="bg-sky-550/10 border border-sky-500/20 rounded-2xl p-4 flex items-center justify-between shadow-md mb-2">
<div className="space-y-0.5 text-right font-sans">
<span className="text-xs font-bold text-slate-800 block">ุงู‡ุชุฒุงุฒ ุงู„ู„ู…ุณ ุงู„ุชูุงุนู„ูŠ (Vibrator Key)</span>
<span className="text-[10px] text-slate-500 block">ู†ุจุถ ุงู‡ุชุฒุงุฒ ุญู‚ูŠู‚ูŠ ูŠู†ุทู„ู‚ ุนู†ุฏ ุงู„ุถุบุท ูˆุงู„ุชูุงุนู„ ุจุงู„ู„ู…ุณ</span>
</div>
<button
onClick={() => {
const newState = !hapticEnabled;
setHapticEnabled(newState);
if (newState && navigator.vibrate) {
try { navigator.vibrate([100]); } catch(e){}
}
showToast(newState ? "๐Ÿ“ณ ุชู… ุชูุนูŠู„ ุงู‡ุชุฒุงุฒ ุงู„ู„ู…ุณ ุงู„ุชูุงุนู„ูŠ" : "๐Ÿ”‡ ุชู… ุฅูŠู‚ุงู ุงู„ุงู‡ุชุฒุงุฒ", "info");
}}
className={`px-3.5 py-2 rounded-xl text-xs font-bold transition-all ${
hapticEnabled
? "bg-emerald-500/20 text-emerald-700 border border-emerald-500/35"
: "bg-slate-200 text-slate-500 border border-slate-300"
}`}
>
{hapticEnabled ? "ู…ูุนู‘ู„ ๐Ÿ“ณ" : "ู…ุนุทู‘ู„ ๐Ÿ”‡"}
</button>
</div>
<p className="text-[10px] text-slate-400 font-bold uppercase tracking-wider mb-2">ุชุตูุญ ู„ูˆุญุฉ ุงู„ุชุญูƒู…</p>
{tabsList.map((tab) => (
<button
key={tab.id}
onClick={() => {
triggerHaptic();
setActiveTab(tab.id);
setIsMobileMenuOpen(false);
}}
className={`p-3.5 rounded-xl text-sm font-semibold flex items-center justify-between transition ${
activeTab === tab.id
? "bg-sky-500/20 border border-sky-500/40 text-sky-800 font-bold shadow-sm"
: "bg-white/80 border border-sky-500/10 text-slate-700 hover:text-sky-900"
}`}
>
<span className="flex items-center gap-2">
{tab.icon}
{tab.arabic}
</span>
<span className="text-[10px] text-slate-500">{tab.label}</span>
</button>
))}
</div>
)}
{/* 2. Main Content Core Container */}
<main className="flex-1 w-full max-w-7xl mx-auto p-4 sm:p-6 lg:p-8">
{!dbReady ? (
<div className="flex flex-col items-center justify-center py-24 text-center space-y-4">
<RefreshCw className="w-10 h-10 text-sky-600 animate-spin" />
<h3 className="font-bold">ุฌุงุฑูŠ ุชุญู…ูŠู„ ุฎุฒู†ุฉ ุงู„ุฃูˆูู„ุงูŠู† (IndexedDB)</h3>
<p className="text-xs text-slate-500">ู†ู‡ูŠูŠุก ู„ูƒ ุจูŠุฆุฉ ุขู…ู†ุฉ ู…ุดูุฑุฉ ู…ุญู„ูŠุงู‹ ุจุงู„ูƒุงู…ู„...</p>
</div>
) : (
<>
{/* Dynamic tabs distribution */}
{activeTab === "clones" && <ClonerTab triggerHaptic={triggerHaptic} />}
{activeTab === "monitors" && <MonitorTab triggerHaptic={triggerHaptic} />}
{activeTab === "keys" && <KeysTab triggerHaptic={triggerHaptic} />}
{activeTab === "browser" && <BrowserViewport triggerHaptic={triggerHaptic} />}
{activeTab === "emails" && <EmailsTab triggerHaptic={triggerHaptic} />}
{activeTab === "sites" && <SitesTab triggerHaptic={triggerHaptic} />}
{activeTab === "accounts" && <AccountsTab triggerHaptic={triggerHaptic} />}
{activeTab === "studio" && <StudioTab triggerHaptic={triggerHaptic} />}
{activeTab === "workflows" && <WorkflowsTab triggerHaptic={triggerHaptic} />}
{activeTab === "deploy" && <DeployTab triggerHaptic={triggerHaptic} />}
</>
)}
</main>
{/* 3. Floating AI Assistant Chatbot Panel */}
<AiAssistant triggerHaptic={triggerHaptic} />
{/* Toast alert notifications indicator portal */}
{toastMessage && (
<div className="fixed bottom-16 right-6 z-50 bg-white/90 border border-sky-500/20 shadow-2xl p-4 rounded-xl flex items-center gap-3 animate-slide-up max-w-sm backdrop-blur-lg">
<div className={`${
toastType === "success" ? "text-emerald-600" : toastType === "warn" ? "text-red-500" : "text-sky-600"
}`}>
<Bell className="w-5 h-5" />
</div>
<span className="text-xs text-slate-800 font-sans select-text leading-snug">{toastMessage}</span>
</div>
)}
{/* 4. Footer Diagnostic Status Bar (Fixed, 40px approx) */}
<footer className="fixed bottom-0 left-0 right-0 h-10 bg-white/75 border-t border-sky-500/15 z-40 flex items-center justify-between px-4 sm:px-6 text-[11px] text-slate-600 tracking-tight font-sans select-none backdrop-blur-xl">
<div className="flex items-center gap-4">
<span className="flex items-center gap-1.5 font-semibold text-emerald-600">
<span className="w-2.5 h-2.5 rounded-full bg-emerald-500 animate-pulse" />
{metricApis}
</span>
<span className="hidden sm:inline-block border-l border-sky-500/20 h-4" />
<span className="hidden sm:flex items-center gap-1.5 font-semibold text-sky-700">
<span className="w-2.5 h-2.5 rounded-full bg-sky-500" />
{metricWorkflows}
</span>
</div>
{/* Center state */}
<span className="font-semibold text-[10px] sm:text-xs">
๐ŸŸข {metricPingState} | ๐Ÿ”‹ {batteryLevel} | ๐Ÿ“ณ {hapticEnabled ? "ON" : "OFF"} | ๐ŸŽจ Frosted Glass
</span>
{/* Version branding */}
<span className="font-mono text-[9px] text-slate-400 hidden sm:inline">
SiteClone Pro v20.0.0 FINAL
</span>
</footer>
</div>
);
}