Character Design Tool
Build Your Character
Edit Features
Categories
Options for...
Select a category to view/edit options.
Error: Selected category not found.
Select a category to view/edit options.
'; } } function fullRefreshUI() { renderBuilder(); renderConfig(); } // === EVENT HANDLERS (Must be global for onclick) === window.cdtToggleEditSection = () => { if (!editContent || !toggleEditText) return; cdtState.editSectionVisible = !cdtState.editSectionVisible; editContent.style.display = cdtState.editSectionVisible ? 'block' : 'none'; toggleEditText.textContent = cdtState.editSectionVisible ? 'Hide' : 'Show'; const icon = editContent.previousElementSibling.querySelector('button i'); if (icon) { icon.className = cdtState.editSectionVisible ? 'fas fa-chevron-up' : 'fas fa-chevron-down'; } }; // --- Builder Handlers --- function handleOptionSelect(event) { const selectElement = event.target; const categoryId = selectElement.dataset.categoryId; const optionId = selectElement.value; if (optionId) { cdtState.selectedOptions[categoryId] = optionId; } else { delete cdtState.selectedOptions[categoryId]; // Remove if default is selected } generateDescription(); // Update description immediately } // --- Config Handlers --- window.cdtAddCategory = () => { if (!newCategoryNameInput) return; const name = newCategoryNameInput.value.trim(); if (!name) { alert('Please enter a category name.'); return; } // Check for duplicates if (cdtConfig.categories.some(c => c.name.toLowerCase() === name.toLowerCase())) { alert('A category with this name already exists.'); return; } cdtConfig.categories.push({ id: 'c' + Date.now(), name, options: [] }); newCategoryNameInput.value = ''; renderConfig(); renderBuilder(); // Update the builder dropdowns }; function handleCategorySelect(event) { const item = event.currentTarget; // The div that was clicked cdtState.selectedCategoryId = item.dataset.categoryId; renderConfig(); // Re-render to show selection highlight and options } // Make it available globally for inline onclick window.handleCategorySelect = handleCategorySelect; window.cdtDeleteCategory = (id) => { if (!confirm('Are you sure you want to delete this category and all its options?')) return; cdtConfig.categories = cdtConfig.categories.filter(c => c.id !== id); // Deselect if the deleted category was selected if (cdtState.selectedCategoryId === id) { cdtState.selectedCategoryId = null; } // Remove selections for this category from the character delete cdtState.selectedOptions[id]; renderConfig(); renderBuilder(); }; window.cdtAddOption = () => { if (!newOptionNameInput || !cdtState.selectedCategoryId) return; const name = newOptionNameInput.value.trim(); if (!name) { alert('Please enter an option name.'); return; } const category = findCategory(cdtState.selectedCategoryId); if (!category) { alert('Error: No category selected.'); return; } // Check for duplicates within the category if (category.options.some(o => o.name.toLowerCase() === name.toLowerCase())) { alert('An option with this name already exists in this category.'); return; } category.options.push({ id: 'o' + Date.now(), name }); newOptionNameInput.value = ''; renderConfig(); // Re-render options list renderBuilder(); // Update the corresponding dropdown }; window.cdtDeleteOption = (categoryId, optionId) => { // No confirmation needed for quick deletion const category = findCategory(categoryId); if (category) { category.options = category.options.filter(o => o.id !== optionId); // If this option was selected for the character, remove it if (cdtState.selectedOptions[categoryId] === optionId) { delete cdtState.selectedOptions[categoryId]; } renderConfig(); renderBuilder(); } }; // --- PDF Download --- window.cdtDownloadPDF = () => { if (!jsPDF || !jsPDF.autoTable) { alert('PDF library not loaded.'); return; } try { const doc = new jsPDF(); const pageMargin = 15; const pageWidth = doc.internal.pageSize.getWidth(); const contentWidth = pageWidth - pageMargin * 2; let y = 20; // 1. Title doc.setFontSize(20); doc.text("Character Sheet", pageWidth / 2, y, { align: 'center' }); y += 15; // 2. Features Table doc.setFontSize(16); doc.text("Selected Features", pageMargin, y); y += 10; const tableHead = [["Category", "Selection"]]; const tableBody = []; let hasSelections = false; cdtConfig.categories.forEach(category => { const selectedOptionId = cdtState.selectedOptions[category.id]; const option = selectedOptionId ? findOption(category.id, selectedOptionId) : null; if (option) { tableBody.push([category.name, option.name]); hasSelections = true; } else { tableBody.push([category.name, "(Not Selected)"]); } }); if (tableBody.length > 0) { doc.autoTable({ startY: y, head: tableHead, body: tableBody, theme: 'striped', headStyles: { fillColor: [0, 95, 204] }, // Primary color }); y = doc.autoTable.previous.finalY + 15; } else { doc.setFontSize(12); doc.text("No categories defined yet.", pageMargin, y); y += 10; } // 3. Description if (hasSelections && descriptionOutput) { doc.setFontSize(16); doc.text("Character Description", pageMargin, y); y += 10; doc.setFontSize(11); doc.setFont(undefined, 'normal'); const splitText = doc.splitTextToSize( descriptionOutput.value, contentWidth ); doc.text(splitText, pageMargin, y); } else if (!hasSelections) { doc.setFontSize(12); doc.text("No features selected to generate a description.", pageMargin, y); } doc.save("Character_Sheet.pdf"); } catch (e) { console.error("Error generating PDF:", e); alert("An error occurred while generating the PDF."); } }; // === INITIALIZATION === fullRefreshUI(); // Initially hide edit section if (editContent) editContent.style.display = 'none'; if (toggleEditText) toggleEditText.textContent = 'Show'; });