| 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); |
| |
| |
| const [toastMessage, setToastMessage] = useState<string | null>(null); |
| const [toastType, setToastType] = useState<"success" | "warn" | "info">("success"); |
|
|
| |
| const [metricApis, setMetricApis] = useState("8/10 APIs"); |
| const [metricWorkflows, setMetricWorkflows] = useState("3 workflows"); |
| const [metricPingState, setMetricPingState] = useState("ู
ุชุตู"); |
| const [batteryLevel, setBatteryLevel] = useState("85%"); |
|
|
| useEffect(() => { |
| |
| initIndexedDB() |
| .then(() => { |
| setDbReady(true); |
| showToast("โ ุชู
ุชููุฆุฉ ูุงุนุฏุฉ ุจูุงูุงุช IndexedDB ูุชูุนูู ูุถุน ุงูุฃูููุงูู ุจูุฌุงุญ", "success"); |
| |
| |
| 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); |
| |
| setDbReady(true); |
| showToast("โ ุชู
ุชูุนูู ุงูุชุฎุฒูู ุงูุณุญุงุจู/ุงูู
ุญูู ุจุงููุงู
ู ุฏุงุฎู ุจูุฆุฉ ุงูู
ุนุงููุฉ", "success"); |
| }); |
|
|
| |
| 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 { |
| |
| } |
| }; |
|
|
| const showToast = (msg: string, type: "success" | "warn" | "info") => { |
| setToastMessage(msg); |
| setToastType(type); |
| |
| |
| const timer = setTimeout(() => { |
| setToastMessage(null); |
| }, 4000); |
| }; |
|
|
| const triggerHaptic = () => { |
| if (!hapticEnabled) return; |
| try { |
| if (navigator.vibrate) { |
| navigator.vibrate([40]); |
| } |
| } catch { |
| |
| } |
| }; |
|
|
| |
| 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> |
|
|
| {} |
| <AiAssistant triggerHaptic={triggerHaptic} /> |
|
|
| {} |
| {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> |
| )} |
|
|
| {} |
| <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> |
|
|
| {} |
| <span className="font-semibold text-[10px] sm:text-xs"> |
| ๐ข {metricPingState} | ๐ {batteryLevel} | ๐ณ {hapticEnabled ? "ON" : "OFF"} | ๐จ Frosted Glass |
| </span> |
|
|
| {} |
| <span className="font-mono text-[9px] text-slate-400 hidden sm:inline"> |
| SiteClone Pro v20.0.0 FINAL |
| </span> |
| </footer> |
| </div> |
| ); |
| } |
|
|