Secret Santa Name Generator

Secret Santa Name Generator

Secret Santa Name Generator

Generate fair and randomized pairings while enforcing exclusion rules.

Click the **Generate Pairings** button to create a new, valid pairing list. Results respect all defined exclusions.

Secret Santa Pairings

Exclusions Summary

Instructions

After generating the list, share each card privately with the respective Giver. Use the PDF for formal record-keeping.

Generated list is final and valid based on the rules below.

Pairings:

${pairsHTML}

Exclusion Rules:

    ${ssng_data.exclusions.map(e => `
  • ${ssng_getNameById(e[0])} cannot draw ${ssng_getNameById(e[1])}.
  • `).join('') || '
  • No specific constraints applied.
  • '}

Note: All participants are automatically prevented from drawing themselves.

`; } /** * Generates and downloads a PDF of the pairings */ async function ssng_downloadPDF() { if (ssng_data.pairings.length === 0) { alert("Please successfully generate a valid set of pairings before downloading."); return; } if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') { alert("Error: PDF libraries failed to load."); return; } ssng_renderPdfClone(); const { jsPDF } = window.jspdf; try { const contentDiv = ssng_pdfRenderClone.querySelector('.pdf-content'); if (!contentDiv) return; const canvas = await html2canvas(ssng_pdfRenderClone, { scale: 1.5, useCORS: true }); const imgData = canvas.toDataURL('image/png'); const imgProps = { width: canvas.width, height: canvas.height }; const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const margin = 40; const contentWidth = pdfWidth - (margin * 2); const contentHeight = (contentWidth * imgProps.height) / imgProps.width; let heightLeft = contentHeight; let position = 0; pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight); heightLeft -= (pdfHeight - margin * 2); while (heightLeft > 0) { position -= (pdfHeight - margin * 2); pdf.addPage(); pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight); heightLeft -= (pdfHeight - margin * 2); } pdf.save('Secret_Santa_Pairings.pdf'); } catch (error) { console.error("PDF generation failed:", error); alert("An error occurred while generating the PDF."); } } // --- EVENT LISTENERS --- // Tab link clicks ssng_tabLinks.forEach((link, index) => { link.addEventListener('click', () => ssng_switchTab(index)); }); // Next/Prev button clicks if (ssng_prevButton) { ssng_prevButton.addEventListener('click', () => { if (ssng_currentTab > 0) ssng_switchTab(ssng_currentTab - 1); }); } if (ssng_nextButton) { ssng_nextButton.addEventListener('click', () => { if (ssng_currentTab === ssng_tabLinks.length - 1) { ssng_updateDataFromConfig(); ssng_switchTab(0); } else { if (ssng_currentTab < ssng_tabLinks.length - 1) ssng_switchTab(ssng_currentTab + 1); } }); } // PDF download if (ssng_downloadPdfButton) { ssng_downloadPdfButton.addEventListener('click', ssng_downloadPDF); } // Generation trigger if (ssng_generateButton) { ssng_generateButton.addEventListener('click', ssng_generatePairings); } // --- Config Tab Listeners --- // 1. Participants if (ssng_addParticipantButton) { ssng_addParticipantButton.addEventListener('click', () => { ssng_participantsContainer.appendChild(ssng_createParticipantInput()); }); } if (ssng_participantsContainer) { ssng_participantsContainer.addEventListener('click', (e) => { const removeButton = e.target.closest('.ssng-remove-participant'); if (removeButton) { removeButton.closest('.flex[data-id]').remove(); ssng_updateDataFromConfig(); // Update IDs before rerender ssng_renderConfig(); // Rerender full config area to refresh dropdowns } }); } // 2. Exclusions if (ssng_addExclusionRuleButton) { ssng_addExclusionRuleButton.addEventListener('click', () => { // Add with dummy IDs, updated later by ssng_updateDataFromConfig ssng_exclusionsConfigContainer.appendChild(ssng_createExclusionInput(ssng_data.participants[0]?.id || 0, ssng_data.participants[1]?.id || 0, ssng_exclusionRuleCounter++)); }); } if (ssng_exclusionsConfigContainer) { ssng_exclusionsConfigContainer.addEventListener('click', (e) => { const removeButton = e.target.closest('.ssng-remove-exclusion'); if (removeButton) { removeButton.closest('.flex[data-index]').remove(); } }); } // --- INITIALIZATION --- ssng_renderConfig(); ssng_renderDashboard(); // Set initial tab state ssng_tabPanes.forEach((pane, index) => { pane.classList.toggle('hidden', index !== 0); pane.classList.toggle('ssng-active', index === 0); }); ssng_tabLinks.forEach((link, index) => { TAB_CLASSES.active.forEach(cls => link.classList.remove(cls)); TAB_CLASSES.inactive.forEach(cls => link.classList.remove(cls)); if (index === 0) { TAB_CLASSES.active.forEach(cls => link.classList.add(cls)); } else { TAB_CLASSES.inactive.forEach(cls => link.classList.add(cls)); } }); });
Scroll to Top