80 lines
2.9 KiB
TypeScript
80 lines
2.9 KiB
TypeScript
import cn from "@bureaudouble/outils/cn.ts";
|
|
import type { CallToEroticAction } from "../../game-engine/game-schemas.ts";
|
|
import { markdownParse } from "../../utils/markdown-parser.ts";
|
|
import {
|
|
eroticSuggestionContainerVariants,
|
|
eroticSuggestionsVariants,
|
|
} from "../../game-engine/persona-styles.ts";
|
|
import { gameStateToVariantState } from "../../game-engine/persona-styles.ts";
|
|
import { PositionalScroller } from "../utils/positional-scroller.tsx";
|
|
import { ZipperSVG } from "../vectors/zipper.tsx";
|
|
import { LoveLetterSVG } from "../vectors/love-letter.tsx";
|
|
|
|
export const EroticActionSuggestions: React.FC<{
|
|
actions: CallToEroticAction[] | undefined;
|
|
variantState: ReturnType<typeof gameStateToVariantState>;
|
|
onActionClick: (promptValue: string) => void;
|
|
disabled?: boolean;
|
|
}> = ({ actions, onActionClick, variantState, disabled }) => {
|
|
const parsePartialAction = (
|
|
action?: {
|
|
displayText?: string | null;
|
|
promptValue?: string | null;
|
|
style?: string | null;
|
|
},
|
|
) => {
|
|
const [displayText, promptValue, o] = [
|
|
action?.promptValue,
|
|
action?.displayText,
|
|
(action as any)?.value ?? (action as any)?.mode,
|
|
].toSorted((a, b) => a?.length - b?.length);
|
|
return {
|
|
displayText: displayText ?? promptValue ?? o ?? "",
|
|
promptValue: promptValue ?? displayText ?? o ?? "",
|
|
};
|
|
};
|
|
|
|
return (
|
|
<PositionalScroller
|
|
className={eroticSuggestionContainerVariants(variantState)}
|
|
>
|
|
{actions?.map?.((action, index) => (
|
|
<button
|
|
key={index}
|
|
type="button"
|
|
onClick={(e) => {
|
|
(e.target as HTMLButtonElement).scrollIntoView({
|
|
block: "center",
|
|
inline: "center",
|
|
});
|
|
onActionClick(
|
|
parsePartialAction(action)?.promptValue,
|
|
);
|
|
}}
|
|
disabled={disabled} // Already checked above, but good for safety
|
|
data-suggestion
|
|
title={parsePartialAction(action)?.promptValue} // Show persona's rationale on hover
|
|
className={cn(
|
|
"first:ml-auto last:mr-auto",
|
|
"transition-colors duration-150 leading-tight disabled:opacity-60 disabled:cursor-not-allowed",
|
|
"data-[intersect-position=center]:z-10 *:line-clamp-4",
|
|
eroticSuggestionsVariants({ ...variantState, type: action.style }),
|
|
)}
|
|
>
|
|
<div
|
|
dangerouslySetInnerHTML={{
|
|
__html: markdownParse(
|
|
parsePartialAction(action).displayText,
|
|
),
|
|
}}
|
|
/>
|
|
{variantState.personaId === "polaire"
|
|
? <ZipperSVG className="size-full inset-0 absolute" />
|
|
: variantState.personaId === "cybelle"
|
|
? <LoveLetterSVG className="size-full inset-0 absolute hover:opacity-0" />
|
|
: null}
|
|
</button>
|
|
))}
|
|
</PositionalScroller>
|
|
);
|
|
};
|