Update toolbar

This commit is contained in:
Bill 2022-01-05 22:05:35 -05:00
parent 0e728d9654
commit 7a84fde7c3
6 changed files with 487 additions and 47 deletions

View File

@ -0,0 +1,58 @@
import { RoomObjectCategory } from '@nitrots/nitro-renderer';
import { FC, useEffect } from 'react';
import { GetRoomEngine, GetRoomSession } from '../../api';
import { ItemCountView } from '../../views/shared/item-count/ItemCountView';
import { ToolbarViewItems } from './common/ToolbarViewItems';
export interface ToolbarMeViewProps
{
unseenAchievementCount: number;
handleToolbarItemClick: (item: string) => void;
}
export const ToolbarMeView: FC<ToolbarMeViewProps> = props =>
{
const { unseenAchievementCount = 0, handleToolbarItemClick = null } = props;
useEffect(() =>
{
const roomSession = GetRoomSession();
if(!roomSession) return;
GetRoomEngine().selectRoomObject(roomSession.roomId, roomSession.ownRoomIndex, RoomObjectCategory.UNIT);
}, []);
return (
<div className="d-flex nitro-toolbar-me px-1 py-2">
<div className="navigation-items">
<div className="navigation-item">
<i className="icon icon-me-talents"></i>
</div>
<div className="navigation-item">
<i className="icon icon-me-helper-tool"></i>
</div>
<div className="navigation-item" onClick={ () => handleToolbarItemClick(ToolbarViewItems.ACHIEVEMENTS_ITEM) }>
<i className="icon icon-me-achievements"></i>
{ (unseenAchievementCount > 0) &&
<ItemCountView count={ unseenAchievementCount } /> }
</div>
<div className="navigation-item" onClick={ () => handleToolbarItemClick(ToolbarViewItems.PROFILE_ITEM) }>
<i className="icon icon-me-profile"></i>
</div>
<div className="navigation-item">
<i className="icon icon-me-rooms"></i>
</div>
<div className="navigation-item" onClick={ () => handleToolbarItemClick(ToolbarViewItems.CLOTHING_ITEM) }>
<i className="icon icon-me-clothing"></i>
</div>
<div className="navigation-item">
<i className="icon icon-me-forums"></i>
</div>
<div className="navigation-item" onClick={ () => handleToolbarItemClick(ToolbarViewItems.SETTINGS_ITEM) }>
<i className="icon icon-me-settings"></i>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,166 @@
.nitro-toolbar-container {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: $toolbar-height;
z-index: $toolbar-zindex;
.nitro-toolbar {
height: 100%;
pointer-events: all;
background: rgba($dark, 0.95);
box-shadow: inset 0px 5px lighten(rgba($dark, 0.6), 2.5),
inset 0 -4px darken(rgba($dark, 0.6), 4);
#toolbar-chat-input-container {
margin: 0 10px;
@include media-breakpoint-down(sm) {
width: 0px;
height: 0px;
}
}
.navigation-items {
display: flex;
align-items: center;
&.navigation-avatar {
border-right: 1px solid rgba(0, 0, 0, 0.3);
}
.navigation-item {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
//margin: 0 1px;
position: relative;
&.item-avatar {
width: 50px;
height: 45px;
overflow: hidden;
.avatar-image {
margin-left: -5px;
margin-top: 25px;
}
}
.icon,
&.item-avatar {
position: relative;
//transition: transform .2s ease-out;
&:hover,
&.active {
-webkit-transform: translate(-1px, -1px);
transform: translate(-1px, -1px);
filter: drop-shadow(2px 2px 0 rgba($black, 0.8));
}
}
.avatar-image {
pointer-events: none;
}
.chat-input-container {
left: 60px;
}
}
}
.nitro-toolbar-me-menu {
bottom: 77px;
left: 200px;
position: absolute;
font-size: 12px;
z-index: $toolbar-memenu-zindex;
.list-group {
.list-group-item {
min-width: 70px;
transition: all 0.3s;
font-size: 10px;
text-align: center;
i {
filter: grayscale(1);
}
&:hover {
color: $cyan;
text-decoration: underline;
i {
filter: grayscale(0);
}
}
.count {
top: 0px;
right: 5px;
font-size: 10px;
}
}
}
}
}
}
.toolbar-icon-animation {
position: absolute;
object-fit: cover;
height: auto;
width: auto;
max-width: 120px;
max-height: 150px;
z-index: 500;
filter: drop-shadow(2px 1px 0 rgba($white, 1))
drop-shadow(-2px 1px 0 rgba($white, 1))
drop-shadow(0 -2px 0 rgba($white, 1));
}
.nitro-toolbar-me {
position: absolute;
bottom: 65px;
left: 15px;
z-index: $toolbar-me-zindex;
background: rgba(20, 20, 20, .95);
border: 1px solid #101010;
box-shadow: inset 2px 2px rgba(255, 255, 255, .1), inset -2px -2px rgba(255, 255, 255, .1);
border-radius: $border-radius;
.navigation-items {
display: flex;
align-items: center;
&.navigation-avatar {
border-right: 1px solid rgba(0, 0, 0, .3);
}
.navigation-item {
position: relative;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
cursor: pointer;
width: 50px;
font-size: 11px;
.icon {
transition: filter .2s ease-out;
filter: grayscale(1);
}
&:hover {
.icon {
filter: grayscale(0) drop-shadow(2px 2px 0 rgba($black, 0.8));
}
}
}
}
}

View File

@ -0,0 +1,244 @@
import { Dispose, DropBounce, EaseOut, FigureUpdateEvent, JumpBy, Motions, NitroToolbarAnimateIconEvent, Queue, UserInfoDataParser, UserInfoEvent, Wait } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { CreateLinkEvent, GetRoomSession, GetRoomSessionManager, GetSessionDataManager, GetUserProfile, GoToDesktop, OpenMessengerChat } from '../../api';
import { AvatarEditorEvent, CatalogEvent, FriendsEvent, FriendsMessengerIconEvent, FriendsRequestCountEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events';
import { AchievementsUIEvent, AchievementsUIUnseenCountEvent } from '../../events/achievements';
import { UnseenItemTrackerUpdateEvent } from '../../events/inventory/UnseenItemTrackerUpdateEvent';
import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent';
import { UserSettingsUIEvent } from '../../events/user-settings/UserSettingsUIEvent';
import { BatchUpdates, dispatchUiEvent, useRoomEngineEvent, useUiEvent } from '../../hooks';
import { CreateMessageHook } from '../../hooks/messages/message-event';
import { TransitionAnimation } from '../../layout/transitions/TransitionAnimation';
import { TransitionAnimationTypes } from '../../layout/transitions/TransitionAnimation.types';
import { AvatarImageView } from '../../views/shared/avatar-image/AvatarImageView';
import { ItemCountView } from '../../views/shared/item-count/ItemCountView';
import { ToolbarViewItems } from './common/ToolbarViewItems';
import { ToolbarMeView } from './ToolbarMeView';
export interface ToolbarViewProps
{
isInRoom: boolean;
}
const CHAT_ICON_HIDDEN: number = 0;
const CHAT_ICON_SHOWING: number = 1;
const CHAT_ICON_UNREAD: number = 2;
export const ToolbarView: FC<ToolbarViewProps> = props =>
{
const { isInRoom } = props;
const [ userInfo, setUserInfo ] = useState<UserInfoDataParser>(null);
const [ userFigure, setUserFigure ] = useState<string>(null);
const [ isMeExpanded, setMeExpanded ] = useState(false);
const [ chatIconType, setChatIconType ] = useState(CHAT_ICON_HIDDEN);
const [ unseenInventoryCount, setUnseenInventoryCount ] = useState(0);
const [ unseenAchievementCount, setUnseenAchievementCount ] = useState(0);
const [ unseenFriendRequestCount, setFriendRequestCount ] = useState(0);
const isMod = GetSessionDataManager().isModerator;
const onUserInfoEvent = useCallback((event: UserInfoEvent) =>
{
const parser = event.getParser();
BatchUpdates(() =>
{
setUserInfo(parser.userInfo);
setUserFigure(parser.userInfo.figure);
});
}, []);
CreateMessageHook(UserInfoEvent, onUserInfoEvent);
const onUserFigureEvent = useCallback((event: FigureUpdateEvent) =>
{
const parser = event.getParser();
setUserFigure(parser.figure);
}, []);
CreateMessageHook(FigureUpdateEvent, onUserFigureEvent);
const onFriendsMessengerIconEvent = useCallback((event: FriendsMessengerIconEvent) =>
{
setChatIconType(event.iconType);
}, []);
useUiEvent(FriendsMessengerIconEvent.UPDATE_ICON, onFriendsMessengerIconEvent);
const onUnseenItemTrackerUpdateEvent = useCallback((event: UnseenItemTrackerUpdateEvent) =>
{
setUnseenInventoryCount(event.count);
}, []);
useUiEvent(UnseenItemTrackerUpdateEvent.UPDATE_COUNT, onUnseenItemTrackerUpdateEvent);
const onAchievementsUIUnseenCountEvent = useCallback((event: AchievementsUIUnseenCountEvent) =>
{
setUnseenAchievementCount(event.count);
}, []);
useUiEvent(AchievementsUIUnseenCountEvent.UNSEEN_COUNT, onAchievementsUIUnseenCountEvent);
const onFriendsRequestCountEvent = useCallback((event: FriendsRequestCountEvent) =>
{
setFriendRequestCount(event.count);
}, []);
useUiEvent(FriendsRequestCountEvent.UPDATE_COUNT, onFriendsRequestCountEvent);
const animationIconToToolbar = useCallback((iconName: string, image: HTMLImageElement, x: number, y: number) =>
{
const target = (document.body.getElementsByClassName(iconName)[0] as HTMLElement);
if(!target) return;
image.className = 'toolbar-icon-animation';
image.style.visibility = 'visible';
image.style.left = (x + 'px');
image.style.top = (y + 'px');
document.body.append(image);
const targetBounds = target.getBoundingClientRect();
const imageBounds = image.getBoundingClientRect();
const left = (imageBounds.x - targetBounds.x);
const top = (imageBounds.y - targetBounds.y);
const squared = Math.sqrt(((left * left) + (top * top)));
const wait = (500 - Math.abs(((((1 / squared) * 100) * 500) * 0.5)));
const height = 20;
const motionName = (`ToolbarBouncing[${ iconName }]`);
if(!Motions.getMotionByTag(motionName))
{
Motions.runMotion(new Queue(new Wait((wait + 8)), new DropBounce(target, 400, 12))).tag = motionName;
}
const motion = new Queue(new EaseOut(new JumpBy(image, wait, ((targetBounds.x - imageBounds.x) + height), (targetBounds.y - imageBounds.y), 100, 1), 1), new Dispose(image));
Motions.runMotion(motion);
}, []);
const onNitroToolbarAnimateIconEvent = useCallback((event: NitroToolbarAnimateIconEvent) =>
{
animationIconToToolbar('icon-inventory', event.image, event.x, event.y);
}, [ animationIconToToolbar ]);
useRoomEngineEvent(NitroToolbarAnimateIconEvent.ANIMATE_ICON, onNitroToolbarAnimateIconEvent);
const handleToolbarItemClick = useCallback((item: string) =>
{
switch(item)
{
case ToolbarViewItems.NAVIGATOR_ITEM:
dispatchUiEvent(new NavigatorEvent(NavigatorEvent.TOGGLE_NAVIGATOR));
return;
case ToolbarViewItems.INVENTORY_ITEM:
dispatchUiEvent(new InventoryEvent(InventoryEvent.TOGGLE_INVENTORY));
return;
case ToolbarViewItems.CATALOG_ITEM:
dispatchUiEvent(new CatalogEvent(CatalogEvent.TOGGLE_CATALOG));
return;
case ToolbarViewItems.FRIEND_LIST_ITEM:
dispatchUiEvent(new CatalogEvent(FriendsEvent.TOGGLE_FRIEND_LIST));
return;
case ToolbarViewItems.CAMERA_ITEM:
dispatchUiEvent(new RoomWidgetCameraEvent(RoomWidgetCameraEvent.TOGGLE_CAMERA));
return;
case ToolbarViewItems.CLOTHING_ITEM:
dispatchUiEvent(new AvatarEditorEvent(AvatarEditorEvent.TOGGLE_EDITOR));
setMeExpanded(false);
return;
case ToolbarViewItems.MOD_TOOLS_ITEM:
dispatchUiEvent(new ModToolsEvent(ModToolsEvent.TOGGLE_MOD_TOOLS));
return;
case ToolbarViewItems.ACHIEVEMENTS_ITEM:
dispatchUiEvent(new AchievementsUIEvent(AchievementsUIEvent.TOGGLE_ACHIEVEMENTS));
setMeExpanded(false);
return;
case ToolbarViewItems.PROFILE_ITEM:
GetUserProfile(GetSessionDataManager().userId);
setMeExpanded(false);
return;
case ToolbarViewItems.SETTINGS_ITEM:
dispatchUiEvent(new UserSettingsUIEvent(UserSettingsUIEvent.TOGGLE_USER_SETTINGS));
setMeExpanded(false);
return;
case ToolbarViewItems.FRIEND_CHAT_ITEM:
OpenMessengerChat();
return;
}
}, []);
const visitDesktop = useCallback(() =>
{
if(!GetRoomSession()) return;
GoToDesktop();
GetRoomSessionManager().removeSession(-1);
}, []);
return (
<div className="nitro-toolbar-container">
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ isMeExpanded } timeout={ 300 }>
<ToolbarMeView unseenAchievementCount={ unseenAchievementCount } handleToolbarItemClick={ handleToolbarItemClick } />
</TransitionAnimation>
<div className="d-flex justify-content-between align-items-center nitro-toolbar py-1 px-3">
<div className="d-flex align-items-center">
<div className="navigation-items gap-2">
<div className={ 'navigation-item item-avatar ' + (isMeExpanded ? 'active ' : '') } onClick={ event => setMeExpanded(!isMeExpanded) }>
<AvatarImageView figure={ userFigure } direction={ 2 } />
{ (unseenAchievementCount > 0) &&
<ItemCountView count={ unseenAchievementCount } /> }
</div>
{ isInRoom && (
<div className="navigation-item" onClick={ visitDesktop }>
<i className="icon icon-habbo"></i>
</div>) }
{ !isInRoom && (
<div className="navigation-item" onClick={ event => CreateLinkEvent('navigator/goto/home') }>
<i className="icon icon-house"></i>
</div>) }
<div className="navigation-item" onClick={ event => handleToolbarItemClick(ToolbarViewItems.NAVIGATOR_ITEM) }>
<i className="icon icon-rooms"></i>
</div>
<div className="navigation-item" onClick={ event => handleToolbarItemClick(ToolbarViewItems.CATALOG_ITEM) }>
<i className="icon icon-catalog"></i>
</div>
<div className="navigation-item" onClick={ event => handleToolbarItemClick(ToolbarViewItems.INVENTORY_ITEM) }>
<i className="icon icon-inventory"></i>
{ (unseenInventoryCount > 0) &&
<ItemCountView count={ unseenInventoryCount } /> }
</div>
{ isInRoom && (
<div className="navigation-item" onClick={ event => handleToolbarItemClick(ToolbarViewItems.CAMERA_ITEM) }>
<i className="icon icon-camera"></i>
</div>) }
{ isMod && (
<div className="navigation-item" onClick={ event => handleToolbarItemClick(ToolbarViewItems.MOD_TOOLS_ITEM) }>
<i className="icon icon-modtools"></i>
</div>) }
</div>
<div id="toolbar-chat-input-container" className="d-flex align-items-center" />
</div>
<div className="d-flex align-items-center gap-2">
<div className="navigation-items gap-2">
<div className="navigation-item" onClick={ event => handleToolbarItemClick(ToolbarViewItems.FRIEND_LIST_ITEM) }>
<i className="icon icon-friendall"></i>
{ (unseenFriendRequestCount > 0) &&
<ItemCountView count={ unseenFriendRequestCount } /> }
</div>
{ ((chatIconType === CHAT_ICON_SHOWING) || (chatIconType === CHAT_ICON_UNREAD)) &&
<div className="navigation-item" onClick={ event => handleToolbarItemClick(ToolbarViewItems.FRIEND_CHAT_ITEM) }>
{ (chatIconType === CHAT_ICON_SHOWING) && <i className="icon icon-message" /> }
{ (chatIconType === CHAT_ICON_UNREAD) && <i className="icon icon-message is-unseen" /> }
</div> }
</div>
<div id="toolbar-friend-bar-container" className="d-none d-lg-block" />
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,19 @@
export interface ToolbarViewProps
{
isInRoom: boolean;
}
export class ToolbarViewItems
{
public static NAVIGATOR_ITEM: string = 'TVI_NAVIGATOR_ITEM';
public static INVENTORY_ITEM: string = 'TVI_INVENTORY_ITEM';
public static CATALOG_ITEM: string = 'TVI_CATALOG_ITEM';
public static FRIEND_LIST_ITEM: string = 'TVI_FRIEND_LIST_ITEM';
public static FRIEND_CHAT_ITEM: string = 'TVI_FRIEND_CHAT_ITEM';
public static CLOTHING_ITEM: string = 'TVI_CLOTHING_ITEM';
public static CAMERA_ITEM: string = 'TVI_CAMERA_ITEM';
public static MOD_TOOLS_ITEM: string = 'TVI_MOD_TOOLS_ITEM';
public static ACHIEVEMENTS_ITEM: string = 'TVI_ACHIEVEMENTS_ITEM';
public static PROFILE_ITEM: string = 'TVI_PROFILE_ITEM';
public static SETTINGS_ITEM: string = 'TVI_SETTINGS_ITEM';
}

View File

@ -1,41 +0,0 @@
.nitro-toolbar-me {
position: absolute;
bottom: 65px;
left: 15px;
z-index: $toolbar-me-zindex;
background: rgba(20, 20, 20, .95);
border: 1px solid #101010;
box-shadow: inset 2px 2px rgba(255, 255, 255, .1), inset -2px -2px rgba(255, 255, 255, .1);
border-radius: $border-radius;
.navigation-items {
display: flex;
align-items: center;
&.navigation-avatar {
border-right: 1px solid rgba(0, 0, 0, .3);
}
.navigation-item {
position: relative;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
cursor: pointer;
width: 50px;
font-size: 11px;
.icon {
transition: filter .2s ease-out;
filter: grayscale(1);
}
&:hover {
.icon {
filter: grayscale(0) drop-shadow(2px 2px 0 rgba($black, 0.8));
}
}
}
}
}

View File

@ -1,6 +0,0 @@
export interface ToolbarMeViewProps
{
unseenAchievementCount: number;
handleToolbarItemClick: (item: string) => void;
}