New source found from dndbeyond.com
This commit is contained in:
@@ -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);
|
||||
|
||||
+4
-3
@@ -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>
|
||||
|
||||
-62
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
-5
@@ -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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user