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,70 @@
|
||||
import clsx from "clsx";
|
||||
import { FC, HTMLAttributes, type MouseEvent } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
|
||||
import GridIcon from "@dndbeyond/fontawesome-cache/svgs/solid/grid.svg";
|
||||
import { useIsVisible } from "@dndbeyond/ttui/hooks/useIsVisible";
|
||||
|
||||
import { useSidebar } from "~/contexts/Sidebar";
|
||||
import { useUnpropagatedClick } from "~/hooks/useUnpropagatedClick";
|
||||
|
||||
import { sidebarId } from "../../constants";
|
||||
import { ArrowsLeftIcon } from "../Sidebar/svgs/ArrowsLeftIcon";
|
||||
import { ArrowsRightIcon } from "../Sidebar/svgs/ArrowsRightIcon";
|
||||
import { SectionMenu } from "./SectionMenu";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export interface MobileNavProps extends HTMLAttributes<HTMLDivElement> {}
|
||||
|
||||
export const MobileNav: FC<MobileNavProps> = ({ className, ...props }) => {
|
||||
const {
|
||||
ref,
|
||||
isVisible: isMenuVisible,
|
||||
setIsVisible: setIsMenuVisible,
|
||||
} = useIsVisible(false);
|
||||
const { sidebar } = useSidebar();
|
||||
|
||||
const handleToggleSidebar = useUnpropagatedClick(() => {
|
||||
setIsMenuVisible(false);
|
||||
sidebar.setIsVisible(!sidebar.isVisible);
|
||||
});
|
||||
|
||||
const handleToggleMenu = () => {
|
||||
setIsMenuVisible(!isMenuVisible);
|
||||
};
|
||||
|
||||
const handleCloseMenu = (e?: MouseEvent) => {
|
||||
e?.stopPropagation();
|
||||
setIsMenuVisible(false);
|
||||
};
|
||||
|
||||
return createPortal(
|
||||
<div className={clsx([styles.mobileNav, className])} ref={ref} {...props}>
|
||||
{!sidebar.isVisible && (
|
||||
<div>
|
||||
<button
|
||||
className={styles.navToggle}
|
||||
onClick={handleToggleMenu}
|
||||
aria-label="Show navigation"
|
||||
>
|
||||
<GridIcon className={styles.icon} />
|
||||
</button>
|
||||
<SectionMenu open={isMenuVisible} onClose={handleCloseMenu} />
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
className={styles.sidebarToggle}
|
||||
onClick={handleToggleSidebar}
|
||||
aria-controls={sidebarId}
|
||||
aria-label={`${sidebar.isVisible ? "Hide" : "Show"} sidebar`}
|
||||
>
|
||||
{sidebar.isVisible ? (
|
||||
<ArrowsRightIcon className={styles.icon} />
|
||||
) : (
|
||||
<ArrowsLeftIcon className={styles.icon} />
|
||||
)}
|
||||
</button>
|
||||
</div>,
|
||||
document.body
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
import clsx from "clsx";
|
||||
import { FC } from "react";
|
||||
|
||||
import { ButtonProps } from "@dndbeyond/ttui/components/Button";
|
||||
|
||||
import { Button } from "~/components/Button";
|
||||
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export interface SectionButtonProps extends ButtonProps {}
|
||||
|
||||
export const SectionButton: FC<SectionButtonProps> = ({
|
||||
className,
|
||||
onClick,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<Button
|
||||
className={clsx([styles.sectionButton, className])}
|
||||
onClick={onClick}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,116 @@
|
||||
import clsx from "clsx";
|
||||
import { FC } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import { rulesEngineSelectors } from "@dndbeyond/character-rules-engine";
|
||||
import { Dialog, DialogProps } from "@dndbeyond/ttui/components/Dialog";
|
||||
|
||||
import { useSheetContext } from "~/subApps/sheet/contexts/Sheet";
|
||||
import {
|
||||
ActionsIcon,
|
||||
AttributesIcon,
|
||||
DescriptionIcon,
|
||||
EquipmentIcon,
|
||||
ExtrasIcon,
|
||||
FeatureTraitsIcon,
|
||||
NotesIcon,
|
||||
ProficienciesSvg,
|
||||
SkillsIcon,
|
||||
SpellsIcon,
|
||||
} from "~/svgs";
|
||||
import { appEnvSelectors } from "~/tools/js/Shared/selectors";
|
||||
|
||||
import { SectionButton } from "../SectionButton";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export interface SectionMenuProps extends DialogProps {
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
export const SectionMenu: FC<SectionMenuProps> = ({
|
||||
className,
|
||||
open,
|
||||
...props
|
||||
}) => {
|
||||
const { setMobileActiveSectionId: setId } = useSheetContext();
|
||||
const isReadonly = useSelector(appEnvSelectors.getIsReadonly);
|
||||
const hasSpells = useSelector(rulesEngineSelectors.hasSpells);
|
||||
|
||||
return createPortal(
|
||||
<>
|
||||
<Dialog
|
||||
className={clsx([styles.sectionNav, className])}
|
||||
open={open}
|
||||
modal
|
||||
{...props}
|
||||
>
|
||||
<SectionButton
|
||||
className={styles.fullWidth}
|
||||
onClick={() => setId("main")}
|
||||
>
|
||||
<AttributesIcon />
|
||||
<span>
|
||||
Abilities, Saves, Senses
|
||||
<span className={styles.mobile}>
|
||||
, Proficiencies, Training, Skills
|
||||
</span>
|
||||
</span>
|
||||
</SectionButton>
|
||||
<SectionButton
|
||||
className={styles.mobile}
|
||||
onClick={() => setId("skills")}
|
||||
>
|
||||
<SkillsIcon />
|
||||
Skills
|
||||
</SectionButton>
|
||||
<SectionButton onClick={() => setId("actions")}>
|
||||
<ActionsIcon />
|
||||
Actions
|
||||
</SectionButton>
|
||||
<SectionButton onClick={() => setId("equipment")}>
|
||||
<EquipmentIcon />
|
||||
Inventory
|
||||
</SectionButton>
|
||||
{hasSpells && (
|
||||
<SectionButton onClick={() => setId("spells")}>
|
||||
<SpellsIcon />
|
||||
Spells
|
||||
</SectionButton>
|
||||
)}
|
||||
<SectionButton onClick={() => setId("features_traits")}>
|
||||
<FeatureTraitsIcon />
|
||||
Features & Traits
|
||||
</SectionButton>
|
||||
<SectionButton
|
||||
className={styles.mobile}
|
||||
onClick={() => setId("proficiencies")}
|
||||
>
|
||||
<ProficienciesSvg />
|
||||
<span>Proficiencies & Training</span>
|
||||
</SectionButton>
|
||||
{!isReadonly && (
|
||||
<SectionButton onClick={() => setId("description")}>
|
||||
<DescriptionIcon />
|
||||
Background
|
||||
</SectionButton>
|
||||
)}
|
||||
{!isReadonly && (
|
||||
<SectionButton onClick={() => setId("notes")}>
|
||||
<NotesIcon />
|
||||
Notes
|
||||
</SectionButton>
|
||||
)}
|
||||
<SectionButton
|
||||
className={hasSpells ? styles.fullWidth : ""}
|
||||
onClick={() => setId("extras")}
|
||||
>
|
||||
<ExtrasIcon />
|
||||
Extras
|
||||
</SectionButton>
|
||||
</Dialog>
|
||||
{open && <div className={styles.backdrop} />}
|
||||
</>,
|
||||
document.body
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user