Initial commit
This commit is contained in:
654
app/card-images.js
Normal file
654
app/card-images.js
Normal file
@@ -0,0 +1,654 @@
|
||||
(function () {
|
||||
const DEFAULT_DECK_ID = "ceremonial-magick";
|
||||
|
||||
const trumpNumberByCanonicalName = {
|
||||
fool: 0,
|
||||
magus: 1,
|
||||
magician: 1,
|
||||
"high priestess": 2,
|
||||
empress: 3,
|
||||
emperor: 4,
|
||||
hierophant: 5,
|
||||
lovers: 6,
|
||||
chariot: 7,
|
||||
lust: 8,
|
||||
strength: 8,
|
||||
hermit: 9,
|
||||
fortune: 10,
|
||||
"wheel of fortune": 10,
|
||||
justice: 11,
|
||||
"hanged man": 12,
|
||||
death: 13,
|
||||
art: 14,
|
||||
temperance: 14,
|
||||
devil: 15,
|
||||
tower: 16,
|
||||
star: 17,
|
||||
moon: 18,
|
||||
sun: 19,
|
||||
aeon: 20,
|
||||
judgement: 20,
|
||||
judgment: 20,
|
||||
universe: 21,
|
||||
world: 21
|
||||
};
|
||||
|
||||
const pipValueByToken = {
|
||||
ace: 1,
|
||||
two: 2,
|
||||
three: 3,
|
||||
four: 4,
|
||||
five: 5,
|
||||
six: 6,
|
||||
seven: 7,
|
||||
eight: 8,
|
||||
nine: 9,
|
||||
ten: 10,
|
||||
"2": 2,
|
||||
"3": 3,
|
||||
"4": 4,
|
||||
"5": 5,
|
||||
"6": 6,
|
||||
"7": 7,
|
||||
"8": 8,
|
||||
"9": 9,
|
||||
"10": 10
|
||||
};
|
||||
|
||||
const rankWordByPipValue = {
|
||||
1: "Ace",
|
||||
2: "Two",
|
||||
3: "Three",
|
||||
4: "Four",
|
||||
5: "Five",
|
||||
6: "Six",
|
||||
7: "Seven",
|
||||
8: "Eight",
|
||||
9: "Nine",
|
||||
10: "Ten"
|
||||
};
|
||||
|
||||
const trumpRomanToNumber = {
|
||||
I: 1,
|
||||
II: 2,
|
||||
III: 3,
|
||||
IV: 4,
|
||||
V: 5,
|
||||
VI: 6,
|
||||
VII: 7,
|
||||
VIII: 8,
|
||||
IX: 9,
|
||||
X: 10,
|
||||
XI: 11,
|
||||
XII: 12,
|
||||
XIII: 13,
|
||||
XIV: 14,
|
||||
XV: 15,
|
||||
XVI: 16,
|
||||
XVII: 17,
|
||||
XVIII: 18,
|
||||
XIX: 19,
|
||||
XX: 20,
|
||||
XXI: 21
|
||||
};
|
||||
|
||||
const suitSearchAliasesById = {
|
||||
wands: ["wands"],
|
||||
cups: ["cups"],
|
||||
swords: ["swords"],
|
||||
disks: ["disks", "pentacles", "coins"]
|
||||
};
|
||||
|
||||
const DECK_REGISTRY_PATH = "asset/tarot deck/decks.json";
|
||||
|
||||
const deckManifestSources = buildDeckManifestSources();
|
||||
|
||||
const manifestCache = new Map();
|
||||
let activeDeckId = DEFAULT_DECK_ID;
|
||||
|
||||
function canonicalMajorName(cardName) {
|
||||
return String(cardName || "")
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/^the\s+/, "")
|
||||
.replace(/\s+/g, " ");
|
||||
}
|
||||
|
||||
function canonicalMinorName(cardName) {
|
||||
const parsedMinor = parseMinorCard(cardName);
|
||||
if (!parsedMinor) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return `${String(parsedMinor.rankKey || "").trim().toLowerCase()} of ${parsedMinor.suitId}`;
|
||||
}
|
||||
|
||||
function toTitleCase(value) {
|
||||
const normalized = String(value || "").trim().toLowerCase();
|
||||
if (!normalized) {
|
||||
return "";
|
||||
}
|
||||
return normalized.charAt(0).toUpperCase() + normalized.slice(1);
|
||||
}
|
||||
|
||||
function normalizeDeckId(deckId) {
|
||||
const normalized = String(deckId || "").trim().toLowerCase();
|
||||
if (deckManifestSources[normalized]) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
if (deckManifestSources[DEFAULT_DECK_ID]) {
|
||||
return DEFAULT_DECK_ID;
|
||||
}
|
||||
|
||||
const fallbackId = Object.keys(deckManifestSources)[0];
|
||||
return fallbackId || DEFAULT_DECK_ID;
|
||||
}
|
||||
|
||||
function normalizeTrumpNumber(value) {
|
||||
const parsed = Number(value);
|
||||
if (!Number.isInteger(parsed) || parsed < 0 || parsed > 21) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function parseTrumpNumberKey(value) {
|
||||
const normalized = String(value || "").trim().toUpperCase();
|
||||
if (!normalized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (/^\d+$/.test(normalized)) {
|
||||
return normalizeTrumpNumber(Number(normalized));
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(trumpRomanToNumber, normalized)) {
|
||||
return normalizeTrumpNumber(trumpRomanToNumber[normalized]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function normalizeSuitId(suitInput) {
|
||||
const suit = String(suitInput || "").trim().toLowerCase();
|
||||
if (suit === "pentacles") {
|
||||
return "disks";
|
||||
}
|
||||
return suit;
|
||||
}
|
||||
|
||||
function resolveDeckOptions(optionsOrDeckId) {
|
||||
let resolvedDeckId = activeDeckId;
|
||||
let trumpNumber = null;
|
||||
|
||||
if (typeof optionsOrDeckId === "string") {
|
||||
resolvedDeckId = normalizeDeckId(optionsOrDeckId);
|
||||
} else if (optionsOrDeckId && typeof optionsOrDeckId === "object") {
|
||||
if (optionsOrDeckId.deckId) {
|
||||
resolvedDeckId = normalizeDeckId(optionsOrDeckId.deckId);
|
||||
}
|
||||
trumpNumber = normalizeTrumpNumber(optionsOrDeckId.trumpNumber);
|
||||
}
|
||||
|
||||
return { resolvedDeckId, trumpNumber };
|
||||
}
|
||||
|
||||
function parseMinorCard(cardName) {
|
||||
const match = String(cardName || "")
|
||||
.trim()
|
||||
.match(/^(ace|two|three|four|five|six|seven|eight|nine|ten|knight|queen|prince|princess|king|page|[2-9]|10)\s+of\s+(cups|wands|swords|pentacles|disks)$/i);
|
||||
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rankToken = String(match[1] || "").toLowerCase();
|
||||
const suitId = normalizeSuitId(match[2]);
|
||||
const pipValue = pipValueByToken[rankToken] ?? null;
|
||||
|
||||
if (Number.isFinite(pipValue)) {
|
||||
const rankWord = rankWordByPipValue[pipValue] || "";
|
||||
return {
|
||||
suitId,
|
||||
pipValue,
|
||||
court: "",
|
||||
rankWord,
|
||||
rankKey: rankWord.toLowerCase()
|
||||
};
|
||||
}
|
||||
|
||||
const courtWord = toTitleCase(rankToken);
|
||||
if (!courtWord) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
suitId,
|
||||
pipValue: null,
|
||||
court: rankToken,
|
||||
rankWord: courtWord,
|
||||
rankKey: rankToken
|
||||
};
|
||||
}
|
||||
|
||||
function applyTemplate(template, variables) {
|
||||
return String(template || "")
|
||||
.replace(/\{([a-zA-Z0-9_]+)\}/g, (_, token) => {
|
||||
const value = variables[token];
|
||||
return value == null ? "" : String(value);
|
||||
});
|
||||
}
|
||||
|
||||
function readManifestJsonSync(path) {
|
||||
try {
|
||||
const request = new XMLHttpRequest();
|
||||
request.open("GET", encodeURI(path), false);
|
||||
request.send(null);
|
||||
|
||||
const okStatus = (request.status >= 200 && request.status < 300) || request.status === 0;
|
||||
if (!okStatus || !request.responseText) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return JSON.parse(request.responseText);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function toDeckSourceMap(sourceList) {
|
||||
const sourceMap = {};
|
||||
if (!Array.isArray(sourceList)) {
|
||||
return sourceMap;
|
||||
}
|
||||
|
||||
sourceList.forEach((entry) => {
|
||||
const id = String(entry?.id || "").trim().toLowerCase();
|
||||
const basePath = String(entry?.basePath || "").trim().replace(/\/$/, "");
|
||||
const manifestPath = String(entry?.manifestPath || "").trim();
|
||||
if (!id || !basePath || !manifestPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
sourceMap[id] = {
|
||||
id,
|
||||
label: String(entry?.label || id),
|
||||
basePath,
|
||||
manifestPath
|
||||
};
|
||||
});
|
||||
|
||||
return sourceMap;
|
||||
}
|
||||
|
||||
function buildDeckManifestSources() {
|
||||
const registry = readManifestJsonSync(DECK_REGISTRY_PATH);
|
||||
const registryDecks = Array.isArray(registry)
|
||||
? registry
|
||||
: (Array.isArray(registry?.decks) ? registry.decks : null);
|
||||
|
||||
return toDeckSourceMap(registryDecks);
|
||||
}
|
||||
|
||||
function normalizeDeckManifest(source, rawManifest) {
|
||||
if (!rawManifest || typeof rawManifest !== "object") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rawNameOverrides = rawManifest.nameOverrides;
|
||||
const nameOverrides = {};
|
||||
if (rawNameOverrides && typeof rawNameOverrides === "object") {
|
||||
Object.entries(rawNameOverrides).forEach(([rawKey, rawValue]) => {
|
||||
const key = canonicalMajorName(rawKey);
|
||||
const value = String(rawValue || "").trim();
|
||||
if (key && value) {
|
||||
nameOverrides[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const rawMajorNameOverridesByTrump = rawManifest.majorNameOverridesByTrump;
|
||||
const majorNameOverridesByTrump = {};
|
||||
if (rawMajorNameOverridesByTrump && typeof rawMajorNameOverridesByTrump === "object") {
|
||||
Object.entries(rawMajorNameOverridesByTrump).forEach(([rawKey, rawValue]) => {
|
||||
const trumpNumber = parseTrumpNumberKey(rawKey);
|
||||
const value = String(rawValue || "").trim();
|
||||
if (Number.isInteger(trumpNumber) && value) {
|
||||
majorNameOverridesByTrump[trumpNumber] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const rawMinorNameOverrides = rawManifest.minorNameOverrides;
|
||||
const minorNameOverrides = {};
|
||||
if (rawMinorNameOverrides && typeof rawMinorNameOverrides === "object") {
|
||||
Object.entries(rawMinorNameOverrides).forEach(([rawKey, rawValue]) => {
|
||||
const key = canonicalMinorName(rawKey);
|
||||
const value = String(rawValue || "").trim();
|
||||
if (key && value) {
|
||||
minorNameOverrides[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
id: source.id,
|
||||
label: String(rawManifest.label || source.label || source.id),
|
||||
basePath: String(source.basePath || "").replace(/\/$/, ""),
|
||||
majors: rawManifest.majors || {},
|
||||
minors: rawManifest.minors || {},
|
||||
nameOverrides,
|
||||
minorNameOverrides,
|
||||
majorNameOverridesByTrump
|
||||
};
|
||||
}
|
||||
|
||||
function getDeckManifest(deckId) {
|
||||
const normalizedDeckId = normalizeDeckId(deckId);
|
||||
if (manifestCache.has(normalizedDeckId)) {
|
||||
return manifestCache.get(normalizedDeckId);
|
||||
}
|
||||
|
||||
const source = deckManifestSources[normalizedDeckId];
|
||||
if (!source) {
|
||||
manifestCache.set(normalizedDeckId, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
const rawManifest = readManifestJsonSync(source.manifestPath);
|
||||
const normalizedManifest = normalizeDeckManifest(source, rawManifest);
|
||||
manifestCache.set(normalizedDeckId, normalizedManifest);
|
||||
return normalizedManifest;
|
||||
}
|
||||
|
||||
function getRankIndex(minorRule, parsedMinor) {
|
||||
if (!minorRule || !parsedMinor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const lowerRankWord = String(parsedMinor.rankWord || "").toLowerCase();
|
||||
const lowerRankKey = String(parsedMinor.rankKey || "").toLowerCase();
|
||||
|
||||
const indexByKey = minorRule.rankIndexByKey;
|
||||
if (indexByKey && typeof indexByKey === "object") {
|
||||
const mapped = Number(indexByKey[lowerRankKey]);
|
||||
if (Number.isInteger(mapped) && mapped >= 0) {
|
||||
return mapped;
|
||||
}
|
||||
}
|
||||
|
||||
const rankOrder = Array.isArray(minorRule.rankOrder) ? minorRule.rankOrder : [];
|
||||
for (let i = 0; i < rankOrder.length; i += 1) {
|
||||
const candidate = String(rankOrder[i] || "").toLowerCase();
|
||||
if (candidate && (candidate === lowerRankWord || candidate === lowerRankKey)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveMajorFile(manifest, canonicalName) {
|
||||
const majorRule = manifest?.majors;
|
||||
if (!majorRule || typeof majorRule !== "object") {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (majorRule.mode === "canonical-map") {
|
||||
const cards = majorRule.cards || {};
|
||||
const fileName = cards[canonicalName];
|
||||
return typeof fileName === "string" && fileName ? fileName : null;
|
||||
}
|
||||
|
||||
const trumpNo = trumpNumberByCanonicalName[canonicalName];
|
||||
if (!Number.isInteger(trumpNo) || trumpNo < 0 || trumpNo > 21) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (majorRule.mode === "trump-map") {
|
||||
const cards = majorRule.cards || {};
|
||||
const fileName = cards[String(trumpNo)] ?? cards[trumpNo];
|
||||
return typeof fileName === "string" && fileName ? fileName : null;
|
||||
}
|
||||
|
||||
if (majorRule.mode === "trump-template") {
|
||||
const numberPad = Number.isInteger(majorRule.numberPad) ? majorRule.numberPad : 2;
|
||||
const template = String(majorRule.template || "{number}.png");
|
||||
const number = String(trumpNo).padStart(numberPad, "0");
|
||||
return applyTemplate(template, {
|
||||
trump: trumpNo,
|
||||
number
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveMinorFile(manifest, parsedMinor) {
|
||||
const minorRule = manifest?.minors;
|
||||
if (!minorRule || typeof minorRule !== "object") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rankIndex = getRankIndex(minorRule, parsedMinor);
|
||||
if (!Number.isInteger(rankIndex) || rankIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (minorRule.mode === "suit-base-and-rank-order") {
|
||||
const suitBaseRaw = Number(minorRule?.suitBase?.[parsedMinor.suitId]);
|
||||
if (!Number.isFinite(suitBaseRaw)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const numberPad = Number.isInteger(minorRule.numberPad) ? minorRule.numberPad : 2;
|
||||
const cardNumber = String(suitBaseRaw + rankIndex).padStart(numberPad, "0");
|
||||
const suitWord = String(minorRule?.suitLabel?.[parsedMinor.suitId] || toTitleCase(parsedMinor.suitId));
|
||||
const template = String(minorRule.template || "{number}_{rank} {suit}.webp");
|
||||
|
||||
return applyTemplate(template, {
|
||||
number: cardNumber,
|
||||
rank: parsedMinor.rankWord,
|
||||
rankKey: parsedMinor.rankKey,
|
||||
suit: suitWord,
|
||||
suitId: parsedMinor.suitId,
|
||||
index: rankIndex + 1
|
||||
});
|
||||
}
|
||||
|
||||
if (minorRule.mode === "suit-prefix-and-rank-order") {
|
||||
const suitPrefix = minorRule?.suitPrefix?.[parsedMinor.suitId];
|
||||
if (!suitPrefix) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const indexStart = Number.isInteger(minorRule.indexStart) ? minorRule.indexStart : 1;
|
||||
const indexPad = Number.isInteger(minorRule.indexPad) ? minorRule.indexPad : 2;
|
||||
const suitIndex = String(indexStart + rankIndex).padStart(indexPad, "0");
|
||||
const template = String(minorRule.template || "{suit}{index}.png");
|
||||
|
||||
return applyTemplate(template, {
|
||||
suit: suitPrefix,
|
||||
suitId: parsedMinor.suitId,
|
||||
index: suitIndex,
|
||||
rank: parsedMinor.rankWord,
|
||||
rankKey: parsedMinor.rankKey
|
||||
});
|
||||
}
|
||||
|
||||
if (minorRule.mode === "suit-base-number-template") {
|
||||
const suitBaseRaw = Number(minorRule?.suitBase?.[parsedMinor.suitId]);
|
||||
if (!Number.isFinite(suitBaseRaw)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const numberPad = Number.isInteger(minorRule.numberPad) ? minorRule.numberPad : 2;
|
||||
const cardNumber = String(suitBaseRaw + rankIndex).padStart(numberPad, "0");
|
||||
const template = String(minorRule.template || "{number}.png");
|
||||
|
||||
return applyTemplate(template, {
|
||||
number: cardNumber,
|
||||
suitId: parsedMinor.suitId,
|
||||
rank: parsedMinor.rankWord,
|
||||
rankKey: parsedMinor.rankKey,
|
||||
index: rankIndex
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveWithDeck(deckId, cardName) {
|
||||
const manifest = getDeckManifest(deckId);
|
||||
if (!manifest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const canonical = canonicalMajorName(cardName);
|
||||
const majorFile = resolveMajorFile(manifest, canonical);
|
||||
if (majorFile) {
|
||||
return `${manifest.basePath}/${majorFile}`;
|
||||
}
|
||||
|
||||
const parsedMinor = parseMinorCard(cardName);
|
||||
if (!parsedMinor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const minorFile = resolveMinorFile(manifest, parsedMinor);
|
||||
if (!minorFile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return `${manifest.basePath}/${minorFile}`;
|
||||
}
|
||||
|
||||
function resolveTarotCardImage(cardName) {
|
||||
const activePath = resolveWithDeck(activeDeckId, cardName);
|
||||
if (activePath) {
|
||||
return encodeURI(activePath);
|
||||
}
|
||||
|
||||
if (activeDeckId !== DEFAULT_DECK_ID) {
|
||||
const fallbackPath = resolveWithDeck(DEFAULT_DECK_ID, cardName);
|
||||
if (fallbackPath) {
|
||||
return encodeURI(fallbackPath);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveDisplayNameWithDeck(deckId, cardName, trumpNumber) {
|
||||
const manifest = getDeckManifest(deckId);
|
||||
const fallbackName = String(cardName || "").trim();
|
||||
if (!manifest) {
|
||||
return fallbackName;
|
||||
}
|
||||
|
||||
let resolvedTrumpNumber = normalizeTrumpNumber(trumpNumber);
|
||||
if (!Number.isInteger(resolvedTrumpNumber)) {
|
||||
const canonical = canonicalMajorName(cardName);
|
||||
resolvedTrumpNumber = normalizeTrumpNumber(trumpNumberByCanonicalName[canonical]);
|
||||
}
|
||||
|
||||
if (Number.isInteger(resolvedTrumpNumber)) {
|
||||
const byTrump = manifest?.majorNameOverridesByTrump?.[resolvedTrumpNumber];
|
||||
if (byTrump) {
|
||||
return byTrump;
|
||||
}
|
||||
}
|
||||
|
||||
const canonical = canonicalMajorName(cardName);
|
||||
const override = manifest?.nameOverrides?.[canonical];
|
||||
if (override) {
|
||||
return override;
|
||||
}
|
||||
|
||||
const minorKey = canonicalMinorName(cardName);
|
||||
const minorOverride = manifest?.minorNameOverrides?.[minorKey];
|
||||
if (minorOverride) {
|
||||
return minorOverride;
|
||||
}
|
||||
|
||||
return fallbackName;
|
||||
}
|
||||
|
||||
function getTarotCardSearchAliases(cardName, optionsOrDeckId) {
|
||||
const fallbackName = String(cardName || "").trim();
|
||||
if (!fallbackName) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const { resolvedDeckId, trumpNumber } = resolveDeckOptions(optionsOrDeckId);
|
||||
const aliases = new Set();
|
||||
aliases.add(fallbackName);
|
||||
|
||||
const displayName = String(resolveDisplayNameWithDeck(resolvedDeckId, fallbackName, trumpNumber) || "").trim();
|
||||
if (displayName) {
|
||||
aliases.add(displayName);
|
||||
}
|
||||
|
||||
const canonicalMajor = canonicalMajorName(fallbackName);
|
||||
const resolvedTrumpNumber = Number.isInteger(normalizeTrumpNumber(trumpNumber))
|
||||
? normalizeTrumpNumber(trumpNumber)
|
||||
: normalizeTrumpNumber(trumpNumberByCanonicalName[canonicalMajor]);
|
||||
|
||||
if (Number.isInteger(resolvedTrumpNumber)) {
|
||||
aliases.add(canonicalMajor);
|
||||
aliases.add(`the ${canonicalMajor}`);
|
||||
aliases.add(`trump ${resolvedTrumpNumber}`);
|
||||
}
|
||||
|
||||
const parsedMinor = parseMinorCard(fallbackName);
|
||||
if (parsedMinor) {
|
||||
const suitAliases = suitSearchAliasesById[parsedMinor.suitId] || [parsedMinor.suitId];
|
||||
suitAliases.forEach((suitAlias) => {
|
||||
aliases.add(`${parsedMinor.rankKey} of ${suitAlias}`);
|
||||
if (Number.isInteger(parsedMinor.pipValue)) {
|
||||
aliases.add(`${parsedMinor.pipValue} of ${suitAlias}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Array.from(aliases);
|
||||
}
|
||||
|
||||
function getTarotCardDisplayName(cardName, optionsOrDeckId) {
|
||||
const { resolvedDeckId, trumpNumber } = resolveDeckOptions(optionsOrDeckId);
|
||||
|
||||
return resolveDisplayNameWithDeck(resolvedDeckId, cardName, trumpNumber);
|
||||
}
|
||||
|
||||
function setActiveDeck(deckId) {
|
||||
activeDeckId = normalizeDeckId(deckId);
|
||||
getDeckManifest(activeDeckId);
|
||||
return activeDeckId;
|
||||
}
|
||||
|
||||
function getDeckOptions() {
|
||||
return Object.values(deckManifestSources).map((source) => {
|
||||
const manifest = getDeckManifest(source.id);
|
||||
return {
|
||||
id: source.id,
|
||||
label: manifest?.label || source.label
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("settings:updated", (event) => {
|
||||
const nextDeck = event?.detail?.settings?.tarotDeck;
|
||||
setActiveDeck(nextDeck);
|
||||
});
|
||||
|
||||
window.TarotCardImages = {
|
||||
resolveTarotCardImage,
|
||||
getTarotCardDisplayName,
|
||||
getTarotCardSearchAliases,
|
||||
setActiveDeck,
|
||||
getDeckOptions,
|
||||
getActiveDeck: () => activeDeckId
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user