No materials added.
';
return;
}
sdc_data.materials.forEach(material => {
const item = document.createElement('div');
item.className = 'sdc-list-item';
item.innerHTML = `
${sdc_escapeHTML(material.name)} (+$${material.cost.toFixed(2)})
`;
sdc_materialListEl.appendChild(item);
});
}
/**
* Saves the new base price
*/
window.sdc_saveBasePrice = function() {
if (!sdc_basePriceInput) return;
const newPrice = parseFloat(sdc_basePriceInput.value);
if (!isNaN(newPrice) && newPrice >= 0) {
sdc_data.basePrice = newPrice;
sdc_updatePrice();
alert('Base price updated.');
} else {
alert('Please enter a valid price.');
sdc_basePriceInput.value = sdc_data.basePrice.toFixed(2);
}
}
/**
* Adds a new material from the form
*/
window.sdc_addMaterial = function(event) {
event.preventDefault();
if (!sdc_newMaterialNameInput || !sdc_newMaterialCostInput) return;
const name = sdc_newMaterialNameInput.value.trim();
const cost = parseFloat(sdc_newMaterialCostInput.value);
if (name && !isNaN(cost) && cost >= 0) {
if (sdc_data.materials.some(m => m.name.toLowerCase() === name.toLowerCase())) {
alert('A material with this name already exists.');
return;
}
sdc_data.materials.push({ name, cost });
sdc_renderConfigLists();
sdc_renderDashboardControls();
// Reset form
sdc_newMaterialNameInput.value = '';
sdc_newMaterialCostInput.value = '0.00';
}
}
/**
* Deletes a material
*/
window.sdc_deleteMaterial = function(name) {
if (sdc_data.materials.length <= 1) {
alert('You must have at least one material.');
return;
}
if (confirm(`Are you sure you want to delete "${name}"?`)) {
sdc_data.materials = sdc_data.materials.filter(m => m.name !== name);
sdc_renderConfigLists();
sdc_renderDashboardControls();
sdc_handleDesignChange(); // Update price in case deleted material was selected
}
}
// --- TAB & NAVIGATION FUNCTIONS ---
window.sdc_switchTab = function(tabIndex) {
sdc_currentTabIndex = tabIndex;
sdc_tabContents.forEach((content, index) => {
content.classList.toggle('sdc-active', index === tabIndex);
});
sdc_tabs.forEach((tab, index) => {
tab.classList.toggle('sdc-active', index === tabIndex);
});
sdc_updateNavButtons();
}
window.sdc_navigateTabs = function(direction) {
if (direction === 'next' && sdc_currentTabIndex < sdc_numTabs - 1) {
sdc_switchTab(sdc_currentTabIndex + 1);
} else if (direction === 'prev' && sdc_currentTabIndex > 0) {
sdc_switchTab(sdc_currentTabIndex - 1);
}
}
function sdc_updateNavButtons() {
sdc_prevBtn.style.visibility = (sdc_currentTabIndex === 0) ? 'hidden' : 'visible';
sdc_nextBtn.style.visibility = (sdc_currentTabIndex === sdc_numTabs - 1) ? 'hidden' : 'visible';
}
// --- PDF GENERATION ---
/**
* Generates and downloads the design as a PDF
*/
window.sdc_generatePdf = function() {
if (typeof jspdf === 'undefined' || typeof jspdf.jsPDF === 'undefined') {
alert('Error: PDF generation library (jsPDF) not loaded.');
return;
}
if (typeof window.jspdf.plugin.autotable === 'undefined') {
alert('Error: PDF generation library (jsPDF-AutoTable) not loaded.');
return;
}
try {
const { jsPDF } = jspdf;
const doc = new jsPDF();
const svgEl = document.getElementById('sdc-shoe-svg');
const canvasEl = document.getElementById('sdc-pdf-canvas');
if (!svgEl || !canvasEl) {
throw new Error('SVG or Canvas element not found.');
}
// 1. Serialize and draw SVG to Canvas
const svgData = new XMLSerializer().serializeToString(svgEl);
const img = new Image();
const svgBase64 = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgData)));
img.onload = function() {
// Set canvas dimensions
const svgRect = svgEl.getBoundingClientRect();
canvasEl.width = svgRect.width * 2; // Increase resolution for PDF
canvasEl.height = svgRect.height * 2;
const ctx = canvasEl.getContext('2d');
ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
// Draw image to canvas
ctx.drawImage(img, 0, 0, canvasEl.width, canvasEl.height);
// Get canvas image data
const canvasImgData = canvasEl.toDataURL('image/png');
// 2. Build the PDF
const margin = 15;
const docWidth = doc.internal.pageSize.getWidth();
const imgWidth = docWidth - (margin * 2);
const imgHeight = (canvasEl.height * imgWidth) / canvasEl.width;
let cursorY = 20;
// Title
doc.setFont('helvetica', 'bold');
doc.setFontSize(20);
doc.setTextColor(varGet('--sdc-primary-color', '#0073e6'));
doc.text("My Custom Shoe Design", 105, cursorY, { align: 'center' });
cursorY += 15;
// Shoe Image
doc.addImage(canvasImgData, 'PNG', margin, cursorY, imgWidth, imgHeight);
cursorY += imgHeight + 15;
// 3. Add Design Summary Table
const basePrice = parseFloat(sdc_data.basePrice) || 0;
const material = sdc_data.materials.find(m => m.name === sdc_currentDesign.material);
const materialCost = material ? parseFloat(material.cost) : 0;
const totalPrice = basePrice + materialCost;
const tableHead = [["Component", "Selection", "Cost"]];
const tableBody = [
['Base Shoe', '-', `$${basePrice.toFixed(2)}`],
['Upper Material', sdc_currentDesign.material, `$${materialCost.toFixed(2)}`],
['Upper Color', sdc_currentDesign.upperColor, '-'],
['Sole Color', sdc_currentDesign.soleColor, '-'],
['Laces Color', sdc_currentDesign.lacesColor, '-'],
['Logo Color', sdc_currentDesign.logoColor, '-']
];
doc.autoTable({
head: tableHead,
body: tableBody,
startY: cursorY,
theme: 'striped',
headStyles: {
fillColor: varGet('--sdc-primary-color', '#0073e6'),
textColor: varGet('--sdc-text-light', '#fff')
},
alternateRowStyles: {
fillColor: varGet('--sdc-light-primary', '#e6f1fc')
},
// Total Row
didDrawPage: (data) => {
doc.setFont('helvetica', 'bold');
doc.setFontSize(14);
doc.text('Total Price:', data.settings.margin.left, doc.autoTable.previous.finalY + 10);
doc.text(`$${totalPrice.toFixed(2)}`, data.table.width - data.settings.margin.right, doc.autoTable.previous.finalY + 10, { align: 'right' });
}
});
// 4. Save PDF
doc.save('my_shoe_design.pdf');
};
img.src = svgBase64;
} catch (e) {
console.error("PDF Generation Error: ", e);
alert("An error occurred while generating the PDF.");
}
}
// --- UTILITY FUNCTIONS ---
function varGet(varName, fallback = '#000') {
try {
return getComputedStyle(document.documentElement).getPropertyValue(varName).trim() || fallback;
} catch (e) {
return fallback;
}
}
function sdc_escapeHTML(str) {
if (!str) return '';
return str.replace(/[&<>"']/g, function(m) {
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[m];
});
}
// --- INITIALIZATION ---
function sdc_initTool() {
// Setup tabs
sdc_switchTab(0);
// Populate config tab
sdc_renderConfigLists();
// Populate dashboard
sdc_renderDashboardControls();
// Set initial state
sdc_handleDesignChange();
// Attach event listeners for dashboard controls
if (sdc_materialSelect) sdc_materialSelect.addEventListener('input', sdc_handleDesignChange);
if (sdc_upperColorInput) sdc_upperColorInput.addEventListener('input', sdc_handleDesignChange);
if (sdc_soleColorInput) sdc_soleColorInput.addEventListener('input', sdc_handleDesignChange);
if (sdc_lacesColorInput) sdc_lacesColorInput.addEventListener('input', sdc_handleDesignChange);
if (sdc_logoColorInput) sdc_logoColorInput.addEventListener('input', sdc_handleDesignChange);
}
sdc_initTool(); // Run the tool
}); // End of DOMContentLoaded