let ingredientFields: HTMLInputElement[] = [] let ingredientTable: HTMLTableSectionElement = document.querySelector('#ingredient-table')! let ingredientAddButton: HTMLButtonElement = document.querySelector('#add-ingredient-btn')! let stepInput: HTMLTextAreaElement = document.querySelector('#new-instruction')! let stepList: HTMLUListElement = document.querySelector('#step-list')! let currentStepIndex = 0 // - VARS let ingredients: {qty: string, unit: string, name: string}[] = [] let steps: { index: number, instruction: string, ingredients: string[], // IDs of ingredient fields }[] = [] // - INIT document.addEventListener('DOMContentLoaded', function() { ingredientFields.push( document.querySelector('#ing-qty')!, document.querySelector('#ing-unit')!, document.querySelector('#ing-name')! ) // show plus button once the user types in the text fields ingredientFields.forEach(f => { f.addEventListener('input', showAddIngredientButton) f.addEventListener('keyup', showAddIngredientButton) }) // onclick for add button document.querySelector('#add-ingredient-btn')?.addEventListener('click', addIngredient); // for pressing enter to reset cursor ingredientFields[2].addEventListener('keyup', e => {if (e.key === 'Enter') addIngredient()} ) // Initial check for button state showAddIngredientButton() // Steps stepInput.addEventListener('keyup', e => { if (e.key === 'Enter' && e.shiftKey) addStep() } ) }); // - ADD function addIngredient() { const ing = { qty: ingredientFields[0].value, unit: ingredientFields[1].value, name: ingredientFields[2].value } ingredients.push(ing) const newRow = document.createElement('tr') newRow.innerHTML = ` ${ing.qty} ${ing.unit} ${ing.name} ` // Add row to table and clear fields ingredientTable.appendChild(newRow) ingredientFields.forEach(f => f.value = '') ingredientAddButton.style.display = 'none' // Hide Add Ingredient button // move cursor to Qty field again ingredientFields[0].focus() } function addStep() { const step = { index: currentStepIndex++, instruction: stepInput.value, ingredients: [] } steps.push(step) renderSteps() stepInput.value = '' } function renderSteps() { // clear the step list stepList.innerHTML = '' // re-render all steps in their current order steps.forEach((step, displayIndex) => { const newStep = document.createElement('div') // times like this i regret using astro newStep.innerHTML = `

Step ${displayIndex + 1}

${step.instruction}

` newStep.id = `step-${step.index}` newStep.className = "bg-[#2a2b2c] rounded-lg mb-2 p-3" stepList.appendChild(newStep) }) // event listeners to reorder buttons document.querySelectorAll('#move-up-btn').forEach(btn => { btn.addEventListener('click', (e) => { const stepIndex = parseInt((e.target as HTMLButtonElement).dataset.stepIndex!) moveStep(stepIndex, -1) }) }) document.querySelectorAll('#move-down-btn').forEach(btn => { btn.addEventListener('click', (e) => { const stepIndex = parseInt((e.target as HTMLButtonElement).dataset.stepIndex!) moveStep(stepIndex, 1) }) }) } // - UTILS function showAddIngredientButton() { const hasQty = ingredientFields[0].value.trim().length > 0 const hasName = ingredientFields[2].value.trim().length > 0 if (hasQty && hasName) { ingredientAddButton.disabled = false } else { ingredientAddButton.disabled = true } } // shift: the direction to move. should be +1 to move down or -1 to move up the list function moveStep(stepIndex: number, shift: number) { // Find the step in the array const currentStepArrayIndex = steps.findIndex(step => step.index === stepIndex) if (currentStepArrayIndex === -1) return // step not found const newIndex = currentStepArrayIndex + shift // check bounds if (newIndex < 0 || newIndex >= steps.length) return // swap the steps in the array const temp = steps[currentStepArrayIndex] steps[currentStepArrayIndex] = steps[newIndex] steps[newIndex] = temp // re-render the steps renderSteps() }