// Eu Faço Parte — Sections part 2: O que fazemos / Apoio a projetos / Iniciativas / Stats / Mapa / Ações const ApoioProjetos = () => (
01 · {t('apoio.eyebrow')}

{t('apoio.p1')}

"

{t('apoio.p2')}

{t('apoio.cta')}
{ const ph = document.createElement('div'); ph.className = 'ph oque-ph'; ph.dataset.label = '— Projetos · iniciativas locais'; e.currentTarget.replaceWith(ph); }} />
{t('apoio.cap1')}
{ const ph = document.createElement('div'); ph.className = 'ph oque-ph'; ph.dataset.label = '— Projetos · peneira esportiva'; e.currentTarget.replaceWith(ph); }} />
{t('apoio.cap2')}
); // ---- Initiatives grid ---- // Nomes traduzidos inline (não no dicionário i18n.jsx, mantém auto-suficiente) const initiatives = [ { names: { pt: 'Surf Sagi', en: 'Surf Sagi', it: 'Surf Sagi', de: 'Surf Sagi' }, slug: 'surf-sagi', file: 'projeto-surf-sagi.html', img: 'images/iniciativa-surf-sagi.jpg' }, { names: { pt: 'Artesanato & Brinquedos', en: 'Crafts & Toys', it: 'Artigianato & Giocattoli', de: 'Kunsthandwerk & Spielzeug' }, slug: 'artesanato', file: 'projeto-artesanato.html', img: 'images/iniciativa-artesanato.jpg' }, { names: { pt: 'Sagi Vidas', en: 'Sagi Lives', it: 'Sagi Vidas', de: 'Sagi Vidas' }, slug: 'sagi-vidas', file: 'projeto-sagi-vidas.html', img: 'images/iniciativa-sagi-vidas.jpg' }, { names: { pt: 'Sonhos em Campo', en: 'Dreams on the Field', it: 'Sogni in Campo', de: 'Träume auf dem Feld' }, slug: 'sonhos-campo', file: 'projeto-sonhos-campo.html', img: 'images/iniciativa-sonhos-campo.png' }, { names: { pt: 'Juntos nós Cuidamos', en: 'Together We Care', it: 'Insieme ci prendiamo cura', de: 'Gemeinsam sorgen wir' }, slug: 'juntos', file: 'projeto-juntos.html', img: 'images/iniciativa-juntos.png' }, { names: { pt: 'Abrigo ANCA & Educação Profissional', en: 'ANCA Shelter & Vocational Education', it: 'Rifugio ANCA & Formazione professionale', de: 'ANCA-Unterkunft & Berufsausbildung' }, slug: 'anca', file: 'projeto-anca.html', img: 'images/iniciativa-anca.jpg' }, { names: { pt: 'Roupas & Memórias', en: 'Clothes & Memories', it: 'Vestiti & Memorie', de: 'Kleidung & Erinnerungen' }, slug: 'roupas', file: 'projeto-roupas.html', img: 'images/iniciativa-roupas.jpg' }, { names: { pt: 'Dia das Crianças para 300 jovens', en: "Children's Day for 300 young people", it: 'Giornata dei Bambini per 300 giovani', de: 'Kindertag für 300 junge Menschen' }, slug: 'dia-criancas', file: 'projeto-dia-criancas.html', img: 'https://eufacoparte.org/uploads/2024/05/Imagem-do-WhatsApp-de-2024-03-25-as-09.06.40_924bb40f.jpg' }, { names: { pt: 'O direito de celebrar', en: 'The right to celebrate', it: 'Il diritto di festeggiare', de: 'Das Recht zu feiern' }, slug: 'celebrar', file: 'projeto-celebrar.html', img: 'https://eufacoparte.org/uploads/2024/05/Imagem-do-WhatsApp-de-2024-05-17-as-15.50.26_13059e0d-1.jpg' }, { names: { pt: 'Memórias Afetivas e Saudáveis na Cozinha', en: 'Healthy Memories in the Kitchen', it: 'Memorie Affettive in Cucina', de: 'Liebevolle Erinnerungen in der Küche' }, slug: 'cozinha', file: 'projeto-cozinha.html', img: 'https://eufacoparte.org/uploads/2024/05/Imagem-do-WhatsApp-de-2024-04-21-as-16.35.53_ad5169b4.jpg' }, ]; const Initiatives = () => { const VISIBLE = 4, GAP = 20, DUR = 520; const total = initiatives.length; const LEAD = VISIBLE; const extended = [ ...initiatives.slice(-LEAD), ...initiatives, ...initiatives.slice(0, LEAD), ]; const [idx, setIdx] = React.useState(LEAD); const [anim, setAnim] = React.useState(false); const [containerW, setContainerW] = React.useState(0); const [paused, setPaused] = React.useState(false); const wrapRef = React.useRef(null); const timerRef = React.useRef(null); React.useLayoutEffect(() => { if (!wrapRef.current) return; const ro = new ResizeObserver(([e]) => setContainerW(e.contentRect.width)); ro.observe(wrapRef.current); setContainerW(wrapRef.current.offsetWidth); return () => ro.disconnect(); }, []); const cardW = containerW ? (containerW - GAP * (VISIBLE - 1)) / VISIBLE : 0; const step = cardW + GAP; const goto = (newIdx, animate) => { setAnim(animate); setIdx(newIdx); }; const advance = React.useCallback(() => { setAnim(true); setIdx(prev => { const next = prev + 1; if (next >= LEAD + total) setTimeout(() => goto(LEAD, false), DUR + 16); return next; }); }, [LEAD, total, DUR]); const retreat = () => { setAnim(true); setIdx(prev => { const next = prev - 1; if (next < LEAD) setTimeout(() => goto(LEAD + total - 1, false), DUR + 16); return next; }); }; React.useEffect(() => { if (paused) return; timerRef.current = setInterval(advance, 3500); return () => clearInterval(timerRef.current); }, [advance, paused]); const translateX = -idx * step; const currentDot = ((idx - LEAD) % total + total) % total; return (
01.1 · {t('iniciativas.eyebrow')}
setPaused(true)} onMouseLeave={() => setPaused(false)} >
{extended.map((it, i) => { const name = it.names[window.LANG] || it.names.en || it.names.pt; return (
{name}

{name}

{t('iniciativas.cta')} →
); })}
{initiatives.map((_, i) => { const name = initiatives[i].names[window.LANG] || initiatives[i].names.en || initiatives[i].names.pt; return (
); }; // ---- Stats count-up ---- const CountUp = ({ numStr, duration = 1800 }) => { const target = parseInt(numStr.replace(/\./g, ''), 10); const [val, setVal] = React.useState(0); const started = React.useRef(false); const ref = React.useRef(null); React.useEffect(() => { const el = ref.current; if (!el) return; const obs = new IntersectionObserver(([entry]) => { if (!entry.isIntersecting || started.current) return; started.current = true; const t0 = performance.now(); const tick = (now) => { const p = Math.min((now - t0) / duration, 1); const eased = 1 - Math.pow(1 - p, 3); setVal(Math.round(eased * target)); if (p < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); }, { threshold: 0.4 }); obs.observe(el); return () => obs.disconnect(); }, [target, duration]); const localeMap = { pt: 'pt-BR', en: 'en-GB', it: 'it-IT', de: 'de-CH' }; return {val.toLocaleString(localeMap[window.LANG] || 'en-GB')}; }; // ---- Stats ---- const Stats = () => { const stats = [ { pre: t('stats.s1_pre'), num: '1.200', label: t('stats.s1_label'), body: t('stats.s1_body') }, { pre: t('stats.s2_pre'), num: '12', label: t('stats.s2_label'), body: t('stats.s2_body') }, { pre: t('stats.s3_pre'), num: '12', label: t('stats.s3_label'), body: t('stats.s3_body') }, ]; return (
02 · {t('stats.eyebrow')}

{stats.map((s, i) => (
{s.pre} {s.label}

{s.body}

))}
{t('stats.ig')}
); }; // ---- Mapa do Brasil ---- const BRASIL_ACTIVE = new Set(['DF', 'RN', 'RJ', 'GO', 'MG']); const GEOJSON_URL = 'https://raw.githubusercontent.com/codeforamerica/click_that_hood/master/public/data/brazil-states.geojson'; const STATE_TO_SIGLA = { 'Acre':'AC','Alagoas':'AL','Amapá':'AP','Amazonas':'AM','Bahia':'BA', 'Ceará':'CE','Espírito Santo':'ES','Maranhão':'MA','Mato Grosso':'MT', 'Mato Grosso do Sul':'MS','Pará':'PA','Paraíba':'PB','Paraná':'PR', 'Pernambuco':'PE','Piauí':'PI','Rio Grande do Sul':'RS','Rondônia':'RO', 'Roraima':'RR','Santa Catarina':'SC','São Paulo':'SP','Sergipe':'SE','Tocantins':'TO', }; const BrasilMapSVG = ({ chosen }) => { const svgRef = React.useRef(null); const geoRef = React.useRef(null); const applyFills = (chosenSigla) => { if (!svgRef.current || typeof d3 === 'undefined') return; d3.select(svgRef.current).selectAll('path').attr('fill', d => { const s = d.properties.sigla; if (BRASIL_ACTIVE.has(s)) return 'var(--accent)'; if (chosenSigla && s === chosenSigla) return 'oklch(0.42 0.13 145)'; return 'var(--rule-strong)'; }); }; React.useEffect(() => { if (!svgRef.current || typeof d3 === 'undefined') return; const W = 400, H = 460; fetch(GEOJSON_URL) .then(r => r.json()) .then(geo => { geoRef.current = geo; const projection = d3.geoMercator().fitSize([W, H], geo); const pathGen = d3.geoPath().projection(projection); const svg = d3.select(svgRef.current); svg.selectAll('*').remove(); svg.selectAll('path') .data(geo.features) .join('path') .attr('d', pathGen) .attr('stroke', 'var(--paper)') .attr('stroke-width', 0.8); applyFills(chosen ? STATE_TO_SIGLA[chosen] : null); }); }, []); React.useEffect(() => { if (geoRef.current) applyFills(chosen ? STATE_TO_SIGLA[chosen] : null); }, [chosen]); return ; }; const MAPA_INACTIVE_STATES = [ 'Acre','Alagoas','Amapá','Amazonas','Bahia','Ceará', 'Espírito Santo','Maranhão','Mato Grosso','Mato Grosso do Sul', 'Pará','Paraíba','Paraná','Pernambuco','Piauí', 'Rio Grande do Sul','Rondônia','Roraima','Santa Catarina', 'São Paulo','Sergipe','Tocantins', ]; const BrasilMap = () => { const [picking, setPicking] = React.useState(false); const [chosen, setChosen] = React.useState(null); const select = (state) => { setChosen(state); setPicking(false); }; return (
01.2 · {t('mapa.eyebrow')}

