New source found from dndbeyond.com

This commit is contained in:
2026-07-08 01:00:09 -07:00
parent 9a983a6d7b
commit dcefa0d2f2
2865 changed files with 222467 additions and 49053 deletions
@@ -1,7 +1,8 @@
import React from "react";
import { connect, DispatchProp } from "react-redux";
import { useSearchParams } from "react-router-dom";
import { AnyAction } from "redux";
import { PrivacyTypeRadio } from "@dndbeyond/character-components/es";
import {
AnySimpleDataType,
characterActions,
@@ -21,8 +22,9 @@ import {
rulesEngineSelectors,
RaceUtils,
} from "@dndbeyond/character-rules-engine/es";
import { Dice } from "@dndbeyond/dice";
import { CheckboxGroup, CheckboxInfo } from "~/components/CheckboxGroup";
import { PrivacyTypeRadio } from "~/components/PrivacyTypeRadio";
import { SourceCategoryDescription } from "~/constants";
import { useSidebar } from "~/contexts/Sidebar";
import { PaneInfo } from "~/contexts/Sidebar/Sidebar";
@@ -31,17 +33,15 @@ import { PaneComponentEnum } from "~/subApps/sheet/components/Sidebar/types";
import config from "../../../../config";
import { appEnvActions } from "../../../actions";
import {
CheckboxInfo,
FormCheckBoxesField,
} from "../../../components/common/FormCheckBoxesField";
import { appEnvSelectors } from "../../../selectors";
import { SharedAppState } from "../../../stores/typings";
import { PaneIdentifierUtils } from "../../../utils";
import PreferencesPaneSelectField from "./PreferencesPaneSelectField";
import { ToggleInfo } from "./PreferencesPaneTogglesField";
import styles from "./styles.module.css";
interface Props extends DispatchProp {
// TODO: We are typing with AnyAction here to work around issues with UnknownAction, the type that was introduced in Redux 5.
// If we decide to modernize to Redux 5, we will need to refactor much of the Rules Engine redux usage.
interface Props extends DispatchProp<AnyAction> {
activeSourceCategories: Array<number>;
preferences: CharacterPreferences;
ruleData: RuleData;
@@ -52,10 +52,12 @@ interface Props extends DispatchProp {
classSpellListSpellsLookup: ClassSpellListSpellsLookup;
characterTheme: CharacterTheme;
paneHistoryStart: PaneInfo["paneHistoryStart"];
isVttView: boolean;
}
class PreferencesPane extends React.PureComponent<Props> {
static defaultProps = {
diceEnabled: false,
isVttView: false,
};
handlePreferenceChange = (
@@ -80,6 +82,7 @@ class PreferencesPane extends React.PureComponent<Props> {
handleSourceCategoryChange = (sourceId: number, isActive: boolean): void => {
const { dispatch, activeSourceCategories } = this.props;
let newSourceCats: Array<number> = [];
if (isActive) {
newSourceCats = [...activeSourceCategories, sourceId];
} else {
@@ -208,7 +211,6 @@ class PreferencesPane extends React.PureComponent<Props> {
try {
localStorage.setItem("dice-enabled", newDiceEnabledSetting.toString());
Dice.setEnabled(newDiceEnabledSetting);
} catch (e) {}
dispatch(
@@ -228,8 +230,13 @@ class PreferencesPane extends React.PureComponent<Props> {
};
render() {
const { preferences, activeSourceCategories, ruleData, diceEnabled } =
this.props;
const {
preferences,
activeSourceCategories,
ruleData,
diceEnabled,
isVttView,
} = this.props;
const {
useHomebrewContent,
@@ -237,7 +244,6 @@ class PreferencesPane extends React.PureComponent<Props> {
hitPointType,
progressionType,
abilityScoreDisplayType,
sharingType,
privacyType,
ignoreCoinWeight,
enforceFeatRules,
@@ -288,12 +294,6 @@ class PreferencesPane extends React.PureComponent<Props> {
},
];
const sharingOptions: Array<HtmlSelectOption> = [
{ label: "Full", value: Constants.PreferenceSharingTypeEnum.FULL },
{ label: "Limited", value: Constants.PreferenceSharingTypeEnum.LIMITED },
// {label: 'Stat Block', value: Constants.PreferenceSharingTypeEnum.STAT_BLOCK},
];
let sourceToggles: Array<CheckboxInfo> = [];
let partneredSourceToggles: Array<CheckboxInfo> = [];
@@ -302,10 +302,11 @@ class PreferencesPane extends React.PureComponent<Props> {
return null;
}
const toggle: ToggleInfo = {
const toggle: CheckboxInfo = {
label: `${sourceCategory.name}`,
initiallyEnabled: activeSourceCategories.includes(sourceCategory.id),
onChange: this.handleSourceCategoryChange.bind(this, sourceCategory.id),
onChange: (e) =>
this.handleSourceCategoryChange(sourceCategory.id, e.target.checked),
sortOrder: sourceCategory.sortOrder,
};
@@ -319,96 +320,95 @@ class PreferencesPane extends React.PureComponent<Props> {
return (
<div className="ct-preferences-pane">
<Header>Preferences</Header>
<FormCheckBoxesField
heading="Sources"
<CheckboxGroup
className={styles.checkboxGroup}
title="Sources"
description={SourceCategoryDescription.official}
name="source-categories"
checkboxes={[
...sourceToggles,
{
label: "Homebrew",
initiallyEnabled: useHomebrewContent,
onChange: this.handlePreferenceChange.bind(
this,
"useHomebrewContent"
),
onChange: (e) =>
this.handlePreferenceChange(
"useHomebrewContent",
e.target.checked
),
sortOrder: 0,
},
...sourceToggles,
]}
themed={true}
showAccordion={true}
variant="sidebar"
darkMode={enableDarkMode}
variant="collapse"
accordionDefaultOpen={true}
themed
/>
<FormCheckBoxesField
heading="Partnered Content"
<CheckboxGroup
className={styles.checkboxGroup}
title="Partnered Content"
description={SourceCategoryDescription.partnered}
name="partnered-source-categories"
checkboxes={partneredSourceToggles}
checkUncheckAllEnabled={true}
themed={true}
accordionHeading="Categories"
variant="sidebar"
darkMode={enableDarkMode}
showAccordion={true}
variant="collapse"
themed
/>
<FormCheckBoxesField
heading="Underdark Mode"
<CheckboxGroup
className={styles.checkboxGroup}
title="Underdark Mode"
description="Enables dark mode for this character"
name="enable-dark-mode"
variant="inline"
data-testid="underdark-mode-toggle"
checkboxes={[
{
initiallyEnabled: enableDarkMode,
label: "Enable dark mode",
onChange: this.handlePreferenceChange.bind(
this,
"enableDarkMode"
),
onChange: (e) =>
this.handlePreferenceChange("enableDarkMode", e.target.checked),
},
]}
themed={true}
variant="sidebar"
darkMode={enableDarkMode}
themed
/>
<FormCheckBoxesField
heading="Dice Rolling"
description="Enables digital dice rolling for this character"
checkboxes={[
{
initiallyEnabled: diceEnabled,
label: "Enable Dice Rolling",
onChange: this.handleDiceToggle,
},
]}
themed={true}
variant="sidebar"
darkMode={enableDarkMode}
/>
<FormCheckBoxesField
heading="Optional Features"
description="Allow or restrict optional features for this character."
{!isVttView && (
<CheckboxGroup
className={styles.checkboxGroup}
title="Dice Rolling"
description="Enables digital dice rolling for all characters on this browser"
name="enable-dice-rolling"
variant="inline"
checkboxes={[
{
initiallyEnabled: diceEnabled,
label: "Enable Dice Rolling",
onChange: this.handleDiceToggle,
},
]}
themed
/>
)}
<CheckboxGroup
className={styles.checkboxGroup}
title="Optional Features"
description="Allow or restrict optional features for this character"
name="optional-features"
checkboxes={[
{
label: "Optional Class Features",
initiallyEnabled: enableOptionalClassFeatures,
onChangePromise:
onChangeConfirm:
this.handleOptionalClassFeaturesPreferenceChangePromise,
},
{
label: "Customize Your Origin",
initiallyEnabled: enableOptionalOrigins,
onChangePromise:
onChangeConfirm:
this.handleOptionalOriginsPreferenceChangePromise,
},
]}
themed={true}
variant="sidebar"
darkMode={enableDarkMode}
themed
/>
<PreferencesPaneSelectField
className={styles.selectField}
heading="Advancement Type"
description="Story-based character progression / XP-based character progression"
onChangePromise={this.handleProgressionPreferenceChangePromise}
@@ -418,6 +418,7 @@ class PreferencesPane extends React.PureComponent<Props> {
block={true}
/>
<PreferencesPaneSelectField
className={styles.selectField}
heading="Hit Point Type"
description="When leveling up, increase hit points by the fixed value for your chosen class or manually enter a rolled value"
onChangePromise={this.handleHitPointPreferenceChangePromise}
@@ -427,88 +428,93 @@ class PreferencesPane extends React.PureComponent<Props> {
block={true}
/>
<FormCheckBoxesField
heading="Use Prerequisites"
<CheckboxGroup
className={styles.checkboxGroup}
title="Use Prerequisites"
description="Allow or restrict choices based on rule prerequisites for the following for this character"
name="use-prerequisites"
checkboxes={[
{
label: "Feats",
initiallyEnabled: enforceFeatRules,
onChange: this.handlePreferenceChange.bind(
this,
"enforceFeatRules"
),
onChange: (e) =>
this.handlePreferenceChange(
"enforceFeatRules",
e.target.checked
),
},
{
label: "Multiclass Requirements",
initiallyEnabled: enforceMulticlassRules,
onChange: this.handlePreferenceChange.bind(
this,
"enforceMulticlassRules"
),
onChange: (e) =>
this.handlePreferenceChange(
"enforceMulticlassRules",
e.target.checked
),
},
]}
themed={true}
variant="sidebar"
darkMode={enableDarkMode}
/>
<FormCheckBoxesField
heading="Show level-scaled spells"
<CheckboxGroup
className={styles.checkboxGroup}
title="Show level-scaled spells"
description="Display and highlight available spells to cast with higher level spell slots"
name="show-scaled-spells"
variant="inline"
checkboxes={[
{
initiallyEnabled: showScaledSpells,
label: "Show Level-Scaled Spells",
onChange: this.handlePreferenceChange.bind(
this,
"showScaledSpells"
),
onChange: (e) =>
this.handlePreferenceChange(
"showScaledSpells",
e.target.checked
),
},
]}
themed={true}
variant="sidebar"
darkMode={enableDarkMode}
themed
/>
<PreferencesPaneSelectField
className={styles.selectField}
heading="Encumbrance Type"
description="Use the standard encumbrance rules / Disable the encumbrance display / Use the more detailed rules for encumbrance"
onChange={this.handleIntPreferenceChange.bind(
this,
"encumbranceType"
)}
onChange={(value) =>
this.handleIntPreferenceChange("encumbranceType", value)
}
initialOptionRemoved={true}
options={encumbranceOptions}
initialValue={encumbranceType}
block={true}
/>
<FormCheckBoxesField
heading="Ignore Coin Weight"
<CheckboxGroup
className={styles.checkboxGroup}
title="Ignore Coin Weight"
description="Coins do not count against your total weight carried (50 coins weigh 1 lb.)"
name="ignore-coin-weight"
variant="inline"
checkboxes={[
{
initiallyEnabled: ignoreCoinWeight,
label: "Ignore Coin Weight",
onChange: this.handlePreferenceChange.bind(
this,
"ignoreCoinWeight"
),
onChange: (e) =>
this.handlePreferenceChange(
"ignoreCoinWeight",
e.target.checked
),
},
]}
themed={true}
variant="sidebar"
darkMode={enableDarkMode}
themed
/>
<PreferencesPaneSelectField
className={styles.selectField}
heading="Ability Score/Modifier Display"
description="Reverse the arrangement of ability modifiers and scores"
onChange={this.handleIntPreferenceChange.bind(
this,
"abilityScoreDisplayType"
)}
onChange={(value) =>
this.handleIntPreferenceChange("abilityScoreDisplayType", value)
}
initialOptionRemoved={true}
options={abilityDisplayOptions}
initialValue={abilityScoreDisplayType}
@@ -516,21 +522,20 @@ class PreferencesPane extends React.PureComponent<Props> {
/>
<PrivacyTypeRadio
handleChange={(e) =>
this.handleChangePrivacy(parseInt(e?.target?.value))
}
darkMode={enableDarkMode}
className={styles.privacyTypeRadio}
initialValue={privacyType}
onChange={(e) =>
this.handleChangePrivacy(
HelperUtils.parseInputInt(e?.target?.value)
)
}
themed={true}
variant="sidebar"
/>
<div className="ct-preferences-pane__version">
<div className="ct-preferences-pane__version-label">Version:</div>
<div className="ct-preferences-pane__version-value">
{config.version}
</div>
</div>
<footer className={styles.footer}>
<strong>Version:</strong>
{config.version || "@dndbeyond/character-app@dev"}
</footer>
</div>
);
}
@@ -556,7 +561,15 @@ const PreferencesPaneContainer = (props) => {
const {
pane: { paneHistoryStart },
} = useSidebar();
return <PreferencesPane paneHistoryStart={paneHistoryStart} {...props} />;
const [searchParams] = useSearchParams();
const isVttView = searchParams.get("view") === "vtt";
return (
<PreferencesPane
paneHistoryStart={paneHistoryStart}
isVttView={isVttView}
{...props}
/>
);
};
export default connect(mapStateToProps)(PreferencesPaneContainer);
@@ -1,12 +1,12 @@
import { uniqueId } from "lodash";
import React from "react";
import { Select } from "@dndbeyond/character-components/es";
import {
HelperUtils,
HtmlSelectOption,
} from "@dndbeyond/character-rules-engine/es";
import { Select } from "~/components/Select";
import { Heading } from "~/subApps/sheet/components/Sidebar/components/Heading";
interface Props {
@@ -141,12 +141,13 @@ export default class PreferencesPaneSelectField extends React.PureComponent<
<Select
options={options}
onChange={onChange ? this.handleChange : undefined}
onChangePromise={
onChangeConfirm={
onChangePromise ? this.handleChangePromise : undefined
}
value={value}
initialOptionRemoved={initialOptionRemoved}
hidePlaceholderOption={initialOptionRemoved}
placeholder={placeholder}
name={uId}
/>
</div>
</div>
@@ -1,62 +0,0 @@
import { orderBy } from "lodash";
import React from "react";
import { Toggle } from "~/components/Toggle";
import { Heading } from "~/subApps/sheet/components/Sidebar/components/Heading";
import { ToggleInfo } from "./typings";
interface Props {
toggles: Array<ToggleInfo>;
heading: React.ReactNode;
description: string;
}
export default class PreferencesPaneTogglesField extends React.PureComponent<Props> {
static defaultProps = {
initiallyEnabled: false,
};
render() {
const { heading, description, toggles } = this.props;
if (!toggles.length) {
return null;
}
const sortedToggles = orderBy(toggles, "sortOrder");
return (
<div className="ct-preferences-pane__field ct-preferences-pane__field--toggle">
<div className="ct-preferences-pane__field-summary">
<Heading className="ct-preferences-pane__field-heading">
{heading}
</Heading>
{description && (
<div className="ct-preferences-pane__field-description">
{description}
</div>
)}
</div>
<div className="ct-preferences-pane__field-toggles">
{sortedToggles.map((toggle, idx) => (
<div className="ct-preferences-pane__field-toggle" key={idx}>
<div className="ct-preferences-pane__field-input">
<Toggle
checked={toggle.initiallyEnabled}
onClick={toggle.onChange}
onChangePromise={toggle.onChangePromise}
color="themed"
aria-label={toggle.label}
/>
</div>
<div className="ct-preferences-pane__field-label">
{toggle.label}
</div>
</div>
))}
</div>
</div>
);
}
}
@@ -1,5 +0,0 @@
import PreferencesPaneTogglesField from "./PreferencesPaneTogglesField";
export * from "./typings";
export default PreferencesPaneTogglesField;
export { PreferencesPaneTogglesField };
@@ -1,12 +1,10 @@
import PreferencesPane from "./PreferencesPane";
import PreferencesPaneSelectField from "./PreferencesPaneSelectField";
import PreferencesPaneToggleField from "./PreferencesPaneToggleField";
import PreferencesPaneTogglesField from "./PreferencesPaneTogglesField";
export default PreferencesPane;
export {
PreferencesPane,
PreferencesPaneSelectField,
PreferencesPaneToggleField,
PreferencesPaneTogglesField,
};