Implementa o editor interativo de Canvas para montagem livre de cartazes
This commit is contained in:
+521
-6
@@ -7185,10 +7185,35 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const tamanho = document.getElementById('cartazTamanhoSelect') ? document.getElementById('cartazTamanhoSelect').value : 'A4';
|
const tamanho = document.getElementById('cartazTamanhoSelect') ? document.getElementById('cartazTamanhoSelect').value : 'A4';
|
||||||
const orientacao = document.getElementById('cartazOrientacaoSelect') ? document.getElementById('cartazOrientacaoSelect').value : 'retrato';
|
const orientacao = document.getElementById('cartazOrientacaoSelect') ? document.getElementById('cartazOrientacaoSelect').value : 'retrato';
|
||||||
|
|
||||||
const imgContainerHtml = cartazPreviewImageContainer.style.display === 'block'
|
const imgContainerHtml = cartazPreviewImageContainer.style.display === 'block' && !canvasModeActive
|
||||||
? `<div style="width: 100%; margin-bottom: 20px; border-radius: 8px; overflow: hidden; border: 2px solid rgba(0,0,0,0.1); text-align: center; background: rgba(0,0,0,0.02);"><img src="${cartazPreviewImage.src}" style="max-width: 100%; max-height: 350px; object-fit: contain; display: inline-block;"></div>`
|
? `<div style="width: 100%; margin-bottom: 20px; border-radius: 8px; overflow: hidden; border: 2px solid rgba(0,0,0,0.1); text-align: center; background: rgba(0,0,0,0.02);"><img src="${cartazPreviewImage.src}" style="max-width: 100%; max-height: 350px; object-fit: contain; display: inline-block;"></div>`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
let printContent = '';
|
||||||
|
if (canvasModeActive) {
|
||||||
|
// Clone printable area and cleanup handles / active state borders for print output
|
||||||
|
const tempContainer = document.createElement('div');
|
||||||
|
tempContainer.innerHTML = cartazPrintableArea.innerHTML;
|
||||||
|
tempContainer.querySelectorAll('.canvas-resize-handle').forEach(h => h.remove());
|
||||||
|
tempContainer.querySelectorAll('.canvas-item').forEach(item => {
|
||||||
|
item.classList.remove('active-item');
|
||||||
|
item.removeAttribute('contenteditable');
|
||||||
|
// We can remove border style only if it was a dashed editing border
|
||||||
|
if (item.style.border.includes('dashed')) {
|
||||||
|
item.style.border = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
printContent = tempContainer.innerHTML;
|
||||||
|
} else {
|
||||||
|
printContent = `
|
||||||
|
<h1>${title}</h1>
|
||||||
|
${imgContainerHtml}
|
||||||
|
<div class="content-area">
|
||||||
|
${cartazPreviewContent.innerHTML}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
const printWindow = window.open('', '_blank');
|
const printWindow = window.open('', '_blank');
|
||||||
printWindow.document.write(`
|
printWindow.document.write(`
|
||||||
<html>
|
<html>
|
||||||
@@ -7225,6 +7250,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
border: ${border === 'none' ? 'none' : `${border} ${text}`};
|
border: ${border === 'none' ? 'none' : `${border} ${text}`};
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
container-type: inline-size;
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -7260,6 +7288,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
li {
|
li {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Estilos específicos do Canvas no PDF/Print */
|
||||||
|
.canvas-item {
|
||||||
|
position: absolute !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px;
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
body { background: transparent; padding: 0; display: block; }
|
body { background: transparent; padding: 0; display: block; }
|
||||||
.cartaz-frame {
|
.cartaz-frame {
|
||||||
@@ -7277,11 +7317,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="cartaz-frame">
|
<div class="cartaz-frame">
|
||||||
<h1>${title}</h1>
|
${printContent}
|
||||||
${imgContainerHtml}
|
|
||||||
<div class="content-area">
|
|
||||||
${cartazPreviewContent.innerHTML}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
@@ -7409,4 +7445,483 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
cartazesHistoryContainer.innerHTML = '<div style="color: #ef4444; padding: 20px;">Erro ao carregar histórico de cartazes.</div>';
|
cartazesHistoryContainer.innerHTML = '<div style="color: #ef4444; padding: 20px;">Erro ao carregar histórico de cartazes.</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- MODO DESIGN CANVAS (EDITOR INTERATIVO DE CARTAZES) ---
|
||||||
|
const btnCanvasModeToggle = document.getElementById('btnCanvasModeToggle');
|
||||||
|
const canvasControlPanel = document.getElementById('canvasControlPanel');
|
||||||
|
const btnCanvasAddText = document.getElementById('btnCanvasAddText');
|
||||||
|
const btnCanvasAddCard = document.getElementById('btnCanvasAddCard');
|
||||||
|
const canvasFontFamily = document.getElementById('canvasFontFamily');
|
||||||
|
const canvasFontSize = document.getElementById('canvasFontSize');
|
||||||
|
const canvasTextColor = document.getElementById('canvasTextColor');
|
||||||
|
const canvasBgColorInput = document.getElementById('canvasBgColor');
|
||||||
|
const btnCanvasZIndexUp = document.getElementById('btnCanvasZIndexUp');
|
||||||
|
const btnCanvasZIndexDown = document.getElementById('btnCanvasZIndexDown');
|
||||||
|
const btnCanvasDelete = document.getElementById('btnCanvasDelete');
|
||||||
|
|
||||||
|
let canvasModeActive = false;
|
||||||
|
let selectedCanvasItem = null;
|
||||||
|
let isDraggingCanvas = false;
|
||||||
|
let isResizingCanvas = false;
|
||||||
|
let dragStartX, dragStartY;
|
||||||
|
let dragStartLeft, dragStartTop;
|
||||||
|
let dragStartWidth, dragStartHeight;
|
||||||
|
|
||||||
|
function enterCanvasMode() {
|
||||||
|
canvasModeActive = true;
|
||||||
|
if (btnCanvasModeToggle) {
|
||||||
|
btnCanvasModeToggle.textContent = '💾 Salvar Canvas';
|
||||||
|
btnCanvasModeToggle.style.background = '#10a37f';
|
||||||
|
btnCanvasModeToggle.style.color = 'white';
|
||||||
|
}
|
||||||
|
if (canvasControlPanel) canvasControlPanel.style.display = 'flex';
|
||||||
|
|
||||||
|
cartazPrintableArea.style.position = 'relative';
|
||||||
|
const rectParent = cartazPrintableArea.getBoundingClientRect();
|
||||||
|
|
||||||
|
const items = [];
|
||||||
|
if (cartazPreviewTitle) items.push(cartazPreviewTitle);
|
||||||
|
if (cartazPreviewImageContainer && cartazPreviewImageContainer.style.display !== 'none') {
|
||||||
|
items.push(cartazPreviewImageContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cards = Array.from(cartazPreviewContent.children);
|
||||||
|
cards.forEach(card => {
|
||||||
|
items.push(card);
|
||||||
|
});
|
||||||
|
|
||||||
|
const clientRects = items.map(item => item.getBoundingClientRect());
|
||||||
|
|
||||||
|
items.forEach((item, index) => {
|
||||||
|
const rect = clientRects[index];
|
||||||
|
|
||||||
|
const leftPercent = ((rect.left - rectParent.left) / rectParent.width) * 100;
|
||||||
|
const topPercent = ((rect.top - rectParent.top) / rectParent.height) * 100;
|
||||||
|
const widthPercent = (rect.width / rectParent.width) * 100;
|
||||||
|
const heightPercent = (rect.height / rectParent.height) * 100;
|
||||||
|
|
||||||
|
item.classList.add('canvas-item');
|
||||||
|
item.style.position = 'absolute';
|
||||||
|
item.style.left = `${leftPercent}%`;
|
||||||
|
item.style.top = `${topPercent}%`;
|
||||||
|
item.style.width = `${widthPercent}%`;
|
||||||
|
item.style.height = `${heightPercent}%`;
|
||||||
|
item.style.margin = '0';
|
||||||
|
|
||||||
|
item.setAttribute('contenteditable', 'true');
|
||||||
|
|
||||||
|
if (!item.querySelector('.canvas-resize-handle')) {
|
||||||
|
const handle = document.createElement('div');
|
||||||
|
handle.className = 'canvas-resize-handle';
|
||||||
|
item.appendChild(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.parentNode === cartazPreviewContent) {
|
||||||
|
cartazPrintableArea.appendChild(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupCanvasItemEvents(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
cartazPreviewContent.style.display = 'none';
|
||||||
|
showToast('Modo Design Canvas ativado! Arraste, redimensione e clique duas vezes para editar o texto.', 'info');
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitCanvasMode() {
|
||||||
|
canvasModeActive = false;
|
||||||
|
if (btnCanvasModeToggle) {
|
||||||
|
btnCanvasModeToggle.textContent = '🎨 Design Canvas';
|
||||||
|
btnCanvasModeToggle.style.background = 'transparent';
|
||||||
|
btnCanvasModeToggle.style.color = 'var(--text-secondary)';
|
||||||
|
}
|
||||||
|
if (canvasControlPanel) canvasControlPanel.style.display = 'none';
|
||||||
|
|
||||||
|
if (selectedCanvasItem) {
|
||||||
|
selectedCanvasItem.classList.remove('active-item');
|
||||||
|
selectedCanvasItem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = cartazPrintableArea.querySelectorAll('.canvas-item');
|
||||||
|
items.forEach(item => {
|
||||||
|
item.removeAttribute('contenteditable');
|
||||||
|
});
|
||||||
|
|
||||||
|
showToast('Layout do Canvas salvo com sucesso!', 'success');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupCanvasItemEvents(item) {
|
||||||
|
item.addEventListener('click', (e) => {
|
||||||
|
if (!canvasModeActive) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
if (selectedCanvasItem) {
|
||||||
|
selectedCanvasItem.classList.remove('active-item');
|
||||||
|
}
|
||||||
|
selectedCanvasItem = item;
|
||||||
|
item.classList.add('active-item');
|
||||||
|
|
||||||
|
updateToolbarForSelected();
|
||||||
|
});
|
||||||
|
|
||||||
|
item.addEventListener('mousedown', (e) => {
|
||||||
|
if (!canvasModeActive) return;
|
||||||
|
if (e.target.classList.contains('canvas-resize-handle')) return;
|
||||||
|
|
||||||
|
if (document.activeElement === item && e.target !== item && !e.target.classList.contains('canvas-item')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
selectedCanvasItem = item;
|
||||||
|
document.querySelectorAll('.canvas-item').forEach(el => el.classList.remove('active-item'));
|
||||||
|
item.classList.add('active-item');
|
||||||
|
updateToolbarForSelected();
|
||||||
|
|
||||||
|
isDraggingCanvas = true;
|
||||||
|
dragStartX = e.clientX;
|
||||||
|
dragStartY = e.clientY;
|
||||||
|
|
||||||
|
const parentRect = cartazPrintableArea.getBoundingClientRect();
|
||||||
|
const itemRect = item.getBoundingClientRect();
|
||||||
|
|
||||||
|
dragStartLeft = ((itemRect.left - parentRect.left) / parentRect.width) * 100;
|
||||||
|
dragStartTop = ((itemRect.top - parentRect.top) / parentRect.height) * 100;
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', handleCanvasDrag);
|
||||||
|
document.addEventListener('mouseup', stopCanvasDrag);
|
||||||
|
});
|
||||||
|
|
||||||
|
item.addEventListener('touchstart', (e) => {
|
||||||
|
if (!canvasModeActive) return;
|
||||||
|
if (e.target.classList.contains('canvas-resize-handle')) return;
|
||||||
|
|
||||||
|
if (document.activeElement === item && e.target !== item) return;
|
||||||
|
|
||||||
|
selectedCanvasItem = item;
|
||||||
|
document.querySelectorAll('.canvas-item').forEach(el => el.classList.remove('active-item'));
|
||||||
|
item.classList.add('active-item');
|
||||||
|
updateToolbarForSelected();
|
||||||
|
|
||||||
|
isDraggingCanvas = true;
|
||||||
|
const touch = e.touches[0];
|
||||||
|
dragStartX = touch.clientX;
|
||||||
|
dragStartY = touch.clientY;
|
||||||
|
|
||||||
|
const parentRect = cartazPrintableArea.getBoundingClientRect();
|
||||||
|
const itemRect = item.getBoundingClientRect();
|
||||||
|
|
||||||
|
dragStartLeft = ((itemRect.left - parentRect.left) / parentRect.width) * 100;
|
||||||
|
dragStartTop = ((itemRect.top - parentRect.top) / parentRect.height) * 100;
|
||||||
|
|
||||||
|
document.addEventListener('touchmove', handleCanvasTouchDrag, { passive: false });
|
||||||
|
document.addEventListener('touchend', stopCanvasDrag);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handle = item.querySelector('.canvas-resize-handle');
|
||||||
|
if (handle) {
|
||||||
|
handle.addEventListener('mousedown', (e) => {
|
||||||
|
if (!canvasModeActive) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
isResizingCanvas = true;
|
||||||
|
dragStartX = e.clientX;
|
||||||
|
dragStartY = e.clientY;
|
||||||
|
|
||||||
|
const parentRect = cartazPrintableArea.getBoundingClientRect();
|
||||||
|
const itemRect = item.getBoundingClientRect();
|
||||||
|
|
||||||
|
dragStartWidth = (itemRect.width / parentRect.width) * 100;
|
||||||
|
dragStartHeight = (itemRect.height / parentRect.height) * 100;
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', handleCanvasResize);
|
||||||
|
document.addEventListener('mouseup', stopCanvasResize);
|
||||||
|
});
|
||||||
|
|
||||||
|
handle.addEventListener('touchstart', (e) => {
|
||||||
|
if (!canvasModeActive) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
isResizingCanvas = true;
|
||||||
|
const touch = e.touches[0];
|
||||||
|
dragStartX = touch.clientX;
|
||||||
|
dragStartY = touch.clientY;
|
||||||
|
|
||||||
|
const parentRect = cartazPrintableArea.getBoundingClientRect();
|
||||||
|
const itemRect = item.getBoundingClientRect();
|
||||||
|
|
||||||
|
dragStartWidth = (itemRect.width / parentRect.width) * 100;
|
||||||
|
dragStartHeight = (itemRect.height / parentRect.height) * 100;
|
||||||
|
|
||||||
|
document.addEventListener('touchmove', handleCanvasTouchResize, { passive: false });
|
||||||
|
document.addEventListener('touchend', stopCanvasResize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCanvasDrag(e) {
|
||||||
|
if (!isDraggingCanvas || !selectedCanvasItem) return;
|
||||||
|
const dx = e.clientX - dragStartX;
|
||||||
|
const dy = e.clientY - dragStartY;
|
||||||
|
const parentRect = cartazPrintableArea.getBoundingClientRect();
|
||||||
|
const dxPercent = (dx / parentRect.width) * 100;
|
||||||
|
const dyPercent = (dy / parentRect.height) * 100;
|
||||||
|
|
||||||
|
let newLeft = dragStartLeft + dxPercent;
|
||||||
|
let newTop = dragStartTop + dyPercent;
|
||||||
|
|
||||||
|
const itemRect = selectedCanvasItem.getBoundingClientRect();
|
||||||
|
const itemWPercent = (itemRect.width / parentRect.width) * 100;
|
||||||
|
const itemHPercent = (itemRect.height / parentRect.height) * 100;
|
||||||
|
|
||||||
|
if (newLeft < 0) newLeft = 0;
|
||||||
|
if (newTop < 0) newTop = 0;
|
||||||
|
if (newLeft + itemWPercent > 100) newLeft = 100 - itemWPercent;
|
||||||
|
if (newTop + itemHPercent > 100) newTop = 100 - itemHPercent;
|
||||||
|
|
||||||
|
selectedCanvasItem.style.left = `${newLeft}%`;
|
||||||
|
selectedCanvasItem.style.top = `${newTop}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCanvasTouchDrag(e) {
|
||||||
|
if (!isDraggingCanvas || !selectedCanvasItem) return;
|
||||||
|
e.preventDefault();
|
||||||
|
const touch = e.touches[0];
|
||||||
|
const dx = touch.clientX - dragStartX;
|
||||||
|
const dy = touch.clientY - dragStartY;
|
||||||
|
const parentRect = cartazPrintableArea.getBoundingClientRect();
|
||||||
|
const dxPercent = (dx / parentRect.width) * 100;
|
||||||
|
const dyPercent = (dy / parentRect.height) * 100;
|
||||||
|
|
||||||
|
let newLeft = dragStartLeft + dxPercent;
|
||||||
|
let newTop = dragStartTop + dyPercent;
|
||||||
|
|
||||||
|
const itemRect = selectedCanvasItem.getBoundingClientRect();
|
||||||
|
const itemWPercent = (itemRect.width / parentRect.width) * 100;
|
||||||
|
const itemHPercent = (itemRect.height / parentRect.height) * 100;
|
||||||
|
|
||||||
|
if (newLeft < 0) newLeft = 0;
|
||||||
|
if (newTop < 0) newTop = 0;
|
||||||
|
if (newLeft + itemWPercent > 100) newLeft = 100 - itemWPercent;
|
||||||
|
if (newTop + itemHPercent > 100) newTop = 100 - itemHPercent;
|
||||||
|
|
||||||
|
selectedCanvasItem.style.left = `${newLeft}%`;
|
||||||
|
selectedCanvasItem.style.top = `${newTop}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopCanvasDrag() {
|
||||||
|
isDraggingCanvas = false;
|
||||||
|
document.removeEventListener('mousemove', handleCanvasDrag);
|
||||||
|
document.removeEventListener('mouseup', stopCanvasDrag);
|
||||||
|
document.removeEventListener('touchmove', handleCanvasTouchDrag);
|
||||||
|
document.removeEventListener('touchend', stopCanvasDrag);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCanvasResize(e) {
|
||||||
|
if (!isResizingCanvas || !selectedCanvasItem) return;
|
||||||
|
const dx = e.clientX - dragStartX;
|
||||||
|
const dy = e.clientY - dragStartY;
|
||||||
|
const parentRect = cartazPrintableArea.getBoundingClientRect();
|
||||||
|
const dxPercent = (dx / parentRect.width) * 100;
|
||||||
|
const dyPercent = (dy / parentRect.height) * 100;
|
||||||
|
|
||||||
|
let newWidth = dragStartWidth + dxPercent;
|
||||||
|
let newHeight = dragStartHeight + dyPercent;
|
||||||
|
|
||||||
|
if (newWidth < 10) newWidth = 10;
|
||||||
|
if (newHeight < 5) newHeight = 5;
|
||||||
|
|
||||||
|
const itemLeft = parseFloat(selectedCanvasItem.style.left) || 0;
|
||||||
|
const itemTop = parseFloat(selectedCanvasItem.style.top) || 0;
|
||||||
|
|
||||||
|
if (itemLeft + newWidth > 100) newWidth = 100 - itemLeft;
|
||||||
|
if (itemTop + newHeight > 100) newHeight = 100 - itemTop;
|
||||||
|
|
||||||
|
selectedCanvasItem.style.width = `${newWidth}%`;
|
||||||
|
selectedCanvasItem.style.height = `${newHeight}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCanvasTouchResize(e) {
|
||||||
|
if (!isResizingCanvas || !selectedCanvasItem) return;
|
||||||
|
e.preventDefault();
|
||||||
|
const touch = e.touches[0];
|
||||||
|
const dx = touch.clientX - dragStartX;
|
||||||
|
const dy = touch.clientY - dragStartY;
|
||||||
|
const parentRect = cartazPrintableArea.getBoundingClientRect();
|
||||||
|
const dxPercent = (dx / parentRect.width) * 100;
|
||||||
|
const dyPercent = (dy / parentRect.height) * 100;
|
||||||
|
|
||||||
|
let newWidth = dragStartWidth + dxPercent;
|
||||||
|
let newHeight = dragStartHeight + dyPercent;
|
||||||
|
|
||||||
|
if (newWidth < 10) newWidth = 10;
|
||||||
|
if (newHeight < 5) newHeight = 5;
|
||||||
|
|
||||||
|
const itemLeft = parseFloat(selectedCanvasItem.style.left) || 0;
|
||||||
|
const itemTop = parseFloat(selectedCanvasItem.style.top) || 0;
|
||||||
|
|
||||||
|
if (itemLeft + newWidth > 100) newWidth = 100 - itemLeft;
|
||||||
|
if (itemTop + newHeight > 100) newHeight = 100 - itemTop;
|
||||||
|
|
||||||
|
selectedCanvasItem.style.width = `${newWidth}%`;
|
||||||
|
selectedCanvasItem.style.height = `${newHeight}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopCanvasResize() {
|
||||||
|
isResizingCanvas = false;
|
||||||
|
document.removeEventListener('mousemove', handleCanvasResize);
|
||||||
|
document.removeEventListener('mouseup', stopCanvasResize);
|
||||||
|
document.removeEventListener('touchmove', handleCanvasTouchResize);
|
||||||
|
document.removeEventListener('touchend', stopCanvasResize);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rgbToHex(rgb) {
|
||||||
|
if (!rgb || rgb === 'transparent') return '#ffffff';
|
||||||
|
if (rgb.startsWith('#')) return rgb;
|
||||||
|
const match = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);
|
||||||
|
if (!match) return '#ffffff';
|
||||||
|
const r = parseInt(match[1]);
|
||||||
|
const g = parseInt(match[2]);
|
||||||
|
const b = parseInt(match[3]);
|
||||||
|
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateToolbarForSelected() {
|
||||||
|
if (!selectedCanvasItem) return;
|
||||||
|
|
||||||
|
const ff = window.getComputedStyle(selectedCanvasItem).fontFamily.replace(/['"]/g, '').split(',')[0].trim();
|
||||||
|
if (canvasFontFamily) canvasFontFamily.value = ff;
|
||||||
|
|
||||||
|
const fs = parseFloat(window.getComputedStyle(selectedCanvasItem).fontSize);
|
||||||
|
if (canvasFontSize) canvasFontSize.value = Math.round(fs);
|
||||||
|
|
||||||
|
const col = rgbToHex(window.getComputedStyle(selectedCanvasItem).color);
|
||||||
|
if (canvasTextColor) canvasTextColor.value = col;
|
||||||
|
|
||||||
|
const bg = rgbToHex(window.getComputedStyle(selectedCanvasItem).backgroundColor);
|
||||||
|
if (canvasBgColorInput) canvasBgColorInput.value = bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canvasFontFamily) {
|
||||||
|
canvasFontFamily.addEventListener('change', () => {
|
||||||
|
if (selectedCanvasItem) selectedCanvasItem.style.fontFamily = canvasFontFamily.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (canvasFontSize) {
|
||||||
|
canvasFontSize.addEventListener('input', () => {
|
||||||
|
if (selectedCanvasItem) selectedCanvasItem.style.fontSize = `${canvasFontSize.value}px`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (canvasTextColor) {
|
||||||
|
canvasTextColor.addEventListener('input', () => {
|
||||||
|
if (selectedCanvasItem) selectedCanvasItem.style.color = canvasTextColor.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (canvasBgColorInput) {
|
||||||
|
canvasBgColorInput.addEventListener('input', () => {
|
||||||
|
if (selectedCanvasItem) selectedCanvasItem.style.backgroundColor = canvasBgColorInput.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (btnCanvasZIndexUp) {
|
||||||
|
btnCanvasZIndexUp.addEventListener('click', () => {
|
||||||
|
if (selectedCanvasItem) {
|
||||||
|
const currentZ = parseInt(selectedCanvasItem.style.zIndex) || 1;
|
||||||
|
selectedCanvasItem.style.zIndex = currentZ + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (btnCanvasZIndexDown) {
|
||||||
|
btnCanvasZIndexDown.addEventListener('click', () => {
|
||||||
|
if (selectedCanvasItem) {
|
||||||
|
const currentZ = parseInt(selectedCanvasItem.style.zIndex) || 1;
|
||||||
|
selectedCanvasItem.style.zIndex = Math.max(1, currentZ - 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (btnCanvasDelete) {
|
||||||
|
btnCanvasDelete.addEventListener('click', () => {
|
||||||
|
if (selectedCanvasItem) {
|
||||||
|
selectedCanvasItem.remove();
|
||||||
|
selectedCanvasItem = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btnCanvasAddText) {
|
||||||
|
btnCanvasAddText.addEventListener('click', () => {
|
||||||
|
if (!canvasModeActive) return;
|
||||||
|
const textItem = document.createElement('div');
|
||||||
|
textItem.className = 'canvas-item';
|
||||||
|
textItem.innerHTML = 'Novo Texto (Clique duplo para editar)';
|
||||||
|
textItem.style.left = '10%';
|
||||||
|
textItem.style.top = '15%';
|
||||||
|
textItem.style.width = '50%';
|
||||||
|
textItem.style.height = '8%';
|
||||||
|
textItem.style.fontSize = '20px';
|
||||||
|
textItem.style.color = cartazTextColor.value || '#2d3748';
|
||||||
|
textItem.style.fontFamily = cartazFontSelect.value || 'Fredoka';
|
||||||
|
textItem.setAttribute('contenteditable', 'true');
|
||||||
|
|
||||||
|
const handle = document.createElement('div');
|
||||||
|
handle.className = 'canvas-resize-handle';
|
||||||
|
textItem.appendChild(handle);
|
||||||
|
|
||||||
|
cartazPrintableArea.appendChild(textItem);
|
||||||
|
setupCanvasItemEvents(textItem);
|
||||||
|
textItem.click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btnCanvasAddCard) {
|
||||||
|
btnCanvasAddCard.addEventListener('click', () => {
|
||||||
|
if (!canvasModeActive) return;
|
||||||
|
const cardItem = document.createElement('div');
|
||||||
|
cardItem.className = 'canvas-item';
|
||||||
|
cardItem.style.background = 'rgba(255, 255, 255, 0.4)';
|
||||||
|
cardItem.style.border = '2px dashed ' + (cartazTextColor.value || '#2d3748');
|
||||||
|
cardItem.style.borderRadius = '12px';
|
||||||
|
cardItem.style.left = '20%';
|
||||||
|
cardItem.style.top = '25%';
|
||||||
|
cardItem.style.width = '45%';
|
||||||
|
cardItem.style.height = '20%';
|
||||||
|
cardItem.style.padding = '15px';
|
||||||
|
cardItem.innerHTML = '<h3>Novo Card</h3><p>Edite este texto...</p>';
|
||||||
|
cardItem.style.fontFamily = cartazFontSelect.value || 'Fredoka';
|
||||||
|
cardItem.setAttribute('contenteditable', 'true');
|
||||||
|
|
||||||
|
const handle = document.createElement('div');
|
||||||
|
handle.className = 'canvas-resize-handle';
|
||||||
|
cardItem.appendChild(handle);
|
||||||
|
|
||||||
|
cartazPrintableArea.appendChild(cardItem);
|
||||||
|
setupCanvasItemEvents(cardItem);
|
||||||
|
cardItem.click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btnCanvasModeToggle) {
|
||||||
|
btnCanvasModeToggle.addEventListener('click', () => {
|
||||||
|
if (canvasModeActive) {
|
||||||
|
exitCanvasMode();
|
||||||
|
} else {
|
||||||
|
if (cartazEditArea && cartazEditArea.style.display !== 'none') {
|
||||||
|
btnEditCartazToggle.click();
|
||||||
|
}
|
||||||
|
enterCanvasMode();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cartazPrintableArea) {
|
||||||
|
cartazPrintableArea.addEventListener('click', (e) => {
|
||||||
|
if (!canvasModeActive) return;
|
||||||
|
if (e.target === cartazPrintableArea) {
|
||||||
|
if (selectedCanvasItem) {
|
||||||
|
selectedCanvasItem.classList.remove('active-item');
|
||||||
|
selectedCanvasItem = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+38
-1
@@ -1850,11 +1850,48 @@
|
|||||||
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border-light); padding-bottom: 8px;">
|
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border-light); padding-bottom: 8px;">
|
||||||
<h4 style="margin: 0; color: var(--text-primary);">👁️ Visualização do Cartaz</h4>
|
<h4 style="margin: 0; color: var(--text-primary);">👁️ Visualização do Cartaz</h4>
|
||||||
<div style="display: flex; gap: 8px;">
|
<div style="display: flex; gap: 8px;">
|
||||||
<button id="btnEditCartazToggle" class="btn-save-settings" style="background: transparent; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 5px 10px; font-size: 0.75rem;">✏️ Editar Conteúdo</button>
|
<button id="btnCanvasModeToggle" class="btn-save-settings" style="background: transparent; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 5px 10px; font-size: 0.75rem;">🎨 Design Canvas</button>
|
||||||
|
<button id="btnEditCartazToggle" class="btn-save-settings" style="background: transparent; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 5px 10px; font-size: 0.75rem;">✏️ Editar HTML</button>
|
||||||
<button id="btnPrintCartaz" class="btn-save-settings" style="background: #3b82f6; border: none; color: white; padding: 5px 12px; font-size: 0.75rem; font-weight: bold; border-radius: 6px;">🖨️ Imprimir Cartaz</button>
|
<button id="btnPrintCartaz" class="btn-save-settings" style="background: #3b82f6; border: none; color: white; padding: 5px 12px; font-size: 0.75rem; font-weight: bold; border-radius: 6px;">🖨️ Imprimir Cartaz</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Painel de Controle do Canvas (Apenas visível no Modo Canvas) -->
|
||||||
|
<div id="canvasControlPanel" style="display: none; background: var(--bg-secondary); border: 1px solid var(--border-light); padding: 10px; border-radius: 8px; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 8px;">
|
||||||
|
<button id="btnCanvasAddText" class="btn-save-settings" style="background: #10a37f; color: white; border: none; padding: 4px 10px; font-size: 0.75rem; font-weight: 600; border-radius: 6px; cursor: pointer;">➕ Texto</button>
|
||||||
|
<button id="btnCanvasAddCard" class="btn-save-settings" style="background: #a855f7; color: white; border: none; padding: 4px 10px; font-size: 0.75rem; font-weight: 600; border-radius: 6px; cursor: pointer;">➕ Card</button>
|
||||||
|
|
||||||
|
<div style="height: 20px; width: 1px; background: var(--border-light);"></div>
|
||||||
|
|
||||||
|
<!-- Controles do Item Selecionado -->
|
||||||
|
<span style="font-size: 0.75rem; color: var(--text-secondary);">Item:</span>
|
||||||
|
<select id="canvasFontFamily" class="obs-select" style="padding: 2px 5px; font-size: 0.75rem; min-width: 90px; margin: 0;">
|
||||||
|
<option value="Fredoka">Fredoka</option>
|
||||||
|
<option value="Outfit">Outfit</option>
|
||||||
|
<option value="Caveat">Caveat</option>
|
||||||
|
<option value="Playfair Display">Playfair</option>
|
||||||
|
<option value="Arial">Arial</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<input type="number" id="canvasFontSize" class="obs-input" style="width: 55px; padding: 2px 5px; font-size: 0.75rem; margin: 0;" min="8" max="72" value="16" title="Tamanho da fonte (px)">
|
||||||
|
|
||||||
|
<div style="display: flex; align-items: center; gap: 4px;">
|
||||||
|
<label style="font-size: 0.72rem; color: var(--text-secondary);">Cor:</label>
|
||||||
|
<input type="color" id="canvasTextColor" style="width: 24px; height: 24px; border: 1px solid var(--border-light); border-radius: 4px; padding: 0; cursor: pointer; background: transparent; margin: 0;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="display: flex; align-items: center; gap: 4px;">
|
||||||
|
<label style="font-size: 0.72rem; color: var(--text-secondary);">Fundo:</label>
|
||||||
|
<input type="color" id="canvasBgColor" style="width: 24px; height: 24px; border: 1px solid var(--border-light); border-radius: 4px; padding: 0; cursor: pointer; background: transparent; margin: 0;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="display: flex; gap: 4px; align-items: center;">
|
||||||
|
<button id="btnCanvasZIndexUp" class="btn-save-settings" style="background: transparent; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 2px 6px; font-size: 0.7rem; cursor: pointer;" title="Trazer para Frente">🔺</button>
|
||||||
|
<button id="btnCanvasZIndexDown" class="btn-save-settings" style="background: transparent; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 2px 6px; font-size: 0.7rem; cursor: pointer;" title="Enviar para Trás">🔻</button>
|
||||||
|
<button id="btnCanvasDelete" class="btn-save-settings" style="background: #ef4444; color: white; border: none; padding: 2px 8px; font-size: 0.7rem; font-weight: bold; border-radius: 4px; cursor: pointer;" title="Excluir Elemento">🗑️ Excluir</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Área de Edição do Conteúdo (Inicialmente Oculta) -->
|
<!-- Área de Edição do Conteúdo (Inicialmente Oculta) -->
|
||||||
<div id="cartazEditArea" style="display: none; flex-direction: column; gap: 8px;">
|
<div id="cartazEditArea" style="display: none; flex-direction: column; gap: 8px;">
|
||||||
<label style="color: var(--text-secondary); font-size: 0.78rem; font-weight: 600; text-transform: uppercase;">Editor HTML do Cartaz</label>
|
<label style="color: var(--text-secondary); font-size: 0.78rem; font-weight: 600; text-transform: uppercase;">Editor HTML do Cartaz</label>
|
||||||
|
|||||||
@@ -3685,6 +3685,60 @@ code {
|
|||||||
max-height: 100% !important;
|
max-height: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Estilos de Itens do Canvas (Arrastáveis e Redimensionáveis) */
|
||||||
|
.canvas-item {
|
||||||
|
position: absolute !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: move;
|
||||||
|
border: 1px dashed rgba(59, 130, 246, 0.4);
|
||||||
|
padding: 10px;
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 8px;
|
||||||
|
user-select: text; /* Permite selecionar texto interno para edição */
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-item:hover {
|
||||||
|
border-color: rgba(59, 130, 246, 0.8);
|
||||||
|
box-shadow: 0 0 8px rgba(59, 130, 246, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-item.active-item {
|
||||||
|
border: 2.5px solid #3b82f6 !important;
|
||||||
|
box-shadow: 0 0 12px rgba(59, 130, 246, 0.4);
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alça de redimensionamento do card */
|
||||||
|
.canvas-resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
background: #3b82f6;
|
||||||
|
border: 2px solid white;
|
||||||
|
border-radius: 50%;
|
||||||
|
bottom: -7px;
|
||||||
|
right: -7px;
|
||||||
|
cursor: se-resize;
|
||||||
|
z-index: 10;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-item.active-item .canvas-resize-handle {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Oculte alças e tracejados na impressão e exportação */
|
||||||
|
@media print {
|
||||||
|
.canvas-resize-handle {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.canvas-item {
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user