feat: adiciona mascote Capicoda na página inicial
Capicoda é uma capivara comunista que conversa com quem visita o site, identifica se a pessoa é desenvolvedora e a direciona para contribuir com o DECODA (repositório, setup local, fluxo de PR). - app/src/vendor/capicoda/: widget autocontido em vanilla JS (CSS, SVG da capivara e árvore de diálogo embutidos), README e página de demo standalone. - HomePage: injeta o widget apenas na home via import ?url + useEffect, com limpeza ao sair da rota.
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
* @module pages.HomePage.HomePage
|
||||
*/
|
||||
|
||||
import { useEffect } from "react";
|
||||
import capicodaUrl from "@/vendor/capicoda/capicoda.js?url";
|
||||
import Navbar from "../../components/Navbar";
|
||||
import PropTypes from "prop-types";
|
||||
import Hero from "./Hero";
|
||||
@@ -16,6 +18,21 @@ import StudentsMaterials from "./StudentsMaterials";
|
||||
import TeachersMaterials from "./TeachersMaterials";
|
||||
|
||||
const HomePage = () => {
|
||||
// Mascote Capicoda: injetado apenas na página inicial. O widget é um script
|
||||
// autocontido que se anexa ao body; na saída da home removemos o script e o
|
||||
// nó raiz (#dcs-root) para não vazar para outras rotas.
|
||||
useEffect(() => {
|
||||
const script = document.createElement("script");
|
||||
script.src = capicodaUrl;
|
||||
script.defer = true;
|
||||
document.body.appendChild(script);
|
||||
return () => {
|
||||
script.remove();
|
||||
const root = document.getElementById("dcs-root");
|
||||
if (root) root.remove();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
{/* Navegação */}
|
||||
|
||||
102
app/src/vendor/capicoda/README.md
vendored
Normal file
102
app/src/vendor/capicoda/README.md
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
# Capicoda 🚩🦫
|
||||
|
||||
A **capivara comunista** do Núcleo de Tecnologia do MTST. Um widget de chat que
|
||||
aparece na página do Núcleo, conversa com quem visita, identifica se a pessoa é
|
||||
desenvolvedora e a direciona para **contribuir com o [DECODA](https://git.mtst.tec.br/educacao/decoda/)**.
|
||||
|
||||
Projeto do hackathon do Núcleo de Tecnologia do MTST.
|
||||
|
||||
---
|
||||
|
||||
## ✨ O que é
|
||||
|
||||
- Balão de chat no canto inferior direito de qualquer site.
|
||||
- Conversa por **roteiro fixo** (botões) — sem IA, sem backend, sem build.
|
||||
- Faz a triagem do visitante (**dev / aprendiz / curiosx**) e entrega o caminho
|
||||
certo: repositório, como rodar localmente, como abrir um PR, ou como ajudar
|
||||
sem programar.
|
||||
- Um único arquivo: **`capicoda.js`** (CSS, SVG da capivara e diálogo embutidos).
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Rodar o demo
|
||||
|
||||
Não precisa instalar nada. Na pasta do projeto:
|
||||
|
||||
```bash
|
||||
python3 -m http.server 8000
|
||||
```
|
||||
|
||||
Abra **http://localhost:8000/demo.html** e clique no balão da capivara.
|
||||
|
||||
> Também dá pra só abrir o `demo.html` direto no navegador (duplo clique).
|
||||
|
||||
---
|
||||
|
||||
## 🔌 Embutir em outro site
|
||||
|
||||
Copie `capicoda.js` para o site e adicione **uma linha** antes do `</body>`:
|
||||
|
||||
```html
|
||||
<script src="capicoda.js" defer></script>
|
||||
```
|
||||
|
||||
Pronto — o balão se injeta sozinho. Não conflita com o CSS da página (tudo é
|
||||
prefixado com `dcs-` e isolado num `#dcs-root`).
|
||||
|
||||
---
|
||||
|
||||
## 💬 Editar a conversa
|
||||
|
||||
Toda a conversa vive no objeto **`TREE`** no topo do `capicoda.js`. Cada nó:
|
||||
|
||||
```js
|
||||
nome_do_no: {
|
||||
msg: "Texto do balão", // ou um array de balões em sequência
|
||||
options: [
|
||||
{ label: "Botão A", next: "outro_no" }, // navega para outro nó
|
||||
{ label: "Abrir repo", url: URLS.repo }, // abre um link em nova aba
|
||||
{ label: "Destaque", next: "x", primary: true } // botão em vermelho cheio
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Os links reais ficam no objeto `URLS` (repo, página do DECODA, página do Núcleo).
|
||||
|
||||
### Mapa do roteiro
|
||||
|
||||
```
|
||||
start ──┬─ Bora! ───────────────► qualifica
|
||||
└─ O que é o DECODA? ───► oque_decoda ──► qualifica
|
||||
|
||||
qualifica ─┬─ Sou dev ──────► area ─┬─ Front/JS ──► cta_front
|
||||
│ ├─ Back/DevOps ► cta_infra
|
||||
│ └─ Full/outra ─► cta_geral
|
||||
├─ Tô aprendendo ► aprendiz
|
||||
└─ Só curiosx ───► curioso
|
||||
|
||||
cta_* ─┬─ Ver repositório (link)
|
||||
├─ Como rodar localmente ► setup
|
||||
├─ Como mandar um PR ─────► fluxo_pr
|
||||
└─ Voltar ao início ──────► start
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Identidade
|
||||
|
||||
Capivara marrom de boina vermelha com estrela dourada (SVG inline). Paleta MTST
|
||||
(vermelho `#c1121f`). Tom acolhedor e militante-bem-humorado.
|
||||
|
||||
---
|
||||
|
||||
## 🔮 Próximos passos (fora do escopo do hackathon)
|
||||
|
||||
- Modo IA opcional (Claude API) para conversa livre.
|
||||
- Captura de contato de quem quer contribuir (onboarding → mutirão).
|
||||
- Puxar "good first issues" dinamicamente da aba de Issues do repositório.
|
||||
- Integração na página real do Núcleo e/ou sobre o app DECODA.
|
||||
|
||||
---
|
||||
|
||||
Desenvolvido com ✊ para o DECODA · Núcleo de Tecnologia do MTST
|
||||
341
app/src/vendor/capicoda/capicoda.js
vendored
Normal file
341
app/src/vendor/capicoda/capicoda.js
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
/*!
|
||||
* 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: <script src="capicoda.js" defer></script>
|
||||
* 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 <b>Capicoda</b>, a capivara do Núcleo de Tecnologia do MTST. 🦫",
|
||||
"Tô aqui pra te apresentar o <b>DECODA</b> — 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 <b>DECODA</b> é uma plataforma educacional do MTST: ensina lógica de programação com <b>jogos</b> e <b>blocos visuais</b> (arrastar e soltar, sem decoreba de sintaxe).",
|
||||
"É 100% gratuita, sem cadastro. A ideia é pensamento computacional como ferramenta de <b>transformação social</b> — 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 é <b>React + Vite + Blockly</b> 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 <b>Docker + Docker Compose</b> com <b>Nginx</b> 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. 🛠️",
|
||||
"<b>Jeito fácil (Docker):</b><br>1. <code>git clone https://git.mtst.tec.br/educacao/decoda.git</code><br>2. <code>cd decoda</code><br>3. <code>docker compose up --build -d</code><br>→ app em <code>http://localhost</code>, docs em <code>http://localhost/docs</code>",
|
||||
"<b>Sem Docker (Node 20+ e pnpm):</b><br><code>cd app && pnpm install && pnpm run dev</code> → <code>http://localhost:5173</code>",
|
||||
],
|
||||
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. <b>Fork</b> do projeto<br>2. <code>git checkout -b feature/sua-ideia</code> (a partir de <code>develop</code>)<br>3. <code>git commit -m \"feat: ...\"</code><br>4. <code>git push origin feature/sua-ideia</code><br>5. Abra um <b>Pull Request</b> → 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 <i>justamente</i> 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 =
|
||||
'<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">' +
|
||||
// orelhas
|
||||
'<ellipse cx="26" cy="42" rx="9" ry="8" fill="#7d5836"/>' +
|
||||
'<ellipse cx="74" cy="42" rx="9" ry="8" fill="#7d5836"/>' +
|
||||
// cabeça
|
||||
'<ellipse cx="50" cy="60" rx="33" ry="29" fill="#9b6b43"/>' +
|
||||
// focinho
|
||||
'<ellipse cx="50" cy="74" rx="20" ry="14" fill="#c2966b"/>' +
|
||||
// narinas
|
||||
'<ellipse cx="43" cy="72" rx="2.2" ry="3" fill="#5a3d24"/>' +
|
||||
'<ellipse cx="57" cy="72" rx="2.2" ry="3" fill="#5a3d24"/>' +
|
||||
// olhos
|
||||
'<circle cx="38" cy="52" r="3.4" fill="#3a2817"/>' +
|
||||
'<circle cx="62" cy="52" r="3.4" fill="#3a2817"/>' +
|
||||
'<circle cx="39.2" cy="50.8" r="1.1" fill="#fff"/>' +
|
||||
'<circle cx="63.2" cy="50.8" r="1.1" fill="#fff"/>' +
|
||||
// boina comunista
|
||||
'<ellipse cx="50" cy="31" rx="26" ry="12" fill="#c1121f"/>' +
|
||||
'<ellipse cx="50" cy="29" rx="20" ry="9" fill="#e63946"/>' +
|
||||
'<rect x="47" y="18" width="6" height="6" rx="3" fill="#c1121f"/>' +
|
||||
// estrela dourada
|
||||
'<path d="M50,20 L51.9,25.4 L57.6,25.5 L53,29 L54.7,34.5 L50,31.2 L45.3,34.5 L47,29 L42.4,25.5 L48.1,25.4 Z" fill="#f4c430"/>' +
|
||||
"</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" },
|
||||
"<span></span><span></span><span></span>");
|
||||
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();
|
||||
}
|
||||
})();
|
||||
69
app/src/vendor/capicoda/demo.html
vendored
Normal file
69
app/src/vendor/capicoda/demo.html
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Capicoda — demo · Núcleo de Tecnologia do MTST</title>
|
||||
<style>
|
||||
:root { --vermelho: #c1121f; }
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
||||
color: #1d1d1f; line-height: 1.6; background: #faf6f1;
|
||||
}
|
||||
header {
|
||||
background: var(--vermelho); color: #fff; padding: 18px 24px;
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
}
|
||||
header .star { font-size: 26px; }
|
||||
header h1 { font-size: 19px; font-weight: 700; }
|
||||
.hero {
|
||||
max-width: 760px; margin: 0 auto; padding: 64px 24px 40px; text-align: center;
|
||||
}
|
||||
.hero h2 { font-size: 38px; line-height: 1.2; margin-bottom: 16px; }
|
||||
.hero h2 span { color: var(--vermelho); }
|
||||
.hero p { font-size: 18px; color: #4a4a4a; max-width: 560px; margin: 0 auto; }
|
||||
.grid {
|
||||
max-width: 760px; margin: 0 auto; padding: 24px; display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px;
|
||||
}
|
||||
.card { background: #fff; border: 1px solid #eee; border-radius: 14px; padding: 20px; }
|
||||
.card h3 { font-size: 16px; margin-bottom: 6px; }
|
||||
.card p { font-size: 14px; color: #555; }
|
||||
.hint {
|
||||
max-width: 760px; margin: 12px auto 80px; padding: 16px 20px; border-radius: 12px;
|
||||
background: #fff3cd; border: 1px solid #ffe69c; color: #664d03; font-size: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
footer { text-align: center; padding: 24px; color: #999; font-size: 13px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<span class="star">🚩</span>
|
||||
<h1>Núcleo de Tecnologia · MTST</h1>
|
||||
</header>
|
||||
|
||||
<section class="hero">
|
||||
<h2>Aprenda a programar com o <span>DECODA</span></h2>
|
||||
<p>Plataforma educacional do MTST: lógica de programação através de jogos
|
||||
e blocos visuais. Tecnologia como ferramenta de transformação social.</p>
|
||||
</section>
|
||||
|
||||
<section class="grid">
|
||||
<div class="card"><h3>🎮 Jogos</h3><p>Atividades interativas para aprender programação na prática.</p></div>
|
||||
<div class="card"><h3>🧩 Blocos visuais</h3><p>Programação arrastar-e-soltar com Blockly, sem decorar sintaxe.</p></div>
|
||||
<div class="card"><h3>🆓 Livre e gratuito</h3><p>100% gratuito, sem cadastro, código aberto.</p></div>
|
||||
</section>
|
||||
|
||||
<div class="hint">
|
||||
👉 Página de demonstração. O balão da capivara <b>Capicoda</b> aparece no
|
||||
canto inferior direito — clique pra conversar.
|
||||
</div>
|
||||
|
||||
<footer>Demo do mascote Capicoda · hackathon do Núcleo de Tecnologia do MTST</footer>
|
||||
|
||||
<!-- É só isto que precisa ir na página real do Núcleo: -->
|
||||
<script src="capicoda.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user