Sculpture Material Sheet Generator
Add / Edit Material
Current Material List
| Ref ID / Name | Type | Supplier | Qty | Unit Cost | Total Cost | Actions |
|---|
Generated Material Sheet Report
| Ref ID | Material Name | Type | Supplier | Qty & Units | Unit Cost | Total Cost (USD) |
|---|
Safety & Disposal Notes Summary
No specific notes recorded.
${material.safety}
`; } }); reviewSafetyNotes.innerHTML = safetyNotesContent || 'No specific safety or disposal notes recorded for critical materials.
'; pdfDownloadBtn.disabled = materialInventory.length === 0; }; const downloadPDF = () => { const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'pt', 'a4'); let currentY = 40; const margin = 40; const pageWidth = doc.internal.pageSize.width; const maxWidth = pageWidth - (margin * 2); const sculptureName = sculptureNameInput.value || 'Untitled Sculpture'; const artistName = artistNameInput.value || 'N/A'; const datePrepared = datePreparedInput.value || 'N/A'; const totalCost = summaryTotalCost.value; const checkPageBreak = (spaceNeeded) => { if (currentY + spaceNeeded > doc.internal.pageSize.height - margin) { doc.addPage(); currentY = margin; } }; const addText = (text, size = 10, style = 'normal', indent = 0) => { doc.setFontSize(size); doc.setFont('Helvetica', style); const lines = doc.splitTextToSize(text, maxWidth - indent); checkPageBreak(lines.length * (size * 1.2)); doc.text(lines, margin + indent, currentY); currentY += (lines.length * (size * 1.2)); }; // --- PDF Header --- doc.setFontSize(22); doc.setFont('Helvetica', 'bold'); doc.setTextColor(156, 39, 176); doc.text(`Material Sheet: ${sculptureName}`, margin, currentY); currentY += 15; doc.setFontSize(10); doc.setFont('Helvetica', 'normal'); doc.setTextColor(121, 85, 72); doc.text(`Artist: ${artistName} | Prepared: ${datePrepared}`, margin, currentY); currentY += 15; // --- Summary Block --- doc.setFontSize(10); doc.setFont('Helvetica', 'bold'); doc.setTextColor(0); doc.text(`Total Project Cost: ${totalCost} | Total Items: ${summaryTotalItems.value} | Primary Type: ${summaryPrimaryType.value}`, margin, currentY); currentY += 25; // --- Material Table --- const headStyles = { fillColor: [121, 85, 72], textColor: [255], fontStyle: 'bold' }; // Secondary color (Brown) const head = [ ["Ref ID", "Material Name", "Type", "Supplier", "Qty & Units", "Unit Cost", "Total Cost (USD)"] ]; const body = materialInventory.map(material => { const totalCost = calculateTotalCost(material.unitCost, material.quantity); const costStr = `$${totalCost.toFixed(2)}`; return [ material.id, material.name, material.type, material.supplier, `${material.quantity} ${material.units}`, `$${material.unitCost.toFixed(2)}`, costStr ]; }); doc.autoTable({ startY: currentY, head: head, body: body, theme: 'grid', headStyles: headStyles, styles: { fontSize: 8, cellPadding: 3, font: 'Helvetica' }, columnStyles: { 6: { fontStyle: 'bold' } } }); currentY = doc.autoTable.previous.finalY + 15; // --- Safety Notes --- checkPageBreak(20); doc.setFontSize(14); doc.setFont('Helvetica', 'bold'); doc.setTextColor(156, 39, 176); doc.text("Safety & Disposal Notes Summary", margin, currentY); currentY += 10; doc.setDrawColor(255, 193, 7); doc.setLineWidth(1); doc.rect(margin, currentY, maxWidth, 1, 'S'); // Yellow underline currentY += 5; let notesText = ''; materialInventory.forEach(m => { if (m.safety && m.safety.trim() !== '') { notesText += `${m.name} (${m.id}): ${m.safety}\n\n`; } }); if (notesText === '') notesText = "No specific safety or disposal notes recorded for critical materials."; addText(notesText, 10, 'normal', 5); // 5pt indent doc.save(`${sculptureName.replace(/\s/g, '_')}_Material_Sheet.pdf`); }; // --- Tab Navigation --- const switchTab = (tabIndex) => { tabs.forEach((tab, index) => { tab.classList.toggle('active', index === tabIndex); contents[index].classList.toggle('active', index === tabIndex); }); currentTab = tabIndex; updateNavButtons(); if (tabIndex === 2) { renderReviewTable(); } } const updateNavButtons = () => { prevBtn.disabled = currentTab === 0; nextBtn.disabled = currentTab === tabs.length - 1; } tabs.forEach((tab, index) => { tab.addEventListener('click', () => { const tabNode = tab.closest('.material-tab-button'); const newIndex = Array.from(tabNode.parentNode.children).indexOf(tabNode); switchTab(newIndex); }); }); nextBtn.addEventListener('click', () => { if (currentTab < tabs.length - 1) switchTab(currentTab + 1); }); prevBtn.addEventListener('click', () => { if (currentTab > 0) switchTab(currentTab - 1); }); // --- Event Listeners --- pdfDownloadBtn.addEventListener('click', downloadPDF); // Update summary and review if metadata changes Array.from(metaFormElements).forEach(el => { el.addEventListener('input', calculateSummary); }); // --- Initial Setup --- renderMaterialInventory(); calculateSummary(); updateNavButtons(); });