// Writing: bilingual blog index (/writing) + single article (/writing/) const LINKEDIN_URL = "https://www.linkedin.com/in/vlad-tudor-18090a1a2"; function articleBySlug(slug) { return (window.BLOG || []).find((a) => a.slug === slug) || null; } function isCoverGraphic(src) { return typeof src === "string" && src.endsWith(".svg"); } // Article URLs are two-segment (/writing/), so relative "assets/..." paths // would resolve against /writing/. Force root-absolute so images load everywhere. function blogAsset(src) { return typeof src === "string" && src.indexOf("assets/") === 0 ? "/" + src : src; } // Writing copy in a given language, falling back to the passed copy. function writingCopy(lang, fallback) { return (window.CONTENT && window.CONTENT[lang] && window.CONTENT[lang].writing) || fallback; } // Minimal inline **bold** rendering for body/list/table/faq text. function renderRich(text) { if (typeof text !== "string" || text.indexOf("**") === -1) return text; return text.split("**").map((part, i) => (i % 2 === 1 ? {part} : part)); } function ArticleMeta({ a }) { return (
{a.dateLabel} {a.readingMins} min {a.tags && a.tags.length > 0 && ( {a.tags.slice(0, 3).join(" / ")} )}
); } function ArticleCard({ a }) { const href = "/writing/" + a.slug; return ( { e.preventDefault(); goTo(href); }}>
{a.dateLabel} {a.tags && a.tags[0] && {a.tags[0]}}

{a.title}

{a.dek}

Read
); } function LangToggle({ lang, onPick }) { return (
{["en", "ro"].map((l) => ( ))}
); } function FeaturedCard({ a }) { const href = "/writing/" + a.slug; return ( { e.preventDefault(); goTo(href); }}>
Latest
{a.dateLabel} {a.readingMins} min {a.tags && a.tags[0] && {a.tags[0]}}

{a.title}

{a.dek}

Read the essay
); } function WritingIndex({ c }) { const [lang, setLang] = React.useState(() => { try { return localStorage.getItem("blogLang") || "en"; } catch (e) { return "en"; } }); const pick = (l) => { setLang(l); try { localStorage.setItem("blogLang", l); } catch (e) {} }; const wc = writingCopy(lang, c); const list = (window.BLOG || []). filter((a) => (a.lang || "en") === lang). sort((a, b) => (a.date < b.date ? 1 : -1)); const featured = list[0] || null; const rest = featured ? list.slice(1) : list; return (
{wc.eyebrow}

{wc.title}

{wc.lead}

{featured && }
{wc.cta_more}
{rest.map((a) => )}
); } function ArticleBlock({ b }) { switch (b.t) { case "h": case "h2": return

{b.x}

; case "h3": return

{b.x}

; case "ul": return ( ); case "table": return (
{b.headers.map((h, i) => )} {b.rows.map((r, ri) => {r.map((cell, ci) => )})}
{renderRich(h)}
{renderRich(cell)}
); case "img": return (
{b.alt {b.cap &&
{b.cap}
}
); case "quote": return ; default: return

{renderRich(b.x)}

; } } function ReadingProgress() { const [p, setP] = React.useState(0); React.useEffect(() => { const onScroll = () => { const h = document.documentElement; const max = (h.scrollHeight - h.clientHeight) || 1; setP(Math.min(1, Math.max(0, (h.scrollTop || window.scrollY || 0) / max))); }; window.addEventListener("scroll", onScroll, { passive: true }); window.addEventListener("resize", onScroll); onScroll(); return () => { window.removeEventListener("scroll", onScroll); window.removeEventListener("resize", onScroll); }; }, []); return (