diff --git a/ayto/index.html b/ayto/index.html index 820834f..b2abe08 100644 --- a/ayto/index.html +++ b/ayto/index.html @@ -3,12 +3,14 @@ - AYTO? Match Calculator + AYTO Matcher | Probability Engine + + - + - - + -
- -
-

- Unlock the Perfect Matches -

-

- The ultimate probability engine for "Are You The One?". - Our Rust-powered core calculates millions of possibilities in real-time. -

-
- - +
- - -
+ + - -
- - +
+ - +
+
+ + + + + @@ -311,24 +405,23 @@ const loadButton = $("load-button"); const fileLoader = $("file-loader"); const themeSelect = $("theme-select"); + const inputSections = $("input-sections"); + const statusDashboard = $("status-dashboard"); const g1NamesText = $("group1-names"); const g2NamesText = $("group2-names"); - const tbSection = $("truth-booth-section"); const tbForm = $("truth-booth-form"); const tbGroup1 = $("tb-group1"); const tbGroup2 = $("tb-group2"); const tbResult = $("tb-result"); const tbList = $("truth-booth-list"); - const ceremonySection = $("ceremony-section"); const ceremonyForm = $("ceremony-form"); const ceremonyPairsContainer = $("ceremony-pairs-container"); const ceremonyBeams = $("ceremony-beams"); const ceremonyList = $("ceremony-list"); - const calculateSection = $("calculate-section"); const gridSection = $("grid-section"); const resultsDisplay = $("results-display"); const totalPossibilitiesText = $("total-possibilities"); @@ -341,6 +434,9 @@ const loadingSpinner = $("loading-spinner"); const initialPossibilitiesText = $("initial-possibilities-text"); + // Initialize Icons + lucide.createIcons(); + themeSelect.addEventListener('change', (e) => { document.documentElement.setAttribute('data-theme', e.target.value); localStorage.setItem('ayto-theme', e.target.value); @@ -358,19 +454,19 @@ function showError(message) { errorText.textContent = message; errorMessage.classList.remove("hidden"); - errorMessage.classList.remove("opacity-0"); + errorMessage.style.opacity = "1"; setTimeout(() => { - errorMessage.classList.add("opacity-0"); - setTimeout(() => errorMessage.classList.add("hidden"), 300); - }, 4000); + errorMessage.style.opacity = "0"; + setTimeout(() => errorMessage.classList.add("hidden"), 500); + }, 5000); } function handleSetupContestants() { const g1 = g1NamesText.value.split('\n').map(s => s.trim()).filter(s => s.length > 0); const g2 = g2NamesText.value.split('\n').map(s => s.trim()).filter(s => s.length > 0); - if (g1.length === 0 || g2.length === 0) return showError("The villa is empty! Add names."); - if (g1.length > g2.length) return showError("Too many matchers, not enough pool!"); + if (g1.length === 0 || g2.length === 0) return showError("Enter contestant names to begin."); + if (g1.length > g2.length) return showError("The matcher group must be smaller than or equal to the pool."); group1Names = g1; group2Names = g2; @@ -382,15 +478,14 @@ populateSelectors(); populateCeremonyPairBuilder(); - initialPossibilitiesText.textContent = `Villa ready: ${group1Names.length} vs ${group2Names.length}`; + initialPossibilitiesText.textContent = `${group1Names.length} Matches • ${group2Names.length} Potential Pools`; - tbSection.classList.remove("hidden"); - ceremonySection.classList.remove("hidden"); - calculateSection.classList.remove("hidden"); + inputSections.classList.remove("hidden"); + statusDashboard.classList.remove("hidden"); gridSection.classList.remove("hidden"); - resultsDisplay.classList.add("hidden"); saveButton.disabled = false; + lucide.createIcons(); return true; } @@ -402,10 +497,10 @@ function populateCeremonyPairBuilder() { ceremonyPairsContainer.innerHTML = group1Names.map(name => ` -
- ${name} - + ${group2Names.map(g2name => ``).join('')}
@@ -414,13 +509,18 @@ function renderTruthBoothUI(booth) { const el = document.createElement('div'); - el.className = `p-4 rounded-2xl flex justify-between items-center glass animate-fade-in ${booth.isMatch ? 'border-green/20 text-green' : 'border-red/20 text-red'}`; + const color = booth.isMatch ? 'text-green border-green/20' : 'text-red border-red/20'; + el.className = `p-3 rounded-2xl flex justify-between items-center bg-white/[0.02] border animate-slide-in ${color}`; el.innerHTML = ` - ${booth.p1} + ${booth.p2} = ${booth.isMatch ? 'Match' : 'No'} - +
+ + ${booth.p1} + ${booth.p2} +
+ `; tbList.appendChild(el); el.querySelector('.remove-tb-btn').addEventListener('click', handleRemoveTruthBooth); + lucide.createIcons(); } function handleAddTruthBooth(e) { @@ -428,33 +528,38 @@ const booth = { id: Date.now(), p1: tbGroup1.value, p2: tbGroup2.value, isMatch: tbResult.value === 'match' }; truthBooths.push(booth); renderTruthBoothUI(booth); + handleCalculate(); } function handleRemoveTruthBooth(e) { - const idToRemove = Number(e.target.dataset.id); + const idToRemove = Number(e.currentTarget.dataset.id); truthBooths = truthBooths.filter(b => b.id !== idToRemove); - e.target.parentElement.remove(); + e.currentTarget.closest('div').remove(); + handleCalculate(); } function renderCeremonyUI(ceremony, index) { const el = document.createElement('div'); - el.className = 'p-5 rounded-2xl glass border-white/5 ceremony-item animate-fade-in'; + el.className = 'p-5 rounded-3xl glass-panel border-white/5 shadow-lg animate-slide-in group'; el.innerHTML = ` -
- Ceremony ${index} • ${ceremony.beams} Beams - +
+
+ ${index} + ${ceremony.beams} Beams +
+
-
+
${Object.entries(ceremony.pairs).map(([p1, p2]) => ` -
- ${p1} - ${p2} +
+ ${p1} ↔ ${p2}
`).join('')}
`; ceremonyList.appendChild(el); el.querySelector('.remove-ceremony-btn').addEventListener('click', handleRemoveCeremony); + lucide.createIcons(); } function handleAddCeremony(e) { @@ -465,24 +570,26 @@ for (const select of pairSelectors) { const g2Name = select.value; - if (!g2Name) return showError("Incomplete ceremony! Pair everyone."); + if (!g2Name) return showError("Match everyone before recording the ceremony."); selectedG2Names.push(g2Name); pairs[select.dataset.g1Name] = g2Name; } - if (new Set(selectedG2Names).size !== selectedG2Names.length) return showError("Duplicate selection in ceremony!"); + if (new Set(selectedG2Names).size !== selectedG2Names.length) return showError("Each pool member can only be selected once."); const beams = parseInt(ceremonyBeams.value, 10); const ceremony = { id: Date.now(), pairs, beams }; ceremonies.push(ceremony); renderCeremonyUI(ceremony, ceremonies.length); + handleCalculate(); } function handleRemoveCeremony(e) { - const idToRemove = Number(e.target.dataset.id); + const idToRemove = Number(e.currentTarget.dataset.id); ceremonies = ceremonies.filter(c => c.id !== idToRemove); ceremonyList.innerHTML = ''; ceremonies.forEach((c, i) => renderCeremonyUI(c, i + 1)); + handleCalculate(); } async function handleCalculate() { @@ -501,22 +608,20 @@ body: JSON.stringify(payload) }); - if (!res.ok) throw new Error("Backend malfunction"); + if (!res.ok) throw new Error("Calculation engine error."); const results = await res.json(); totalPossibilitiesText.textContent = results.possibilities.toLocaleString(); - resultsDisplay.classList.remove("hidden"); if (results.possibilities === 0) { - showError("Impossible scenario detected!"); + showError("IMPOSSIBLE SCENARIO: The data entered is contradictory."); probTableBody.innerHTML = ''; probTableHead.innerHTML = ''; } else { displayProbabilityGrid(results.grid_data); - gridSection.scrollIntoView({ behavior: 'smooth' }); } } catch (e) { - showError("Connection failed"); + showError("Could not reach the analysis server."); } finally { hideLoading(); } @@ -525,20 +630,27 @@ function displayProbabilityGrid(gridData) { probTableHead.innerHTML = ` - - ${gridData.columns.map(name => `${name}`).join('')} + + ${gridData.columns.map(name => `${name}`).join('')} `; probTableBody.innerHTML = gridData.index.map((g1Name, rowIndex) => ` - ${g1Name} + ${g1Name} ${gridData.columns.map((g2Name, colIndex) => { const prob = gridData.data[rowIndex][colIndex] * 100; - let cellClass = 'prob-possible'; - if (prob >= 99.9) cellClass = 'prob-100'; - else if (prob <= 0.1) cellClass = 'prob-0'; - return `${prob.toFixed(1)}%`; + let cellClass = 'text-overlay1'; + let badgeClass = 'bg-white/5 text-overlay1'; + + if (prob >= 99.9) badgeClass = 'bg-green/20 text-green shadow-[0_0_15px_rgba(166,227,161,0.2)]'; + else if (prob <= 0.1) badgeClass = 'bg-red/10 text-red opacity-30'; + else if (prob > 50) badgeClass = 'bg-blue/20 text-blue'; + else if (prob > 0) badgeClass = 'bg-peach/20 text-peach'; + + return ` + ${prob.toFixed(1)}% + `; }).join('')} `).join(''); @@ -565,6 +677,7 @@ truthBooths = s.truthBooths; ceremonies = s.ceremonies; truthBooths.forEach(renderTruthBoothUI); ceremonies.forEach((c, i) => renderCeremonyUI(c, i + 1)); + handleCalculate(); }; reader.readAsText(file); });