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:
2025-05-28 11:50:03 -07:00
commit 8df9031d27
3592 changed files with 319051 additions and 0 deletions
@@ -0,0 +1,98 @@
import * as React from "react";
import { Constants } from "@dndbeyond/character-rules-engine/es";
import {
DarkCharismaSvg,
DarkConstitutionSvg,
DarkDexteritySvg,
DarkIntelligenceSvg,
DarkStrengthSvg,
DarkWisdomSvg,
LightCharismaSvg,
LightConstitutionSvg,
LightDexteritySvg,
LightIntelligenceSvg,
LightStrengthSvg,
LightWisdomSvg,
} from "../../Svg";
//TODO should dynamically create props based on which component and expected props, for now this is duplicated from InjectedSvgProps hocTypings.ts
interface SvgInjectedProps {
className?: string;
}
interface Props {
statId: Constants.AbilityStatEnum;
themeMode?: "dark" | "light";
className: string;
}
export default class AbilityIcon extends React.PureComponent<Props> {
static defaultProps = {
className: "",
};
getDarkSvg = (): React.ComponentType<SvgInjectedProps> | null => {
const { statId } = this.props;
switch (statId) {
case Constants.AbilityStatEnum.CHARISMA:
return DarkCharismaSvg;
case Constants.AbilityStatEnum.CONSTITUTION:
return DarkConstitutionSvg;
case Constants.AbilityStatEnum.DEXTERITY:
return DarkDexteritySvg;
case Constants.AbilityStatEnum.INTELLIGENCE:
return DarkIntelligenceSvg;
case Constants.AbilityStatEnum.STRENGTH:
return DarkStrengthSvg;
case Constants.AbilityStatEnum.WISDOM:
return DarkWisdomSvg;
default:
return null;
}
};
getLightSvg = (): React.ComponentType<SvgInjectedProps> | null => {
const { statId } = this.props;
switch (statId) {
case Constants.AbilityStatEnum.CHARISMA:
return LightCharismaSvg;
case Constants.AbilityStatEnum.CONSTITUTION:
return LightConstitutionSvg;
case Constants.AbilityStatEnum.DEXTERITY:
return LightDexteritySvg;
case Constants.AbilityStatEnum.INTELLIGENCE:
return LightIntelligenceSvg;
case Constants.AbilityStatEnum.STRENGTH:
return LightStrengthSvg;
case Constants.AbilityStatEnum.WISDOM:
return LightWisdomSvg;
default:
return null;
}
};
render() {
const { themeMode, className } = this.props;
let classNames: Array<string> = [className, "ddbc-ability-icon"];
let SvgIcon: React.ComponentType<SvgInjectedProps> | null = null;
switch (themeMode) {
case "light":
SvgIcon = this.getLightSvg();
break;
case "dark":
default:
SvgIcon = this.getDarkSvg();
}
if (SvgIcon === null) {
return null;
}
return <SvgIcon className={classNames.join(" ")} />;
}
}
@@ -0,0 +1,55 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
import { AdvantageDisadvantageSvg } from "../../Svg";
import {
SvgConstantDarkModePositiveTheme,
SvgConstantDarkModeNegativeTheme,
SvgConstantPositiveTheme,
SvgConstantNegativeTheme,
} from "../../componentConstants";
interface Props {
title: string;
className: string;
theme: CharacterTheme;
}
export default class AdvantageDisadvantageIcon extends React.PureComponent<Props> {
static defaultProps = {
title: "",
className: "",
theme: {},
};
render() {
const { title, className, theme } = this.props;
let classNames: Array<string> = [
className,
"ddbc-advantage-disadvantage-icon",
];
return (
<Tooltip
title={title}
className={classNames.join(" ")}
isDarkMode={theme?.isDarkMode}
>
<AdvantageDisadvantageSvg
fillColor={
theme.isDarkMode
? SvgConstantDarkModePositiveTheme.fill
: SvgConstantPositiveTheme.fill
}
secondaryFillColor={
theme.isDarkMode
? SvgConstantDarkModeNegativeTheme.fill
: SvgConstantNegativeTheme.fill
}
/>
</Tooltip>
);
}
}
@@ -0,0 +1,4 @@
import AdvantageDisadvantageIcon from "./AdvantageDisadvantageIcon";
export default AdvantageDisadvantageIcon;
export { AdvantageDisadvantageIcon };
@@ -0,0 +1,42 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
import { DarkModePositiveAdvantageSvg, PositiveAdvantageSvg } from "../../Svg";
interface Props {
title: string;
className: string;
theme?: CharacterTheme;
secondaryFill?: string;
}
export default class AdvantageIcon extends React.PureComponent<Props> {
static defaultProps = {
title: "Advantage",
className: "",
theme: {},
};
render() {
const { title, className, theme } = this.props;
let classNames: Array<string> = [className, "ddbc-advantage-icon"];
return (
<Tooltip
title={title}
className={classNames.join(" ")}
isDarkMode={theme?.isDarkMode}
>
<span aria-label="Advantage">
{theme?.isDarkMode ? (
<DarkModePositiveAdvantageSvg />
) : (
<PositiveAdvantageSvg />
)}
</span>
</Tooltip>
);
}
}
@@ -0,0 +1,125 @@
import * as React from "react";
import {
DarkConeSvg,
DarkCubeSvg,
DarkCylinderSvg,
DarkLineSvg,
DarkSphereSvg,
DarkSquareSvg,
GrayConeSvg,
GrayCubeSvg,
GrayCylinderSvg,
GrayLineSvg,
GraySphereSvg,
GraySquareSvg,
LightConeSvg,
LightCubeSvg,
LightCylinderSvg,
LightLineSvg,
LightSphereSvg,
LightSquareSvg,
} from "../../Svg";
import { AoeTypePropType } from "../IconConstants";
interface SvgInjectedProps {
className?: string;
}
interface Props {
type?: AoeTypePropType;
themeMode?: "dark" | "gray" | "light";
className?: string;
}
const AoeTypeIcon: React.FunctionComponent<Props> = ({
className = "",
themeMode = "dark",
type,
}) => {
const DarkSvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (type) {
case "cone":
return DarkConeSvg;
case "cube":
return DarkCubeSvg;
case "cylinder":
return DarkCylinderSvg;
case "line":
return DarkLineSvg;
case "sphere":
case "emanation":
return DarkSphereSvg;
case "square":
return DarkSquareSvg;
default:
return null;
}
};
const GraySvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (type) {
case "cone":
return GrayConeSvg;
case "cube":
return GrayCubeSvg;
case "cylinder":
return GrayCylinderSvg;
case "line":
return GrayLineSvg;
case "sphere":
case "emanation":
return GraySphereSvg;
case "square":
return GraySquareSvg;
default:
return null;
}
};
const LightSvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (type) {
case "cone":
return LightConeSvg;
case "cube":
return LightCubeSvg;
case "cylinder":
return LightCylinderSvg;
case "line":
return LightLineSvg;
case "sphere":
case "emanation":
return LightSphereSvg;
case "square":
return LightSquareSvg;
default:
return null;
}
};
let classNames: Array<string> = [
className,
"ddbc-aoe-type-icon",
`ddbc-aoe-type-icon--${type}`,
];
let SvgIcon: React.ComponentType<SvgInjectedProps> | null = null;
switch (themeMode) {
case "light":
SvgIcon = LightSvg();
break;
case "gray":
SvgIcon = GraySvg();
break;
case "dark":
default:
SvgIcon = DarkSvg();
}
if (SvgIcon === null) {
return null;
}
return <SvgIcon className={classNames.join(" ")} />;
};
export default AoeTypeIcon;
@@ -0,0 +1,161 @@
import * as React from "react";
import { Constants } from "@dndbeyond/character-rules-engine/es";
import {
DarkMeleeSpellSvg,
DarkMeleeWeaponSvg,
DarkRangedSpellSvg,
DarkRangedWeaponSvg,
DarkThrownSvg,
DarkUnarmedStrikeSvg,
DarkWeaponSpellDamageSvg,
GrayMeleeSpellSvg,
GrayMeleeWeaponSvg,
GrayRangedSpellSvg,
GrayRangedWeaponSvg,
GrayThrownSvg,
GrayUnarmedStrikeSvg,
GrayWeaponSpellDamageSvg,
LightMeleeSpellSvg,
LightMeleeWeaponSvg,
LightRangedSpellSvg,
LightRangedWeaponSvg,
LightThrownSvg,
LightUnarmedStrikeSvg,
LightWeaponSpellDamageSvg,
} from "../../Svg";
interface SvgInjectedProps {
className?: string;
}
interface Props {
actionType: Constants.ActionTypeEnum | null;
rangeType: Constants.AttackTypeRangeEnum;
themeMode?: "dark" | "gray" | "light";
className?: string;
overrideType?: "weapon-spell" | null;
}
const AttackTypeIcon: React.FunctionComponent<Props> = ({
className = "",
themeMode = "dark",
actionType,
rangeType,
overrideType,
}) => {
const DarkSvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (true) {
case actionType === Constants.ActionTypeEnum.GENERAL &&
rangeType === Constants.AttackTypeRangeEnum.MELEE:
return DarkUnarmedStrikeSvg;
case actionType === Constants.ActionTypeEnum.GENERAL &&
rangeType === Constants.AttackTypeRangeEnum.RANGED:
return DarkThrownSvg;
case actionType === Constants.ActionTypeEnum.SPELL &&
rangeType === Constants.AttackTypeRangeEnum.MELEE:
return DarkMeleeSpellSvg;
case actionType === Constants.ActionTypeEnum.SPELL &&
rangeType === Constants.AttackTypeRangeEnum.RANGED:
return DarkRangedSpellSvg;
case actionType === Constants.ActionTypeEnum.WEAPON &&
overrideType === "weapon-spell":
return DarkWeaponSpellDamageSvg;
case actionType === Constants.ActionTypeEnum.WEAPON &&
rangeType === Constants.AttackTypeRangeEnum.MELEE:
return DarkMeleeWeaponSvg;
case actionType === Constants.ActionTypeEnum.WEAPON &&
rangeType === Constants.AttackTypeRangeEnum.RANGED:
return DarkRangedWeaponSvg;
default:
return null;
}
};
const GraySvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (true) {
case actionType === Constants.ActionTypeEnum.GENERAL &&
rangeType === Constants.AttackTypeRangeEnum.MELEE:
return GrayUnarmedStrikeSvg;
case actionType === Constants.ActionTypeEnum.GENERAL &&
rangeType === Constants.AttackTypeRangeEnum.RANGED:
return GrayThrownSvg;
case actionType === Constants.ActionTypeEnum.SPELL &&
rangeType === Constants.AttackTypeRangeEnum.MELEE:
return GrayMeleeSpellSvg;
case actionType === Constants.ActionTypeEnum.SPELL &&
rangeType === Constants.AttackTypeRangeEnum.RANGED:
return GrayRangedSpellSvg;
case actionType === Constants.ActionTypeEnum.WEAPON &&
overrideType === "weapon-spell":
return GrayWeaponSpellDamageSvg;
case actionType === Constants.ActionTypeEnum.WEAPON &&
rangeType === Constants.AttackTypeRangeEnum.MELEE:
return GrayMeleeWeaponSvg;
case actionType === Constants.ActionTypeEnum.WEAPON &&
rangeType === Constants.AttackTypeRangeEnum.RANGED:
return GrayRangedWeaponSvg;
default:
return null;
}
};
const LightSvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (true) {
case actionType === Constants.ActionTypeEnum.GENERAL &&
rangeType === Constants.AttackTypeRangeEnum.MELEE:
return LightUnarmedStrikeSvg;
case actionType === Constants.ActionTypeEnum.GENERAL &&
rangeType === Constants.AttackTypeRangeEnum.RANGED:
return LightThrownSvg;
case actionType === Constants.ActionTypeEnum.SPELL &&
rangeType === Constants.AttackTypeRangeEnum.MELEE:
return LightMeleeSpellSvg;
case actionType === Constants.ActionTypeEnum.SPELL &&
rangeType === Constants.AttackTypeRangeEnum.RANGED:
return LightRangedSpellSvg;
case actionType === Constants.ActionTypeEnum.WEAPON &&
overrideType === "weapon-spell":
return LightWeaponSpellDamageSvg;
case actionType === Constants.ActionTypeEnum.WEAPON &&
rangeType === Constants.AttackTypeRangeEnum.MELEE:
return LightMeleeWeaponSvg;
case actionType === Constants.ActionTypeEnum.WEAPON &&
rangeType === Constants.AttackTypeRangeEnum.RANGED:
return LightRangedWeaponSvg;
default:
return null;
}
};
let classNames: Array<string> = [
className,
"ddbc-attack-type-icon",
`ddbc-attack-type-icon--${actionType}-${rangeType}`,
];
if (overrideType) {
classNames.push(`ddbc-attack-type-icon--${overrideType}`);
}
let SvgIcon: React.ComponentType<SvgInjectedProps> | null = null;
switch (themeMode) {
case "light":
SvgIcon = LightSvg();
break;
case "gray":
SvgIcon = GraySvg();
break;
case "dark":
default:
SvgIcon = DarkSvg();
}
if (SvgIcon === null) {
return null;
}
return <SvgIcon className={classNames.join(" ")} />;
};
export default AttackTypeIcon;
@@ -0,0 +1,43 @@
import * as React from "react";
import { v4 as uuidv4 } from "uuid";
import { Tooltip } from "~/components/Tooltip";
import { useCharacterTheme } from "~/contexts/CharacterTheme";
import { DarkAttunementSvg, GrayAttunementSvg } from "../../Svg";
interface SvgInjectedProps {
className?: string;
}
interface Props {
className?: string;
showTooltip?: boolean;
}
const AttunementIcon: React.FunctionComponent<Props> = ({
className = "",
showTooltip = true,
}) => {
const { isDarkMode } = useCharacterTheme();
let classNames: Array<string> = [className, "ddbc-attunement-icon"];
let SvgIcon: React.ComponentType<SvgInjectedProps> = isDarkMode
? GrayAttunementSvg
: DarkAttunementSvg;
const tooltipId = `attunmentIcon-${uuidv4()}`;
return (
<>
<span
className={classNames.join(" ")}
data-tooltip-id={tooltipId}
data-tooltip-content="Item is Attuned"
>
<SvgIcon className="ddbc-attunement-icon__icon" />
</span>
{showTooltip && <Tooltip id={tooltipId} />}
</>
);
};
export default AttunementIcon;
@@ -0,0 +1,59 @@
import * as React from "react";
import { Constants } from "@dndbeyond/character-rules-engine/es";
import {
GoldCoinSvg,
SilverCoinSvg,
CopperCoinSvg,
ElectrumCoinSvg,
PlatinumCoinSvg,
} from "../../Svg";
//TODO should dynamically create props based on which component and expected props, for now this is duplicated from InjectedSvgProps hocTypings.ts
interface SvgInjectedProps {
className?: string;
}
interface Props {
coinType: Constants.CoinTypeEnum;
className: string;
}
export default class AbilityIcon extends React.PureComponent<Props> {
static defaultProps = {
className: "",
};
render() {
const { className, coinType } = this.props;
let classNames: Array<string> = [className, "ddbc-ability-icon"];
let SvgIcon: React.ComponentType<SvgInjectedProps> | null = null;
switch (coinType) {
case Constants.CoinTypeEnum.cp:
SvgIcon = CopperCoinSvg;
break;
case Constants.CoinTypeEnum.ep:
SvgIcon = ElectrumCoinSvg;
break;
case Constants.CoinTypeEnum.gp:
SvgIcon = GoldCoinSvg;
break;
case Constants.CoinTypeEnum.pp:
SvgIcon = PlatinumCoinSvg;
break;
case Constants.CoinTypeEnum.sp:
SvgIcon = SilverCoinSvg;
break;
default:
SvgIcon = null;
}
if (SvgIcon === null) {
return null;
}
return <SvgIcon className={classNames.join(" ")} />;
}
}
@@ -0,0 +1,4 @@
import CoinIcon from "./CoinIcon";
export default CoinIcon;
export { CoinIcon };
@@ -0,0 +1,60 @@
import clsx from "clsx";
import * as React from "react";
import { v4 as uuidv4 } from "uuid";
import { Tooltip } from "~/components/Tooltip";
import {
DarkConcentrationSvg,
GrayConcentrationSvg,
LightConcentrationSvg,
} from "../../Svg";
import styles from "./styles.module.css";
interface SvgInjectedProps {
className?: string;
}
interface Props {
themeMode?: "dark" | "gray" | "light";
className: string;
}
export default class ConcentrationIcon extends React.PureComponent<Props> {
static defaultProps = {
className: "",
themeMode: "dark",
};
render() {
const { themeMode, className, ...props } = this.props;
const id = uuidv4();
let SvgIcon: React.ComponentType<SvgInjectedProps> | null = null;
switch (themeMode) {
case "light":
SvgIcon = LightConcentrationSvg;
break;
case "gray":
SvgIcon = GrayConcentrationSvg;
break;
case "dark":
default:
SvgIcon = DarkConcentrationSvg;
}
if (SvgIcon === null) {
return null;
}
return (
<div
className={clsx([styles.concentrationIcon, className])}
data-tooltip-id={id}
data-tooltip-content="Concentration"
>
<SvgIcon className={styles.svg} {...props} />
<Tooltip id={id} />
</div>
);
}
}
@@ -0,0 +1,4 @@
import ConcentrationIcon from "./ConcentrationIcon";
export default ConcentrationIcon;
export { ConcentrationIcon };
@@ -0,0 +1,129 @@
import * as React from "react";
import { Constants } from "@dndbeyond/character-rules-engine/es";
import {
DarkBlindedSvg,
LightBlindedSvg,
DarkCharmedSvg,
LightCharmedSvg,
DarkDeafenedSvg,
LightDeafenedSvg,
LightExhaustedSvg,
DarkExhaustedSvg,
LightFrightenedSvg,
DarkFrightenedSvg,
LightGrappledSvg,
DarkGrappledSvg,
DarkIncapacitatedSvg,
LightIncapacitatedSvg,
LightInvisibleSvg,
DarkInvisibleSvg,
DarkParalyzedSvg,
LightParalyzedSvg,
DarkPetrifiedSvg,
LightPetrifiedSvg,
LightPoisonedSvg,
DarkPoisonedSvg,
LightProneSvg,
DarkProneSvg,
LightRestrainedSvg,
DarkRestrainedSvg,
LightStunnedSvg,
DarkStunnedSvg,
LightUnconsciousSvg,
DarkUnconsciousSvg,
} from "../../Svg";
interface SvgInjectedProps {
className?: string;
}
interface Props {
conditionType: Constants.ConditionIdEnum;
className: string;
isDarkMode: boolean;
}
const iconMap = {
[Constants.ConditionIdEnum.BLINDED]: {
light: LightBlindedSvg,
dark: DarkBlindedSvg,
},
[Constants.ConditionIdEnum.CHARMED]: {
light: LightCharmedSvg,
dark: DarkCharmedSvg,
},
[Constants.ConditionIdEnum.DEAFENED]: {
light: LightDeafenedSvg,
dark: DarkDeafenedSvg,
},
[Constants.ConditionIdEnum.EXHAUSTION]: {
light: LightExhaustedSvg,
dark: DarkExhaustedSvg,
},
[Constants.ConditionIdEnum.FRIGHTENED]: {
light: LightFrightenedSvg,
dark: DarkFrightenedSvg,
},
[Constants.ConditionIdEnum.GRAPPLED]: {
light: LightGrappledSvg,
dark: DarkGrappledSvg,
},
[Constants.ConditionIdEnum.INCAPACITATED]: {
light: LightIncapacitatedSvg,
dark: DarkIncapacitatedSvg,
},
[Constants.ConditionIdEnum.INVISIBLE]: {
light: LightInvisibleSvg,
dark: DarkInvisibleSvg,
},
[Constants.ConditionIdEnum.PARALYZED]: {
light: LightParalyzedSvg,
dark: DarkParalyzedSvg,
},
[Constants.ConditionIdEnum.PETRIFIED]: {
light: LightPetrifiedSvg,
dark: DarkPetrifiedSvg,
},
[Constants.ConditionIdEnum.POISONED]: {
light: LightPoisonedSvg,
dark: DarkPoisonedSvg,
},
[Constants.ConditionIdEnum.PRONE]: {
light: LightProneSvg,
dark: DarkProneSvg,
},
[Constants.ConditionIdEnum.RESTRAINED]: {
light: LightRestrainedSvg,
dark: DarkRestrainedSvg,
},
[Constants.ConditionIdEnum.STUNNED]: {
light: LightStunnedSvg,
dark: DarkStunnedSvg,
},
[Constants.ConditionIdEnum.UNCONSCIOUS]: {
light: LightUnconsciousSvg,
dark: DarkUnconsciousSvg,
},
};
export default class ConditionIcon extends React.PureComponent<Props> {
static defaultProps = {
className: "",
};
render() {
const { className, conditionType, isDarkMode } = this.props;
let classNames: Array<string> = [className, "ddbc-condition-icon"];
let SvgIcon: React.ComponentType<SvgInjectedProps> | null =
iconMap[conditionType]?.[isDarkMode ? "light" : "dark"] ?? null;
if (SvgIcon === null) {
return null;
}
return <SvgIcon className={classNames.join(" ")} />;
}
}
@@ -0,0 +1,4 @@
import ConditionIcon from "./ConditionIcon";
export default ConditionIcon;
export { ConditionIcon };
@@ -0,0 +1,204 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
import {
DarkAcidSvg,
GrayAcidSvg,
LightAcidSvg,
DarkBludgeoningSvg,
GrayBludgeoningSvg,
LightBludgeoningSvg,
DarkColdSvg,
GrayColdSvg,
LightColdSvg,
DarkFireSvg,
GrayFireSvg,
LightFireSvg,
DarkForceSvg,
GrayForceSvg,
LightForceSvg,
DarkLightningSvg,
GrayLightningSvg,
LightLightningSvg,
DarkNecroticSvg,
GrayNecroticSvg,
LightNecroticSvg,
DarkPiercingSvg,
GrayPiercingSvg,
LightPiercingSvg,
DarkPoisonSvg,
GrayPoisonSvg,
LightPoisonSvg,
DarkPsychicSvg,
GrayPsychicSvg,
LightPsychicSvg,
DarkRadiantSvg,
GrayRadiantSvg,
LightRadiantSvg,
DarkSlashingSvg,
GraySlashingSvg,
LightSlashingSvg,
DarkThunderSvg,
GrayThunderSvg,
LightThunderSvg,
} from "../../Svg";
import { DamageTypePropType } from "../IconConstants";
interface SvgInjectedProps {
className?: string;
}
interface Props {
type: DamageTypePropType;
showTooltip?: boolean;
className?: string;
theme?: CharacterTheme;
themeMode?: "dark" | "gray" | "light";
}
const DamageTypeIcon: React.FunctionComponent<Props> = ({
showTooltip = true,
className = "",
type,
theme,
themeMode = theme?.isDarkMode ? "gray" : "dark",
}) => {
const DarkSvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (type) {
case "acid":
return DarkAcidSvg;
case "bludgeoning":
return DarkBludgeoningSvg;
case "cold":
return DarkColdSvg;
case "fire":
return DarkFireSvg;
case "force":
return DarkForceSvg;
case "lightning":
return DarkLightningSvg;
case "necrotic":
return DarkNecroticSvg;
case "piercing":
return DarkPiercingSvg;
case "poison":
return DarkPoisonSvg;
case "psychic":
return DarkPsychicSvg;
case "radiant":
return DarkRadiantSvg;
case "slashing":
return DarkSlashingSvg;
case "thunder":
return DarkThunderSvg;
default:
return null;
}
};
const GraySvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (type) {
case "acid":
return GrayAcidSvg;
case "bludgeoning":
return GrayBludgeoningSvg;
case "cold":
return GrayColdSvg;
case "fire":
return GrayFireSvg;
case "force":
return GrayForceSvg;
case "lightning":
return GrayLightningSvg;
case "necrotic":
return GrayNecroticSvg;
case "piercing":
return GrayPiercingSvg;
case "poison":
return GrayPoisonSvg;
case "psychic":
return GrayPsychicSvg;
case "radiant":
return GrayRadiantSvg;
case "slashing":
return GraySlashingSvg;
case "thunder":
return GrayThunderSvg;
default:
return null;
}
};
const LightSvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (type) {
case "acid":
return LightAcidSvg;
case "bludgeoning":
return LightBludgeoningSvg;
case "cold":
return LightColdSvg;
case "fire":
return LightFireSvg;
case "force":
return LightForceSvg;
case "lightning":
return LightLightningSvg;
case "necrotic":
return LightNecroticSvg;
case "piercing":
return LightPiercingSvg;
case "poison":
return LightPoisonSvg;
case "psychic":
return LightPsychicSvg;
case "radiant":
return LightRadiantSvg;
case "slashing":
return LightSlashingSvg;
case "thunder":
return LightThunderSvg;
default:
return null;
}
};
let classNames: Array<string> = [
className,
"ddbc-damage-type-icon",
`ddbc-damage-type-icon--${type}`,
];
let SvgIcon: React.ComponentType<SvgInjectedProps> | null = null;
switch (themeMode) {
case "light":
SvgIcon = LightSvg();
break;
case "gray":
SvgIcon = GraySvg();
break;
case "dark":
default:
SvgIcon = DarkSvg();
}
if (SvgIcon === null) {
return null;
}
return (
<span className={classNames.join(" ")} aria-label={`${type} damage`}>
<Tooltip
title={type}
enabled={showTooltip}
isDarkMode={theme?.isDarkMode}
>
<SvgIcon
className={`ddbc-damage-type-icon__img ddbc-damage-type-icon__img--${type}`}
/>
</Tooltip>
</span>
);
};
export default DamageTypeIcon;
@@ -0,0 +1,44 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
import {
DarkModeNegativeDisadvantageSvg,
NegativeDisadvantageSvg,
} from "../../Svg";
interface Props {
title: string;
className: string;
theme?: CharacterTheme;
}
export default class DisadvantageIcon extends React.PureComponent<Props> {
static defaultProps = {
title: "Disadvantage",
className: "",
theme: {},
};
render() {
const { title, className, theme } = this.props;
const classNames: Array<string> = [className, "ddbc-disadvantage-icon"];
return (
<Tooltip
title={title}
className={classNames.join(" ")}
isDarkMode={theme?.isDarkMode}
>
<span aria-label="Disadvantage">
{theme?.isDarkMode ? (
<DarkModeNegativeDisadvantageSvg />
) : (
<NegativeDisadvantageSvg />
)}
</span>
</Tooltip>
);
}
}
@@ -0,0 +1,56 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
import { DarkHealingSvg, GrayHealingSvg } from "../../Svg";
interface SvgInjectedProps {
className?: string;
}
interface Props {
className: string;
isHp: boolean;
isTemp: boolean;
showTooltip: boolean;
theme?: CharacterTheme;
}
export default class HealingIcon extends React.PureComponent<Props> {
static defaultProps = {
className: "",
isHp: false,
isTemp: false,
showTooltip: true,
};
render() {
const { isHp, isTemp, showTooltip, className, theme } = this.props;
let classNames: Array<string> = [className, "ddbc-healing-icon"];
let tooltips: Array<string> = [];
if (isHp) {
classNames.push("ddbc-healing-icon--hp");
tooltips.push("Healing");
}
if (isTemp) {
classNames.push("ddbc-healing-icon--temp");
tooltips.push("Temp HP Healing");
}
let SvgIcon: React.ComponentType<SvgInjectedProps> = theme?.isDarkMode
? GrayHealingSvg
: DarkHealingSvg;
return (
<span className={classNames.join(" ")} aria-label="healing">
<Tooltip
title={tooltips.join(", ")}
enabled={showTooltip}
isDarkMode={theme?.isDarkMode}
>
<SvgIcon className="ddbc-healing-icon__icon" />
</Tooltip>
</span>
);
}
}
@@ -0,0 +1,40 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
import { DarkModePositiveImmunitySvg, PositiveImmunitySvg } from "../../Svg";
interface SvgInjectedProps {
className?: string;
}
interface Props {
title: string;
className: string;
theme?: CharacterTheme;
secondaryFill?: string;
}
export default class ImmunityIcon extends React.PureComponent<Props> {
static defaultProps = {
title: "Immunity",
className: "",
theme: {},
};
render() {
const { title, className, theme } = this.props;
let classNames: Array<string> = [className, "ddbc-immunity-icon"];
let SvgIcon: React.ComponentType<SvgInjectedProps> = theme?.isDarkMode
? DarkModePositiveImmunitySvg
: PositiveImmunitySvg;
return (
<Tooltip title={title} isDarkMode={theme?.isDarkMode}>
<SvgIcon className={classNames.join(" ")} />
</Tooltip>
);
}
}
@@ -0,0 +1,97 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
interface Props {
className: string;
tooltip: string;
onClick?: () => void;
enableTooltip: boolean;
showIconOnEdge: boolean;
showIcon: boolean;
theme: CharacterTheme;
}
export default class ManageIcon extends React.PureComponent<Props> {
static defaultProps = {
tooltip: "Manage",
enableTooltip: true,
showIconOnEdge: true,
showIcon: true,
className: "",
};
handleClick = (evt: React.MouseEvent): void => {
const { onClick } = this.props;
if (onClick) {
evt.stopPropagation();
evt.nativeEvent.stopImmediatePropagation();
onClick();
}
};
render() {
const {
tooltip,
children,
onClick,
enableTooltip,
showIconOnEdge,
showIcon,
className,
theme,
} = this.props;
let classNames: Array<string> = [className, "ddbc-manage-icon"];
if (showIconOnEdge) {
classNames.push("ddbc-manage-icon--edge-icon");
}
if (showIcon) {
classNames.push("ddbc-manage-icon--interactive");
}
if (theme?.isDarkMode) {
classNames.push("ddbc-manage-icon--dark-mode");
}
let contentNode: React.ReactNode = (
<React.Fragment>
{children && (
<span className="ddbc-manage-icon__content">{children}</span>
)}
{showIcon && (
<span
className={`ddbc-manage-icon__icon ${
theme?.isDarkMode ? `ddbc-manage-icon__icon--dark-mode` : ""
}`}
/>
)}
</React.Fragment>
);
if (enableTooltip) {
return (
<Tooltip
title={tooltip}
className={classNames.join(" ")}
onClick={onClick}
isInteractive={true}
isDarkMode={theme?.isDarkMode}
>
{contentNode}
</Tooltip>
);
}
return (
<span
className={classNames.join(" ")}
onClick={this.handleClick}
role="button"
aria-label="Manage"
>
{contentNode}
</span>
);
}
}
@@ -0,0 +1,46 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import {
CharacterTheme,
Constants,
} from "@dndbeyond/character-rules-engine/es";
import { ModifiedProficiencyHalfSvg, ProficiencyHalfSvg } from "../../../Svg";
interface Props {
isModified: boolean;
className: string;
theme?: CharacterTheme;
}
export default class HalfProficiencyIcon extends React.PureComponent<Props> {
static defaultProps = {
isModified: false,
className: "",
};
render() {
const { isModified, className, theme } = this.props;
let IconComponent: React.ComponentType<any> = isModified
? ModifiedProficiencyHalfSvg
: ProficiencyHalfSvg;
let classNames: Array<string> = ["ddbc-half-proficiency-icon", className];
if (isModified) {
classNames.push("ddbc-half-proficiency-icon--modified");
}
let fillColor;
if (theme?.isDarkMode) {
fillColor = isModified
? Constants.CharacterColorEnum.DARKMODE_TEXT
: theme?.themeColor;
}
return (
<Tooltip title="Half Proficiency" isDarkMode={theme?.isDarkMode}>
<IconComponent className={classNames.join(" ")} fillColor={fillColor} />
</Tooltip>
);
}
}
@@ -0,0 +1,4 @@
import HalfProficiencyIcon from "./HalfProficiencyIcon";
export default HalfProficiencyIcon;
export { HalfProficiencyIcon };
@@ -0,0 +1,35 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
interface Props {
isModified: boolean;
className: string;
theme?: CharacterTheme;
}
export default class NoProficiencyIcon extends React.PureComponent<Props> {
static defaultProps = {
isModified: false,
className: "",
};
render() {
const { isModified, className, theme } = this.props;
let classNames: Array<string> = ["ddbc-no-proficiency-icon", className];
if (isModified) {
classNames.push("ddbc-no-proficiency-icon--modified");
}
if (theme?.isDarkMode) {
classNames.push("ddbc-no-proficiency-icon--dark-mode");
}
return (
<Tooltip title="Not Proficient" isDarkMode={theme?.isDarkMode}>
<span className={classNames.join(" ")} />
</Tooltip>
);
}
}
@@ -0,0 +1,4 @@
import NoProficiencyIcon from "./NoProficiencyIcon";
export default NoProficiencyIcon;
export { NoProficiencyIcon };
@@ -0,0 +1,50 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import {
CharacterTheme,
Constants,
} from "@dndbeyond/character-rules-engine/es";
import { ProficiencySvg, ModifiedProficiencySvg } from "../../../Svg";
interface Props {
isModified: boolean;
className: string;
theme?: CharacterTheme;
}
export default class ProficiencyIcon extends React.PureComponent<Props> {
static defaultProps = {
isModified: false,
className: "",
};
render() {
const { isModified, className, theme } = this.props;
let IconComponent: React.ComponentType<any> = isModified
? ModifiedProficiencySvg
: ProficiencySvg;
let classNames: Array<string> = ["ddbc-proficiency-icon", className];
if (isModified) {
classNames.push("ddbc-proficiency-icon--modified");
}
return (
<Tooltip title="Proficiency" isDarkMode={theme?.isDarkMode}>
<IconComponent
className={classNames.join(" ")}
fillColor={
theme?.isDarkMode && !isModified
? theme.themeColor
: theme?.isDarkMode
? Constants.CharacterColorEnum.DARKMODE_TEXT
: undefined
}
/>
</Tooltip>
);
}
}
@@ -0,0 +1,4 @@
import ProficiencyIcon from "./ProficiencyIcon";
export default ProficiencyIcon;
export { ProficiencyIcon };
@@ -0,0 +1,63 @@
import * as React from "react";
import {
CharacterTheme,
Constants,
} from "@dndbeyond/character-rules-engine/es";
import HalfProficiencyIcon from "./HalfProficiencyIcon";
import NoProficiencyIcon from "./NoProficiencyIcon";
import ProficiencyIcon from "./ProficiencyIcon";
import TwiceProficiencyIcon from "./TwiceProficiencyIcon";
interface Props {
proficiencyLevel: number;
isModified: boolean;
theme?: CharacterTheme;
}
export default class ProficiencyLevelIcon extends React.PureComponent<Props> {
static defaultProps = {
isModified: false,
};
render() {
const { proficiencyLevel, isModified, theme } = this.props;
let IconComponent: React.ComponentType<any> | null = null;
let proficiencyVerbiage: string = "Not Proficient";
switch (proficiencyLevel) {
case Constants.ProficiencyLevelEnum.NONE:
IconComponent = NoProficiencyIcon;
break;
case Constants.ProficiencyLevelEnum.HALF:
IconComponent = HalfProficiencyIcon;
proficiencyVerbiage = "Half Proficient";
break;
case Constants.ProficiencyLevelEnum.FULL:
IconComponent = ProficiencyIcon;
proficiencyVerbiage = "Proficient";
break;
case Constants.ProficiencyLevelEnum.EXPERT:
IconComponent = TwiceProficiencyIcon;
proficiencyVerbiage = "Expert";
break;
default:
//not implemented
}
if (IconComponent === null) {
return null;
}
return (
<span aria-label={proficiencyVerbiage}>
<IconComponent
className="ddbc-proficiency-level-icon"
isModified={isModified}
theme={theme}
/>
</span>
);
}
}
@@ -0,0 +1,56 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import {
CharacterTheme,
Constants,
} from "@dndbeyond/character-rules-engine/es";
import {
ModifiedProficiencyDoubleSvg,
ProficiencyDoubleSvg,
} from "../../../Svg";
interface Props {
isModified: boolean;
className: string;
theme?: CharacterTheme;
}
export default class TwiceProficiencyIcon extends React.PureComponent<Props> {
static defaultProps = {
isModified: false,
className: "",
};
render() {
const { isModified, className, theme } = this.props;
let IconComponent: React.ComponentType<any> = isModified
? ModifiedProficiencyDoubleSvg
: ProficiencyDoubleSvg;
let classNames: Array<string> = ["ddbc-twice-proficiency-icon", className];
if (isModified) {
classNames.push("ddbc-twice-proficiency-icon--modified");
}
let secondaryFill;
if (theme?.isDarkMode) {
secondaryFill = isModified
? Constants.CharacterColorEnum.DARKMODE_TEXT
: theme?.themeColor;
}
return (
<Tooltip title="Expertise" isDarkMode={theme?.isDarkMode}>
<span className={classNames.join(" ")}>
<IconComponent
className="ddbc-twice-proficiency-icon__inner"
fillColor={theme?.isDarkMode ? theme.themeColor : undefined}
secondaryFillColor={secondaryFill}
/>
</span>
</Tooltip>
);
}
}
@@ -0,0 +1,4 @@
import TwiceProficiencyIcon from "./TwiceProficiencyIcon";
export default TwiceProficiencyIcon;
export { TwiceProficiencyIcon };
@@ -0,0 +1,43 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
import {
PositiveResistanceSvg,
DarkModePositiveResistanceSvg,
} from "../../Svg";
interface SvgInjectedProps {
className?: string;
}
interface Props {
title: string;
className: string;
theme?: CharacterTheme;
secondaryFill?: string;
}
export default class ResistanceIcon extends React.PureComponent<Props> {
static defaultProps = {
title: "Resistance",
className: "",
theme: {},
};
render() {
const { title, className, theme } = this.props;
let classNames: Array<string> = [className, "ddbc-resistance-icon"];
let SvgIcon: React.ComponentType<SvgInjectedProps> = theme?.isDarkMode
? DarkModePositiveResistanceSvg
: PositiveResistanceSvg;
return (
<Tooltip title={title} isDarkMode={theme?.isDarkMode}>
<SvgIcon className={classNames.join(" ")} />
</Tooltip>
);
}
}
@@ -0,0 +1,4 @@
import ResistanceIcon from "./ResistanceIcon";
export default ResistanceIcon;
export { ResistanceIcon };
@@ -0,0 +1,57 @@
import clsx from "clsx";
import * as React from "react";
import { v4 as uuidv4 } from "uuid";
import { Tooltip } from "~/components/Tooltip";
import { DarkRitualSvg, GrayRitualSvg, LightRitualSvg } from "../../Svg";
import styles from "./styles.module.css";
interface SvgInjectedProps {
className?: string;
}
interface Props {
themeMode?: "dark" | "gray" | "light";
className: string;
}
export default class RitualIcon extends React.PureComponent<Props> {
static defaultProps = {
className: "",
themeMode: "dark",
};
render() {
const { themeMode, className, ...props } = this.props;
const id = uuidv4();
let SvgIcon: React.ComponentType<SvgInjectedProps> | null = null;
switch (themeMode) {
case "light":
SvgIcon = LightRitualSvg;
break;
case "gray":
SvgIcon = GrayRitualSvg;
break;
case "dark":
default:
SvgIcon = DarkRitualSvg;
}
if (SvgIcon === null) {
return null;
}
return (
<div
className={clsx([styles.ritualIcon, className])}
data-tooltip-id={id}
data-tooltip-content="Ritual"
>
<SvgIcon className={styles.svg} {...props} />
<Tooltip id={id} />
</div>
);
}
}
@@ -0,0 +1,140 @@
import * as React from "react";
import {
DarkAbjurationSvg,
DarkConjurationSvg,
DarkDivinationSvg,
DarkEnchantmentSvg,
DarkEvocationSvg,
DarkIllusionSvg,
DarkNecromancySvg,
DarkTransmutationSvg,
GrayAbjurationSvg,
GrayConjurationSvg,
GrayDivinationSvg,
GrayEnchantmentSvg,
GrayEvocationSvg,
GrayIllusionSvg,
GrayNecromancySvg,
GrayTransmutationSvg,
LightAbjurationSvg,
LightConjurationSvg,
LightDivinationSvg,
LightEnchantmentSvg,
LightEvocationSvg,
LightIllusionSvg,
LightNecromancySvg,
LightTransmutationSvg,
} from "../../Svg";
import { SpellSchoolPropType } from "../IconConstants";
interface SvgInjectedProps {
className?: string;
}
interface Props {
school: SpellSchoolPropType;
themeMode?: "dark" | "gray" | "light";
className?: string;
}
const SpellSchoolIcon: React.FunctionComponent<Props> = ({
className = "",
themeMode = "dark",
school,
}) => {
const DarkSvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (school) {
case "abjuration":
return DarkAbjurationSvg;
case "conjuration":
return DarkConjurationSvg;
case "divination":
return DarkDivinationSvg;
case "enchantment":
return DarkEnchantmentSvg;
case "evocation":
return DarkEvocationSvg;
case "illusion":
return DarkIllusionSvg;
case "necromancy":
return DarkNecromancySvg;
case "transmutation":
return DarkTransmutationSvg;
default:
return null;
}
};
const GraySvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (school) {
case "abjuration":
return GrayAbjurationSvg;
case "conjuration":
return GrayConjurationSvg;
case "divination":
return GrayDivinationSvg;
case "enchantment":
return GrayEnchantmentSvg;
case "evocation":
return GrayEvocationSvg;
case "illusion":
return GrayIllusionSvg;
case "necromancy":
return GrayNecromancySvg;
case "transmutation":
return GrayTransmutationSvg;
default:
return null;
}
};
const LightSvg = (): React.ComponentType<SvgInjectedProps> | null => {
switch (school) {
case "abjuration":
return LightAbjurationSvg;
case "conjuration":
return LightConjurationSvg;
case "divination":
return LightDivinationSvg;
case "enchantment":
return LightEnchantmentSvg;
case "evocation":
return LightEvocationSvg;
case "illusion":
return LightIllusionSvg;
case "necromancy":
return LightNecromancySvg;
case "transmutation":
return LightTransmutationSvg;
default:
return null;
}
};
let classNames: Array<string> = [
className,
"ddbc-spell-school-icon",
`ddbc-spell-school-icon--${school}`,
];
let SvgIcon: React.ComponentType<SvgInjectedProps> | null = null;
switch (themeMode) {
case "light":
SvgIcon = LightSvg();
break;
case "gray":
SvgIcon = GraySvg();
break;
case "dark":
default:
SvgIcon = DarkSvg();
}
if (SvgIcon === null) {
return null;
}
return <SvgIcon className={classNames.join(" ")} />;
};
export default SpellSchoolIcon;
@@ -0,0 +1,33 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
interface Props {
title: string;
className: string;
theme?: CharacterTheme;
}
export default class TodoIcon extends React.PureComponent<Props> {
static defaultProps = {
title: "Missing",
className: "",
};
render() {
const { title, className, theme } = this.props;
let classNames: Array<string> = [className, "ddbc-todo-icon"];
return (
<Tooltip
title={title}
className={classNames.join(" ")}
isDarkMode={theme?.isDarkMode}
>
!
</Tooltip>
);
}
}
@@ -0,0 +1,4 @@
import TodoIcon from "./TodoIcon";
export default TodoIcon;
export { TodoIcon };
@@ -0,0 +1,43 @@
import * as React from "react";
import { Tooltip } from "@dndbeyond/character-common-components/es";
import { CharacterTheme } from "@dndbeyond/character-rules-engine/es";
import {
DarkModeNegativeVulnerabilitySvg,
NegativeVulnerabilitySvg,
} from "../../Svg";
interface SvgInjectedProps {
className?: string;
}
interface Props {
title: string;
className: string;
theme?: CharacterTheme;
secondaryFill?: string;
}
export default class VulnerabilityIcon extends React.PureComponent<Props> {
static defaultProps = {
title: "Vulnerability",
className: "",
theme: {},
};
render() {
const { title, className, theme } = this.props;
let classNames: Array<string> = [className, "ddbc-vulnerability-icon"];
let SvgIcon: React.ComponentType<SvgInjectedProps> = theme?.isDarkMode
? DarkModeNegativeVulnerabilitySvg
: NegativeVulnerabilitySvg;
return (
<Tooltip title={title} isDarkMode={theme?.isDarkMode}>
<SvgIcon className={classNames.join(" ")} />
</Tooltip>
);
}
}