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
@@ -0,0 +1,92 @@
'use client';
import ChevronLeft from '@dndbeyond/fontawesome-cache/svgs/regular/chevron-left.svg';
import ChevronRight from '@dndbeyond/fontawesome-cache/svgs/regular/chevron-right.svg';
import clsx from 'clsx';
import useEmblaCarousel from 'embla-carousel-react';
import { useCallback, useEffect, useState } from 'react';
import Markdown from 'react-markdown';
import { getItemAttributes, getSubElementAttributes } from '../../../bi/helpers';
import styles from './PromoCarousel.module.css';
type PromoCarouselType = {
promotions: {
text: string;
color?: string;
}[];
};
export const PromoCarousel = ({ promotions }: PromoCarouselType) => {
const [emblaRef, emblaApi] = useEmblaCarousel();
const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);
const [nextBtnDisabled, setNextBtnDisabled] = useState(true);
const [activeSlide, setActiveSlide] = useState(0);
const onPrevButtonClick = () => {
emblaApi?.scrollPrev();
determineSliderPosition();
if (emblaApi) setActiveSlide(emblaApi.selectedScrollSnap());
};
const onNextButtonClick = () => {
emblaApi?.scrollNext();
determineSliderPosition();
if (emblaApi) setActiveSlide(emblaApi.selectedScrollSnap());
};
const determineSliderPosition = useCallback(() => {
setPrevBtnDisabled(!emblaApi?.canScrollPrev());
setNextBtnDisabled(!emblaApi?.canScrollNext());
}, [emblaApi]);
useEffect(() => {
if (emblaApi) setActiveSlide(emblaApi.selectedScrollSnap());
determineSliderPosition();
}, [determineSliderPosition]);
return (
<div className={styles.carouselContainer}>
<button
onClick={onPrevButtonClick}
className={clsx(
styles.navigationButton,
prevBtnDisabled && styles.navigationButtonDisabled,
promotions.length === 1 && styles.navigationButtonHidden,
)}
disabled={prevBtnDisabled}
{...getItemAttributes('Previous', 'button', 'scroll', undefined, undefined)}
>
<ChevronLeft />
</button>
<div
className={styles.carousel}
ref={emblaRef}
{...getSubElementAttributes('Promo Carousel', 'main tile', undefined)}
>
<div className={styles.carouselScrollContainer}>
{promotions.map((promo, index) => (
// React versions below 19 remove the 'inert' attribute when provided as a boolean. Passing it as a string "true" as a workaround.
<div
inert={activeSlide !== index && ('inert' as unknown as boolean)}
key={index + promo.text}
className={styles.slide}
>
<Markdown>{promo.text}</Markdown>
</div>
))}
</div>
</div>
<button
onClick={onNextButtonClick}
className={clsx(
styles.navigationButton,
nextBtnDisabled && styles.navigationButtonDisabled,
promotions.length === 1 && styles.navigationButtonHidden,
)}
disabled={nextBtnDisabled}
{...getItemAttributes('Next', 'button', 'scroll', undefined, undefined)}
>
<ChevronRight />
</button>
</div>
);
};
@@ -0,0 +1,53 @@
'use client';
import { Button } from '@dndbeyond/ttui/components/Button';
import clsx from 'clsx';
import { forwardRef } from 'react';
import { getItemAttributes, getSubElementAttributes } from '../../bi/helpers';
import type { Meta, Title as PromoCarouselAdapterSchema } from '../../schemas/promotion-message-schema';
import type { LanguageType, TopNavigationMessages } from '../../types';
import { AmplienceComponent } from '../AmplienceComponent';
import styles from './TopNavigation.module.css';
type TopNavigationType = {
className?: string;
promoSlotData?: {
content: PromoCarouselAdapterSchema;
_meta: Meta;
};
messages: TopNavigationMessages;
locale: LanguageType;
onDismissBanner?: () => void;
};
export const TopNavigation = forwardRef<HTMLDivElement, TopNavigationType>(
({ className, promoSlotData, messages, locale, onDismissBanner }, ref) => {
return (
<div
ref={ref}
className={clsx(styles.promoBannerWrapper, className)}
data-testid="topNavigation-wrapper"
{...getSubElementAttributes('Top Navigation', 'main tile', undefined)}
>
<div className={styles.promoBanner}>
<div></div>
<div>{promoSlotData && <AmplienceComponent item={promoSlotData} locale={locale} />}</div>
{!!onDismissBanner && (
<Button
variant="outline"
color="primary"
size="x-small"
className={styles.dismissButton}
onClick={onDismissBanner}
data-testid="dismiss-button"
{...getItemAttributes('Dismiss Promo Banner', 'button', 'close', undefined, undefined)}
>
{messages.dismiss}
</Button>
)}
</div>
</div>
);
},
);
TopNavigation.displayName = 'TopNavigation';