/* global React, ReactDOM, useTweaks, TweaksPanel, TweakSection, TweakColor, TweakRadio, TweakSlider */ const { useState, useRef, useEffect, useLayoutEffect, useCallback } = React; const EASE = [0.16, 1, 0.3, 1]; function animateEl(el, kf, opts) { const M = window.__motion; if (!M || !el) return; try { M.animate(el, kf, opts); } catch (e) {} } /* ---- one history entry (echo + output) — content ALWAYS ends visible ---- */ function Entry({ entry }) { const ref = useRef(null); useLayoutEffect(() => { const el = ref.current; if (!el) return; let cancelled = false; const targets = entry.kind === 'welcome' ? Array.from(el.querySelectorAll('.welcome > *')) : entry.kind === 'boot' ? Array.from(el.querySelectorAll('.bootlog > *')) : [el]; const reveal = () => targets.forEach((tg) => { tg.style.opacity = '1'; tg.style.transform = 'none'; }); const run = () => { const M = window.__motion; if (!M) { reveal(); return; } try { targets.forEach((tg) => { tg.style.opacity = '0'; }); const opts = (entry.kind === 'welcome' || entry.kind === 'boot') ? { duration: entry.kind === 'boot' ? 0.32 : 0.5, delay: M.stagger(entry.kind === 'boot' ? 0.11 : 0.07), ease: EASE } : { duration: 0.4, ease: EASE }; const anim = M.animate(targets, { opacity: [0, 1], y: [10, 0] }, opts); if (anim && anim.finished && anim.finished.then) anim.finished.then(reveal).catch(reveal); } catch (e) { reveal(); } setTimeout(() => { if (!cancelled) reveal(); }, 900); // hard fallback }; if (window.__motion) run(); else { window.addEventListener('gb-motion-ready', run, { once: true }); setTimeout(() => { if (!window.__motion && !cancelled) reveal(); }, 1100); } return () => { cancelled = true; }; }, []); return (
{entry.command != null && (
{entry.command}
)}
); } const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "accent": "#7ee787", "fontSize": 14 }/*EDITMODE-END*/; let UID = 0; const URL_PARAMS = new URLSearchParams(location.search); const LS = (k, d) => { try { return localStorage.getItem(k) || d; } catch (e) { return d; } }; const INITIAL_LANG = (URL_PARAMS.get('lang') || LS('gb-lang', 'pt')) === 'en' ? 'en' : 'pt'; const INITIAL_THEME = (URL_PARAMS.get('theme') || LS('gb-theme', 'dark')) === 'light' ? 'light' : 'dark'; /* accent swatches need a darker counterpart to stay readable on the light theme */ const LIGHT_ACCENT = { '#7ee787': '#1f9d55', '#e3b341': '#a1670f', '#79c0ff': '#0969da', '#e6e8ec': '#3d403b' }; function Terminal() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); const [lang, setLang] = useState(INITIAL_LANG); const [theme, setThemeState] = useState(INITIAL_THEME); const [history, setHistory] = useState([]); const [input, setInput] = useState(''); const [hIndex, setHIndex] = useState(-1); const bodyRef = useRef(null); const inputRef = useRef(null); // boot sequence → welcome (first load only) useEffect(() => { const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; setHistory([{ id: ++UID, command: null, kind: 'boot', html: window.GB_DATA.boot(lang) }]); const tmo = setTimeout(() => { setHistory((h) => [...h, { id: ++UID, command: null, kind: 'welcome', html: window.GB_DATA.welcome(lang) }]); }, reduce ? 60 : 1150); return () => clearTimeout(tmo); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // theme + language live in the shared site preference (site.js / localStorage) useEffect(() => { const onTheme = (e) => setThemeState(e.detail === 'light' ? 'light' : 'dark'); const onLang = (e) => { const l = e.detail === 'en' ? 'en' : 'pt'; setLang(l); setHistory([{ id: ++UID, command: null, kind: 'welcome', html: window.GB_DATA.welcome(l) }]); }; window.addEventListener('gb-theme', onTheme); window.addEventListener('gb-lang', onLang); return () => { window.removeEventListener('gb-theme', onTheme); window.removeEventListener('gb-lang', onLang); }; }, []); // apply tweaks to :root useEffect(() => { const r = document.documentElement; r.style.setProperty('--accent', theme === 'light' ? (LIGHT_ACCENT[t.accent] || t.accent) : t.accent); r.style.setProperty('--term-fs', t.fontSize + 'px'); }, [t.accent, t.fontSize, theme]); useEffect(() => { document.documentElement.setAttribute('data-theme', theme); }, [theme]); // window entrance useEffect(() => { const win = document.querySelector('.window'); if (win) { win.style.opacity = '0'; animateEl(win, { opacity: [0, 1], y: [14, 0], scale: [0.992, 1] }, { duration: 0.6, ease: EASE }); } const onReady = () => { const w = document.querySelector('.window'); if (w && getComputedStyle(w).opacity === '0') { w.style.opacity = '1'; animateEl(w, { opacity: [0, 1], y: [14, 0] }, { duration: 0.6, ease: EASE }); } }; if (!window.__motion) window.addEventListener('gb-motion-ready', onReady, { once: true }); // safety: never leave window hidden setTimeout(() => { const w = document.querySelector('.window'); if (w) w.style.opacity = '1'; }, 900); }, []); // focus the terminal without scrolling the pitch out of view; page starts at the top useEffect(() => { window.scrollTo(0, 0); const focus = () => { try { inputRef.current?.focus({ preventScroll: true }); } catch (e) {} }; focus(); const t1 = setTimeout(focus, 120); const t2 = setTimeout(focus, 1300); // after boot → welcome // typing anywhere lands in the prompt const onKey = (e) => { if (e.metaKey || e.ctrlKey || e.altKey) return; const el = document.activeElement; if (el && (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable)) return; if (e.key.length === 1 || e.key === 'Backspace' || e.key === 'Enter') focus(); }; window.addEventListener('keydown', onKey); return () => { clearTimeout(t1); clearTimeout(t2); window.removeEventListener('keydown', onKey); }; }, []); // keep scrolled to bottom useEffect(() => { const b = bodyRef.current; if (b) b.scrollTop = b.scrollHeight; }, [history]); const COMMANDS = ['rescue', 'about', 'stack', 'projects', 'experience', 'education', 'contact', 'status', 'arch', 'help', 'clear']; const ALIASES = { skills: 'stack', tech: 'stack', work: 'experience', exp: 'experience', edu: 'education', studies: 'education', who: 'about', whoami: 'about', proj: 'projects', ls: 'projects', email: 'contact', me: 'about', fix: 'rescue', socorro: 'rescue', consultoria: 'rescue', consulting: 'rescue', audit: 'rescue', diagnose: 'rescue', diagnostico: 'rescue', cleanup: 'rescue', debug: 'rescue', services: 'rescue', servicos: 'rescue', }; const run = useCallback((raw) => { const command = raw.trim(); const c = command.toLowerCase(); if (!c) { setHistory((h) => [...h, { id: ++UID, command: raw, kind: 'output', html: '' }]); return; } // language switch → reset to welcome in new lang if (c === 'en' || c === 'pt') { setLang(c); if (window.GBSite) window.GBSite.setLang(c); else { try { localStorage.setItem('gb-lang', c); } catch (e) {} } setHistory([{ id: ++UID, command: null, kind: 'welcome', html: window.GB_DATA.welcome(c) }]); return; } if (c === 'clear') { setHistory([]); return; } // interactive easter eggs (side effects) if (c === 'theme') { const next = theme === 'dark' ? 'light' : 'dark'; if (window.GBSite) window.GBSite.setTheme(next); else { setThemeState(next); try { localStorage.setItem('gb-theme', next); } catch (e) {} } setHistory((h) => [...h, { id: ++UID, command: raw, kind: 'output', html: `
${lang === 'en' ? 'theme →' : 'tema →'} ${next}
` }]); return; } if (c === 'matrix') { runMatrix(); setHistory((h) => [...h, { id: ++UID, command: raw, kind: 'output', html: `
${lang === 'en' ? 'Wake up, Glauber… (4s)' : 'Acorde, Glauber… (4s)'}
` }]); return; } // multiword / power commands const head = c.split(/\s+/)[0]; if (head === 'curl' || head === 'wget' || head === 'http' || head === 'fetch') { const html = window.GB_DATA.api(lang, c); setHistory((h) => [...h, { id: ++UID, command: raw, kind: 'output', html }]); return; } if (head === 'select') { const html = window.GB_DATA.sql(lang, c); setHistory((h) => [...h, { id: ++UID, command: raw, kind: html.startsWith('
[...h, { id: ++UID, command: raw, kind: 'output', html: window.GB_DATA.tree(lang) }]); return; } const resolved = ALIASES[c] || c; let html; if (window.GB_DATA[resolved] && COMMANDS.includes(resolved)) { html = window.GB_DATA[resolved](lang); } else { html = miscOutput(c, lang); } setHistory((h) => [...h, { id: ++UID, command: raw, kind: html.startsWith('
{ const seq = ['ArrowUp','ArrowUp','ArrowDown','ArrowDown','ArrowLeft','ArrowRight','ArrowLeft','ArrowRight','b','a']; let pos = 0; const onKey = (e) => { const k = e.key.length === 1 ? e.key.toLowerCase() : e.key; pos = (k === seq[pos]) ? pos + 1 : (k === seq[0] ? 1 : 0); if (pos === seq.length) { pos = 0; const en = document.documentElement.lang === 'en'; setHistory((h) => [...h, { id: ++UID, command: null, kind: 'output', html: `
▲▲▼▼◄►◄► B A — ${en ? 'Konami unlocked. 30 extra lives of high availability granted.' : 'Konami desbloqueado. 30 vidas extras de alta disponibilidade concedidas.'}
` }]); runMatrix(2600); } }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, []); const onKeyDown = (e) => { if (e.key === 'Enter') { run(input); setInput(''); setHIndex(-1); } else if (e.key === 'ArrowUp') { e.preventDefault(); const cmds = history.filter((x) => x.command != null && x.command.trim()).map((x) => x.command); if (!cmds.length) return; const ni = Math.min(hIndex + 1, cmds.length - 1); setHIndex(ni); setInput(cmds[cmds.length - 1 - ni] || ''); } else if (e.key === 'ArrowDown') { e.preventDefault(); const cmds = history.filter((x) => x.command != null && x.command.trim()).map((x) => x.command); const ni = Math.max(hIndex - 1, -1); setHIndex(ni); setInput(ni === -1 ? '' : cmds[cmds.length - 1 - ni] || ''); } else if (e.key === 'Tab') { e.preventDefault(); const all = [...COMMANDS, 'help', 'clear', 'en', 'pt', 'curl', 'tree', 'status', 'arch', 'rescue']; const m = all.find((x) => x.startsWith(input.trim().toLowerCase())); if (m) setInput(m); } else if (e.key === 'l' && e.ctrlKey) { e.preventDefault(); setHistory([]); } }; // click anywhere focuses input; click on [data-cmd] runs that command const onBodyClick = (e) => { const cmdEl = e.target.closest('[data-cmd]'); if (cmdEl) { const c = cmdEl.getAttribute('data-cmd'); run(c); setInput(''); setHIndex(-1); inputRef.current?.focus(); return; } if (window.getSelection && String(window.getSelection())) return; // don't steal text selection inputRef.current?.focus(); }; return (
glauber@borges — zsh — 80×24
{lang === 'en' ? 'online' : 'online'}
{history.map((entry) => )}
setInput(e.target.value)} onKeyDown={onKeyDown} spellCheck="false" autoCapitalize="off" autoComplete="off" autoCorrect="off" aria-label={lang === 'en' ? 'Type a command' : 'Digite um comando'} />
{lang === 'en' ? <>Type help · ↑ ↓ history · Tab autocomplete : <>Digite help · ↑ ↓ histórico · Tab autocompleta} {lang === 'en' ? 'clear to reset' : 'clear para limpar'}
setTweak('accent', v)} /> setTweak('fontSize', v)} />
); } /* misc / easter-egg commands */ function miscOutput(c, lang) { const en = lang === 'en'; const date = new Date().toLocaleString(en ? 'en-US' : 'pt-BR'); const blk = (s, cls) => `
${s}
`; switch (c) { case 'whoami': return blk('glauber'); case 'pwd': return blk('/home/glauber/payments'); case 'date': return blk(date); case 'uname': return blk('devbox 6.10.0-backend x86_64 GNU/Coffee'); case 'echo': return blk('echo $WHO → glauber', 'dim'); case 'uptime': return blk(en ? `up 10+ years, 4 squads, load average: high availability` : `no ar há 10+ anos, 4 squads, load average: alta disponibilidade`, 'dim'); case 'neofetch': case 'screenfetch': return neofetch(en); case 'sudo': return blk(en ? 'Nice try. glauber is not in the sudoers file. This incident will be reported. 👀'.replace(' 👀','') : 'Boa tentativa. glauber não está no arquivo sudoers. Este incidente será reportado.', 'dim'); case 'sudo su': case 'su': return blk(en ? 'Permission denied. The payments cluster does not negotiate.' : 'Permissão negada. O cluster de pagamentos não negocia.', 'dim'); case 'vim': case 'vi': case 'nvim': case 'emacs': return blk(en ? `You opened ${c}. Now you live here. (try exit)` : `Você abriu ${c}. Agora você mora aqui. (tente exit)`, 'dim'); case 'exit': case 'quit': case ':q': case ':wq': case ':q!': return blk(en ? "There is no escape from a good terminal. But there is a contact." : 'Não há saída de um bom terminal. Mas há um contato.', 'dim'); case 'coffee': case 'make coffee': case 'brew': return blk(en ? '☕ brewing… HTTP 418: I’m a teapot. Back-end still compiles though.'.replace('☕ ','> ') : '> preparando café… HTTP 418: I’m a teapot. Mas o back-end compila mesmo assim.', 'dim'); case 'git': case 'git status': return blk(`On branch main\n${en ? 'Your career is ahead of origin/main by 10 years.' : 'Sua carreira está 10 anos à frente de origin/main.'}`.replace('\n','
')); case 'git blame': return blk(en ? 'It was probably the gateway. It’s always the gateway.' : 'Provavelmente foi o gateway. É sempre o gateway.', 'dim'); case 'rm -rf /': case 'rm -rf': case 'rm -rf /*': return blk(en ? 'Refused. Production is sacred. 🛡 We don’t do that here.'.replace(' 🛡','') : 'Recusado. Produção é sagrada. A gente não faz isso aqui.', 'dim'); case 'ping': return blk(en ? '64 bytes from glauberborges.me: time=0.1ms — always reachable.' : '64 bytes de glauberborges.me: time=0.1ms — sempre disponível.', 'dim'); case 'top': case 'htop': case 'ps': return blk([ `PID COMMAND %CPU`, `1 payments-core 42.0`, `7 side-projects 18.0`, `15 mentoring 12.0`, `42 learning (always) ∞`, ].join('
')); case 'joke': case 'fortune': return blk(randomFrom(en ? JOKES_EN : JOKES_PT), 'dim'); case 'motd': return blk(en ? '“The best system is the one nobody notices is running.”' : '“O melhor sistema é aquele que ninguém percebe que está rodando.”', 'dim'); case 'theme': return ''; // handled in run() case 'matrix': return ''; // handled in run() case 'hire': case 'hire glauber': case 'hire me': return blk(`${en ? 'Let’s talk. Reach out:' : 'Vamos conversar. Fale comigo:'} ola@glauberborges.me`); case 'sl': return blk(en ? 'You meant `ls`. The train has left the station anyway. 🚂'.replace(' 🚂','') : 'Você quis dizer `ls`. Mas o trem já partiu.', 'dim'); case 'help me': case '?': return blk(en ? 'Aren’t we all. Try help.' : 'Quem não, né. Tente help.', 'dim'); case 'secret': case 'eggs': case 'easter': return blk(en ? `psst — try: neofetch · matrix · coffee · top · joke · sudo · theme · and the Konami code ↑↑↓↓←→←→ b a` : `psiu — tente: neofetch · matrix · coffee · top · joke · sudo · theme · e o código Konami ↑↑↓↓←→←→ b a`, 'dim'); default: return `
${en ? 'command not found' : 'comando não encontrado'}: ${escapeHtml(c)}
${en ? 'type' : 'digite'} help ${en ? 'or' : 'ou'} secret
`; } } const JOKES_PT = [ 'Existem 2 tipos de problema em sistemas distribuídos: 2. entrega exatamente uma vez 1. ordem das mensagens 2. entrega exatamente uma vez.', 'Não é bug, é uma feature não documentada com alta disponibilidade.', 'Cache invalidation, naming things, e contar pessoas em uma daily.', 'O deploy passou em staging. — frase dita momentos antes do desastre.', 'Funciona na minha máquina. ☑ — então mandamos sua máquina pra produção.'.replace(' ☑',''), ]; const JOKES_EN = [ 'There are 2 hard problems in distributed systems: 2. exactly-once delivery 1. message ordering 2. exactly-once delivery.', 'It’s not a bug, it’s an undocumented feature with high availability.', 'Cache invalidation, naming things, and counting people in a standup.', 'It passed in staging. — words said moments before disaster.', 'It works on my machine. — so we shipped my machine to production.', ]; function randomFrom(a) { return a[Math.floor(Math.random() * a.length)]; } function neofetch(en) { const logo = [ " __ ", " ___ / / __ _ ", " / _ `/ _ \\/ ' \\ ", " \\_, /_.__/_/_/_/ ", " /___/ payments ", ].join('\n'); const rows = [ ['OS', 'devbox · Backend Linux'], ['Host', 'Tech Lead'], ['Uptime', en ? '10+ years' : '10+ anos'], ['Shell', 'zsh · php · laravel'], ['Kernel', 'microservices 6.x (AWS · Azure · K8s)'], ['Stack', 'PHP · Redis · RabbitMQ · Elasticsearch'], ['Editor', 'nvim · Cursor · Claude Code'], ['Locale', en ? 'remote · UTC-3' : 'remoto · UTC-3'], ].map(([k, v]) => `${k}${v}`).join(''); const bar = ['#ec6a5e','#f4bf4f','#61c554','#79c0ff','#b48ead','#56d4dd'] .map((c) => `███`).join(''); return `
glauber@borges
─────────────
${rows}
${bar}
`; } function escapeHtml(s) { return s.replace(/[&<>"]/g, (m) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[m])); } /* Matrix rain overlay — brief, tasteful, self-cleaning */ let __matrixRunning = false; function runMatrix(duration) { if (__matrixRunning) return; __matrixRunning = true; duration = duration || 4000; const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; const canvas = document.createElement('canvas'); canvas.id = 'matrix-rain'; document.body.appendChild(canvas); const ctx = canvas.getContext('2d'); const accent = getComputedStyle(document.documentElement).getPropertyValue('--accent').trim() || '#7ee787'; let w, h, cols, drops, fontSize = 16; const chars = 'アイウエオカキクケコ0123456789{}[]<>=+*/$#&;PHP'.split(''); const resize = () => { w = canvas.width = window.innerWidth; h = canvas.height = window.innerHeight; cols = Math.floor(w / fontSize); drops = Array(cols).fill(0).map(() => Math.floor(Math.random() * -50)); }; resize(); window.addEventListener('resize', resize); requestAnimationFrame(() => canvas.classList.add('on')); let raf; const draw = () => { ctx.fillStyle = 'rgba(8,8,10,0.10)'; ctx.fillRect(0, 0, w, h); ctx.fillStyle = accent; ctx.font = fontSize + 'px JetBrains Mono, monospace'; for (let i = 0; i < cols; i++) { const ch = chars[Math.floor(Math.random() * chars.length)]; ctx.fillText(ch, i * fontSize, drops[i] * fontSize); if (drops[i] * fontSize > h && Math.random() > 0.975) drops[i] = 0; drops[i]++; } raf = requestAnimationFrame(draw); }; if (reduce) { /* draw a single static frame */ draw(); cancelAnimationFrame(raf); } else raf = requestAnimationFrame(draw); setTimeout(() => { canvas.classList.remove('on'); setTimeout(() => { cancelAnimationFrame(raf); window.removeEventListener('resize', resize); canvas.remove(); __matrixRunning = false; }, 450); }, duration); } ReactDOM.createRoot(document.getElementById('root')).render();