feat: add transcendence and apotheosis badges to public profile

- PublicProfileResponse now includes transcendenceCount and apotheosisCount
- ProfileSettings adds showTranscendence and showApotheosis toggles (both on by default)
- Profile page displays  Apotheosis, 🌌 Transcendence, and  Prestige badges in that order
- EditProfileModal exposes the two new visibility toggles under Current Run settings
- Styled to match the resource bar badges (gold for apotheosis, purple for transcendence)
This commit is contained in:
2026-03-07 02:39:59 -08:00
committed by Naomi Carrigan
parent a6f9844120
commit cb8e83377a
6 changed files with 47 additions and 0 deletions
+8
View File
@@ -30,6 +30,8 @@ const parseProfileSettings = (raw: unknown): ProfileSettings => {
showCurrentGold: obj.showCurrentGold !== false, showCurrentGold: obj.showCurrentGold !== false,
showCurrentClicks: obj.showCurrentClicks !== false, showCurrentClicks: obj.showCurrentClicks !== false,
showPrestige: obj.showPrestige !== false, showPrestige: obj.showPrestige !== false,
showTranscendence: obj.showTranscendence !== false,
showApotheosis: obj.showApotheosis !== false,
showBossesDefeated: obj.showBossesDefeated !== false, showBossesDefeated: obj.showBossesDefeated !== false,
showQuestsCompleted: obj.showQuestsCompleted !== false, showQuestsCompleted: obj.showQuestsCompleted !== false,
showAdventurersRecruited: obj.showAdventurersRecruited !== false, showAdventurersRecruited: obj.showAdventurersRecruited !== false,
@@ -54,6 +56,8 @@ profileRouter.get("/:discordId", async (context) => {
const state = gameStateRecord?.state as unknown as GameState | undefined; const state = gameStateRecord?.state as unknown as GameState | undefined;
const prestigeCount = state?.prestige.count ?? 0; const prestigeCount = state?.prestige.count ?? 0;
const transcendenceCount = state?.transcendence?.count ?? 0;
const apotheosisCount = state?.apotheosis?.count ?? 0;
const profileSettings = parseProfileSettings(player.profileSettings); const profileSettings = parseProfileSettings(player.profileSettings);
const bossesDefeated = state?.bosses.filter((b) => b.status === "defeated").length ?? 0; const bossesDefeated = state?.bosses.filter((b) => b.status === "defeated").length ?? 0;
@@ -81,6 +85,8 @@ profileRouter.get("/:discordId", async (context) => {
currentRunGold: state?.player.totalGoldEarned ?? 0, currentRunGold: state?.player.totalGoldEarned ?? 0,
currentRunClicks: state?.player.totalClicks ?? 0, currentRunClicks: state?.player.totalClicks ?? 0,
prestigeCount, prestigeCount,
transcendenceCount,
apotheosisCount,
bossesDefeated, bossesDefeated,
questsCompleted, questsCompleted,
adventurersRecruited, adventurersRecruited,
@@ -108,6 +114,8 @@ profileRouter.put("/", authMiddleware, async (context) => {
showCurrentGold: body.profileSettings?.showCurrentGold !== false, showCurrentGold: body.profileSettings?.showCurrentGold !== false,
showCurrentClicks: body.profileSettings?.showCurrentClicks !== false, showCurrentClicks: body.profileSettings?.showCurrentClicks !== false,
showPrestige: body.profileSettings?.showPrestige !== false, showPrestige: body.profileSettings?.showPrestige !== false,
showTranscendence: body.profileSettings?.showTranscendence !== false,
showApotheosis: body.profileSettings?.showApotheosis !== false,
showBossesDefeated: body.profileSettings?.showBossesDefeated !== false, showBossesDefeated: body.profileSettings?.showBossesDefeated !== false,
showQuestsCompleted: body.profileSettings?.showQuestsCompleted !== false, showQuestsCompleted: body.profileSettings?.showQuestsCompleted !== false,
showAdventurersRecruited: body.profileSettings?.showAdventurersRecruited !== false, showAdventurersRecruited: body.profileSettings?.showAdventurersRecruited !== false,
@@ -17,6 +17,8 @@ interface StatToggle {
const CURRENT_RUN_TOGGLES: StatToggle[] = [ const CURRENT_RUN_TOGGLES: StatToggle[] = [
{ key: "showCurrentGold", label: "Gold Earned This Run", icon: "🪙" }, { key: "showCurrentGold", label: "Gold Earned This Run", icon: "🪙" },
{ key: "showCurrentClicks", label: "Clicks This Run", icon: "👆" }, { key: "showCurrentClicks", label: "Clicks This Run", icon: "👆" },
{ key: "showApotheosis", label: "Apotheosis Badge", icon: "✨" },
{ key: "showTranscendence", label: "Transcendence Badge", icon: "🌌" },
{ key: "showPrestige", label: "Prestige Level", icon: "⭐" }, { key: "showPrestige", label: "Prestige Level", icon: "⭐" },
{ key: "showBossesDefeated", label: "Bosses Defeated", icon: "💀" }, { key: "showBossesDefeated", label: "Bosses Defeated", icon: "💀" },
{ key: "showQuestsCompleted", label: "Quests Completed", icon: "📜" }, { key: "showQuestsCompleted", label: "Quests Completed", icon: "📜" },
@@ -179,6 +179,16 @@ export const ProfilePage = ({ discordId }: ProfilePageProps): React.JSX.Element
<div className="profile-identity"> <div className="profile-identity">
<h1 className="profile-character-name">{profile.characterName}</h1> <h1 className="profile-character-name">{profile.characterName}</h1>
<p className="profile-username">@{profile.username}</p> <p className="profile-username">@{profile.username}</p>
{s.showApotheosis && profile.apotheosisCount > 0 && (
<span className="profile-apotheosis-badge">
Apotheosis {profile.apotheosisCount}
</span>
)}
{s.showTranscendence && profile.transcendenceCount > 0 && (
<span className="profile-transcendence-badge">
🌌 Transcendence {profile.transcendenceCount}
</span>
)}
{s.showPrestige && profile.prestigeCount > 0 && ( {s.showPrestige && profile.prestigeCount > 0 && (
<span className="profile-prestige-badge"> <span className="profile-prestige-badge">
Prestige {profile.prestigeCount} Prestige {profile.prestigeCount}
+21
View File
@@ -1466,6 +1466,27 @@ body {
margin: 0; margin: 0;
} }
.profile-apotheosis-badge {
background: linear-gradient(135deg, rgba(120, 53, 15, 0.2), rgba(217, 119, 6, 0.2));
border: 1px solid rgba(217, 119, 6, 0.5);
border-radius: 1rem;
color: #fbbf24;
font-size: 0.8rem;
font-weight: 700;
padding: 0.2rem 0.6rem;
width: fit-content;
}
.profile-transcendence-badge {
background: rgba(124, 58, 237, 0.15);
border: 1px solid rgba(124, 58, 237, 0.4);
border-radius: 1rem;
color: #a78bfa;
font-size: 0.8rem;
padding: 0.2rem 0.6rem;
width: fit-content;
}
.profile-prestige-badge { .profile-prestige-badge {
background: rgba(255, 215, 0, 0.15); background: rgba(255, 215, 0, 0.15);
border: 1px solid rgba(255, 215, 0, 0.4); border: 1px solid rgba(255, 215, 0, 0.4);
+2
View File
@@ -109,6 +109,8 @@ export interface PublicProfileResponse {
currentRunGold: number; currentRunGold: number;
currentRunClicks: number; currentRunClicks: number;
prestigeCount: number; prestigeCount: number;
transcendenceCount: number;
apotheosisCount: number;
bossesDefeated: number; bossesDefeated: number;
questsCompleted: number; questsCompleted: number;
adventurersRecruited: number; adventurersRecruited: number;
@@ -13,6 +13,8 @@ export interface ProfileSettings {
showCurrentGold: boolean; showCurrentGold: boolean;
showCurrentClicks: boolean; showCurrentClicks: boolean;
showPrestige: boolean; showPrestige: boolean;
showTranscendence: boolean;
showApotheosis: boolean;
showBossesDefeated: boolean; showBossesDefeated: boolean;
showQuestsCompleted: boolean; showQuestsCompleted: boolean;
showAdventurersRecruited: boolean; showAdventurersRecruited: boolean;
@@ -31,6 +33,8 @@ export const DEFAULT_PROFILE_SETTINGS: ProfileSettings = {
showCurrentGold: true, showCurrentGold: true,
showCurrentClicks: true, showCurrentClicks: true,
showPrestige: true, showPrestige: true,
showTranscendence: true,
showApotheosis: true,
showBossesDefeated: true, showBossesDefeated: true,
showQuestsCompleted: true, showQuestsCompleted: true,
showAdventurersRecruited: true, showAdventurersRecruited: true,