Grabbed dndbeyond's source code
``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
import { visuallyHidden } from "@mui/utils";
|
||||
import { useContext } from "react";
|
||||
import { Tooltip } from "@dndbeyond/character-common-components/es";
|
||||
import {
|
||||
AbilityManager,
|
||||
CharacterTheme,
|
||||
FormatUtils,
|
||||
SituationalSavingThrowInfo,
|
||||
SituationalSavingThrowInfoLookup,
|
||||
} from "@dndbeyond/character-rules-engine/es";
|
||||
import { DiceTools, IRollContext, RollType } from "@dndbeyond/dice";
|
||||
import { GameLogContext } from "@dndbeyond/game-log-components";
|
||||
import BoxBackground from "../BoxBackground";
|
||||
import { ProficiencyLevelIcon } from "../Icons";
|
||||
import {
|
||||
ThemedSavingThrowSelectionBoxSvg,
|
||||
ThemedSavingThrowSelectionSmallBoxSvg,
|
||||
ThemedSavingThrowRowBoxSvg,
|
||||
ThemedSavingThrowRowSmallBoxSvg,
|
||||
NegativeBonusNegativeSvg,
|
||||
PositiveBonusPositiveSvg,
|
||||
DarkModePositiveBonusPositiveSvg,
|
||||
DarkModeNegativeBonusNegativeSvg,
|
||||
} from "../Svg";
|
||||
import { isNotNullOrUndefined } from "../utils/TypeScriptUtils";
|
||||
import { DigitalDiceWrapper } from "../Dice";
|
||||
import { NumberDisplay } from "~/components/NumberDisplay";
|
||||
|
||||
interface Props {
|
||||
abilities: Array<AbilityManager>;
|
||||
situationalBonusSavingThrowsLookup: SituationalSavingThrowInfoLookup;
|
||||
onClick?: (ability: AbilityManager) => void;
|
||||
rowStyle?: "small" | "normal";
|
||||
className?: string;
|
||||
diceEnabled?: boolean;
|
||||
theme: CharacterTheme;
|
||||
rollContext: IRollContext;
|
||||
};
|
||||
|
||||
export default function SavingThrowsSummary({
|
||||
abilities,
|
||||
situationalBonusSavingThrowsLookup,
|
||||
onClick = (ability: AbilityManager) => {},
|
||||
theme,
|
||||
rollContext,
|
||||
className = "",
|
||||
diceEnabled = false,
|
||||
rowStyle = "normal",
|
||||
}: Props) {
|
||||
const handleClick = (
|
||||
ability: AbilityManager,
|
||||
evt: React.MouseEvent
|
||||
): void => {
|
||||
if (onClick) {
|
||||
evt.stopPropagation();
|
||||
evt.nativeEvent.stopImmediatePropagation();
|
||||
onClick(ability);
|
||||
}
|
||||
};
|
||||
|
||||
const [{ messageTargetOptions, defaultMessageTargetOption, userId }] =
|
||||
useContext(GameLogContext);
|
||||
|
||||
return (
|
||||
<div className="ddbc-saving-throws-summary">
|
||||
{abilities.map((ability) => {
|
||||
let situationalBonusSavingThrows: Array<SituationalSavingThrowInfo> =
|
||||
[];
|
||||
let maxOptBonus: number = 0;
|
||||
|
||||
if (situationalBonusSavingThrowsLookup) {
|
||||
situationalBonusSavingThrows =
|
||||
situationalBonusSavingThrowsLookup[ability.getId()];
|
||||
if (
|
||||
situationalBonusSavingThrows &&
|
||||
situationalBonusSavingThrows.length
|
||||
) {
|
||||
let situationalBonusSavingThrowsValues: Array<number> =
|
||||
situationalBonusSavingThrows.map((optBonus) => optBonus.value);
|
||||
maxOptBonus = Math.max(...situationalBonusSavingThrowsValues);
|
||||
}
|
||||
}
|
||||
|
||||
let situationalBonusClasses: Array<string> = [
|
||||
"ddbc-saving-throws-summary__ability-situational",
|
||||
];
|
||||
let IconComponent: React.ComponentType<any> | null = null;
|
||||
if (maxOptBonus < 0) {
|
||||
situationalBonusClasses.push(
|
||||
"ddbc-saving-throws-summary__ability-situational--bonus-neg"
|
||||
);
|
||||
IconComponent = theme?.isDarkMode
|
||||
? DarkModeNegativeBonusNegativeSvg
|
||||
: NegativeBonusNegativeSvg;
|
||||
} else {
|
||||
situationalBonusClasses.push(
|
||||
"ddbc-saving-throws-summary__ability-situational--bonus-pos"
|
||||
);
|
||||
IconComponent = theme?.isDarkMode
|
||||
? DarkModePositiveBonusPositiveSvg
|
||||
: PositiveBonusPositiveSvg;
|
||||
}
|
||||
|
||||
let StyleComponent: React.ComponentType<any> =
|
||||
ThemedSavingThrowRowBoxSvg;
|
||||
let SelectionBox = ThemedSavingThrowSelectionBoxSvg;
|
||||
if (rowStyle === "small") {
|
||||
StyleComponent = ThemedSavingThrowRowSmallBoxSvg;
|
||||
SelectionBox = ThemedSavingThrowSelectionSmallBoxSvg;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={ability.getStatKey()}
|
||||
className={`ddbc-saving-throws-summary__ability ddbc-saving-throws-summary__ability--${FormatUtils.slugify(
|
||||
ability.getStatKey()
|
||||
)}`}
|
||||
onClick={(event) => handleClick(ability, event)}
|
||||
>
|
||||
<BoxBackground
|
||||
StyleComponent={StyleComponent}
|
||||
theme={{
|
||||
...theme,
|
||||
themeColor: `${theme.themeColor}80`,
|
||||
}}
|
||||
/>
|
||||
<h3 style={visuallyHidden}>{ability.getLabel()} Saving Throw</h3>
|
||||
<div className="ddbc-saving-throws-summary__ability-proficiency">
|
||||
<ProficiencyLevelIcon
|
||||
proficiencyLevel={ability.getProficiencyLevel()}
|
||||
isModified={ability.getIsSaveProficiencyModified()}
|
||||
theme={theme}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={`ddbc-saving-throws-summary__ability-name ${
|
||||
theme.isDarkMode
|
||||
? "ddbc-saving-throws-summary__ability-name--dark-mode"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<abbr
|
||||
title={ability.getLabel() ?? "Unknown Saving Throw"}
|
||||
aria-hidden={true}
|
||||
>
|
||||
{ability.getName()}
|
||||
</abbr>
|
||||
</div>
|
||||
<div className="ddbc-saving-throws-summary__ability-modifier">
|
||||
<DigitalDiceWrapper
|
||||
diceNotation={DiceTools.CustomD20(ability.getSave())}
|
||||
rollType={RollType.Save}
|
||||
rollAction={ability.getName()}
|
||||
diceEnabled={diceEnabled}
|
||||
themeColor={theme.themeColor}
|
||||
rollContext={rollContext}
|
||||
rollTargetOptions={
|
||||
messageTargetOptions?.entities
|
||||
? Object.values(messageTargetOptions.entities).filter(
|
||||
isNotNullOrUndefined
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
rollTargetDefault={defaultMessageTargetOption}
|
||||
userId={Number(userId)}
|
||||
>
|
||||
<NumberDisplay
|
||||
number={ability.getSave()}
|
||||
type="signed"
|
||||
isModified={ability.getIsSaveModifierModified()}
|
||||
/>
|
||||
</DigitalDiceWrapper>
|
||||
<SelectionBox
|
||||
theme={theme}
|
||||
className={`ddbc-saving-throws-summary__ability-modifier-background`}
|
||||
/>
|
||||
</div>
|
||||
{situationalBonusSavingThrows &&
|
||||
situationalBonusSavingThrows.length > 0 && (
|
||||
<Tooltip
|
||||
className={situationalBonusClasses.join(" ")}
|
||||
isDarkMode={theme.isDarkMode}
|
||||
title={`Situational Bonus${
|
||||
situationalBonusSavingThrows.length !== 1 ? "es" : ""
|
||||
}`}
|
||||
>
|
||||
<IconComponent className="ddbc-saving-throws-summary__ability-situational-icon" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user