feat: vampire UI infrastructure - mode bar, tab row, and blood-red theme

- Added vampire API client functions (boss challenge, siring, awakening, upgrades, craft, explore)
- Fixed goddess API client URL bugs (/goddess/* → /goddess-boss/challenge, /goddess-upgrade/buy, /goddess-craft, /goddess-explore/*)
- Added VampireTab type and vampireTabs array (11 tabs) to GameLayout
- Fixed mode unlock chain: vampire after apotheosis, goddess after eternalSovereignty
- Added body.vampire-mode CSS class toggle alongside existing goddess-mode toggle
- Added vampire tab bar nav with blood-red theme
- Replaced single vampire placeholder with per-tab placeholders
- Added body.vampire-mode CSS variables (blood-red palette) and .vampire-tab-bar styles
- Added Blood/Ichor/Soul Shards resource display to ResourceBar (gated on apotheosis)
This commit is contained in:
2026-04-16 10:03:14 -07:00
committed by Naomi Carrigan
parent 8fa5d12f05
commit d9d1228172
4 changed files with 392 additions and 39 deletions
+179 -15
View File
@@ -10,8 +10,12 @@ import type {
ApotheosisRequest,
ApotheosisResponse,
AuthResponse,
AwakeningRequest,
AwakeningResponse,
BossChallengeRequest,
BossChallengeResponse,
BuyAwakeningUpgradeRequest,
BuyAwakeningUpgradeResponse,
BuyConsecrationUpgradeRequest,
BuyConsecrationUpgradeResponse,
BuyEchoUpgradeRequest,
@@ -22,6 +26,10 @@ import type {
BuyGoddessUpgradeResponse,
BuyPrestigeUpgradeRequest,
BuyPrestigeUpgradeResponse,
BuySiringUpgradeRequest,
BuySiringUpgradeResponse,
BuyVampireUpgradeRequest,
BuyVampireUpgradeResponse,
ConsecrationRequest,
ConsecrationResponse,
CraftRecipeRequest,
@@ -49,11 +57,22 @@ import type {
PublicProfileResponse,
SaveRequest,
SaveResponse,
SiringRequest,
SiringResponse,
SyncNewContentResponse,
TranscendenceRequest,
TranscendenceResponse,
UpdateProfileRequest,
UpdateProfileResponse,
VampireBossChallengeRequest,
VampireBossChallengeResponse,
VampireCraftRequest,
VampireCraftResponse,
VampireExploreClaimableResponse,
VampireExploreCollectRequest,
VampireExploreCollectResponse,
VampireExploreStartRequest,
VampireExploreStartResponse,
} from "@elysium/types";
const baseUrl = "/api";
@@ -356,10 +375,10 @@ const debugHardReset = async(): Promise<LoadResponse> => {
const challengeGoddessBoss = async(
body: GoddessBossChallengeRequest,
): Promise<GoddessBossChallengeResponse> => {
return await fetchJson<GoddessBossChallengeResponse>("/goddess/boss", {
body: JSON.stringify(body),
method: "POST",
});
return await fetchJson<GoddessBossChallengeResponse>(
"/goddess-boss/challenge",
{ body: JSON.stringify(body), method: "POST" },
);
};
/**
@@ -426,7 +445,7 @@ const buyEnlightenmentUpgrade = async(
const buyGoddessUpgrade = async(
body: BuyGoddessUpgradeRequest,
): Promise<BuyGoddessUpgradeResponse> => {
return await fetchJson<BuyGoddessUpgradeResponse>("/goddess/upgrade", {
return await fetchJson<BuyGoddessUpgradeResponse>("/goddess-upgrade/buy", {
body: JSON.stringify(body),
method: "POST",
});
@@ -440,7 +459,7 @@ const buyGoddessUpgrade = async(
const craftGoddessRecipe = async(
body: GoddessCraftRequest,
): Promise<GoddessCraftResponse> => {
return await fetchJson<GoddessCraftResponse>("/goddess/craft", {
return await fetchJson<GoddessCraftResponse>("/goddess-craft", {
body: JSON.stringify(body),
method: "POST",
});
@@ -454,10 +473,10 @@ const craftGoddessRecipe = async(
const startGoddessExploration = async(
body: GoddessExploreStartRequest,
): Promise<GoddessExploreStartResponse> => {
return await fetchJson<GoddessExploreStartResponse>("/goddess/explore", {
body: JSON.stringify(body),
method: "POST",
});
return await fetchJson<GoddessExploreStartResponse>(
"/goddess-explore/start",
{ body: JSON.stringify(body), method: "POST" },
);
};
/**
@@ -468,10 +487,10 @@ const startGoddessExploration = async(
const collectGoddessExploration = async(
body: GoddessExploreCollectRequest,
): Promise<GoddessExploreCollectResponse> => {
return await fetchJson<GoddessExploreCollectResponse>("/goddess/explore", {
body: JSON.stringify(body),
method: "PUT",
});
return await fetchJson<GoddessExploreCollectResponse>(
"/goddess-explore/collect",
{ body: JSON.stringify(body), method: "PUT" },
);
};
/**
@@ -483,7 +502,142 @@ const checkGoddessExplorationClaimable = async(
areaId: string,
): Promise<GoddessExploreClaimableResponse> => {
return await fetchJson<GoddessExploreClaimableResponse>(
`/goddess/explore/claimable?areaId=${encodeURIComponent(areaId)}`,
`/goddess-explore/claimable?areaId=${encodeURIComponent(areaId)}`,
);
};
/**
* Challenges a vampire boss.
* @param body - The vampire boss challenge request payload.
* @returns The vampire boss challenge response data.
*/
const challengeVampireBoss = async(
body: VampireBossChallengeRequest,
): Promise<VampireBossChallengeResponse> => {
return await fetchJson<VampireBossChallengeResponse>(
"/vampire-boss/challenge",
{ body: JSON.stringify(body), method: "POST" },
);
};
/**
* Triggers a siring reset on the server.
* @param body - The siring request payload.
* @returns The siring response data.
*/
const sire = async(body: SiringRequest): Promise<SiringResponse> => {
return await fetchJson<SiringResponse>("/siring", {
body: JSON.stringify(body),
method: "POST",
});
};
/**
* Purchases a siring upgrade on the server.
* @param body - The buy siring upgrade request payload.
* @returns The buy siring upgrade response data.
*/
const buySiringUpgrade = async(
body: BuySiringUpgradeRequest,
): Promise<BuySiringUpgradeResponse> => {
return await fetchJson<BuySiringUpgradeResponse>("/siring/buy-upgrade", {
body: JSON.stringify(body),
method: "POST",
});
};
/**
* Triggers a vampire awakening reset on the server.
* @param body - The awakening request payload.
* @returns The awakening response data.
*/
const awaken = async(body: AwakeningRequest): Promise<AwakeningResponse> => {
return await fetchJson<AwakeningResponse>("/vampire-awakening", {
body: JSON.stringify(body),
method: "POST",
});
};
/**
* Purchases a vampire awakening upgrade on the server.
* @param body - The buy awakening upgrade request payload.
* @returns The buy awakening upgrade response data.
*/
const buyAwakeningUpgrade = async(
body: BuyAwakeningUpgradeRequest,
): Promise<BuyAwakeningUpgradeResponse> => {
return await fetchJson<BuyAwakeningUpgradeResponse>(
"/vampire-awakening/buy-upgrade",
{ body: JSON.stringify(body), method: "POST" },
);
};
/**
* Purchases a vampire upgrade on the server.
* @param body - The buy vampire upgrade request payload.
* @returns The buy vampire upgrade response data.
*/
const buyVampireUpgrade = async(
body: BuyVampireUpgradeRequest,
): Promise<BuyVampireUpgradeResponse> => {
return await fetchJson<BuyVampireUpgradeResponse>("/vampire-upgrade/buy", {
body: JSON.stringify(body),
method: "POST",
});
};
/**
* Crafts a vampire recipe on the server.
* @param body - The vampire craft request payload.
* @returns The vampire craft response data.
*/
const craftVampireRecipe = async(
body: VampireCraftRequest,
): Promise<VampireCraftResponse> => {
return await fetchJson<VampireCraftResponse>("/vampire-craft", {
body: JSON.stringify(body),
method: "POST",
});
};
/**
* Starts a vampire exploration in a given area.
* @param body - The vampire exploration start request payload.
* @returns The vampire exploration start response data.
*/
const startVampireExploration = async(
body: VampireExploreStartRequest,
): Promise<VampireExploreStartResponse> => {
return await fetchJson<VampireExploreStartResponse>(
"/vampire-explore/start",
{ body: JSON.stringify(body), method: "POST" },
);
};
/**
* Collects the rewards from a completed vampire exploration.
* @param body - The vampire exploration collect request payload.
* @returns The vampire exploration collect response data.
*/
const collectVampireExploration = async(
body: VampireExploreCollectRequest,
): Promise<VampireExploreCollectResponse> => {
return await fetchJson<VampireExploreCollectResponse>(
"/vampire-explore/collect",
{ body: JSON.stringify(body), method: "PUT" },
);
};
/**
* Checks whether a given vampire exploration area is ready to claim on the server.
* @param areaId - The area ID to check.
* @returns Whether the vampire exploration is claimable.
*/
const checkVampireExplorationClaimable = async(
areaId: string,
): Promise<VampireExploreClaimableResponse> => {
return await fetchJson<VampireExploreClaimableResponse>(
`/vampire-explore/claimable?areaId=${encodeURIComponent(areaId)}`,
);
};
@@ -515,20 +669,28 @@ const updateProfile = async(
export {
ValidationError,
achieveApotheosis,
awaken,
buyAwakeningUpgrade,
buyConsecrationUpgrade,
buyEchoUpgrade,
buyEnlightenmentUpgrade,
buyGoddessUpgrade,
buyPrestigeUpgrade,
buySiringUpgrade,
buyVampireUpgrade,
challengeBoss,
challengeGoddessBoss,
challengeVampireBoss,
checkExplorationClaimable,
checkGoddessExplorationClaimable,
checkVampireExplorationClaimable,
collectExploration,
collectGoddessExploration,
collectVampireExploration,
consecrate,
craftGoddessRecipe,
craftRecipe,
craftVampireRecipe,
debugHardReset,
enlighten,
forceUnlocks,
@@ -541,8 +703,10 @@ export {
prestige,
resetProgress,
saveGame,
sire,
startExploration,
startGoddessExploration,
startVampireExploration,
transcend,
updateProfile,
};