Updates
5
package-lock.json
generated
@ -2803,6 +2803,11 @@
|
||||
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
||||
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
|
||||
},
|
||||
"animate.css": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/animate.css/-/animate.css-4.1.1.tgz",
|
||||
"integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ=="
|
||||
},
|
||||
"ansi-colors": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
|
||||
|
@ -10,6 +10,7 @@
|
||||
"@types/node": "^12.20.7",
|
||||
"@types/react": "^17.0.3",
|
||||
"@types/react-dom": "^17.0.3",
|
||||
"animate.css": "^4.1.1",
|
||||
"classnames": "^2.3.1",
|
||||
"immutable": "^4.0.0-rc.12",
|
||||
"nitro-renderer": "file:../nitro-renderer",
|
||||
|
@ -10,35 +10,12 @@
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root" class="w-100 h-100"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
<script>
|
||||
var NitroConfig = {
|
||||
configurationUrl: '/configuration.json',
|
||||
|
BIN
src/assets/images/room-widgets/stickie-widget/stickie-blue.png
Normal file
After Width: | Height: | Size: 401 B |
BIN
src/assets/images/room-widgets/stickie-widget/stickie-close.png
Normal file
After Width: | Height: | Size: 189 B |
BIN
src/assets/images/room-widgets/stickie-widget/stickie-green.png
Normal file
After Width: | Height: | Size: 401 B |
BIN
src/assets/images/room-widgets/stickie-widget/stickie-pink.png
Normal file
After Width: | Height: | Size: 758 B |
After Width: | Height: | Size: 5.7 KiB |
BIN
src/assets/images/room-widgets/stickie-widget/stickie-trash.png
Normal file
After Width: | Height: | Size: 170 B |
BIN
src/assets/images/room-widgets/stickie-widget/stickie-yellow.png
Normal file
After Width: | Height: | Size: 401 B |
@ -4,7 +4,7 @@ import { DraggableWindowProps } from './DraggableWindow.types';
|
||||
export function DraggableWindow(props: DraggableWindowProps): JSX.Element
|
||||
{
|
||||
return (
|
||||
<Draggable handle={ props.handle } bounds="parent" { ...props.draggableOptions }>
|
||||
<Draggable handle={ props.handle } { ...props.draggableOptions }>
|
||||
{ props.children }
|
||||
</Draggable>
|
||||
);
|
||||
|
@ -1,4 +1,5 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;500&display=swap');
|
||||
@import '../node_modules/animate.css/animate.css';
|
||||
@import './assets/styles';
|
||||
|
||||
html,
|
||||
@ -26,7 +27,6 @@ $infostand-zindex: 30;
|
||||
$chat-zindex: 20;
|
||||
$highscore-zindex: 19;
|
||||
|
||||
@import './transitions/TransitionStyles';
|
||||
@import './utils/Styles';
|
||||
@import './App';
|
||||
@import './views/Styles';
|
||||
|
@ -1,23 +0,0 @@
|
||||
import { Transition } from 'react-transition-group';
|
||||
import { FadeTransitionProps } from './FadeTransition.types';
|
||||
import { getTransitionStyle, transitionTypes } from './TransitionStyles';
|
||||
|
||||
export function FadeTransition(props: FadeTransitionProps): JSX.Element
|
||||
{
|
||||
const { inProp = false, timeout = 300 } = props;
|
||||
|
||||
const style = getTransitionStyle('ease-in-out', timeout);
|
||||
|
||||
return (
|
||||
<Transition in={ inProp } timeout={ timeout }>
|
||||
{state => (
|
||||
<div style={{
|
||||
...style,
|
||||
...transitionTypes[state]
|
||||
}}>
|
||||
{ props.children }
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export interface FadeTransitionProps
|
||||
{
|
||||
inProp: boolean;
|
||||
timeout?: number;
|
||||
children?: ReactNode;
|
||||
}
|
18
src/transitions/TransitionAnimation.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { Transition } from 'react-transition-group';
|
||||
import { TransitionAnimationProps } from './TransitionAnimation.types';
|
||||
import { getTransitionAnimationStyle } from './TransitionAnimationStyles';
|
||||
|
||||
export function TransitionAnimation(props: TransitionAnimationProps): JSX.Element
|
||||
{
|
||||
const { type = null, inProp = false, timeout = 300, className = null, children = null } = props;
|
||||
|
||||
return (
|
||||
<Transition in={ inProp } timeout={ timeout }>
|
||||
{state => (
|
||||
<div className={ className + " animate__animated" } style={ { ...getTransitionAnimationStyle(type, state, timeout) } }>
|
||||
{ children }
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
);
|
||||
}
|
20
src/transitions/TransitionAnimation.types.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export interface TransitionAnimationProps
|
||||
{
|
||||
type: string;
|
||||
inProp: boolean;
|
||||
timeout?: number;
|
||||
className?: string;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export class TransitionAnimationTypes
|
||||
{
|
||||
public static BOUNCE: string = 'bounce';
|
||||
public static SLIDE_LEFT: string = 'slideLeft';
|
||||
public static FLIP_X: string = 'flipX';
|
||||
public static FADE_DOWN: string = 'fadeDown';
|
||||
public static FADE_UP: string = 'fadeUp';
|
||||
public static HEAD_SHAKE: string = 'headShake';
|
||||
}
|
98
src/transitions/TransitionAnimationStyles.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { CSSProperties } from 'react';
|
||||
import { TransitionStatus } from 'react-transition-group';
|
||||
import { ENTERING, EXITING } from 'react-transition-group/Transition';
|
||||
import { TransitionAnimationTypes } from './TransitionAnimation.types';
|
||||
|
||||
export function getTransitionAnimationStyle(type: string, transition: TransitionStatus, timeout: number = 300): Partial<CSSProperties>
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case TransitionAnimationTypes.BOUNCE:
|
||||
switch(transition)
|
||||
{
|
||||
default:
|
||||
case ENTERING:
|
||||
return {
|
||||
animationName: `bounceIn`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
case EXITING:
|
||||
return {
|
||||
animationName: `bounceOut`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
}
|
||||
case TransitionAnimationTypes.SLIDE_LEFT:
|
||||
switch(transition)
|
||||
{
|
||||
default:
|
||||
case ENTERING:
|
||||
return {
|
||||
animationName: `slideInLeft`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
case EXITING:
|
||||
return {
|
||||
animationName: `slideOutLeft`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
}
|
||||
case TransitionAnimationTypes.FLIP_X:
|
||||
switch(transition)
|
||||
{
|
||||
default:
|
||||
case ENTERING:
|
||||
return {
|
||||
animationName: `flipInX`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
case EXITING:
|
||||
return {
|
||||
animationName: `flipOutX`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
}
|
||||
case TransitionAnimationTypes.FADE_UP:
|
||||
switch(transition)
|
||||
{
|
||||
default:
|
||||
case ENTERING:
|
||||
return {
|
||||
animationName: `fadeInUp`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
case EXITING:
|
||||
return {
|
||||
animationName: `fadeOutDown`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
}
|
||||
case TransitionAnimationTypes.FADE_DOWN:
|
||||
switch(transition)
|
||||
{
|
||||
default:
|
||||
case ENTERING:
|
||||
return {
|
||||
animationName: `fadeInDown`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
case EXITING:
|
||||
return {
|
||||
animationName: `fadeOutUp`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
}
|
||||
case TransitionAnimationTypes.HEAD_SHAKE:
|
||||
switch(transition)
|
||||
{
|
||||
default:
|
||||
case ENTERING:
|
||||
return {
|
||||
animationName: `headShake`,
|
||||
animationDuration: `${ timeout }ms`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
top: -100%;
|
||||
}
|
||||
to {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
bottom: -100%;
|
||||
}
|
||||
to {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideRight {
|
||||
from {
|
||||
right: -100%;
|
||||
}
|
||||
to {
|
||||
right: 0;
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
export const transitionTypes = {
|
||||
entering: { opacity: 1 },
|
||||
entered: { opacity: 1 },
|
||||
exiting: { opacity: 0 },
|
||||
exited: { opacity: 0 },
|
||||
};
|
||||
|
||||
export function getTransitionStyle(type: string, timeout: number = 300): Partial<CSSStyleDeclaration>
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case 'ease-in-out':
|
||||
return {
|
||||
transition: `opacity ${ timeout }ms ease-in-out`,
|
||||
opacity: '0'
|
||||
}
|
||||
}
|
||||
}
|
7
src/utils/ColorUtils.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export class ColorUtils
|
||||
{
|
||||
public static makeColorHex(color: string): string
|
||||
{
|
||||
return ('#' + color);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { Nitro, RoomSessionEvent } from 'nitro-renderer';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
|
||||
import { FadeTransition } from '../../transitions/FadeTransition';
|
||||
import { TransitionAnimation } from '../../transitions/TransitionAnimation';
|
||||
import { HotelView } from '../hotel-view/HotelView';
|
||||
import { NavigatorView } from '../navigator/NavigatorView';
|
||||
import { RightSideView } from '../right-side/RightSideView';
|
||||
@ -41,9 +41,9 @@ export function MainView(props: MainViewProps): JSX.Element
|
||||
<div className="nitro-main">
|
||||
{ landingViewVisible && <HotelView /> }
|
||||
<RoomHostView />
|
||||
<FadeTransition inProp={ isReady } timeout={ 300 }>
|
||||
<TransitionAnimation className="nitro-toolbar" type={ 'fadeUp' } inProp={ isReady } timeout={ 300 }>
|
||||
<ToolbarView isInRoom={ !landingViewVisible } />
|
||||
</FadeTransition>
|
||||
</TransitionAnimation>
|
||||
<NavigatorView />
|
||||
<RightSideView />
|
||||
</div>
|
||||
|
103
src/views/navigator/NavigatorMessageHandler.tsx
Normal file
@ -0,0 +1,103 @@
|
||||
import { NavigatorCategoriesComposer, NavigatorMetadataEvent, NavigatorSearchEvent, NavigatorSettingsComposer, RoomDataParser, RoomForwardEvent, RoomInfoComposer, RoomInfoEvent, RoomInfoOwnerEvent, UserInfoEvent } from 'nitro-renderer';
|
||||
import { useCallback } from 'react';
|
||||
import { GetRoomSessionManager, GetSessionDataManager } from '../../api';
|
||||
import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event';
|
||||
import { NavigatorMessageHandlerProps } from './NavigatorMessageHandler.types';
|
||||
|
||||
export function NavigatorMessageHandler(props: NavigatorMessageHandlerProps): JSX.Element
|
||||
{
|
||||
const { setTopLevelContext = null, setTopLevelContexts = null, setSearchResults = null } = props;
|
||||
|
||||
const onUserInfoEvent = useCallback((event: UserInfoEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
SendMessageHook(new NavigatorCategoriesComposer());
|
||||
SendMessageHook(new NavigatorSettingsComposer());
|
||||
}, []);
|
||||
|
||||
const onRoomForwardEvent = useCallback((event: RoomForwardEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
SendMessageHook(new RoomInfoComposer(parser.roomId, false, true));
|
||||
}, []);
|
||||
|
||||
const onRoomInfoOwnerEvent = useCallback((event: RoomInfoOwnerEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
SendMessageHook(new RoomInfoComposer(parser.roomId, true, false));
|
||||
}, []);
|
||||
|
||||
const onRoomInfoEvent = useCallback((event: RoomInfoEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(parser.roomEnter)
|
||||
{
|
||||
// this._data.enteredGuestRoom = parser.data;
|
||||
// this._data.staffPick = parser.data.roomPicker;
|
||||
|
||||
// const isCreatedRoom = (this._data.createdRoomId === parser.data.roomId);
|
||||
|
||||
// if(!isCreatedRoom && parser.data.displayRoomEntryAd)
|
||||
// {
|
||||
// // display ad
|
||||
// }
|
||||
|
||||
// this._data.createdRoomId = 0;
|
||||
}
|
||||
|
||||
else if(parser.roomForward)
|
||||
{
|
||||
if((parser.data.ownerName !== GetSessionDataManager().userName) && !parser.isGroupMember)
|
||||
{
|
||||
switch(parser.data.doorMode)
|
||||
{
|
||||
case RoomDataParser.DOORBELL_STATE:
|
||||
console.log('open doorbell');
|
||||
return;
|
||||
case RoomDataParser.PASSWORD_STATE:
|
||||
console.log('open password');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GetRoomSessionManager().createSession(parser.data.roomId);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// this._data.enteredGuestRoom = parser.data;
|
||||
// this._data.staffPick = parser.data.roomPicker;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onNavigatorMetadataEvent = useCallback((event: NavigatorMetadataEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setTopLevelContexts(parser.topLevelContexts);
|
||||
|
||||
if(parser.topLevelContexts.length > 0) setTopLevelContext(parser.topLevelContexts[0]);
|
||||
|
||||
// clear search
|
||||
}, [ setTopLevelContext, setTopLevelContexts ]);
|
||||
|
||||
const onNavigatorSearchEvent = useCallback((event: NavigatorSearchEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setSearchResults(parser.result.results);
|
||||
}, [ setSearchResults ]);
|
||||
|
||||
CreateMessageHook(new UserInfoEvent(onUserInfoEvent));
|
||||
CreateMessageHook(new RoomForwardEvent(onRoomForwardEvent));
|
||||
CreateMessageHook(new RoomInfoOwnerEvent(onRoomInfoOwnerEvent));
|
||||
CreateMessageHook(new RoomInfoEvent(onRoomInfoEvent));
|
||||
CreateMessageHook(new NavigatorMetadataEvent(onNavigatorMetadataEvent));
|
||||
CreateMessageHook(new NavigatorSearchEvent(onNavigatorSearchEvent));
|
||||
|
||||
return null;
|
||||
}
|
8
src/views/navigator/NavigatorMessageHandler.types.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { NavigatorSearchResultList, NavigatorTopLevelContext } from 'nitro-renderer';
|
||||
|
||||
export interface NavigatorMessageHandlerProps
|
||||
{
|
||||
setTopLevelContext: (context: NavigatorTopLevelContext) => void;
|
||||
setTopLevelContexts: (contexts: NavigatorTopLevelContext[]) => void;
|
||||
setSearchResults: (results: NavigatorSearchResultList[]) => void;
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
import { NavigatorCategoriesComposer, NavigatorInitComposer, NavigatorMetadataEvent, NavigatorSearchComposer, NavigatorSettingsComposer, NavigatorTopLevelContext, RoomDataParser, RoomForwardEvent, RoomInfoComposer, RoomInfoEvent, RoomInfoOwnerEvent, RoomSessionEvent, UserInfoEvent } from 'nitro-renderer';
|
||||
import { NavigatorInitComposer, NavigatorSearchComposer, NavigatorSearchResultList, NavigatorTopLevelContext, RoomSessionEvent } from 'nitro-renderer';
|
||||
import { MouseEvent, useCallback, useEffect, useState } from 'react';
|
||||
import { GetRoomSessionManager, GetSessionDataManager } from '../../api';
|
||||
import { NavigatorEvent } from '../../events';
|
||||
import { DraggableWindow } from '../../hooks/draggable-window/DraggableWindow';
|
||||
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
|
||||
import { useUiEvent } from '../../hooks/events/ui/ui-event';
|
||||
import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event';
|
||||
import { SendMessageHook } from '../../hooks/messages/message-event';
|
||||
import { LocalizeText } from '../../utils/LocalizeText';
|
||||
import { NavigatorMessageHandler } from './NavigatorMessageHandler';
|
||||
import { NavigatorViewProps } from './NavigatorView.types';
|
||||
import { NavigatorTabsView } from './tabs/NavigatorTabsView';
|
||||
|
||||
@ -19,6 +19,7 @@ export function NavigatorView(props: NavigatorViewProps): JSX.Element
|
||||
|
||||
const [ topLevelContexts, setTopLevelContexts ] = useState<NavigatorTopLevelContext[]>(null);
|
||||
const [ topLevelContext, setTopLevelContext ] = useState<NavigatorTopLevelContext>(null);
|
||||
const [ searchResults, setSearchResults ] = useState<NavigatorSearchResultList[]>(null);
|
||||
|
||||
function hideNavigator(event: MouseEvent = null): void
|
||||
{
|
||||
@ -27,83 +28,6 @@ export function NavigatorView(props: NavigatorViewProps): JSX.Element
|
||||
setIsVisible(false);
|
||||
}
|
||||
|
||||
const onUserInfoEvent = useCallback((event: UserInfoEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
SendMessageHook(new NavigatorCategoriesComposer());
|
||||
SendMessageHook(new NavigatorSettingsComposer());
|
||||
}, []);
|
||||
|
||||
const onRoomForwardEvent = useCallback((event: RoomForwardEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
SendMessageHook(new RoomInfoComposer(parser.roomId, false, true));
|
||||
}, []);
|
||||
|
||||
const onRoomInfoOwnerEvent = useCallback((event: RoomInfoOwnerEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
SendMessageHook(new RoomInfoComposer(parser.roomId, true, false));
|
||||
}, []);
|
||||
|
||||
const onRoomInfoEvent = useCallback((event: RoomInfoEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(parser.roomEnter)
|
||||
{
|
||||
// this._data.enteredGuestRoom = parser.data;
|
||||
// this._data.staffPick = parser.data.roomPicker;
|
||||
|
||||
// const isCreatedRoom = (this._data.createdRoomId === parser.data.roomId);
|
||||
|
||||
// if(!isCreatedRoom && parser.data.displayRoomEntryAd)
|
||||
// {
|
||||
// // display ad
|
||||
// }
|
||||
|
||||
// this._data.createdRoomId = 0;
|
||||
}
|
||||
|
||||
else if(parser.roomForward)
|
||||
{
|
||||
if((parser.data.ownerName !== GetSessionDataManager().userName) && !parser.isGroupMember)
|
||||
{
|
||||
switch(parser.data.doorMode)
|
||||
{
|
||||
case RoomDataParser.DOORBELL_STATE:
|
||||
console.log('open doorbell');
|
||||
return;
|
||||
case RoomDataParser.PASSWORD_STATE:
|
||||
console.log('open password');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GetRoomSessionManager().createSession(parser.data.roomId);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// this._data.enteredGuestRoom = parser.data;
|
||||
// this._data.staffPick = parser.data.roomPicker;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onNavigatorMetadataEvent = useCallback((event: NavigatorMetadataEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setTopLevelContexts(parser.topLevelContexts);
|
||||
|
||||
if(parser.topLevelContexts.length > 0) setTopLevelContext(parser.topLevelContexts[0]);
|
||||
|
||||
// clear search
|
||||
}, []);
|
||||
|
||||
const onNavigatorEvent = useCallback((event: NavigatorEvent) =>
|
||||
{
|
||||
switch(event.type)
|
||||
@ -131,6 +55,8 @@ export function NavigatorView(props: NavigatorViewProps): JSX.Element
|
||||
{
|
||||
if(!topLevelContext) return;
|
||||
|
||||
setIsSearching(true);
|
||||
|
||||
sendSearch(topLevelContext.code, '');
|
||||
}, [ topLevelContext ]);
|
||||
|
||||
@ -155,30 +81,30 @@ export function NavigatorView(props: NavigatorViewProps): JSX.Element
|
||||
}
|
||||
}, [ isVisible, isLoaded, search ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setIsSearching(false);
|
||||
}, [ searchResults ]);
|
||||
|
||||
useUiEvent(NavigatorEvent.SHOW_NAVIGATOR, onNavigatorEvent);
|
||||
useUiEvent(NavigatorEvent.TOGGLE_NAVIGATOR, onNavigatorEvent);
|
||||
|
||||
useRoomSessionManagerEvent(RoomSessionEvent.CREATED, onRoomSessionEvent);
|
||||
|
||||
CreateMessageHook(new UserInfoEvent(onUserInfoEvent));
|
||||
CreateMessageHook(new RoomForwardEvent(onRoomForwardEvent));
|
||||
CreateMessageHook(new RoomInfoOwnerEvent(onRoomInfoOwnerEvent));
|
||||
CreateMessageHook(new RoomInfoEvent(onRoomInfoEvent));
|
||||
CreateMessageHook(new NavigatorMetadataEvent(onNavigatorMetadataEvent));
|
||||
|
||||
if(!isVisible) return null;
|
||||
|
||||
return (
|
||||
<DraggableWindow handle=".drag-handler">
|
||||
<div className="nitro-navigator d-flex flex-column bg-primary border border-black shadow rounded">
|
||||
<div className="drag-handler d-flex justify-content-between align-items-center px-3 pt-3">
|
||||
<div className="h6 m-0">{ LocalizeText(isLoading ? 'navigator.title.is.busy' : 'navigator.title') }</div>
|
||||
<button type="button" className="close" onClick={ hideNavigator }>
|
||||
<i className="fas fa-times"></i>
|
||||
</button>
|
||||
<>
|
||||
<NavigatorMessageHandler setTopLevelContext={ setTopLevelContext } setTopLevelContexts={ setTopLevelContexts } setSearchResults={ setSearchResults } />
|
||||
{ isVisible && <DraggableWindow handle=".drag-handler">
|
||||
<div className="nitro-navigator d-flex flex-column bg-primary border border-black shadow rounded">
|
||||
<div className="drag-handler d-flex justify-content-between align-items-center px-3 pt-3">
|
||||
<div className="h6 m-0">{ LocalizeText((isLoading || isSearching) ? 'navigator.title.is.busy' : 'navigator.title') }</div>
|
||||
<button type="button" className="close" onClick={ hideNavigator }>
|
||||
<i className="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<NavigatorTabsView topLevelContext={ topLevelContext } topLevelContexts={ topLevelContexts } setTopLevelContext={ setTopLevelContext } />
|
||||
</div>
|
||||
<NavigatorTabsView topLevelContext={ topLevelContext } topLevelContexts={ topLevelContexts } setTopLevelContext={ setTopLevelContext } />
|
||||
</div>
|
||||
</DraggableWindow>
|
||||
</DraggableWindow> }
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,44 +1,69 @@
|
||||
import { Map } from 'immutable';
|
||||
import { Nitro, UserCreditsEvent, UserCurrencyComposer, UserCurrencyEvent, UserCurrencyUpdateEvent } from 'nitro-renderer';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event';
|
||||
import { FadeTransition } from '../../transitions/FadeTransition';
|
||||
import { TransitionAnimation } from '../../transitions/TransitionAnimation';
|
||||
import { TransitionAnimationTypes } from '../../transitions/TransitionAnimation.types';
|
||||
import { CurrencySet } from './currency/CurrencySet';
|
||||
import { CurrencyView } from './currency/CurrencyView';
|
||||
import { PurseViewProps } from './PurseView.types';
|
||||
|
||||
export function PurseView(props: PurseViewProps): JSX.Element
|
||||
{
|
||||
const [ currencies, setCurrencies ] = useState(Map({ '-1': 0 }));
|
||||
const [ currencies, setCurrencies ] = useState<CurrencySet[]>([ new CurrencySet(-1, 0) ]);
|
||||
const [ isReady, setIsReady ] = useState(false);
|
||||
|
||||
const onUserCreditsEvent = (event: UserCreditsEvent) =>
|
||||
const displayedCurrencies = Nitro.instance.getConfiguration<number[]>('system.currency.types', []);
|
||||
|
||||
const onUserCreditsEvent = useCallback((event: UserCreditsEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setCurrencies(currencies.set('-1', parseFloat(parser.credits)));
|
||||
};
|
||||
updateCurrency(-1, parseFloat(parser.credits));
|
||||
}, []);
|
||||
|
||||
const onUserCurrencyEvent = (event: UserCurrencyEvent) =>
|
||||
const onUserCurrencyEvent = useCallback((event: UserCurrencyEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
const map = {};
|
||||
for(const [ key, value ] of parser.currencies.entries()) updateCurrency(key, value);
|
||||
|
||||
for(const [ key, value ] of parser.currencies.entries())
|
||||
{
|
||||
map[key.toString()] = value;
|
||||
}
|
||||
|
||||
setCurrencies(currencies.merge(map));
|
||||
setIsReady(true);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onUserCurrencyUpdateEvent = (event: UserCurrencyUpdateEvent) =>
|
||||
const onUserCurrencyUpdateEvent = useCallback((event: UserCurrencyUpdateEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setCurrencies(currencies.set(parser.type.toString(), parser.amount));
|
||||
};
|
||||
updateCurrency(parser.type, parser.amount)
|
||||
}, []);
|
||||
|
||||
function updateCurrency(type: number, amount: number): void
|
||||
{
|
||||
setCurrencies(oldState =>
|
||||
{
|
||||
const newState: CurrencySet[] = [];
|
||||
|
||||
let found = false;
|
||||
|
||||
for(const set of oldState)
|
||||
{
|
||||
if(set.type !== type)
|
||||
{
|
||||
newState.push(set);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
newState.push(new CurrencySet(set.type, amount));
|
||||
|
||||
found = true;
|
||||
}
|
||||
|
||||
if(!found) newState.push(new CurrencySet(type, amount));
|
||||
|
||||
return newState;
|
||||
});
|
||||
}
|
||||
|
||||
CreateMessageHook(new UserCreditsEvent(onUserCreditsEvent));
|
||||
CreateMessageHook(new UserCurrencyEvent(onUserCurrencyEvent));
|
||||
@ -49,20 +74,16 @@ export function PurseView(props: PurseViewProps): JSX.Element
|
||||
SendMessageHook(new UserCurrencyComposer());
|
||||
}, []);
|
||||
|
||||
const displayedCurrencies = Nitro.instance.getConfiguration<number[]>('system.currency.types', []);
|
||||
|
||||
return (
|
||||
<FadeTransition inProp={ isReady } timeout={ 300 }>
|
||||
<div className="nitro-purse position-relative mb-1">
|
||||
<div className="row px-0 mx-0">
|
||||
{ currencies && currencies.entrySeq().map(([ key, value ]) =>
|
||||
{
|
||||
if(displayedCurrencies.indexOf(parseInt(key)) === -1) return null;
|
||||
<TransitionAnimation className="nitro-purse position-relative mb-1" type={ TransitionAnimationTypes.FADE_DOWN } inProp={ isReady } timeout={ 300 }>
|
||||
<div className="row px-0 mx-0">
|
||||
{ currencies && currencies.map((set, index) =>
|
||||
{
|
||||
if(displayedCurrencies.indexOf(set.type) === -1) return null;
|
||||
|
||||
return <CurrencyView key={ key } type={ parseInt(key) } amount={ value } />
|
||||
}) }
|
||||
</div>
|
||||
return <CurrencyView key={ index } currencySet={ set } />
|
||||
}) }
|
||||
</div>
|
||||
</FadeTransition>
|
||||
</TransitionAnimation>
|
||||
);
|
||||
}
|
||||
|
9
src/views/purse/currency/CurrencySet.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export class CurrencySet
|
||||
{
|
||||
constructor(
|
||||
public type: number,
|
||||
public amount: number)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -1,14 +1,27 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { TransitionAnimation } from '../../../transitions/TransitionAnimation';
|
||||
import { TransitionAnimationTypes } from '../../../transitions/TransitionAnimation.types';
|
||||
import { CurrencyIcon } from '../../../utils/currency-icon/CurrencyIcon';
|
||||
import { CurrencyViewProps } from './CurrencyView.types';
|
||||
|
||||
export function CurrencyView(props: CurrencyViewProps): JSX.Element
|
||||
{
|
||||
const { type = -1, amount = 0 } = props;
|
||||
const { currencySet = null } = props;
|
||||
const [ isAnimating, setIsAnimating ] = useState(false);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setIsAnimating(true);
|
||||
|
||||
const timeout = setTimeout(() => setIsAnimating(false), 1000);
|
||||
|
||||
return () => clearTimeout(timeout);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="d-flex bg-primary rounded shadow border border-black mb-1 p-1 nitro-currency">
|
||||
<div className="d-flex flex-grow-1 align-items-center justify-content-end">{ amount }</div>
|
||||
<div className="bg-secondary rounded ml-1"><CurrencyIcon type={ type } /></div>
|
||||
</div>
|
||||
<TransitionAnimation className="d-flex bg-primary rounded shadow border border-black mb-1 p-1 nitro-currency" type={ TransitionAnimationTypes.HEAD_SHAKE } inProp={ isAnimating } timeout={ 300 }>
|
||||
<div className="d-flex flex-grow-1 align-items-center justify-content-end">{ currencySet.amount }</div>
|
||||
<div className="bg-secondary rounded ml-1"><CurrencyIcon type={ currencySet.type } /></div>
|
||||
</TransitionAnimation>
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { CurrencySet } from './CurrencySet';
|
||||
|
||||
export interface CurrencyViewProps
|
||||
{
|
||||
type: number;
|
||||
amount: number;
|
||||
currencySet: CurrencySet;
|
||||
}
|
||||
|
@ -10,3 +10,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@import './widgets/Widgets';
|
||||
|
1
src/views/room/widgets/Widgets.scss
Normal file
@ -0,0 +1 @@
|
||||
@import './furniture/FurnitureWidgets';
|
1
src/views/room/widgets/furniture/FurnitureWidgets.scss
Normal file
@ -0,0 +1 @@
|
||||
@import './stickie/FurnitureStickieView';
|
@ -0,0 +1,9 @@
|
||||
export class FurnitureStickieData
|
||||
{
|
||||
constructor(
|
||||
public objectId: number,
|
||||
public category: number,
|
||||
public color: string,
|
||||
public text: string,
|
||||
public canModify: boolean) {}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
export const STICKIE_COLORS = ['9CCEFF','FF9CFF', '9CFF9C','FFFF33'];
|
||||
export const STICKIE_COLOR_NAMES = [ 'blue', 'pink', 'green', 'yellow' ];
|
||||
|
||||
export function getStickieColorName(color: string): string
|
||||
{
|
||||
let index = STICKIE_COLORS.indexOf(color);
|
||||
|
||||
if(index === -1) index = 0;
|
||||
|
||||
return STICKIE_COLOR_NAMES[index];
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
.nitro-stickie {
|
||||
width: 185px;
|
||||
height: 178px;
|
||||
padding: 1px;
|
||||
|
||||
.stickie-header {
|
||||
width: 183px;
|
||||
height: 18px;
|
||||
padding: 0 7px;
|
||||
|
||||
.header-trash,
|
||||
.header-close {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.stickie-color {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.stickie-context {
|
||||
width: 183px;
|
||||
height: 145px;
|
||||
padding: 2px 7px;
|
||||
font-size: 12px;
|
||||
color: $black;
|
||||
|
||||
.context-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
textarea {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
resize: none;
|
||||
|
||||
&:active {
|
||||
border: 0;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nitro-stickie-image {
|
||||
background-image: url('../../../../../assets/images/room-widgets/stickie-widget/stickie-spritesheet.png');
|
||||
|
||||
&.stickie-blue,
|
||||
&.stickie-yellow,
|
||||
&.stickie-green,
|
||||
&.stickie-pink {
|
||||
width: 185px;
|
||||
height: 178px;
|
||||
}
|
||||
|
||||
&.stickie-blue {
|
||||
background-position: -2px -2px;
|
||||
}
|
||||
|
||||
&.stickie-yellow {
|
||||
background-image: url('../../../../../assets/images/room-widgets/stickie-widget/stickie-yellow.png');
|
||||
//background-position: -191px -184px;
|
||||
}
|
||||
|
||||
&.stickie-green {
|
||||
background-position: -191px -2px;
|
||||
}
|
||||
|
||||
&.stickie-pink {
|
||||
background-position: -2px -184px;
|
||||
}
|
||||
|
||||
&.stickie-close {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-position: -2px -366px;
|
||||
}
|
||||
|
||||
&.stickie-trash {
|
||||
width: 9px;
|
||||
height: 10px;
|
||||
background-position: -16px -366px;
|
||||
}
|
||||
}
|
@ -1,22 +1,158 @@
|
||||
import { RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer';
|
||||
import { useState } from 'react';
|
||||
import { MouseEventType, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer';
|
||||
import { createRef, useCallback, useEffect, useState } from 'react';
|
||||
import { GetRoomEngine, GetRoomSession, GetSessionDataManager } from '../../../../../api';
|
||||
import { DraggableWindow } from '../../../../../hooks/draggable-window/DraggableWindow';
|
||||
import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base';
|
||||
import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event';
|
||||
import { ColorUtils } from '../../../../../utils/ColorUtils';
|
||||
import { RoomWidgetRoomObjectUpdateEvent } from '../../events';
|
||||
import { FurnitureStickieData } from './FurnitureStickieData';
|
||||
import { getStickieColorName, STICKIE_COLORS } from './FurnitureStickieUtils';
|
||||
import { FurnitureStickieViewProps } from './FurnitureStickieView.types';
|
||||
|
||||
export function FurnitureStickieView(props: FurnitureStickieViewProps): JSX.Element
|
||||
{
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
const { events = null } = props;
|
||||
|
||||
const onRoomEngineObjectEvent = (event: RoomEngineObjectEvent) =>
|
||||
const [ stickieData, setStickieData ] = useState<FurnitureStickieData>(null);
|
||||
const [ isEditing, setIsEditing ] = useState(false);
|
||||
|
||||
const textAreaRef = createRef<HTMLTextAreaElement>();
|
||||
|
||||
const onNitroEvent = useCallback((event: NitroEvent) =>
|
||||
{
|
||||
setIsVisible(true);
|
||||
};
|
||||
switch(event.type)
|
||||
{
|
||||
case RoomEngineTriggerWidgetEvent.REQUEST_STICKIE: {
|
||||
const widgetEvent = (event as RoomEngineTriggerWidgetEvent);
|
||||
|
||||
useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_STICKIE, onRoomEngineObjectEvent);
|
||||
const roomObject = GetRoomEngine().getRoomObject(widgetEvent.roomId, widgetEvent.objectId, widgetEvent.category);
|
||||
|
||||
if(!isVisible) return null;
|
||||
if(!roomObject) return;
|
||||
|
||||
const data = roomObject.model.getValue<string>(RoomObjectVariable.FURNITURE_ITEMDATA);
|
||||
|
||||
if(data.length < 6) return;
|
||||
|
||||
let color: string = null;
|
||||
let text: string = null;
|
||||
|
||||
if(data.indexOf(' ') > 0)
|
||||
{
|
||||
color = data.slice(0, data.indexOf(' '));
|
||||
text = data.slice((data.indexOf(' ') + 1), data.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
color = data;
|
||||
}
|
||||
|
||||
setStickieData(new FurnitureStickieData(widgetEvent.objectId, widgetEvent.category, color, text, (GetRoomSession(widgetEvent.roomId).isRoomOwner || GetSessionDataManager().isModerator)));
|
||||
setIsEditing(false);
|
||||
return;
|
||||
}
|
||||
case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: {
|
||||
const widgetEvent = (event as RoomWidgetRoomObjectUpdateEvent);
|
||||
|
||||
setIsEditing(false);
|
||||
setStickieData(prevState =>
|
||||
{
|
||||
if(!prevState || (widgetEvent.id !== prevState.objectId) || (widgetEvent.category !== prevState.category)) return prevState;
|
||||
|
||||
return null;
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const processAction = useCallback((type: string, value: string = null) =>
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case 'close':
|
||||
setStickieData(null);
|
||||
return;
|
||||
case 'trash':
|
||||
setStickieData(prevState =>
|
||||
{
|
||||
if(!prevState) return null;
|
||||
|
||||
GetRoomEngine().deleteRoomObject(prevState.objectId, prevState.category);
|
||||
|
||||
return null;
|
||||
});
|
||||
return;
|
||||
case 'changeColor':
|
||||
setStickieData(prevState =>
|
||||
{
|
||||
const newStickieData = new FurnitureStickieData(prevState.objectId, prevState.category, value, prevState.text, prevState.canModify);
|
||||
|
||||
GetRoomEngine().modifyRoomObjectData(newStickieData.objectId, newStickieData.category, newStickieData.color, newStickieData.text);
|
||||
|
||||
return newStickieData;
|
||||
});
|
||||
return;
|
||||
case 'changeText': {
|
||||
setIsEditing(false);
|
||||
setStickieData(prevState =>
|
||||
{
|
||||
const newStickieData = new FurnitureStickieData(prevState.objectId, prevState.category, prevState.color, value, prevState.canModify);
|
||||
|
||||
GetRoomEngine().modifyRoomObjectData(newStickieData.objectId, newStickieData.category, newStickieData.color, newStickieData.text);
|
||||
|
||||
return newStickieData;
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_STICKIE, onNitroEvent);
|
||||
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, events, onNitroEvent);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isEditing) return;
|
||||
|
||||
const event = (mouseEvent: MouseEvent) =>
|
||||
{
|
||||
if(mouseEvent.target === textAreaRef.current) return;
|
||||
|
||||
console.log('change it');
|
||||
|
||||
processAction('changeText', textAreaRef.current.value);
|
||||
}
|
||||
|
||||
document.addEventListener(MouseEventType.MOUSE_DOWN, event);
|
||||
|
||||
return () => document.removeEventListener(MouseEventType.MOUSE_DOWN, event);
|
||||
}, [ isEditing, textAreaRef, processAction ]);
|
||||
|
||||
if(!stickieData) return null;
|
||||
|
||||
console.log('rerender stickie')
|
||||
|
||||
return (
|
||||
<div>stickie is visible</div>
|
||||
<DraggableWindow handle=".drag-handler">
|
||||
<div className={ "nitro-stickie nitro-stickie-image stickie-" + getStickieColorName(stickieData.color) }>
|
||||
<div className="d-flex align-items-center stickie-header drag-handler">
|
||||
<div className="d-flex align-items-center flex-grow-1 h-100">
|
||||
{ stickieData.canModify &&
|
||||
<>
|
||||
<div className="nitro-stickie-image stickie-trash header-trash" onClick={ event => processAction('trash') }></div>
|
||||
{ STICKIE_COLORS.map((color, index) =>
|
||||
{
|
||||
return <div className="stickie-color ml-1" key={ index } onClick={ event => processAction('changeColor', color) } style={ {backgroundColor: ColorUtils.makeColorHex(color) } } />
|
||||
})}
|
||||
</> }
|
||||
</div>
|
||||
<div className="d-flex align-items-center nitro-stickie-image stickie-close header-close" onClick={ event => processAction('close') }></div>
|
||||
</div>
|
||||
<div className="stickie-context">
|
||||
{ !isEditing ? <div className="context-text" onClick={ event => stickieData.canModify && setIsEditing(true) }>{ stickieData.text }</div> : <textarea className="context-text" ref={ textAreaRef } defaultValue={ stickieData.text || '' } autoFocus></textarea> }
|
||||
</div>
|
||||
</div>
|
||||
</DraggableWindow>
|
||||
);
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ export function ToolbarView(props: ToolbarViewProps): JSX.Element
|
||||
CreateMessageHook(new UserInfoEvent(onUserInfoEvent));
|
||||
|
||||
return (
|
||||
<div className="nitro-toolbar">
|
||||
<>
|
||||
<div className="card p-0 overflow-hidden">
|
||||
<ul className="list-group list-group-horizontal p-1">
|
||||
{ isInRoom && (
|
||||
@ -88,6 +88,6 @@ export function ToolbarView(props: ToolbarViewProps): JSX.Element
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|