Fashion Sketch Sheet Generator

Fashion Sketch Sheet Generator

Garment Technical Sheet (Editable)

Define your garment details using the "Configuration" tab and click "Generate Sheet."

Garment Identification

Materials & Details

Current Materials

No materials added yet.

"; return; } materials.forEach(m => { const itemEl = document.createElement("div"); itemEl.className = "fssg-config-list-item"; itemEl.dataset.id = m.id; itemEl.innerHTML = ` [${escapeHTML(m.category)}] ${escapeHTML(m.item)} (${escapeHTML(m.supplier)}) `; configMaterialList.appendChild(itemEl); }); } // --- Dashboard Management --- function renderDashboard(isInitial = true) { // Get config values const name = configDesignName.value; const collection = configCollection.value; const desc = configDesc.value; // --- Build Dashboard HTML --- dashboardOutput.innerHTML = `
# Item Name Category Supplier / Color / Details Action
`; // Populate Table Body const tbody = dashboardOutput.querySelector('#fssg-dash-tbody'); materials.forEach((m, index) => { const tr = document.createElement('tr'); tr.dataset.id = m.id; tr.innerHTML = ` ${index + 1} `; tbody.appendChild(tr); }); setupDashboardListeners(); if (!isInitial) showTab('fssg-tab-dashboard'); } /** * Attaches listeners to the dashboard elements */ function setupDashboardListeners() { const output = dashboardOutput; if (!output) return; // Event delegation for removal output.addEventListener('click', (e) => { if (e.target.dataset.action === 'remove-dash-item') { const tr = e.target.closest('tr'); materials.splice(materials.findIndex(m => m.id === tr.dataset.id), 1); // Rerender entirely to renumber and update state/config renderDashboard(false); updateConfigListDisplay(); } }); // Event delegation for input/change updates output.addEventListener('input', handleDashboardUpdate); output.addEventListener('change', handleDashboardUpdate); } /** * Handles updates made directly to the dashboard inputs/textareas */ function handleDashboardUpdate(e) { const target = e.target; const value = target.value; // 1. Update Config header fields from Dashboard if (target.id === 'fssg-dash-name') configDesignName.value = value; else if (target.id === 'fssg-dash-collection') configCollection.value = value; else if (target.id === 'fssg-dash-desc') configDesc.value = value; // 2. Update Material State const tr = target.closest('tr'); if (tr) { const mId = tr.dataset.id; const material = materials.find(m => m.id === mId); if (material) { const field = target.dataset.field; if (field) { material[field] = value; // Rerender config list immediately updateConfigListDisplay(); } } } } /** * Generates a PDF report from the dashboard data */ function downloadPDF() { if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF.autoTable === 'undefined') { alert("Error: PDF libraries could not be loaded. Please try again."); return; } // Get final data from dashboard inputs const name = configDesignName.value || "Untitled Design"; const collection = configCollection.value || "N/A"; const desc = configDesc.value || "N/A"; const constructionNotes = fssgContainer.querySelector("#fssg-dash-construction")?.value || "None recorded."; if (!name.trim()) { alert("Please generate the sheet first."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF("p", "pt", "a4"); const margin = 40; let yPos = margin; const lineHeight = 14; const usableWidth = doc.internal.pageSize.getWidth() - margin * 2; // Function to add a structured text block function addBlock(title, text, isTitle = false) { const titleHeight = isTitle ? 25 : 20; const textLines = doc.splitTextToSize(text, usableWidth); const textHeight = textLines.length * lineHeight; if (yPos + titleHeight + textHeight > doc.internal.pageSize.getHeight() - margin) { doc.addPage(); yPos = margin; } doc.setFontSize(isTitle ? 18 : 14); doc.setFont(undefined, 'bold'); doc.text(title, margin, yPos); yPos += isTitle ? lineHeight * 1.5 : lineHeight; if (!isTitle) { doc.setFontSize(10); doc.setFont(undefined, 'normal'); doc.text(textLines, margin, yPos); yPos += textHeight + lineHeight * 0.5; } else { yPos += 5; } } // --- Document Title & Header --- doc.setFontSize(22); doc.setFont(undefined, 'bold'); doc.text("FASHION TECHNICAL SHEET", doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += lineHeight * 2; doc.setFontSize(12); doc.setFont(undefined, 'normal'); doc.text(`Design Name: ${name}`, margin, yPos); doc.text(`Collection: ${collection}`, margin + 250, yPos); yPos += lineHeight * 2; // --- 1. Design Concept --- addBlock("1. Design Concept Summary", desc); // --- 2. Sketch Area Placeholder --- addBlock("2. Technical Sketch & Annotation Area (Print & Sketch)", "This area is reserved for hand-drawn front and back technical flats. Use this space for detailed annotations and callouts.", false); doc.rect(margin, yPos, usableWidth, 200); // Drawing a box placeholder yPos += 220; // --- 3. Materials Table --- if (yPos > doc.internal.pageSize.getHeight() - 100) { doc.addPage(); yPos = margin; } addBlock("3. Bill of Materials (BOM)", "The following list details all required fabrics, trims, and notions for construction.", false); const tableHead = [["#", "Item Name", "Category", "Supplier / Color / Details"]]; const tableBody = materials.map((m, index) => [ index + 1, m.item, m.category, m.supplier ]); doc.autoTable({ startY: yPos, head: tableHead, body: tableBody, theme: 'striped', headStyles: { fillColor: [233, 30, 99], textColor: [255, 255, 255], fontSize: 9 }, styles: { fontSize: 8, cellPadding: 4, overflow: 'linebreak' }, columnStyles: { 0: { cellWidth: 20, halign: 'center' }, 1: { cellWidth: 150 }, 2: { cellWidth: 80 }, 3: { cellWidth: 'auto' } }, margin: { left: margin, right: margin } }); yPos = doc.autoTable.previous.finalY + 20; // --- 4. Construction Notes --- addBlock("4. Construction Notes & Special Finishes", constructionNotes); doc.save(`${name.replace(/ /g,"_")}_Sketch_Sheet.pdf`); } /** * Helper to escape HTML */ function escapeHTML(str) { if (!str) return ""; return str .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } // --- 4. INITIALIZATION & EVENT LISTENERS --- // Tab Listeners tabButtons.forEach((btn) => { btn.addEventListener("click", () => showTab(btn.dataset.target)); }); navButtons.forEach((btn) => { btn.addEventListener("click", () => showTab(btn.dataset.target)); }); // Config Tab Listeners if (addMaterialForm) { addMaterialForm.addEventListener("submit", handleAddMaterial); } if (configMaterialList) { configMaterialList.addEventListener("click", handleRemoveMaterial); } if (generateBtn) { generateBtn.addEventListener("click", () => renderDashboard(false)); } // PDF Button if (pdfBtn) { pdfBtn.addEventListener("click", downloadPDF); } // Dashboard Listeners if (dashboardOutput) { dashboardOutput.addEventListener('input', handleDashboardUpdate); dashboardOutput.addEventListener('change', handleDashboardUpdate); } // Initial config list display updateConfigListDisplay(); // Initial State: Generate dashboard with samples renderDashboard(); showTab("fssg-tab-dashboard"); });
Scroll to Top