/* ui-zodiac.js β€” Zodiac sign browser section */ (function () { "use strict"; const zodiacReferenceBuilders = window.ZodiacReferenceBuilders || {}; if ( typeof zodiacReferenceBuilders.buildCubeSignPlacements !== "function" || typeof zodiacReferenceBuilders.buildMonthReferencesBySign !== "function" || typeof zodiacReferenceBuilders.cubePlacementLabel !== "function" || typeof zodiacReferenceBuilders.formatDateRange !== "function" ) { throw new Error("ZodiacReferenceBuilders module must load before ui-zodiac.js"); } const ELEMENT_STYLE = { fire: { emoji: "πŸ”₯", badge: "zod-badge--fire", label: "Fire" }, earth: { emoji: "🌍", badge: "zod-badge--earth", label: "Earth" }, air: { emoji: "πŸ’¨", badge: "zod-badge--air", label: "Air" }, water: { emoji: "πŸ’§", badge: "zod-badge--water", label: "Water" } }; const PLANET_SYMBOLS = { saturn: "β™„οΈŽ", jupiter: "β™ƒοΈŽ", mars: "β™‚οΈŽ", sol: "β˜‰οΈŽ", venus: "β™€οΈŽ", mercury: "☿︎", luna: "☾︎" }; const state = { initialized: false, entries: [], filteredEntries: [], selectedId: null, searchQuery: "", kabPaths: [], decansBySign: {}, monthRefsBySignId: new Map(), cubePlacementBySignId: new Map() }; // ── Elements ────────────────────────────────────────────────────────── function getElements() { return { listEl: document.getElementById("zodiac-sign-list"), countEl: document.getElementById("zodiac-sign-count"), searchEl: document.getElementById("zodiac-search-input"), searchClearEl: document.getElementById("zodiac-search-clear"), detailNameEl: document.getElementById("zodiac-detail-name"), detailSubEl: document.getElementById("zodiac-detail-sub"), detailBodyEl: document.getElementById("zodiac-detail-body") }; } // ── Normalise ───────────────────────────────────────────────────────── function norm(s) { return String(s || "").toLowerCase().replace(/[^a-z0-9 ]/g, "").trim(); } function cap(s) { return String(s || "").charAt(0).toUpperCase() + String(s || "").slice(1); } function buildSearchText(sign) { return norm([ sign.name?.en, sign.meaning?.en, sign.elementId, sign.quadruplicity, sign.planetId, sign.id ].join(" ")); } function formatDateRange(rulesFrom) { return zodiacReferenceBuilders.formatDateRange(rulesFrom); } function buildMonthReferencesBySign(referenceData) { return zodiacReferenceBuilders.buildMonthReferencesBySign(referenceData); } function buildCubeSignPlacements(magickDataset) { return zodiacReferenceBuilders.buildCubeSignPlacements(magickDataset); } function cubePlacementLabel(placement) { return zodiacReferenceBuilders.cubePlacementLabel(placement); } // ── List ────────────────────────────────────────────────────────────── function applyFilter() { const q = norm(state.searchQuery); state.filteredEntries = q ? state.entries.filter((s) => buildSearchText(s).includes(q)) : [...state.entries]; } function renderList(els) { if (!els.listEl) return; els.listEl.innerHTML = ""; state.filteredEntries.forEach((sign) => { const active = sign.id === state.selectedId; const el = document.createElement("div"); el.className = "planet-list-item" + (active ? " is-selected" : ""); el.setAttribute("role", "option"); el.setAttribute("aria-selected", active ? "true" : "false"); el.dataset.id = sign.id; const elemStyle = ELEMENT_STYLE[sign.elementId] || {}; el.innerHTML = `
${sign.symbol || "?"} ${sign.name?.en || sign.id} ${elemStyle.emoji || ""}
${cap(sign.elementId)} Β· ${cap(sign.quadruplicity)} Β· ${cap(sign.planetId)}
`; el.addEventListener("click", () => { selectById(sign.id, els); }); els.listEl.appendChild(el); }); if (els.countEl) { els.countEl.textContent = state.searchQuery ? `${state.filteredEntries.length} of ${state.entries.length} signs` : `${state.entries.length} signs`; } } // ── Detail ──────────────────────────────────────────────────────────── function renderDetail(sign, els) { if (!els.detailNameEl) return; const elemStyle = ELEMENT_STYLE[sign.elementId] || {}; const polarity = ["fire", "air"].includes(sign.elementId) ? "Masculine / Positive" : "Feminine / Negative"; const kabPath = state.kabPaths.find( (p) => p.astrology?.type === "zodiac" && p.astrology?.name?.toLowerCase() === sign.id ); const decans = state.decansBySign[sign.id] || []; const monthRefs = state.monthRefsBySignId.get(String(sign.id || "").toLowerCase()) || []; const cubePlacement = state.cubePlacementBySignId.get(String(sign.id || "").toLowerCase()) || null; // Heading els.detailNameEl.textContent = sign.symbol || sign.id; els.detailSubEl.textContent = `${sign.name?.en || ""} β€” ${sign.meaning?.en || ""}`; const sections = []; // ── Sign Details ────────────────────────────────────────────────── const elemBadge = `${elemStyle.emoji || ""} ${cap(sign.elementId)}`; const quadBadge = `${cap(sign.quadruplicity)}`; sections.push(`
Sign Details
Symbol
${sign.symbol || "β€”"}
Meaning
${sign.meaning?.en || "β€”"}
Element
${elemBadge}
Modality
${quadBadge}
Polarity
${polarity}
Dates
${formatDateRange(sign.rulesFrom)}
Position
#${sign.no} of 12
`); // ── Ruling Planet ───────────────────────────────────────────────── const planetSym = PLANET_SYMBOLS[sign.planetId] || ""; sections.push(`
Ruling Planet

${planetSym} ${cap(sign.planetId)}

`); if (cubePlacement) { sections.push(`
Cube of Space
This sign appears in Cube edge correspondences.
`); } // ── Kabbalah Path + Trump ───────────────────────────────────────── if (kabPath) { const hl = kabPath.hebrewLetter || {}; sections.push(`
Kabbalah & Major Arcana
${hl.char || ""}
${hl.transliteration || ""} (${hl.meaning || ""})
${cap(hl.letterType || "")} letter Β· Path ${kabPath.pathNumber}
Trump Card
${kabPath.tarot?.card || "β€”"}
Intelligence
${kabPath.intelligence || "β€”"}
`); } // ── Decans & Minor Arcana ───────────────────────────────────────── if (decans.length) { const decanRows = decans.map((d) => { const ord = ["1st","2nd","3rd"][d.index - 1] || d.index; const sym = PLANET_SYMBOLS[d.rulerPlanetId] || ""; return `
${ord} ${sym} ${cap(d.rulerPlanetId)}
`; }).join(""); sections.push(`
Decans & Minor Arcana
${decanRows}
`); } if (monthRefs.length) { const monthButtons = monthRefs.map((month) => `` ).join(""); sections.push(`
Calendar Months
Month correspondences linked to ${sign.name?.en || sign.id}.
${monthButtons}
`); } // ── Kabbalah extras ─────────────────────────────────────────────── if (sign.tribeOfIsraelId || sign.tetragrammatonPermutation) { sections.push(`
Kabbalah Correspondences
${sign.tribeOfIsraelId ? `
Tribe of Israel
${cap(sign.tribeOfIsraelId)}
` : ""} ${sign.tetragrammatonPermutation ? `
Tetragrammaton
${sign.tetragrammatonPermutation}
` : ""}
`); } els.detailBodyEl.innerHTML = `
${sections.join("")}
`; // Attach button listeners els.detailBodyEl.querySelectorAll("[data-nav]").forEach((btn) => { btn.addEventListener("click", () => { const nav = btn.dataset.nav; if (nav === "planet") { document.dispatchEvent(new CustomEvent("nav:planet", { detail: { planetId: btn.dataset.planetId } })); } else if (nav === "kab-path") { document.dispatchEvent(new CustomEvent("tarot:view-kab-path", { detail: { pathNumber: Number(btn.dataset.pathNumber) } })); } else if (nav === "trump") { document.dispatchEvent(new CustomEvent("kab:view-trump", { detail: { trumpNumber: Number(btn.dataset.trumpNumber) } })); } else if (nav === "tarot-card") { document.dispatchEvent(new CustomEvent("nav:tarot-trump", { detail: { cardName: btn.dataset.cardName } })); } else if (nav === "calendar-month") { document.dispatchEvent(new CustomEvent("nav:calendar-month", { detail: { monthId: btn.dataset.monthId } })); } else if (nav === "cube-sign") { document.dispatchEvent(new CustomEvent("nav:cube", { detail: { signId: btn.dataset.signId, wallId: btn.dataset.wallId, edgeId: btn.dataset.edgeId } })); } }); }); } function resetDetail(els) { if (els.detailNameEl) els.detailNameEl.textContent = "--"; if (els.detailSubEl) els.detailSubEl.textContent = "Select a sign to explore"; if (els.detailBodyEl) els.detailBodyEl.innerHTML = ""; } // ── Selection ───────────────────────────────────────────────────────── function selectById(id, els) { const sign = state.entries.find((s) => s.id === id); if (!sign) return; state.selectedId = id; renderList(els); renderDetail(sign, els); } // ── Public select (for incoming navigation) ─────────────────────────── function selectBySignId(signId) { const els = getElements(); if (!state.initialized) return; const sign = state.entries.find((s) => s.id === signId); if (sign) selectById(signId, els); } // ── Init ─────────────────────────────────────────────────────────────── function ensureZodiacSection(referenceData, magickDataset) { state.monthRefsBySignId = buildMonthReferencesBySign(referenceData); state.cubePlacementBySignId = buildCubeSignPlacements(magickDataset); if (state.initialized) { const els = getElements(); const current = state.entries.find((entry) => entry.id === state.selectedId); if (current) { renderDetail(current, els); } return; } state.initialized = true; const zodiacObj = magickDataset?.grouped?.astrology?.zodiac || {}; state.entries = Object.values(zodiacObj).sort((a, b) => (a.no || 0) - (b.no || 0)); const kabTree = magickDataset?.grouped?.kabbalah?.["kabbalah-tree"]; state.kabPaths = Array.isArray(kabTree?.paths) ? kabTree.paths : []; state.decansBySign = referenceData?.decansBySign || {}; const els = getElements(); applyFilter(); renderList(els); if (state.entries.length > 0) { selectById(state.entries[0].id, els); } // Search if (els.searchEl) { els.searchEl.addEventListener("input", () => { state.searchQuery = els.searchEl.value; if (els.searchClearEl) els.searchClearEl.disabled = !state.searchQuery; applyFilter(); renderList(els); if (!state.filteredEntries.some((s) => s.id === state.selectedId)) { if (state.filteredEntries.length > 0) { selectById(state.filteredEntries[0].id, els); } else { state.selectedId = null; resetDetail(els); } } }); } if (els.searchClearEl) { els.searchClearEl.addEventListener("click", () => { state.searchQuery = ""; if (els.searchEl) els.searchEl.value = ""; els.searchClearEl.disabled = true; applyFilter(); renderList(els); if (state.entries.length > 0) selectById(state.entries[0].id, els); }); } } window.ZodiacSectionUi = { ensureZodiacSection, selectBySignId }; })();