feat: melhorias na interface e estrutura do frontend
This commit is contained in:
145
static/js/main.js
Normal file
145
static/js/main.js
Normal file
@@ -0,0 +1,145 @@
|
||||
// Máscaras para campos de formulário
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Máscara para CPF
|
||||
const cpfInputs = document.querySelectorAll('input[name="cpf"]');
|
||||
cpfInputs.forEach(input => {
|
||||
input.addEventListener('input', function(e) {
|
||||
let value = e.target.value.replace(/\D/g, '');
|
||||
if (value.length <= 11) {
|
||||
value = value.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, "$1.$2.$3-$4");
|
||||
e.target.value = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Máscara para telefone
|
||||
const phoneInputs = document.querySelectorAll('input[name="telefone"]');
|
||||
phoneInputs.forEach(input => {
|
||||
input.addEventListener('input', function(e) {
|
||||
let value = e.target.value.replace(/\D/g, '');
|
||||
if (value.length <= 11) {
|
||||
if (value.length === 11) {
|
||||
value = value.replace(/(\d{2})(\d{5})(\d{4})/, "($1) $2-$3");
|
||||
} else {
|
||||
value = value.replace(/(\d{2})(\d{4})(\d{4})/, "($1) $2-$3");
|
||||
}
|
||||
e.target.value = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Formatação de valores monetários
|
||||
const moneyInputs = document.querySelectorAll('input[type="number"][step="0.01"]');
|
||||
moneyInputs.forEach(input => {
|
||||
input.addEventListener('blur', function(e) {
|
||||
const value = parseFloat(e.target.value);
|
||||
if (!isNaN(value)) {
|
||||
e.target.value = value.toFixed(2);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Funções para tabelas
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tables = document.querySelectorAll('.table');
|
||||
tables.forEach(table => {
|
||||
// Ordenação
|
||||
const headers = table.querySelectorAll('th[data-sort]');
|
||||
headers.forEach(header => {
|
||||
header.addEventListener('click', function() {
|
||||
const column = this.dataset.sort;
|
||||
const asc = this.classList.toggle('sort-asc');
|
||||
const tbody = table.querySelector('tbody');
|
||||
const rows = Array.from(tbody.querySelectorAll('tr'));
|
||||
|
||||
rows.sort((a, b) => {
|
||||
const aVal = a.querySelector(`td[data-${column}]`).dataset[column];
|
||||
const bVal = b.querySelector(`td[data-${column}]`).dataset[column];
|
||||
return asc ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
|
||||
});
|
||||
|
||||
rows.forEach(row => tbody.appendChild(row));
|
||||
});
|
||||
});
|
||||
|
||||
// Filtro
|
||||
const filterInput = document.querySelector(`#filter-${table.id}`);
|
||||
if (filterInput) {
|
||||
filterInput.addEventListener('input', function() {
|
||||
const searchTerm = this.value.toLowerCase();
|
||||
const rows = table.querySelectorAll('tbody tr');
|
||||
|
||||
rows.forEach(row => {
|
||||
const text = row.textContent.toLowerCase();
|
||||
row.style.display = text.includes(searchTerm) ? '' : 'none';
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Validação de formulários
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const forms = document.querySelectorAll('form');
|
||||
forms.forEach(form => {
|
||||
form.addEventListener('submit', function(e) {
|
||||
if (!form.checkValidity()) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// Destacar campos inválidos
|
||||
const invalidInputs = form.querySelectorAll(':invalid');
|
||||
invalidInputs.forEach(input => {
|
||||
input.classList.add('is-invalid');
|
||||
|
||||
// Adicionar mensagem de erro
|
||||
const feedback = document.createElement('div');
|
||||
feedback.className = 'invalid-feedback';
|
||||
feedback.textContent = input.validationMessage;
|
||||
input.parentNode.appendChild(feedback);
|
||||
});
|
||||
}
|
||||
|
||||
form.classList.add('was-validated');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Animações e feedback visual
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Animar cards ao carregar
|
||||
const cards = document.querySelectorAll('.card');
|
||||
cards.forEach((card, index) => {
|
||||
card.style.opacity = '0';
|
||||
card.style.transform = 'translateY(20px)';
|
||||
setTimeout(() => {
|
||||
card.style.transition = 'all 0.3s ease';
|
||||
card.style.opacity = '1';
|
||||
card.style.transform = 'translateY(0)';
|
||||
}, index * 100);
|
||||
});
|
||||
|
||||
// Feedback visual para ações
|
||||
const actionButtons = document.querySelectorAll('[data-action]');
|
||||
actionButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
button.classList.add('animate__animated', 'animate__pulse');
|
||||
setTimeout(() => {
|
||||
button.classList.remove('animate__animated', 'animate__pulse');
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Confirmações de ações
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const deleteButtons = document.querySelectorAll('[data-confirm]');
|
||||
deleteButtons.forEach(button => {
|
||||
button.addEventListener('click', function(e) {
|
||||
if (!confirm(this.dataset.confirm)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user