Files
TaroTime/app/ui-kabbalah-detail.js
2026-03-07 05:17:50 -08:00

509 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function () {
"use strict";
const PLANET_ID_TO_LABEL = {
saturn: "Saturn",
jupiter: "Jupiter",
mars: "Mars",
sol: "Sol",
venus: "Venus",
mercury: "Mercury",
luna: "Luna"
};
const MINOR_RANK_BY_PLURAL = {
aces: "Ace",
twos: "Two",
threes: "Three",
fours: "Four",
fives: "Five",
sixes: "Six",
sevens: "Seven",
eights: "Eight",
nines: "Nine",
tens: "Ten"
};
const MINOR_SUITS = ["Wands", "Cups", "Swords", "Disks"];
const DEFAULT_FOUR_QABALISTIC_WORLD_LAYERS = [
{
slot: "Yod",
letterChar: "י",
hebrewToken: "yod",
world: "Atziluth",
worldLayer: "Archetypal World (Gods Will)",
worldDescription: "World of gods or specific facets or divine qualities.",
soulLayer: "Chiah",
soulTitle: "Life Force",
soulDescription: "The Chiah is the Life Force itself and our true identity as reflection of Supreme Consciousness."
},
{
slot: "Heh",
letterChar: "ה",
hebrewToken: "he",
world: "Briah",
worldLayer: "Creative World (Gods Love)",
worldDescription: "World of archangels, executors of divine qualities.",
soulLayer: "Neshamah",
soulTitle: "Soul-Intuition",
soulDescription: "The Neshamah is the part of our soul that transcends the thinking process."
},
{
slot: "Vav",
letterChar: "ו",
hebrewToken: "vav",
world: "Yetzirah",
worldLayer: "Formative World (Gods Mind)",
worldDescription: "World of angels who work under archangelic direction.",
soulLayer: "Ruach",
soulTitle: "Intellect",
soulDescription: "The Ruach is the thinking mind that often dominates attention and identity."
},
{
slot: "Heh (final)",
letterChar: "ה",
hebrewToken: "he",
world: "Assiah",
worldLayer: "Material World (Gods Creation)",
worldDescription: "World of spirits that infuse matter and energy through specialized duties.",
soulLayer: "Nephesh",
soulTitle: "Animal Soul",
soulDescription: "The Nephesh is instinctive consciousness expressed through appetite, emotion, sex drive, and survival."
}
];
function metaCard(label, value, wide) {
const card = document.createElement("div");
card.className = wide ? "planet-meta-card kab-wide-card" : "planet-meta-card";
card.innerHTML = `<strong>${label}</strong><p class="planet-text">${value || "—"}</p>`;
return card;
}
function createNavButton(label, eventName, detail) {
const btn = document.createElement("button");
btn.type = "button";
btn.className = "kab-god-link";
btn.textContent = `${label}`;
btn.addEventListener("click", () => {
document.dispatchEvent(new CustomEvent(eventName, { detail }));
});
return btn;
}
function appendLinkRow(card, buttons) {
if (!buttons?.length) return;
const row = document.createElement("div");
row.className = "kab-god-links";
buttons.forEach((button) => row.appendChild(button));
card.appendChild(row);
}
function buildPlanetLuminaryCard(planetValue, context) {
const card = metaCard("Planet / Luminary", planetValue);
const planetId = context.resolvePlanetId(planetValue);
if (planetId) {
appendLinkRow(card, [
createNavButton(`View ${PLANET_ID_TO_LABEL[planetId] || planetValue} in Planets`, "nav:planet", { planetId })
]);
return card;
}
const zodiacId = context.resolveZodiacId(planetValue);
if (zodiacId) {
appendLinkRow(card, [
createNavButton(`View ${zodiacId.charAt(0).toUpperCase() + zodiacId.slice(1)} in Zodiac`, "nav:zodiac", { signId: zodiacId })
]);
}
return card;
}
function extractMinorRank(attribution) {
const match = String(attribution || "").match(/\bthe\s+4\s+(aces|twos|threes|fours|fives|sixes|sevens|eights|nines|tens)\b/i);
if (!match) return null;
return MINOR_RANK_BY_PLURAL[(match[1] || "").toLowerCase()] || null;
}
function buildMinorTarotNames(attribution) {
const rank = extractMinorRank(attribution);
if (!rank) return [];
return MINOR_SUITS.map((suit) => `${rank} of ${suit}`);
}
function buildTarotAttributionCard(attribution) {
const card = metaCard("Tarot Attribution", attribution);
const minorCards = buildMinorTarotNames(attribution);
if (minorCards.length) {
appendLinkRow(card, minorCards.map((cardName) =>
createNavButton(cardName, "nav:tarot-trump", { cardName })
));
}
return card;
}
function buildAstrologyCard(astrology, context) {
const astroText = astrology ? `${astrology.name} (${astrology.type})` : "—";
const card = metaCard("Astrology", astroText);
if (astrology?.type === "planet") {
const planetId = context.resolvePlanetId(astrology.name);
if (planetId) {
appendLinkRow(card, [
createNavButton(`View ${PLANET_ID_TO_LABEL[planetId] || astrology.name} in Planets`, "nav:planet", { planetId })
]);
}
} else if (astrology?.type === "zodiac") {
const signId = context.resolveZodiacId(astrology.name);
if (signId) {
appendLinkRow(card, [
createNavButton(`View ${signId.charAt(0).toUpperCase() + signId.slice(1)} in Zodiac`, "nav:zodiac", { signId })
]);
}
}
return card;
}
function buildConnectsCard(path, fromName, toName) {
const card = metaCard("Connects", `${fromName}${toName}`);
appendLinkRow(card, [
createNavButton(`View ${fromName}`, "nav:kabbalah-path", { pathNo: Number(path.connects.from) }),
createNavButton(`View ${toName}`, "nav:kabbalah-path", { pathNo: Number(path.connects.to) })
]);
return card;
}
function buildHebrewLetterCard(letter, context) {
const label = `${letter.char || ""} ${letter.transliteration || ""} — "${letter.meaning || ""}" (${letter.letterType || ""})`;
const card = metaCard("Hebrew Letter", label);
const hebrewLetterId = context.resolveHebrewLetterId(letter.transliteration || letter.char || "");
if (hebrewLetterId) {
appendLinkRow(card, [
createNavButton(`View ${letter.transliteration || letter.char || "Letter"} in Alphabet`, "nav:alphabet", {
alphabet: "hebrew",
hebrewLetterId
})
]);
}
return card;
}
function buildFourWorldsCard(tree, activeHebrewToken, context) {
const activeToken = String(activeHebrewToken || "").trim().toLowerCase();
const worldLayers = Array.isArray(context.fourWorldLayers) && context.fourWorldLayers.length
? context.fourWorldLayers
: DEFAULT_FOUR_QABALISTIC_WORLD_LAYERS;
const card = document.createElement("div");
card.className = "planet-meta-card kab-wide-card";
const title = document.createElement("strong");
title.textContent = "Four Qabalistic Worlds & Soul Layers";
card.appendChild(title);
const stack = document.createElement("div");
stack.className = "cal-item-stack";
worldLayers.forEach((layer) => {
const row = document.createElement("div");
row.className = "cal-item-row";
const isActive = Boolean(activeToken) && activeToken === String(layer.hebrewToken || "").trim().toLowerCase();
const head = document.createElement("div");
head.className = "cal-item-head";
head.innerHTML = `
<span class="cal-item-name">${layer.slot}: ${layer.letterChar}${layer.world}</span>
<span class="planet-list-meta">${layer.soulLayer}</span>
`;
row.appendChild(head);
const worldLine = document.createElement("div");
worldLine.className = "planet-text";
worldLine.textContent = `${layer.worldLayer} · ${layer.worldDescription}`;
row.appendChild(worldLine);
const soulLine = document.createElement("div");
soulLine.className = "planet-text";
soulLine.textContent = `${layer.soulLayer}${layer.soulTitle}: ${layer.soulDescription}`;
row.appendChild(soulLine);
const buttonRow = [];
const hebrewLetterId = context.resolveHebrewLetterId(layer.hebrewToken);
if (hebrewLetterId) {
buttonRow.push(
createNavButton(`View ${layer.letterChar} in Alphabet`, "nav:alphabet", {
alphabet: "hebrew",
hebrewLetterId
})
);
}
const linkedPath = context.findPathByHebrewToken(tree, layer.hebrewToken);
if (linkedPath?.pathNumber != null) {
buttonRow.push(
createNavButton(`View Path ${linkedPath.pathNumber}`, "nav:kabbalah-path", { pathNo: Number(linkedPath.pathNumber) })
);
}
appendLinkRow(row, buttonRow);
if (isActive) {
row.style.borderColor = "#818cf8";
}
stack.appendChild(row);
});
card.appendChild(stack);
return card;
}
function splitCorrespondenceNames(value) {
return String(value || "")
.split(/,|;|·|\/|\bor\b|\band\b|\+/i)
.map((item) => item.trim())
.filter(Boolean);
}
function uniqueNames(values) {
const seen = new Set();
const output = [];
values.forEach((name) => {
const key = String(name || "").toLowerCase();
if (seen.has(key)) return;
seen.add(key);
output.push(name);
});
return output;
}
function godLinksCard(label, names, pathNo, metaText) {
const card = document.createElement("div");
card.className = "planet-meta-card";
const title = document.createElement("strong");
title.textContent = label;
card.appendChild(title);
if (metaText) {
const meta = document.createElement("p");
meta.className = "planet-text kab-god-meta";
meta.textContent = metaText;
card.appendChild(meta);
}
const row = document.createElement("div");
row.className = "kab-god-links";
names.forEach((name) => {
const btn = document.createElement("button");
btn.type = "button";
btn.className = "kab-god-link";
btn.textContent = name;
btn.addEventListener("click", () => {
document.dispatchEvent(new CustomEvent("nav:gods", {
detail: { godName: name, pathNo: Number(pathNo) }
}));
});
row.appendChild(btn);
});
card.appendChild(row);
return card;
}
function appendGodsCards(pathNo, elements, godsData) {
const gd = godsData?.[String(pathNo)];
if (!gd) return;
const hasAny = gd.greek || gd.roman || gd.egyptian || gd.egyptianPractical
|| gd.elohim || gd.archangel || gd.angelicOrder;
if (!hasAny) return;
const sep = document.createElement("div");
sep.className = "planet-meta-card kab-wide-card";
sep.innerHTML = `<strong style="color:#a1a1aa;font-size:11px;text-transform:uppercase;letter-spacing:.05em">Divine Correspondences</strong>`;
elements.detailBodyEl.appendChild(sep);
const greekNames = uniqueNames(splitCorrespondenceNames(gd.greek));
const romanNames = uniqueNames(splitCorrespondenceNames(gd.roman));
const egyptNames = uniqueNames([
...splitCorrespondenceNames(gd.egyptianPractical),
...splitCorrespondenceNames(gd.egyptian)
]);
if (greekNames.length) {
elements.detailBodyEl.appendChild(godLinksCard("Greek", greekNames, pathNo));
}
if (romanNames.length) {
elements.detailBodyEl.appendChild(godLinksCard("Roman", romanNames, pathNo));
}
if (egyptNames.length) {
elements.detailBodyEl.appendChild(godLinksCard("Egyptian", egyptNames, pathNo));
}
if (gd.elohim) {
const g = gd.elohim;
const meta = `${g.hebrew}${g.meaning ? " — " + g.meaning : ""}`;
elements.detailBodyEl.appendChild(godLinksCard(
"God Name",
uniqueNames(splitCorrespondenceNames(g.transliteration)),
pathNo,
meta
));
}
if (gd.archangel) {
const a = gd.archangel;
const meta = `${a.hebrew}`;
elements.detailBodyEl.appendChild(godLinksCard(
"Archangel",
uniqueNames(splitCorrespondenceNames(a.transliteration)),
pathNo,
meta
));
}
if (gd.angelicOrder) {
const o = gd.angelicOrder;
elements.detailBodyEl.appendChild(metaCard(
"Angelic Order",
`${o.hebrew} ${o.transliteration}${o.meaning ? " — " + o.meaning : ""}`
));
}
}
function renderSephiraDetail(context) {
const { seph, tree, elements } = context;
elements.detailNameEl.textContent = `${seph.number} · ${seph.name}`;
elements.detailSubEl.textContent =
[seph.nameHebrew, seph.translation, seph.planet].filter(Boolean).join(" · ");
elements.detailBodyEl.innerHTML = "";
elements.detailBodyEl.appendChild(buildFourWorldsCard(tree, "", context));
elements.detailBodyEl.appendChild(buildPlanetLuminaryCard(seph.planet, context));
elements.detailBodyEl.appendChild(metaCard("Intelligence", seph.intelligence));
elements.detailBodyEl.appendChild(buildTarotAttributionCard(seph.tarot));
if (seph.description) {
elements.detailBodyEl.appendChild(
metaCard(seph.name, seph.description, true)
);
}
const connected = tree.paths.filter(
(entry) => entry.connects.from === seph.number || entry.connects.to === seph.number
);
if (connected.length) {
const card = document.createElement("div");
card.className = "planet-meta-card kab-wide-card";
const chips = connected.map((entry) =>
`<span class="kab-chip" data-path="${entry.pathNumber}" role="button" tabindex="0" title="Path ${entry.pathNumber}: ${entry.tarot?.card || ""}">`
+ `${entry.hebrewLetter?.char || ""} <span class="kab-chip-sub">${entry.pathNumber}</span>`
+ `</span>`
).join("");
card.innerHTML = `<strong>Connected Paths</strong><div class="kab-chips">${chips}</div>`;
elements.detailBodyEl.appendChild(card);
card.querySelectorAll(".kab-chip[data-path]").forEach((chip) => {
const handler = () => {
const path = tree.paths.find((entry) => entry.pathNumber === Number(chip.dataset.path));
if (path && typeof context.onPathSelect === "function") {
context.onPathSelect(path);
}
};
chip.addEventListener("click", handler);
chip.addEventListener("keydown", (event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
handler();
}
});
});
}
appendGodsCards(seph.number, elements, context.godsData);
}
function renderPathDetail(context) {
const { path, tree, elements } = context;
const letter = path.hebrewLetter || {};
const fromName = tree.sephiroth.find((entry) => entry.number === path.connects.from)?.name || path.connects.from;
const toName = tree.sephiroth.find((entry) => entry.number === path.connects.to)?.name || path.connects.to;
const astro = path.astrology ? `${path.astrology.name} (${path.astrology.type})` : "—";
const tarotStr = path.tarot?.card
? `${path.tarot.card}${path.tarot.trumpNumber != null ? " · Trump " + path.tarot.trumpNumber : ""}`
: "—";
elements.detailNameEl.textContent =
`Path ${path.pathNumber} · ${letter.char || ""} ${letter.transliteration || ""}`;
elements.detailSubEl.textContent = [path.tarot?.card, astro].filter(Boolean).join(" · ");
elements.detailBodyEl.innerHTML = "";
elements.detailBodyEl.appendChild(buildFourWorldsCard(tree, context.activeHebrewToken, context));
elements.detailBodyEl.appendChild(buildConnectsCard(path, fromName, toName));
elements.detailBodyEl.appendChild(buildHebrewLetterCard(letter, context));
elements.detailBodyEl.appendChild(buildAstrologyCard(path.astrology, context));
const tarotMetaCard = document.createElement("div");
tarotMetaCard.className = "planet-meta-card";
const tarotLabel = document.createElement("strong");
tarotLabel.textContent = "Tarot";
tarotMetaCard.appendChild(tarotLabel);
if (path.tarot?.card && path.tarot.trumpNumber != null) {
const tarotBtn = document.createElement("button");
tarotBtn.type = "button";
tarotBtn.className = "kab-tarot-link";
tarotBtn.textContent = `${path.tarot.card} · Trump ${path.tarot.trumpNumber}`;
tarotBtn.title = "Open in Tarot section";
tarotBtn.addEventListener("click", () => {
document.dispatchEvent(new CustomEvent("kab:view-trump", {
detail: { trumpNumber: path.tarot.trumpNumber }
}));
});
tarotMetaCard.appendChild(tarotBtn);
} else {
const tarotP = document.createElement("p");
tarotP.className = "planet-text";
tarotP.textContent = tarotStr || "—";
tarotMetaCard.appendChild(tarotP);
}
elements.detailBodyEl.appendChild(tarotMetaCard);
elements.detailBodyEl.appendChild(metaCard("Intelligence", path.intelligence));
elements.detailBodyEl.appendChild(metaCard("Pillar", path.pillar));
if (path.description) {
const desc = document.createElement("div");
desc.className = "planet-meta-card kab-wide-card";
desc.innerHTML =
`<strong>Path ${path.pathNumber} — Sefer Yetzirah</strong>`
+ `<p class="planet-text">${path.description.replace(/\n/g, "<br><br>")}</p>`;
elements.detailBodyEl.appendChild(desc);
}
appendGodsCards(path.pathNumber, elements, context.godsData);
}
function renderRoseLandingIntro(roseElements) {
if (!roseElements?.detailNameEl || !roseElements?.detailSubEl || !roseElements?.detailBodyEl) {
return;
}
roseElements.detailNameEl.textContent = "Rosicrucian Cross";
roseElements.detailSubEl.textContent = "Select a Hebrew letter petal to explore a Tree path";
const introCard = document.createElement("div");
introCard.className = "planet-meta-card kab-wide-card";
introCard.innerHTML = "<strong>Interactive Path Crosswalk</strong>"
+ "<p class=\"planet-text\">Each petal maps to one of the 22 Hebrew letter paths (11-32). Click any large Hebrew letter to view astrology, tarot, and path intelligence details.</p>";
roseElements.detailBodyEl.innerHTML = "";
roseElements.detailBodyEl.appendChild(introCard);
}
window.KabbalahDetailUi = {
renderSephiraDetail,
renderPathDetail,
renderRoseLandingIntro
};
})();