Spaces:
Running
Running
BRIDGE Platform Agent
feat(platform): BRIDGE Modules hub with /modules/e and /modules/s routed workspaces
1955a0f Download src/modules/ModuleHub.tsx from sitcod3/BRIDGE_Modul-S_prod: direct link, hf CLI and curl.
- Browser
- Download file 8.48 kB
-
https://huggingface.co/spaces/sitcod3/BRIDGE_Modul-S_prod/resolve/main/src/modules/ModuleHub.tsx
- Command line
-
hf download hf://spaces/sitcod3/BRIDGE_Modul-S_prod/src/modules/ModuleHub.tsx
-
curl -L -o ModuleHub.tsx https://huggingface.co/spaces/sitcod3/BRIDGE_Modul-S_prod/resolve/main/src/modules/ModuleHub.tsx
8.48 kB
| import { useEffect } from "react"; | |
| import { motion } from "motion/react"; | |
| import { ArrowRight, Boxes, CheckCircle2, XCircle, Zap } from "lucide-react"; | |
| import GlassCard from "../components/GlassCard"; | |
| import AnimatedLogo from "../components/AnimatedLogo"; | |
| import { useApiKey } from "../context/ApiKeyContext"; | |
| import { MINT_THEME } from "../context/ThemeContext"; | |
| import { useLaunch } from "./LaunchContext"; | |
| import { MODULES, MODULE_IDS } from "./registry"; | |
| import { preloadModulePages } from "./lazyPages"; | |
| const MODULE_CAPS: Record<string, string[]> = { | |
| e: ["Sequence automation", "Unified inbox", "Warmup radar", "Deliverability analytics"], | |
| s: ["Campaign management", "Lead database", "Webhook automation", "Email warmup"], | |
| }; | |
| /** | |
| * BRIDGE platform hub — the launcher. Real platform primitives only | |
| * (GlassCard, AnimatedLogo, API-key status). Buttons trigger the module | |
| * launch animation (re-seeded per launch) via LaunchContext. | |
| */ | |
| export default function ModuleHub() { | |
| const { startLaunch } = useLaunch(); | |
| const { activeKey } = useApiKey(); | |
| useEffect(() => { | |
| // Preload both modules' chunks so the first launch never janks. | |
| const idle = window.requestIdleCallback ?? ((cb: () => void) => window.setTimeout(cb, 200)); | |
| const handle = idle(() => { | |
| preloadModulePages("e"); | |
| preloadModulePages("s"); | |
| }); | |
| return () => { | |
| if (typeof window.cancelIdleCallback === "function" && typeof handle === "number") { | |
| window.cancelIdleCallback(handle); | |
| } | |
| }; | |
| }, []); | |
| return ( | |
| <div className="min-h-screen bg-[#05070a] text-zinc-100 relative overflow-hidden"> | |
| {/* Ambient layers — platform primitives */} | |
| <div | |
| className="absolute inset-0 pointer-events-none" | |
| style={{ | |
| background: | |
| "radial-gradient(ellipse at top right, rgba(0, 229, 188, 0.10), transparent 60%), radial-gradient(ellipse at bottom left, rgba(99, 102, 241, 0.12), transparent 60%)", | |
| }} | |
| /> | |
| <div className="relative z-10 max-w-5xl mx-auto px-4 md:px-8 py-12 md:py-20"> | |
| {/* Header */} | |
| <div className="flex flex-col items-start gap-6 mb-12"> | |
| <div className="flex items-center gap-3"> | |
| <AnimatedLogo className="w-10 h-10" /> | |
| <div> | |
| <div className="text-lg font-bold tracking-[0.08em] text-white"> | |
| BRIDGE<span className="text-[#00e5bc]">Modules</span> | |
| </div> | |
| <div className="text-[9px] font-bold tracking-[0.2em] text-zinc-500 uppercase font-mono"> | |
| Outbound Systems OS · Platform Hub | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <h1 className="text-2xl md:text-3xl font-bold text-white tracking-tight"> | |
| Launch a workspace. | |
| </h1> | |
| <p className="text-sm text-zinc-400 mt-2 max-w-xl"> | |
| Two autonomous outbound engines, one command platform. Each module | |
| assembles its own dashboard from live primitives when launched. | |
| </p> | |
| </div> | |
| <div className="flex items-center gap-2"> | |
| {activeKey ? ( | |
| <div className="flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-wider px-2.5 py-1 rounded-full border shadow-sm text-[#00e5bc] bg-[rgba(0,229,188,0.12)] border-[rgba(0,229,188,0.3)]"> | |
| <CheckCircle2 className="w-3 h-3" /> | |
| API Connected | |
| </div> | |
| ) : ( | |
| <div className="flex items-center gap-1.5 text-[10px] font-bold uppercase tracking-wider text-rose-300 bg-rose-500/10 border border-rose-500/20 px-2.5 py-1 rounded-full"> | |
| <XCircle className="w-3 h-3" /> | |
| API Key Missing — set one in a module's Settings | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| {/* Module launcher cards — real primitives */} | |
| <div className="grid md:grid-cols-2 gap-4 md:gap-6"> | |
| {MODULE_IDS.map((id) => { | |
| const def = MODULES[id]; | |
| const Icon = def.icon; | |
| const theme = def.theme; | |
| const mint = id === "e" ? MINT_THEME : null; | |
| return ( | |
| <motion.div | |
| key={id} | |
| initial={{ opacity: 0, y: 18 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1], delay: id === "e" ? 0.05 : 0.15 }} | |
| > | |
| <GlassCard className="p-6 md:p-7 h-full flex flex-col group hover:border-white/10 transition-all duration-500"> | |
| <div className="flex items-start justify-between mb-5"> | |
| <div | |
| className="w-11 h-11 rounded-xl flex items-center justify-center border" | |
| style={{ | |
| backgroundColor: `${theme.accent}14`, | |
| borderColor: `${theme.accent}44`, | |
| boxShadow: `0 0 24px ${theme.accent}22`, | |
| }} | |
| > | |
| <Icon className="w-5 h-5" style={{ color: theme.accent }} /> | |
| </div> | |
| <span | |
| className="text-[9px] font-bold font-mono uppercase tracking-[0.18em] px-2 py-1 rounded-md border" | |
| style={{ | |
| color: theme.accentText, | |
| borderColor: `${theme.accent}44`, | |
| backgroundColor: `${theme.accent}14`, | |
| }} | |
| > | |
| {theme.code} | |
| </span> | |
| </div> | |
| <h2 className="text-xl font-bold text-white tracking-tight"> | |
| BRIDGE | |
| <span style={{ color: theme.accent }}>{def.wordmark}</span> | |
| </h2> | |
| <p className="text-[13px] text-zinc-400 mt-2 leading-relaxed flex-1"> | |
| {def.blurb} | |
| </p> | |
| <ul className="mt-5 space-y-1.5"> | |
| {MODULE_CAPS[id].map((cap) => ( | |
| <li key={cap} className="flex items-center gap-2 text-xs text-zinc-300"> | |
| <span | |
| className="w-1 h-1 rounded-full shrink-0" | |
| style={{ backgroundColor: theme.accent, boxShadow: `0 0 6px ${theme.accent}` }} | |
| /> | |
| {cap} | |
| </li> | |
| ))} | |
| </ul> | |
| <div className="mt-6 flex items-center justify-between gap-3"> | |
| <div className="flex items-center gap-1.5 text-[10px] font-mono text-zinc-500 uppercase tracking-wider"> | |
| <Boxes className="w-3.5 h-3.5" /> | |
| Slow-mo assembly on launch | |
| </div> | |
| <button | |
| type="button" | |
| onClick={() => startLaunch(id)} | |
| onMouseEnter={() => preloadModulePages(id)} | |
| className="flex items-center gap-2 px-4 py-2.5 rounded-lg text-[13px] font-bold transition-all duration-300 active:scale-[0.98] border" | |
| style={{ | |
| backgroundColor: theme.buttonBg, | |
| color: theme.buttonText, | |
| borderColor: theme.buttonBg, | |
| boxShadow: `0 0 24px ${theme.accent}33`, | |
| }} | |
| aria-label={`Launch ${def.label}`} | |
| > | |
| {id === "e" ? <Zap className="w-4 h-4" /> : <Boxes className="w-4 h-4" />} | |
| Launch {def.label.replace(/^Module /, "")} | |
| <ArrowRight className="w-4 h-4 group-hover:translate-x-0.5 transition-transform" /> | |
| </button> | |
| </div> | |
| {mint && ( | |
| <div className="mt-4 text-[10px] font-mono text-zinc-600 uppercase tracking-[0.16em]"> | |
| GreenTheme build · accent {mint.accent} | |
| </div> | |
| )} | |
| </GlassCard> | |
| </motion.div> | |
| ); | |
| })} | |
| </div> | |
| <div className="mt-10 text-center text-[10px] font-mono text-zinc-600 uppercase tracking-[0.2em]"> | |
| Bridge Modules · Direct URLs — /modules/e · /modules/s | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |