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
+27 -7
View File
@@ -1,6 +1,6 @@
"use client";
import { useEffect, useMemo, useState } from "react";
import { useEffect, useMemo, useState, type CSSProperties } from "react";
import Image from "next/image";
import { ArrowLeft, Heart, Sparkles } from "lucide-react";
@@ -21,6 +21,10 @@ import {
type TipCoffeeType,
} from "@/lib/tip/tip_coffee";
import { useAppNavigator } from "@/router/use-app-navigator";
import {
useActiveCharacter,
useActiveCharacterRoutes,
} from "@/providers/character-provider";
import { useAuthState } from "@/stores/auth/auth-context";
import { TipCheckoutButton } from "./tip-checkout-button";
@@ -52,11 +56,16 @@ export function TipScreen({
initialPayChannel = null,
}: TipScreenProps) {
const navigator = useAppNavigator();
const character = useActiveCharacter();
const characterRoutes = useActiveCharacterRoutes();
const authState = useAuthState();
const [selectedCoffeeType, setSelectedCoffeeType] =
useState<TipCoffeeType>(coffeeType);
const coffeeOption = getTipCoffeeOption(selectedCoffeeType);
const returnPath = buildTipCoffeePath(selectedCoffeeType);
const returnPath = buildTipCoffeePath(
selectedCoffeeType,
characterRoutes.tip,
);
const resolvedInitialPayChannel =
initialPayChannel ?? navigator.getDefaultPayChannel();
const { payment, paymentDispatch } = usePaymentRouteFlow({
@@ -155,7 +164,10 @@ export function TipScreen({
}
if (!canCreateOrder) return;
paymentDispatch({ type: "PaymentCreateOrderSubmitted" });
paymentDispatch({
type: "PaymentCreateOrderSubmitted",
recipientCharacterId: character.id,
});
};
const handleCoffeeTypeChange = (type: TipCoffeeType) => {
@@ -182,7 +194,14 @@ export function TipScreen({
return (
<MobileShell background="#fff5ed">
<main className={styles.shell}>
<main
className={styles.shell}
style={
{
"--tip-cover-image": `url("${character.assets.cover}")`,
} as CSSProperties
}
>
<div className={styles.bgImage} aria-hidden="true" />
<div className={styles.bgGlowOne} aria-hidden="true" />
<div className={styles.bgGlowTwo} aria-hidden="true" />
@@ -198,13 +217,14 @@ export function TipScreen({
>
<ArrowLeft size={19} aria-hidden="true" />
</button>
<span className={styles.headerPill}>Tip Elio</span>
<span className={styles.headerPill}>{character.copy.tipHeader}</span>
</header>
<section className={styles.hero} aria-labelledby="tip-title">
<div className={styles.avatarRing}>
<CharacterAvatar
alt="Elio Silvestri"
src={character.assets.avatar}
alt={character.displayName}
size="100%"
imageSize={88}
priority
@@ -212,7 +232,7 @@ export function TipScreen({
</div>
<p className={styles.eyebrow}>A little sweetness for today</p>
<h1 id="tip-title" className={styles.title}>
Buy Elio a coffee
{character.copy.tipTitle}
</h1>
<p className={styles.subtitle}>
Send a warm coffee tip and keep the private moments glowing.