/* global React */ const { useState, useEffect, useRef } = React; /* ============================================================ Reveal-on-scroll wrapper ============================================================ */ function Reveal({ children, as = "div", delay = 0, className = "", ...rest }) { const ref = useRef(null); const [visible, setVisible] = useState(false); useEffect(() => { const el = ref.current; if (!el) return; // Fallback: if IO doesn't fire within ~600ms (sandboxed iframes, certain // preview environments), reveal anyway so content is never stuck invisible. const fallback = setTimeout(() => setVisible(true), 600); let io; try { io = new IntersectionObserver( (entries) => { entries.forEach((e) => { if (e.isIntersecting) { setVisible(true); clearTimeout(fallback); io.unobserve(el); } }); }, { threshold: 0.12, rootMargin: "0px 0px -60px 0px" } ); io.observe(el); } catch (_) { setVisible(true); } return () => {clearTimeout(fallback);io && io.disconnect();}; }, []); const Tag = as; const cls = ["reveal", visible ? "in" : "", delay ? `reveal-delay-${delay}` : "", className]. filter(Boolean). join(" "); return ( {children} ); } /* ============================================================ NAV ============================================================ */ function Nav({ theme, onToggleTheme }) { return ( kolber.tech / .NET + React Engineer · Product Owner 01 — Stack 02 — Work 03 — Education 04 — About 05 — Now {theme === "dark" ? "Dark" : "Light"} Contact ↗ ); } /* ============================================================ HERO with role toggle ============================================================ */ const ROLES = [ { key: "engineer", label: "Senior Software Engineer", num: "01", blurb: "Architecting and shipping production .NET and React systems — distributed architectures with Microsoft Orleans, Terraform-managed Azure, and code that holds up under audit.", stats: [ { num: ".NET 9", label: "C# 13 in prod" }, { num: "React 18", label: "TypeScript first" }, { num: "Azure", label: "Terraform · Orleans" }] }, { key: "po", label: "Product Owner", num: "02", blurb: "Translating stakeholder ambition into a backlog the team can actually build — sharp acceptance criteria, ruthless prioritisation, and a refinement cadence that doesn't burn out.", stats: [ { num: "4", label: "Dev team size" }, { num: "40+", label: "Releases shipped" }, { num: "DDD", label: "Domain modelling" }, { num: "Agile", label: "Scrum · Confluence" }] }]; function Hero() { const [active, setActive] = useState("engineer"); const [paused, setPaused] = useState(false); const role = ROLES.find((r) => r.key === active); // Auto-cycle every 10s; pauses if the user clicks a chip. useEffect(() => { if (paused) return; const id = setInterval(() => { setActive((curr) => { const idx = ROLES.findIndex((r) => r.key === curr); return ROLES[(idx + 1) % ROLES.length].key; }); }, 10000); return () => clearInterval(id); }, [paused]); const pickRole = (key) => { setActive(key); setPaused(true); }; return ( KRAKÓW, POLAND · CET · POLISH (NATIVE) / ENGLISH C2 Marcin Kolber {ROLES.map((r) => pickRole(r.key)} role="tab" aria-selected={active === r.key}> {r.num} {r.label} )} In this role {role.blurb} {role.stats.map((s, i) => {/^\d/.test(s.num) ? <> {s.num.match(/^\d+/)[0]} {s.num.replace(/^\d+/, "")} > : s.num } {s.label} )} ); } Object.assign(window, { Reveal, Nav, Hero });
{role.blurb}