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:
@@ -0,0 +1,55 @@
|
||||
import clsx from "clsx";
|
||||
import { FC, HTMLAttributes } from "react";
|
||||
|
||||
import { GroupedListingItem, ListingItem } from "../../types";
|
||||
import { ListingGroup } from "./ListingGroup";
|
||||
import { ListingItemButton } from "./ListingItemButton/ListingItemButton";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export interface ListingProps extends HTMLAttributes<HTMLDivElement> {
|
||||
items: Array<ListingItem | GroupedListingItem>;
|
||||
disabledIds?: Array<number | string>;
|
||||
onQuickSelect?: (entity: ListingItem["entity"]) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic listing component that displays a list of items. Items cannot be
|
||||
* internal because it is used for both races/species and classes. Keeping the
|
||||
* data fetch outside this component allows for more flexibility.
|
||||
*/
|
||||
|
||||
export const Listing: FC<ListingProps> = ({
|
||||
className,
|
||||
items,
|
||||
disabledIds,
|
||||
onQuickSelect,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<div className={clsx([styles.listing, className])} {...props}>
|
||||
{items.length > 0 ? (
|
||||
items.map((item) => {
|
||||
const isDisabled = disabledIds && disabledIds.includes(item.id);
|
||||
|
||||
return item.type === "group" ? (
|
||||
<ListingGroup
|
||||
item={item as GroupedListingItem}
|
||||
key={item.id + "group"}
|
||||
disabledIds={disabledIds}
|
||||
onQuickSelect={onQuickSelect}
|
||||
/>
|
||||
) : (
|
||||
<ListingItemButton
|
||||
item={item as ListingItem}
|
||||
isDisabled={isDisabled}
|
||||
key={item.id}
|
||||
onQuickSelect={onQuickSelect}
|
||||
/>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<p className={styles.notFound}>No Listings Found</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
import clsx from "clsx";
|
||||
import { FC, HTMLAttributes, MouseEvent, useState } from "react";
|
||||
|
||||
import ChevronDown from "@dndbeyond/fontawesome-cache/svgs/solid/chevron-down.svg";
|
||||
|
||||
import { LegacyBadge } from "~/components/LegacyBadge";
|
||||
import { GroupedListingItem } from "~/subApps/builder/types";
|
||||
|
||||
import { ListingItemButton } from "../ListingItemButton";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export interface ListingGroupProps extends HTMLAttributes<HTMLDetailsElement> {
|
||||
item: GroupedListingItem;
|
||||
disabledIds?: Array<number | string>;
|
||||
onQuickSelect?: (entity: GroupedListingItem["entity"]) => void;
|
||||
}
|
||||
|
||||
export const ListingGroup: FC<ListingGroupProps> = ({
|
||||
className,
|
||||
item,
|
||||
disabledIds,
|
||||
onQuickSelect,
|
||||
...props
|
||||
}) => {
|
||||
const {
|
||||
entityTypeId,
|
||||
error,
|
||||
heading,
|
||||
id,
|
||||
image,
|
||||
isLegacy,
|
||||
metaItems,
|
||||
text,
|
||||
type,
|
||||
onClick,
|
||||
...itemProps
|
||||
} = item;
|
||||
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
|
||||
const handleToggle = (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
setIsOpen(!isOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<details className={styles.details} key={id} open={isOpen} {...props}>
|
||||
<summary
|
||||
className={clsx([styles.summary, className])}
|
||||
onClick={handleToggle}
|
||||
>
|
||||
{image && (
|
||||
<img src={image} alt={`${heading} avatar`} className={styles.image} />
|
||||
)}
|
||||
<div>
|
||||
<header className={styles.header}>
|
||||
<h3 className={styles.heading}>
|
||||
{heading}{" "}
|
||||
<span
|
||||
className={styles.count}
|
||||
>{`(${itemProps.listItems.length})`}</span>
|
||||
</h3>
|
||||
{isLegacy && <LegacyBadge className={styles.tag} />}
|
||||
</header>
|
||||
{text && <p className={styles.text}>{text}</p>}
|
||||
{metaItems && metaItems.length > 0 && (
|
||||
<div className={styles.metaItems}>
|
||||
{metaItems.map((metaItem, idx) => (
|
||||
<span className={styles[metaItem.type]} key={idx}>
|
||||
{metaItem.text}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ChevronDown className={styles.icon} />
|
||||
</summary>
|
||||
<div className={styles.content}>
|
||||
{itemProps.listItems.map((item) => (
|
||||
<ListingItemButton
|
||||
item={item}
|
||||
isDisabled={disabledIds && disabledIds.includes(item.id)}
|
||||
key={item.id}
|
||||
onQuickSelect={onQuickSelect}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</details>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
import clsx from "clsx";
|
||||
import { FC, HTMLAttributes, MouseEvent } from "react";
|
||||
|
||||
import ChevronRight from "@dndbeyond/fontawesome-cache/svgs/solid/chevron-right.svg";
|
||||
|
||||
import { LegacyBadge } from "~/components/LegacyBadge";
|
||||
import { ListingItem } from "~/subApps/builder/types";
|
||||
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export interface ListingItemProps extends HTMLAttributes<HTMLButtonElement> {
|
||||
item: ListingItem;
|
||||
isDisabled?: boolean;
|
||||
onQuickSelect?: (entity: ListingItem["entity"]) => void;
|
||||
}
|
||||
|
||||
export const ListingItemButton: FC<ListingItemProps> = ({
|
||||
className,
|
||||
item,
|
||||
isDisabled,
|
||||
onQuickSelect,
|
||||
...props
|
||||
}) => {
|
||||
const {
|
||||
entityTypeId,
|
||||
error,
|
||||
heading,
|
||||
id,
|
||||
image,
|
||||
isLegacy,
|
||||
metaItems,
|
||||
text,
|
||||
type,
|
||||
onClick,
|
||||
...itemProps
|
||||
} = item;
|
||||
|
||||
const handleClick = (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
//QuickSelect is from Quick and RandomBuild modes only
|
||||
if (onQuickSelect && !isDisabled) {
|
||||
onQuickSelect(item.entity);
|
||||
} else if (onClick && !isDisabled) {
|
||||
onClick(id);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
className={clsx([styles.button, className])}
|
||||
onClick={handleClick}
|
||||
aria-disabled={isDisabled}
|
||||
key={id}
|
||||
{...props}
|
||||
>
|
||||
{image && (
|
||||
<img src={image} alt={`${heading} avatar`} className={styles.image} />
|
||||
)}
|
||||
<div>
|
||||
<header className={styles.header}>
|
||||
<h3 className={styles.heading}>{heading}</h3>
|
||||
{isLegacy && <LegacyBadge className={styles.tag} />}
|
||||
</header>
|
||||
{text && <p className={styles.text}>{text}</p>}
|
||||
{metaItems && metaItems.length > 0 && (
|
||||
<div className={styles.metaItems}>
|
||||
{metaItems.map((metaItem, idx) => (
|
||||
<span className={styles[metaItem.type]} key={idx}>
|
||||
{metaItem.text}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ChevronRight className={styles.icon} />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user