diff --git a/index.html b/index.html index 6f2433a..2ace457 100644 --- a/index.html +++ b/index.html @@ -205,6 +205,7 @@ + diff --git a/src/app.jsx b/src/app.jsx index f549da0..16d6616 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -1,4 +1,4 @@ -// Root app: theme + ⌘K + Tweaks + scroll reveal +// Root app: theme + ⌘K + Tweaks + hash router const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "accent": "#7c5cff", @@ -8,6 +8,27 @@ const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "heroHeadlineSuffix": "automation engineer" }/*EDITMODE-END*/; +// Simple hash router — reads window.location.hash +function useHashRoute() { + const [route, setRoute] = React.useState(() => { + const h = window.location.hash; + return h.startsWith('#/') ? h.slice(2) : ''; + }); + + React.useEffect(() => { + const onHash = () => { + const h = window.location.hash; + const r = h.startsWith('#/') ? h.slice(2) : ''; + setRoute(r); + window.scrollTo(0, 0); + }; + window.addEventListener('hashchange', onHash); + return () => window.removeEventListener('hashchange', onHash); + }, []); + + return route; +} + function App() { const [theme, setTheme] = React.useState(() => { return localStorage.getItem("aura-theme") || "dark"; @@ -15,11 +36,11 @@ function App() { const [paletteOpen, setPaletteOpen] = React.useState(false); const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS); const [lang, setLang] = React.useState(() => localStorage.getItem("aura-lang") || "en"); + const route = useHashRoute(); React.useEffect(() => { localStorage.setItem("aura-lang", lang); }, [lang]); const toggleLang = () => setLang(l => l === "en" ? "bn" : "en"); - // theme React.useEffect(() => { document.documentElement.dataset.theme = theme; localStorage.setItem("aura-theme", theme); @@ -33,7 +54,6 @@ function App() { return () => window.removeEventListener("aura:toggle-theme", onToggle); }, []); - // ⌘K React.useEffect(() => { const onKey = (e) => { if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") { @@ -45,17 +65,13 @@ function App() { return () => window.removeEventListener("keydown", onKey); }, []); - // tweaks accent vars — apply to :root React.useEffect(() => { document.documentElement.style.setProperty("--accent", tweaks.accent); document.documentElement.style.setProperty("--accent-2", tweaks.accent2); - document.documentElement.style.setProperty("--accent-glow", tweaks.accent + "59"); // ~35% alpha + document.documentElement.style.setProperty("--accent-glow", tweaks.accent + "59"); }, [tweaks.accent, tweaks.accent2]); - // density - const density = tweaks.density; - - // scroll reveal + // scroll reveal (re-run on route change) React.useEffect(() => { const els = document.querySelectorAll(".reveal"); const io = new IntersectionObserver(entries => { @@ -63,36 +79,56 @@ function App() { }, { threshold: 0.1 }); els.forEach(el => io.observe(el)); return () => io.disconnect(); - }, []); + }, [route]); + const density = tweaks.density; const T = window; + const navProps = { + onCmdK: () => setPaletteOpen(true), + theme, onToggleTheme: toggleTheme, + lang, onToggleLang: toggleLang, + route, + }; + + const renderPage = () => { + switch (route) { + case 'services': + return ; + case 'stack': + return ; + case 'agents': + return ; + case 'timeline': + return ; + case 'contact': + return ; + default: + return ( +
+ + + + + + + +
+ ); + } + }; + return ( <> - setPaletteOpen(true)} theme={theme} onToggleTheme={toggleTheme} lang={lang} onToggleLang={toggleLang} /> -
- - - - - - - -
+ + {renderPage()} - setPaletteOpen(false)} /> - setTheme(v)} - options={["dark", "light"]} - /> - + setTheme(v)} options={["dark", "light"]} /> setTweak("accent", v)} /> setTweak("accent2", v)} /> @@ -105,29 +141,17 @@ function App() { ["Mono", "#ffffff", "#a4a8b3"], ].map(([name, a, b]) => ( ))} - - setTweak("density", v)} - options={["compact", "spacious"]} - /> - + setTweak("density", v)} options={["compact", "spacious"]} /> setTweak("heroHeadlinePrefix", v)} /> setTweak("heroHeadlineSuffix", v)} /> diff --git a/src/data.jsx b/src/data.jsx index cfb3250..561eb47 100644 --- a/src/data.jsx +++ b/src/data.jsx @@ -144,6 +144,26 @@ const PORTFOLIO_DATA = { impact: { primary: "99.98%", secondary: "uptime maintained" }, color: "cyan", }, + { + id: "meta-ads-ai", + name: "AI-Powered Meta Ads", + nameBn: "এআই-চালিত মেটা অ্যাডস", + kind: "Growth Service", + badge: "NEW · Meta MCP", + description: + "AI agents connected directly to Meta's official API — optimizing bids, rotating creatives, and reallocating budgets every 15 minutes. Not a human checking ads twice a day. A system that never sleeps.", + stack: ["Meta MCP", "Meta Ads API", "n8n", "Claude AI", "Anthropic"], + impact: { primary: "5×", secondary: "ROAS vs. manual management" }, + color: "rose", + highlights: [ + "Real-time bid & budget optimization every 15 min", + "100+ ad variants A/B tested simultaneously by AI", + "Automated audience expansion & lookalike generation", + "Creative fatigue detection — pauses before burnout", + "Daily AI-written performance reports to your inbox", + "Full Meta API access via official MCP integration", + ], + }, ], agentRun: [ diff --git a/src/nav.jsx b/src/nav.jsx index 8b420bc..0b690a3 100644 --- a/src/nav.jsx +++ b/src/nav.jsx @@ -1,15 +1,16 @@ -// Top nav — minimal, sticky, blurred +// Top nav — minimal, sticky, blurred — mobile-responsive const DASHBOARD = 'https://aura.auraajenticai.cloud' const NAV_FALLBACK = [ - { id: "work", label: "Services", url: "#work" }, - { id: "stack", label: "Stack", url: "#stack" }, - { id: "agents", label: "Agents", url: "#agents" }, - { id: "timeline", label: "Timeline", url: "#timeline" }, - { id: "contact", label: "Contact", url: "#contact" }, + { id: "services", label: "Services", url: "#/services" }, + { id: "stack", label: "Stack", url: "#/stack" }, + { id: "agents", label: "Agents", url: "#/agents" }, + { id: "timeline", label: "Timeline", url: "#/timeline" }, + { id: "contact", label: "Contact", url: "#/contact" }, ] -const Nav = ({ onCmdK, theme, onToggleTheme, accent, lang, onToggleLang }) => { +const Nav = ({ onCmdK, theme, onToggleTheme, accent, lang, onToggleLang, route }) => { const [scrolled, setScrolled] = React.useState(false); + const [menuOpen, setMenuOpen] = React.useState(false); const [links, setLinks] = React.useState(NAV_FALLBACK); React.useEffect(() => { @@ -42,146 +43,278 @@ const Nav = ({ onCmdK, theme, onToggleTheme, accent, lang, onToggleLang }) => { }, []); return ( - + )} + ); }; diff --git a/src/pages.jsx b/src/pages.jsx new file mode 100644 index 0000000..83cf41a --- /dev/null +++ b/src/pages.jsx @@ -0,0 +1,441 @@ +// Individual page views for hash router + +const COLOR_MAP = { + violet: { bg: "rgba(124,92,255,0.08)", border: "rgba(124,92,255,0.22)", text: "#a78bfa" }, + cyan: { bg: "rgba(0,212,255,0.07)", border: "rgba(0,212,255,0.20)", text: "#67e8f9" }, + green: { bg: "rgba(34,197,94,0.07)", border: "rgba(34,197,94,0.20)", text: "#86efac" }, + amber: { bg: "rgba(251,191,36,0.08)", border: "rgba(251,191,36,0.22)", text: "#fde68a" }, + rose: { bg: "rgba(244,63,94,0.08)", border: "rgba(244,63,94,0.22)", text: "#fda4af" }, +}; + +const PageHero = ({ eyebrow, title, sub, children }) => ( +
+ +
+); + +// ─── SERVICES PAGE ──────────────────────────────────────────────────────────── + +const ServicesPage = ({ lang }) => { + const D = PORTFOLIO_DATA; + const [active, setActive] = React.useState(null); + + return ( +
+ Services that ship — not decks that pitch} + sub="Every engagement ends with production code. No retainers for decks. No sprints for prototypes that never deploy." + /> + +
+
+
+ {D.services.map((svc, i) => { + const c = COLOR_MAP[svc.color] || COLOR_MAP.violet; + const isOpen = active === svc.id; + const isNew = !!svc.badge; + return ( +
setActive(isOpen ? null : svc.id)} + > + {/* Header row */} +
+
+ 0{i + 1} +
+
+

+ {lang === "bn" && svc.nameBn ? svc.nameBn : svc.name} +

+ {isNew && ( + {svc.badge} + )} +
+ {svc.kind} +
+
+
+
+
{svc.impact.primary}
+
{svc.impact.secondary}
+
+
+
+
+
+ + {/* Expanded content */} + {isOpen && ( +
+
+
+

{svc.description}

+ {svc.highlights && ( +
    + {svc.highlights.map((h, hi) => ( +
  • + + {h} +
  • + ))} +
+ )} +
+ +
+
+ )} +
+ ); + })} +
+
+
+ +
+ ); +}; + +// ─── STACK PAGE ────────────────────────────────────────────────────────────── + +const StackPage = () => { + const D = PORTFOLIO_DATA; + const cats = Object.entries(D.stack); + const [activeTab, setActiveTab] = React.useState(cats[0][0]); + const skills = cats.find(([k]) => k === activeTab)?.[1] || []; + + return ( +
+ Tools we wield daily} + sub="Production-tested across 40+ agents, 12 enterprise clients, and 7 years of shipping real systems." + /> +
+
+ {/* Tab bar */} +
+ {cats.map(([cat]) => ( + + ))} +
+ + {/* Skill bars */} +
+ {skills.map((s, i) => ( +
+
+ {s.name} + {s.level}% +
+
+
+
+
+ ))} +
+
+
+
+ ); +}; + +// ─── AGENTS PAGE ───────────────────────────────────────────────────────────── + +const AgentsPage = () => ( +
+ Agents that act — not chat} + sub="Every agent we ship has tool access, memory, retry logic, and an audit trail. Live demo below." + /> +
+
+ +
+
+
+); + +// ─── TIMELINE PAGE ─────────────────────────────────────────────────────────── + +const TimelinePage = () => { + const D = PORTFOLIO_DATA; + return ( +
+ +
+
+
+ {D.experience.map((exp, i) => ( +
+
+
{exp.year}
+
+
+ {exp.role} + {exp.kind} +
+
{exp.company}
+

{exp.detail}

+
+
+ ))} +
+
+
+
+ ); +}; + +// ─── CONTACT PAGE ───────────────────────────────────────────────────────────── + +const ContactPage = ({ lang }) => { + const [sent, setSent] = React.useState(false); + const [form, setForm] = React.useState({ name: "", email: "", service: "", message: "" }); + const [loading, setLoading] = React.useState(false); + + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); + await new Promise(r => setTimeout(r, 1000)); + setSent(true); + setLoading(false); + }; + + const services = PORTFOLIO_DATA.services.map(s => s.name); + + return ( +
+ +
+
+
+ {/* Left info */} +
+
+ {[ + { label: "Email", value: "hello@auraajenticai.cloud", href: "mailto:hello@auraajenticai.cloud" }, + { label: "Response time", value: "< 24 hours" }, + { label: "Location", value: "Dhaka, Bangladesh · Remote" }, + { label: "Availability", value: "Open to new projects" }, + ].map(item => ( +
+
{item.label}
+ {item.href + ? {item.value} + :
{item.value}
+ } +
+ ))} +
+
+ + {/* Contact form */} + {sent ? ( +
+
+

Message sent!

+

We'll get back to you within 24 hours.

+
+ ) : ( +
+ {[ + { key: "name", label: "Your name", type: "text", placeholder: "Jane Smith" }, + { key: "email", label: "Email", type: "email", placeholder: "jane@company.com" }, + ].map(f => ( +
+ + setForm(p => ({ ...p, [f.key]: e.target.value }))} + style={{ + width: "100%", padding: "11px 14px", + background: "var(--bg-elev)", border: "1px solid var(--line)", + borderRadius: 9, color: "var(--text)", fontSize: 14.5, + fontFamily: "var(--font-sans)", outline: "none", + boxSizing: "border-box", + }} + /> +
+ ))} +
+ + +
+
+ +