New source found from dndbeyond.com

This commit is contained in:
David Kruger 2025-06-05 01:00:10 -07:00
parent 3954b12f5d
commit 451d940294
14 changed files with 88 additions and 35 deletions

View File

@ -67,7 +67,7 @@ export const CharacterNameLimitMsg = `The max length for a name is ${InputLimits
export const SourceCategoryDescription = { export const SourceCategoryDescription = {
official: official:
"The sources below add additional character options beyond the 2024 Core Rules. You will only see character options from the Core Rules and content you own and have enabled here.", "You will only see character options from content you own and have enabled here in both the builder and your character sheet. Removing all sources will prevent you from being able to create a complete character.",
homebrew: homebrew:
"Character options designed by other players and uploaded to D&D BEYOND. Talk to your DM before including Homebrew content.", "Character options designed by other players and uploaded to D&D BEYOND. Talk to your DM before including Homebrew content.",
partnered: partnered:

View File

@ -5,22 +5,22 @@ import type {
AllHTMLAttributes, AllHTMLAttributes,
ButtonHTMLAttributes, ButtonHTMLAttributes,
FC, FC,
PropsWithChildren, ReactNode,
} from "react"; } from "react";
import styles from "./styles/Button.module.css"; import styles from "./styles/Button.module.css";
import sizeStyles from "./styles/ButtonSizes.module.css"; import sizeStyles from "./styles/ButtonSizes.module.css";
import variantStyles from "./styles/ButtonVariants.module.css"; import variantStyles from "./styles/ButtonVariants.module.css";
export interface ButtonProps export interface ButtonProps
extends PropsWithChildren, extends Omit<
Omit<
AllHTMLAttributes<HTMLAnchorElement | HTMLButtonElement | HTMLDivElement>, AllHTMLAttributes<HTMLAnchorElement | HTMLButtonElement | HTMLDivElement>,
"size" | "type" "size" | "type"
>, >,
Pick<ButtonHTMLAttributes<HTMLButtonElement>, "type"> { Pick<ButtonHTMLAttributes<HTMLButtonElement>, "type"> {
children?: ReactNode;
className?: string; className?: string;
color?: "primary" | "secondary" | "success" | "info" | "warning" | "error"; color?: "primary" | "secondary" | "success" | "info" | "warning" | "error";
variant?: "solid" | "outline" | "text"; variant?: "solid" | "outline" | "text" | "tool";
size?: "x-small" | "small" | "medium" | "large" | "x-large"; size?: "x-small" | "small" | "medium" | "large" | "x-large";
isDiv?: boolean; isDiv?: boolean;
} }

View File

@ -3,7 +3,7 @@ import type { ChangeEvent, FC, ReactNode } from "react";
import styles from "./Checkbox.module.css"; import styles from "./Checkbox.module.css";
export interface CheckboxProps { export interface CheckboxProps {
id?: string; id: string;
label?: ReactNode; label?: ReactNode;
defaultChecked?: boolean; defaultChecked?: boolean;
checked?: boolean; checked?: boolean;

View File

@ -15,6 +15,7 @@ export interface DialogProps extends HTMLAttributes<HTMLDialogElement> {
open: boolean; open: boolean;
onClose: (e?: MouseEvent) => void; onClose: (e?: MouseEvent) => void;
modal?: boolean; modal?: boolean;
onBackdropClick?: () => void;
} }
export const Dialog: React.FC<DialogProps> = ({ export const Dialog: React.FC<DialogProps> = ({
@ -23,6 +24,7 @@ export const Dialog: React.FC<DialogProps> = ({
modal, modal,
children, children,
className, className,
onBackdropClick,
...props ...props
}) => { }) => {
const dialogRef = useRef<HTMLDialogElement>(null); const dialogRef = useRef<HTMLDialogElement>(null);
@ -46,7 +48,10 @@ export const Dialog: React.FC<DialogProps> = ({
rect.left <= e.clientX && rect.left <= e.clientX &&
e.clientX <= rect.left + rect.width; e.clientX <= rect.left + rect.width;
if (!isClickInDialog) handleClose(); if (!isClickInDialog) {
onBackdropClick?.();
handleClose();
}
}; };
const handleEsc = (e: KeyboardEvent) => { const handleEsc = (e: KeyboardEvent) => {

View File

@ -2,15 +2,23 @@ import type { MegaMenuCardProps } from "../MegaMenuCard";
const ddbImageBase = "https://media.dndbeyond.com/mega-menu"; const ddbImageBase = "https://media.dndbeyond.com/mega-menu";
export const characterBuilder: MegaMenuCardProps = { export const groupOne: MegaMenuCardProps[] = [
label: "Character Builder",
imageUrl: `${ddbImageBase}/323a928e32eff87dee85dfbe0793ce12.jpg`,
link: "https://www.dndbeyond.com/characters/builder",
};
export const primaryItems: MegaMenuCardProps[] = [
{ {
label: "Maps", label: "Character Builder",
imageUrl: `${ddbImageBase}/character_builder.png`,
link: "https://www.dndbeyond.com/characters/builder",
},
{
label: "Sigil 3D VTT",
imageUrl: `${ddbImageBase}/playtest_sigil.png`,
link: "https://www.dndbeyond.com/project-sigil",
flags: [{ label: "New", variant: "success" }],
},
];
export const groupTwo: MegaMenuCardProps[] = [
{
label: "Maps VTT",
imageUrl: `${ddbImageBase}/049ddb9085342521d25c5230451cfd45.jpg`, imageUrl: `${ddbImageBase}/049ddb9085342521d25c5230451cfd45.jpg`,
link: "https://www.dndbeyond.com/games", link: "https://www.dndbeyond.com/games",
flags: [{ label: "Beta", variant: "info" }], flags: [{ label: "Beta", variant: "info" }],
@ -23,7 +31,7 @@ export const primaryItems: MegaMenuCardProps[] = [
}, },
]; ];
export const secondaryItems: MegaMenuCardProps[] = [ export const groupThree: MegaMenuCardProps[] = [
{ {
label: "Mobile App", label: "Mobile App",
imageUrl: `${ddbImageBase}/3aa58aac2d02bb52d62204e158b48ce6.jpg`, imageUrl: `${ddbImageBase}/3aa58aac2d02bb52d62204e158b48ce6.jpg`,

View File

@ -1,5 +1,6 @@
"use client"; "use client";
import clsx from "clsx";
import type { FC } from "react"; import type { FC } from "react";
import { Tooltip as ReactTooltip, type ITooltip } from "react-tooltip"; import { Tooltip as ReactTooltip, type ITooltip } from "react-tooltip";
import styles from "./Tooltip.module.css"; import styles from "./Tooltip.module.css";
@ -7,22 +8,24 @@ import styles from "./Tooltip.module.css";
export interface TooltipProps extends ITooltip { export interface TooltipProps extends ITooltip {
id: string; id: string;
"data-testid"?: string; "data-testid"?: string;
disableStyleInjection?: "core" | undefined;
} }
export const Tooltip: FC<TooltipProps> = ({ export const Tooltip: FC<TooltipProps> = ({
id, id,
"data-testid": testId, "data-testid": testId,
children, children,
disableStyleInjection,
...props ...props
}) => { }) => (
return ( <div className={styles.container} {...(testId && { "data-testid": testId })}>
<div <ReactTooltip
className={styles.container} id={id}
{...(testId && { "data-testid": testId })} {...props}
className={clsx([styles.tooltip, props.className])}
disableStyleInjection={disableStyleInjection}
> >
<ReactTooltip id={id} className={styles.tooltip} {...props}> {children}
{children} </ReactTooltip>
</ReactTooltip> </div>
</div> );
);
};

View File

@ -37,6 +37,7 @@ export const Listing: FC<ListingProps> = ({
key={item.id + "group"} key={item.id + "group"}
disabledIds={disabledIds} disabledIds={disabledIds}
onQuickSelect={onQuickSelect} onQuickSelect={onQuickSelect}
data-testid="sourceHeader"
/> />
) : ( ) : (
<ListingItemButton <ListingItemButton
@ -44,6 +45,7 @@ export const Listing: FC<ListingProps> = ({
isDisabled={isDisabled} isDisabled={isDisabled}
key={item.id} key={item.id}
onQuickSelect={onQuickSelect} onQuickSelect={onQuickSelect}
data-testid="optionButton"
/> />
); );
}) })

View File

@ -287,7 +287,11 @@ export const ClassChoose: FC<ClassChooseProps> = ({
}; };
return ( return (
<div className={clsx([styles.page, className])} {...props}> <div
className={clsx([styles.page, className])}
{...props}
data-testid="chooseClassSection"
>
{showHeader && ( {showHeader && (
<> <>
<PortraitName /> <PortraitName />
@ -400,7 +404,10 @@ export const ClassChoose: FC<ClassChooseProps> = ({
); );
}) })
) : ( ) : (
<p className={styles.notFound}>No Results Found</p> <p className={styles.notFound}>
No Class options available. Return to the <strong>Home</strong>{" "}
tab to enable more source categories.
</p>
)} )}
</> </>
)} )}

View File

@ -96,7 +96,11 @@ export const SpeciesChoose: FC<SpeciesChooseProps> = ({
}; };
return ( return (
<div className={clsx([styles.speciesChoose, className])} {...props}> <div
className={clsx([styles.speciesChoose, className])}
{...props}
data-testid="chooseSpeciesSection"
>
{showHeader && ( {showHeader && (
<> <>
<PortraitName /> <PortraitName />
@ -160,8 +164,13 @@ export const SpeciesChoose: FC<SpeciesChooseProps> = ({
</div> </div>
<hr className={styles.divider} /> <hr className={styles.divider} />
<div className={clsx([styles.text, styles.marketplace])}> <div className={clsx([styles.text, styles.marketplace])}>
Looking for something not in the list below? Unlock all official options Check your source settings on the <strong>Home</strong> tab if you can't
in the <Link href="/marketplace">Marketplace</Link>. find Species you've purchased.
<br />
Expand your library in the <Link href="/marketplace">
Marketplace
</Link>{" "}
for more Species options.
</div> </div>
{isLoading ? ( {isLoading ? (
<Spinner /> <Spinner />

View File

@ -1163,8 +1163,12 @@ class DescriptionManage extends React.PureComponent<Props, State> {
return ( return (
<React.Fragment> <React.Fragment>
<div className="ct-character-tools__marketplace-callout"> <div className="ct-character-tools__marketplace-callout">
Looking for something not in the list below? Unlock all official Check your source settings on the <strong>Home</strong> tab if you
options in the <Link href="/marketplace">Marketplace</Link>. can't find Backgrounds you've purchased.
<br />
Expand your library in the{" "}
<Link href="/marketplace">Marketplace</Link> for more Background
options.
</div> </div>
<div className="description-manage-background-chooser-con"> <div className="description-manage-background-chooser-con">
<div className="description-manage-background-chooser-field"> <div className="description-manage-background-chooser-field">

View File

@ -20,6 +20,7 @@ import PageHeader from "../../../components/PageHeader";
import { builderEnvSelectors, builderSelectors } from "../../../selectors"; import { builderEnvSelectors, builderSelectors } from "../../../selectors";
import { BuilderAppState } from "../../../typings"; import { BuilderAppState } from "../../../typings";
import ConnectedBuilderPage from "../ConnectedBuilderPage"; import ConnectedBuilderPage from "../ConnectedBuilderPage";
import styles from "./styles.module.css";
interface Props extends DispatchProp { interface Props extends DispatchProp {
characterId: number | null; characterId: number | null;
@ -243,6 +244,13 @@ class WhatsNext extends React.PureComponent<Props, State> {
<div className="whats-next-action">{this.renderPdfButton()}</div> <div className="whats-next-action">{this.renderPdfButton()}</div>
</div> </div>
{this.renderPdfData()} {this.renderPdfData()}
{!isCharacterSheetReady && (
<p className={styles.returnToHomeText}>
If you are unable to create a character due to missing options,
return to the <strong>Home</strong> tab and change your source
settings.
</p>
)}
<div className="whats-next-characters"> <div className="whats-next-characters">
<Link href={characterListingUrl}>View all my characters</Link> <Link href={characterListingUrl}>View all my characters</Link>
</div> </div>

View File

@ -1,6 +1,7 @@
import clsx from "clsx"; import clsx from "clsx";
import { orderBy } from "lodash"; import { orderBy } from "lodash";
import React from "react"; import React from "react";
import { v4 as uuidv4 } from "uuid";
import { Checkbox } from "~/components/Checkbox"; import { Checkbox } from "~/components/Checkbox";
import { HtmlContent } from "~/components/HtmlContent"; import { HtmlContent } from "~/components/HtmlContent";
@ -81,6 +82,7 @@ export const FormCheckBoxesField: React.FC<Props> = ({
</div> </div>
<div className={styles.checkbox}> <div className={styles.checkbox}>
<Checkbox <Checkbox
id={uuidv4()}
checked={checkbox.initiallyEnabled} checked={checkbox.initiallyEnabled}
aria-label={checkbox.label} aria-label={checkbox.label}
onClick={checkbox.onChange} onClick={checkbox.onChange}
@ -121,6 +123,7 @@ export const FormCheckBoxesField: React.FC<Props> = ({
<div className={styles.group} key={idx}> <div className={styles.group} key={idx}>
<div className={styles.checkbox}> <div className={styles.checkbox}>
<Checkbox <Checkbox
id={uuidv4()}
checked={checkbox.initiallyEnabled} checked={checkbox.initiallyEnabled}
aria-label={checkbox.label} aria-label={checkbox.label}
onClick={checkbox.onChange} onClick={checkbox.onChange}
@ -174,6 +177,7 @@ export const FormCheckBoxesField: React.FC<Props> = ({
onCheckUncheckAll && onCheckUncheckAll &&
variant === CheckboxVariant.DEFAULT && ( variant === CheckboxVariant.DEFAULT && (
<Checkbox <Checkbox
id={uuidv4()}
checked={allChecksEnabled} checked={allChecksEnabled}
aria-label="Check/Uncheck all" aria-label="Check/Uncheck all"
onClick={onCheckUncheckAll.onChange} onClick={onCheckUncheckAll.onChange}
@ -215,6 +219,7 @@ export const FormCheckBoxesField: React.FC<Props> = ({
<div className={styles.summaryHeadingGroup}> <div className={styles.summaryHeadingGroup}>
{checkUncheckAllEnabled && onCheckUncheckAll && ( {checkUncheckAllEnabled && onCheckUncheckAll && (
<Checkbox <Checkbox
id={uuidv4()}
checked={allChecksEnabled} checked={allChecksEnabled}
aria-label="Check/Uncheck all" aria-label="Check/Uncheck all"
onClick={onCheckUncheckAll.onChange} onClick={onCheckUncheckAll.onChange}

View File

@ -0,0 +1,2 @@
// extracted by mini-css-extract-plugin
export default {"returnToHomeText":"styles_returnToHomeText__C7eSU"};

View File

@ -1,2 +1,2 @@
// extracted by mini-css-extract-plugin // extracted by mini-css-extract-plugin
export default {"primary":"ButtonVariants_primary__TMQ5y","secondary":"ButtonVariants_secondary__Z0czz","success":"ButtonVariants_success__OhFyN","info":"ButtonVariants_info__+w8ox","warning":"ButtonVariants_warning__qCfwB","error":"ButtonVariants_error__6SkiQ","outline":"ButtonVariants_outline__v36Mn","svg":"ButtonVariants_svg__Si33n","text":"ButtonVariants_text__vKMzd"}; export default {"primary":"ButtonVariants_primary__TMQ5y","secondary":"ButtonVariants_secondary__Z0czz","success":"ButtonVariants_success__OhFyN","info":"ButtonVariants_info__+w8ox","warning":"ButtonVariants_warning__qCfwB","error":"ButtonVariants_error__6SkiQ","outline":"ButtonVariants_outline__v36Mn","svg":"ButtonVariants_svg__Si33n","text":"ButtonVariants_text__vKMzd","tool":"ButtonVariants_tool__mrrWB"};