Código fonte para a criação de uma Urna Eletrônica, para você aprimorar seus estudos em Html5, Javascript e Tailwind css3

Código fonte para a criação de uma Urna Eletrônica, para você aprimorar seus estudos em Html5, Javascript e Tailwind css3

Normalmente a urna eletrônica brasileira exibe o número do candidato (para presidente), com botões para dígitos, "Branco", "Corrige", "Confirma". Também mostra o nome e a foto do candidato? Normalmente a urna real mostra nome, número, partido e foto do candidato. Para simplificar, podemos implementar um banco de dados fictício de candidatos com os principais da última eleição (Lula, Bolsonaro, etc.). 

O usuário digita o número do candidato, o sistema busca o candidato e exibe as informações. No final, confirma o voto e armazena a contagem, exibindo uma mensagem de sucesso. Além disso, deve impedir a votação após confirmar, talvez permitir reiniciar? Mas a urna típica – cada eleitor vota, então poderíamos ter um mecanismo de "Finalizar Votação" para demonstração, ou um painel de administração simples? O requisito: "gerar uma urna de votação presidencial, igual a usada no Brasil na última eleição presidencial" deve se comportar de maneira semelhante: o eleitor digita o número, vê os detalhes do candidato (nome, foto se possível: podemos usar placeholders com Font Awesome ou emoji ou imagem). 

Como a urna eletrônica real usa imagens, podemos usar imagens redondas simples ou iniciais. Para profissionalismo, projetamos com Tailwind CSS: responsivo, moderno, com tema escuro/claro? Use um fundo e design que lembrem a urna: frequentemente azul/amarelo ou cinza? Talvez um design neutro. Além disso, código comentado passo a passo, tudo em um único arquivo HTML. Como precisamos produzir um trecho de código executável, podemos incorporar estilo, scripts, CDN do Tailwind, além do JavaScript para a lógica de votação.

Para testar o código abaixo, basta selecionar e copiar todo o codigo abaixo no bloco de notas e salvar com a extensão html exemplo urna.html, selecione a pasta onde será gravado o arquivo, depois basta clicar duas vezes no ícone para abrir no navegador chrome ou qualquer outro.



<!DOCTYPE html>

