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,249 @@
import { orderBy } from "lodash";
import React from "react";
import { connect, DispatchProp } from "react-redux";
import {
Collapsible,
ProficiencyLevelIcon,
} from "@dndbeyond/character-components/es";
import {
rulesEngineSelectors,
characterActions,
Constants,
RuleData,
RuleDataUtils,
Skill,
SkillUtils,
ValueLookup,
ValueUtils,
CharacterTheme,
} from "@dndbeyond/character-rules-engine/es";
import { Link } from "~/components/Link";
import { NumberDisplay } from "~/components/NumberDisplay";
import { useSidebar } from "~/contexts/Sidebar";
import { PaneInfo } from "~/contexts/Sidebar/Sidebar";
import { Header } from "~/subApps/sheet/components/Sidebar/components/Header";
import { PaneComponentEnum } from "~/subApps/sheet/components/Sidebar/types";
import { appEnvSelectors } from "../../../selectors";
import { SharedAppState } from "../../../stores/typings";
import { PaneIdentifierUtils } from "../../../utils";
interface Props extends DispatchProp {
skills: Array<Skill>;
customSkills: Array<Skill>;
ruleData: RuleData;
valueLookup: ValueLookup;
proficiencyBonus: number;
isReadonly: boolean;
theme: CharacterTheme;
paneHistoryPush: PaneInfo["paneHistoryPush"];
}
class SkillsPane extends React.PureComponent<Props> {
handleCustomSkillClick = (skill: Skill): void => {
const { paneHistoryPush } = this.props;
paneHistoryPush(
PaneComponentEnum.CUSTOM_SKILL,
PaneIdentifierUtils.generateCustomSkill(SkillUtils.getId(skill))
);
};
handleSkillAdd = (): void => {
const { dispatch, customSkills } = this.props;
dispatch(
characterActions.customProficiencyCreate(
`Custom Skill ${customSkills.length + 1}`,
Constants.CustomProficiencyTypeEnum.SKILL
)
);
};
handleDataUpdate = (id: number, properties: Record<string, any>): void => {
const { dispatch } = this.props;
dispatch(characterActions.customProficiencySet(id, properties));
};
handleSkillClick = (skill: Skill, evt: React.MouseEvent): void => {
const { paneHistoryPush } = this.props;
evt.stopPropagation();
evt.nativeEvent.stopImmediatePropagation();
paneHistoryPush(
PaneComponentEnum.SKILL,
PaneIdentifierUtils.generateSkill(SkillUtils.getId(skill))
);
};
renderCustomSkills = (): React.ReactNode => {
const { customSkills, ruleData, isReadonly, theme } = this.props;
return (
<Collapsible header="Custom Skills">
<div className="ct-skills-pane__custom">
<div className="ct-skills-pane__custom-skills">
{customSkills.map((skill) => {
const id = SkillUtils.getId(skill);
const modifier = SkillUtils.getModifier(skill);
const statName = RuleDataUtils.getAbilityShortName(
SkillUtils.getStat(skill),
ruleData
);
const proficiencyLevel = SkillUtils.getProficiencyLevel(skill);
const name = SkillUtils.getName(skill);
return (
<div
key={id}
className="ct-skills__item"
onClick={this.handleCustomSkillClick.bind(this, skill)}
>
<div className="ct-skills__col--proficiency">
<ProficiencyLevelIcon
theme={theme}
proficiencyLevel={proficiencyLevel}
/>
</div>
<div className="ct-skills__col--stat">
{statName === null ? "--" : statName}
</div>
<div className="ct-skills__col--skill">{name}</div>
<div className={"ct-skills__col--modifier"}>
<NumberDisplay type="signed" number={modifier} />
</div>
</div>
);
})}
</div>
{!isReadonly && (
<div className="ct-skills-pane__custom-add">
<Link useTheme={true} onClick={this.handleSkillAdd}>
+ Add Custom Skill
</Link>
</div>
)}
</div>
</Collapsible>
);
};
renderSkills = (): React.ReactNode => {
const { skills, ruleData, valueLookup, theme } = this.props;
let statsLookup = RuleDataUtils.getStatsLookup(ruleData);
let orderedSkills = orderBy(skills, (skill) => skill.name);
return (
<Collapsible header="Skills" initiallyCollapsed={false}>
<div className="ct-skills-pane__skills">
{orderedSkills.map((skill) => {
let valueTypes: Array<Constants.AdjustmentTypeEnum> = [
Constants.AdjustmentTypeEnum.SKILL_STAT_OVERRIDE,
Constants.AdjustmentTypeEnum.SKILL_PROFICIENCY_LEVEL,
Constants.AdjustmentTypeEnum.SKILL_MISC_BONUS,
Constants.AdjustmentTypeEnum.SKILL_MAGIC_BONUS,
Constants.AdjustmentTypeEnum.SKILL_OVERRIDE,
];
let valueDataLookup = ValueUtils.getDataLookup(
valueLookup,
valueTypes,
ValueUtils.hack__toString(skill.id),
ValueUtils.hack__toString(skill.entityTypeId)
);
let hasModifiedLevel = valueDataLookup.hasOwnProperty(
Constants.AdjustmentTypeEnum.SKILL_PROFICIENCY_LEVEL
);
let hasModifiedValue =
valueDataLookup.hasOwnProperty(
Constants.AdjustmentTypeEnum.SKILL_OVERRIDE
) ||
valueDataLookup.hasOwnProperty(
Constants.AdjustmentTypeEnum.SKILL_MAGIC_BONUS
) ||
valueDataLookup.hasOwnProperty(
Constants.AdjustmentTypeEnum.SKILL_MISC_BONUS
);
let statClassNames: Array<string> = ["ct-skills__col--stat"];
if (
valueDataLookup.hasOwnProperty(
Constants.AdjustmentTypeEnum.SKILL_STAT_OVERRIDE
)
) {
statClassNames.push("ct-skills__col--stat-modified");
}
let modifierClassNames: Array<string> = [
"ct-skills__col--modifier",
];
if (hasModifiedValue) {
modifierClassNames.push("ct-skills__col--modifier-modified");
}
const id = SkillUtils.getId(skill);
const modifier = SkillUtils.getModifier(skill);
const statName = RuleDataUtils.getAbilityShortName(
SkillUtils.getStat(skill),
ruleData
);
const proficiencyLevel = SkillUtils.getProficiencyLevel(skill);
const name = SkillUtils.getName(skill);
return (
<div
key={id}
className="ct-skills__item"
onClick={this.handleSkillClick.bind(this, skill)}
>
<div className="ct-skills__col--proficiency">
<ProficiencyLevelIcon
theme={theme}
isModified={hasModifiedLevel}
proficiencyLevel={proficiencyLevel}
/>
</div>
<div className={statClassNames.join(" ")}>{statName}</div>
<div className="ct-skills__col--skill">{name}</div>
<div className={modifierClassNames.join(" ")}>
<NumberDisplay type="signed" number={modifier} />
</div>
</div>
);
})}
</div>
</Collapsible>
);
};
render() {
return (
<div className="ct-skills-pane">
<Header>All Skills</Header>
{this.renderSkills()}
{this.renderCustomSkills()}
</div>
);
}
}
function mapStateToProps(state: SharedAppState) {
return {
proficiencyBonus: rulesEngineSelectors.getProficiencyBonus(state),
skills: rulesEngineSelectors.getSkills(state),
customSkills: rulesEngineSelectors.getCustomSkills(state),
ruleData: rulesEngineSelectors.getRuleData(state),
valueLookup: rulesEngineSelectors.getCharacterValueLookup(state),
isReadonly: appEnvSelectors.getIsReadonly(state),
};
}
const SkillsPaneContainer = (props) => {
const {
pane: { paneHistoryPush },
} = useSidebar();
return <SkillsPane paneHistoryPush={paneHistoryPush} {...props} />;
};
export default connect(mapStateToProps)(SkillsPaneContainer);
@@ -0,0 +1,4 @@
import SkillsPane from "./SkillsPane";
export default SkillsPane;
export { SkillsPane };