mirror of
https://github.com/duckietm/Nitro-Cool-UI.git
synced 2025-06-21 14:26:58 +00:00
🎴 Updated Animation
Please run yarn install as we have added a other way to do animation
This commit is contained in:
parent
44e2514921
commit
1949f7c807
@ -18,6 +18,7 @@
|
|||||||
"dompurify": "^3.0.11",
|
"dompurify": "^3.0.11",
|
||||||
"emoji-mart": "^5.5.2",
|
"emoji-mart": "^5.5.2",
|
||||||
"emoji-toolkit": "8.0.0",
|
"emoji-toolkit": "8.0.0",
|
||||||
|
"framer-motion": "^11.2.12",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-bootstrap": "^2.7.2",
|
"react-bootstrap": "^2.7.2",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
12
src/App.tsx
12
src/App.tsx
@ -1,7 +1,8 @@
|
|||||||
import { ConfigurationEvent, GetAssetManager, HabboWebTools, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroConfiguration, NitroEvent, NitroLocalizationEvent, NitroVersion, RoomEngineEvent } from '@nitrots/nitro-renderer';
|
import { ConfigurationEvent, GetAssetManager, HabboWebTools, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroConfiguration, NitroEvent, NitroLocalizationEvent, NitroVersion, RoomEngineEvent } from '@nitrots/nitro-renderer';
|
||||||
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
import { Base } from './common';
|
||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { GetCommunication, GetConfiguration, GetNitroInstance, GetUIVersion } from './api';
|
import { GetCommunication, GetConfiguration, GetNitroInstance, GetUIVersion } from './api';
|
||||||
import { Base, TransitionAnimation, TransitionAnimationTypes } from './common';
|
|
||||||
import { LoadingView } from './components/loading/LoadingView';
|
import { LoadingView } from './components/loading/LoadingView';
|
||||||
import { MainView } from './components/main/MainView';
|
import { MainView } from './components/main/MainView';
|
||||||
import { useConfigurationEvent, useLocalizationEvent, useMainEvent, useRoomEngineEvent } from './hooks';
|
import { useConfigurationEvent, useLocalizationEvent, useMainEvent, useRoomEngineEvent } from './hooks';
|
||||||
@ -132,9 +133,12 @@ export const App: FC<{}> = props =>
|
|||||||
<Base fit overflow="hidden" className={ imageRendering && 'image-rendering-pixelated' }>
|
<Base fit overflow="hidden" className={ imageRendering && 'image-rendering-pixelated' }>
|
||||||
{ (!isReady || isError) &&
|
{ (!isReady || isError) &&
|
||||||
<LoadingView isError={ isError } message={ message } percent={ percent } /> }
|
<LoadingView isError={ isError } message={ message } percent={ percent } /> }
|
||||||
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ (isReady) }>
|
<AnimatePresence>
|
||||||
<MainView />
|
{ isReady && ( <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.3 }}>
|
||||||
</TransitionAnimation>
|
<MainView />
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
<Base id="draggable-windows-container" />
|
<Base id="draggable-windows-container" />
|
||||||
</Base>
|
</Base>
|
||||||
);
|
);
|
||||||
|
@ -18,6 +18,5 @@ export * from './layout';
|
|||||||
export * from './layout/limited-edition';
|
export * from './layout/limited-edition';
|
||||||
export * from "./Slider";
|
export * from "./Slider";
|
||||||
export * from './Text';
|
export * from './Text';
|
||||||
export * from './transitions';
|
|
||||||
export * from './types';
|
export * from './types';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { FC, useEffect, useMemo, useState } from 'react';
|
import { FC, useEffect, useMemo, useState } from 'react';
|
||||||
import { Flex, FlexProps } from '..';
|
import { Flex, FlexProps } from '..';
|
||||||
import { TransitionAnimation, TransitionAnimationTypes } from '../transitions';
|
|
||||||
|
|
||||||
export interface LayoutNotificationBubbleViewProps extends FlexProps
|
export interface LayoutNotificationBubbleViewProps extends FlexProps
|
||||||
{
|
{
|
||||||
@ -45,8 +45,14 @@ export const LayoutNotificationBubbleView: FC<LayoutNotificationBubbleViewProps>
|
|||||||
}, [ fadesOut, timeoutMs, onClose ]);
|
}, [ fadesOut, timeoutMs, onClose ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ isVisible } timeout={ 300 }>
|
<AnimatePresence>
|
||||||
<Flex overflow={ overflow } classNames={ getClassNames } onClick={ onClose } { ...rest } />
|
{ isVisible &&
|
||||||
</TransitionAnimation>
|
<motion.div
|
||||||
|
initial={ { opacity: 0 }}
|
||||||
|
animate={ { opacity: 1 }}
|
||||||
|
exit={ { opacity: 0 }}>
|
||||||
|
<Flex overflow={ overflow } classNames={ getClassNames } onClick={ onClose } { ...rest } />
|
||||||
|
</motion.div> }
|
||||||
|
</AnimatePresence>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
import { FC, ReactNode, useEffect, useState } from 'react';
|
|
||||||
import { Transition } from 'react-transition-group';
|
|
||||||
import { getTransitionAnimationStyle } from './TransitionAnimationStyles';
|
|
||||||
|
|
||||||
interface TransitionAnimationProps
|
|
||||||
{
|
|
||||||
type: string;
|
|
||||||
inProp: boolean;
|
|
||||||
timeout?: number;
|
|
||||||
className?: string;
|
|
||||||
children?: ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TransitionAnimation: FC<TransitionAnimationProps> = props =>
|
|
||||||
{
|
|
||||||
const { type = null, inProp = false, timeout = 300, className = null, children = null } = props;
|
|
||||||
|
|
||||||
const [ isChildrenVisible, setChildrenVisible ] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
let timeoutData: ReturnType<typeof setTimeout> = null;
|
|
||||||
|
|
||||||
if(inProp)
|
|
||||||
{
|
|
||||||
setChildrenVisible(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
timeoutData = setTimeout(() =>
|
|
||||||
{
|
|
||||||
setChildrenVisible(false);
|
|
||||||
clearTimeout(timeout);
|
|
||||||
}, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () =>
|
|
||||||
{
|
|
||||||
if(timeoutData) clearTimeout(timeoutData);
|
|
||||||
}
|
|
||||||
}, [ inProp, timeout ]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Transition in={ inProp } timeout={ timeout }>
|
|
||||||
{ state => (
|
|
||||||
<div className={ (className ?? '') + ' animate__animated' } style={ { ...getTransitionAnimationStyle(type, state, timeout) } }>
|
|
||||||
{ isChildrenVisible && children }
|
|
||||||
</div>
|
|
||||||
) }
|
|
||||||
</Transition>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
import { CSSProperties } from 'react';
|
|
||||||
import { TransitionStatus } from 'react-transition-group';
|
|
||||||
import { ENTERING, EXITING } from 'react-transition-group/Transition';
|
|
||||||
import { TransitionAnimationTypes } from './TransitionAnimationTypes';
|
|
||||||
|
|
||||||
export function getTransitionAnimationStyle(type: string, transition: TransitionStatus, timeout: number = 300): Partial<CSSProperties>
|
|
||||||
{
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case TransitionAnimationTypes.BOUNCE:
|
|
||||||
switch(transition)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return {}
|
|
||||||
case ENTERING:
|
|
||||||
return {
|
|
||||||
animationName: 'bounceIn',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
case EXITING:
|
|
||||||
return {
|
|
||||||
animationName: 'bounceOut',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case TransitionAnimationTypes.SLIDE_LEFT:
|
|
||||||
switch(transition)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return {}
|
|
||||||
case ENTERING:
|
|
||||||
return {
|
|
||||||
animationName: 'slideInLeft',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
case EXITING:
|
|
||||||
return {
|
|
||||||
animationName: 'slideOutLeft',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case TransitionAnimationTypes.SLIDE_RIGHT:
|
|
||||||
switch(transition)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return {}
|
|
||||||
case ENTERING:
|
|
||||||
return {
|
|
||||||
animationName: 'slideInRight',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
case EXITING:
|
|
||||||
return {
|
|
||||||
animationName: 'slideOutRight',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case TransitionAnimationTypes.FLIP_X:
|
|
||||||
switch(transition)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return {}
|
|
||||||
case ENTERING:
|
|
||||||
return {
|
|
||||||
animationName: 'flipInX',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
case EXITING:
|
|
||||||
return {
|
|
||||||
animationName: 'flipOutX',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case TransitionAnimationTypes.FADE_UP:
|
|
||||||
switch(transition)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return {}
|
|
||||||
case ENTERING:
|
|
||||||
return {
|
|
||||||
animationName: 'fadeInUp',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
case EXITING:
|
|
||||||
return {
|
|
||||||
animationName: 'fadeOutDown',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case TransitionAnimationTypes.FADE_IN:
|
|
||||||
switch(transition)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return {}
|
|
||||||
case ENTERING:
|
|
||||||
return {
|
|
||||||
animationName: 'fadeIn',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
case EXITING:
|
|
||||||
return {
|
|
||||||
animationName: 'fadeOut',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case TransitionAnimationTypes.FADE_DOWN:
|
|
||||||
switch(transition)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return {}
|
|
||||||
case ENTERING:
|
|
||||||
return {
|
|
||||||
animationName: 'fadeInDown',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
case EXITING:
|
|
||||||
return {
|
|
||||||
animationName: 'fadeOutUp',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case TransitionAnimationTypes.HEAD_SHAKE:
|
|
||||||
switch(transition)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return {}
|
|
||||||
case ENTERING:
|
|
||||||
return {
|
|
||||||
animationName: 'headShake',
|
|
||||||
animationDuration: `${ timeout }ms`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
export class TransitionAnimationTypes
|
|
||||||
{
|
|
||||||
public static BOUNCE: string = 'bounce';
|
|
||||||
public static SLIDE_LEFT: string = 'slideLeft';
|
|
||||||
public static SLIDE_RIGHT: string = 'slideRight';
|
|
||||||
public static FLIP_X: string = 'flipX';
|
|
||||||
public static FADE_IN: string = 'fadeIn';
|
|
||||||
public static FADE_DOWN: string = 'fadeDown';
|
|
||||||
public static FADE_UP: string = 'fadeUp';
|
|
||||||
public static HEAD_SHAKE: string = 'headShake';
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
export * from './TransitionAnimation';
|
|
||||||
export * from './TransitionAnimationStyles';
|
|
||||||
export * from './TransitionAnimationTypes';
|
|
@ -1,7 +1,8 @@
|
|||||||
import { HabboWebTools, ILinkEventTracker, RoomSessionEvent } from '@nitrots/nitro-renderer';
|
import { HabboWebTools, ILinkEventTracker, RoomSessionEvent } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { AddEventLinkTracker, GetCommunication, RemoveLinkEventTracker } from '../../api';
|
import { AddEventLinkTracker, GetCommunication, RemoveLinkEventTracker } from '../../api';
|
||||||
import { Base, TransitionAnimation, TransitionAnimationTypes } from '../../common';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
import { Base } from '../../common';
|
||||||
import { useRoomSessionManagerEvent } from '../../hooks';
|
import { useRoomSessionManagerEvent } from '../../hooks';
|
||||||
import { AchievementsView } from '../achievements/AchievementsView';
|
import { AchievementsView } from '../achievements/AchievementsView';
|
||||||
import { AvatarEditorView } from '../avatar-editor/AvatarEditorView';
|
import { AvatarEditorView } from '../avatar-editor/AvatarEditorView';
|
||||||
@ -83,9 +84,15 @@ export const MainView: FC<{}> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Base fit>
|
<Base fit>
|
||||||
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ landingViewVisible } timeout={ 300 }>
|
<AnimatePresence>
|
||||||
<HotelView />
|
{ landingViewVisible &&
|
||||||
</TransitionAnimation>
|
<motion.div
|
||||||
|
initial={ { opacity: 0 }}
|
||||||
|
animate={ { opacity: 1 }}
|
||||||
|
exit={ { opacity: 0 }}>
|
||||||
|
<HotelView />
|
||||||
|
</motion.div> }
|
||||||
|
</AnimatePresence>
|
||||||
<ToolbarView isInRoom={ !landingViewVisible } />
|
<ToolbarView isInRoom={ !landingViewVisible } />
|
||||||
<ModToolsView />
|
<ModToolsView />
|
||||||
<RoomView />
|
<RoomView />
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { RoomSession } from '@nitrots/nitro-renderer';
|
||||||
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { FC, useEffect, useRef } from 'react';
|
import { FC, useEffect, useRef } from 'react';
|
||||||
import { DispatchMouseEvent, DispatchTouchEvent, GetNitroInstance } from '../../api';
|
import { DispatchMouseEvent, DispatchTouchEvent, GetNitroInstance } from '../../api';
|
||||||
import { Base } from '../../common';
|
import { Base } from '../../common';
|
||||||
@ -12,6 +14,8 @@ export const RoomView: FC<{}> = props =>
|
|||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
|
if(!roomSession) return;
|
||||||
|
|
||||||
const canvas = GetNitroInstance().application.renderer.view;
|
const canvas = GetNitroInstance().application.renderer.view;
|
||||||
|
|
||||||
if(!canvas) return;
|
if(!canvas) return;
|
||||||
@ -31,15 +35,24 @@ export const RoomView: FC<{}> = props =>
|
|||||||
if(!element) return;
|
if(!element) return;
|
||||||
|
|
||||||
element.appendChild(canvas);
|
element.appendChild(canvas);
|
||||||
}, []);
|
}, [ roomSession ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Base fit innerRef={ elementRef } className={ (!roomSession && 'd-none') }>
|
<AnimatePresence>
|
||||||
{ roomSession &&
|
{
|
||||||
<>
|
<motion.div
|
||||||
<RoomWidgetsView />
|
initial={ { opacity: 0 }}
|
||||||
{ roomSession.isSpectator && <RoomSpectatorView /> }
|
animate={ { opacity: 1 }}
|
||||||
</> }
|
exit={ { opacity: 0 }}>
|
||||||
</Base>
|
<div ref={ elementRef } className="w-100 h-100">
|
||||||
|
{ roomSession instanceof RoomSession &&
|
||||||
|
<>
|
||||||
|
<RoomWidgetsView />
|
||||||
|
{ roomSession.isSpectator && <RoomSpectatorView /> }
|
||||||
|
</> }
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
}
|
||||||
|
</AnimatePresence>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
.nitro-room-tools-container {
|
.nitro-room-tools-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: $toolbar-height + 25px;
|
bottom: $toolbar-height + 25px;
|
||||||
left: 0;
|
left: 0px;
|
||||||
|
display: flex; // Lay out children side by side
|
||||||
|
align-items: flex-start; // Align items to the top
|
||||||
|
|
||||||
.nitro-room-tools {
|
.nitro-room-tools {
|
||||||
background: #212131;
|
background: #212131;
|
||||||
@ -9,13 +11,13 @@
|
|||||||
border-top-right-radius: $border-radius;
|
border-top-right-radius: $border-radius;
|
||||||
border-bottom-right-radius: $border-radius;
|
border-bottom-right-radius: $border-radius;
|
||||||
transition: all .2s ease;
|
transition: all .2s ease;
|
||||||
z-index: 71;
|
z-index: 2;
|
||||||
margin-left: -20px;
|
margin-left: -20px;
|
||||||
|
|
||||||
.list-group-item {
|
.list-group-item {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
padding: 3px 0px;
|
padding: 3px 0px;
|
||||||
color: $white;
|
color: #FFF;
|
||||||
border-color: rgba($black, 0.3);
|
border-color: rgba($black, 0.3);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
@ -46,13 +48,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nitro-room-tools-side-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column; // Stack children vertically
|
||||||
|
margin-left: 10px; // Space between nitro-room-tools and side container
|
||||||
|
gap: 10px; // Space between history and info
|
||||||
|
}
|
||||||
|
|
||||||
.nitro-room-history {
|
.nitro-room-history {
|
||||||
background: #212131;
|
background: #212131;
|
||||||
box-shadow: inset 0px 5px lighten(rgba($dark, .6), 2.5), inset 0 -4px darken(rgba($dark, .6), 4);
|
box-shadow: inset 0px 5px lighten(rgba($dark, .6), 2.5), inset 0 -4px darken(rgba($dark, .6), 4);
|
||||||
transition: all .2s ease;
|
transition: all .2s ease;
|
||||||
width: 150px;
|
width: 150px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
z-index: 3;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nitro-room-tools-info {
|
.nitro-room-tools-info {
|
||||||
|
@ -12,9 +12,11 @@ export const FurnitureCraftingView: FC<{}> = props =>
|
|||||||
|
|
||||||
const isOwner = useMemo(() =>
|
const isOwner = useMemo(() =>
|
||||||
{
|
{
|
||||||
|
if(!roomSession) return false;
|
||||||
|
|
||||||
const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, objectId, RoomObjectCategory.FLOOR);
|
const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, objectId, RoomObjectCategory.FLOOR);
|
||||||
return IsOwnerOfFurniture(roomObject);
|
return IsOwnerOfFurniture(roomObject);
|
||||||
}, [ objectId, roomSession.roomId ]);
|
}, [ objectId, roomSession ]);
|
||||||
|
|
||||||
const canCraft = useMemo(() =>
|
const canCraft = useMemo(() =>
|
||||||
{
|
{
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { GetGuestRoomResultEvent, NavigatorSearchComposer, RateFlatMessageComposer, RoomDataParser } from '@nitrots/nitro-renderer';
|
import { GetGuestRoomResultEvent, NavigatorSearchComposer, RateFlatMessageComposer, RoomDataParser } from '@nitrots/nitro-renderer';
|
||||||
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { CreateLinkEvent, GetRoomEngine, LocalizeText, SendMessageComposer, SetLocalStorage, TryVisitRoom } from '../../../../api';
|
import { CreateLinkEvent, GetRoomEngine, LocalizeText, SendMessageComposer, SetLocalStorage, TryVisitRoom } from '../../../../api';
|
||||||
import { Base, Column, Flex, Text, TransitionAnimation, TransitionAnimationTypes, classNames } from '../../../../common';
|
import { Base, Column, Flex, Text, classNames } from '../../../../common';
|
||||||
import { useMessageEvent, useNavigator, useRoom } from '../../../../hooks';
|
import { useMessageEvent, useNavigator, useRoom } from '../../../../hooks';
|
||||||
|
|
||||||
export const RoomToolsWidgetView: FC<{}> = props =>
|
export const RoomToolsWidgetView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ areBubblesMuted, setAreBubblesMuted ] = useState(false);
|
const [ areBubblesMuted, setAreBubblesMuted ] = useState(false);
|
||||||
const [ isZoomedIn, setIsZoomedIn ] = useState<boolean>(false);
|
const [ isZoomedIn, setIsZoomedIn ] = useState<boolean>(false);
|
||||||
const [ roomName, setRoomName ] = useState<string>(null);
|
const [ roomName, setRoomName ] = useState<string>(null);
|
||||||
const [ roomOwner, setRoomOwner ] = useState<string>(null);
|
const [ roomOwner, setRoomOwner ] = useState<string>(null);
|
||||||
@ -17,8 +18,8 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
const [ roomHistory, setRoomHistory ] = useState<{ roomId: number, roomName: string }[]>([]);
|
const [ roomHistory, setRoomHistory ] = useState<{ roomId: number, roomName: string }[]>([]);
|
||||||
const { navigatorData = null } = useNavigator();
|
const { navigatorData = null } = useNavigator();
|
||||||
const { roomSession = null } = useRoom();
|
const { roomSession = null } = useRoom();
|
||||||
|
|
||||||
useEffect(() => { if (!roomName) { setRoomName(LocalizeText('landing.view.generic.welcome.first_login')); } }, [roomName]);
|
useEffect(() => { if (!roomName) { setRoomName(LocalizeText('landing.view.generic.welcome.first_login')); } }, [roomName]);
|
||||||
|
|
||||||
const handleToolClick = (action: string, value?: string) =>
|
const handleToolClick = (action: string, value?: string) =>
|
||||||
{
|
{
|
||||||
@ -31,35 +32,32 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
setIsZoomedIn(prevValue =>
|
setIsZoomedIn(prevValue =>
|
||||||
{
|
{
|
||||||
let scale = GetRoomEngine().getRoomInstanceRenderingCanvasScale(roomSession.roomId, 1);
|
let scale = GetRoomEngine().getRoomInstanceRenderingCanvasScale(roomSession.roomId, 1);
|
||||||
|
|
||||||
if(!prevValue) scale /= 2;
|
if(!prevValue) scale /= 2;
|
||||||
else scale *= 2;
|
else scale *= 2;
|
||||||
|
|
||||||
GetRoomEngine().setRoomInstanceRenderingCanvasScale(roomSession.roomId, 1, scale);
|
GetRoomEngine().setRoomInstanceRenderingCanvasScale(roomSession.roomId, 1, scale);
|
||||||
|
|
||||||
return !prevValue;
|
return !prevValue;
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
case 'chat_history':
|
case 'chat_history':
|
||||||
CreateLinkEvent('chat-history/toggle');
|
CreateLinkEvent('chat-history/toggle');
|
||||||
return;
|
return;
|
||||||
case 'hiddenbubbles':
|
case 'hiddenbubbles':
|
||||||
CreateLinkEvent('nitrobubblehidden/toggle');
|
CreateLinkEvent('nitrobubblehidden/toggle');
|
||||||
const bubbleElement = document.getElementById('bubble');
|
const bubbleElement = document.getElementById('bubble');
|
||||||
if (bubbleElement) {
|
if (bubbleElement) {
|
||||||
bubbleElement.classList.toggle('icon-chat-disablebubble');
|
bubbleElement.classList.toggle('icon-chat-disablebubble');
|
||||||
}
|
}
|
||||||
const hiddenbubblesTextElement = document.getElementById('hiddenbubblesText');
|
const hiddenbubblesTextElement = document.getElementById('hiddenbubblesText');
|
||||||
if (hiddenbubblesTextElement) {
|
if (hiddenbubblesTextElement) {
|
||||||
const newText = areBubblesMuted ? LocalizeText('room.unmute.button.text') : LocalizeText('room.mute.button.text');
|
const newText = areBubblesMuted ? LocalizeText('room.unmute.button.text') : LocalizeText('room.mute.button.text');
|
||||||
hiddenbubblesTextElement.innerText = newText;
|
hiddenbubblesTextElement.innerText = newText;
|
||||||
}
|
}
|
||||||
setAreBubblesMuted(!areBubblesMuted);
|
setAreBubblesMuted(!areBubblesMuted);
|
||||||
const bubbleIcon = document.getElementById('bubbleIcon');
|
const bubbleIcon = document.getElementById('bubbleIcon');
|
||||||
if (bubbleIcon) {
|
if (bubbleIcon) {
|
||||||
bubbleIcon.classList.toggle('icon-chat-disablebubble');
|
bubbleIcon.classList.toggle('icon-chat-disablebubble');
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case 'like_room':
|
case 'like_room':
|
||||||
SendMessageComposer(new RateFlatMessageComposer(1));
|
SendMessageComposer(new RateFlatMessageComposer(1));
|
||||||
return;
|
return;
|
||||||
@ -85,13 +83,9 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
const onChangeRoomHistory = (roomId: number, roomName: string) =>
|
const onChangeRoomHistory = (roomId: number, roomName: string) =>
|
||||||
{
|
{
|
||||||
let newStorage = JSON.parse(window.localStorage.getItem('nitro.room.history'));
|
let newStorage = JSON.parse(window.localStorage.getItem('nitro.room.history'));
|
||||||
|
|
||||||
if (newStorage && newStorage.filter( (room: RoomDataParser) => room.roomId === roomId ).length > 0) return;
|
if (newStorage && newStorage.filter( (room: RoomDataParser) => room.roomId === roomId ).length > 0) return;
|
||||||
|
|
||||||
if (newStorage && newStorage.length >= 10) newStorage.shift();
|
if (newStorage && newStorage.length >= 10) newStorage.shift();
|
||||||
|
|
||||||
const newData = !newStorage ? [ { roomId: roomId, roomName: roomName } ] : [ ...newStorage, { roomId: roomId, roomName: roomName } ];
|
const newData = !newStorage ? [ { roomId: roomId, roomName: roomName } ] : [ ...newStorage, { roomId: roomId, roomName: roomName } ];
|
||||||
|
|
||||||
setRoomHistory(newData);
|
setRoomHistory(newData);
|
||||||
return SetLocalStorage('nitro.room.history', newData );
|
return SetLocalStorage('nitro.room.history', newData );
|
||||||
}
|
}
|
||||||
@ -99,13 +93,11 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
useMessageEvent<GetGuestRoomResultEvent>(GetGuestRoomResultEvent, event =>
|
useMessageEvent<GetGuestRoomResultEvent>(GetGuestRoomResultEvent, event =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
if(!parser.roomEnter || (parser.data.roomId !== roomSession.roomId)) return;
|
if(!parser.roomEnter || (parser.data.roomId !== roomSession.roomId)) return;
|
||||||
|
|
||||||
if(roomName !== parser.data.roomName) setRoomName(parser.data.roomName);
|
if(roomName !== parser.data.roomName) setRoomName(parser.data.roomName);
|
||||||
if(roomOwner !== parser.data.ownerName) setRoomOwner(parser.data.ownerName);
|
if(roomOwner !== parser.data.ownerName) setRoomOwner(parser.data.ownerName);
|
||||||
if(roomTags !== parser.data.tags) setRoomTags(parser.data.tags);
|
if(roomTags !== parser.data.tags) setRoomTags(parser.data.tags);
|
||||||
|
|
||||||
onChangeRoomHistory(parser.data.roomId, parser.data.roomName);
|
onChangeRoomHistory(parser.data.roomId, parser.data.roomName);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -115,21 +107,14 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
{
|
{
|
||||||
if (JSON.parse(window.localStorage.getItem('nitro.room.history'))) window.localStorage.removeItem('nitro.room.history');
|
if (JSON.parse(window.localStorage.getItem('nitro.room.history'))) window.localStorage.removeItem('nitro.room.history');
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener('beforeunload', handleTabClose);
|
window.addEventListener('beforeunload', handleTabClose);
|
||||||
|
return () => window.removeEventListener('beforeunload', handleTabClose);
|
||||||
return () =>
|
|
||||||
{
|
|
||||||
window.removeEventListener('beforeunload', handleTabClose);
|
|
||||||
};
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
|
|
||||||
const timeout = setTimeout(() => setIsOpen(false), 5000);
|
const timeout = setTimeout(() => setIsOpen(false), 5000);
|
||||||
|
|
||||||
return () => clearTimeout(timeout);
|
return () => clearTimeout(timeout);
|
||||||
}, [ roomName, roomOwner, roomTags, show ]);
|
}, [ roomName, roomOwner, roomTags, show ]);
|
||||||
|
|
||||||
@ -154,7 +139,7 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
{ navigatorData.canRate &&
|
{ navigatorData.canRate &&
|
||||||
<Base pointer title={ LocalizeText('room.like.button.text') } onClick={ () => handleToolClick('like_room') } className="icon icon-like-room" /> }
|
<Base pointer title={ LocalizeText('room.like.button.text') } onClick={ () => handleToolClick('like_room') } className="icon icon-like-room" /> }
|
||||||
<Base pointer onClick={ () => handleToolClick('toggle_room_link') } className="icon icon-room-link" />
|
<Base pointer onClick={ () => handleToolClick('toggle_room_link') } className="icon icon-room-link" />
|
||||||
<Base pointer onClick={ () => handleToolClick('hiddenbubbles') } className={`icon ${areBubblesMuted ? 'icon-chat-disablebubble' : 'icon-chat-enablebubble'}`} />
|
<Base pointer onClick={ () => handleToolClick('hiddenbubbles') } className={`icon ${areBubblesMuted ? 'icon-chat-disablebubble' : 'icon-chat-enablebubble'}`} />
|
||||||
</Column>
|
</Column>
|
||||||
<Column className="d-flex flex-column">
|
<Column className="d-flex flex-column">
|
||||||
<Flex className="w-100 room-tool-item">
|
<Flex className="w-100 room-tool-item">
|
||||||
@ -164,7 +149,8 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
<Text variant="muted" underline small onClick={ () => handleToolClick('zoom') }>{ LocalizeText('room.zoom.button.text') }</Text>
|
<Text variant="muted" underline small onClick={ () => handleToolClick('zoom') }>{ LocalizeText('room.zoom.button.text') }</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex className="w-100 room-tool-item">
|
<Flex className="w-100 room-tool-item">
|
||||||
<Text variant="muted" underline small onClick={ () => handleToolClick('chat_history') }>{ LocalizeText('room.chathistory.button.text') }</Text></Flex>
|
<Text variant="muted" underline small onClick={ () => handleToolClick('chat_history') }>{ LocalizeText('room.chathistory.button.text') }</Text>
|
||||||
|
</Flex>
|
||||||
{ navigatorData.canRate &&
|
{ navigatorData.canRate &&
|
||||||
<Flex className="w-100 room-tool-item">
|
<Flex className="w-100 room-tool-item">
|
||||||
<Text variant="muted" underline small onClick={ () => handleToolClick('like_room') }>{ LocalizeText('room.like.button.text') }</Text>
|
<Text variant="muted" underline small onClick={ () => handleToolClick('like_room') }>{ LocalizeText('room.like.button.text') }</Text>
|
||||||
@ -172,7 +158,7 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
<Flex className="w-100 room-tool-item">
|
<Flex className="w-100 room-tool-item">
|
||||||
<Text variant="muted" underline small onClick={ () => handleToolClick('toggle_room_link') }>{ LocalizeText('navigator.embed.caption') }</Text>
|
<Text variant="muted" underline small onClick={ () => handleToolClick('toggle_room_link') }>{ LocalizeText('navigator.embed.caption') }</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex className="w-100 room-tool-item">
|
<Flex className="w-100 room-tool-item">
|
||||||
<Text variant="muted" underline small onClick={() => handleToolClick('hiddenbubbles')}> {areBubblesMuted ? LocalizeText('room.unmute.button.text') : LocalizeText('room.mute.button.text')}</Text>
|
<Text variant="muted" underline small onClick={() => handleToolClick('hiddenbubbles')}> {areBubblesMuted ? LocalizeText('room.unmute.button.text') : LocalizeText('room.mute.button.text')}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Column>
|
</Column>
|
||||||
@ -183,34 +169,50 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
<Base pointer={ roomHistory.length > 1 && roomHistory[roomHistory.length - 1]?.roomId !== navigatorData.currentRoomId } title={ LocalizeText('room.history.button.forward.tooltip') } className={ `icon ${ (roomHistory?.length === 0 || roomHistory[roomHistory.length - 1]?.roomId === navigatorData.currentRoomId) ? 'icon-room-history-next-disabled' : 'icon-room-history-next-enabled' }` } onClick={ () => (roomHistory?.length === 0 || roomHistory[roomHistory.length - 1]?.roomId === navigatorData.currentRoomId) ? null : handleToolClick('room_history_next') } />
|
<Base pointer={ roomHistory.length > 1 && roomHistory[roomHistory.length - 1]?.roomId !== navigatorData.currentRoomId } title={ LocalizeText('room.history.button.forward.tooltip') } className={ `icon ${ (roomHistory?.length === 0 || roomHistory[roomHistory.length - 1]?.roomId === navigatorData.currentRoomId) ? 'icon-room-history-next-disabled' : 'icon-room-history-next-enabled' }` } onClick={ () => (roomHistory?.length === 0 || roomHistory[roomHistory.length - 1]?.roomId === navigatorData.currentRoomId) ? null : handleToolClick('room_history_next') } />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Column>
|
</Column>
|
||||||
<Flex className="nitro-room-tools-history" style={ { bottom: !navigatorData.canRate ? '180px' : '210px' } }>
|
|
||||||
<TransitionAnimation type={ TransitionAnimationTypes.SLIDE_LEFT } inProp={ isOpenHistory }>
|
<Flex className="nitro-room-tools-side-container">
|
||||||
<Column center>
|
<AnimatePresence>
|
||||||
<Column className="px-3 py-2 rounded nitro-room-history">
|
{ isOpenHistory && ( <motion.div initial={{ x: -400 }} animate={{ x: 0 }} exit={{ x: -400 }}>
|
||||||
<Column gap={ 1 }>
|
<Column center>
|
||||||
{ (roomHistory.length > 0) && roomHistory.map(history =>
|
<Column className="px-3 py-2 rounded nitro-room-history">
|
||||||
{
|
<Column gap={ 1 }>
|
||||||
return <Text key={ history.roomId } bold={ history.roomId === navigatorData.currentRoomId } variant={ history.roomId === navigatorData.currentRoomId ? 'white' : 'muted' } pointer onClick={ () => TryVisitRoom(history.roomId) }>{ history.roomName }</Text>;
|
{ (roomHistory.length > 0) && roomHistory.map(history =>
|
||||||
}) }
|
<Text key={ history.roomId } bold={ history.roomId === navigatorData.currentRoomId } variant={ history.roomId === navigatorData.currentRoomId ? 'white' : 'muted' } pointer onClick={ () => TryVisitRoom(history.roomId) }>{ history.roomName }</Text>
|
||||||
|
) }
|
||||||
|
</Column>
|
||||||
|
</Column>
|
||||||
</Column>
|
</Column>
|
||||||
</Column>
|
</motion.div>
|
||||||
</Column>
|
)}
|
||||||
</TransitionAnimation>
|
</AnimatePresence>
|
||||||
|
|
||||||
|
<AnimatePresence>
|
||||||
|
{ isOpen && ( <motion.div initial={{ x: -400 }} animate={{ x: 0 }} exit={{ x: -400 }}>
|
||||||
|
<Column center>
|
||||||
|
<Column className="px-3 py-2 rounded nitro-room-tools-info" overflow="hidden">
|
||||||
|
<Column gap={1}>
|
||||||
|
<Text wrap variant="white" fontSize={4} truncate>{roomName}</Text>
|
||||||
|
<Text variant="muted" fontSize={5} truncate>{roomOwner}</Text>
|
||||||
|
</Column>
|
||||||
|
{roomTags && roomTags.length > 0 ? (
|
||||||
|
<Flex gap={2}>
|
||||||
|
{roomTags.map((tag, index) => (
|
||||||
|
<Text key={index} small pointer truncate variant="white" className="rounded bg-primary p-1" onClick={() => handleToolClick('navigator_search_tag', tag)}>
|
||||||
|
#{tag}
|
||||||
|
</Text>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
) : (
|
||||||
|
<Text variant="muted">{ LocalizeText('navigator.notagsfound') }</Text>
|
||||||
|
)}
|
||||||
|
</Column>
|
||||||
|
</Column>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Column justifyContent="center">
|
|
||||||
<TransitionAnimation type={TransitionAnimationTypes.SLIDE_LEFT} inProp={isOpen} timeout={300}>
|
|
||||||
<Column center>
|
|
||||||
<Column className="px-3 py-2 rounded nitro-room-tools-info" overflow="hidden">
|
|
||||||
<Column gap={1}> <Text wrap variant="white" fontSize={4} truncate>{roomName}</Text> <Text variant="muted" fontSize={5} truncate>{roomOwner}</Text> </Column>
|
|
||||||
{roomTags && roomTags.length > 0 ? (
|
|
||||||
<Flex gap={2}> {roomTags.map((tag, index) => ( <Text key={index} small pointer truncate variant="white" className="rounded bg-primary p-1" onClick={() => handleToolClick('navigator_search_tag', tag)} > #{tag} </Text> ))}
|
|
||||||
</Flex> ) : ( <Text variant="muted"> { LocalizeText('navigator.notagsfound') } </Text> )}
|
|
||||||
</Column>
|
|
||||||
</Column>
|
|
||||||
</TransitionAnimation>
|
|
||||||
</Column>
|
|
||||||
</>
|
</>
|
||||||
) }
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -1,17 +1,14 @@
|
|||||||
import { MouseEventType, RoomObjectCategory } from '@nitrots/nitro-renderer';
|
import { MouseEventType, RoomObjectCategory } from '@nitrots/nitro-renderer';
|
||||||
import { Dispatch, FC, PropsWithChildren, SetStateAction, useEffect, useRef } from 'react';
|
import { Dispatch, FC, PropsWithChildren, SetStateAction, useEffect, useRef } from 'react';
|
||||||
import { CreateLinkEvent, DispatchUiEvent, GetConfiguration, GetRoomEngine, GetRoomSession, GetSessionDataManager, GetUserProfile } from '../../api';
|
import { CreateLinkEvent, DispatchUiEvent, GetConfiguration, GetRoomEngine, GetRoomSession, GetUserProfile } from '../../api';
|
||||||
import { Base, Flex, LayoutItemCountView } from '../../common';
|
import { Base, Flex, LayoutItemCountView } from '../../common';
|
||||||
import { GuideToolEvent } from '../../events';
|
import { GuideToolEvent } from '../../events';
|
||||||
|
|
||||||
interface ToolbarMeViewProps
|
export const ToolbarMeView: FC<PropsWithChildren<{
|
||||||
{
|
|
||||||
useGuideTool: boolean;
|
useGuideTool: boolean;
|
||||||
unseenAchievementCount: number;
|
unseenAchievementCount: number;
|
||||||
setMeExpanded: Dispatch<SetStateAction<boolean>>;
|
setMeExpanded: Dispatch<SetStateAction<boolean>>;
|
||||||
}
|
}>> = props =>
|
||||||
|
|
||||||
export const ToolbarMeView: FC<PropsWithChildren<ToolbarMeViewProps>> = props =>
|
|
||||||
{
|
{
|
||||||
const { useGuideTool = false, unseenAchievementCount = 0, setMeExpanded = null, children = null, ...rest } = props;
|
const { useGuideTool = false, unseenAchievementCount = 0, setMeExpanded = null, children = null, ...rest } = props;
|
||||||
const elementRef = useRef<HTMLDivElement>();
|
const elementRef = useRef<HTMLDivElement>();
|
||||||
@ -19,7 +16,6 @@ export const ToolbarMeView: FC<PropsWithChildren<ToolbarMeViewProps>> = props =>
|
|||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
const roomSession = GetRoomSession();
|
const roomSession = GetRoomSession();
|
||||||
|
|
||||||
if(!roomSession) return;
|
if(!roomSession) return;
|
||||||
|
|
||||||
GetRoomEngine().selectRoomObject(roomSession.roomId, roomSession.ownRoomIndex, RoomObjectCategory.UNIT);
|
GetRoomEngine().selectRoomObject(roomSession.roomId, roomSession.ownRoomIndex, RoomObjectCategory.UNIT);
|
||||||
@ -27,15 +23,25 @@ export const ToolbarMeView: FC<PropsWithChildren<ToolbarMeViewProps>> = props =>
|
|||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
const onClick = (event: MouseEvent) => setMeExpanded(false);
|
const handleClickOutside = (event: MouseEvent) =>
|
||||||
|
{
|
||||||
|
if (elementRef.current && !elementRef.current.contains(event.target as Node))
|
||||||
|
{
|
||||||
|
setMeExpanded(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
document.addEventListener('click', onClick);
|
document.addEventListener('click', handleClickOutside);
|
||||||
|
return () => document.removeEventListener('click', handleClickOutside);
|
||||||
return () => document.removeEventListener(MouseEventType.MOUSE_CLICK, onClick);
|
|
||||||
}, [ setMeExpanded ]);
|
}, [ setMeExpanded ]);
|
||||||
|
|
||||||
|
const handleMenuClick = (event: React.MouseEvent) =>
|
||||||
|
{
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex innerRef={ elementRef } alignItems="center" className="nitro-toolbar-me p-2" gap={ 2 }>
|
<Flex innerRef={ elementRef } alignItems="center" className="nitro-toolbar-me p-2" gap={ 2 } onClick={ handleMenuClick } >
|
||||||
{ (GetConfiguration('guides.enabled') && useGuideTool) &&
|
{ (GetConfiguration('guides.enabled') && useGuideTool) &&
|
||||||
<Base pointer className="navigation-item icon icon-me-helper-tool click-box" onClick={ event => DispatchUiEvent(new GuideToolEvent(GuideToolEvent.TOGGLE_GUIDE_TOOL)) } /> }
|
<Base pointer className="navigation-item icon icon-me-helper-tool click-box" onClick={ event => DispatchUiEvent(new GuideToolEvent(GuideToolEvent.TOGGLE_GUIDE_TOOL)) } /> }
|
||||||
<Base pointer className="navigation-item icon icon-me-achievements click-box" onClick={ event => CreateLinkEvent('achievements/toggle') }>
|
<Base pointer className="navigation-item icon icon-me-achievements click-box" onClick={ event => CreateLinkEvent('achievements/toggle') }>
|
||||||
@ -49,4 +55,4 @@ export const ToolbarMeView: FC<PropsWithChildren<ToolbarMeViewProps>> = props =>
|
|||||||
{ children }
|
{ children }
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -70,7 +70,7 @@
|
|||||||
|
|
||||||
.nitro-toolbar-me {
|
.nitro-toolbar-me {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 68px;
|
bottom: 35px;
|
||||||
left: 15px;
|
left: 15px;
|
||||||
z-index: $toolbar-memenu-zindex;
|
z-index: $toolbar-memenu-zindex;
|
||||||
//background: rgba(20, 20, 20, .95);
|
//background: rgba(20, 20, 20, .95);
|
||||||
@ -87,7 +87,7 @@
|
|||||||
row-gap: 0rem!important;
|
row-gap: 0rem!important;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
left: 62px;
|
left: 62px;
|
||||||
z-index: 9999999;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-item {
|
.navigation-item {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Dispose, DropBounce, EaseOut, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, Wait } from '@nitrots/nitro-renderer';
|
import { Dispose, DropBounce, EaseOut, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, Wait } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useState } from 'react';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
import { FC, useState, useEffect } from 'react';
|
||||||
import { CreateLinkEvent, GetConfiguration, GetSessionDataManager, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api';
|
import { CreateLinkEvent, GetConfiguration, GetSessionDataManager, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api';
|
||||||
import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common';
|
import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView } from '../../common';
|
||||||
import { useAchievements, useFriends, useInventoryUnseenTracker, useMessageEvent, useMessenger, useRoomEngineEvent, useSessionInfo } from '../../hooks';
|
import { useAchievements, useFriends, useInventoryUnseenTracker, useMessageEvent, useMessenger, useRoomEngineEvent, useSessionInfo } from '../../hooks';
|
||||||
import { ToolbarMeView } from './ToolbarMeView';
|
import { ToolbarMeView } from './ToolbarMeView';
|
||||||
|
|
||||||
@ -20,7 +21,6 @@ export const ToolbarView: FC<{ isInRoom: boolean }> = props =>
|
|||||||
useMessageEvent<PerkAllowancesMessageEvent>(PerkAllowancesMessageEvent, event =>
|
useMessageEvent<PerkAllowancesMessageEvent>(PerkAllowancesMessageEvent, event =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
setUseGuideTool(parser.isAllowed(PerkEnum.USE_GUIDE_TOOL));
|
setUseGuideTool(parser.isAllowed(PerkEnum.USE_GUIDE_TOOL));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -29,25 +29,21 @@ export const ToolbarView: FC<{ isInRoom: boolean }> = props =>
|
|||||||
const animationIconToToolbar = (iconName: string, image: HTMLImageElement, x: number, y: number) =>
|
const animationIconToToolbar = (iconName: string, image: HTMLImageElement, x: number, y: number) =>
|
||||||
{
|
{
|
||||||
const target = (document.body.getElementsByClassName(iconName)[0] as HTMLElement);
|
const target = (document.body.getElementsByClassName(iconName)[0] as HTMLElement);
|
||||||
|
|
||||||
if(!target) return;
|
if(!target) return;
|
||||||
|
|
||||||
image.className = 'toolbar-icon-animation';
|
image.className = 'toolbar-icon-animation';
|
||||||
image.style.visibility = 'visible';
|
image.style.visibility = 'visible';
|
||||||
image.style.left = (x + 'px');
|
image.style.left = (x + 'px');
|
||||||
image.style.top = (y + 'px');
|
image.style.top = (y + 'px');
|
||||||
|
|
||||||
document.body.append(image);
|
document.body.append(image);
|
||||||
|
|
||||||
const targetBounds = target.getBoundingClientRect();
|
const targetBounds = target.getBoundingClientRect();
|
||||||
const imageBounds = image.getBoundingClientRect();
|
const imageBounds = image.getBoundingClientRect();
|
||||||
|
|
||||||
const left = (imageBounds.x - targetBounds.x);
|
const left = (imageBounds.x - targetBounds.x);
|
||||||
const top = (imageBounds.y - targetBounds.y);
|
const top = (imageBounds.y - targetBounds.y);
|
||||||
const squared = Math.sqrt(((left * left) + (top * top)));
|
const squared = Math.sqrt(((left * left) + (top * top)));
|
||||||
const wait = (500 - Math.abs(((((1 / squared) * 100) * 500) * 0.5)));
|
const wait = (500 - Math.abs(((((1 / squared) * 100) * 500) * 0.5)));
|
||||||
const height = 20;
|
const height = 20;
|
||||||
|
|
||||||
const motionName = (`ToolbarBouncing[${ iconName }]`);
|
const motionName = (`ToolbarBouncing[${ iconName }]`);
|
||||||
|
|
||||||
if(!Motions.getMotionByTag(motionName))
|
if(!Motions.getMotionByTag(motionName))
|
||||||
@ -56,22 +52,45 @@ export const ToolbarView: FC<{ isInRoom: boolean }> = props =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
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));
|
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);
|
Motions.runMotion(motion);
|
||||||
}
|
}
|
||||||
|
|
||||||
animationIconToToolbar('icon-inventory', event.image, event.x, event.y);
|
animationIconToToolbar('icon-inventory', event.image, event.x, event.y);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleAvatarClick = (event: React.MouseEvent) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
setMeExpanded(prev => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ isMeExpanded } timeout={ 300 }>
|
<AnimatePresence>
|
||||||
<ToolbarMeView useGuideTool={ useGuideTool } unseenAchievementCount={ getTotalUnseen } setMeExpanded={ setMeExpanded } />
|
{ isMeExpanded && (
|
||||||
</TransitionAnimation>
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
transition={{ duration: 0.3 }}
|
||||||
|
className="nitro-toolbar-me"
|
||||||
|
>
|
||||||
|
<ToolbarMeView
|
||||||
|
useGuideTool={ useGuideTool }
|
||||||
|
unseenAchievementCount={ getTotalUnseen }
|
||||||
|
setMeExpanded={ setMeExpanded }
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
<Flex alignItems="center" justifyContent="between" gap={ 2 } className="nitro-toolbar py-1 px-3">
|
<Flex alignItems="center" justifyContent="between" gap={ 2 } className="nitro-toolbar py-1 px-3">
|
||||||
<Flex gap={ 2 } alignItems="center" className="widthsizemax">
|
<Flex gap={ 2 } alignItems="center" className="widthsizemax">
|
||||||
<Flex alignItems="center" gap={ 2 }>
|
<Flex alignItems="center" gap={ 2 }>
|
||||||
<Flex center pointer className={ 'navigation-item item-avatar ' + (isMeExpanded ? 'active ' : '') } onClick={ event => setMeExpanded(!isMeExpanded) }>
|
<Flex
|
||||||
|
center
|
||||||
|
pointer
|
||||||
|
className={ 'navigation-item item-avatar ' + (isMeExpanded ? 'active ' : '') }
|
||||||
|
onClick={ handleAvatarClick }
|
||||||
|
>
|
||||||
<LayoutAvatarImageView figure={ userFigure } headOnly={ true } direction={ 2 } position="absolute" />
|
<LayoutAvatarImageView figure={ userFigure } headOnly={ true } direction={ 2 } position="absolute" />
|
||||||
{ (getTotalUnseen > 0) &&
|
{ (getTotalUnseen > 0) &&
|
||||||
<LayoutItemCountView className="text-black" count={ getTotalUnseen } /> }
|
<LayoutItemCountView className="text-black" count={ getTotalUnseen } /> }
|
||||||
@ -108,4 +127,4 @@ export const ToolbarView: FC<{ isInRoom: boolean }> = props =>
|
|||||||
</Flex>
|
</Flex>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -346,6 +346,8 @@ const useAvatarInfoWidgetState = () =>
|
|||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
|
if(!roomSession) return;
|
||||||
|
|
||||||
roomSession.isDecorating = isDecorating;
|
roomSession.isDecorating = isDecorating;
|
||||||
}, [ roomSession, isDecorating ]);
|
}, [ roomSession, isDecorating ]);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user