<html lang="pt-BR">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">

    <title>Urna Eletrônica 2026 | Simulação Oficial</title>

    <!-- Tailwind CSS v3 + Font Awesome (ícones opcionais para melhor semântica visual) -->

    <script src="https://cdn.tailwindcss.com"></script>

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">

    <!-- custom ajuste fino para sombras e transições -->

    <style>

        /* pequeno ajuste para foco e transição suave nos botões */

        button:active { transform: scale(0.97); transition: 0.05s ease; }

        .numero-digitado {

            font-family: 'Courier New', monospace;

            letter-spacing: 4px;

        }

        /* estilo da tela simulando o display da urna */

        .display-urna {

            background: linear-gradient(145deg, #eef2f5 0%, #d9e0e6 100%);

            box-shadow: inset 0 2px 4px rgba(0,0,0,0.05), 0 4px 8px rgba(0,0,0,0.1);

        }

        .teclado-numero {

            transition: all 0.1s ease;

            box-shadow: 0 2px 4px rgba(0,0,0,0.1);

        }

        .teclado-numero:hover {

            background-color: #e2e8f0;

        }

    </style>

</head>

<body class="bg-gradient-to-br from-slate-800 to-slate-900 min-h-screen flex items-center justify-center p-4 font-sans">


    <div class="w-full max-w-5xl mx-auto">

        <!-- Artigo: cabeçalho profissional -->

        <div class="text-center mb-4">

            <h1 class="text-2xl md:text-3xl font-bold text-white drop-shadow-md tracking-tight">🗳️ Urna Eletrônica Presidencial <span class="text-yellow-300">Brasil 2026</span></h1>

            <p class="text-slate-300 text-sm mt-1">Simulação oficial • Voto direto e sigiloso • Justiça Eleitoral</p>

        </div>


        <!-- Estrutura principal da urna (grid: painel esquerdo/teclado) -->

        <div class="bg-white rounded-2xl shadow-2xl overflow-hidden border border-slate-200">

            <div class="grid md:grid-cols-3 gap-0">

                

                <!-- LADO ESQUERDO: DISPLAY E INFORMAÇÕES DO CANDIDATO (área principal da urna) -->

                <div class="md:col-span-2 bg-gray-50 p-6 border-r border-gray-200">

                    <!-- Título da eleição -->

                    <div class="flex items-center gap-2 mb-3 pb-2 border-b border-gray-300">

                        <i class="fas fa-flag-checkered text-green-700"></i>

                        <span class="font-bold text-gray-700 uppercase tracking-wide">Eleição Presidencial</span>

                        <span class="bg-red-600 text-white text-xs px-2 py-0.5 rounded-full ml-2">1º Turno</span>

                    </div>


                    <!-- Área de exibição do número digitado (similar ao visor) -->

                    <div class="display-urna rounded-xl p-5 mb-5 border border-gray-300">

                        <div class="text-xs text-gray-500 uppercase tracking-wider mb-1">Digite o número</div>

                        <div class="numero-digitado text-6xl md:text-7xl font-mono font-bold text-gray-800 bg-white rounded-lg p-3 text-center shadow-inner" id="numeroDisplay">

                            —

                        </div>

                    </div>


                    <!-- Informações do candidato (dinâmico) -->

                    <div class="bg-white rounded-xl border border-gray-200 p-4 shadow-sm transition-all duration-200" id="candidateInfoPanel">

                        <!-- conteúdo preenchido via JS -->

                        <div id="infoContent" class="flex flex-col md:flex-row gap-4 items-start">

                            <div class="w-24 h-24 bg-slate-200 rounded-full flex items-center justify-center text-4xl font-bold text-slate-500 shadow-inner">

                                <i class="fas fa-user-circle text-5xl text-slate-400"></i>

                            </div>

                            <div class="flex-1 space-y-1">

                                <p class="text-gray-400 text-sm">Aguardando digitação...</p>

                                <p class="font-mono text-2xl font-bold text-gray-500">_ _</p>

                                <p class="text-gray-500">Nenhum candidato selecionado</p>

                            </div>

                        </div>

                    </div>


                    <!-- Área de mensagens de retorno (feedback para o eleitor) -->

                    <div class="mt-4 text-sm text-center font-medium py-2 px-3 rounded-lg bg-amber-50 border border-amber-200 text-amber-800" id="feedbackMessage">

                        <i class="fas fa-info-circle mr-1"></i> Utilize o teclado ou botões para votar

                    </div>

                </div>


                <!-- LADO DIREITO: TECLADO NUMÉRICO + AÇÕES (BRANCO, CORRIGE, CONFIRMA) -->

                <div class="bg-slate-100 p-5 flex flex-col">

                    <div class="text-center mb-2 font-semibold text-slate-600 flex items-center justify-center gap-2">

                        <i class="fas fa-keyboard"></i> <span>Teclado da Urna</span>

                    </div>

                    <!-- grade 3x3 números + ações -->

                    <div class="grid grid-cols-3 gap-3 mb-4">

                        <!-- botões 1 a 9 -->

                        <button data-digit="1" class="teclado-numero bg-white hover:bg-gray-100 text-gray-800 font-bold py-4 rounded-xl shadow-md text-2xl transition-all">1</button>

                        <button data-digit="2" class="teclado-numero bg-white hover:bg-gray-100 text-gray-800 font-bold py-4 rounded-xl shadow-md text-2xl">2</button>

                        <button data-digit="3" class="teclado-numero bg-white hover:bg-gray-100 text-gray-800 font-bold py-4 rounded-xl shadow-md text-2xl">3</button>

                        <button data-digit="4" class="teclado-numero bg-white hover:bg-gray-100 text-gray-800 font-bold py-4 rounded-xl shadow-md text-2xl">4</button>

                        <button data-digit="5" class="teclado-numero bg-white hover:bg-gray-100 text-gray-800 font-bold py-4 rounded-xl shadow-md text-2xl">5</button>

                        <button data-digit="6" class="teclado-numero bg-white hover:bg-gray-100 text-gray-800 font-bold py-4 rounded-xl shadow-md text-2xl">6</button>

                        <button data-digit="7" class="teclado-numero bg-white hover:bg-gray-100 text-gray-800 font-bold py-4 rounded-xl shadow-md text-2xl">7</button>

                        <button data-digit="8" class="teclado-numero bg-white hover:bg-gray-100 text-gray-800 font-bold py-4 rounded-xl shadow-md text-2xl">8</button>

                        <button data-digit="9" class="teclado-numero bg-white hover:bg-gray-100 text-gray-800 font-bold py-4 rounded-xl shadow-md text-2xl">9</button>

                        <!-- Zero ocupa posição central inferior, mas mantemos padrão -->

                        <button data-digit="0" class="teclado-numero bg-white hover:bg-gray-100 text-gray-800 font-bold py-4 rounded-xl shadow-md text-2xl col-span-1">0</button>

                        <!-- espaço vazio para manter grid (apenas visual) -->

                        <div></div>

                        <div></div>

                    </div>

                    

                    <!-- Botões de ação principais (branco, corrige, confirma) -->

                    <div class="grid grid-cols-3 gap-3 mt-2">

                        <button id="btnBranco" class="bg-gray-500 hover:bg-gray-600 text-white font-bold py-3 rounded-xl shadow-md transition flex items-center justify-center gap-2">

                            <i class="fas fa-square"></i> BRANCO

                        </button>

                        <button id="btnCorrige" class="bg-orange-500 hover:bg-orange-600 text-white font-bold py-3 rounded-xl shadow-md transition flex items-center justify-center gap-2">

                            <i class="fas fa-undo-alt"></i> CORRIGE

                        </button>

                        <button id="btnConfirma" class="bg-green-600 hover:bg-green-700 text-white font-bold py-3 rounded-xl shadow-md transition flex items-center justify-center gap-2">

                            <i class="fas fa-check-circle"></i> CONFIRMA

                        </button>

                    </div>

                    

                    <!-- espaço instruções -->

                    <div class="text-center text-xs text-gray-500 mt-5 border-t pt-3">

                        <i class="fas fa-lock"></i> Voto secreto · 2 dígitos

                    </div>

                </div>

            </div>

        </div>

        

        <!-- PAINEL DE APURAÇÃO PARCIAL (resultados dinâmicos - apenas para fins educacionais/simulação) -->

        <div class="mt-6 bg-white/90 backdrop-blur-sm rounded-2xl shadow-xl p-4 border border-slate-200">

            <div class="flex justify-between items-center flex-wrap gap-2 border-b pb-2 mb-3">

                <div class="flex items-center gap-2">

                    <i class="fas fa-chart-simple text-blue-700"></i>

                    <h2 class="font-bold text-gray-700 text-lg">📊 Apuração Parcial (Votos computados)</h2>

                </div>

                <button id="resetVotosBtn" class="text-xs bg-red-100 hover:bg-red-200 text-red-700 px-3 py-1 rounded-full transition flex items-center gap-1"><i class="fas fa-trash-alt"></i> Zerar Estatísticas</button>

            </div>

            <div id="resultadosContainer" class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-3 text-sm">

                <!-- JS preenche dinamicamente os totais -->

            </div>

            <p class="text-xs text-gray-400 mt-3 text-center">🔒 Simulação de urna eletrônica - Votos registrados conforme legislação fictícia. A cada confirmação, seu voto é contabilizado.</p>

        </div>

    </div>


    <script>

        // ============================================================

        //  URNA ELETRÔNICA BRASILEIRA - CÓDIGO PROFISSIONAL

        //  Linguagem: JavaScript (ES6+) com Tailwind CSS

        //  Descrição: Simulação completa do processo de votação para presidente

        //  Funcionalidades: digitação 2 dígitos, candidatos reais da última eleição,

        //  votos válidos, nulos, brancos, teclado físico, feedback, segurança anti-duplo clique.

        //  Documentação passo a passo integrada.

        // ============================================================


        // -------------------- 1. BASE DE DADOS DOS CANDIDATOS (Última eleição presidencial) --------------------

        // Números oficiais e nomes reais com partidos

        const CANDIDATOS = [

            { numero: "13", nome: "LUIZ INÁCIO LULA DA SILVA", partido: "PT", vice: "Geraldo Alckmin", fotoIcon: "fas fa-hand-peace", cor: "bg-red-100" },

            { numero: "22", nome: "JAIR MESSIAS BOLSONARO", partido: "PL", vice: "Braga Netto", fotoIcon: "fas fa-fist-raised", cor: "bg-blue-100" },

            { numero: "12", nome: "CIRO GOMES", partido: "PDT", vice: "Ana Paula Matos", fotoIcon: "fas fa-chart-line", cor: "bg-green-100" },

            { numero: "15", nome: "SIMONE TEBET", partido: "MDB", vice: "Mara Gabrilli", fotoIcon: "fas fa-star-of-life", cor: "bg-purple-100" },

            { numero: "44", nome: "SORAYA THRONICKE", partido: "UNIÃO", vice: "Marcos Cintra", fotoIcon: "fas fa-dove", cor: "bg-yellow-100" }

        ];


        // Mapa para busca rápida por número

        const candidatosMap = new Map();

        CANDIDATOS.forEach(c => candidatosMap.set(c.numero, c));


        // -------------------- 2. ESTADO GLOBAL DA URNA --------------------

        let currentNumber = "";            // número digitado (string de até 2 dígitos)

        let blankMode = false;              // modo branco ativo?

        let processingVote = false;         // trava para evitar múltiplas confirmações

        let lastFeedbackTimeout = null;


        // Estrutura de votos (totais)

        let votos = {

            candidatos: {},      // chave: número do candidato, valor: quantidade

            brancos: 0,

            nulos: 0

        };

        // Inicializa contagem de cada candidato com 0

        CANDIDATOS.forEach(c => { votos.candidatos[c.numero] = 0; });


        // -------------------- 3. REFERÊNCIAS DOM --------------------

        const numeroDisplayEl = document.getElementById("numeroDisplay");

        const candidateInfoPanel = document.getElementById("infoContent");

        const feedbackMsgEl = document.getElementById("feedbackMessage");

        const resultadosContainer = document.getElementById("resultadosContainer");

        const btnBranco = document.getElementById("btnBranco");

        const btnCorrige = document.getElementById("btnCorrige");

        const btnConfirma = document.getElementById("btnConfirma");

        const resetVotosBtn = document.getElementById("resetVotosBtn");


        // -------------------- 4. FUNÇÕES AUXILIARES DE UI E FEEDBACK --------------------

        function mostrarFeedback(mensagem, tipo = "info") {

            if (lastFeedbackTimeout) clearTimeout(lastFeedbackTimeout);

            let corBg = "bg-blue-50 border-blue-200 text-blue-800";

            let icone = "fa-info-circle";

            if (tipo === "sucesso") { corBg = "bg-green-50 border-green-200 text-green-800"; icone = "fa-check-circle"; }

            if (tipo === "erro") { corBg = "bg-red-50 border-red-200 text-red-800"; icone = "fa-exclamation-triangle"; }

            if (tipo === "aviso") { corBg = "bg-yellow-50 border-yellow-200 text-yellow-800"; icone = "fa-clock"; }

            feedbackMsgEl.innerHTML = `<i class="fas ${icone} mr-1"></i> ${mensagem}`;

            feedbackMsgEl.className = `text-sm text-center font-medium py-2 px-3 rounded-lg border ${corBg} transition-all`;

            lastFeedbackTimeout = setTimeout(() => {

                if (feedbackMsgEl) feedbackMsgEl.innerHTML = `<i class="fas fa-info-circle mr-1"></i> Aguardando voto ou digite o número`;

                feedbackMsgEl.className = "text-sm text-center font-medium py-2 px-3 rounded-lg bg-amber-50 border border-amber-200 text-amber-800";

            }, 2800);

        }


        // Atualiza a interface com base no estado (número digitado ou modo branco)

        function atualizarInterfaceCompleta() {

            // Atualiza display do número

            if (blankMode) {

                numeroDisplayEl.innerText = "BRANCO";

                numeroDisplayEl.classList.add("text-yellow-600");

            } else {

                numeroDisplayEl.innerText = currentNumber.length ? currentNumber : "—";

                numeroDisplayEl.classList.remove("text-yellow-600");

            }


            // Painel de informações do candidato / branco

            if (blankMode) {

                // Exibe tela de voto em branco

                candidateInfoPanel.innerHTML = `

                    <div class="flex flex-col md:flex-row gap-4 items-start w-full">

                        <div class="w-24 h-24 bg-gray-200 rounded-full flex items-center justify-center text-4xl font-bold text-gray-500 shadow-inner">

                            <i class="fas fa-ban text-4xl text-gray-500"></i>

                        </div>

                        <div class="flex-1 space-y-2">

                            <p class="text-gray-600 font-semibold uppercase text-sm">VOTO EM BRANCO</p>

                            <p class="text-2xl font-mono font-bold text-gray-700">—</p>

                            <p class="text-gray-600">Confirme para registrar voto branco</p>

                            <span class="inline-block bg-gray-100 text-gray-600 text-xs px-2 py-1 rounded-full">Nenhum candidato</span>

                        </div>

                    </div>

                `;

                return;

            }


            // Se não está em branco, mostra informações do candidato baseado no número

            if (currentNumber.length === 0) {

                candidateInfoPanel.innerHTML = `

                    <div class="flex flex-col md:flex-row gap-4 items-start w-full">

                        <div class="w-24 h-24 bg-slate-200 rounded-full flex items-center justify-center text-4xl font-bold text-slate-500">

                            <i class="fas fa-user-circle text-5xl text-slate-400"></i>

                        </div>

                        <div class="flex-1 space-y-1">

                            <p class="text-gray-400 text-sm">Aguardando digitação</p>

                            <p class="font-mono text-2xl font-bold text-gray-500">_ _</p>

                            <p class="text-gray-500">Digite o número do candidato</p>

                        </div>

                    </div>

                `;

                return;

            }


            // Busca candidato no mapa

            const candidato = candidatosMap.get(currentNumber);

            if (candidato) {

                // Mostra candidato encontrado

                candidateInfoPanel.innerHTML = `

                    <div class="flex flex-col md:flex-row gap-4 items-start w-full">

                        <div class="w-24 h-24 ${candidato.cor} rounded-full flex items-center justify-center text-4xl font-bold text-gray-700 shadow-inner border-2 border-gray-300">

                            <i class="${candidato.fotoIcon} text-4xl"></i>

                        </div>

                        <div class="flex-1 space-y-1.5">

                            <p class="text-xs text-gray-500 uppercase tracking-wide">Candidato(a) à Presidência</p>

                            <p class="font-bold text-xl text-gray-800">${candidato.nome}</p>

                            <p class="text-sm"><span class="font-semibold">Partido:</span> ${candidato.partido}</p>

                            <p class="text-sm"><span class="font-semibold">Vice:</span> ${candidato.vice}</p>

                            <div class="flex gap-2 mt-1"><span class="bg-blue-100 text-blue-800 text-xs px-2 py-0.5 rounded-full">Número: ${candidato.numero}</span></div>

                        </div>

                    </div>

                `;

            } else {

                // Número não corresponde a nenhum candidato -> voto nulo potencial

                candidateInfoPanel.innerHTML = `

                    <div class="flex flex-col md:flex-row gap-4 items-start w-full">

                        <div class="w-24 h-24 bg-red-100 rounded-full flex items-center justify-center text-4xl font-bold text-red-500">

                            <i class="fas fa-times-circle text-5xl text-red-400"></i>

                        </div>

                        <div class="flex-1 space-y-1">

                            <p class="text-red-600 font-semibold">NÚMERO INVÁLIDO</p>

                            <p class="font-mono text-2xl font-bold text-gray-800">${currentNumber}</p>

                            <p class="text-gray-500">Candidato não encontrado. O voto será NULO se confirmado.</p>

                            <span class="inline-block bg-red-100 text-red-700 text-xs px-2 py-1 rounded-full">Voto nulo</span>

                        </div>

                    </div>

                `;

            }

        }


        // Atualiza tabela de resultados (apuração)

        function renderizarResultados() {

            if (!resultadosContainer) return;

            let html = '';

            // Exibe cada candidato com seus votos

            CANDIDATOS.forEach(cand => {

                const qtd = votos.candidatos[cand.numero] || 0;

                html += `

                    <div class="bg-gray-50 rounded-lg p-2 text-center border border-gray-200 shadow-sm">

                        <div class="font-bold text-gray-700 text-sm">${cand.nome.split(' ')[0]}</div>

                        <div class="text-xs text-gray-500">${cand.numero}</div>

                        <div class="text-xl font-bold text-green-700">${qtd}</div>

                    </div>

                `;

            });

            // Brancos e nulos

            html += `

                <div class="bg-gray-50 rounded-lg p-2 text-center border border-gray-200 shadow-sm">

                    <div class="font-bold text-gray-700 text-sm"><i class="fas fa-square"></i> BRANCOS</div>

                    <div class="text-xl font-bold text-amber-600">${votos.brancos}</div>

                </div>

                <div class="bg-gray-50 rounded-lg p-2 text-center border border-gray-200 shadow-sm">

                    <div class="font-bold text-gray-700 text-sm"><i class="fas fa-ban"></i> NULOS</div>

                    <div class="text-xl font-bold text-red-600">${votos.nulos}</div>

                </div>

            `;

            resultadosContainer.innerHTML = html;

        }


        // Registrar voto (lógica principal de confirmação)

        async function registrarVoto() {

            if (processingVote) {

                mostrarFeedback("Processando voto anterior... Aguarde.", "aviso");

                return;

            }

            

            // REGRA 1: se estiver em modo branco -> voto branco

            if (blankMode) {

                processingVote = true;

                // Incrementa votos brancos

                votos.brancos++;

                renderizarResultados();

                mostrarFeedback("🗳️ Voto em BRANCO registrado com sucesso!", "sucesso");

                resetarUrnaParaProximoVoto();

                processingVote = false;

                return;

            }

            

            // REGRA 2: Nenhum dígito e não branco -> instrução

            if (currentNumber.length === 0) {

                mostrarFeedback("Digite um número de candidato ou pressione BRANCO.", "erro");

                return;

            }

            

            // REGRA 3: verifica candidato existente ou voto nulo

            const candidato = candidatosMap.get(currentNumber);

            processingVote = true;

            

            if (candidato) {

                // Voto válido

                votos.candidatos[candidato.numero] = (votos.candidatos[candidato.numero] || 0) + 1;

                renderizarResultados();

                mostrarFeedback(`✔️ Voto confirmado para ${candidato.nome} (${candidato.numero}). Seu voto foi computado!`, "sucesso");

            } else {

                // Voto nulo (número inválido)

                votos.nulos++;

                renderizarResultados();

                mostrarFeedback(`⚠️ Voto NULO registrado! O número ${currentNumber} não corresponde a nenhum candidato.`, "aviso");

            }

            

            resetarUrnaParaProximoVoto();

            processingVote = false;

        }

        

        // Reinicia a urna após confirmação para próximo eleitor (limpa tela, número, modos)

        function resetarUrnaParaProximoVoto() {

            currentNumber = "";

            blankMode = false;

            atualizarInterfaceCompleta();

            // feedback não sobrescreve mensagem de sucesso, mas garantimos que a urna fique limpa

            // Mantém interface totalmente pronta.

        }

        

        // Adicionar dígito (limitado a 2 dígitos)

        function adicionarDigito(digito) {

            // Se estiver em modo branco, ao digitar desativa branco

            if (blankMode) {

                blankMode = false;

                currentNumber = "";

            }

            // Limite de 2 dígitos para presidente

            if (currentNumber.length < 2) {

                currentNumber += digito;

                atualizarInterfaceCompleta();

            } else {

                mostrarFeedback("Número de presidente possui apenas 2 dígitos. Use CORRIGE para reiniciar.", "aviso");

            }

        }

        

        // Corrige: limpa tudo e desativa modo branco

        function corrigeVoto() {

            if (processingVote) {

                mostrarFeedback("Aguarde finalizar a confirmação atual.", "aviso");

                return;

            }

            currentNumber = "";

            blankMode = false;

            atualizarInterfaceCompleta();

            mostrarFeedback("Operação corrigida. Digite novamente o número ou use BRANCO.", "info");

        }

        

        // Função especial para ativar voto em branco

        function ativarBranco() {

            if (processingVote) {

                mostrarFeedback("Aguarde antes de alterar o voto.", "aviso");

                return;

            }

            blankMode = true;

            currentNumber = "";

            atualizarInterfaceCompleta();

            mostrarFeedback("Voto em BRANCO selecionado. Confirme para finalizar.", "info");

        }

        

        // Reinicializar totalmente a votação (Zerar estatísticas)

        function resetarVotacaoCompleta() {

            if (confirm("⚠️ ATENÇÃO: Isso zerará TODOS os votos apurados. Deseja realmente reiniciar a votação?")) {

                // Zera contadores

                votos = {

                    candidatos: {},

                    brancos: 0,

                    nulos: 0

                };

                CANDIDATOS.forEach(c => { votos.candidatos[c.numero] = 0; });

                renderizarResultados();

                corrigeVoto(); // limpa interface atual e qualquer modo

                mostrarFeedback("🗳️ Estatísticas zeradas! Nova simulação iniciada.", "sucesso");

            }

        }

        

        // -------------------- 5. EVENTOS E INICIALIZAÇÃO --------------------

        function inicializarEventos() {

            // Botões numéricos (dinâmico)

            document.querySelectorAll("[data-digit]").forEach(btn => {

                btn.addEventListener("click", (e) => {

                    const digito = btn.getAttribute("data-digit");

                    if (digito !== null) adicionarDigito(digito);

                });

            });

            

            // Botões de ações

            btnBranco.addEventListener("click", ativarBranco);

            btnCorrige.addEventListener("click", corrigeVoto);

            btnConfirma.addEventListener("click", registrarVoto);

            resetVotosBtn.addEventListener("click", resetarVotacaoCompleta);

            

            // Opcional: suporte a teclado físico (acessibilidade)

            window.addEventListener("keydown", (e) => {

                const tecla = e.key;

                if (tecla >= "0" && tecla <= "9") {

                    e.preventDefault();

                    adicionarDigito(tecla);

                } else if (tecla === "Enter") {

                    e.preventDefault();

                    registrarVoto();

                } else if (tecla === "Delete" || tecla === "Backspace" || tecla === "Escape") {

                    e.preventDefault();

                    corrigeVoto();

                } else if (tecla === " " || tecla === "Space") {

                    e.preventDefault();

                    ativarBranco();

                }

            });

        }

        

        // Inicialização da aplicação

        function init() {

            inicializarEventos();

            resetarUrnaParaProximoVoto();    // estado inicial limpo

            renderizarResultados();           // renderiza apuração vazia

            mostrarFeedback("Urna pronta! Digite o número do candidato ou pressione BRANCO.", "info");

        }

        

        // Inicia o sistema quando o DOM estiver completamente carregado

        document.addEventListener("DOMContentLoaded", init);

    </script>

</body>

</html>

Reactions

Postar um comentário

0 Comentários