Phase 3: Aura Agentic AI public site — rebrand, services, bilingual, n8n contact form, Dockerfile

This commit is contained in:
khondokartowsif171
2026-04-27 18:02:25 +06:00
commit 27cdba1cac
16 changed files with 3266 additions and 0 deletions
+235
View File
@@ -0,0 +1,235 @@
// AI agent showcase — animated terminal "console replay" of an agent run
const AgentShowcase = () => {
const D = PORTFOLIO_DATA;
const run = D.agentRun;
const totalDuration = run[run.length - 1].t + 1500;
const [playing, setPlaying] = React.useState(true);
const [elapsed, setElapsed] = React.useState(0);
const [resetKey, setResetKey] = React.useState(0);
React.useEffect(() => {
if (!playing) return;
let raf, start = performance.now() - elapsed;
const tick = (now) => {
const e = now - start;
if (e >= totalDuration) {
setElapsed(totalDuration);
setPlaying(false);
return;
}
setElapsed(e);
raf = requestAnimationFrame(tick);
};
raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, [playing, resetKey]);
const visible = run.filter(r => r.t <= elapsed);
const progress = Math.min(elapsed / totalDuration, 1);
const restart = () => {
setElapsed(0);
setPlaying(true);
setResetKey(k => k + 1);
};
const lineFor = (line, i) => {
const styles = {
system: { prefix: "▸", color: "var(--text-faint)" },
user: { prefix: "", color: "var(--accent)" },
thought: { prefix: "↪", color: "var(--text-dim)" },
tool: { prefix: "⌁", color: "var(--accent-2)" },
output: { prefix: "✓", color: "var(--good)" },
};
const s = styles[line.kind];
return (
<div key={i} style={{
display: "grid",
gridTemplateColumns: "20px 1fr",
gap: 12,
padding: "8px 0",
borderBottom: i < visible.length - 1 ? "1px dashed var(--line)" : "none",
animation: `float-up 0.35s both`,
}}>
<span style={{ color: s.color, fontWeight: 600 }}>{s.prefix}</span>
<div>
{line.kind === "tool" ? (
<div>
<div style={{ display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" }}>
<span style={{
padding: "2px 8px",
background: "var(--bg-elev)",
border: "1px solid var(--line)",
borderRadius: 4,
fontSize: 11,
color: "var(--accent-2)",
fontWeight: 500,
}}>{line.tool}</span>
<span style={{
fontSize: 11,
color: "var(--good)",
fontFamily: "var(--font-mono)",
display: "inline-flex",
alignItems: "center",
gap: 4,
}}>
<span style={{ width: 5, height: 5, borderRadius: "50%", background: "var(--good)" }} />
{line.status}
</span>
<span style={{ fontSize: 11, color: "var(--text-faint)" }}>{line.meta}</span>
</div>
<div style={{ marginTop: 6, color: "var(--text)", fontSize: 12.5 }}>{line.text}</div>
</div>
) : (
<span style={{
color: line.kind === "user" || line.kind === "output" ? "var(--text)" : "var(--text-dim)",
fontWeight: line.kind === "user" || line.kind === "output" ? 500 : 400,
fontSize: line.kind === "system" ? 11.5 : 13,
}}>{line.text}</span>
)}
</div>
</div>
);
};
return (
<section id="agents" style={{ padding: "120px 0", borderTop: "1px solid var(--line)", position: "relative", overflow: "hidden" }}>
{/* faint accent wash */}
<div aria-hidden style={{
position: "absolute",
top: "30%", left: "50%",
transform: "translateX(-50%)",
width: 800, height: 400,
background: "radial-gradient(ellipse, var(--accent-glow), transparent 70%)",
filter: "blur(60px)",
opacity: 0.6,
pointerEvents: "none",
}} />
<div className="container" style={{ position: "relative" }}>
<SectionHeader
eyebrow="Agent runtime"
num="04 / 06"
title={<>What it actually <span style={{ fontFamily: "var(--font-serif)", fontStyle: "italic", fontWeight: 400 }}>looks like</span> when an agent does the work.</>}
sub="Below is a real session replay — model decomposes a task, calls tools, and writes back. This is the surface every agent I ship gets out of the box: trace, evals, audit trail."
/>
<div style={{ display: "grid", gridTemplateColumns: "1.2fr 1fr", gap: 16, alignItems: "start" }} className="agent-grid">
{/* Terminal */}
<div className="panel" style={{ overflow: "hidden", fontFamily: "var(--font-mono)" }}>
{/* chrome */}
<div style={{
display: "flex",
alignItems: "center",
gap: 12,
padding: "12px 16px",
borderBottom: "1px solid var(--line)",
background: "var(--bg-elev)",
}}>
<div style={{ display: "flex", gap: 6 }}>
<span style={{ width: 11, height: 11, borderRadius: "50%", background: "#ff5f56" }} />
<span style={{ width: 11, height: 11, borderRadius: "50%", background: "#ffbd2e" }} />
<span style={{ width: 11, height: 11, borderRadius: "50%", background: "#27c93f" }} />
</div>
<span style={{ fontSize: 11.5, color: "var(--text-faint)" }}>aura runtime run_8af3e2.replay</span>
<span style={{ marginLeft: "auto", fontSize: 11, color: "var(--text-faint)" }}>{(elapsed/1000).toFixed(1)}s / {(totalDuration/1000).toFixed(1)}s</span>
</div>
{/* scanline progress */}
<div style={{ height: 2, background: "var(--line)" }}>
<div style={{
width: `${progress * 100}%`,
height: "100%",
background: "linear-gradient(90deg, var(--accent), var(--accent-2))",
transition: "width 0.1s linear",
}} />
</div>
{/* body */}
<div style={{ padding: "16px 20px", minHeight: 460, fontSize: 12.5 }}>
{visible.map((l, i) => lineFor(l, i))}
{playing && (
<div style={{
display: "inline-block",
width: 8, height: 14,
background: "var(--accent)",
marginTop: 8,
animation: "blink 1s infinite",
verticalAlign: "middle",
}} />
)}
</div>
{/* controls */}
<div style={{
display: "flex",
alignItems: "center",
gap: 10,
padding: "12px 16px",
borderTop: "1px solid var(--line)",
background: "var(--bg-elev)",
}}>
<button onClick={() => setPlaying(p => !p)} style={{
padding: "6px 12px",
background: "var(--text)",
color: "var(--bg)",
border: "none",
borderRadius: 6,
fontSize: 12,
fontWeight: 500,
fontFamily: "var(--font-sans)",
}}>{playing ? "Pause" : (elapsed >= totalDuration ? "Replay" : "Play")}</button>
<button onClick={restart} style={{
padding: "6px 12px",
background: "transparent",
color: "var(--text-dim)",
border: "1px solid var(--line)",
borderRadius: 6,
fontSize: 12,
fontFamily: "var(--font-sans)",
}}>Restart</button>
<span style={{ marginLeft: "auto", fontSize: 11, color: "var(--text-faint)" }}>
{visible.length} / {run.length} steps
</span>
</div>
</div>
{/* Sidebar: capabilities */}
<div style={{ display: "grid", gap: 12 }}>
{[
{ i: Icons.Layers, t: "Orchestration", d: "Durable graphs with retries, timeouts, and human-in-the-loop checkpoints." },
{ i: Icons.Cube, t: "Tool registry", d: "Typed tool catalog — Postgres, Stripe, Slack, custom HTTP, on-chain calls." },
{ i: Icons.Bolt, t: "Eval harness", d: "Golden datasets, regression suites, drift detection on every model swap." },
{ i: Icons.Database, t: "Audit trail", d: "Every step, prompt, and token logged. Replayable. Court-admissible." },
].map(({ i: I, t, d }) => (
<div key={t} className="panel" style={{ padding: 20 }}>
<div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 10 }}>
<div style={{
width: 32, height: 32,
display: "grid", placeItems: "center",
background: "var(--accent-glow)",
border: "1px solid color-mix(in srgb, var(--accent) 30%, transparent)",
borderRadius: 8,
color: "var(--accent)",
}}><I size={15} /></div>
<span style={{ fontSize: 14.5, fontWeight: 500 }}>{t}</span>
</div>
<p style={{ margin: 0, fontSize: 13, lineHeight: 1.5, color: "var(--text-dim)" }}>{d}</p>
</div>
))}
</div>
</div>
<style>{`
@media (max-width: 1000px) {
.agent-grid { grid-template-columns: 1fr !important; }
}
`}</style>
</div>
</section>
);
};
window.AgentShowcase = AgentShowcase;
+138
View File
@@ -0,0 +1,138 @@
// Root app: theme + ⌘K + Tweaks + scroll reveal
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"accent": "#7c5cff",
"accent2": "#00d4ff",
"density": "spacious",
"heroHeadlinePrefix": "Agentic AI &",
"heroHeadlineSuffix": "automation engineer"
}/*EDITMODE-END*/;
function App() {
const [theme, setTheme] = React.useState(() => {
return localStorage.getItem("aura-theme") || "dark";
});
const [paletteOpen, setPaletteOpen] = React.useState(false);
const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);
const [lang, setLang] = React.useState(() => localStorage.getItem("aura-lang") || "en");
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);
}, [theme]);
const toggleTheme = () => setTheme(t => t === "dark" ? "light" : "dark");
React.useEffect(() => {
const onToggle = () => toggleTheme();
window.addEventListener("aura:toggle-theme", onToggle);
return () => window.removeEventListener("aura:toggle-theme", onToggle);
}, []);
// ⌘K
React.useEffect(() => {
const onKey = (e) => {
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
e.preventDefault();
setPaletteOpen(o => !o);
}
};
window.addEventListener("keydown", onKey);
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
}, [tweaks.accent, tweaks.accent2]);
// density
const density = tweaks.density;
// scroll reveal
React.useEffect(() => {
const els = document.querySelectorAll(".reveal");
const io = new IntersectionObserver(entries => {
entries.forEach(en => { if (en.isIntersecting) en.target.classList.add("in"); });
}, { threshold: 0.1 });
els.forEach(el => io.observe(el));
return () => io.disconnect();
}, []);
const T = window;
return (
<>
<T.Nav onCmdK={() => setPaletteOpen(true)} theme={theme} onToggleTheme={toggleTheme} lang={lang} onToggleLang={toggleLang} />
<main style={density === "compact" ? { fontSize: 14.5 } : undefined}>
<T.Hero headlinePrefix={tweaks.heroHeadlinePrefix} headlineSuffix={tweaks.heroHeadlineSuffix} lang={lang} />
<T.About />
<T.Skills />
<T.Projects />
<T.AgentShowcase />
<T.Timeline />
<T.Contact lang={lang} />
</main>
<T.Footer />
<T.CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} />
<window.TweaksPanel title="Tweaks">
<window.TweakSection label="Theme" />
<window.TweakRadio
label="Mode"
value={theme}
onChange={v => setTheme(v)}
options={["dark", "light"]}
/>
<window.TweakSection label="Accent" />
<window.TweakColor label="Primary" value={tweaks.accent} onChange={v => setTweak("accent", v)} />
<window.TweakColor label="Secondary" value={tweaks.accent2} onChange={v => setTweak("accent2", v)} />
<div style={{ display: "flex", gap: 4, flexWrap: "wrap", padding: "0 0 4px" }}>
{[
["Violet", "#7c5cff", "#00d4ff"],
["Cyan", "#00d4ff", "#7c5cff"],
["Emerald", "#22c55e", "#7c5cff"],
["Sunset", "#ff6b35", "#fbbf24"],
["Mono", "#ffffff", "#a4a8b3"],
].map(([name, a, b]) => (
<button key={name} onClick={() => setTweak({ accent: a, accent2: b })} style={{
padding: "4px 8px",
fontSize: 10.5,
background: "transparent",
border: "1px solid rgba(0,0,0,.12)",
borderRadius: 5,
color: "#29261b",
display: "inline-flex", gap: 5, alignItems: "center",
cursor: "pointer",
}}>
<span style={{ width: 9, height: 9, background: a, borderRadius: "50%", display: "inline-block" }} />
{name}
</button>
))}
</div>
<window.TweakSection label="Density" />
<window.TweakRadio
label="Layout"
value={tweaks.density}
onChange={v => setTweak("density", v)}
options={["compact", "spacious"]}
/>
<window.TweakSection label="Hero copy" />
<window.TweakText label="Prefix" value={tweaks.heroHeadlinePrefix} onChange={v => setTweak("heroHeadlinePrefix", v)} />
<window.TweakText label="Suffix" value={tweaks.heroHeadlineSuffix} onChange={v => setTweak("heroHeadlineSuffix", v)} />
</window.TweaksPanel>
</>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
+178
View File
@@ -0,0 +1,178 @@
// Command palette — ⌘K
const CommandPalette = ({ open, onClose }) => {
const D = PORTFOLIO_DATA;
const [q, setQ] = React.useState("");
const [active, setActive] = React.useState(0);
const inputRef = React.useRef(null);
React.useEffect(() => {
if (open) {
setQ("");
setActive(0);
setTimeout(() => inputRef.current?.focus(), 50);
}
}, [open]);
const items = React.useMemo(() => {
const base = [
{ group: "Navigate", label: "Go to Work", icon: Icons.Cube, action: () => location.hash = "#work" },
{ group: "Navigate", label: "Go to Stack", icon: Icons.Code, action: () => location.hash = "#stack" },
{ group: "Navigate", label: "Go to Agent showcase", icon: Icons.Sparkles, action: () => location.hash = "#agents" },
{ group: "Navigate", label: "Go to Timeline", icon: Icons.Bolt, action: () => location.hash = "#timeline" },
{ group: "Navigate", label: "Go to Contact", icon: Icons.Mail, action: () => location.hash = "#contact" },
...D.projects.map(p => ({
group: "Projects",
label: p.name,
sub: p.kind,
icon: Icons.Cube,
action: () => location.hash = "#work",
})),
{ group: "Action", label: "Email me directly", icon: Icons.Mail, action: () => window.location.href = `mailto:${D.brand.email}` },
{ group: "Action", label: "Open GitHub", icon: Icons.Github, action: () => window.open(D.brand.socials.github) },
{ group: "Action", label: "Open LinkedIn", icon: Icons.LinkedIn, action: () => window.open(D.brand.socials.linkedin) },
{ group: "Action", label: "Toggle theme", icon: Icons.Sun, action: () => window.dispatchEvent(new CustomEvent("aura:toggle-theme")) },
];
if (!q) return base;
const Q = q.toLowerCase();
return base.filter(i => i.label.toLowerCase().includes(Q) || (i.sub && i.sub.toLowerCase().includes(Q)));
}, [q]);
React.useEffect(() => { setActive(0); }, [q]);
const onKey = (e) => {
if (e.key === "ArrowDown") { e.preventDefault(); setActive(a => Math.min(a + 1, items.length - 1)); }
else if (e.key === "ArrowUp") { e.preventDefault(); setActive(a => Math.max(a - 1, 0)); }
else if (e.key === "Enter") { e.preventDefault(); if (items[active]) { items[active].action(); onClose(); } }
else if (e.key === "Escape") { onClose(); }
};
if (!open) return null;
// group items
const groups = items.reduce((acc, it, idx) => {
(acc[it.group] = acc[it.group] || []).push({ ...it, idx });
return acc;
}, {});
return (
<div onClick={onClose} style={{
position: "fixed", inset: 0, zIndex: 100,
background: "color-mix(in srgb, #000 60%, transparent)",
backdropFilter: "blur(6px)",
display: "flex",
alignItems: "flex-start",
justifyContent: "center",
paddingTop: "12vh",
animation: "float-up 0.2s",
}}>
<div onClick={e => e.stopPropagation()} style={{
width: "min(640px, 92vw)",
background: "var(--bg-card)",
border: "1px solid var(--line-strong)",
borderRadius: 14,
boxShadow: "var(--shadow-lg)",
overflow: "hidden",
}}>
<div style={{
display: "flex",
alignItems: "center",
gap: 10,
padding: "14px 18px",
borderBottom: "1px solid var(--line)",
}}>
<Icons.Search size={15} style={{ color: "var(--text-faint)" }} />
<input
ref={inputRef}
value={q}
onChange={e => setQ(e.target.value)}
onKeyDown={onKey}
placeholder="Search projects, sections, actions…"
style={{
flex: 1,
background: "transparent",
border: "none",
outline: "none",
color: "var(--text)",
fontSize: 15,
fontFamily: "inherit",
}}
/>
<kbd style={{
fontFamily: "var(--font-mono)",
fontSize: 11,
padding: "2px 6px",
border: "1px solid var(--line)",
borderRadius: 4,
color: "var(--text-faint)",
}}>esc</kbd>
</div>
<div style={{ maxHeight: 420, overflowY: "auto", padding: 8 }}>
{items.length === 0 && (
<div style={{ padding: 24, textAlign: "center", color: "var(--text-faint)", fontSize: 13 }}>
No matches for "{q}"
</div>
)}
{Object.entries(groups).map(([group, gitems]) => (
<div key={group} style={{ marginBottom: 8 }}>
<div style={{
padding: "10px 12px 6px",
fontFamily: "var(--font-mono)",
fontSize: 10.5,
color: "var(--text-faint)",
textTransform: "uppercase",
letterSpacing: "0.08em",
}}>{group}</div>
{gitems.map(it => {
const I = it.icon;
const on = it.idx === active;
return (
<button
key={it.label}
onMouseEnter={() => setActive(it.idx)}
onClick={() => { it.action(); onClose(); }}
style={{
width: "100%",
display: "flex",
alignItems: "center",
gap: 12,
padding: "10px 12px",
background: on ? "var(--bg-elev)" : "transparent",
border: "none",
borderRadius: 8,
color: "var(--text)",
fontSize: 13.5,
textAlign: "left",
}}>
<I size={14} style={{ color: on ? "var(--accent)" : "var(--text-faint)" }} />
<span style={{ flex: 1 }}>{it.label}</span>
{it.sub && <span style={{ fontSize: 11, color: "var(--text-faint)" }}>{it.sub}</span>}
{on && <Icons.Arrow size={12} style={{ color: "var(--text-faint)" }} />}
</button>
);
})}
</div>
))}
</div>
<div style={{
display: "flex",
gap: 16,
padding: "10px 16px",
borderTop: "1px solid var(--line)",
background: "var(--bg-elev)",
fontSize: 11,
fontFamily: "var(--font-mono)",
color: "var(--text-faint)",
}}>
<span> navigate</span>
<span> select</span>
<span>esc dismiss</span>
</div>
</div>
</div>
);
};
window.CommandPalette = CommandPalette;
+195
View File
@@ -0,0 +1,195 @@
// Content for the portfolio
const PORTFOLIO_DATA = {
brand: {
name: "Aura Agentic AI",
handle: "@aura",
title: "Agentic AI & Full-Stack Development",
titleBn: "এজেন্টিক এআই ও ফুল-স্ট্যাক ডেভেলপমেন্ট",
tagline: "We build AI agents, automation & enterprise systems that work 24/7.",
taglineBn: "আমরা AI এজেন্ট, অটোমেশন ও এন্টারপ্রাইজ সিস্টেম তৈরি করি যা ২৪/৭ কাজ করে।",
location: "Dhaka, Bangladesh · Remote",
yearsExp: 7,
email: "hello@auraajenticai.cloud",
domain: "auraajenticai.cloud",
socials: {
github: "https://github.com",
linkedin: "https://linkedin.com",
twitter: "https://twitter.com",
},
},
metrics: [
{ label: "Years shipping", value: "7+" },
{ label: "Agents in production", value: "40+" },
{ label: "Enterprise clients", value: "12" },
{ label: "Uptime maintained", value: "99.98%" },
],
about: {
pitch: "I build the systems that act on behalf of teams — agents that triage, route, decide, and execute. The work spans the full stack: model orchestration, eval harnesses, queue infrastructure, dashboards, on-chain settlement, and the tedious connective tissue that turns a clever demo into something a CFO will sign off on.",
bullets: [
"Designed agent runtimes for fintech & MLM platforms moving 8-figure GMV",
"Built orchestration layers across OpenAI, Anthropic, vLLM, and self-hosted models",
"Shipped Web3 settlement rails — wallets, signers, on-chain audit trails",
"Lead architect on three SaaS dashboards now serving 50k+ daily users",
],
},
stack: {
Frontend: [
{ name: "React", level: 98 },
{ name: "Next.js", level: 96 },
{ name: "TypeScript", level: 95 },
{ name: "Tailwind", level: 94 },
{ name: "Framer Motion", level: 88 },
],
Backend: [
{ name: "Node.js", level: 96 },
{ name: "Python · FastAPI", level: 92 },
{ name: "PostgreSQL", level: 94 },
{ name: "Supabase", level: 90 },
{ name: "Redis · BullMQ", level: 88 },
],
"AI / Agents": [
{ name: "LangGraph", level: 95 },
{ name: "OpenAI · Anthropic", level: 96 },
{ name: "Vector DBs", level: 90 },
{ name: "Eval harnesses", level: 86 },
{ name: "Tool routing", level: 92 },
],
"Web3": [
{ name: "Solidity", level: 84 },
{ name: "ethers · viem", level: 90 },
{ name: "Wallet integrations", level: 92 },
{ name: "On-chain indexing", level: 80 },
],
DevOps: [
{ name: "Docker", level: 92 },
{ name: "AWS · GCP", level: 88 },
{ name: "Vercel · Fly.io", level: 94 },
{ name: "GitHub Actions", level: 90 },
{ name: "Observability", level: 86 },
],
},
services: [
{
id: "web-app-dev",
name: "Website & Webapp Development",
nameBn: "ওয়েবসাইট ও ওয়েবঅ্যাপ ডেভেলপমেন্ট",
kind: "Core Service",
description:
"From landing pages to full SaaS dashboards — pixel-perfect, fast, and built to scale. SvelteKit, Next.js, React, Tailwind.",
stack: ["SvelteKit", "Next.js", "React", "Tailwind", "PostgreSQL"],
impact: { primary: "50k+", secondary: "daily users served" },
color: "violet",
},
{
id: "ai-agent-automation",
name: "AI Agent & Automation",
nameBn: "এআই এজেন্ট ও অটোমেশন",
kind: "Core Service",
description:
"Custom AI agents that triage, decide, and execute — integrated with your tools via n8n, Anthropic, and OpenAI.",
stack: ["Anthropic Claude", "n8n", "LangGraph", "Node.js", "Hono"],
impact: { primary: "1.2M+", secondary: "agent runs / month" },
color: "cyan",
},
{
id: "web3-blockchain",
name: "Web3 & Blockchain",
nameBn: "ওয়েব৩ ও ব্লকচেইন",
kind: "Specialist Service",
description:
"Wallets, smart contracts, multi-chain bridges, and on-chain audit trails. Gasless UX that hides complexity from end users.",
stack: ["Solidity", "viem", "wagmi", "Cloudflare Workers"],
impact: { primary: "12 chains", secondary: "EVM + Solana" },
color: "green",
},
{
id: "mt5-ea-trading",
name: "MT5 EA & Trading Automation",
nameBn: "MT5 EA ও ট্রেডিং অটোমেশন",
kind: "Specialist Service",
description:
"Expert Advisors, real-time P&L dashboards, risk envelopes, and one-click kill switches for MetaTrader 5 platforms.",
stack: ["MQL5", "Go", "ClickHouse", "WebSockets", "React"],
impact: { primary: "<80ms", secondary: "tick-to-render latency" },
color: "amber",
},
{
id: "scraping-data-pipeline",
name: "Browser Scraping & Data Pipeline",
nameBn: "ব্রাউজার স্ক্র্যাপিং ও ডেটা পাইপলাইন",
kind: "Specialist Service",
description:
"Playwright/Puppeteer scrapers, proxy rotation, structured data extraction, and ETL pipelines into your DB or warehouse.",
stack: ["Playwright", "Puppeteer", "Python", "Airflow", "PostgreSQL"],
impact: { primary: "10M+", secondary: "records extracted / month" },
color: "violet",
},
{
id: "infra-devops",
name: "Infrastructure & DevOps",
nameBn: "ইনফ্রাস্ট্রাকচার ও ডেভঅপস",
kind: "Specialist Service",
description:
"VPS setup, Docker, Coolify, Traefik, CI/CD pipelines, SSL, monitoring, and zero-downtime deploys on your own cloud.",
stack: ["Docker", "Coolify", "Traefik", "GitHub Actions", "PostgreSQL"],
impact: { primary: "99.98%", secondary: "uptime maintained" },
color: "cyan",
},
],
agentRun: [
{ t: 0, kind: "system", text: "agent.session :: id=run_8af3e2 model=claude-sonnet-4.5" },
{ t: 350, kind: "user", text: 'task: "Reconcile yesterday\'s payouts. Flag anything > $5k or > 3σ from the cohort baseline."' },
{ t: 1200, kind: "thought", text: "Decompose → fetch payouts, compute cohort baseline (μ, σ), filter, draft reconciliation note." },
{ t: 1900, kind: "tool", tool: "postgres.query", text: "SELECT id, member_id, amount, created_at FROM payouts WHERE day = $1", status: "ok", meta: "1,284 rows · 42ms" },
{ t: 2700, kind: "tool", tool: "math.stats", text: "compute(μ=412.30, σ=187.40, n=1284)", status: "ok", meta: "8ms" },
{ t: 3400, kind: "tool", tool: "slack.notify", text: '#finance-ops · "12 outliers flagged for review"', status: "ok", meta: "delivered" },
{ t: 4100, kind: "thought", text: "All checks passed. Drafting reconciliation summary for the CFO digest." },
{ t: 4900, kind: "output", text: "Reconciliation complete. 12 outliers flagged · 1 above-threshold (member_4419 · $7,420). Audit trail written." },
{ t: 5400, kind: "system", text: "session.end :: tokens=8,412 · cost=$0.083 · duration=5.4s" },
],
experience: [
{
year: "2024 — Present",
role: "Founder & Principal Engineer",
company: "Aura Agentic Cloud",
kind: "Product",
detail: "Building the agent runtime layer — orchestration, evals, observability — used by 12 enterprise teams.",
},
{
year: "2022 — 2024",
role: "Staff Full-Stack Engineer",
company: "Confidential · Fintech",
kind: "Contract",
detail: "Led the rebuild of an MLM compensation engine, ran the migration from monolith to multi-tenant.",
},
{
year: "2021 — 2022",
role: "Senior Engineer · Web3",
company: "Stealth DeFi protocol",
kind: "Contract",
detail: "Wallet UX, signer abstraction, on-chain settlement rails. Shipped before the protocol announced.",
},
{
year: "2019 — 2021",
role: "Full-Stack Engineer",
company: "Series-B SaaS",
kind: "Full-time",
detail: "Owned the dashboard surface area — billing, RBAC, integrations. Pushed app from 4k to 28k DAU.",
},
{
year: "2018 — 2019",
role: "Software Engineer",
company: "Agency · Remote",
kind: "Full-time",
detail: "Cut my teeth shipping React + Node products across e-commerce, logistics, and edtech.",
},
],
};
window.PORTFOLIO_DATA = PORTFOLIO_DATA;
+304
View File
@@ -0,0 +1,304 @@
// Hero — flowing terminal/code background + bold headline
const TerminalRain = () => {
// A column of streaming code lines that drift upward forever.
// Two columns offset so the loop is seamless.
const lines = React.useMemo(() => {
const samples = [
"import { Agent } from '@aura/runtime'",
"export const triage = new Agent({",
" model: 'claude-sonnet-4.5',",
" tools: [postgres, slack, stripe],",
" policy: 'tier-1-support',",
"})",
"",
"// orchestrator.ts",
"const run = await graph.invoke({",
" task: 'reconcile payouts',",
" context: { day: '2026-04-26' },",
"})",
"",
"→ tool.call postgres.query ok 42ms",
"→ tool.call math.stats ok 8ms",
"→ tool.call slack.notify ok 120ms",
"✓ run completed tokens=8412 $0.083",
"",
"contract Settlement {",
" function release(address to, uint256 amt)",
" external onlyOwner returns (bool) {",
" require(escrow[to] >= amt, 'insufficient');",
" escrow[to] -= amt;",
" payable(to).transfer(amt);",
" emit Released(to, amt, block.timestamp);",
" return true;",
" }",
"}",
"",
"[runtime] cold-start agent pool …",
"[runtime] 24 agents warmed in 312ms",
"[runtime] queue depth=0 p50=84ms p99=410ms",
"",
"POST /v1/runs 201 Created",
"GET /v1/runs/run_8af3e2 200 OK",
"POST /v1/tools/register 201 Created",
];
return [...samples, ...samples];
}, []);
const colorFor = (line) => {
if (line.startsWith("//")) return "var(--text-faint)";
if (line.startsWith("→")) return "var(--accent-2)";
if (line.startsWith("✓")) return "var(--good)";
if (line.startsWith("[runtime]")) return "var(--text-faint)";
if (line.match(/^(POST|GET|PUT|DELETE)/)) return "var(--accent)";
if (line.match(/^(import|export|const|function|return|contract|require|emit)/)) return "var(--accent)";
return "var(--text-dim)";
};
return (
<div aria-hidden="true" style={{
position: "absolute",
inset: 0,
overflow: "hidden",
pointerEvents: "none",
maskImage: "radial-gradient(ellipse 90% 70% at 50% 40%, black 35%, transparent 75%)",
WebkitMaskImage: "radial-gradient(ellipse 90% 70% at 50% 40%, black 35%, transparent 75%)",
opacity: 0.55,
}}>
{/* faint grid */}
<div style={{
position: "absolute",
inset: 0,
backgroundImage: `
linear-gradient(var(--line) 1px, transparent 1px),
linear-gradient(90deg, var(--line) 1px, transparent 1px)
`,
backgroundSize: "60px 60px",
opacity: 0.5,
}} />
{/* streaming columns */}
{[0, 1, 2].map(col => (
<div key={col} style={{
position: "absolute",
top: 0,
left: `${15 + col * 28}%`,
width: 320,
fontFamily: "var(--font-mono)",
fontSize: 11.5,
lineHeight: 1.9,
animation: `scroll-y ${28 + col * 6}s linear infinite`,
animationDelay: `${col * -8}s`,
}}>
{lines.map((l, i) => (
<div key={i} style={{
color: colorFor(l),
opacity: 0.7 + (Math.sin((i + col * 7) * 0.7) * 0.3),
whiteSpace: "pre",
}}>{l || "\u00A0"}</div>
))}
</div>
))}
{/* accent glow blobs */}
<div style={{
position: "absolute",
top: "20%", left: "10%",
width: 400, height: 400,
borderRadius: "50%",
background: "radial-gradient(circle, var(--accent-glow), transparent 70%)",
filter: "blur(40px)",
}} />
<div style={{
position: "absolute",
bottom: "10%", right: "8%",
width: 500, height: 500,
borderRadius: "50%",
background: "radial-gradient(circle, color-mix(in srgb, var(--accent-2) 20%, transparent), transparent 70%)",
filter: "blur(60px)",
}} />
</div>
);
};
const Hero = ({ headlinePrefix, headlineSuffix, lang = "en" }) => {
const D = PORTFOLIO_DATA;
const prefix = headlinePrefix || "Agentic AI &";
const suffix = headlineSuffix || "automation engineer";
return (
<section id="top" style={{
position: "relative",
minHeight: "100vh",
paddingTop: 96,
paddingBottom: 80,
display: "flex",
alignItems: "center",
overflow: "hidden",
}}>
<TerminalRain />
<div className="container" style={{ position: "relative", zIndex: 1 }}>
{/* status pill */}
<div style={{
display: "inline-flex",
alignItems: "center",
gap: 10,
padding: "6px 12px 6px 10px",
background: "color-mix(in srgb, var(--bg-card) 80%, transparent)",
border: "1px solid var(--line)",
backdropFilter: "blur(6px)",
borderRadius: 999,
fontSize: 12.5,
color: "var(--text-dim)",
marginBottom: 32,
}}>
<span style={{
width: 7, height: 7, borderRadius: "50%",
background: "var(--good)",
boxShadow: "0 0 10px var(--good)",
animation: "pulse-dot 2s infinite",
}} />
Accepting new projects · Q3 2026
</div>
{/* headline */}
<h1 style={{
fontFamily: "var(--font-sans)",
fontSize: "clamp(44px, 7.2vw, 96px)",
fontWeight: 500,
lineHeight: 0.98,
letterSpacing: "-0.04em",
margin: 0,
maxWidth: 980,
}}>
{prefix}<br/>
<span style={{ fontFamily: "var(--font-serif)", fontStyle: "italic", fontWeight: 400 }}>full-stack</span>{" "}
<span style={{
background: "linear-gradient(110deg, var(--accent), var(--accent-2))",
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
backgroundClip: "text",
}}>{suffix}</span>.
</h1>
{/* sub */}
<p style={{
marginTop: 28,
maxWidth: 620,
fontSize: 18,
lineHeight: 1.55,
color: "var(--text-dim)",
}}>
{D.brand.tagline}
</p>
<p style={{
marginTop: 8,
maxWidth: 620,
fontSize: 14,
lineHeight: 1.6,
color: "var(--text-faint)",
fontFamily: "var(--font-sans)",
}}>
{D.brand.taglineBn}
</p>
{/* CTAs */}
<div style={{ display: "flex", gap: 12, marginTop: 40, flexWrap: "wrap" }}>
<a href="#work" style={{
display: "inline-flex",
alignItems: "center",
gap: 8,
padding: "12px 20px",
background: "var(--text)",
color: "var(--bg)",
fontSize: 14,
fontWeight: 500,
borderRadius: 10,
transition: "transform 0.15s",
}}
onMouseEnter={e => e.currentTarget.style.transform = "translateY(-1px)"}
onMouseLeave={e => e.currentTarget.style.transform = "none"}
>
View Services <Icons.Arrow size={14} />
</a>
<a href="#contact" style={{
display: "inline-flex",
alignItems: "center",
gap: 8,
padding: "12px 20px",
background: "transparent",
color: "var(--text)",
fontSize: 14,
fontWeight: 500,
border: "1px solid var(--line-strong)",
borderRadius: 10,
textDecoration: "none",
}}>
Get a Quote <Icons.ArrowUpRight size={14} />
</a>
</div>
{/* tiny meta row */}
<div style={{
display: "flex",
gap: 28,
marginTop: 80,
flexWrap: "wrap",
fontSize: 12.5,
color: "var(--text-faint)",
fontFamily: "var(--font-mono)",
}}>
<span>{D.brand.location}</span>
<span>·</span>
<span>{D.brand.domain}</span>
<span>·</span>
<span>Last shipped: 2 days ago</span>
</div>
{/* metric strip */}
<div style={{
marginTop: 56,
display: "grid",
gridTemplateColumns: "repeat(4, 1fr)",
gap: 0,
borderTop: "1px solid var(--line)",
borderBottom: "1px solid var(--line)",
}} className="metric-strip">
{D.metrics.map((m, i) => (
<div key={m.label} style={{
padding: "24px 20px",
borderRight: i < D.metrics.length - 1 ? "1px solid var(--line)" : "none",
}}>
<div style={{
fontSize: "clamp(28px, 3.4vw, 40px)",
fontWeight: 500,
letterSpacing: "-0.02em",
lineHeight: 1,
}}>{m.value}</div>
<div style={{
marginTop: 8,
fontSize: 12,
color: "var(--text-faint)",
fontFamily: "var(--font-mono)",
textTransform: "uppercase",
letterSpacing: "0.06em",
}}>{m.label}</div>
</div>
))}
</div>
<style>{`
@media (max-width: 720px) {
.metric-strip { grid-template-columns: repeat(2, 1fr) !important; }
.metric-strip > div:nth-child(2) { border-right: none !important; }
.metric-strip > div:nth-child(1), .metric-strip > div:nth-child(2) {
border-bottom: 1px solid var(--line);
}
}
`}</style>
</div>
</section>
);
};
window.Hero = Hero;
+60
View File
@@ -0,0 +1,60 @@
// Inline SVG icons — single stroke, 1.5px, sized 1em via currentColor
const Icon = ({ d, size = 16, fill, stroke = "currentColor", strokeWidth = 1.5, children, viewBox = "0 0 24 24", style }) => (
<svg
width={size}
height={size}
viewBox={viewBox}
fill={fill || "none"}
stroke={stroke}
strokeWidth={strokeWidth}
strokeLinecap="round"
strokeLinejoin="round"
style={style}
>
{d ? <path d={d} /> : children}
</svg>
);
const Icons = {
Sun: (p) => <Icon {...p}><circle cx="12" cy="12" r="4" /><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" /></Icon>,
Moon: (p) => <Icon {...p}><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" /></Icon>,
Command: (p) => <Icon {...p}><path d="M18 3a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3H6a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3V6a3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3h12a3 3 0 0 0 3-3 3 3 0 0 0-3-3z" /></Icon>,
Arrow: (p) => <Icon {...p}><path d="M5 12h14M13 5l7 7-7 7" /></Icon>,
ArrowUpRight: (p) => <Icon {...p}><path d="M7 17 17 7M8 7h9v9" /></Icon>,
Github: (p) => <Icon {...p}><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" /></Icon>,
LinkedIn: (p) => <Icon {...p}><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-4 0v7h-4v-7a6 6 0 0 1 6-6zM2 9h4v12H2zM4 6a2 2 0 1 0 0-4 2 2 0 0 0 0 4z" /></Icon>,
Twitter: (p) => <Icon {...p}><path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z" /></Icon>,
Mail: (p) => <Icon {...p}><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" /><path d="m22 6-10 7L2 6" /></Icon>,
Sparkles: (p) => <Icon {...p}><path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1" /></Icon>,
Bolt: (p) => <Icon {...p}><path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" /></Icon>,
Code: (p) => <Icon {...p}><path d="m16 18 6-6-6-6M8 6l-6 6 6 6" /></Icon>,
Cube: (p) => <Icon {...p}><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" /><path d="m3.27 6.96 8.73 5.05 8.73-5.05M12 22.08V12" /></Icon>,
Cpu: (p) => <Icon {...p}><rect x="4" y="4" width="16" height="16" rx="2" /><rect x="9" y="9" width="6" height="6" /><path d="M9 1v3M15 1v3M9 20v3M15 20v3M20 9h3M20 14h3M1 9h3M1 14h3" /></Icon>,
Server: (p) => <Icon {...p}><rect x="2" y="2" width="20" height="8" rx="2" /><rect x="2" y="14" width="20" height="8" rx="2" /><path d="M6 6h.01M6 18h.01" /></Icon>,
Database: (p) => <Icon {...p}><ellipse cx="12" cy="5" rx="9" ry="3" /><path d="M3 5v14c0 1.7 4 3 9 3s9-1.3 9-3V5M3 12c0 1.7 4 3 9 3s9-1.3 9-3" /></Icon>,
Cloud: (p) => <Icon {...p}><path d="M17.5 19a4.5 4.5 0 1 0-1.4-8.78 7 7 0 1 0-12.05 5.78" /></Icon>,
Box: (p) => <Icon {...p}><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16zM7.5 4.21l9 5.19M3.27 6.96 12 12.01l8.73-5.05M12 22.08V12" /></Icon>,
Wallet: (p) => <Icon {...p}><path d="M21 12V7H5a2 2 0 0 1 0-4h14v4" /><path d="M3 5v14a2 2 0 0 0 2 2h16v-5" /><path d="M18 12a2 2 0 0 0 0 4h4v-4z" /></Icon>,
Zap: (p) => <Icon {...p}><path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" /></Icon>,
Layers: (p) => <Icon {...p}><path d="m12 2 10 6.5-10 6.5L2 8.5 12 2z" /><path d="m2 17.5 10 6.5 10-6.5M2 13l10 6.5L22 13" /></Icon>,
Check: (p) => <Icon {...p}><path d="m20 6-11 11-5-5" /></Icon>,
Dot: (p) => <Icon {...p}><circle cx="12" cy="12" r="3" fill="currentColor" /></Icon>,
Search: (p) => <Icon {...p}><circle cx="11" cy="11" r="8" /><path d="m21 21-4.35-4.35" /></Icon>,
Send: (p) => <Icon {...p}><path d="m22 2-7 20-4-9-9-4 20-7z" /></Icon>,
Globe: (p) => <Icon {...p}><circle cx="12" cy="12" r="10" /><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" /></Icon>,
Terminal: (p) => <Icon {...p}><path d="m4 17 6-6-6-6M12 19h8" /></Icon>,
Logo: ({ size = 28 }) => (
<svg width={size} height={size} viewBox="0 0 32 32" fill="none">
<defs>
<linearGradient id="logoG" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse">
<stop stopColor="var(--accent)" />
<stop offset="1" stopColor="var(--accent-2)" />
</linearGradient>
</defs>
<rect x="2" y="2" width="28" height="28" rx="8" fill="none" stroke="url(#logoG)" strokeWidth="1.5" />
<path d="M10 22 L16 8 L22 22 M12.5 17 H19.5" stroke="url(#logoG)" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" fill="none" />
</svg>
),
};
window.Icons = Icons;
+163
View File
@@ -0,0 +1,163 @@
// Top nav — minimal, sticky, blurred
const Nav = ({ onCmdK, theme, onToggleTheme, accent, lang, onToggleLang }) => {
const [scrolled, setScrolled] = React.useState(false);
React.useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 12);
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
const links = [
{ id: "work", label: "Services" },
{ id: "stack", label: "Stack" },
{ id: "agents", label: "Agents" },
{ id: "timeline", label: "Timeline" },
{ id: "contact", label: "Contact" },
];
return (
<nav style={{
position: "fixed",
top: 0,
left: 0,
right: 0,
zIndex: 50,
borderBottom: scrolled ? "1px solid var(--line)" : "1px solid transparent",
background: scrolled ? "color-mix(in srgb, var(--bg) 75%, transparent)" : "transparent",
backdropFilter: scrolled ? "blur(14px)" : "none",
WebkitBackdropFilter: scrolled ? "blur(14px)" : "none",
transition: "all 0.25s ease",
}}>
<div className="container" style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
height: 64,
}}>
{/* Brand */}
<a href="#top" style={{ display: "flex", alignItems: "center", gap: 10 }}>
<Icons.Logo size={26} />
<span style={{ fontWeight: 600, fontSize: 15, letterSpacing: "-0.01em" }}>{PORTFOLIO_DATA.brand.name}</span>
<span style={{
fontFamily: "var(--font-mono)",
fontSize: 11,
color: "var(--text-faint)",
padding: "2px 7px",
border: "1px solid var(--line)",
borderRadius: 999,
marginLeft: 4,
}}>v.2026</span>
</a>
{/* Center links */}
<div style={{ display: "flex", gap: 4, alignItems: "center" }} className="nav-links">
{links.map(l => (
<a key={l.id} href={`#${l.id}`} style={{
fontSize: 13.5,
color: "var(--text-dim)",
padding: "6px 12px",
borderRadius: 8,
transition: "all 0.15s",
}}
onMouseEnter={e => { e.currentTarget.style.color = "var(--text)"; e.currentTarget.style.background = "var(--line)"; }}
onMouseLeave={e => { e.currentTarget.style.color = "var(--text-dim)"; e.currentTarget.style.background = "transparent"; }}
>{l.label}</a>
))}
</div>
{/* Right: ⌘K, theme, hire */}
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<button onClick={onCmdK} style={{
display: "flex",
alignItems: "center",
gap: 8,
padding: "6px 8px 6px 12px",
background: "transparent",
border: "1px solid var(--line)",
borderRadius: 8,
color: "var(--text-dim)",
fontSize: 12.5,
}}>
<Icons.Search size={13} />
<span>Search</span>
<kbd style={{
fontFamily: "var(--font-mono)",
fontSize: 10.5,
padding: "2px 5px",
border: "1px solid var(--line)",
borderRadius: 4,
color: "var(--text-faint)",
}}>K</kbd>
</button>
<button onClick={onToggleTheme} aria-label="Toggle theme" style={{
width: 34, height: 34,
display: "grid", placeItems: "center",
background: "transparent",
border: "1px solid var(--line)",
borderRadius: 8,
color: "var(--text-dim)",
}}>
{theme === "dark" ? <Icons.Sun size={15} /> : <Icons.Moon size={15} />}
</button>
{/* EN/BN toggle */}
<button onClick={onToggleLang} style={{
padding: "6px 10px",
background: "transparent",
border: "1px solid var(--line)",
borderRadius: 8,
color: "var(--text-dim)",
fontSize: 12,
fontWeight: 600,
cursor: "pointer",
letterSpacing: "0.04em",
}}>
{lang === "en" ? "বাং" : "EN"}
</button>
{/* Get a Quote */}
<a href="mailto:hello@auraajenticai.cloud?subject=Project Quote" style={{
padding: "7px 13px",
background: "transparent",
border: "1px solid var(--line)",
borderRadius: 8,
color: "var(--text-dim)",
fontSize: 13,
fontWeight: 500,
textDecoration: "none",
whiteSpace: "nowrap",
}}>
Get a Quote
</a>
{/* Client Login */}
<a href="https://auth.auraajenticai.cloud/login" style={{
display: "flex",
alignItems: "center",
gap: 6,
padding: "8px 14px",
background: "var(--text)",
color: "var(--bg)",
fontSize: 13,
fontWeight: 500,
borderRadius: 8,
textDecoration: "none",
whiteSpace: "nowrap",
}}>
Client Login <Icons.Arrow size={13} />
</a>
</div>
</div>
<style>{`
@media (max-width: 880px) {
.nav-links { display: none !important; }
}
`}</style>
</nav>
);
};
window.Nav = Nav;
+332
View File
@@ -0,0 +1,332 @@
// Projects — SaaS-card grid with featured first
const colorMap = {
violet: { bg: "rgba(124, 92, 255, 0.08)", border: "rgba(124, 92, 255, 0.25)", text: "#a18bff" },
cyan: { bg: "rgba(0, 212, 255, 0.08)", border: "rgba(0, 212, 255, 0.25)", text: "#5ee0ff" },
green: { bg: "rgba(74, 222, 128, 0.08)", border: "rgba(74, 222, 128, 0.25)", text: "#7ee8a3" },
amber: { bg: "rgba(251, 191, 36, 0.08)", border: "rgba(251, 191, 36, 0.25)", text: "#fcd34d" },
};
const ProjectCard = ({ p }) => {
const tint = colorMap[p.color] || colorMap.violet;
const [hover, setHover] = React.useState(false);
return (
<article
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
style={{
position: "relative",
gridColumn: "span 1",
background: "var(--bg-card)",
border: "1px solid var(--line)",
borderRadius: 16,
overflow: "hidden",
cursor: "pointer",
transition: "all 0.25s ease",
transform: hover ? "translateY(-2px)" : "none",
boxShadow: hover ? `0 24px 60px -20px ${tint.border}` : "none",
}}>
{/* hover sheen */}
<div style={{
position: "absolute",
inset: 0,
background: `radial-gradient(circle at 30% 0%, ${tint.bg}, transparent 60%)`,
opacity: hover ? 1 : 0.5,
transition: "opacity 0.25s",
pointerEvents: "none",
}} />
{/* Decorative top — small visual specific to service type */}
<div style={{
position: "relative",
height: 160,
borderBottom: "1px solid var(--line)",
overflow: "hidden",
background: `linear-gradient(180deg, color-mix(in srgb, ${tint.text} 8%, var(--bg-card)), var(--bg-card))`,
}}>
<ProjectVisual id={p.id} tint={tint} hover={hover} />
<div style={{
position: "absolute",
top: 16, left: 16,
display: "flex",
alignItems: "center",
gap: 8,
padding: "5px 10px",
background: "color-mix(in srgb, var(--bg) 60%, transparent)",
backdropFilter: "blur(6px)",
border: `1px solid ${tint.border}`,
borderRadius: 999,
fontSize: 11,
fontFamily: "var(--font-mono)",
color: tint.text,
textTransform: "uppercase",
letterSpacing: "0.06em",
}}>
<span style={{ width: 6, height: 6, borderRadius: "50%", background: tint.text }} />
{p.kind}
</div>
<div style={{
position: "absolute",
top: 16, right: 16,
fontFamily: "var(--font-mono)",
fontSize: 11,
color: tint.text,
padding: "2px 8px",
background: tint.bg,
border: `1px solid ${tint.border}`,
borderRadius: 4,
}}>{p.kind}</div>
</div>
<div style={{ padding: 24, position: "relative" }}>
<h3 style={{
margin: 0,
fontSize: 20,
fontWeight: 500,
letterSpacing: "-0.02em",
}}>{p.name}</h3>
{p.nameBn && (
<div style={{
marginTop: 4,
fontSize: 12,
color: "var(--text-faint)",
fontFamily: "var(--font-sans)",
}}>{p.nameBn}</div>
)}
<p style={{
marginTop: 12,
marginBottom: 20,
fontSize: 14,
lineHeight: 1.55,
color: "var(--text-dim)",
}}>{p.description}</p>
{/* Stack badges */}
<div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 20 }}>
{p.stack.map(s => (
<span key={s} style={{
padding: "4px 10px",
background: "var(--bg-elev)",
border: "1px solid var(--line)",
borderRadius: 6,
fontFamily: "var(--font-mono)",
fontSize: 11,
color: "var(--text-dim)",
}}>{s}</span>
))}
</div>
{/* Footer: impact + actions */}
<div style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
paddingTop: 18,
borderTop: "1px solid var(--line)",
gap: 12,
}}>
<div>
<div style={{
fontSize: featured ? 22 : 18,
fontWeight: 500,
letterSpacing: "-0.01em",
color: tint.text,
}}>{p.impact.primary}</div>
<div style={{
marginTop: 2,
fontSize: 11,
fontFamily: "var(--font-mono)",
color: "var(--text-faint)",
textTransform: "uppercase",
letterSpacing: "0.06em",
}}>{p.impact.secondary}</div>
</div>
<div style={{ display: "flex", gap: 6 }}>
<button style={{
width: 34, height: 34,
display: "grid", placeItems: "center",
background: "transparent",
border: "1px solid var(--line)",
borderRadius: 8,
color: "var(--text-dim)",
}} title="GitHub"><Icons.Github size={14} /></button>
<button style={{
padding: "0 14px", height: 34,
display: "inline-flex", alignItems: "center", gap: 6,
background: "var(--text)",
color: "var(--bg)",
border: "none",
borderRadius: 8,
fontSize: 13,
fontWeight: 500,
}}>Demo <Icons.ArrowUpRight size={12} /></button>
</div>
</div>
</div>
</article>
);
};
// Tiny SVG visual per service — gives each card a distinct "product preview"
const ProjectVisual = ({ id, tint, hover }) => {
if (id === "ai-agent-automation") {
return (
<svg viewBox="0 0 600 220" style={{ width: "100%", height: "100%", position: "absolute", inset: 0 }}>
<defs>
<linearGradient id="aura-g" x1="0" x2="1">
<stop stopColor={tint.text} stopOpacity="0.6"/>
<stop offset="1" stopColor={tint.text} stopOpacity="0.05"/>
</linearGradient>
</defs>
{/* nodes */}
{[
[120, 60], [220, 110], [320, 70], [420, 130], [500, 90],
[180, 160], [280, 180], [380, 50], [460, 180],
].map(([x, y], i) => (
<g key={i}>
<circle cx={x} cy={y} r="4" fill={tint.text} opacity="0.9" />
<circle cx={x} cy={y} r="14" fill={tint.text} opacity={hover ? 0.18 : 0.08}>
<animate attributeName="r" from="4" to="22" dur={`${2 + i*0.3}s`} repeatCount="indefinite" />
<animate attributeName="opacity" from="0.25" to="0" dur={`${2 + i*0.3}s`} repeatCount="indefinite" />
</circle>
</g>
))}
{/* connectors */}
<g stroke={tint.text} strokeOpacity="0.35" strokeWidth="1" fill="none">
<path d="M120,60 L220,110 L320,70 L420,130 L500,90"/>
<path d="M180,160 L280,180 L380,50 L460,180"/>
<path d="M120,60 L180,160 M220,110 L280,180 M320,70 L380,50 M420,130 L460,180"/>
</g>
</svg>
);
}
if (id === "scraping-data-pipeline") {
// bar chart
const bars = [40, 64, 52, 78, 92, 70, 110, 95, 130, 118, 142];
return (
<svg viewBox="0 0 600 160" style={{ width: "100%", height: "100%", position: "absolute", inset: 0 }} preserveAspectRatio="xMidYMid meet">
{bars.map((h, i) => (
<rect key={i} x={50 + i*45} y={150 - h} width="22" height={h} rx="3" fill={tint.text} opacity={0.4 + i*0.05}>
<animate attributeName="height" from="0" to={h} dur="0.8s" begin={`${i*0.05}s`} fill="freeze" />
<animate attributeName="y" from="150" to={150-h} dur="0.8s" begin={`${i*0.05}s`} fill="freeze" />
</rect>
))}
<line x1="40" y1="150" x2="580" y2="150" stroke={tint.border} />
</svg>
);
}
if (id === "web3-blockchain") {
// chain dots
const chains = ["ETH","ARB","OP","BASE","SOL","ZK","POL","BNB","AVAX","CELO","XLM","TRX"];
return (
<div style={{ position: "absolute", inset: 0, display: "grid", gridTemplateColumns: "repeat(6, 1fr)", padding: 24, gap: 8, alignContent: "center" }}>
{chains.map((c, i) => (
<div key={c} style={{
padding: "8px 0",
textAlign: "center",
border: `1px solid ${tint.border}`,
borderRadius: 6,
fontFamily: "var(--font-mono)",
fontSize: 11,
color: tint.text,
background: tint.bg,
animation: `float-up 0.5s ${i*0.04}s both`,
}}>{c}</div>
))}
</div>
);
}
if (id === "mt5-ea-trading") {
// line chart
return (
<svg viewBox="0 0 600 160" style={{ width: "100%", height: "100%", position: "absolute", inset: 0 }}>
<defs>
<linearGradient id="ea-g" x1="0" y1="0" x2="0" y2="1">
<stop stopColor={tint.text} stopOpacity="0.4"/>
<stop offset="1" stopColor={tint.text} stopOpacity="0"/>
</linearGradient>
</defs>
<path d="M0,110 L60,90 L120,100 L180,70 L240,80 L300,55 L360,70 L420,40 L480,55 L540,30 L600,45 L600,160 L0,160 Z" fill="url(#ea-g)" />
<path d="M0,110 L60,90 L120,100 L180,70 L240,80 L300,55 L360,70 L420,40 L480,55 L540,30 L600,45" stroke={tint.text} strokeWidth="1.5" fill="none" />
{[60,180,300,420,540].map((x, i) => (
<circle key={i} cx={x} cy={[90,70,55,40,30][i]} r="3" fill={tint.text} />
))}
</svg>
);
}
if (id === "web-app-dev") {
// schema → grid morph
return (
<svg viewBox="0 0 600 200" style={{ width: "100%", height: "100%", position: "absolute", inset: 0 }}>
{/* schema box */}
<g transform="translate(60, 50)">
<rect width="160" height="100" rx="8" fill="none" stroke={tint.border} />
{[20, 40, 60, 80].map(y => <line key={y} x1="12" y1={y} x2="148" y2={y} stroke={tint.border} strokeOpacity="0.5" strokeDasharray="2 2" />)}
{[20, 40, 60, 80].map(y => <rect key={y} x="14" y={y-4} width="60" height="6" fill={tint.text} opacity="0.4" rx="1" />)}
</g>
{/* arrow */}
<g transform="translate(240, 90)" stroke={tint.text} fill="none" strokeWidth="1.5">
<line x1="0" y1="10" x2="80" y2="10" />
<polyline points="70,4 80,10 70,16" />
</g>
{/* dashboard grid */}
<g transform="translate(360, 30)">
<rect width="200" height="140" rx="8" fill={tint.bg} stroke={tint.border} />
<rect x="12" y="12" width="80" height="36" rx="4" fill={tint.text} opacity="0.5" />
<rect x="100" y="12" width="88" height="36" rx="4" fill={tint.text} opacity="0.3" />
<rect x="12" y="56" width="176" height="72" rx="4" fill={tint.text} opacity="0.18" />
</g>
</svg>
);
}
if (id === "infra-devops") {
// chat bubbles
return (
<div style={{ position: "absolute", inset: 0, padding: "20px 28px", display: "flex", flexDirection: "column", gap: 8, justifyContent: "center", fontFamily: "var(--font-mono)", fontSize: 11 }}>
<div style={{ alignSelf: "flex-start", padding: "8px 12px", background: "var(--bg-elev)", border: "1px solid var(--line)", borderRadius: 12, color: "var(--text-dim)", maxWidth: "70%" }}>How do I rotate my API key?</div>
<div style={{ alignSelf: "flex-end", padding: "8px 12px", background: tint.bg, border: `1px solid ${tint.border}`, borderRadius: 12, color: tint.text, maxWidth: "70%" }}>Settings API Rotate. New key live in &lt;5s.</div>
<div style={{ alignSelf: "flex-start", padding: "8px 12px", background: "var(--bg-elev)", border: "1px solid var(--line)", borderRadius: 12, color: "var(--text-dim)", maxWidth: "70%", display: "flex", gap: 4, alignItems: "center" }}>
<span style={{ width: 4, height: 4, borderRadius: "50%", background: "var(--text-dim)", animation: "pulse-dot 1.2s infinite" }} />
<span style={{ width: 4, height: 4, borderRadius: "50%", background: "var(--text-dim)", animation: "pulse-dot 1.2s 0.2s infinite" }} />
<span style={{ width: 4, height: 4, borderRadius: "50%", background: "var(--text-dim)", animation: "pulse-dot 1.2s 0.4s infinite" }} />
</div>
</div>
);
}
return null;
};
const Projects = () => {
const D = PORTFOLIO_DATA;
return (
<section id="work" style={{ padding: "120px 0", borderTop: "1px solid var(--line)" }}>
<div className="container">
<SectionHeader
eyebrow="What we build"
num="03 / 06"
title={<>Six services. One team. All <span style={{ fontFamily: "var(--font-serif)", fontStyle: "italic", fontWeight: 400 }}>production-grade</span>.</>}
sub="From landing pages to AI agent runtimes — we take your idea from spec to live deployment."
/>
<div style={{
display: "grid",
gridTemplateColumns: "repeat(2, 1fr)",
gap: 16,
}} className="proj-grid">
{D.services.map(p => <ProjectCard key={p.id} p={p} />)}
</div>
<style>{`
@media (max-width: 880px) {
.proj-grid { grid-template-columns: 1fr !important; }
.proj-grid > article { grid-column: span 1 !important; }
}
`}</style>
</div>
</section>
);
};
window.Projects = Projects;
+242
View File
@@ -0,0 +1,242 @@
// SectionHeader + About + Skills (interactive tabs)
const SectionHeader = ({ eyebrow, title, sub, num }) => (
<div style={{ marginBottom: 56 }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 18 }}>
<span className="eyebrow">{eyebrow}</span>
{num && <span style={{
fontFamily: "var(--font-mono)",
fontSize: 11,
color: "var(--text-faint)",
}}>{num}</span>}
</div>
<h2 style={{
fontSize: "clamp(32px, 4.6vw, 54px)",
fontWeight: 500,
letterSpacing: "-0.03em",
lineHeight: 1.05,
margin: 0,
maxWidth: 820,
}}>{title}</h2>
{sub && <p style={{
marginTop: 18,
fontSize: 17,
lineHeight: 1.55,
color: "var(--text-dim)",
maxWidth: 640,
}}>{sub}</p>}
</div>
);
const About = () => {
const D = PORTFOLIO_DATA;
return (
<section id="about" style={{ padding: "120px 0", borderTop: "1px solid var(--line)" }}>
<div className="container">
<SectionHeader
eyebrow="About"
num="01 / 06"
title={<>I architect the systems that act not the demos that <span style={{ fontFamily: "var(--font-serif)", fontStyle: "italic", fontWeight: 400 }}>impress</span>.</>}
/>
<div style={{
display: "grid",
gridTemplateColumns: "1.4fr 1fr",
gap: 48,
alignItems: "start",
}} className="about-grid">
<div>
<p style={{
fontSize: 18,
lineHeight: 1.65,
color: "var(--text-dim)",
margin: 0,
}}>{D.about.pitch}</p>
<ul style={{
marginTop: 32,
padding: 0,
listStyle: "none",
display: "grid",
gap: 14,
}}>
{D.about.bullets.map((b, i) => (
<li key={i} style={{
display: "flex",
gap: 14,
fontSize: 15,
lineHeight: 1.55,
color: "var(--text)",
}}>
<span style={{
flex: "0 0 auto",
marginTop: 8,
width: 18, height: 1,
background: "var(--accent)",
}} />
<span>{b}</span>
</li>
))}
</ul>
</div>
{/* Side card: at a glance */}
<div className="panel" style={{ padding: 28 }}>
<div className="eyebrow" style={{ marginBottom: 20 }}>At a glance</div>
<div style={{ display: "grid", gap: 16 }}>
{[
["Discipline", "Agentic systems · Full-stack"],
["Years", `${D.brand.yearsExp}+ shipping`],
["Stack range", "TS · Python · Solidity"],
["Working with", "Founders · CTOs · Platform leads"],
["Engagement", "Embedded · Lead architect"],
["Location", D.brand.location],
].map(([k, v]) => (
<div key={k} style={{
display: "grid",
gridTemplateColumns: "110px 1fr",
gap: 16,
fontSize: 13.5,
paddingBottom: 14,
borderBottom: "1px solid var(--line)",
}}>
<span style={{ color: "var(--text-faint)", fontFamily: "var(--font-mono)", fontSize: 11.5, textTransform: "uppercase", letterSpacing: "0.06em", paddingTop: 2 }}>{k}</span>
<span style={{ color: "var(--text)" }}>{v}</span>
</div>
))}
</div>
<a href="#contact" style={{
display: "inline-flex",
alignItems: "center",
gap: 8,
marginTop: 8,
fontSize: 13,
color: "var(--accent)",
}}>
Start a conversation <Icons.ArrowUpRight size={13} />
</a>
</div>
</div>
<style>{`
@media (max-width: 880px) {
.about-grid { grid-template-columns: 1fr !important; gap: 32px !important; }
}
`}</style>
</div>
</section>
);
};
const Skills = () => {
const D = PORTFOLIO_DATA;
const cats = Object.keys(D.stack);
const [active, setActive] = React.useState(cats[0]);
const items = D.stack[active];
const catIcon = {
"Frontend": Icons.Code,
"Backend": Icons.Server,
"AI / Agents": Icons.Sparkles,
"Web3": Icons.Wallet,
"DevOps": Icons.Cloud,
};
return (
<section id="stack" style={{ padding: "120px 0", borderTop: "1px solid var(--line)" }}>
<div className="container">
<SectionHeader
eyebrow="Stack"
num="02 / 06"
title="Tools I reach for, weighted by reps."
sub="Numbers are honest signal — not a vanity bar. They reflect production hours, not tutorials watched."
/>
{/* Category tabs */}
<div style={{
display: "flex",
gap: 6,
padding: 6,
background: "var(--bg-card)",
border: "1px solid var(--line)",
borderRadius: 12,
width: "fit-content",
flexWrap: "wrap",
marginBottom: 32,
}}>
{cats.map(c => {
const I = catIcon[c];
const on = active === c;
return (
<button key={c} onClick={() => setActive(c)} style={{
display: "flex",
alignItems: "center",
gap: 8,
padding: "9px 14px",
background: on ? "var(--bg-elev)" : "transparent",
color: on ? "var(--text)" : "var(--text-dim)",
border: on ? "1px solid var(--line-strong)" : "1px solid transparent",
borderRadius: 8,
fontSize: 13,
fontWeight: 500,
transition: "all 0.15s",
}}>
<I size={13} /> {c}
</button>
);
})}
</div>
{/* Items */}
<div style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
gap: 12,
}}>
{items.map((s, i) => (
<div key={s.name} className="panel" style={{
padding: "20px 22px",
animation: `float-up 0.5s ${i * 0.05}s both`,
}}>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 14 }}>
<span style={{ fontSize: 14.5, fontWeight: 500 }}>{s.name}</span>
<span style={{
fontFamily: "var(--font-mono)",
fontSize: 11,
color: "var(--text-faint)",
}}>{s.level}</span>
</div>
<div style={{
height: 3,
background: "var(--line)",
borderRadius: 2,
overflow: "hidden",
position: "relative",
}}>
<div style={{
width: `${s.level}%`,
height: "100%",
background: "linear-gradient(90deg, var(--accent), var(--accent-2))",
borderRadius: 2,
animation: `grow-w 0.9s ${0.1 + i * 0.04}s both cubic-bezier(0.2,0.8,0.2,1)`,
transformOrigin: "left",
}} />
</div>
</div>
))}
</div>
<style>{`
@keyframes grow-w {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
`}</style>
</div>
</section>
);
};
window.About = About;
window.Skills = Skills;
window.SectionHeader = SectionHeader;
+535
View File
@@ -0,0 +1,535 @@
// Timeline + Contact + Footer
const Timeline = () => {
const D = PORTFOLIO_DATA;
return (
<section id="timeline" style={{ padding: "120px 0", borderTop: "1px solid var(--line)" }}>
<div className="container">
<SectionHeader
eyebrow="Trajectory"
num="05 / 06"
title="Seven years, one through-line: shipping systems that work in production."
/>
<div style={{ position: "relative", paddingLeft: 32 }}>
{/* spine */}
<div style={{
position: "absolute",
left: 7, top: 6, bottom: 6,
width: 1,
background: "linear-gradient(180deg, var(--accent), var(--line) 80%)",
}} />
{D.experience.map((e, i) => (
<div key={i} style={{
position: "relative",
paddingBottom: i < D.experience.length - 1 ? 40 : 0,
animation: `float-up 0.5s ${i * 0.08}s both`,
}}>
{/* node */}
<div style={{
position: "absolute",
left: -32,
top: 4,
width: 15, height: 15,
borderRadius: "50%",
background: "var(--bg)",
border: `2px solid ${i === 0 ? "var(--accent)" : "var(--line-strong)"}`,
boxShadow: i === 0 ? "0 0 16px var(--accent-glow)" : "none",
}}>
{i === 0 && <div style={{
position: "absolute",
inset: 2,
borderRadius: "50%",
background: "var(--accent)",
animation: "pulse-dot 2s infinite",
}} />}
</div>
<div style={{
display: "grid",
gridTemplateColumns: "180px 1fr",
gap: 32,
alignItems: "start",
}} className="tl-row">
<div>
<div style={{
fontFamily: "var(--font-mono)",
fontSize: 11.5,
color: "var(--text-faint)",
textTransform: "uppercase",
letterSpacing: "0.06em",
}}>{e.year}</div>
<span style={{
display: "inline-block",
marginTop: 8,
padding: "2px 8px",
border: "1px solid var(--line)",
borderRadius: 4,
fontSize: 10.5,
color: "var(--text-dim)",
fontFamily: "var(--font-mono)",
}}>{e.kind}</span>
</div>
<div>
<h3 style={{
margin: 0,
fontSize: 19,
fontWeight: 500,
letterSpacing: "-0.01em",
}}>{e.role}</h3>
<div style={{
marginTop: 4,
fontSize: 14,
color: "var(--accent-2)",
}}>{e.company}</div>
<p style={{
marginTop: 10,
marginBottom: 0,
fontSize: 14,
lineHeight: 1.6,
color: "var(--text-dim)",
maxWidth: 600,
}}>{e.detail}</p>
</div>
</div>
</div>
))}
</div>
<style>{`
@media (max-width: 720px) {
.tl-row { grid-template-columns: 1fr !important; gap: 8px !important; }
}
`}</style>
</div>
</section>
);
};
const Contact = ({ lang = "en" }) => {
const D = PORTFOLIO_DATA;
const [form, setForm] = React.useState({ name: "", email: "", service: "", budget: "", message: "" });
const [errors, setErrors] = React.useState({});
const [status, setStatus] = React.useState("idle"); // idle | sending | sent
const SERVICES = [
"Website & Webapp Development",
"AI Agent & Automation",
"Web3 & Blockchain",
"MT5 EA & Trading Automation",
"Browser Scraping & Data Pipeline",
"Infrastructure & DevOps",
];
const BUDGETS = ["< $500", "$500 $2,000", "$2,000 $5,000", "$5,000 $15,000", "$15,000+"];
const validate = () => {
const e = {};
if (!form.name.trim()) e.name = "Required";
if (!form.email.trim()) e.email = "Required";
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email)) e.email = "Not a valid email";
if (!form.service) e.service = "Please pick a service";
if (!form.message.trim()) e.message = "Tell us about the project";
else if (form.message.trim().length < 12) e.message = "A few more words please";
return e;
};
const submit = async (ev) => {
ev.preventDefault();
const e = validate();
setErrors(e);
if (Object.keys(e).length) return;
setStatus("sending");
try {
await fetch("https://n8n.auraajenticai.cloud/webhook/contact", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(form),
});
setStatus("sent");
} catch {
setStatus("idle");
setErrors({ message: "Network error — please email us directly." });
}
};
const Field = ({ id, label, type = "text", as = "input", placeholder }) => {
const Tag = as;
const hasErr = errors[id];
return (
<label style={{ display: "block" }}>
<div style={{
display: "flex",
justifyContent: "space-between",
marginBottom: 8,
fontSize: 12,
fontFamily: "var(--font-mono)",
color: hasErr ? "var(--danger)" : "var(--text-faint)",
textTransform: "uppercase",
letterSpacing: "0.06em",
}}>
<span>{label}</span>
{hasErr && <span>{hasErr}</span>}
</div>
<Tag
type={type}
value={form[id]}
onChange={(ev) => setForm(f => ({ ...f, [id]: ev.target.value }))}
placeholder={placeholder}
rows={as === "textarea" ? 5 : undefined}
style={{
width: "100%",
background: "var(--bg-elev)",
color: "var(--text)",
border: `1px solid ${hasErr ? "var(--danger)" : "var(--line)"}`,
borderRadius: 10,
padding: "12px 14px",
fontSize: 14,
fontFamily: "var(--font-sans)",
resize: as === "textarea" ? "vertical" : "none",
outline: "none",
transition: "border 0.15s",
}}
onFocus={(ev) => ev.target.style.borderColor = hasErr ? "var(--danger)" : "var(--accent)"}
onBlur={(ev) => ev.target.style.borderColor = hasErr ? "var(--danger)" : "var(--line)"}
/>
</label>
);
};
const SelectField = ({ id, label, options, required = false }) => {
const hasErr = errors[id];
return (
<label style={{ display: "block" }}>
<div style={{
display: "flex",
justifyContent: "space-between",
marginBottom: 8,
fontSize: 12,
fontFamily: "var(--font-mono)",
color: hasErr ? "var(--danger)" : "var(--text-faint)",
textTransform: "uppercase",
letterSpacing: "0.06em",
}}>
<span>{label}</span>
{hasErr && <span>{hasErr}</span>}
</div>
<select
value={form[id]}
onChange={(ev) => setForm(f => ({ ...f, [id]: ev.target.value }))}
style={{
width: "100%",
background: "var(--bg-elev)",
color: form[id] ? "var(--text)" : "var(--text-faint)",
border: `1px solid ${hasErr ? "var(--danger)" : "var(--line)"}`,
borderRadius: 10,
padding: "12px 14px",
fontSize: 14,
fontFamily: "var(--font-sans)",
outline: "none",
transition: "border 0.15s",
cursor: "pointer",
}}
onFocus={(ev) => ev.target.style.borderColor = hasErr ? "var(--danger)" : "var(--accent)"}
onBlur={(ev) => ev.target.style.borderColor = hasErr ? "var(--danger)" : "var(--line)"}
>
<option value="">Select</option>
{options.map(o => <option key={o} value={o}>{o}</option>)}
</select>
</label>
);
};
return (
<section id="contact" style={{ padding: "120px 0", borderTop: "1px solid var(--line)" }}>
<div className="container">
<SectionHeader
eyebrow="Contact"
num="06 / 06"
title={<>Have a project that needs to <span style={{ fontFamily: "var(--font-serif)", fontStyle: "italic", fontWeight: 400 }}>actually ship</span>?</>}
sub="Tell us what you're building — we'll respond within 24 hours with a plan and a quote."
/>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 48, alignItems: "start" }} className="contact-grid">
{/* form */}
<form onSubmit={submit} className="panel" style={{ padding: 32, display: "grid", gap: 18 }}>
{status === "sent" ? (
<div style={{ textAlign: "center", padding: "40px 20px" }}>
<div style={{
width: 56, height: 56,
margin: "0 auto 20px",
borderRadius: "50%",
background: "color-mix(in srgb, var(--good) 15%, transparent)",
border: "1px solid var(--good)",
display: "grid", placeItems: "center",
color: "var(--good)",
}}><Icons.Check size={26} /></div>
<h3 style={{ margin: 0, fontSize: 22, fontWeight: 500, letterSpacing: "-0.02em" }}>
{lang === "en" ? "We'll be in touch!" : "বার্তা পাঠানো হয়েছে!"}
</h3>
<p style={{ marginTop: 10, color: "var(--text-dim)", fontSize: 14 }}>
{lang === "en"
? "We'll get back to you within 24 hours!"
: "আমরা ২৪ ঘণ্টার মধ্যে যোগাযোগ করবো!"}
</p>
<button type="button" onClick={() => { setForm({ name: "", email: "", service: "", budget: "", message: "" }); setStatus("idle"); }} style={{
marginTop: 20,
padding: "8px 16px",
background: "transparent",
color: "var(--text-dim)",
border: "1px solid var(--line)",
borderRadius: 8,
fontSize: 13,
cursor: "pointer",
}}>{lang === "en" ? "Send another" : "আবার পাঠান"}</button>
</div>
) : (
<>
<Field id="name" label="Name" placeholder="Your name" />
<Field id="email" label="Email" type="email" placeholder="you@company.com" />
<SelectField id="service" label="Service" options={SERVICES} required />
<SelectField id="budget" label="Budget (optional)" options={BUDGETS} />
<Field id="message" label="Project Brief" as="textarea" placeholder="What are you trying to build, and where are you stuck?" />
<button type="submit" disabled={status === "sending"} style={{
marginTop: 4,
padding: "12px 18px",
background: "var(--text)",
color: "var(--bg)",
border: "none",
borderRadius: 10,
fontSize: 14,
fontWeight: 500,
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
gap: 8,
opacity: status === "sending" ? 0.6 : 1,
cursor: status === "sending" ? "wait" : "pointer",
}}>
{status === "sending" ? "Sending…" : <>Send message <Icons.Send size={13} /></>}
</button>
</>
)}
</form>
{/* meta + chatbot teaser */}
<div style={{ display: "grid", gap: 16 }}>
<div className="panel" style={{ padding: 28 }}>
<div className="eyebrow" style={{ marginBottom: 18 }}>Direct</div>
<a href={`mailto:${D.brand.email}`} style={{
fontSize: 22,
fontWeight: 500,
letterSpacing: "-0.02em",
display: "inline-flex",
alignItems: "center",
gap: 10,
}}>
<Icons.Mail size={18} /> {D.brand.email}
</a>
<div style={{ marginTop: 24, display: "flex", gap: 8 }}>
{[
{ i: Icons.Github, l: "GitHub", h: D.brand.socials.github },
{ i: Icons.LinkedIn, l: "LinkedIn", h: D.brand.socials.linkedin },
{ i: Icons.Twitter, l: "Twitter", h: D.brand.socials.twitter },
].map(({ i: I, l, h }) => (
<a key={l} href={h} title={l} style={{
width: 40, height: 40,
display: "grid", placeItems: "center",
border: "1px solid var(--line)",
borderRadius: 8,
color: "var(--text-dim)",
transition: "all 0.15s",
}}
onMouseEnter={ev => { ev.currentTarget.style.color = "var(--text)"; ev.currentTarget.style.borderColor = "var(--line-strong)"; }}
onMouseLeave={ev => { ev.currentTarget.style.color = "var(--text-dim)"; ev.currentTarget.style.borderColor = "var(--line)"; }}
><I size={15} /></a>
))}
</div>
</div>
<ChatbotWidget />
</div>
</div>
<style>{`
@media (max-width: 880px) {
.contact-grid { grid-template-columns: 1fr !important; gap: 24px !important; }
}
`}</style>
</div>
</section>
);
};
const ChatbotWidget = () => {
const [msgs, setMsgs] = React.useState([
{ role: "bot", text: "Ask me anything about the work — projects, stack choices, timelines." },
]);
const [input, setInput] = React.useState("");
const [thinking, setThinking] = React.useState(false);
const scrollRef = React.useRef(null);
React.useEffect(() => {
if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}, [msgs, thinking]);
const reply = async (q) => {
setThinking(true);
try {
const text = await window.claude.complete(
`You are a concise portfolio assistant for Aura, a senior agentic AI & full-stack engineer with 7+ years experience. Domains: AI agents, Web3, MLM/EA dashboards, full-stack. Answer in 1-3 sentences, professional but friendly. Question: ${q}`
);
setMsgs(m => [...m, { role: "bot", text }]);
} catch (e) {
setMsgs(m => [...m, { role: "bot", text: "Aura's offline — drop a note via the form and I'll reply within 48h." }]);
}
setThinking(false);
};
const send = () => {
const q = input.trim();
if (!q) return;
setMsgs(m => [...m, { role: "user", text: q }]);
setInput("");
reply(q);
};
return (
<div className="panel" style={{ padding: 0, overflow: "hidden" }}>
<div style={{
padding: "16px 20px",
borderBottom: "1px solid var(--line)",
display: "flex",
alignItems: "center",
gap: 10,
}}>
<div style={{
width: 28, height: 28,
display: "grid", placeItems: "center",
borderRadius: 7,
background: "var(--accent-glow)",
color: "var(--accent)",
}}><Icons.Sparkles size={14} /></div>
<div>
<div style={{ fontSize: 13.5, fontWeight: 500 }}>Ask about my work</div>
<div style={{ fontSize: 11, color: "var(--text-faint)", fontFamily: "var(--font-mono)" }}>powered by claude · live</div>
</div>
<span style={{
marginLeft: "auto",
fontSize: 10.5,
padding: "2px 8px",
background: "color-mix(in srgb, var(--good) 15%, transparent)",
color: "var(--good)",
border: "1px solid color-mix(in srgb, var(--good) 30%, transparent)",
borderRadius: 999,
fontFamily: "var(--font-mono)",
textTransform: "uppercase",
letterSpacing: "0.06em",
}}>online</span>
</div>
<div ref={scrollRef} style={{
padding: 16,
height: 200,
overflowY: "auto",
display: "flex",
flexDirection: "column",
gap: 10,
fontSize: 13,
}}>
{msgs.map((m, i) => (
<div key={i} style={{
alignSelf: m.role === "user" ? "flex-end" : "flex-start",
maxWidth: "85%",
padding: "8px 12px",
background: m.role === "user" ? "var(--accent)" : "var(--bg-elev)",
color: m.role === "user" ? "white" : "var(--text)",
border: m.role === "user" ? "none" : "1px solid var(--line)",
borderRadius: 12,
lineHeight: 1.5,
}}>{m.text}</div>
))}
{thinking && (
<div style={{
alignSelf: "flex-start",
padding: "8px 12px",
background: "var(--bg-elev)",
border: "1px solid var(--line)",
borderRadius: 12,
display: "flex", gap: 4, alignItems: "center",
}}>
{[0,1,2].map(i => (
<span key={i} style={{
width: 5, height: 5, borderRadius: "50%",
background: "var(--text-faint)",
animation: `pulse-dot 1.2s ${i * 0.15}s infinite`,
}} />
))}
</div>
)}
</div>
<form onSubmit={(e) => { e.preventDefault(); send(); }} style={{
display: "flex",
gap: 8,
padding: 12,
borderTop: "1px solid var(--line)",
background: "var(--bg-elev)",
}}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Ask about a project, stack, or timeline…"
style={{
flex: 1,
background: "var(--bg-card)",
color: "var(--text)",
border: "1px solid var(--line)",
borderRadius: 8,
padding: "9px 12px",
fontSize: 13,
fontFamily: "inherit",
outline: "none",
}}
/>
<button type="submit" style={{
padding: "0 12px",
background: "var(--text)",
color: "var(--bg)",
border: "none",
borderRadius: 8,
fontSize: 12,
fontWeight: 500,
display: "flex", alignItems: "center", gap: 6,
}}><Icons.Send size={12} /></button>
</form>
</div>
);
};
const Footer = () => {
const D = PORTFOLIO_DATA;
return (
<footer style={{
borderTop: "1px solid var(--line)",
padding: "48px 0 32px",
}}>
<div className="container" style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
flexWrap: "wrap",
gap: 16,
}}>
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
<Icons.Logo size={22} />
<span style={{ fontSize: 13, color: "var(--text-dim)" }}>{D.brand.name} · {D.brand.domain}</span>
</div>
<div style={{ fontSize: 12, color: "var(--text-faint)", fontFamily: "var(--font-mono)" }}>
© 2026 Built with intent.
</div>
</div>
</footer>
);
};
window.Timeline = Timeline;
window.Contact = Contact;
window.Footer = Footer;