feat: add panel settings and footer customization options in the editor
This commit is contained in:
@@ -36,7 +36,11 @@ class YotoCoversApp {
|
|||||||
fontFamily: 'Comic Sans MS',
|
fontFamily: 'Comic Sans MS',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
footerColor: '#ff6b6b',
|
footerColor: '#ff6b6b',
|
||||||
fullBleed: false
|
fullBleed: false,
|
||||||
|
panelMode: true,
|
||||||
|
titlePanel: { borderWidth: 2, rotation: -2, expand: true },
|
||||||
|
imagePanel: { borderWidth: 3, rotation: 1 },
|
||||||
|
footerPanel: { borderWidth: 2, rotation: 3 }
|
||||||
},
|
},
|
||||||
polaroid: {
|
polaroid: {
|
||||||
backgroundStyle: 'polaroid',
|
backgroundStyle: 'polaroid',
|
||||||
@@ -235,10 +239,27 @@ class YotoCoversApp {
|
|||||||
document.getElementById('card-title-x').addEventListener('input', () => this.updateActiveCard());
|
document.getElementById('card-title-x').addEventListener('input', () => this.updateActiveCard());
|
||||||
document.getElementById('card-title-y').addEventListener('input', () => this.updateActiveCard());
|
document.getElementById('card-title-y').addEventListener('input', () => this.updateActiveCard());
|
||||||
document.getElementById('card-title-draggable').addEventListener('change', () => this.updateActiveCard());
|
document.getElementById('card-title-draggable').addEventListener('change', () => this.updateActiveCard());
|
||||||
|
document.getElementById('card-footer-font-size').addEventListener('input', () => this.updateActiveCard());
|
||||||
|
document.getElementById('card-footer-x').addEventListener('input', () => this.updateActiveCard());
|
||||||
|
document.getElementById('card-footer-y').addEventListener('input', () => this.updateActiveCard());
|
||||||
|
document.getElementById('card-footer-draggable').addEventListener('change', () => this.updateActiveCard());
|
||||||
document.getElementById('card-image-fit').addEventListener('change', () => this.updateActiveCard());
|
document.getElementById('card-image-fit').addEventListener('change', () => this.updateActiveCard());
|
||||||
document.getElementById('card-image-position').addEventListener('change', () => this.updateActiveCard());
|
document.getElementById('card-image-position').addEventListener('change', () => this.updateActiveCard());
|
||||||
document.getElementById('card-image-select').addEventListener('change', () => this.updateActiveCard());
|
document.getElementById('card-image-select').addEventListener('change', () => this.updateActiveCard());
|
||||||
|
|
||||||
|
// Panel settings
|
||||||
|
document.getElementById('card-panel-mode').addEventListener('change', () => {
|
||||||
|
this.updateActiveCard();
|
||||||
|
this.updateSectionVisibility();
|
||||||
|
});
|
||||||
|
document.getElementById('card-title-panel-border').addEventListener('input', () => this.updateActiveCard());
|
||||||
|
document.getElementById('card-title-panel-rotation').addEventListener('input', () => this.updateActiveCard());
|
||||||
|
document.getElementById('card-title-panel-expand').addEventListener('change', () => this.updateActiveCard());
|
||||||
|
document.getElementById('card-image-panel-border').addEventListener('input', () => this.updateActiveCard());
|
||||||
|
document.getElementById('card-image-panel-rotation').addEventListener('input', () => this.updateActiveCard());
|
||||||
|
document.getElementById('card-footer-panel-border').addEventListener('input', () => this.updateActiveCard());
|
||||||
|
document.getElementById('card-footer-panel-rotation').addEventListener('input', () => this.updateActiveCard());
|
||||||
|
|
||||||
// Title style selection auto-update
|
// Title style selection auto-update
|
||||||
document.querySelectorAll('.title-style-option').forEach(option => {
|
document.querySelectorAll('.title-style-option').forEach(option => {
|
||||||
option.addEventListener('click', () => {
|
option.addEventListener('click', () => {
|
||||||
@@ -374,6 +395,22 @@ class YotoCoversApp {
|
|||||||
document.getElementById('card-image-position').value = preset.imagePosition;
|
document.getElementById('card-image-position').value = preset.imagePosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set panel properties if defined in preset
|
||||||
|
document.getElementById('card-panel-mode').checked = preset.panelMode === true;
|
||||||
|
if (preset.titlePanel !== undefined) {
|
||||||
|
document.getElementById('card-title-panel-border').value = preset.titlePanel.borderWidth;
|
||||||
|
document.getElementById('card-title-panel-rotation').value = preset.titlePanel.rotation;
|
||||||
|
document.getElementById('card-title-panel-expand').checked = preset.titlePanel.expand;
|
||||||
|
}
|
||||||
|
if (preset.imagePanel !== undefined) {
|
||||||
|
document.getElementById('card-image-panel-border').value = preset.imagePanel.borderWidth;
|
||||||
|
document.getElementById('card-image-panel-rotation').value = preset.imagePanel.rotation;
|
||||||
|
}
|
||||||
|
if (preset.footerPanel !== undefined) {
|
||||||
|
document.getElementById('card-footer-panel-border').value = preset.footerPanel.borderWidth;
|
||||||
|
document.getElementById('card-footer-panel-rotation').value = preset.footerPanel.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
this.updateActiveCard();
|
this.updateActiveCard();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +432,19 @@ class YotoCoversApp {
|
|||||||
showTitle: true,
|
showTitle: true,
|
||||||
showFooter: true,
|
showFooter: true,
|
||||||
imageFit: 'cover',
|
imageFit: 'cover',
|
||||||
imagePosition: 'center'
|
imagePosition: 'center',
|
||||||
|
titleFontSize: 20,
|
||||||
|
footerFontSize: 12,
|
||||||
|
titleX: 50,
|
||||||
|
titleY: 20,
|
||||||
|
footerX: 50,
|
||||||
|
footerY: 90,
|
||||||
|
titleDraggable: false,
|
||||||
|
footerDraggable: false,
|
||||||
|
panelMode: false,
|
||||||
|
titlePanel: { borderWidth: 0, rotation: 0, expand: false },
|
||||||
|
imagePanel: { borderWidth: 0, rotation: 0 },
|
||||||
|
footerPanel: { borderWidth: 0, rotation: 0 }
|
||||||
};
|
};
|
||||||
this.cardVariations.push(variation);
|
this.cardVariations.push(variation);
|
||||||
this.updateCardList();
|
this.updateCardList();
|
||||||
@@ -508,6 +557,20 @@ class YotoCoversApp {
|
|||||||
if (preset.fullBleed !== undefined && variation.fullBleed !== preset.fullBleed) matches = false;
|
if (preset.fullBleed !== undefined && variation.fullBleed !== preset.fullBleed) matches = false;
|
||||||
if (preset.showFooter !== undefined && variation.showFooter !== preset.showFooter) matches = false;
|
if (preset.showFooter !== undefined && variation.showFooter !== preset.showFooter) matches = false;
|
||||||
if (preset.imagePosition !== undefined && variation.imagePosition !== preset.imagePosition) matches = false;
|
if (preset.imagePosition !== undefined && variation.imagePosition !== preset.imagePosition) matches = false;
|
||||||
|
if (preset.panelMode !== undefined && variation.panelMode !== preset.panelMode) matches = false;
|
||||||
|
if (preset.titlePanel !== undefined) {
|
||||||
|
if (variation.titlePanel?.borderWidth !== preset.titlePanel.borderWidth ||
|
||||||
|
variation.titlePanel?.rotation !== preset.titlePanel.rotation ||
|
||||||
|
variation.titlePanel?.expand !== preset.titlePanel.expand) matches = false;
|
||||||
|
}
|
||||||
|
if (preset.imagePanel !== undefined) {
|
||||||
|
if (variation.imagePanel?.borderWidth !== preset.imagePanel.borderWidth ||
|
||||||
|
variation.imagePanel?.rotation !== preset.imagePanel.rotation) matches = false;
|
||||||
|
}
|
||||||
|
if (preset.footerPanel !== undefined) {
|
||||||
|
if (variation.footerPanel?.borderWidth !== preset.footerPanel.borderWidth ||
|
||||||
|
variation.footerPanel?.rotation !== preset.footerPanel.rotation) matches = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (matches) {
|
if (matches) {
|
||||||
matchingPreset = presetName;
|
matchingPreset = presetName;
|
||||||
@@ -552,13 +615,29 @@ class YotoCoversApp {
|
|||||||
// Set title options
|
// Set title options
|
||||||
document.getElementById('card-title-font-size').value = variation.titleFontSize || 20;
|
document.getElementById('card-title-font-size').value = variation.titleFontSize || 20;
|
||||||
document.getElementById('card-title-x').value = variation.titleX !== undefined ? variation.titleX : 50;
|
document.getElementById('card-title-x').value = variation.titleX !== undefined ? variation.titleX : 50;
|
||||||
document.getElementById('card-title-y').value = variation.titleY !== undefined ? variation.titleY : 10;
|
document.getElementById('card-title-y').value = variation.titleY !== undefined ? variation.titleY : 20;
|
||||||
document.getElementById('card-title-draggable').checked = variation.titleDraggable === true;
|
document.getElementById('card-title-draggable').checked = variation.titleDraggable === true;
|
||||||
|
|
||||||
|
// Set footer options
|
||||||
|
document.getElementById('card-footer-font-size').value = variation.footerFontSize || 12;
|
||||||
|
document.getElementById('card-footer-x').value = variation.footerX !== undefined ? variation.footerX : 50;
|
||||||
|
document.getElementById('card-footer-y').value = variation.footerY !== undefined ? variation.footerY : 90;
|
||||||
|
document.getElementById('card-footer-draggable').checked = variation.footerDraggable === true;
|
||||||
|
|
||||||
// Set image options
|
// Set image options
|
||||||
document.getElementById('card-image-fit').value = variation.imageFit || 'cover';
|
document.getElementById('card-image-fit').value = variation.imageFit || 'cover';
|
||||||
document.getElementById('card-image-position').value = variation.imagePosition || 'center';
|
document.getElementById('card-image-position').value = variation.imagePosition || 'center';
|
||||||
|
|
||||||
|
// Set panel options
|
||||||
|
document.getElementById('card-panel-mode').checked = variation.panelMode === true;
|
||||||
|
document.getElementById('card-title-panel-border').value = variation.titlePanel?.borderWidth || 0;
|
||||||
|
document.getElementById('card-title-panel-rotation').value = variation.titlePanel?.rotation || 0;
|
||||||
|
document.getElementById('card-title-panel-expand').checked = variation.titlePanel?.expand === true;
|
||||||
|
document.getElementById('card-image-panel-border').value = variation.imagePanel?.borderWidth || 0;
|
||||||
|
document.getElementById('card-image-panel-rotation').value = variation.imagePanel?.rotation || 0;
|
||||||
|
document.getElementById('card-footer-panel-border').value = variation.footerPanel?.borderWidth || 0;
|
||||||
|
document.getElementById('card-footer-panel-rotation').value = variation.footerPanel?.rotation || 0;
|
||||||
|
|
||||||
// Populate image options
|
// Populate image options
|
||||||
const imageSelect = document.getElementById('card-image-select');
|
const imageSelect = document.getElementById('card-image-select');
|
||||||
imageSelect.innerHTML = '<option value="-1">Use default image</option>';
|
imageSelect.innerHTML = '<option value="-1">Use default image</option>';
|
||||||
@@ -579,9 +658,11 @@ class YotoCoversApp {
|
|||||||
updateSectionVisibility() {
|
updateSectionVisibility() {
|
||||||
const showTitle = document.getElementById('card-show-title').checked;
|
const showTitle = document.getElementById('card-show-title').checked;
|
||||||
const showFooter = document.getElementById('card-show-footer').checked;
|
const showFooter = document.getElementById('card-show-footer').checked;
|
||||||
|
const panelMode = document.getElementById('card-panel-mode').checked;
|
||||||
|
|
||||||
const titleSection = document.getElementById('title-section');
|
const titleSection = document.getElementById('title-section');
|
||||||
const footerSection = document.getElementById('footer-section');
|
const footerSection = document.getElementById('footer-section');
|
||||||
|
const panelSection = document.getElementById('panel-section');
|
||||||
|
|
||||||
if (showTitle) {
|
if (showTitle) {
|
||||||
titleSection.classList.remove('collapsed');
|
titleSection.classList.remove('collapsed');
|
||||||
@@ -594,6 +675,12 @@ class YotoCoversApp {
|
|||||||
} else {
|
} else {
|
||||||
footerSection.classList.add('collapsed');
|
footerSection.classList.add('collapsed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (panelMode) {
|
||||||
|
panelSection.classList.remove('collapsed');
|
||||||
|
} else {
|
||||||
|
panelSection.classList.add('collapsed');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initDragFunctionality() {
|
initDragFunctionality() {
|
||||||
@@ -706,6 +793,89 @@ class YotoCoversApp {
|
|||||||
document.addEventListener('mousemove', handleMouseMove);
|
document.addEventListener('mousemove', handleMouseMove);
|
||||||
document.addEventListener('mouseup', handleMouseUp);
|
document.addEventListener('mouseup', handleMouseUp);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Initialize footer drag functionality
|
||||||
|
const footers = iframeDoc.querySelectorAll('.footer, .comic-footer-panel');
|
||||||
|
console.log('Found footers:', footers.length);
|
||||||
|
|
||||||
|
footers.forEach((footer, index) => {
|
||||||
|
console.log(`Footer ${index} cursor:`, footer.style.cursor);
|
||||||
|
// Only make draggable if cursor is set to 'move' and not a comic panel
|
||||||
|
if (footer.style.cursor !== 'move' || footer.classList.contains('comic-footer-panel')) {
|
||||||
|
console.log(`Footer ${index} not draggable, skipping`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isDragging = false;
|
||||||
|
let startX, startY, initialLeft, initialBottom;
|
||||||
|
|
||||||
|
footer.addEventListener('mousedown', (e) => {
|
||||||
|
console.log('Footer mousedown fired');
|
||||||
|
if (footer.style.cursor !== 'move') return;
|
||||||
|
|
||||||
|
isDragging = true;
|
||||||
|
|
||||||
|
// Get iframe position and convert mouse coordinates to iframe-relative
|
||||||
|
const iframeRect = iframe.getBoundingClientRect();
|
||||||
|
startX = e.clientX - iframeRect.left;
|
||||||
|
startY = e.clientY - iframeRect.top;
|
||||||
|
|
||||||
|
// Store initial position
|
||||||
|
initialLeft = parseFloat(footer.style.left) || 50;
|
||||||
|
initialBottom = parseFloat(footer.style.bottom) || 10;
|
||||||
|
|
||||||
|
footer.style.zIndex = '1000';
|
||||||
|
footer.style.userSelect = 'none';
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleMouseMove = (e) => {
|
||||||
|
if (!isDragging) return;
|
||||||
|
|
||||||
|
// Get iframe position in main document
|
||||||
|
const iframeRect = iframe.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Convert mouse coordinates to be relative to iframe viewport
|
||||||
|
const mouseX = e.clientX - iframeRect.left;
|
||||||
|
const mouseY = e.clientY - iframeRect.top;
|
||||||
|
|
||||||
|
const card = footer.closest('.card');
|
||||||
|
const cardRect = card.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Calculate new position as percentage
|
||||||
|
const deltaX = mouseX - startX;
|
||||||
|
const deltaY = mouseY - startY;
|
||||||
|
|
||||||
|
const newLeftPercent = Math.max(0, Math.min(100, initialLeft + (deltaX / cardRect.width) * 100));
|
||||||
|
const newBottomPercent = Math.max(0, Math.min(100, initialBottom - (deltaY / cardRect.height) * 100));
|
||||||
|
|
||||||
|
footer.style.left = `${newLeftPercent}%`;
|
||||||
|
footer.style.bottom = `${newBottomPercent}%`;
|
||||||
|
|
||||||
|
// Update the card data
|
||||||
|
const cardIndex = Array.from(card.parentElement.children).indexOf(card);
|
||||||
|
if (this.cardVariations[cardIndex]) {
|
||||||
|
this.cardVariations[cardIndex].footerX = Math.round(newLeftPercent);
|
||||||
|
this.cardVariations[cardIndex].footerY = Math.round(100 - newBottomPercent);
|
||||||
|
this.updateUI();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
if (isDragging) {
|
||||||
|
isDragging = false;
|
||||||
|
footer.style.zIndex = '';
|
||||||
|
footer.style.userSelect = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add event listeners to both iframe document and main document
|
||||||
|
// to handle mouse events that might occur outside the iframe
|
||||||
|
iframeDoc.addEventListener('mousemove', handleMouseMove);
|
||||||
|
iframeDoc.addEventListener('mouseup', handleMouseUp);
|
||||||
|
document.addEventListener('mousemove', handleMouseMove);
|
||||||
|
document.addEventListener('mouseup', handleMouseUp);
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Ignore cross-origin errors
|
// Ignore cross-origin errors
|
||||||
console.log('Drag functionality initialization failed:', e);
|
console.log('Drag functionality initialization failed:', e);
|
||||||
@@ -747,10 +917,30 @@ class YotoCoversApp {
|
|||||||
variation.titleX = parseInt(document.getElementById('card-title-x').value);
|
variation.titleX = parseInt(document.getElementById('card-title-x').value);
|
||||||
variation.titleY = parseInt(document.getElementById('card-title-y').value);
|
variation.titleY = parseInt(document.getElementById('card-title-y').value);
|
||||||
variation.titleDraggable = document.getElementById('card-title-draggable').checked;
|
variation.titleDraggable = document.getElementById('card-title-draggable').checked;
|
||||||
|
variation.footerFontSize = parseInt(document.getElementById('card-footer-font-size').value);
|
||||||
|
variation.footerX = parseInt(document.getElementById('card-footer-x').value);
|
||||||
|
variation.footerY = parseInt(document.getElementById('card-footer-y').value);
|
||||||
|
variation.footerDraggable = document.getElementById('card-footer-draggable').checked;
|
||||||
variation.imageFit = document.getElementById('card-image-fit').value;
|
variation.imageFit = document.getElementById('card-image-fit').value;
|
||||||
variation.imagePosition = document.getElementById('card-image-position').value;
|
variation.imagePosition = document.getElementById('card-image-position').value;
|
||||||
variation.imageIndex = parseInt(document.getElementById('card-image-select').value);
|
variation.imageIndex = parseInt(document.getElementById('card-image-select').value);
|
||||||
|
|
||||||
|
// Panel settings
|
||||||
|
variation.panelMode = document.getElementById('card-panel-mode').checked;
|
||||||
|
variation.titlePanel = {
|
||||||
|
borderWidth: parseInt(document.getElementById('card-title-panel-border').value),
|
||||||
|
rotation: parseInt(document.getElementById('card-title-panel-rotation').value),
|
||||||
|
expand: document.getElementById('card-title-panel-expand').checked
|
||||||
|
};
|
||||||
|
variation.imagePanel = {
|
||||||
|
borderWidth: parseInt(document.getElementById('card-image-panel-border').value),
|
||||||
|
rotation: parseInt(document.getElementById('card-image-panel-rotation').value)
|
||||||
|
};
|
||||||
|
variation.footerPanel = {
|
||||||
|
borderWidth: parseInt(document.getElementById('card-footer-panel-border').value),
|
||||||
|
rotation: parseInt(document.getElementById('card-footer-panel-rotation').value)
|
||||||
|
};
|
||||||
|
|
||||||
this.updateCardList();
|
this.updateCardList();
|
||||||
this.generatePreview();
|
this.generatePreview();
|
||||||
}
|
}
|
||||||
@@ -832,7 +1022,9 @@ class YotoCoversApp {
|
|||||||
let imageIndex, cardTitle, cardFooter, cardTitleStyle, cardAccentColor, cardTitleColor, cardFullBleed, cardTitleShadow;
|
let imageIndex, cardTitle, cardFooter, cardTitleStyle, cardAccentColor, cardTitleColor, cardFullBleed, cardTitleShadow;
|
||||||
let cardBackgroundStyle, cardFontFamily, cardFontWeight, cardFooterColor, cardShowTitle, cardShowFooter;
|
let cardBackgroundStyle, cardFontFamily, cardFontWeight, cardFooterColor, cardShowTitle, cardShowFooter;
|
||||||
let cardImageFit, cardImagePosition, cardTitleFontSize, cardTitleX, cardTitleY, cardTitleDraggable;
|
let cardImageFit, cardImagePosition, cardTitleFontSize, cardTitleX, cardTitleY, cardTitleDraggable;
|
||||||
|
let cardFooterFontSize, cardFooterX, cardFooterY, cardFooterDraggable;
|
||||||
let cardShowAccent;
|
let cardShowAccent;
|
||||||
|
let cardPanelMode, cardTitlePanel, cardImagePanel, cardFooterPanel;
|
||||||
|
|
||||||
if (this.cardVariations.length > 0) {
|
if (this.cardVariations.length > 0) {
|
||||||
// Use variation settings
|
// Use variation settings
|
||||||
@@ -857,8 +1049,16 @@ class YotoCoversApp {
|
|||||||
cardImagePosition = (variation && variation.imagePosition) || 'center';
|
cardImagePosition = (variation && variation.imagePosition) || 'center';
|
||||||
cardTitleFontSize = (variation && variation.titleFontSize) || 20;
|
cardTitleFontSize = (variation && variation.titleFontSize) || 20;
|
||||||
cardTitleX = variation && variation.titleX !== undefined ? variation.titleX : 50;
|
cardTitleX = variation && variation.titleX !== undefined ? variation.titleX : 50;
|
||||||
cardTitleY = variation && variation.titleY !== undefined ? variation.titleY : 10;
|
cardTitleY = variation && variation.titleY !== undefined ? variation.titleY : 20;
|
||||||
cardTitleDraggable = variation && variation.titleDraggable !== undefined ? variation.titleDraggable : false;
|
cardTitleDraggable = variation && variation.titleDraggable !== undefined ? variation.titleDraggable : false;
|
||||||
|
cardFooterFontSize = (variation && variation.footerFontSize) || 12;
|
||||||
|
cardFooterX = variation && variation.footerX !== undefined ? variation.footerX : 50;
|
||||||
|
cardFooterY = variation && variation.footerY !== undefined ? variation.footerY : 90;
|
||||||
|
cardFooterDraggable = variation && variation.footerDraggable !== undefined ? variation.footerDraggable : false;
|
||||||
|
cardPanelMode = variation && variation.panelMode !== undefined ? variation.panelMode : false;
|
||||||
|
cardTitlePanel = variation && variation.titlePanel ? variation.titlePanel : { borderWidth: 0, rotation: 0, expand: false };
|
||||||
|
cardImagePanel = variation && variation.imagePanel ? variation.imagePanel : { borderWidth: 0, rotation: 0 };
|
||||||
|
cardFooterPanel = variation && variation.footerPanel ? variation.footerPanel : { borderWidth: 0, rotation: 0 };
|
||||||
} else {
|
} else {
|
||||||
// No variations - auto-assign images
|
// No variations - auto-assign images
|
||||||
imageIndex = i < this.images.length ? i : 0;
|
imageIndex = i < this.images.length ? i : 0;
|
||||||
@@ -881,8 +1081,16 @@ class YotoCoversApp {
|
|||||||
cardImagePosition = 'center';
|
cardImagePosition = 'center';
|
||||||
cardTitleFontSize = 20;
|
cardTitleFontSize = 20;
|
||||||
cardTitleX = 50;
|
cardTitleX = 50;
|
||||||
cardTitleY = 10;
|
cardTitleY = 20;
|
||||||
cardTitleDraggable = false;
|
cardTitleDraggable = false;
|
||||||
|
cardFooterFontSize = 12;
|
||||||
|
cardFooterX = 50;
|
||||||
|
cardFooterY = 90;
|
||||||
|
cardFooterDraggable = false;
|
||||||
|
cardPanelMode = false;
|
||||||
|
cardTitlePanel = { borderWidth: 0, rotation: 0, expand: false };
|
||||||
|
cardImagePanel = { borderWidth: 0, rotation: 0 };
|
||||||
|
cardFooterPanel = { borderWidth: 0, rotation: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const imageUrl = this.images.length > 0 ? this.images[imageIndex].dataUrl : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==';
|
const imageUrl = this.images.length > 0 ? this.images[imageIndex].dataUrl : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==';
|
||||||
@@ -909,6 +1117,14 @@ class YotoCoversApp {
|
|||||||
titleX: cardTitleX,
|
titleX: cardTitleX,
|
||||||
titleY: cardTitleY,
|
titleY: cardTitleY,
|
||||||
titleDraggable: cardTitleDraggable,
|
titleDraggable: cardTitleDraggable,
|
||||||
|
footerFontSize: cardFooterFontSize,
|
||||||
|
footerX: cardFooterX,
|
||||||
|
footerY: cardFooterY,
|
||||||
|
footerDraggable: cardFooterDraggable,
|
||||||
|
panelMode: cardPanelMode,
|
||||||
|
titlePanel: cardTitlePanel,
|
||||||
|
imagePanel: cardImagePanel,
|
||||||
|
footerPanel: cardFooterPanel,
|
||||||
isVisible: true
|
isVisible: true
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -935,6 +1151,10 @@ class YotoCoversApp {
|
|||||||
titleX: 50,
|
titleX: 50,
|
||||||
titleY: 10,
|
titleY: 10,
|
||||||
titleDraggable: false,
|
titleDraggable: false,
|
||||||
|
panelMode: false,
|
||||||
|
titlePanel: { borderWidth: 0, rotation: 0, expand: false },
|
||||||
|
imagePanel: { borderWidth: 0, rotation: 0 },
|
||||||
|
footerPanel: { borderWidth: 0, rotation: 0 },
|
||||||
isVisible: false
|
isVisible: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -995,29 +1215,66 @@ class YotoCoversApp {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
">
|
">
|
||||||
${card.isVisible ? `
|
${card.isVisible ? `
|
||||||
${card.backgroundStyle === 'comic' ? `
|
${card.panelMode ? `
|
||||||
<!-- Comic Style Panels -->
|
<!-- Comic Style Panels -->
|
||||||
<div class="comic-panels">
|
<div class="comic-panels">
|
||||||
${card.showTitle ? `<div class="comic-panel comic-title-panel" style="
|
${card.showTitle ? (card.titleStyle === 'split' ? `
|
||||||
|
<style>
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap');
|
||||||
|
.comic-panel.comic-title-panel.split {
|
||||||
|
--s: 4px;
|
||||||
|
--o: calc(0.5 * var(--s));
|
||||||
|
--sl: calc(50% - 0.5px), #0000 calc(50% + 0.5px);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 8%;
|
left: 8%;
|
||||||
top: 6%;
|
top: 6%;
|
||||||
width: 40%;
|
${card.titlePanel.expand ? 'width: auto; min-width: 30%; max-width: 60%;' : 'width: 40%;'}
|
||||||
height: 15%;
|
height: ${card.titlePanel.expand ? 'auto' : '15%'};
|
||||||
border: 2px solid #000;
|
border: ${card.titlePanel.borderWidth}px solid #000;
|
||||||
|
place-self: center;
|
||||||
|
place-content: center;
|
||||||
|
padding: calc(0.1em) 0.05em 0 0;
|
||||||
|
background:
|
||||||
|
linear-gradient(22.5deg, #fff var(--sl)) text,
|
||||||
|
linear-gradient(22.5deg, #000 var(--sl)),
|
||||||
|
linear-gradient(${card.titleColor} 50%, #0000 0)
|
||||||
|
0 0/ 1% var(--s);
|
||||||
|
color: #0000;
|
||||||
|
-webkit-text-stroke: #fff calc(var(--o));
|
||||||
|
text-transform: uppercase;
|
||||||
|
mix-blend-mode: screen;
|
||||||
|
font: clamp(1em, min(65vh, 35vw), 2em)/ 0.75 'Bebas Neue', sans-serif;
|
||||||
|
transform: rotate(${card.titlePanel.rotation}deg);
|
||||||
|
box-shadow: 2px 2px 4px rgba(0,0,0,0.2);
|
||||||
|
@supports (line-height: 1cap) { line-height: 1cap; }
|
||||||
|
}
|
||||||
|
@media (min-width: 480px) and (min-height: 320px) {
|
||||||
|
.comic-panel.comic-title-panel.split { --s: 6px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="comic-panel comic-title-panel split">${this.escapeHtml(card.title)}</div>
|
||||||
|
` : `<div class="comic-panel comic-title-panel" style="
|
||||||
|
position: absolute;
|
||||||
|
left: 8%;
|
||||||
|
top: 6%;
|
||||||
|
${card.titlePanel.expand ? 'width: auto; min-width: 30%; max-width: 60%;' : 'width: 40%;'}
|
||||||
|
height: ${card.titlePanel.expand ? 'auto' : '15%'};
|
||||||
|
border: ${card.titlePanel.borderWidth}px solid #000;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
white-space: pre-line;
|
||||||
|
text-align: center;
|
||||||
font-size: ${card.titleFontSize * 0.8}px;
|
font-size: ${card.titleFontSize * 0.8}px;
|
||||||
font-weight: ${card.fontWeight === 'bold' ? '700' : '400'};
|
font-weight: ${card.fontWeight === 'bold' ? '700' : '400'};
|
||||||
font-family: '${card.fontFamily}', serif;
|
font-family: '${card.fontFamily}', serif;
|
||||||
color: ${card.titleColor};
|
color: ${card.titleColor};
|
||||||
${card.titleShadow ? 'text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);' : ''}
|
${card.titleShadow ? 'text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);' : ''}
|
||||||
transform: rotate(-2deg);
|
transform: rotate(${card.titlePanel.rotation}deg);
|
||||||
box-shadow: 2px 2px 4px rgba(0,0,0,0.2);
|
box-shadow: 2px 2px 4px rgba(0,0,0,0.2);
|
||||||
${card.titleDraggable && card.backgroundStyle !== 'comic' ? 'cursor: move; user-select: none;' : ''}
|
${card.titleDraggable && !card.panelMode ? 'cursor: move; user-select: none;' : ''}
|
||||||
" data-panel-type="title">${this.escapeHtml(card.title)}</div>` : ''}
|
" data-panel-type="title">${this.escapeHtml(card.title)}</div>`) : ''}
|
||||||
|
|
||||||
<div class="comic-panel comic-image-panel" style="
|
<div class="comic-panel comic-image-panel" style="
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -1025,9 +1282,9 @@ class YotoCoversApp {
|
|||||||
top: 25%;
|
top: 25%;
|
||||||
right: 15%;
|
right: 15%;
|
||||||
bottom: ${card.showFooter ? '35%' : '15%'};
|
bottom: ${card.showFooter ? '35%' : '15%'};
|
||||||
border: 3px solid #000;
|
border: ${card.imagePanel.borderWidth}px solid #000;
|
||||||
background: ${card.fullBleed ? `url('${card.imageUrl}') no-repeat ${card.imagePosition}/${card.imageFit}` : '#f8f9fa'};
|
background: ${card.fullBleed ? `url('${card.imageUrl}') no-repeat ${card.imagePosition}/${card.imageFit}` : '#f8f9fa'};
|
||||||
transform: rotate(1deg);
|
transform: rotate(${card.imagePanel.rotation}deg);
|
||||||
box-shadow: 3px 3px 6px rgba(0,0,0,0.3);
|
box-shadow: 3px 3px 6px rgba(0,0,0,0.3);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
">
|
">
|
||||||
@@ -1054,7 +1311,7 @@ class YotoCoversApp {
|
|||||||
bottom: 6%;
|
bottom: 6%;
|
||||||
width: 35%;
|
width: 35%;
|
||||||
height: 12%;
|
height: 12%;
|
||||||
border: 2px solid #000;
|
border: ${card.footerPanel.borderWidth}px solid #000;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -1063,15 +1320,49 @@ class YotoCoversApp {
|
|||||||
font-weight: ${card.fontWeight};
|
font-weight: ${card.fontWeight};
|
||||||
font-family: '${card.fontFamily}', serif;
|
font-family: '${card.fontFamily}', serif;
|
||||||
color: ${card.footerColor};
|
color: ${card.footerColor};
|
||||||
transform: rotate(3deg);
|
transform: rotate(${card.footerPanel.rotation}deg);
|
||||||
box-shadow: 2px 2px 4px rgba(0,0,0,0.2);
|
box-shadow: 2px 2px 4px rgba(0,0,0,0.2);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
|
white-space: pre-line;
|
||||||
">${this.escapeHtml(card.footer)}</div>` : ''}
|
">${this.escapeHtml(card.footer)}</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
` : `
|
` : `
|
||||||
<!-- Standard Layout -->
|
<!-- Standard Layout -->
|
||||||
${card.showTitle ? `<div class="title ${card.titleStyle}" data-heading="${this.escapeHtml(card.title)}" style="
|
${card.showTitle ? (card.titleStyle === 'split' ? `
|
||||||
|
<style>
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap');
|
||||||
|
.title.split {
|
||||||
|
--s: 4px;
|
||||||
|
--o: calc(0.5 * var(--s));
|
||||||
|
--sl: calc(50% - 0.5px), #0000 calc(50% + 0.5px);
|
||||||
|
position: absolute;
|
||||||
|
left: ${card.titleX}%;
|
||||||
|
top: ${card.titleY}%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
place-self: center;
|
||||||
|
place-content: center;
|
||||||
|
padding: calc(0.1em) 0.05em 0 0;
|
||||||
|
height: calc(1lh - var(--o));
|
||||||
|
background:
|
||||||
|
linear-gradient(22.5deg, #fff var(--sl)) text,
|
||||||
|
linear-gradient(22.5deg, #000 var(--sl)),
|
||||||
|
linear-gradient(${card.titleColor} 50%, #0000 0)
|
||||||
|
0 0/ 1% var(--s);
|
||||||
|
color: #0000;
|
||||||
|
-webkit-text-stroke: #fff calc(var(--o));
|
||||||
|
text-transform: uppercase;
|
||||||
|
mix-blend-mode: screen;
|
||||||
|
font: clamp(2em, min(65vh, 35vw), 3.9em)/ 0.75 'Bebas Neue', sans-serif;
|
||||||
|
${card.titleDraggable ? 'cursor: move; user-select: none;' : ''}
|
||||||
|
@supports (line-height: 1cap) { line-height: 1cap; }
|
||||||
|
}
|
||||||
|
@media (min-width: 480px) and (min-height: 320px) {
|
||||||
|
.title.split { --s: 6px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="title split">${this.escapeHtml(card.title)}</div>
|
||||||
|
` : `<div class="title ${card.titleStyle}" data-heading="${this.escapeHtml(card.title)}" style="
|
||||||
color: ${card.titleColor};
|
color: ${card.titleColor};
|
||||||
font-weight: ${card.fontWeight === 'bold' ? '700' : '400'};
|
font-weight: ${card.fontWeight === 'bold' ? '700' : '400'};
|
||||||
font-family: '${card.fontFamily}', serif;
|
font-family: '${card.fontFamily}', serif;
|
||||||
@@ -1081,14 +1372,24 @@ class YotoCoversApp {
|
|||||||
left: ${card.titleX}%;
|
left: ${card.titleX}%;
|
||||||
top: ${card.titleY}%;
|
top: ${card.titleY}%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
|
white-space: pre-line;
|
||||||
|
text-align: center;
|
||||||
${card.titleDraggable ? 'cursor: move; user-select: none;' : ''}
|
${card.titleDraggable ? 'cursor: move; user-select: none;' : ''}
|
||||||
">${this.escapeHtml(card.title)}</div>` : ''}
|
">${this.escapeHtml(card.title)}</div>`) : ''}
|
||||||
${!card.fullBleed ? `<div class="hero"><img src="${card.imageUrl}" alt="cover" style="object-fit: ${card.imageFit}; object-position: ${card.imagePosition};"/></div>` : ''}
|
${!card.fullBleed ? `<div class="hero"><img src="${card.imageUrl}" alt="cover" style="object-fit: ${card.imageFit}; object-position: ${card.imagePosition};"/></div>` : ''}
|
||||||
${card.showAccent ? `<div class="overlay" style="background: ${card.accentColor}40;"></div>` : `<div class="overlay" style="background: rgba(0,0,0,0);"></div>`}
|
${card.showAccent ? `<div class="overlay" style="background: ${card.accentColor}40;"></div>` : `<div class="overlay" style="background: rgba(0,0,0,0);"></div>`}
|
||||||
${card.showFooter ? `<div class="footer" style="
|
${card.showFooter ? `<div class="footer" style="
|
||||||
color: ${card.footerColor};
|
color: ${card.footerColor};
|
||||||
font-family: '${card.fontFamily}', serif;
|
font-family: '${card.fontFamily}', serif;
|
||||||
font-weight: ${card.fontWeight};
|
font-weight: ${card.fontWeight};
|
||||||
|
font-size: ${card.footerFontSize}px;
|
||||||
|
position: absolute;
|
||||||
|
left: ${card.footerX}%;
|
||||||
|
bottom: ${100 - card.footerY}%;
|
||||||
|
transform: translate(-50%, 50%);
|
||||||
|
white-space: pre-line;
|
||||||
|
text-align: center;
|
||||||
|
${card.footerDraggable ? 'cursor: move; user-select: none;' : ''}
|
||||||
">${this.escapeHtml(card.footer)}</div>` : ''}
|
">${this.escapeHtml(card.footer)}</div>` : ''}
|
||||||
`}
|
`}
|
||||||
` : ''}
|
` : ''}
|
||||||
@@ -1269,7 +1570,7 @@ class YotoCoversApp {
|
|||||||
escapeHtml(text) {
|
escapeHtml(text) {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.textContent = text;
|
div.textContent = text;
|
||||||
return div.innerHTML;
|
return div.innerHTML.replace(/\n/g, '<br>');
|
||||||
}
|
}
|
||||||
|
|
||||||
openPreviewInNewTab() {
|
openPreviewInNewTab() {
|
||||||
|
|||||||
+91
-2
@@ -496,6 +496,13 @@
|
|||||||
align-items: end;
|
align-items: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-controls {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15px;
|
||||||
|
align-items: end;
|
||||||
|
}
|
||||||
|
|
||||||
.form-group.inline {
|
.form-group.inline {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
@@ -716,6 +723,64 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Panel Section -->
|
||||||
|
<div class="config-section" id="panel-section">
|
||||||
|
<h4>Panel Settings</h4>
|
||||||
|
<div class="section-controls">
|
||||||
|
<div class="checkbox-group">
|
||||||
|
<input type="checkbox" id="card-panel-mode">
|
||||||
|
<label for="card-panel-mode">Enable panel mode</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="section-content">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Title Panel</label>
|
||||||
|
<div class="panel-controls">
|
||||||
|
<div class="form-group inline">
|
||||||
|
<label for="card-title-panel-border">Border Width</label>
|
||||||
|
<input type="number" id="card-title-panel-border" value="0" min="0" max="10" step="1">
|
||||||
|
</div>
|
||||||
|
<div class="form-group inline">
|
||||||
|
<label for="card-title-panel-rotation">Rotation (°)</label>
|
||||||
|
<input type="number" id="card-title-panel-rotation" value="0" min="-10" max="10" step="1">
|
||||||
|
</div>
|
||||||
|
<div class="checkbox-group inline">
|
||||||
|
<input type="checkbox" id="card-title-panel-expand">
|
||||||
|
<label for="card-title-panel-expand">Expandable</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Image Panel</label>
|
||||||
|
<div class="panel-controls">
|
||||||
|
<div class="form-group inline">
|
||||||
|
<label for="card-image-panel-border">Border Width</label>
|
||||||
|
<input type="number" id="card-image-panel-border" value="0" min="0" max="10" step="1">
|
||||||
|
</div>
|
||||||
|
<div class="form-group inline">
|
||||||
|
<label for="card-image-panel-rotation">Rotation (°)</label>
|
||||||
|
<input type="number" id="card-image-panel-rotation" value="0" min="-10" max="10" step="1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Footer Panel</label>
|
||||||
|
<div class="panel-controls">
|
||||||
|
<div class="form-group inline">
|
||||||
|
<label for="card-footer-panel-border">Border Width</label>
|
||||||
|
<input type="number" id="card-footer-panel-border" value="0" min="0" max="10" step="1">
|
||||||
|
</div>
|
||||||
|
<div class="form-group inline">
|
||||||
|
<label for="card-footer-panel-rotation">Rotation (°)</label>
|
||||||
|
<input type="number" id="card-footer-panel-rotation" value="0" min="-10" max="10" step="1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Title Section -->
|
<!-- Title Section -->
|
||||||
<div class="config-section" id="title-section">
|
<div class="config-section" id="title-section">
|
||||||
<h4>Title</h4>
|
<h4>Title</h4>
|
||||||
@@ -728,7 +793,7 @@
|
|||||||
<div class="section-content">
|
<div class="section-content">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="card-title-input">Title Text</label>
|
<label for="card-title-input">Title Text</label>
|
||||||
<input type="text" id="card-title-input" placeholder="Enter card title">
|
<textarea id="card-title-input" placeholder="Enter card title" rows="2"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -738,6 +803,7 @@
|
|||||||
<div class="title-style-option" data-style="condensed">Condensed</div>
|
<div class="title-style-option" data-style="condensed">Condensed</div>
|
||||||
<div class="title-style-option" data-style="outlined">Outlined</div>
|
<div class="title-style-option" data-style="outlined">Outlined</div>
|
||||||
<div class="title-style-option selected" data-style="classic">Classic</div>
|
<div class="title-style-option selected" data-style="classic">Classic</div>
|
||||||
|
<div class="title-style-option" data-style="split">Split</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -848,7 +914,7 @@
|
|||||||
<div class="section-content">
|
<div class="section-content">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="card-footer-input">Footer Text</label>
|
<label for="card-footer-input">Footer Text</label>
|
||||||
<input type="text" id="card-footer-input" placeholder="Enter footer text">
|
<textarea id="card-footer-input" placeholder="Enter footer text" rows="2"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -858,6 +924,29 @@
|
|||||||
<input type="text" id="card-footer-color-text" value="#111111" class="color-value" readonly>
|
<input type="text" id="card-footer-color-text" value="#111111" class="color-value" readonly>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="card-footer-font-size">Footer Font Size (px)</label>
|
||||||
|
<input type="number" id="card-footer-font-size" value="12" min="8" max="100" step="2">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Footer Position</label>
|
||||||
|
<div class="position-controls">
|
||||||
|
<div class="form-group inline">
|
||||||
|
<label for="card-footer-x">X (%)</label>
|
||||||
|
<input type="number" id="card-footer-x" value="50" min="0" max="100" step="1">
|
||||||
|
</div>
|
||||||
|
<div class="form-group inline">
|
||||||
|
<label for="card-footer-y">Y (%)</label>
|
||||||
|
<input type="number" id="card-footer-y" value="90" min="0" max="100" step="1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="checkbox-group">
|
||||||
|
<input type="checkbox" id="card-footer-draggable">
|
||||||
|
<label for="card-footer-draggable">Enable drag to reposition</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user