{t('mapa.legend_active')}
{t('mapa.legend_inactive')}
{chosen ? (
{t('mapa.coming_to')} {chosen} {t('mapa.heart')}
) : ( <> {picking && (
{MAPA_INACTIVE_STATES.map(s => ( ))}
)} )}
    {['Distrito Federal', 'Rio Grande do Norte', 'Rio de Janeiro', 'Goiás', 'Minas Gerais'].map(s => (
  • {s}
  • ))}

); }; // ── Ações Recentes & Arrecadações ──────────────────────────── const AcaoCard = ({ acao }) => (
{ e.currentTarget.style.boxShadow = '0 8px 28px oklch(0.3 0.02 70 / 0.1)'; e.currentTarget.style.transform = 'translateY(-2px)'; }} onMouseLeave={e => { e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.transform = 'none'; }} >
{acao.title} e.currentTarget.style.transform = 'scale(1.05)'} onMouseLeave={e => e.currentTarget.style.transform = 'scale(1)'} onError={e => { e.currentTarget.closest('div').style.background = 'var(--paper-3)'; e.currentTarget.style.display = 'none'; }} />
{acao.badge} {acao.category}

{acao.title}

{acao.desc}

{acao.impact}
{t('acoes.progress')} 100% ✓
); const ACOES_VISIBLE = 4; const ACOES_GAP = 18; const ACOES_DUR = 480; const AcoesRecentes = () => { const ACOES = [ { badge: t('acoes.a1_badge'), category: t('acoes.a1_cat'), title: t('acoes.a1_title'), desc: t('acoes.a1_desc'), impact: t('acoes.a1_impact'), img: 'images/acao-rede-pais-atipicos-2026.jpg' }, { badge: t('acoes.a2_badge'), category: t('acoes.a2_cat'), title: t('acoes.a2_title'), desc: t('acoes.a2_desc'), impact: t('acoes.a2_impact'), img: 'images/acao-dia-das-maes-2026.jpg' }, { badge: t('acoes.a3_badge'), category: t('acoes.a3_cat'), title: t('acoes.a3_title'), desc: t('acoes.a3_desc'), impact: t('acoes.a3_impact'), img: 'images/acao-pascoa-solidaria-2026.jpg' }, { badge: t('acoes.a4_badge'), category: t('acoes.a4_cat'), title: t('acoes.a4_title'), desc: t('acoes.a4_desc'), impact: t('acoes.a4_impact'), img: 'https://eufacoparte.org/uploads/2025/09/peneira_social_atletas_eu_faco_parte_movimento_do_esporte.png' }, { badge: t('acoes.a5_badge'), category: t('acoes.a5_cat'), title: t('acoes.a5_title'), desc: t('acoes.a5_desc'), impact: t('acoes.a5_impact'), img: 'https://eufacoparte.org/uploads/2025/01/3.png' }, ]; const [idx, setIdx] = React.useState(0); const [anim, setAnim] = React.useState(true); const wrapRef = React.useRef(null); const [cardW, setCardW] = React.useState(0); const n = ACOES.length; const track = [...ACOES, ...ACOES.slice(0, ACOES_VISIBLE)]; React.useEffect(() => { const update = () => { if (!wrapRef.current) return; const w = wrapRef.current.offsetWidth; setCardW((w - ACOES_GAP * (ACOES_VISIBLE - 1)) / ACOES_VISIBLE); }; update(); const ro = new ResizeObserver(update); if (wrapRef.current) ro.observe(wrapRef.current); return () => ro.disconnect(); }, []); React.useEffect(() => { const iv = setInterval(() => { setAnim(true); setIdx(prev => { const next = prev + 1; if (next >= n) setTimeout(() => { setAnim(false); setIdx(0); }, ACOES_DUR + 16); return next; }); }, 10000); return () => clearInterval(iv); }, [n]); return (
· {t('acoes.eyebrow')}

{track.map((a, i) => (
))}
); }; window.ApoioProjetos = ApoioProjetos; window.Initiatives = Initiatives; window.Stats = Stats; window.BrasilMap = BrasilMap; window.AcoesRecentes = AcoesRecentes;