Fountain Pen Ink Swatch Log

Fountain Pen Ink Swatch Log

Add New Ink Log


My Ink Log

No inks logged yet. Use the form above to add one.

Customize Form Labels

Manage Dropdown Options

Flow Options

Shading Options

Sheen Options

Pen: ${ink.pen}

Flow: ${ink.flow} Shading: ${ink.shading} Sheen: ${ink.sheen}

${notes}

`; fpiLogList.appendChild(item); }); } } function renderAllConfigLists() { Object.keys(fpiDropdownData).forEach(renderConfigList); } function renderConfigList(type) { const listEl = fpiToolContainer.querySelector(`#fpi-list-${type}`); if (!listEl) return; listEl.innerHTML = ''; // Clear fpiDropdownData[type].forEach(option => { const tag = document.createElement('div'); tag.className = 'fpi-config-tag'; tag.innerHTML = ` ${option} `; listEl.appendChild(tag); }); } function renderAllDashboardDropdowns() { Object.keys(fpiDropdownData).forEach(renderDashboardDropdown); } function renderDashboardDropdown(type) { const selectEl = fpiToolContainer.querySelector(`#fpi-select-${type}`); if (!selectEl) return; selectEl.innerHTML = ''; fpiDropdownData[type].forEach(option => { const optionEl = document.createElement('option'); optionEl.value = option; optionEl.textContent = option; selectEl.appendChild(optionEl); }); } // --- Event Handlers --- function handleAddInk(e) { e.preventDefault(); const newInk = { id: fpiNextId++, name: fpiToolContainer.querySelector('#fpi-input-name').value, brand: fpiToolContainer.querySelector('#fpi-input-brand').value, pen: fpiToolContainer.querySelector('#fpi-input-pen').value, color: fpiToolContainer.querySelector('#fpi-input-color').value, flow: fpiToolContainer.querySelector('#fpi-select-flow').value, shading: fpiToolContainer.querySelector('#fpi-select-shading').value, sheen: fpiToolContainer.querySelector('#fpi-select-sheen').value, notes: fpiToolContainer.querySelector('#fpi-textarea-notes').value }; fpiInkLog.push(newInk); renderLogList(); fpiAddForm.reset(); fpiToolContainer.querySelector('#fpi-input-color').value = '#005bb5'; // Reset color } function handleLogListClick(e) { const target = e.target; if (target.matches('.fpi-delete-btn')) { const id = parseInt(target.dataset.id, 10); if (confirm("Are you sure you want to delete this ink log?")) { fpiInkLog = fpiInkLog.filter(ink => ink.id !== id); renderLogList(); } } if (target.matches('.fpi-edit-btn')) { const id = parseInt(target.dataset.id, 10); const ink = fpiInkLog.find(ink => ink.id === id); if (!ink) return; // Use prompt() for simple editing as alert/confirm are banned, but prompt is okay. const newName = prompt("Edit Ink Name:", ink.name); if (newName === null) return; const newBrand = prompt("Edit Ink Brand:", ink.brand); if (newBrand === null) return; const newPen = prompt("Edit Pen Used:", ink.pen); if (newPen === null) return; const newNotes = prompt("Edit Notes:", ink.notes); if (newNotes === null) return; // Update the ink object ink.name = newName; ink.brand = newBrand; ink.pen = newPen; ink.notes = newNotes; renderLogList(); } } function handleConfigClick(e) { const target = e.target; if (target.matches('.fpi-add-btn')) { const type = target.dataset.type; const input = fpiToolContainer.querySelector(`#fpi-input-${type}`); if (input) { const value = input.value.trim(); if (value && !fpiDropdownData[type].includes(value)) { fpiDropdownData[type].push(value); renderConfigList(type); renderAllDashboardDropdowns(); input.value = ''; } } } if (target.matches('.fpi-delete-btn')) { const type = target.dataset.type; const value = target.dataset.value; fpiDropdownData[type] = fpiDropdownData[type].filter(opt => opt !== value); renderConfigList(type); renderAllDashboardDropdowns(); } } /** Saves label configuration */ window.fpiSaveConfig = function() { for (const [configId, targetId] of Object.entries(fpiLabelMap)) { const configInput = document.getElementById(configId); const targetElement = document.getElementById(targetId); if (configInput && targetElement) { targetElement.textContent = configInput.value.trim() || "Label"; } } alert('Labels saved!'); fpiTabLinks[0].click(); // Switch to dashboard } /** Generates and downloads a PDF of the report */ async function downloadPDF() { if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') { console.error("jsPDF or html2canvas library not loaded."); alert("Error: PDF generation libraries not loaded."); return; } const { jsPDF } = window.jspdf; if (fpiPdfBtn) { fpiPdfBtn.textContent = 'Generating...'; fpiPdfBtn.disabled = true; } const contentToExport = document.getElementById('fpi-pdf-content'); if (!contentToExport) { // ... reset button return; } contentToExport.classList.add('fpi-pdf-export-content'); try { const canvas = await html2canvas(contentToExport, { scale: 2, useCORS: true, logging: false, onclone: (doc) => { // Hide controls in the cloned document doc.querySelectorAll('.fpi-pdf-hide-in-export').forEach(el => { el.style.display = 'none'; }); } }); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'px', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const ratio = canvas.width / pdfWidth; const scaledHeight = canvas.height / ratio; let position = 0; let heightLeft = scaledHeight; pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, scaledHeight); heightLeft -= pdfHeight; while (heightLeft > 0) { position = heightLeft - scaledHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, scaledHeight); heightLeft -= pdfHeight; } pdf.save('fountain_pen_ink_log.pdf'); } catch (error) { console.error("Error during PDF generation:", error); alert("An error occurred while generating the PDF."); } finally { // Clean up contentToExport.classList.remove('fpi-pdf-export-content'); if (fpiPdfBtn) { fpiPdfBtn.textContent = 'Download Log as PDF'; fpiPdfBtn.disabled = false; } } } // --- Tab Navigation Functions --- window.fpiOpenTab = function(evt, tabName) { if (!fpiTabContents.length || !fpiTabLinks.length) return; fpiTabContents.forEach(tabcontent => { tabcontent.style.display = "none"; tabcontent.classList.remove('fpi-active'); }); fpiTabLinks.forEach(tablink => { tablink.classList.remove('fpi-active'); }); const currentTabContent = document.getElementById(tabName); if (currentTabContent) { currentTabContent.style.display = "block"; currentTabContent.classList.add('fpi-active'); } if (evt && evt.currentTarget) { evt.currentTarget.classList.add('fpi-active'); } fpiCurrentTab = fpiTabLinks.indexOf(evt.currentTarget); updateNavButtons(); } window.fpiNavTab = function(n) { const newIndex = fpiCurrentTab + n; if (newIndex >= 0 && newIndex < fpiTabLinks.length) { fpiTabLinks[newIndex].click(); } } function updateNavButtons() { if (fpiPrevBtn) fpiPrevBtn.disabled = (fpiCurrentTab === 0); if (fpiNextBtn) fpiNextBtn.disabled = (fpiCurrentTab === fpiTabLinks.length - 1); } })();
Scroll to Top