``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
175 lines
4.9 KiB
TypeScript
175 lines
4.9 KiB
TypeScript
import { isEqual } from "lodash";
|
|
import { createContext, FC, useContext, useEffect, useState } from "react";
|
|
import { useSelector } from "react-redux";
|
|
|
|
import {
|
|
PaneComponentEnum,
|
|
PaneComponentInfo,
|
|
PaneIdentifiers,
|
|
SidebarAlignmentEnum,
|
|
SidebarPlacementEnum,
|
|
} from "~/subApps/sheet/components/Sidebar/types";
|
|
import { SIDEBAR_FIXED_POSITION_START_WIDTH } from "~/tools/js/CharacterSheet/config";
|
|
import { appEnvSelectors } from "~/tools/js/Shared/selectors";
|
|
|
|
export interface SidebarInfo {
|
|
isVisible: boolean;
|
|
setIsVisible: (isVisible: boolean) => void;
|
|
isLocked: boolean;
|
|
setIsLocked: (isLocked: boolean) => void;
|
|
placement: SidebarPlacementEnum;
|
|
setPlacement: (placement: SidebarPlacementEnum) => void;
|
|
alignment: SidebarAlignmentEnum;
|
|
setAlignment: (alignment: SidebarAlignmentEnum) => void;
|
|
width: number;
|
|
}
|
|
|
|
export interface PaneInfo {
|
|
activePane: PaneComponentInfo | null;
|
|
showControls: boolean;
|
|
isAtStart: boolean;
|
|
isAtEnd: boolean;
|
|
paneHistoryStart: (
|
|
componentType: PaneComponentEnum,
|
|
componentIdentifiers?: PaneIdentifiers | null
|
|
) => void;
|
|
paneHistoryPush: (
|
|
componentType: PaneComponentEnum,
|
|
componentIdentifiers?: PaneIdentifiers | null
|
|
) => void;
|
|
paneHistoryPrevious: () => void;
|
|
paneHistoryNext: () => void;
|
|
}
|
|
|
|
export interface SidebarContextType {
|
|
sidebar: SidebarInfo;
|
|
pane: PaneInfo;
|
|
}
|
|
|
|
export const SidebarContext = createContext<SidebarContextType>(null!);
|
|
|
|
export const SidebarProvider: FC = ({ children }) => {
|
|
const isMobile = useSelector(appEnvSelectors.getIsMobile);
|
|
const sheetDimensions = useSelector(appEnvSelectors.getDimensions);
|
|
|
|
const [isVisible, setIsVisible] = useState(false);
|
|
const [isLocked, setIsLocked] = useState(false);
|
|
const [placement, setPlacement] = useState(SidebarPlacementEnum.OVERLAY);
|
|
const [alignment, setAlignment] = useState(SidebarAlignmentEnum.RIGHT);
|
|
|
|
const [paneIdx, setPaneIdx] = useState<number>(0);
|
|
const [paneHistory, setPaneHistory] = useState<Array<PaneComponentInfo>>([]);
|
|
|
|
const [activePane, setActivePane] = useState<PaneComponentInfo | null>(null);
|
|
|
|
const width: number = 340;
|
|
|
|
//Create a new pane history
|
|
const paneHistoryStart = (
|
|
type: PaneComponentEnum,
|
|
identifiers: PaneIdentifiers | null = null
|
|
) => {
|
|
setIsVisible(true);
|
|
setPaneIdx(0);
|
|
setPaneHistory([
|
|
{
|
|
type,
|
|
identifiers,
|
|
},
|
|
]);
|
|
};
|
|
|
|
//Add a new pane to the history
|
|
const paneHistoryPush = (
|
|
type: PaneComponentEnum,
|
|
identifiers: PaneIdentifiers | null = null
|
|
) => {
|
|
if (paneIdx === null) {
|
|
paneHistoryStart(type, identifiers);
|
|
} else {
|
|
// get current active pane (last in history)
|
|
const activeHistoryElement = {
|
|
identifiers: activePane?.identifiers,
|
|
type: activePane?.type,
|
|
};
|
|
|
|
// create a new node for the history
|
|
const newHistoryElement = { identifiers, type };
|
|
|
|
// compare the current active pane with the new one (last element in history with new one)
|
|
if (!isEqual(activeHistoryElement, newHistoryElement)) {
|
|
// Check if new history element is different than current - otherwise skip to avoid duplicates
|
|
let newHistory = [
|
|
...paneHistory.slice(0, paneIdx + 1),
|
|
newHistoryElement,
|
|
];
|
|
setPaneHistory(newHistory);
|
|
setPaneIdx(newHistory.length - 1);
|
|
}
|
|
}
|
|
setIsVisible(true);
|
|
};
|
|
|
|
//Go back to the previous pane in the history
|
|
const paneHistoryPrevious = () => {
|
|
setPaneIdx(Math.max(0, paneIdx - 1));
|
|
};
|
|
|
|
//Go to the next pane in the history
|
|
const paneHistoryNext = () => {
|
|
setPaneIdx(Math.min(paneHistory.length - 1, paneIdx + 1));
|
|
};
|
|
|
|
useEffect(() => {
|
|
//If the window less than the fixed position start width (1600px), set the placement to overlay
|
|
if (
|
|
isMobile ||
|
|
sheetDimensions.window.width < SIDEBAR_FIXED_POSITION_START_WIDTH
|
|
) {
|
|
setPlacement(SidebarPlacementEnum.OVERLAY);
|
|
}
|
|
|
|
//set Right alignment if mobile
|
|
setAlignment(isMobile ? SidebarAlignmentEnum.RIGHT : alignment);
|
|
}, [isMobile, sheetDimensions]);
|
|
|
|
useEffect(() => {
|
|
const activePane = paneHistory[paneIdx];
|
|
setActivePane(activePane);
|
|
}, [paneIdx, paneHistory]);
|
|
|
|
return (
|
|
<SidebarContext.Provider
|
|
value={{
|
|
sidebar: {
|
|
isVisible,
|
|
setIsVisible,
|
|
isLocked,
|
|
setIsLocked,
|
|
placement,
|
|
setPlacement,
|
|
alignment,
|
|
setAlignment,
|
|
width,
|
|
},
|
|
pane: {
|
|
activePane,
|
|
showControls: paneHistory.length > 1,
|
|
isAtStart: paneIdx === 0,
|
|
isAtEnd: paneIdx === paneHistory.length - 1,
|
|
paneHistoryStart,
|
|
paneHistoryPush,
|
|
paneHistoryPrevious,
|
|
paneHistoryNext,
|
|
},
|
|
}}
|
|
>
|
|
{children}
|
|
</SidebarContext.Provider>
|
|
);
|
|
};
|
|
|
|
export const useSidebar = () => {
|
|
return useContext(SidebarContext);
|
|
};
|