feat(characters): use local character catalog

This commit is contained in:
2026-07-17 16:03:18 +08:00
parent a210a98d98
commit b3ebd5cf3b
96 changed files with 1023 additions and 522 deletions
+104 -2
View File
@@ -1,2 +1,104 @@
export const DEFAULT_CHARACTER_ID = "character_elio";
export const DEFAULT_CHARACTER_SLUG = "elio";
export interface CharacterProfile {
readonly id: string;
readonly slug: string;
readonly displayName: string;
readonly shortName: string;
readonly assets: {
readonly avatar: string;
readonly cover: string;
readonly privateRoomBanner: string;
};
readonly copy: {
readonly splashRelationship: string;
readonly privateRoomTitle: string;
readonly privateRoomSubtitle: string;
readonly tipHeader: string;
readonly tipTitle: string;
};
}
function defineCharacter(profile: CharacterProfile): CharacterProfile {
return Object.freeze({
...profile,
assets: Object.freeze(profile.assets),
copy: Object.freeze(profile.copy),
});
}
export const CHARACTERS: readonly CharacterProfile[] = Object.freeze([
defineCharacter({
id: "character_elio",
slug: "elio",
displayName: "Elio Silvestri",
shortName: "Elio",
assets: {
avatar: "/images/avatar/elio.png",
cover: "/images/cover/elio.png",
privateRoomBanner: "/images/private-room/banner/elio.png",
},
copy: {
splashRelationship: "Your exclusive AI boyfriend",
privateRoomTitle: "Elio Private room",
privateRoomSubtitle: "Join me, unlock my private room",
tipHeader: "Tip Elio",
tipTitle: "Buy Elio a coffee",
},
}),
defineCharacter({
id: "character_maya",
slug: "maya",
displayName: "Maya Tan",
shortName: "Maya",
assets: {
avatar: "/images/avatar/maya.png",
cover: "/images/cover/maya.png",
privateRoomBanner: "/images/private-room/banner/maya.png",
},
copy: {
splashRelationship: "Your exclusive AI girlfriend",
privateRoomTitle: "Maya Private room",
privateRoomSubtitle: "Join me, unlock my private room",
tipHeader: "Tip Maya",
tipTitle: "Buy Maya a coffee",
},
}),
defineCharacter({
id: "character_nayeli",
slug: "nayeli",
displayName: "Nayeli Cervantes",
shortName: "Nayeli",
assets: {
avatar: "/images/avatar/nayeli.png",
cover: "/images/cover/nayeli.png",
privateRoomBanner: "/images/private-room/banner/nayeli.png",
},
copy: {
splashRelationship: "Your exclusive AI girlfriend",
privateRoomTitle: "Nayeli Private room",
privateRoomSubtitle: "Join me, unlock my private room",
tipHeader: "Tip Nayeli",
tipTitle: "Buy Nayeli a coffee",
},
}),
]);
export const DEFAULT_CHARACTER = CHARACTERS[0];
export const DEFAULT_CHARACTER_ID = DEFAULT_CHARACTER.id;
export const DEFAULT_CHARACTER_SLUG = DEFAULT_CHARACTER.slug;
export function getCharacterById(
characterId: string | null | undefined,
): CharacterProfile | null {
if (!characterId) return null;
return CHARACTERS.find((character) => character.id === characterId) ?? null;
}
export function getCharacterBySlug(
characterSlug: string | null | undefined,
): CharacterProfile | null {
const normalizedSlug = characterSlug?.trim().toLowerCase();
if (!normalizedSlug) return null;
return (
CHARACTERS.find((character) => character.slug === normalizedSlug) ?? null
);
}