Otimização JS e HTML
Prompt
Apartir desse JS abaixo, preciso que crie um HTML com CS moderno, também preciso que otimize esse JS, para ficar mais enxuto. Não posso perder nenhum funcionalidade, só quero que ele fique enxuto e funcional. Utilizo ele com Flask em ptyhon. Então só preciso do HTML, css e esse JS otimizado.
document.addEventListener("DOMContentLoaded", () => {
const tabela = document.querySelector("#pedidoGrid tbody");
const botaoAdicionar = document.querySelector("#adicionarLinha");
const boletaFinalizadaCheckbox = document.querySelector("#boleta_finalizada");
// Modais e botões
const botaoLupa = document.getElementById("botao-lupa");
const modalBuscarCliente = document.getElementById("modal-buscar-cliente");
const botaoBuscarCliente = document.getElementById("botao-buscar");
const campoNome = document.getElementById("campo-nome");
const campoCPF = document.getElementById("campo-cpf");
const campoCNPJ = document.getElementById("campo-cnpj");
const resultadoBusca = document.getElementById("resultado-busca");
const campoCliente = document.querySelector("#campo-cliente");
// Exemplo de clientes para busca (simulação, substitua pelos seus dados reais)
const clientes = [
{ id: 1, nome: "Cliente A", cpf: "123.456.789-00", cnpj: "" },
{ id: 2, nome: "Cliente B", cpf: "", cnpj: "12.345.678/0001-99" },
{ id: 3, nome: "Cliente C", cpf: "234.567.890-11", cnpj: "" },
{ id: 4, nome: "Empresa D", cpf: "", cnpj: "98.765.432/0001-88" },
];
// Função para abrir modal
const abrirModal = () => {
modalBuscarCliente.style.display = "block";
campoNome.focus();
};
// Função para fechar modal
const fecharModal = () => {
modalBuscarCliente.style.display = "none";
};
// Abrir modal ao clicar na lupa
botaoLupa.addEventListener("click", () => {
limparCamposModal();
abrirModal();
});
// Fechar modal ao clicar no botão de fechar (X)
document
.querySelector("#modal-buscar-cliente .close-button")
.addEventListener("click", fecharModal);
// Fechar modal ao pressionar a tecla ESC
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
fecharModal();
}
});
// Limpar campos do modal
function limparCamposModal() {
campoNome.value = "";
campoCPF.value = "";
campoCNPJ.value = "";
resultadoBusca.innerHTML = "";
}
// Máscara para CPF
campoCPF.addEventListener("input", (event) => {
let valor = event.target.value.replace(/\D/g, "");
valor = valor.replace(/(\d{3})(\d)/, "$1.$2");
valor = valor.replace(/(\d{3})(\d)/, "$1.$2");
valor = valor.replace(/(\d{3})(\d{1,2})$/, "$1-$2");
event.target.value = valor;
});
// Máscara para CNPJ
campoCNPJ.addEventListener("input", (event) => {
let valor = event.target.value.replace(/\D/g, "");
valor = valor.replace(/^(\d{2})(\d)/, "$1.$2");
valor = valor.replace(/^(\d{2})\.(\d{3})(\d)/, "$1.$2.$3");
valor = valor.replace(/\.(\d{3})(\d)/, ".$1/$2");
valor = valor.replace(/(\d{4})(\d{1,2})$/, "$1-$2");
event.target.value = valor;
});
let idClienteAtual = null;
let pedidosData = {}; // Objeto para armazenar detalhes dos pedidos
// Função para limpar a boleta (tabela)
function limparBoleta() {
// Seleciona a primeira linha da tabela
const primeiraLinha = tabela.querySelector("tr");
// Limpa o conteúdo da primeira linha em vez de remover a linha
if (primeiraLinha) {
// Limpa os campos específicos da linha, mantendo o combo
const comboPedidos = primeiraLinha.querySelector(".combo-pedidos");
if (comboPedidos) {
comboPedidos.innerHTML = "<option value=''>Selecione o Pedido</option>"; // Reseta as opções, mas deixa o combo acessível
}
primeiraLinha.children[1].textContent = ""; // Filial
primeiraLinha.children[2].textContent = ""; // Valor Pedido
primeiraLinha.children[3].textContent = ""; // Valor Frete
primeiraLinha.children[4].textContent = ""; // Valor Desconto
primeiraLinha.children[5].textContent = ""; // DS (Campo Editável)
primeiraLinha.children[6].textContent = ""; // Valor Final
primeiraLinha.children[7].textContent = ""; // Condição Pagamento
primeiraLinha.children[8].textContent = ""; // NSU
primeiraLinha.children[9].textContent = ""; // OBS
// Adiciona apenas a data na última coluna
const dataAtual = new Date();
const dataFormatada = dataAtual.toLocaleDateString(); // Apenas a data
primeiraLinha.children[10].textContent = dataFormatada; // Atualiza a última coluna com a data
}
// Remove quaisquer outras linhas que estejam na tabela
const outrasLinhas = tabela.querySelectorAll("tr:not(:first-child)");
outrasLinhas.forEach((linha) => linha.remove());
}
// Função para buscar clientes
function buscarClientes() {
// Converter valores dos campos para uppercase antes de enviar (Nome)
const nome = campoNome.value.toUpperCase().trim();
// Manter a máscara dos campos CPF e CNPJ
const cpf = campoCPF.value.toUpperCase().trim();
const cnpj = campoCNPJ.value.toUpperCase().trim();
// Garantir que pelo menos um campo seja preenchido
if (!nome && !cpf && !cnpj) {
resultadoBusca.innerHTML =
"<p style='color: red;'>Preencha pelo menos um dos campos para buscar.</p>";
return;
}
// Indicar que está carregando
resultadoBusca.innerHTML =
"<p style='color: blue;'>Buscando clientes, por favor aguarde...</p>";
// Construir a URL da API com base nos parâmetros de busca
let url = `/buscar_clientes?`;
if (nome) {
url += `nome=${nome}&`;
}
if (cpf) {
url += `cpf=${cpf}&`;
}
if (cnpj) {
url += `cnpj=${cnpj}&`;
}
url = url.slice(0, -1); // Remover o último '&'
// Fazer a chamada AJAX para a rota /buscar_clientes do Flask
fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error(`Erro na requisição: ${response.status}`);
}
return response.json();
})
.then((clientes) => {
// Limpar o conteúdo anterior
resultadoBusca.innerHTML = "";
if (clientes.length > 0) {
clientes.forEach((cliente) => {
const item = document.createElement("div");
item.textContent = `${cliente.nome} ${cliente.cpf ? `- CPF: ${cliente.cpf}` : `- CNPJ: ${cliente.cnpj}`
}`;
item.style.cursor = "pointer";
item.style.padding = "8px";
item.style.borderBottom = "1px solid #ccc";
item.addEventListener("click", () => selecionarCliente(cliente));
resultadoBusca.appendChild(item);
});
} else {
resultadoBusca.innerHTML =
"<p style='color: red;'>Nenhum cliente encontrado.</p>";
}
})
.catch((error) => {
console.error("Erro ao buscar clientes:", error);
resultadoBusca.innerHTML =
"<p style='color: red;'>Erro ao consultar clientes. Tente novamente mais tarde.</p>";
});
}
// Executar busca ao clicar no botão ou pressionar Enter
botaoBuscarCliente.addEventListener("click", buscarClientes);
[campoNome, campoCPF, campoCNPJ].forEach((campo) => {
campo.addEventListener("keypress", (event) => {
if (event.key === "Enter") {
event.preventDefault(); // Evita o comportamento padrão do Enter
buscarClientes();
}
});
});
// Função para selecionar o cliente
function selecionarCliente(cliente) {
const campoCliente = document.querySelector("#campo-cliente");
campoCliente.value = `${cliente.nome} ${cliente.cpf ? `- CPF: ${cliente.cpf}` : `- CNPJ: ${cliente.cnpj}`}`;
idClienteAtual = cliente.cliente; // Garante que está pegando o campo correto
limparBoleta(); // Limpa a tabela antes de prosseguir
fecharModal();
buscarPedidosDoCliente(idClienteAtual);
console.log("ID do cliente selecionado:", idClienteAtual); // Adicionado log para depuração
}
function buscarPedidosDoCliente(idCliente) {
const comboPedidos = document.querySelector("#combo-pedidos");
comboPedidos.innerHTML = "<option value=''>Carregando...</option>";
const url = `/buscar_pedidos_cliente?id_cliente=${idCliente}`;
fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error(`Erro na requisição: ${response.status}`);
}
return response.json();
})
.then((data) => {
pedidosData = {}; // Limpa os dados antigos
comboPedidos.innerHTML = "<option value=''>Selecione o Pedido</option>";
if (data.length === 0) {
comboPedidos.innerHTML = "<option value=''>Nenhum pedido encontrado</option>";
return;
}
// Imprime a resposta do backend no console
console.log("Resposta do backend:", data);
data.forEach((pedido) => {
pedidosData[pedido.pedido_venda] = pedido; // Armazena detalhes do pedido usando `pedido_venda` como chave
const option = document.createElement("option");
option.value = pedido.pedido_venda; // Define o valor do select
option.textContent = pedido.pedido_venda; // Exibe o texto do pedido
comboPedidos.appendChild(option);
});
})
.catch((error) => {
console.error("Erro ao buscar pedidos:", error);
comboPedidos.innerHTML = "<option value=''>Erro ao carregar os pedidos</option>";
});
}
document.querySelector("#combo-pedidos").addEventListener("change", function () {
const pedidoSelecionado = this.value;
// Verifica se o pedido foi selecionado
if (!pedidoSelecionado || !pedidosData[pedidoSelecionado]) {
return;
}
const pedidoDetalhes = pedidosData[pedidoSelecionado]; // Obtém os detalhes do pedido
const linhaTabela = document.querySelector("#pedidoGrid tbody tr"); // Seleciona a linha da tabela
// Preenche as colunas com os valores do pedido
linhaTabela.children[1].textContent = pedidoDetalhes.filial || "N/A"; // Filial
linhaTabela.children[2].textContent = `R$ ${pedidoDetalhes.valor_pedido.toFixed(2)}`;
linhaTabela.children[3].textContent = `R$ ${pedidoDetalhes.frete.toFixed(2)}`;
linhaTabela.children[4].textContent = `R$ ${pedidoDetalhes.desconto.toFixed(2)}`;
linhaTabela.children[7].textContent = pedidoDetalhes.cond_pgto || "N/A"; // Preenche a condição de pagamento
// Calcula o valor final
const valorFinal = pedidoDetalhes.valor_pedido + pedidoDetalhes.frete + pedidoDetalhes.desconto;
linhaTabela.children[6].textContent = `R$ ${valorFinal.toFixed(2)}`;
console.log("Detalhes do pedido selecionado:", pedidoDetalhes);
});
// Função para formatar o valor como moeda no padrão brasileiro
function formatarMoeda(valor) {
valor = valor.replace(/[^\d,]/g, "");
valor = valor.replace(",", ".");
let numero = parseFloat(valor);
return isNaN(numero)
? "0,00"
: numero.toLocaleString("pt-BR", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
// Função para validar entrada (aceitar apenas números e vírgula)
function validarEntradaNumerica(event) {
if (
!/[0-9,]/.test(event.key) &&
!["Backspace", "Delete", "Enter", "Tab", "."].includes(event.key)
) {
event.preventDefault();
}
}
// Função para limpar o combo de pedidos
function limparPedidos() {
const comboPedidos = document.querySelector("#combo-pedidos");
comboPedidos.innerHTML = "<option value=''>Selecione o Pedido</option>";
}
// Adiciona comportamentos aos campos numéricos
function configurarCamposNumericos(linha) {
const camposNumericos = [1, 2, 3, 4].map((indice) => linha.children[indice]);
camposNumericos.forEach((campo) => {
campo.textContent = "";
campo.addEventListener("keydown", validarEntradaNumerica);
campo.addEventListener("blur", () => (campo.textContent = formatarMoeda(campo.textContent)));
campo.addEventListener("keypress", (event) => {
if (event.key === "Enter") {
event.preventDefault();
campo.blur();
}
});
});
}
// Função para limitar o número de caracteres
function limitarInput(event, maxLength) {
const target = event.target;
if (target.textContent.length > maxLength) {
target.textContent = target.textContent.slice(0, maxLength);
const range = document.createRange();
range.selectNodeContents(target);
range.collapse(false);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
}
// Adicionar nova linha à tabela
botaoAdicionar.addEventListener("click", () => adicionarLinha());
function adicionarLinha() {
const novaLinha = document.createElement("tr");
const index = tabela.children.length; // Gera um índice único baseado no número de linhas
novaLinha.setAttribute("data-index", index);
novaLinha.innerHTML = `
<td>
<select class="combo-pedidos" data-index="${index}">
<option value="">Selecione o Pedido</option>
</select>
</td>
<td contenteditable="false"></td>
<td contenteditable="false"></td>
<td contenteditable="false"></td>
<td contenteditable="false"></td>
<td contenteditable="true"></td>
<td contenteditable="false"></td>
<td contenteditable="false"></td>
<td contenteditable="true" class="editable" data-maxlength="30"></td>
<td contenteditable="true" class="editable" data-maxlength="300"></td>
<td>${new Date().toLocaleDateString()}</td>`;
tabela.appendChild(novaLinha);
// Recupera o combo específico da linha
const comboPedidos = novaLinha.querySelector(".combo-pedidos");
comboPedidos.addEventListener("change", (event) => {
const linha = comboPedidos.closest("tr"); // Encontra a linha correspondente
preencherDadosPedidoNaLinha(event, linha); // Passa a linha para preenchimento
});
buscarPedidosDoClienteEspecifico(idClienteAtual, comboPedidos); // Carrega os pedidos
atualizarVisibilidadeLixeiras();
// Adiciona event listeners para os campos NSU e OBS da nova linha
const nsuCell = novaLinha.querySelector('td[contenteditable="true"][data-maxlength="30"]');
const obsCell = novaLinha.querySelector('td[contenteditable="true"][data-maxlength="300"]');
nsuCell.addEventListener('input', limitarConteudo);
obsCell.addEventListener('input', limitarConteudo);
}
function limitarConteudo(event) {
const target = event.target;
const maxLength = parseInt(target.dataset.maxlength, 10);
if (isNaN(maxLength)) {
return; // Se o atributo não estiver definido, não faz nada
}
if (target.textContent.length > maxLength) {
target.textContent = target.textContent.slice(0, maxLength);
// Move o cursor para o final do texto truncado
const range = document.createRange();
range.selectNodeContents(target);
range.collapse(false);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
}
// Adicione event listeners para os campos NSU e OBS existentes
document.querySelectorAll('td[data-maxlength]').forEach(function (cell) {
cell.addEventListener('input', limitarConteudo);
});
function buscarPedidosDoClienteEspecifico(idCliente, comboPedidos) {
comboPedidos.innerHTML = "<option value=''>Carregando...</option>";
const url = `/buscar_pedidos_cliente?id_cliente=${idCliente}`;
fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error(`Erro na requisição: ${response.status}`);
}
return response.json();
})
.then((data) => {
pedidosData = {}; // Limpa os dados antigos
comboPedidos.innerHTML = "<option value=''>Selecione o Pedido</option>";
if (data.length === 0) {
comboPedidos.innerHTML = "<option value=''>Nenhum pedido encontrado</option>";
return;
}
data.forEach((pedido) => {
pedidosData[pedido.pedido_venda] = pedido; // Armazena detalhes do pedido usando `pedido_venda` como chave
const option = document.createElement("option");
option.value = pedido.pedido_venda; // Define o valor do select
option.textContent = pedido.pedido_venda; // Exibe o texto do pedido
comboPedidos.appendChild(option);
});
})
.catch((error) => {
console.error("Erro ao buscar pedidos:", error);
comboPedidos.innerHTML = "<option value=''>Erro ao carregar os pedidos</option>";
});
}
function preencherDadosPedidoNaLinha(event, linha) {
const pedidoSelecionado = event.target.value;
const pedidoDetalhes = pedidosData[pedidoSelecionado];
if (!pedidoDetalhes) return;
// Preenche os campos da linha com os valores do pedido
linha.children[1].textContent = pedidoDetalhes.filial || "N/A"; // Filial
linha.children[2].textContent = `R$ ${pedidoDetalhes.valor_pedido.toFixed(2)}`; // Valor Pedido
linha.children[3].textContent = `R$ ${pedidoDetalhes.frete.toFixed(2)}`; // Valor Frete
linha.children[4].textContent = `R$ ${pedidoDetalhes.desconto.toFixed(2)}`; // Valor Desconto
linha.children[7].textContent = pedidoDetalhes.cond_pgto || "N/A"; // Condição Pagamento
// Atualiza o Valor Final automaticamente
atualizarValorFinal(linha);
}
function atualizarValorFinal(linha) {
const valorPedido = parseFloat(linha.children[2].textContent.replace("R$", "").replace(",", ".")) || 0;
const valorFrete = parseFloat(linha.children[3].textContent.replace("R$", "").replace(",", ".")) || 0;
const valorDesconto = parseFloat(linha.children[4].textContent.replace("R$", "").replace(",", ".")) || 0;
const ds = parseFloat(linha.children[5].textContent.replace(",", ".")) || 0;
// Calcula o valor final
const valorFinal = valorPedido + valorFrete - valorDesconto - ds;
// Atualiza o campo Valor Final da linha
linha.children[6].textContent = `R$ ${valorFinal.toFixed(2)}`;
}
function atualizarCalculos(linha) {
const camposEditaveis = linha.querySelectorAll(".editable");
const valorFinalCell = linha.children[6];
camposEditaveis.forEach((campo, index) => {
campo.removeEventListener("click", () => (campo.textContent = ""));
campo.addEventListener("keydown", (event) => {
if (event.key === "Enter") {
event.preventDefault();
const proximoCampo =
camposEditaveis[index + 1] || camposEditaveis[0];
proximoCampo.focus();
}
});
campo.addEventListener("input", () => calcularValorFinal(linha, valorFinalCell));
});
}
function calcularValorFinal(linha, valorFinalCell) {
const valorPedido =
parseFloat(linha.children[1].textContent.replace(/\./g, "").replace(",", ".")) || 0;
const valorFrete =
parseFloat(linha.children[2].textContent.replace(/\./g, "").replace(",", ".")) || 0;
const valorDesconto =
parseFloat(linha.children[3].textContent.replace(/\./g, "").replace(",", ".")) || 0;
const ds =
parseFloat(linha.children[4].textContent.replace(/\./g, "").replace(",", ".")) || 0;
const valorFinal = valorPedido + valorFrete - valorDesconto - ds;
valorFinalCell.textContent = valorFinal.toLocaleString("pt-BR", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
function adicionarLixeira(linha) {
const celulaLixeira = document.createElement("td");
celulaLixeira.innerHTML = '<i class="fas fa-trash lixeira" style="cursor: pointer;"></i>';
linha.appendChild(celulaLixeira);
// Adiciona evento de clique na lixeira para remover a linha
celulaLixeira.addEventListener("click", () => {
removerLinha(linha);
});
}
function removerLinha(linha) {
tabela.removeChild(linha);
atualizarVisibilidadeLixeiras();
}
function atualizarVisibilidadeLixeiras() {
const linhas = tabela.querySelectorAll("tr"); // Seleciona todas as linhas
const tabelaHeader = tabela.closest("table").querySelector("thead tr"); // Cabeçalho da tabela
// Verifica ou adiciona a coluna de lixeira no cabeçalho
let thLixeira = tabelaHeader.querySelector(".lixeira");
if (linhas.length > 1) {
if (!thLixeira) {
thLixeira = document.createElement("th");
thLixeira.classList.add("lixeira");
thLixeira.style.width = "50px"; // Ajuste opcional
tabelaHeader.appendChild(thLixeira);
}
// Adiciona lixeira a todas as linhas
linhas.forEach((linha) => {
let celulaLixeira = linha.querySelector("td.lixeira");
if (!celulaLixeira) {
celulaLixeira = document.createElement("td");
celulaLixeira.classList.add("lixeira");
celulaLixeira.innerHTML = `<i class="fas fa-trash" style="cursor: pointer; color: red;"></i>`;
// Evento para remoção da linha
celulaLixeira.querySelector("i").addEventListener("click", () => {
removerLinha(linha);
});
linha.appendChild(celulaLixeira); // Adiciona a lixeira na linha
}
});
} else {
// Remove a coluna e as lixeiras, pois só há uma linha
if (thLixeira) {
thLixeira.remove();
}
linhas.forEach((linha) => {
const celulaLixeira = linha.querySelector("td.lixeira");
if (celulaLixeira) {
celulaLixeira.remove();
}
});
}
}
tabela.addEventListener("click", (event) => {
if (event.target.classList.contains("lixeira")) {
const linha = event.target.closest("tr");
linha.remove();
atualizarVisibilidadeLixeiras();
}
});
// Função para limpar o combo de pedidos
function limparPedidos() {
const comboPedidos = document.querySelector("#combo-pedidos");
comboPedidos.innerHTML = "<option value=''>Selecione o Pedido</option>";
}
// Inicialização
// atualizarVisibilidadeLixeiras();
// Evento do botão toggle "Boleta Finalizada"
boletaFinalizadaCheckbox.addEventListener("change", function () {
if (boletaFinalizadaCheckbox.checked) {
console.log("Boleta Finalizada: true");
} else {
console.log("Boleta Finalizada: false");
}
});
// Inicializa o Listener para o combo de pedidos, após a criação da linha
const comboPedidosInicial = document.querySelector("#combo-pedidos");
if (comboPedidosInicial) {
buscarPedidosDoClienteEspecifico(idClienteAtual, comboPedidosInicial);
comboPedidosInicial.addEventListener("change", preencherDadosPedidoNaLinha);
}
document.getElementById("limparBoleta").addEventListener("click", function (event) {
event.preventDefault(); // Evita que a página seja atualizada imediatamente
if (confirm("Tem certeza que deseja limpar todas as informações da boleta?")) {
location.reload(); // Limpa a boleta
}
});
});
document.addEventListener("DOMContentLoaded", () => {
const tabela = document.querySelector("#pedidoGrid tbody");
// const botaoAdicionar = document.querySelector("#adicionarLinha");
// Adiciona os eventos necessários à tabela
tabela.addEventListener("input", (event) => {
const target = event.target;
// Se a célula editada for a coluna "DS (R$)"
if (target && target.cellIndex === 5) { // Índice 4 corresponde ao "DS (R$)"
formatarComoMoeda(target); // Formata como moeda
recalcularLinha(target.closest("tr")); // Recalcula o valor final da linha
}
});
// Função para formatar uma célula como moeda
function formatarComoMoeda(celula) {
celula.textContent = celula.textContent.replace(/[^\d,.\-]/g, ''); // Remove caracteres não numéricos
}
// Função para recalcular o valor final da linha
function recalcularLinha(linha) {
const valorPedido = parseFloat(obterNumeroDaCelula(linha.cells[2])); // Valor Pedido (R$)
const valorFrete = parseFloat(obterNumeroDaCelula(linha.cells[3])); // Valor Frete (R$)
const valorDesconto = parseFloat(obterNumeroDaCelula(linha.cells[4])); // Valor Desconto (R$)
const valorDS = parseFloat(obterNumeroDaCelula(linha.cells[5])); // DS (R$)
// Calcula o valor final
const valorFinal = valorPedido + valorFrete - valorDesconto - valorDS;
// Atualiza a coluna "Valor Final (R$)"
linha.cells[6].textContent = valorFinal.toLocaleString("pt-BR", {
style: "currency",
currency: "BRL",
});
}
// Função para obter o número de uma célula (removendo formatação)
function obterNumeroDaCelula(celula) {
if (!celula) return 0;
const valor = celula.textContent.replace(/[^\d,.-]/g, "").replace(",", ".");
return parseFloat(valor) || 0;
}
});Resultado Gerado
Mais Recomendações
Ver TodosCriar Site Loja Roupas
Desejo criar um site para uma loja de roupas feminias que seja extremamento persoasivo e com todos os recursos para ser encontrado nas buscas do google e instagram, facebook
Criar Web App RPG Inspirado em Diablo II
Crie um web app com visual inspirado em jogos RPG estilo Diablo II. No centro da tela, exiba um personagem animado em pixel art usando esta spritesheet vertical: https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/2ab05d2c-376c-4f03-b12a-f85300e15690/dfouvz7-e626a8a6-df28-4053-ad42-989874e2214c.png/v1/fill/w_603%2Ch_1324%2Cq_70%2Cstrp/diablo__isekai_maou__sprite_sheet_v2_by_quinmf_dfouvz7-pre.jpg A spritesheet possui 8 frames verticais, com largura de 603px e altura total de 1324px. O personagem deve estar animado em loop, usando CSS keyframes para alterar a posição do background verticalmente. A imagem deve ser carregada como background-image de um div com tamanho 603x166 px. Use Tailwind CSS ou CSS puro com steps(8) para simular a animação. O fundo da página deve ter uma estética medieval dark (ex: textura de pedra, tons escuros). Adicione no topo da tela uma HUD com barra de vida (vermelha) e mana (azul), estilizadas como em jogos clássicos. Tudo deve rodar no navegador, sem dependência de APIs externas.
Criar Página de Registro React
crie uma pagina de registro em react
Catálogo de Produtos React
quero alteração desse meu catalogo seja feita por cada produto, quando estou clicando em uma cor ele clica também para o proximo produto. E sem contar que quero alguns exemplos de cores para serem selecionados e que apareça o nome da cor: import React, { useState, useEffect } from 'react'; import './App.css'; const App = () => { const [products, setProducts] = useState([]); const [selectedColor, setSelectedColor] = useState(''); const [selectedSize, setSelectedSize] = useState(''); const [price, setPrice] = useState(0); const [stock, setStock] = useState(0); useEffect(() => { // Simulando a busca de produtos do backend const fetchedProducts = [ { id: 1, name: 'Camiseta Básica', image: 'https://placehold.co/300X300', colors: ['Branco', 'Preto', 'Azul'], sizes: ['P', 'M', 'G'], prices: [29.99, 29.99, 34.99], stock: [10, 15, 8] }, { id: 2, name: 'Calça Jeans', image: 'https://placehold.co/300X300', colors: ['Azul', 'Preto'], sizes: ['38', '40', '42'], prices: [89.99, 99.99], stock: [5, 7] } ]; setProducts(fetchedProducts); if (fetchedProducts.length > 0) { setSelectedColor(fetchedProducts[0].colors[0]); setSelectedSize(fetchedProducts[0].sizes[0]); setPrice(fetchedProducts[0].prices[0]); setStock(fetchedProducts[0].stock[0]); } }, []); const handleColorChange = (productIndex, colorIndex) => { setSelectedColor(products[productIndex].colors[colorIndex]); setPrice(products[productIndex].prices[colorIndex]); setStock(products[productIndex].stock[colorIndex]); }; const handleSizeChange = (productIndex, sizeIndex) => { setSelectedSize(products[productIndex].sizes[sizeIndex]); }; return ( <div className="App min-h-screen bg-gray-100 py-8"> <div className="container mx-auto px-4"> <h1 className="text-4xl font-bold text-center mb-8">Catálogo de Vestuário</h1> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> {products.map((product, productIndex) => ( <div key={product.id} className="bg-white rounded-lg shadow-md p-6"> <img src={product.image} alt={product.name} className="w-full h-64 object-cover rounded-lg mb-4" /> <h2 className="text-xl font-semibold mb-2">{product.name}</h2> <div className="mb-4"> <label className="block text-sm font-medium text-gray-700">Cor:</label> <div className="flex space-x-2 mt-1"> {product.colors.map((color, colorIndex) => ( <button key={colorIndex} onClick={() => handleColorChange(productIndex, colorIndex)} className={`w-8 h-8 rounded-full border-2 ${selectedColor === color ? 'border-blue-500' : 'border-gray-300'} focus:outline-none`} style={{ backgroundColor: color.toLowerCase() }} ></button> ))} </div> </div> <div className="mb-4"> <label className="block text-sm font-medium text-gray-700">Tamanho:</label> <div className="flex space-x-2 mt-1"> {product.sizes.map((size, sizeIndex) => ( <button key={sizeIndex} onClick={() => handleSizeChange(productIndex, sizeIndex)} className={`px-4 py-2 rounded-md ${selectedSize === size ? 'bg-blue-500 text-white' : 'bg-gray-200 text-gray-700'} focus:outline-none`} > {size} </button> ))} </div> </div> <div className="text-lg font-semibold mb-2">Preço: R$ {price.toFixed(2)}</div> <div className="text-sm text-gray-600">Estoque: {stock} unidades</div> </div> ))} </div> <div className="mt-8 text-center text-sm text-gray-500"> © 2025 Todos os direitos reservados. </div> </div> </div> ); }; export default App;
Catálogo de Produtos React
quero alteração desse meu catalogo seja feita por cada produto, quando estou clicando em uma cor ele clica também para o proximo produto. E sem contar que quero alguns exemplos de cores para serem selecionados e que apareça o nome da cor: import React, { useState, useEffect } from 'react'; import './App.css'; const App = () => { const [products, setProducts] = useState([]); const [selectedColor, setSelectedColor] = useState(''); const [selectedSize, setSelectedSize] = useState(''); const [price, setPrice] = useState(0); const [stock, setStock] = useState(0); useEffect(() => { // Simulando a busca de produtos do backend const fetchedProducts = [ { id: 1, name: 'Camiseta Básica', image: 'https://placehold.co/300X300', colors: ['Branco', 'Preto', 'Azul'], sizes: ['P', 'M', 'G'], prices: [29.99, 29.99, 34.99], stock: [10, 15, 8] }, { id: 2, name: 'Calça Jeans', image: 'https://placehold.co/300X300', colors: ['Azul', 'Preto'], sizes: ['38', '40', '42'], prices: [89.99, 99.99], stock: [5, 7] } ]; setProducts(fetchedProducts); if (fetchedProducts.length > 0) { setSelectedColor(fetchedProducts[0].colors[0]); setSelectedSize(fetchedProducts[0].sizes[0]); setPrice(fetchedProducts[0].prices[0]); setStock(fetchedProducts[0].stock[0]); } }, []); const handleColorChange = (productIndex, colorIndex) => { setSelectedColor(products[productIndex].colors[colorIndex]); setPrice(products[productIndex].prices[colorIndex]); setStock(products[productIndex].stock[colorIndex]); }; const handleSizeChange = (productIndex, sizeIndex) => { setSelectedSize(products[productIndex].sizes[sizeIndex]); }; return ( <div className="App min-h-screen bg-gray-100 py-8"> <div className="container mx-auto px-4"> <h1 className="text-4xl font-bold text-center mb-8">Catálogo de Vestuário</h1> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> {products.map((product, productIndex) => ( <div key={product.id} className="bg-white rounded-lg shadow-md p-6"> <img src={product.image} alt={product.name} className="w-full h-64 object-cover rounded-lg mb-4" /> <h2 className="text-xl font-semibold mb-2">{product.name}</h2> <div className="mb-4"> <label className="block text-sm font-medium text-gray-700">Cor:</label> <div className="flex space-x-2 mt-1"> {product.colors.map((color, colorIndex) => ( <button key={colorIndex} onClick={() => handleColorChange(productIndex, colorIndex)} className={`w-8 h-8 rounded-full border-2 ${selectedColor === color ? 'border-blue-500' : 'border-gray-300'} focus:outline-none`} style={{ backgroundColor: color.toLowerCase() }} ></button> ))} </div> </div> <div className="mb-4"> <label className="block text-sm font-medium text-gray-700">Tamanho:</label> <div className="flex space-x-2 mt-1"> {product.sizes.map((size, sizeIndex) => ( <button key={sizeIndex} onClick={() => handleSizeChange(productIndex, sizeIndex)} className={`px-4 py-2 rounded-md ${selectedSize === size ? 'bg-blue-500 text-white' : 'bg-gray-200 text-gray-700'} focus:outline-none`} > {size} </button> ))} </div> </div> <div className="text-lg font-semibold mb-2">Preço: R$ {price.toFixed(2)}</div> <div className="text-sm text-gray-600">Estoque: {stock} unidades</div> </div> ))} </div> <div className="mt-8 text-center text-sm text-gray-500"> © 2025 Todos os direitos reservados. </div> </div> </div> ); }; export default App;
Catálogo de Roupas em Flask
Quero um aplicativo no modelo de catalogo para o ramo de vestuário e confecção, com a possibilidade de escolhe cor e tamnho para cada produto, e traga o preço e o estoque ao selecionar cada uma delas. Ele precisa estar 100% em português. Vou utilizar o Flask do Python com backend, então tente utilizar mais CSS e html. Preciso que adicione foto nesse catalogo e que traga já uma cor e um tamanho preenchido, os primeiros da lista
