Prop List Creator (Theatre/Film)

Prop List Creator (Theatre/Film)

My Play - Prop List

Prop Name Description Scene Status

Project Information

Add New Prop

Current Props

No props added yet.

"; } appState.props.forEach(prop => { const item = document.createElement("div"); item.className = "plc-prop-item"; item.innerHTML = ` ${prop.name} (Scene: ${prop.scene || 'N/A'}) `; propsList.appendChild(item); }); } function getUniqueScenes() { const scenes = new Set(); appState.props.forEach(prop => { if (prop.scene && prop.scene.trim()) { scenes.add(prop.scene.trim()); } }); return Array.from(scenes).sort(); } function renderDashboardTab() { projectTitleDisplay.textContent = `${appState.projectName} - Prop List`; // Populate Scene Filter const uniqueScenes = getUniqueScenes(); const currentSceneFilter = filterSceneSelect.value; // Preserve selection filterSceneSelect.innerHTML = ''; uniqueScenes.forEach(scene => { const option = document.createElement('option'); option.value = scene; option.textContent = scene; filterSceneSelect.appendChild(option); }); filterSceneSelect.value = currentSceneFilter; // Restore selection // Filter props based on selections const sceneFilter = filterSceneSelect.value; const statusFilter = filterStatusSelect.value; const filteredProps = appState.props.filter(prop => { const sceneMatch = sceneFilter === 'all' || prop.scene === sceneFilter; const statusMatch = statusFilter === 'all' || prop.status === statusFilter; return sceneMatch && statusMatch; }); // Render Table tableBody.innerHTML = ""; if (filteredProps.length === 0) { tableBody.innerHTML = "No props match the current filters."; return; } filteredProps.forEach(prop => { const tr = document.createElement("tr"); tr.innerHTML = ` ${prop.name} ${prop.description || ''} ${prop.scene || ''} ${prop.status || ''} `; tableBody.appendChild(tr); }); } // --- Event Handlers --- // Update Dashboard Button updateBtn.addEventListener("click", () => { appState.projectName = projectNameInput.value || "Untitled Project"; saveState(); renderDashboardTab(); // Re-render dashboard with potentially new project name showTab(0); }); // Add Prop addPropBtn.addEventListener("click", () => { const name = propNameInput.value.trim(); const description = propDescInput.value.trim(); const scene = propSceneInput.value.trim(); const status = propStatusSelect.value; if (!name) { alert("Please enter a prop name."); return; } const newProp = { id: Date.now(), name: name, description: description, scene: scene, status: status }; appState.props.push(newProp); saveState(); renderConfigTab(); // Update the list in config tab // Clear form propNameInput.value = ""; propDescInput.value = ""; propSceneInput.value = ""; propStatusSelect.value = "To Source"; }); // Remove Prop (Event Delegation) propsList.addEventListener("click", (e) => { if (e.target.classList.contains("plc-remove-btn")) { const id = parseInt(e.target.dataset.id); appState.props = appState.props.filter(p => p.id !== id); saveState(); renderConfigTab(); // Update list in config } }); // Filters Change filterSceneSelect.addEventListener("change", renderDashboardTab); filterStatusSelect.addEventListener("change", renderDashboardTab); // PDF Download pdfBtn.addEventListener("click", () => { const { jsPDF } = window.jspdf; const fileName = `${appState.projectName.replace(/ /g, '_')}_Prop_List.pdf`; // Clone the export area to modify for PDF without affecting the screen const clonedExportArea = exportArea.cloneNode(true); // Optional: Remove filter display from PDF? // const filtersElement = clonedExportArea.querySelector('.plc-filters'); // if(filtersElement) filtersElement.remove(); html2canvas(clonedExportArea, { // Use the cloned node scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const doc = new jsPDF({ orientation: 'p', // Portrait is usually better for lists unit: 'pt', format: 'a4' }); const pdfWidth = doc.internal.pageSize.getWidth(); const pdfHeight = doc.internal.pageSize.getHeight(); const imgProps = doc.getImageProperties(imgData); const imgWidth = imgProps.width; const imgHeight = imgProps.height; const margin = 40; const usableWidth = pdfWidth - (2 * margin); const ratio = usableWidth / imgWidth; let scaledHeight = imgHeight * ratio; let position = margin; // Handle multi-page if needed if (scaledHeight > pdfHeight - (2 * margin)) { const pageHeight = pdfHeight - (2 * margin); let heightLeft = scaledHeight; while (heightLeft > 0) { // Calculate the height of the portion of the image to add for this page const pageImageHeight = Math.min(pageHeight / ratio, imgHeight - (scaledHeight - heightLeft) / ratio); // Calculate the y offset in the original image const imageOffsetY = (scaledHeight - heightLeft) / ratio; // Create a temporary canvas to draw the slice const tempCanvas = document.createElement('canvas'); tempCanvas.width = imgWidth; tempCanvas.height = pageImageHeight; const tempCtx = tempCanvas.getContext('2d'); tempCtx.drawImage(canvas, 0, imageOffsetY, imgWidth, pageImageHeight, 0, 0, imgWidth, pageImageHeight); const pageImgData = tempCanvas.toDataURL('image/png'); if (position !== margin) { // Add new page if not the first page doc.addPage(); } doc.addImage(pageImgData, 'PNG', margin, margin, usableWidth, pageHeight); heightLeft -= pageHeight; position += pageHeight; // Update position conceptually for the loop } } else { // Single page doc.addImage(imgData, 'PNG', margin, margin, usableWidth, scaledHeight); } doc.save(fileName); }).catch(err => { console.error("PLC PDF Error:", err); // alert("An error occurred while generating the PDF."); // Per spec }); }); // --- Local Storage --- function saveState() { try { localStorage.setItem("plcAppState", JSON.stringify(appState)); } catch (e) { console.warn("PLC: Could not save state."); } } function loadState() { try { const storedState = localStorage.getItem("plcAppState"); if (storedState) appState = JSON.parse(storedState); } catch (e) { console.warn("PLC: Could not load state."); } } // --- Initial Load --- loadState(); renderConfigTab(); // Load state into config first renderDashboardTab(); // Then render dashboard showTab(0); // Start on Dashboard });
Scroll to Top