otimizacoes de performance
Signed-off-by: Rodrigo Bertoldo de Sousa Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
1 parent
f23b925a99
commit
685d37e3f6
2 files changed
+70
-118
No files matched your search
BIN
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
+70
-118
@@ -36,6 +36,7 @@
|
||||
background-size: 400% 400%;
|
||||
animation: gradientAnimation 15s ease infinite;
|
||||
z-index: -2;
|
||||
will-change: background-position;
|
||||
}
|
||||
|
||||
@keyframes gradientAnimation {
|
||||
@@ -62,14 +63,10 @@
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 0 auto 15px;
|
||||
background-image: url('fotos/logo.png');
|
||||
background-size: 80%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background: url('fotos/logo.png') center/80% no-repeat rgba(255, 255, 255, 0.95);
|
||||
border-radius: 50%;
|
||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -92,19 +89,25 @@
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
/* Botão Salvar na Agenda */
|
||||
.save-contact {
|
||||
/* Botões principais */
|
||||
.save-contact,
|
||||
.pix-button {
|
||||
display: inline-block;
|
||||
padding: 12px 30px;
|
||||
background: linear-gradient(135deg, #20337b, #2d4a9e);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 50px;
|
||||
font-size: 0.95em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 25px;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.save-contact {
|
||||
background: linear-gradient(135deg, #20337b, #2d4a9e);
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.save-contact:hover {
|
||||
@@ -113,7 +116,6 @@
|
||||
background: linear-gradient(135deg, #2d4a9e, #20337b);
|
||||
}
|
||||
|
||||
/* Container de ícones */
|
||||
.icons-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -128,7 +130,7 @@
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
transition: all 0.3s ease;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.icon-item:hover {
|
||||
@@ -214,7 +216,6 @@
|
||||
transform: translateY(-1px) scale(0.98);
|
||||
}
|
||||
|
||||
/* Modal PIX */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
@@ -252,6 +253,7 @@
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
|
||||
transform: translateY(30px) scale(0.9);
|
||||
opacity: 0;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
.modal.active .modal-content {
|
||||
@@ -385,6 +387,7 @@
|
||||
transition: all 0.2s ease;
|
||||
border: 2px solid transparent;
|
||||
position: relative;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
.pix-code-area::before {
|
||||
@@ -453,7 +456,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Ícones pequenos */
|
||||
.small-icons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -488,7 +490,6 @@
|
||||
fill: white;
|
||||
}
|
||||
|
||||
/* Responsividade */
|
||||
@media (max-width: 600px) {
|
||||
.header h1 {
|
||||
font-size: 1.5em;
|
||||
@@ -631,129 +632,89 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function openPixModal() {
|
||||
const modal = document.getElementById('pixModal');
|
||||
modal.classList.add('active');
|
||||
setTimeout(() => {
|
||||
document.getElementById('pixValue').focus();
|
||||
}, 100);
|
||||
}
|
||||
// Cache de elementos DOM para melhor performance
|
||||
const pixModal = document.getElementById('pixModal');
|
||||
const pixValue = document.getElementById('pixValue');
|
||||
const pixCodeArea = document.getElementById('pixCodeArea');
|
||||
const copyNotification = document.getElementById('copyNotification');
|
||||
const modalContent = pixModal.querySelector('.modal-content');
|
||||
|
||||
function closePixModal() {
|
||||
const modal = document.getElementById('pixModal');
|
||||
const modalContent = modal.querySelector('.modal-content');
|
||||
const openPixModal = () => {
|
||||
pixModal.classList.add('active');
|
||||
setTimeout(() => pixValue.focus(), 100);
|
||||
};
|
||||
|
||||
// Animação de saída
|
||||
const closePixModal = () => {
|
||||
modalContent.style.animation = 'slideDownScale 0.3s ease forwards';
|
||||
modal.style.animation = 'fadeOut 0.3s ease forwards';
|
||||
pixModal.style.animation = 'fadeOut 0.3s ease forwards';
|
||||
|
||||
setTimeout(() => {
|
||||
modal.classList.remove('active');
|
||||
modal.style.animation = '';
|
||||
pixModal.classList.remove('active');
|
||||
pixModal.style.animation = '';
|
||||
modalContent.style.animation = '';
|
||||
document.getElementById('pixValue').value = '';
|
||||
document.getElementById('pixCodeArea').classList.remove('active');
|
||||
document.getElementById('copyNotification').classList.remove('active');
|
||||
pixValue.value = '';
|
||||
pixCodeArea.classList.remove('active');
|
||||
copyNotification.classList.remove('active');
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
|
||||
function generatePix() {
|
||||
const value = parseFloat(document.getElementById('pixValue').value);
|
||||
const generatePix = () => {
|
||||
const value = parseFloat(pixValue.value);
|
||||
|
||||
if (!value || value <= 0) {
|
||||
alert('Por favor, digite um valor válido');
|
||||
return;
|
||||
}
|
||||
|
||||
// Gera código PIX EMV (padrão brasileiro)
|
||||
const pixKey = 'financeiro@martinsevieira.adv.br';
|
||||
const merchantName = 'MARTINS E VIEIRA';
|
||||
const city = 'PALMAS';
|
||||
const txid = 'PAGAMENTO' + Date.now().toString().slice(-10);
|
||||
const pixCode = buildPixCode(
|
||||
'financeiro@martinsevieira.adv.br',
|
||||
'MARTINS E VIEIRA',
|
||||
'PALMAS',
|
||||
value.toFixed(2),
|
||||
'PAGAMENTO' + Date.now().toString().slice(-10)
|
||||
);
|
||||
|
||||
// Formata o valor com 2 casas decimais
|
||||
const formattedValue = value.toFixed(2);
|
||||
|
||||
// Constrói o código PIX Copia e Cola (EMV)
|
||||
const pixCode = buildPixCode(pixKey, merchantName, city, formattedValue, txid);
|
||||
|
||||
// Exibe o código
|
||||
const pixCodeArea = document.getElementById('pixCodeArea');
|
||||
pixCodeArea.textContent = pixCode;
|
||||
pixCodeArea.classList.add('active');
|
||||
|
||||
// Adiciona evento de clique para copiar
|
||||
pixCodeArea.onclick = function() {
|
||||
pixCodeArea.onclick = () => copyToClipboard(pixCode);
|
||||
copyToClipboard(pixCode);
|
||||
};
|
||||
|
||||
// Copia automaticamente na primeira vez
|
||||
copyToClipboard(pixCode);
|
||||
}
|
||||
|
||||
function buildPixCode(pixKey, merchantName, city, value, txid) {
|
||||
// Função auxiliar para criar campo EMV
|
||||
function emvField(id, value) {
|
||||
const length = value.length.toString().padStart(2, '0');
|
||||
return id + length + value;
|
||||
}
|
||||
|
||||
// Monta a chave PIX
|
||||
const buildPixCode = (pixKey, merchantName, city, value, txid) => {
|
||||
const emvField = (id, value) => id + value.length.toString().padStart(2, '0') + value;
|
||||
const merchantAccountInfo = emvField('00', 'BR.GOV.BCB.PIX') + emvField('01', pixKey);
|
||||
|
||||
let emv = '';
|
||||
emv += emvField('00', '01'); // Payload Format Indicator
|
||||
emv += emvField('26', merchantAccountInfo); // Merchant Account Information
|
||||
emv += emvField('52', '0000'); // Merchant Category Code
|
||||
emv += emvField('53', '986'); // Transaction Currency (986 = BRL)
|
||||
emv += emvField('54', value); // Transaction Amount
|
||||
emv += emvField('58', 'BR'); // Country Code
|
||||
emv += emvField('59', merchantName); // Merchant Name
|
||||
emv += emvField('60', city); // Merchant City
|
||||
emv += emvField('62', emvField('05', txid)); // Additional Data Field
|
||||
let emv = emvField('00', '01') + emvField('26', merchantAccountInfo) +
|
||||
emvField('52', '0000') + emvField('53', '986') + emvField('54', value) +
|
||||
emvField('58', 'BR') + emvField('59', merchantName) + emvField('60', city) +
|
||||
emvField('62', emvField('05', txid)) + '6304';
|
||||
|
||||
// Calcula CRC16
|
||||
emv += '6304';
|
||||
const crc = crc16(emv);
|
||||
emv += crc;
|
||||
return emv + crc16(emv);
|
||||
};
|
||||
|
||||
return emv;
|
||||
}
|
||||
|
||||
function crc16(str) {
|
||||
const crc16 = str => {
|
||||
let crc = 0xFFFF;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
crc ^= str.charCodeAt(i) << 8;
|
||||
for (let j = 0; j < 8; j++) {
|
||||
if (crc & 0x8000) {
|
||||
crc = (crc << 1) ^ 0x1021;
|
||||
} else {
|
||||
crc = crc << 1;
|
||||
}
|
||||
crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
|
||||
}
|
||||
}
|
||||
return (crc & 0xFFFF).toString(16).toUpperCase().padStart(4, '0');
|
||||
}
|
||||
};
|
||||
|
||||
function copyToClipboard(text) {
|
||||
// Usa a API moderna de clipboard
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
showCopyNotification();
|
||||
}).catch(err => {
|
||||
// Fallback para método antigo
|
||||
fallbackCopy(text);
|
||||
});
|
||||
const copyToClipboard = text => {
|
||||
if (navigator.clipboard?.writeText) {
|
||||
navigator.clipboard.writeText(text).then(showCopyNotification, () => fallbackCopy(text));
|
||||
} else {
|
||||
fallbackCopy(text);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function fallbackCopy(text) {
|
||||
const fallbackCopy = text => {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.style.position = 'fixed';
|
||||
textarea.style.opacity = '0';
|
||||
textarea.style.cssText = 'position:fixed;opacity:0';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
try {
|
||||
@@ -763,31 +724,22 @@
|
||||
alert('Erro ao copiar. Por favor, copie manualmente.');
|
||||
}
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
};
|
||||
|
||||
function showCopyNotification() {
|
||||
const notification = document.getElementById('copyNotification');
|
||||
notification.classList.remove('active'); // Remove primeiro para reiniciar animação
|
||||
setTimeout(() => {
|
||||
notification.classList.add('active');
|
||||
}, 10);
|
||||
setTimeout(() => {
|
||||
notification.classList.remove('active');
|
||||
}, 3000);
|
||||
}
|
||||
const showCopyNotification = () => {
|
||||
copyNotification.classList.remove('active');
|
||||
setTimeout(() => copyNotification.classList.add('active'), 10);
|
||||
setTimeout(() => copyNotification.classList.remove('active'), 3000);
|
||||
};
|
||||
|
||||
// Fecha modal ao clicar fora
|
||||
document.getElementById('pixModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) {
|
||||
closePixModal();
|
||||
}
|
||||
pixModal.addEventListener('click', e => {
|
||||
if (e.target === pixModal) closePixModal();
|
||||
});
|
||||
|
||||
// Permite gerar PIX ao pressionar Enter
|
||||
document.getElementById('pixValue').addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
generatePix();
|
||||
}
|
||||
pixValue.addEventListener('keypress', e => {
|
||||
if (e.key === 'Enter') generatePix();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in new issue
Block a user