64 lines
2.7 KiB
TypeScript
64 lines
2.7 KiB
TypeScript
import { lazy, Suspense, type CSSProperties } from "react";
|
|
import { classById, raceById } from "../app/characterCatalog";
|
|
import type { CharacterDraft, CharacterProfile } from "../app/types";
|
|
import { normalizePreviewFrameRateLimit } from "../game/frameRateSettings";
|
|
|
|
const CharacterPreview3D = lazy(() => import("./CharacterPreview3D"));
|
|
|
|
function AvatarSilhouette({ gender, raceSigil }: {
|
|
gender: CharacterDraft["gender"];
|
|
raceSigil: string;
|
|
}) {
|
|
return (
|
|
<div className={`character-avatar character-avatar--${gender}`} aria-hidden="true">
|
|
<span className="character-avatar__cloak" />
|
|
<span className="character-avatar__body" />
|
|
<span className="character-avatar__shoulder character-avatar__shoulder--left" />
|
|
<span className="character-avatar__shoulder character-avatar__shoulder--right" />
|
|
<span className="character-avatar__head"><b>{raceSigil}</b></span>
|
|
<span className="character-avatar__staff"><i /></span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function CharacterPreview({ character, draft, compact = false }: {
|
|
character?: CharacterProfile | null;
|
|
draft?: CharacterDraft;
|
|
compact?: boolean;
|
|
}) {
|
|
const source = character ?? draft;
|
|
if (!source) {
|
|
return <div className="character-preview character-preview--empty"><span>+</span><p>Create a character to answer the call.</p></div>;
|
|
}
|
|
const race = raceById(source.raceId);
|
|
const characterClass = classById(source.classId);
|
|
const name = "name" in source && source.name ? source.name : "New adventurer";
|
|
const rotation = "rotation" in source ? source.rotation : -8;
|
|
const previewFrameRate = normalizePreviewFrameRateLimit(
|
|
"settings" in source ? source.settings?.previewFrameRate : undefined,
|
|
);
|
|
const style = {
|
|
"--race-accent": race.accent,
|
|
"--class-color": characterClass.color,
|
|
"--avatar-turn": `${rotation}deg`,
|
|
} as CSSProperties;
|
|
return (
|
|
<figure className={`character-preview ${compact ? "character-preview--compact" : ""}`} style={style}>
|
|
<div className="character-preview__aura" aria-hidden="true"><i /><i /><i /></div>
|
|
{compact ? (
|
|
<AvatarSilhouette gender={source.gender} raceSigil={race.sigil} />
|
|
) : (
|
|
<Suspense fallback={<AvatarSilhouette gender={source.gender} raceSigil={race.sigil} />}>
|
|
<CharacterPreview3D source={source} frameRateLimit={previewFrameRate} />
|
|
</Suspense>
|
|
)}
|
|
<span className="sr-only">{source.gender} {race.name} {characterClass.name} preview</span>
|
|
<figcaption>
|
|
<small>{race.name} / {source.gender}</small>
|
|
<strong>{name}</strong>
|
|
<span style={{ color: characterClass.color }}>{characterClass.name}</span>
|
|
</figcaption>
|
|
</figure>
|
|
);
|
|
}
|