collapsable context menu

This commit is contained in:
Layne 2022-04-13 02:28:13 -04:00
parent 1266b79989
commit c4fc67ac19
9 changed files with 71 additions and 10 deletions

View File

@ -87,7 +87,7 @@ export const AvatarInfoUseProductView: FC<AvatarInfoUseProductViewProps> = props
}, [ item, updateConfirmingProduct ]);
return (
<ContextMenuView objectId={ item.id } category={ RoomObjectCategory.UNIT } userType={ RoomObjectType.PET } close={ close }>
<ContextMenuView objectId={ item.id } category={ RoomObjectCategory.UNIT } userType={ RoomObjectType.PET } close={ close } collapsable={ true }>
<ContextMenuHeaderView>
{ item.name }
</ContextMenuHeaderView>

View File

@ -213,7 +213,7 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
}, [ userData ]);
return (
<ContextMenuView objectId={ userData.roomIndex } category={ RoomObjectCategory.UNIT } userType={ userData.userType } close={ close }>
<ContextMenuView objectId={ userData.roomIndex } category={ RoomObjectCategory.UNIT } userType={ userData.userType } close={ close } collapsable={ true }>
<ContextMenuHeaderView className="cursor-pointer" onClick={ event => GetUserProfile(userData.webID) }>
{ userData.name }
</ContextMenuHeaderView>

View File

@ -121,7 +121,8 @@ export const AvatarInfoWidgetOwnAvatarView: FC<AvatarInfoWidgetOwnAvatarViewProp
const isRidingHorse = IsRidingHorse();
return (
<ContextMenuView objectId={ userData.roomIndex } category={ RoomObjectCategory.UNIT } userType={ userData.userType } close={ close }>
<ContextMenuView objectId={ userData.roomIndex } category={ RoomObjectCategory.UNIT } userType={ userData.userType } close={ close } collapsable={ true }>
<ContextMenuHeaderView className="cursor-pointer" onClick={ event => GetUserProfile(userData.webID) }>
{ userData.name }
</ContextMenuHeaderView>

View File

@ -142,7 +142,7 @@ export const AvatarInfoWidgetOwnPetView: FC<AvatarInfoWidgetOwnPetViewProps> = p
}, [ petData ]);
return (
<ContextMenuView objectId={ petData.roomIndex } category={ RoomObjectCategory.UNIT } userType={ RoomObjectType.PET } close={ close }>
<ContextMenuView objectId={ petData.roomIndex } category={ RoomObjectCategory.UNIT } userType={ RoomObjectType.PET } close={ close } collapsable={ true }>
<ContextMenuHeaderView>
{ petData.name }
</ContextMenuHeaderView>

View File

@ -109,7 +109,7 @@ export const AvatarInfoWidgetPetView: FC<AvatarInfoWidgetPetViewProps> = props =
}, [ petData ]);
return (
<ContextMenuView objectId={ petData.roomIndex } category={ RoomObjectCategory.UNIT } userType={ RoomObjectType.PET } close={ close }>
<ContextMenuView objectId={ petData.roomIndex } category={ RoomObjectCategory.UNIT } userType={ RoomObjectType.PET } close={ close } collapsable={ true }>
<ContextMenuHeaderView>
{ petData.name }
</ContextMenuHeaderView>

View File

@ -136,7 +136,7 @@ export const AvatarInfoWidgetRentableBotView: FC<AvatarInfoWidgetRentableBotView
const canControl = (rentableBotData.amIOwner || rentableBotData.amIAnyRoomController);
return (
<ContextMenuView objectId={ rentableBotData.roomIndex } category={ RoomObjectCategory.UNIT } userType={ RoomObjectType.RENTABLE_BOT } close={ close }>
<ContextMenuView objectId={ rentableBotData.roomIndex } category={ RoomObjectCategory.UNIT } userType={ RoomObjectType.RENTABLE_BOT } close={ close } collapsable={ true }>
<ContextMenuHeaderView>
{ rentableBotData.name }
</ContextMenuHeaderView>

View File

@ -20,9 +20,11 @@
font-size: 18px;
}
&:not(.name-only) {
&:not(.name-only):not(.menu-hidden) {
min-width: 125px;
}
&:not(.name-only) {
&:after {
content: "";
position: absolute;
@ -49,6 +51,22 @@
margin-bottom: 2px;
}
&.menu-hidden {
.menu-footer {
padding-top:2px;
padding-bottom:0;
}
}
.menu-footer {
color: $white;
font-size: 16px;
width:100%;
min-width: 25px;
padding-bottom:2px;
cursor: pointer;
}
.menu-list-split-3 {
.menu-item {

View File

@ -0,0 +1,25 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { FC, useMemo } from 'react';
import { Flex, FlexProps } from '../../../../common';
interface CaretViewProps extends FlexProps
{
collapsed?: boolean;
}
export const ContextMenuCaretView: FC<CaretViewProps> = props =>
{
const { justifyContent = 'center', alignItems = 'center', classNames = [], collapsed = true, ...rest } = props;
const getClassNames = useMemo(() =>
{
const newClassNames: string[] = [ 'menu-footer' ];
if(classNames.length) newClassNames.push(...classNames);
return newClassNames;
}, [ classNames ]);
return <Flex justifyContent={ justifyContent } alignItems={ alignItems } classNames={ getClassNames } { ...rest }>
<FontAwesomeIcon icon={ !collapsed ? 'caret-down' : 'caret-up' } className="align-self-center" />
</Flex>
}

View File

@ -2,6 +2,7 @@ import { FixedSizeStack, NitroPoint, NitroRectangle, RoomObjectType } from '@nit
import { CSSProperties, FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { GetNitroInstance, GetRoomObjectBounds, GetRoomObjectScreenLocation, GetRoomSession, GetTicker } from '../../../../api';
import { Base, BaseProps } from '../../../../common';
import { ContextMenuCaretView } from './ContextMenuCaretView';
interface ContextMenuViewProps extends BaseProps<HTMLDivElement>
{
@ -10,6 +11,7 @@ interface ContextMenuViewProps extends BaseProps<HTMLDivElement>
userType?: number;
fades?: boolean;
close: () => void;
collapsable?: boolean;
}
const LOCATION_STACK_SIZE: number = 25;
@ -18,9 +20,11 @@ const fadeDelay = 3000;
const fadeLength = 75;
const SPACE_AROUND_EDGES = 10;
let COLLAPSED = false;
export const ContextMenuView: FC<ContextMenuViewProps> = props =>
{
const { objectId = -1, category = -1, userType = -1, fades = false, close = null, position = 'absolute', classNames = [], style = {}, ...rest } = props;
const { objectId = -1, category = -1, userType = -1, fades = false, close = null, position = 'absolute', classNames = [], style = {}, children = null, collapsable = false, ...rest } = props;
const [ pos, setPos ] = useState<{ x: number, y: number }>({ x: null, y: null });
const [ deltaYStack, setDeltaYStack ] = useState<FixedSizeStack>(null);
const [ currentDeltaY, setCurrentDeltaY ] = useState(-1000000);
@ -30,6 +34,8 @@ export const ContextMenuView: FC<ContextMenuViewProps> = props =>
const [ isFrozen, setIsFrozen ] = useState(false);
const elementRef = useRef<HTMLDivElement>();
const [ collapsed, setCollapsed ] = useState(COLLAPSED);
const getOffset = useCallback((bounds: NitroRectangle) =>
{
let height = -(elementRef.current.offsetHeight);
@ -119,12 +125,14 @@ export const ContextMenuView: FC<ContextMenuViewProps> = props =>
{
const newClassNames: string[] = [ 'nitro-context-menu' ];
if (collapsed) newClassNames.push('menu-hidden');
newClassNames.push((pos.x !== null) ? 'visible' : 'invisible');
if(classNames.length) newClassNames.push(...classNames);
return newClassNames;
}, [ pos, classNames ]);
}, [ pos, classNames, collapsed ]);
const getStyle = useMemo(() =>
{
@ -171,5 +179,14 @@ export const ContextMenuView: FC<ContextMenuViewProps> = props =>
return () => clearTimeout(timeout);
}, [ fades ]);
return <Base innerRef={ elementRef } position={ position } classNames={ getClassNames } style={ getStyle } onMouseOver={ event => setIsFrozen(true) } onMouseOut={ event => setIsFrozen(false) } { ...rest } />;
const toggleCollapse = () =>
{
COLLAPSED = !COLLAPSED;
setCollapsed(COLLAPSED)
}
return <Base innerRef={ elementRef } position={ position } classNames={ getClassNames } style={ getStyle } onMouseOver={ event => setIsFrozen(true) } onMouseOut={ event => setIsFrozen(false) } { ...rest }>
{ !(collapsable && COLLAPSED) && children }
{ collapsable && <ContextMenuCaretView onClick={ () => toggleCollapse() } collapsed={ collapsed } /> }
</Base>;
}