/*!
* Capicoda 🚩 — a capivara comunista do Núcleo de Tecnologia do MTST
* Widget autocontido: conversa com o visitante, identifica devs e os
* direciona para contribuir com o DECODA (https://git.mtst.tec.br/educacao/decoda/).
*
* Uso:
* Sem dependências, sem build, sem backend.
*/
(function () {
"use strict";
// ----- Links reais do DECODA ------------------------------------------
var URLS = {
repo: "https://git.mtst.tec.br/educacao/decoda/",
decoda: "https://www.nucleodetecnologia.com.br/decoda",
nucleo: "https://www.nucleodetecnologia.com.br",
};
// ----- Árvore de diálogo ----------------------------------------------
// Cada nó: { msg: string|string[], options: [{label, next?, url?, primary?}] }
// - next: navega para outro nó
// - url: abre link em nova aba (pode coexistir com next)
var TREE = {
start: {
msg: [
"Salve, companheirx! 🚩",
"Sou o Capicoda, a capivara do Núcleo de Tecnologia do MTST. 🦫",
"Tô aqui pra te apresentar o DECODA — e ver se rola você somar com a gente. Bora?",
],
options: [
{ label: "Bora! 🚩", next: "qualifica", primary: true },
{ label: "O que é o DECODA?", next: "oque_decoda" },
],
},
oque_decoda: {
msg: [
"O DECODA é uma plataforma educacional do MTST: ensina lógica de programação com jogos e blocos visuais (arrastar e soltar, sem decoreba de sintaxe).",
"É 100% gratuita, sem cadastro. A ideia é pensamento computacional como ferramenta de transformação social — tecnologia pra quem o sistema deixa de fora.",
],
options: [{ label: "Show. E eu, como ajudo?", next: "qualifica", primary: true }],
},
qualifica: {
msg: "Me conta: você programa ou tá aprendendo?",
options: [
{ label: "Sim, sou dev 👩💻", next: "area", primary: true },
{ label: "Tô aprendendo 🌱", next: "aprendiz" },
{ label: "Só curiosx 👀", next: "curioso" },
],
},
area: {
msg: "Massa! Qual é a tua praia?",
options: [
{ label: "Front-end / JS", next: "cta_front", primary: true },
{ label: "Back / DevOps", next: "cta_infra" },
{ label: "Full stack / outra", next: "cta_geral" },
],
},
cta_front: {
msg: [
"Então é praia tua mesmo! 🌊 O DECODA é React + Vite + Blockly com Tailwind. Os jogos e atividades de blocos são exatamente front-end.",
"Tem componente pra refinar, jogo novo pra criar, acessibilidade pra melhorar. Por onde quer começar?",
],
options: ctaOptions(),
},
cta_infra: {
msg: [
"Tem espaço de sobra! ⚙️ A stack roda em Docker + Docker Compose com Nginx de proxy, e o app empacota até como Electron (modo offline).",
"Build, deploy, CI, performance dos containers... dá pra somar bastante. Por onde começamos?",
],
options: ctaOptions(),
},
cta_geral: {
msg: [
"Perfeito! 🚩 O DECODA tem front (React + Vite + Blockly), docs (Docusaurus) e infra (Docker + Nginx). Tem frente pra todo gosto.",
"Bora dar o primeiro passo:",
],
options: ctaOptions(),
},
setup: {
msg: [
"Rodar localmente é tranquilo. 🛠️",
"Jeito fácil (Docker): 1. git clone https://git.mtst.tec.br/educacao/decoda.git 2. cd decoda 3. docker compose up --build -d → app em http://localhost, docs em http://localhost/docs",
"Sem Docker (Node 20+ e pnpm): cd app && pnpm install && pnpm run dev → http://localhost:5173",
],
options: [
{ label: "Abrir o repositório", url: URLS.repo, primary: true },
{ label: "Como mando um PR?", next: "fluxo_pr" },
{ label: "Voltar ao início", next: "start" },
],
},
fluxo_pr: {
msg: [
"O fluxo de contribuição é Git Flow, bem direto: 🌳",
"1. Fork do projeto 2. git checkout -b feature/sua-ideia (a partir de develop) 3. git commit -m \"feat: ...\" 4. git push origin feature/sua-ideia 5. Abra um Pull Request → code review → merge 🎉",
],
options: [
{ label: "Abrir o repositório", url: URLS.repo, primary: true },
{ label: "Como rodo localmente?", next: "setup" },
{ label: "Voltar ao início", next: "start" },
],
},
aprendiz: {
msg: [
"Que demais! 🌱 O DECODA foi feito justamente pra isso — então você é nosso público E pode contribuir aprendendo.",
"Usa a plataforma pra praticar, e quando se sentir à vontade vem mexer no código. Toda dúvida sua vira melhoria pra próxima pessoa.",
],
options: [
{ label: "Acessar o DECODA", url: URLS.decoda, primary: true },
{ label: "Ver o código (com calma)", next: "setup" },
{ label: "Voltar ao início", next: "start" },
],
},
curioso: {
msg: [
"Tranquilo, sem pressão! 👀 Mesmo sem programar você ajuda muito:",
"Divulga o DECODA, dá feedback de uso, leva pra escolas e ocupações, traz mais gente pra comunidade. Tudo isso é contribuição. ✊",
],
options: [
{ label: "Conhecer o Núcleo", url: URLS.nucleo, primary: true },
{ label: "Conhecer o DECODA", url: URLS.decoda },
{ label: "Voltar ao início", next: "start" },
],
},
};
// Opções padrão dos nós de chamada-pra-ação (CTA)
function ctaOptions() {
return [
{ label: "Ver o repositório", url: URLS.repo, primary: true },
{ label: "Como rodar localmente", next: "setup" },
{ label: "Como mandar um PR", next: "fluxo_pr" },
{ label: "Voltar ao início", next: "start" },
];
}
// ----- SVG da capivara (com boina vermelha + estrela) -----------------
var CAPY_SVG =
'";
// ----- Estilos --------------------------------------------------------
var CSS =
"#dcs-root{position:fixed;bottom:20px;right:20px;z-index:2147483000;font-family:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif}" +
"#dcs-root *{box-sizing:border-box}" +
// botão flutuante
"#dcs-fab{width:64px;height:64px;border:none;border-radius:50%;cursor:pointer;background:#c1121f;box-shadow:0 6px 20px rgba(0,0,0,.28);padding:6px;transition:transform .15s ease;position:relative}" +
"#dcs-fab:hover{transform:scale(1.07)}" +
"#dcs-fab svg{width:100%;height:100%;display:block}" +
"#dcs-fab .dcs-dot{position:absolute;top:-2px;right:-2px;width:18px;height:18px;background:#f4c430;border:2px solid #fff;border-radius:50%}" +
// painel
"#dcs-panel{position:absolute;bottom:80px;right:0;width:340px;max-width:calc(100vw - 32px);height:480px;max-height:calc(100vh - 120px);background:#fff;border-radius:16px;box-shadow:0 12px 40px rgba(0,0,0,.3);display:none;flex-direction:column;overflow:hidden;animation:dcs-pop .18s ease}" +
"#dcs-panel.dcs-open{display:flex}" +
"@keyframes dcs-pop{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}" +
// header
"#dcs-head{background:#c1121f;color:#fff;padding:12px 14px;display:flex;align-items:center;gap:10px;flex:0 0 auto}" +
"#dcs-head .dcs-av{width:40px;height:40px;border-radius:50%;background:#9b6b43;padding:3px;flex:0 0 auto}" +
"#dcs-head .dcs-av svg{width:100%;height:100%;display:block}" +
"#dcs-head h3{margin:0;font-size:15px;font-weight:700}" +
"#dcs-head p{margin:1px 0 0;font-size:11.5px;opacity:.9}" +
"#dcs-close{margin-left:auto;background:none;border:none;color:#fff;font-size:22px;line-height:1;cursor:pointer;opacity:.85;padding:0 4px}" +
"#dcs-close:hover{opacity:1}" +
// corpo
"#dcs-body{flex:1 1 auto;overflow-y:auto;padding:14px;background:#faf6f1}" +
".dcs-bubble{max-width:85%;padding:9px 12px;border-radius:14px;margin-bottom:8px;font-size:14px;line-height:1.45;word-wrap:break-word;animation:dcs-pop .18s ease}" +
".dcs-bot{background:#fff;color:#222;border:1px solid #eee;border-bottom-left-radius:4px}" +
".dcs-user{background:#c1121f;color:#fff;margin-left:auto;border-bottom-right-radius:4px}" +
".dcs-bubble code{background:#f0e8df;color:#7a2e16;padding:1px 5px;border-radius:5px;font-size:12.5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}" +
".dcs-bot code{display:inline-block}" +
// opções
"#dcs-opts{flex:0 0 auto;padding:10px 12px;border-top:1px solid #eee;background:#fff;display:flex;flex-wrap:wrap;gap:8px}" +
".dcs-opt{flex:1 1 auto;min-width:46%;border:1.5px solid #c1121f;background:#fff;color:#c1121f;padding:9px 10px;border-radius:10px;font-size:13px;font-weight:600;cursor:pointer;transition:all .12s ease;text-align:center}" +
".dcs-opt:hover{background:#fff0f0}" +
".dcs-opt.dcs-primary{background:#c1121f;color:#fff}" +
".dcs-opt.dcs-primary:hover{background:#a30e1a}" +
// indicador de digitação
".dcs-typing{display:flex;gap:4px;padding:11px 12px}" +
".dcs-typing span{width:7px;height:7px;border-radius:50%;background:#c1a;opacity:.5;background:#c1121f;animation:dcs-blink 1s infinite}" +
".dcs-typing span:nth-child(2){animation-delay:.2s}.dcs-typing span:nth-child(3){animation-delay:.4s}" +
"@keyframes dcs-blink{0%,60%,100%{opacity:.25}30%{opacity:1}}";
// ----- Construção do DOM ----------------------------------------------
var body, opts, panel, fab;
var typingTimer = null;
function el(tag, attrs, html) {
var n = document.createElement(tag);
if (attrs) for (var k in attrs) n.setAttribute(k, attrs[k]);
if (html != null) n.innerHTML = html;
return n;
}
function build() {
var style = el("style");
style.textContent = CSS;
document.head.appendChild(style);
var root = el("div", { id: "dcs-root" });
fab = el("button", { id: "dcs-fab", "aria-label": "Falar com o Capicoda" }, CAPY_SVG);
fab.appendChild(el("span", { class: "dcs-dot" }));
fab.addEventListener("click", toggle);
panel = el("div", { id: "dcs-panel", role: "dialog", "aria-label": "Capicoda" });
var head = el("div", { id: "dcs-head" });
head.appendChild(el("div", { class: "dcs-av" }, CAPY_SVG));
var titles = el("div");
titles.appendChild(el("h3", null, "Capicoda 🚩"));
titles.appendChild(el("p", null, "capivara do Núcleo de Tec • MTST"));
head.appendChild(titles);
var close = el("button", { id: "dcs-close", "aria-label": "Fechar" }, "×");
close.addEventListener("click", toggle);
head.appendChild(close);
body = el("div", { id: "dcs-body" });
opts = el("div", { id: "dcs-opts" });
panel.appendChild(head);
panel.appendChild(body);
panel.appendChild(opts);
root.appendChild(panel);
root.appendChild(fab);
document.body.appendChild(root);
}
// ----- Motor de conversa ----------------------------------------------
var started = false;
function toggle() {
var open = panel.classList.toggle("dcs-open");
if (open) {
fab.querySelector(".dcs-dot").style.display = "none";
if (!started) {
started = true;
goTo("start");
}
}
}
function scrollDown() {
body.scrollTop = body.scrollHeight;
}
function addBubble(html, who) {
var b = el("div", { class: "dcs-bubble " + (who === "user" ? "dcs-user" : "dcs-bot") }, html);
body.appendChild(b);
scrollDown();
return b;
}
function clearOpts() {
opts.innerHTML = "";
}
function renderOptions(list) {
clearOpts();
list.forEach(function (o) {
var btn = el("button", { class: "dcs-opt" + (o.primary ? " dcs-primary" : "") }, o.label);
btn.addEventListener("click", function () {
addBubble(o.label, "user");
if (o.url) window.open(o.url, "_blank", "noopener");
if (o.next) goTo(o.next);
// link puro (só url): mantém os botões pra pessoa escolher outra ação
});
opts.appendChild(btn);
});
}
function goTo(id) {
var node = TREE[id];
if (!node) return;
if (id === "start") {
body.innerHTML = ""; // reinicia a conversa
}
clearOpts();
var msgs = Array.isArray(node.msg) ? node.msg.slice() : [node.msg];
// mostra indicador de digitação e revela as bolhas em sequência
var typing = el("div", { class: "dcs-bubble dcs-bot dcs-typing" },
"");
body.appendChild(typing);
scrollDown();
var i = 0;
function next() {
if (i < msgs.length) {
if (i === 0 && typing.parentNode) typing.remove();
addBubble(msgs[i], "bot");
i++;
typingTimer = setTimeout(next, 420);
} else {
renderOptions(node.options || []);
}
}
typingTimer = setTimeout(next, 380);
}
// ----- Inicialização --------------------------------------------------
function init() {
if (document.getElementById("dcs-root")) return;
build();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();