New source found from dndbeyond.com
This commit is contained in:
@@ -29,14 +29,8 @@ export const ArmorListItem: FC<ArmorListItemProps> = ({
|
||||
...props
|
||||
}) => {
|
||||
const actions = useEquipmentMethods();
|
||||
const {
|
||||
ruleData,
|
||||
proficiencyBonus,
|
||||
characterTheme,
|
||||
itemUtils,
|
||||
helperUtils,
|
||||
containerLookup,
|
||||
} = useCharacterEngine();
|
||||
const { ruleData, characterTheme, itemUtils, helperUtils, containerLookup } =
|
||||
useCharacterEngine();
|
||||
const image = itemUtils.getAvatarUrl(item);
|
||||
const altText = itemUtils.getName(item);
|
||||
const container = helperUtils.lookupDataOrFallback(
|
||||
@@ -74,7 +68,6 @@ export const ArmorListItem: FC<ArmorListItemProps> = ({
|
||||
ruleData={ruleData}
|
||||
showCustomize={false}
|
||||
showActions={false}
|
||||
proficiencyBonus={proficiencyBonus}
|
||||
/>
|
||||
<EquipmentListItemActions item={item} {...actions} {...props} />
|
||||
</Accordion>
|
||||
|
||||
+1
-104
@@ -7,87 +7,6 @@ import {
|
||||
ItemUtils,
|
||||
} from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import Collapsible, { CollapsibleHeader } from "../common/Collapsible";
|
||||
|
||||
export class EquipmentListItemHeaderAction extends React.PureComponent<{
|
||||
item: Item;
|
||||
heading: any;
|
||||
metaItems: Array<string>;
|
||||
imageUrl: string;
|
||||
|
||||
onUnequip?: (item: Item) => void;
|
||||
onEquip?: (item: Item) => void;
|
||||
|
||||
unequipLabel: string;
|
||||
equipLabel: string;
|
||||
}> {
|
||||
static defaultProps = {
|
||||
showHeaderAction: false,
|
||||
consumeLabel: "Consume",
|
||||
};
|
||||
|
||||
handleUnequip = () => {
|
||||
const { onUnequip, item } = this.props;
|
||||
|
||||
if (onUnequip) {
|
||||
onUnequip(item);
|
||||
}
|
||||
};
|
||||
|
||||
handleEquip = () => {
|
||||
const { onEquip, item } = this.props;
|
||||
|
||||
if (onEquip) {
|
||||
onEquip(item);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { item, heading, imageUrl, metaItems, unequipLabel, equipLabel } =
|
||||
this.props;
|
||||
|
||||
const isEquipped = ItemUtils.isEquipped(item);
|
||||
const isStackable = ItemUtils.isStackable(item);
|
||||
const canEquip = ItemUtils.canEquip(item);
|
||||
const quantity = ItemUtils.getQuantity(item);
|
||||
|
||||
const callout = (
|
||||
<div className="equipment-list-item-callout">
|
||||
{isStackable && (
|
||||
<div className="equipment-list-item-callout-quantity">
|
||||
<span className="equipment-list-item-callout-quantity-extra">
|
||||
Qty
|
||||
</span>
|
||||
<span className="equipment-list-item-callout-quantity-value">
|
||||
{quantity}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{canEquip && (
|
||||
<div className="equipment-list-item-callout-action">
|
||||
<Button
|
||||
onClick={isEquipped ? this.handleUnequip : this.handleEquip}
|
||||
style={isEquipped ? "" : "outline"}
|
||||
size="small"
|
||||
>
|
||||
{isEquipped ? unequipLabel : equipLabel}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<CollapsibleHeader
|
||||
imgSrc={imageUrl}
|
||||
heading={heading}
|
||||
metaItems={metaItems}
|
||||
callout={callout}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface EquipmentListItemProps {
|
||||
item: Item;
|
||||
|
||||
@@ -241,7 +160,7 @@ export class EquipmentListItemActions extends React.PureComponent<
|
||||
|
||||
handleAmountBlur = (evt) => {
|
||||
const parsedValue = HelperUtils.parseInputInt(evt.target.value);
|
||||
const clampedValue = HelperUtils.clampInt(parsedValue ? parsedValue : 0, 0);
|
||||
const clampedValue = HelperUtils.clampInt(parsedValue ?? 0, 0);
|
||||
|
||||
this.handleQuantitySave(clampedValue);
|
||||
};
|
||||
@@ -394,25 +313,3 @@ export class EquipmentListItemActions extends React.PureComponent<
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default class EquipmentListItem extends React.PureComponent<{
|
||||
header: any;
|
||||
clsNames: Array<string>;
|
||||
}> {
|
||||
static defaultProps = {
|
||||
clsNames: [],
|
||||
};
|
||||
|
||||
render() {
|
||||
let { header, children, clsNames } = this.props;
|
||||
|
||||
return (
|
||||
<Collapsible
|
||||
trigger={header}
|
||||
clsNames={["equipment-list-item", ...clsNames]}
|
||||
>
|
||||
{children}
|
||||
</Collapsible>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import EquipmentListItem, {
|
||||
EquipmentListItemActions,
|
||||
EquipmentListItemHeaderAction,
|
||||
} from "./EquipmentListItem";
|
||||
|
||||
export default EquipmentListItem;
|
||||
export {
|
||||
EquipmentListItem,
|
||||
EquipmentListItemActions,
|
||||
EquipmentListItemHeaderAction,
|
||||
};
|
||||
+31
-80
@@ -3,7 +3,6 @@ import React from "react";
|
||||
|
||||
import { LoadingPlaceholder, Button } from "@dndbeyond/character-components/es";
|
||||
import {
|
||||
BaseItemDefinitionContract,
|
||||
HelperUtils,
|
||||
Item,
|
||||
ItemUtils,
|
||||
@@ -17,14 +16,14 @@ import {
|
||||
ItemManager,
|
||||
} from "@dndbeyond/character-rules-engine/es";
|
||||
|
||||
import { Accordion } from "~/components/Accordion";
|
||||
import { AccordionSummary } from "~/components/AccordionSummary";
|
||||
import { ItemFilter } from "~/components/ItemFilter";
|
||||
import { ItemName } from "~/components/ItemName";
|
||||
import { LegacyBadge } from "~/components/LegacyBadge";
|
||||
|
||||
import { AppLoggerUtils } from "../../../utils";
|
||||
import ItemDetail from "../../ItemDetail";
|
||||
import EquipmentListItem from "../EquipmentListItem";
|
||||
import { CollapsibleHeader, CollapsibleHeading } from "../common/Collapsible";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
//TODO: This component should be removed and replaced with the EquipmentShop component
|
||||
export class EquipmentManagerShopItem extends React.PureComponent<
|
||||
@@ -38,7 +37,6 @@ export class EquipmentManagerShopItem extends React.PureComponent<
|
||||
minAddAmount: number;
|
||||
maxAddAmount: number;
|
||||
ruleData: RuleData;
|
||||
proficiencyBonus: number;
|
||||
containerDefinitionKey: string;
|
||||
theme: CharacterTheme;
|
||||
},
|
||||
@@ -113,80 +111,28 @@ export class EquipmentManagerShopItem extends React.PureComponent<
|
||||
);
|
||||
};
|
||||
|
||||
renderButtons = () => {
|
||||
const { item } = this.props;
|
||||
|
||||
return (
|
||||
<div className="equipment-list-header-actions">
|
||||
<Button size="small" onClick={this.handleAdd}>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
renderHeader(item, metaItems, defaultImageUrl) {
|
||||
const { theme } = this.props;
|
||||
const { canAttune, avatarUrl } = item.definition;
|
||||
const isLegacy = ItemUtils.isLegacy(item);
|
||||
|
||||
const heading = (
|
||||
<CollapsibleHeading>
|
||||
<div className="equipment-list-heading">
|
||||
<span className="equipment-list-heading-text">
|
||||
<ItemName item={item} />
|
||||
</span>
|
||||
<span className="equipment-list-heading-icons">
|
||||
{canAttune ? (
|
||||
<i className="equipment-list-heading-icon i-req-attunement" />
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</span>
|
||||
{isLegacy && <LegacyBadge variant="margin-left" />}
|
||||
</div>
|
||||
</CollapsibleHeading>
|
||||
);
|
||||
|
||||
let imageUrl = avatarUrl;
|
||||
if (!imageUrl) {
|
||||
imageUrl = defaultImageUrl;
|
||||
}
|
||||
|
||||
return (
|
||||
<CollapsibleHeader
|
||||
imgSrc={imageUrl ? imageUrl : ""}
|
||||
heading={heading}
|
||||
metaItems={metaItems}
|
||||
callout={this.renderButtons()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { amount } = this.state;
|
||||
const {
|
||||
item,
|
||||
minAddAmount,
|
||||
maxAddAmount,
|
||||
ruleData,
|
||||
proficiencyBonus,
|
||||
theme,
|
||||
} = this.props;
|
||||
const { item, minAddAmount, maxAddAmount, ruleData, theme } = this.props;
|
||||
const avatarUrl = ItemUtils.getDefinitionAvatarUrl(item);
|
||||
|
||||
let metaItems = [ItemUtils.getType(item)];
|
||||
let defaultImageUrl: string | null = null;
|
||||
|
||||
// Set default avatar for weapon
|
||||
if (ItemUtils.isWeaponContract(item)) {
|
||||
defaultImageUrl = RuleDataUtils.getDefaultWeaponImageUrl(ruleData);
|
||||
} else if (ItemUtils.isGearContract(item)) {
|
||||
}
|
||||
// Set default avatar for gear
|
||||
else if (ItemUtils.isGearContract(item)) {
|
||||
const subType = ItemUtils.getSubType(item);
|
||||
if (subType) {
|
||||
metaItems.push(subType);
|
||||
}
|
||||
|
||||
defaultImageUrl = RuleDataUtils.getDefaultGearImageUrl(ruleData);
|
||||
} else if (ItemUtils.isArmorContract(item)) {
|
||||
}
|
||||
// Set default avatar for armor
|
||||
else if (ItemUtils.isArmorContract(item)) {
|
||||
const baseArmorName = ItemUtils.getBaseArmorName(item);
|
||||
if (baseArmorName) {
|
||||
metaItems.push(baseArmorName);
|
||||
@@ -199,8 +145,22 @@ export class EquipmentManagerShopItem extends React.PureComponent<
|
||||
(amount === null ? 1 : amount) * ItemUtils.getBundleSize(item);
|
||||
|
||||
return (
|
||||
<EquipmentListItem
|
||||
header={this.renderHeader(item, metaItems, defaultImageUrl)}
|
||||
<Accordion
|
||||
className={styles.accordion}
|
||||
variant="paper"
|
||||
summary={
|
||||
<AccordionSummary
|
||||
className={styles.accordionSummary}
|
||||
title={<ItemName item={item} showLegacyBadge={true} />}
|
||||
description={metaItems as string[]}
|
||||
imageUrl={avatarUrl ?? defaultImageUrl ?? undefined}
|
||||
callout={
|
||||
<Button size="small" onClick={this.handleAdd}>
|
||||
Add
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<ItemDetail
|
||||
theme={theme}
|
||||
@@ -208,7 +168,6 @@ export class EquipmentManagerShopItem extends React.PureComponent<
|
||||
ruleData={ruleData}
|
||||
showCustomize={false}
|
||||
showActions={false}
|
||||
proficiencyBonus={proficiencyBonus}
|
||||
/>
|
||||
<div className="equipment-list-item-actions">
|
||||
<div className="equipment-list-item-action">
|
||||
@@ -251,7 +210,7 @@ export class EquipmentManagerShopItem extends React.PureComponent<
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</EquipmentListItem>
|
||||
</Accordion>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -266,7 +225,6 @@ interface EquipmentManagerShopProps {
|
||||
containerDefinitionKey: string
|
||||
) => void;
|
||||
ruleData: RuleData;
|
||||
proficiencyBonus: number;
|
||||
containerDefinitionKey: string;
|
||||
theme: CharacterTheme;
|
||||
activeSourceCategories: Array<number>;
|
||||
@@ -465,14 +423,8 @@ export default class EquipmentManagerShop extends React.PureComponent<
|
||||
|
||||
renderPagedListing = (filteredItems: Array<ItemManager>): React.ReactNode => {
|
||||
const { currentPage } = this.state;
|
||||
const {
|
||||
pageSize,
|
||||
onItemAdd,
|
||||
ruleData,
|
||||
proficiencyBonus,
|
||||
containerDefinitionKey,
|
||||
theme,
|
||||
} = this.props;
|
||||
const { pageSize, onItemAdd, ruleData, containerDefinitionKey, theme } =
|
||||
this.props;
|
||||
|
||||
const pagedFilteredItems: Array<ItemManager> = filteredItems.slice(
|
||||
0,
|
||||
@@ -489,7 +441,6 @@ export default class EquipmentManagerShop extends React.PureComponent<
|
||||
key={`${item.getMappingId()}-${idx}`}
|
||||
onItemAdd={onItemAdd}
|
||||
ruleData={ruleData}
|
||||
proficiencyBonus={proficiencyBonus}
|
||||
containerDefinitionKey={containerDefinitionKey}
|
||||
/>
|
||||
))
|
||||
|
||||
@@ -28,14 +28,8 @@ export const GearListItem: FC<GearListProps> = ({
|
||||
unequipLabel,
|
||||
...props
|
||||
}) => {
|
||||
const {
|
||||
ruleData,
|
||||
proficiencyBonus,
|
||||
characterTheme,
|
||||
itemUtils,
|
||||
helperUtils,
|
||||
containerLookup,
|
||||
} = useCharacterEngine();
|
||||
const { ruleData, characterTheme, itemUtils, helperUtils, containerLookup } =
|
||||
useCharacterEngine();
|
||||
const actions = useEquipmentMethods();
|
||||
const image = itemUtils.getAvatarUrl(item);
|
||||
const altText = itemUtils.getName(item);
|
||||
@@ -81,7 +75,6 @@ export const GearListItem: FC<GearListProps> = ({
|
||||
ruleData={ruleData}
|
||||
showCustomize={false}
|
||||
showActions={false}
|
||||
proficiencyBonus={proficiencyBonus}
|
||||
/>
|
||||
<EquipmentListItemActions item={item} {...actions} {...props} />
|
||||
</Accordion>
|
||||
|
||||
@@ -29,14 +29,8 @@ export const WeaponListItem: FC<WeaponListItemProps> = ({
|
||||
...props
|
||||
}) => {
|
||||
const actions = useEquipmentMethods();
|
||||
const {
|
||||
ruleData,
|
||||
proficiencyBonus,
|
||||
characterTheme,
|
||||
itemUtils,
|
||||
helperUtils,
|
||||
containerLookup,
|
||||
} = useCharacterEngine();
|
||||
const { ruleData, characterTheme, itemUtils, helperUtils, containerLookup } =
|
||||
useCharacterEngine();
|
||||
const image = itemUtils.getAvatarUrl(item);
|
||||
const altText = itemUtils.getName(item);
|
||||
const type = itemUtils.getType(item);
|
||||
@@ -80,7 +74,6 @@ export const WeaponListItem: FC<WeaponListItemProps> = ({
|
||||
ruleData={ruleData}
|
||||
showCustomize={false}
|
||||
showActions={false}
|
||||
proficiencyBonus={proficiencyBonus}
|
||||
/>
|
||||
<EquipmentListItemActions item={item} {...actions} {...props} />
|
||||
</Accordion>
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
DisabledChevronDownSvg,
|
||||
DisabledChevronUpSvg,
|
||||
} from "@dndbeyond/character-components/es";
|
||||
|
||||
export class CollapsibleHeading extends React.PureComponent<{
|
||||
className: string;
|
||||
}> {
|
||||
static defaultProps = {
|
||||
className: "",
|
||||
};
|
||||
|
||||
render() {
|
||||
const { className, children } = this.props;
|
||||
return (
|
||||
<div className={["collapsible-heading", className].join(" ")}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class CollapsibleHeaderCallout extends React.PureComponent<{
|
||||
extra: any;
|
||||
value: any;
|
||||
}> {
|
||||
render() {
|
||||
let { extra, value } = this.props;
|
||||
|
||||
return (
|
||||
<span className="collapsible-header-callout">
|
||||
<span className="collapsible-header-callout-extra">{extra}</span>
|
||||
<span className="collapsible-header-callout-value">{value}</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class CollapsibleHeader extends React.PureComponent<{
|
||||
clsIdent?: string;
|
||||
imgSrc?: string;
|
||||
imgKey?: string;
|
||||
iconClsNames: Array<string>;
|
||||
heading: any;
|
||||
metaItems: Array<string>;
|
||||
callout?: any;
|
||||
}> {
|
||||
static defaultProps = {
|
||||
iconClsNames: [],
|
||||
metaItems: [],
|
||||
};
|
||||
|
||||
constructMetaItems() {
|
||||
let { metaItems } = this.props;
|
||||
|
||||
if (!metaItems) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="collapsible-header-meta">
|
||||
{metaItems.map((item, idx) => {
|
||||
return (
|
||||
<span className="collapsible-header-meta-item" key={item + idx}>
|
||||
{item}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { clsIdent, heading, callout, imgSrc, imgKey, iconClsNames } =
|
||||
this.props;
|
||||
let calloutNode, headingNode;
|
||||
|
||||
if (typeof heading === "string") {
|
||||
headingNode = (
|
||||
<CollapsibleHeading className="collapsible-heading">
|
||||
{heading}
|
||||
</CollapsibleHeading>
|
||||
);
|
||||
} else {
|
||||
headingNode = heading;
|
||||
}
|
||||
|
||||
if (typeof callout === "string") {
|
||||
calloutNode = (
|
||||
<div className="collapsible-heading-callout">{callout}</div>
|
||||
);
|
||||
} else {
|
||||
calloutNode = (
|
||||
<div className="collapsible-heading-callout">{callout}</div>
|
||||
);
|
||||
}
|
||||
|
||||
//TODO clean this up and use all of the same thing
|
||||
let iconStyles = {};
|
||||
let allIconClsNames = ["collapsible-header-icon"];
|
||||
let hasIcon = false;
|
||||
if (imgSrc) {
|
||||
iconStyles["backgroundImage"] = `url(${imgSrc})`;
|
||||
hasIcon = true;
|
||||
} else if (imgKey) {
|
||||
allIconClsNames.push(`collapsible-header-icon-${imgKey}`);
|
||||
hasIcon = true;
|
||||
} else if (iconClsNames.length) {
|
||||
allIconClsNames = [...allIconClsNames, ...iconClsNames];
|
||||
hasIcon = true;
|
||||
}
|
||||
|
||||
//TODO fix name to conClsNames for consistency
|
||||
let conClassNames = [`collapsible-header-el`];
|
||||
if (clsIdent) {
|
||||
conClassNames.push(`collapsible-header-el-${clsIdent}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={conClassNames.join(" ")}>
|
||||
{hasIcon && (
|
||||
<div className={allIconClsNames.join(" ")} style={iconStyles} />
|
||||
)}
|
||||
<div className="collapsible-header-info">
|
||||
{headingNode}
|
||||
{this.constructMetaItems()}
|
||||
</div>
|
||||
{calloutNode}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Collapsible extends React.PureComponent<
|
||||
{
|
||||
trigger: any;
|
||||
clsNames: Array<string>;
|
||||
initiallyCollapsed: boolean;
|
||||
onChange?: (isCollapsed: boolean) => void;
|
||||
onOpened?: () => void;
|
||||
onClosed?: () => void;
|
||||
},
|
||||
{
|
||||
collapsed: boolean;
|
||||
mouseOverHeading: boolean;
|
||||
}
|
||||
> {
|
||||
static defaultProps = {
|
||||
clsNames: [],
|
||||
initiallyCollapsed: true,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
collapsed: props.initiallyCollapsed,
|
||||
mouseOverHeading: false,
|
||||
};
|
||||
}
|
||||
|
||||
handleUpdate = () => {
|
||||
const { onChange, onOpened, onClosed } = this.props;
|
||||
const { collapsed } = this.state;
|
||||
|
||||
if (collapsed) {
|
||||
if (onClosed) {
|
||||
onClosed();
|
||||
}
|
||||
} else {
|
||||
if (onOpened) {
|
||||
onOpened();
|
||||
}
|
||||
}
|
||||
|
||||
if (onChange) {
|
||||
onChange(collapsed);
|
||||
}
|
||||
};
|
||||
|
||||
handleClick = (evt) => {
|
||||
this.setState(
|
||||
(prevState, preProps) => ({
|
||||
collapsed: !prevState.collapsed,
|
||||
}),
|
||||
this.handleUpdate
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { collapsed } = this.state;
|
||||
const { trigger, clsNames, children } = this.props;
|
||||
|
||||
let headerContent = trigger;
|
||||
if (typeof headerContent == "string") {
|
||||
headerContent = (
|
||||
<div className="collapsible-heading">{headerContent}</div>
|
||||
);
|
||||
}
|
||||
|
||||
let conClassNames = ["collapsible"];
|
||||
if (clsNames) {
|
||||
conClassNames = [...clsNames, ...conClassNames];
|
||||
}
|
||||
conClassNames.push(
|
||||
this.state.collapsed ? "collapsible-collapsed" : "collapsible-opened"
|
||||
);
|
||||
|
||||
let headerClassNames = ["collapsible-header"];
|
||||
if (this.state.mouseOverHeading) {
|
||||
headerClassNames.push("collapsible-header-over");
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={conClassNames.join(" ")}>
|
||||
<div className={headerClassNames.join(" ")} onClick={this.handleClick}>
|
||||
<div className="collapsible-header-content">{headerContent}</div>
|
||||
{collapsed ? <DisabledChevronDownSvg /> : <DisabledChevronUpSvg />}
|
||||
</div>
|
||||
{collapsed ? null : <div className="collapsible-body">{children}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Collapsible;
|
||||
@@ -1,13 +0,0 @@
|
||||
import Collapsible, {
|
||||
CollapsibleHeader,
|
||||
CollapsibleHeaderCallout,
|
||||
CollapsibleHeading,
|
||||
} from "./Collapsible";
|
||||
|
||||
export default Collapsible;
|
||||
export {
|
||||
Collapsible,
|
||||
CollapsibleHeader,
|
||||
CollapsibleHeading,
|
||||
CollapsibleHeaderCallout,
|
||||
};
|
||||
Reference in New Issue
Block a user