update to frame and tarot times

This commit is contained in:
2026-04-02 22:06:19 -07:00
parent e5d041101f
commit cac243f2cf
9 changed files with 394 additions and 44 deletions

View File

@@ -20,6 +20,152 @@
findSephirahForMinorCard
} = dependencies || {};
function buildDecanRelationKey(signId, decanIndex) {
const normalizedSignId = String(signId || "").trim().toLowerCase();
const normalizedIndex = Number(decanIndex);
if (!normalizedSignId || !Number.isFinite(normalizedIndex)) {
return "";
}
return `${normalizedSignId}-${normalizedIndex}`;
}
function buildSignRelationKey(signId) {
return String(signId || "").trim().toLowerCase();
}
function buildDecanSummaryRelations(relations) {
const decanRelations = (relations || []).filter((relation) => relation?.type === "decan");
const signWindowRelations = (relations || []).filter((relation) => relation?.type === "signWindow");
if (!decanRelations.length && !signWindowRelations.length) {
return [];
}
function normalizeInlineDateRange(value) {
return String(value || "")
.replace(/[–—]/g, " - ")
.replace(/\s*-\s*/g, " - ")
.replace(/\s+/g, " ")
.trim();
}
const rulerByDecanKey = new Map();
const cardByDecanKey = new Map();
const cardsBySignKey = new Map();
(relations || []).forEach((relation) => {
if (relation?.type === "decanRuler") {
const key = buildDecanRelationKey(relation?.data?.signId, relation?.data?.decanIndex);
if (key && !rulerByDecanKey.has(key)) {
rulerByDecanKey.set(key, relation);
}
}
if (relation?.type === "tarotCard") {
const decanKey = buildDecanRelationKey(relation?.data?.signId, relation?.data?.decanIndex);
if (decanKey && !cardByDecanKey.has(decanKey)) {
cardByDecanKey.set(decanKey, relation);
return;
}
const signKey = buildSignRelationKey(relation?.data?.signId);
if (!signKey) {
return;
}
const entries = cardsBySignKey.get(signKey) || [];
entries.push(relation);
cardsBySignKey.set(signKey, entries);
}
});
const decanSummaries = decanRelations.map((relation) => {
const signId = relation?.data?.signId;
const signName = String(relation?.data?.signName || "").trim();
const signSymbol = String(relation?.data?.signSymbol || relation?.data?.symbol || "").trim();
const decanIndex = Number(relation?.data?.index);
const startDegree = Number(relation?.data?.startDegree);
const endDegree = Number(relation?.data?.endDegree);
const dateRange = String(relation?.data?.dateRange || "").trim();
const decanKey = buildDecanRelationKey(signId, decanIndex);
const rulerRelation = rulerByDecanKey.get(decanKey) || null;
const cardRelation = cardByDecanKey.get(decanKey) || null;
const rulerSymbol = String(rulerRelation?.data?.symbol || "").trim();
const rulerName = String(rulerRelation?.data?.name || "").trim();
const rulerLabel = `${rulerSymbol} ${rulerName}`.replace(/\s+/g, " ").trim();
const decanCardName = String(cardRelation?.data?.cardName || "").trim();
const decanCardLabel = decanCardName
? String(getDisplayCardName?.(decanCardName) || decanCardName).trim()
: "";
const signLabel = `${signSymbol} ${signName}`.replace(/\s+/g, " ").trim();
const degreeLabel = Number.isFinite(startDegree) && Number.isFinite(endDegree)
? `(${startDegree}°-${endDegree}°)`
: "";
const dateLabel = normalizeInlineDateRange(dateRange);
const summaryParts = [
rulerLabel,
decanCardLabel,
[signLabel, degreeLabel].filter(Boolean).join(" ").trim(),
dateLabel
].filter(Boolean);
return {
type: decanCardName ? "tarotCard" : "decan",
id: cardRelation?.id || `${decanKey}-summary`,
label: summaryParts.join(": "),
data: {
...(cardRelation?.data || relation?.data || {}),
signId,
signName,
signSymbol,
decanIndex,
dateRange,
cardName: decanCardName || cardRelation?.data?.cardName || ""
},
__key: `decanSummary|${decanKey}|${cardRelation?.data?.cardName || ""}`
};
});
const signSummaries = signWindowRelations.map((relation) => {
const signId = relation?.data?.signId;
const signKey = buildSignRelationKey(signId);
const signName = String(relation?.data?.signName || "").trim();
const signSymbol = String(relation?.data?.signSymbol || relation?.data?.symbol || "").trim();
const startDegree = Number(relation?.data?.startDegree);
const endDegree = Number(relation?.data?.endDegree);
const dateRange = String(relation?.data?.dateRange || "").trim();
const cardLabels = [...new Set((cardsBySignKey.get(signKey) || [])
.map((entry) => String(getDisplayCardName?.(entry?.data?.cardName) || entry?.data?.cardName || "").trim())
.filter(Boolean))];
const signLabel = `${signSymbol} ${signName}`.replace(/\s+/g, " ").trim();
const degreeLabel = Number.isFinite(startDegree) && Number.isFinite(endDegree)
? `(${startDegree}°-${endDegree}°)`
: "";
const dateLabel = normalizeInlineDateRange(dateRange);
const summaryParts = [
cardLabels.join(", "),
[signLabel, degreeLabel].filter(Boolean).join(" ").trim(),
dateLabel
].filter(Boolean);
return {
type: "signWindow",
id: relation?.id || `${signKey}-summary`,
label: summaryParts.join(": "),
data: {
...(relation?.data || {}),
signId,
signName,
signSymbol,
cardNames: cardLabels
},
__key: `signSummary|${signKey}`
};
});
return [...decanSummaries, ...signSummaries];
}
function renderStaticRelationGroup(targetEl, cardEl, relations) {
clearChildren(targetEl);
if (!targetEl || !cardEl) return;
@@ -48,12 +194,20 @@
return true;
});
const decanSummaryRelations = buildDecanSummaryRelations(dedupedRelations);
const hasDecanSummaryRelations = decanSummaryRelations.length > 0;
const hasSignWindowRelations = decanSummaryRelations.some((relation) => relation?.type === "signWindow");
const planetRelations = dedupedRelations.filter((relation) =>
relation.type === "planetCorrespondence" || relation.type === "decanRuler" || relation.type === "planet"
relation.type === "planetCorrespondence"
|| relation.type === "planet"
|| (!hasDecanSummaryRelations && relation.type === "decanRuler")
);
const zodiacRelations = dedupedRelations.filter((relation) =>
relation.type === "zodiacCorrespondence" || relation.type === "zodiac" || relation.type === "decan"
relation.type === "zodiacCorrespondence"
|| relation.type === "zodiac"
|| (!hasDecanSummaryRelations && relation.type === "decan")
);
const courtDateRelations = dedupedRelations.filter((relation) => relation.type === "courtDateWindow");
@@ -63,9 +217,9 @@
const elementRelations = buildElementRelationsForCard(card, baseElementRelations);
const tetragrammatonRelations = buildTetragrammatonRelationsForCard(card);
const smallCardRulershipRelation = buildSmallCardRulershipRelation(card);
const zodiacRelationsWithRulership = smallCardRulershipRelation
? [...zodiacRelations, smallCardRulershipRelation]
: zodiacRelations;
const zodiacRelationsWithRulership = hasDecanSummaryRelations
? [...decanSummaryRelations, ...(smallCardRulershipRelation ? [smallCardRulershipRelation] : [])]
: [...zodiacRelations, ...(smallCardRulershipRelation ? [smallCardRulershipRelation] : [])];
const smallCardCourtLinkRelations = buildSmallCardCourtLinkRelations(card, dedupedRelations);
const mergedCourtDateRelations = [...courtDateRelations, ...smallCardCourtLinkRelations];
const cubeRelations = buildCubeRelationsForCard(card);
@@ -166,6 +320,8 @@
elementRelations,
tetragrammatonRelations,
zodiacRelationsWithRulership,
hasDecanSummaryRelations,
hasSignWindowRelations,
mergedCourtDateRelations,
hebrewRelations,
cubeRelations,
@@ -183,7 +339,10 @@
const groups = [
{ title: "Letter", relations: detailRelations.hebrewRelations },
{ title: "Planet / Ruler", relations: detailRelations.planetRelations },
{ title: "Sign / Decan", relations: detailRelations.zodiacRelationsWithRulership },
{
title: detailRelations.hasSignWindowRelations ? "Signs" : (detailRelations.hasDecanSummaryRelations ? "Decan" : "Sign / Decan"),
relations: detailRelations.zodiacRelationsWithRulership
},
{ title: "Element", relations: detailRelations.elementRelations },
{ title: "Tetragrammaton", relations: detailRelations.tetragrammatonRelations },
{ title: "Dates", relations: detailRelations.mergedCourtDateRelations },