📣 Updated the Left toolbar also added hide all chat
BIN
src/assets/images/icons/disablebubble.png
Normal file
After Width: | Height: | Size: 737 B |
BIN
src/assets/images/icons/enablebubble.png
Normal file
After Width: | Height: | Size: 734 B |
BIN
src/assets/images/icons/room-history-back-disabled.png
Normal file
After Width: | Height: | Size: 267 B |
BIN
src/assets/images/icons/room-history-back-enabled.png
Normal file
After Width: | Height: | Size: 280 B |
BIN
src/assets/images/icons/room-history-disabled.png
Normal file
After Width: | Height: | Size: 393 B |
BIN
src/assets/images/icons/room-history-enabled.png
Normal file
After Width: | Height: | Size: 402 B |
BIN
src/assets/images/icons/room-history-next-disabled.png
Normal file
After Width: | Height: | Size: 260 B |
BIN
src/assets/images/icons/room-history-next-enabled.png
Normal file
After Width: | Height: | Size: 267 B |
@ -19,6 +19,7 @@ import { HotelView } from './hotel-view/HotelView';
|
|||||||
import { InventoryView } from './inventory/InventoryView';
|
import { InventoryView } from './inventory/InventoryView';
|
||||||
import { ModToolsView } from './mod-tools/ModToolsView';
|
import { ModToolsView } from './mod-tools/ModToolsView';
|
||||||
import { NavigatorView } from './navigator/NavigatorView';
|
import { NavigatorView } from './navigator/NavigatorView';
|
||||||
|
import { NitrobubbleHiddenView } from './nitrobubblehidden/NitrobubbleHiddenView';
|
||||||
import { NitropediaView } from './nitropedia/NitropediaView';
|
import { NitropediaView } from './nitropedia/NitropediaView';
|
||||||
import { RightSideView } from './right-side/RightSideView';
|
import { RightSideView } from './right-side/RightSideView';
|
||||||
import { RoomView } from './room/RoomView';
|
import { RoomView } from './room/RoomView';
|
||||||
@ -97,6 +98,7 @@ export const MainView: FC<{}> = props =>
|
|||||||
<AvatarEditorView />
|
<AvatarEditorView />
|
||||||
<AchievementsView />
|
<AchievementsView />
|
||||||
<NavigatorView />
|
<NavigatorView />
|
||||||
|
<NitrobubbleHiddenView />
|
||||||
<InventoryView />
|
<InventoryView />
|
||||||
<CatalogView />
|
<CatalogView />
|
||||||
<FriendsView />
|
<FriendsView />
|
||||||
|
59
src/components/nitrobubblehidden/NitrobubbleHiddenView.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { AddLinkEventTracker, ILinkEventTracker, RemoveLinkEventTracker } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { useChatHistory } from '../../hooks';
|
||||||
|
|
||||||
|
export const NitrobubbleHiddenView: FC<{}> = props =>
|
||||||
|
{
|
||||||
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
|
const [ searchText, setSearchText ] = useState<string>('');
|
||||||
|
const { chatHistory = [] } = useChatHistory();
|
||||||
|
const elementRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const filteredChatHistory = useMemo(() =>
|
||||||
|
{
|
||||||
|
if (searchText.length === 0) return chatHistory;
|
||||||
|
|
||||||
|
let text = searchText.toLowerCase();
|
||||||
|
|
||||||
|
return chatHistory.filter(entry => ((entry.message && entry.message.toLowerCase().includes(text))) || (entry.name && entry.name.toLowerCase().includes(text)));
|
||||||
|
}, [ chatHistory, searchText ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(elementRef && elementRef.current && isVisible) elementRef.current.scrollTop = elementRef.current.scrollHeight;
|
||||||
|
}, [ isVisible ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
const linkTracker: ILinkEventTracker = {
|
||||||
|
linkReceived: (url: string) =>
|
||||||
|
{
|
||||||
|
const parts = url.split('/');
|
||||||
|
|
||||||
|
if(parts.length < 2) return;
|
||||||
|
|
||||||
|
switch(parts[1])
|
||||||
|
{
|
||||||
|
case 'show':
|
||||||
|
setIsVisible(true);
|
||||||
|
return;
|
||||||
|
case 'hide':
|
||||||
|
setIsVisible(false);
|
||||||
|
return;
|
||||||
|
case 'toggle':
|
||||||
|
setIsVisible(prevValue => !prevValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
eventUrlPrefix: 'nitrobubblehidden/'
|
||||||
|
};
|
||||||
|
|
||||||
|
AddLinkEventTracker(linkTracker);
|
||||||
|
|
||||||
|
return () => RemoveLinkEventTracker(linkTracker);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if(!isVisible) return null;
|
||||||
|
var stylecssnew = "<style>.newbubblehe { visibility: hidden !important; }</style>";
|
||||||
|
return ( <div dangerouslySetInnerHTML={ { __html: stylecssnew }} />);
|
||||||
|
}
|
@ -76,7 +76,7 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = ({
|
|||||||
}, [ chat, isReady, isVisible, makeRoom ]);
|
}, [ chat, isReady, isVisible, makeRoom ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ elementRef } className={ `bubble-container ${ isVisible ? 'visible' : 'invisible' } w-max absolute select-none pointer-events-auto` }
|
<div ref={ elementRef } className={ `bubble-container newbubblehe ${ isVisible ? 'visible' : 'invisible' } w-max absolute select-none pointer-events-auto` }
|
||||||
onClick={ () => GetRoomEngine().selectRoomObject(chat.roomId, chat.senderId, RoomObjectCategory.UNIT) }>
|
onClick={ () => GetRoomEngine().selectRoomObject(chat.roomId, chat.senderId, RoomObjectCategory.UNIT) }>
|
||||||
{ chat.styleId === 0 && (
|
{ chat.styleId === 0 && (
|
||||||
<div className="absolute top-[-1px] left-[1px] w-[30px] h-[calc(100%-0.5px)] rounded-[7px] z-[1]" style={ { backgroundColor: chat.color } } />
|
<div className="absolute top-[-1px] left-[1px] w-[30px] h-[calc(100%-0.5px)] rounded-[7px] z-[1]" style={ { backgroundColor: chat.color } } />
|
||||||
|
@ -2,38 +2,33 @@ import { CreateLinkEvent, GetGuestRoomResultEvent, GetRoomEngine, NavigatorSearc
|
|||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { classNames } from '../../../../layout';
|
import { classNames } from '../../../../layout';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { GetConfigurationValue, LocalizeText, SendMessageComposer } from '../../../../api';
|
import { GetConfigurationValue, LocalizeText, SendMessageComposer, SetLocalStorage, TryVisitRoom } from '../../../../api';
|
||||||
import { Text } from '../../../../common';
|
import { Text } 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 [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);
|
||||||
const [roomTags, setRoomTags] = useState<string[]>(null);
|
const [roomTags, setRoomTags] = useState<string[]>(null);
|
||||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||||
|
const [isOpenHistory, setIsOpenHistory] = useState<boolean>(false);
|
||||||
|
const [roomHistory, setRoomHistory] = useState<{ roomId: number, roomName: string }[]>([]);
|
||||||
const { navigatorData = null } = useNavigator();
|
const { navigatorData = null } = useNavigator();
|
||||||
const { roomSession = null } = useRoom();
|
const { roomSession = null } = useRoom();
|
||||||
|
|
||||||
const handleToolClick = (action: string, value?: string) =>
|
const handleToolClick = (action: string, value?: string) => {
|
||||||
{
|
switch (action) {
|
||||||
switch(action)
|
|
||||||
{
|
|
||||||
case 'settings':
|
case 'settings':
|
||||||
CreateLinkEvent('navigator/toggle-room-info');
|
CreateLinkEvent('navigator/toggle-room-info');
|
||||||
return;
|
return;
|
||||||
case 'zoom':
|
case 'zoom':
|
||||||
setIsZoomedIn(prevValue =>
|
setIsZoomedIn(prevValue => {
|
||||||
{
|
if (GetConfigurationValue('room.zoom.enabled', true)) {
|
||||||
if(GetConfigurationValue('room.zoom.enabled', true))
|
|
||||||
{
|
|
||||||
const scale = GetRoomEngine().getRoomInstanceRenderingCanvasScale(roomSession.roomId, 1);
|
const scale = GetRoomEngine().getRoomInstanceRenderingCanvasScale(roomSession.roomId, 1);
|
||||||
GetRoomEngine().setRoomInstanceRenderingCanvasScale(roomSession.roomId, 1, scale === 1 ? 0.5 : 1);
|
GetRoomEngine().setRoomInstanceRenderingCanvasScale(roomSession.roomId, 1, scale === 1 ? 0.5 : 1);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
const geometry = GetRoomEngine().getRoomInstanceGeometry(roomSession.roomId, 1);
|
const geometry = GetRoomEngine().getRoomInstanceGeometry(roomSession.roomId, 1);
|
||||||
if (geometry) geometry.performZoom();
|
if (geometry) geometry.performZoom();
|
||||||
}
|
}
|
||||||
@ -43,6 +38,10 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
case 'chat_history':
|
case 'chat_history':
|
||||||
CreateLinkEvent('chat-history/toggle');
|
CreateLinkEvent('chat-history/toggle');
|
||||||
return;
|
return;
|
||||||
|
case 'hiddenbubbles':
|
||||||
|
CreateLinkEvent('nitrobubblehidden/toggle');
|
||||||
|
setAreBubblesMuted(prev => !prev);
|
||||||
|
return;
|
||||||
case 'like_room':
|
case 'like_room':
|
||||||
SendMessageComposer(new RateFlatMessageComposer(1));
|
SendMessageComposer(new RateFlatMessageComposer(1));
|
||||||
return;
|
return;
|
||||||
@ -53,38 +52,77 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
CreateLinkEvent(`navigator/search/${value}`);
|
CreateLinkEvent(`navigator/search/${value}`);
|
||||||
SendMessageComposer(new NavigatorSearchComposer('hotel_view', `tag:${value}`));
|
SendMessageComposer(new NavigatorSearchComposer('hotel_view', `tag:${value}`));
|
||||||
return;
|
return;
|
||||||
|
case 'room_history':
|
||||||
|
if (roomHistory.length > 0) setIsOpenHistory(prev => !prev);
|
||||||
|
return;
|
||||||
|
case 'room_history_back':
|
||||||
|
const prevIndex = roomHistory.findIndex(room => room.roomId === navigatorData.currentRoomId) - 1;
|
||||||
|
if (prevIndex >= 0) TryVisitRoom(roomHistory[prevIndex].roomId);
|
||||||
|
return;
|
||||||
|
case 'room_history_next':
|
||||||
|
const nextIndex = roomHistory.findIndex(room => room.roomId === navigatorData.currentRoomId) + 1;
|
||||||
|
if (nextIndex < roomHistory.length) TryVisitRoom(roomHistory[nextIndex].roomId);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useMessageEvent<GetGuestRoomResultEvent>(GetGuestRoomResultEvent, event =>
|
const onChangeRoomHistory = (roomId: number, roomName: string) => {
|
||||||
{
|
let newStorage = JSON.parse(window.localStorage.getItem('nitro.room.history') || '[]');
|
||||||
|
if (newStorage.some((room: { roomId: number }) => room.roomId === roomId)) return;
|
||||||
|
|
||||||
|
if (newStorage.length >= 10) newStorage.shift();
|
||||||
|
newStorage = [...newStorage, { roomId, roomName }];
|
||||||
|
|
||||||
|
setRoomHistory(newStorage);
|
||||||
|
SetLocalStorage('nitro.room.history', newStorage);
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
});
|
});
|
||||||
|
|
||||||
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]);
|
}, [roomName, roomOwner, roomTags]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setRoomHistory(JSON.parse(window.localStorage.getItem('nitro.room.history') || '[]'));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleTabClose = () => {
|
||||||
|
window.localStorage.removeItem('nitro.room.history');
|
||||||
|
};
|
||||||
|
window.addEventListener('beforeunload', handleTabClose);
|
||||||
|
return () => window.removeEventListener('beforeunload', handleTabClose);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex space-x-2 nitro-room-tools-container">
|
<div className="flex space-x-2 nitro-room-tools-container">
|
||||||
<div className="flex flex-col items-center justify-center p-2 nitro-room-tools">
|
<div className="flex flex-col items-center justify-center p-2 nitro-room-tools">
|
||||||
|
<div className={classNames('cursor-pointer', 'nitro-icon', (areBubblesMuted ? 'icon-chat-disablebubble' : 'icon-chat-enablebubble'))} title={areBubblesMuted ? LocalizeText('room.unmute.button.text') : LocalizeText('room.mute.button.text')} onClick={() => handleToolClick('hiddenbubbles')} />
|
||||||
<div className="cursor-pointer nitro-icon icon-cog" title={LocalizeText('room.settings.button.text')} onClick={() => handleToolClick('settings')} />
|
<div className="cursor-pointer nitro-icon icon-cog" title={LocalizeText('room.settings.button.text')} onClick={() => handleToolClick('settings')} />
|
||||||
<div className={classNames('cursor-pointer', 'nitro-icon', (!isZoomedIn && 'icon-zoom-less'), (isZoomedIn && 'icon-zoom-more'))} title={LocalizeText('room.zoom.button.text')} onClick={() => handleToolClick('zoom')} />
|
<div className={classNames('cursor-pointer', 'nitro-icon', (!isZoomedIn && 'icon-zoom-less'), (isZoomedIn && 'icon-zoom-more'))} title={LocalizeText('room.zoom.button.text')} onClick={() => handleToolClick('zoom')} />
|
||||||
<div className="cursor-pointer nitro-icon icon-chat-history" title={LocalizeText('room.chathistory.button.text')} onClick={() => handleToolClick('chat_history')} />
|
<div className="cursor-pointer nitro-icon icon-chat-history" title={LocalizeText('room.chathistory.button.text')} onClick={() => handleToolClick('chat_history')} />
|
||||||
{ navigatorData.canRate &&
|
<div className={classNames('cursor-pointer', 'nitro-icon', (areBubblesMuted ? 'icon-chat-disablebubble' : 'icon-chat-enablebubble'))} title={areBubblesMuted ? LocalizeText('room.unmute.button.text') : LocalizeText('room.mute.button.text')} onClick={() => handleToolClick('hiddenbubbles')} />
|
||||||
<div className="cursor-pointer nitro-icon icon-like-room" title={ LocalizeText('room.like.button.text') } onClick={ () => handleToolClick('like_room') } /> }
|
|
||||||
|
{navigatorData.canRate && (
|
||||||
|
<div className="cursor-pointer nitro-icon icon-like-room" title={LocalizeText('room.like.button.text')} onClick={() => handleToolClick('like_room')} />
|
||||||
|
)}
|
||||||
|
<div className="cursor-pointer nitro-icon icon-room-link" title={LocalizeText('navigator.embed.caption')} onClick={() => handleToolClick('toggle_room_link')} />
|
||||||
|
<div className="cursor-pointer nitro-icon icon-room-history-enabled" title={LocalizeText('room.history.button.tooltip')} onClick={() => handleToolClick('room_history')} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col justify-center">
|
<div className="flex flex-col justify-center">
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{ isOpen &&
|
{isOpen && (
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ x: -100 }}
|
initial={{ x: -100 }}
|
||||||
animate={{ x: 0 }}
|
animate={{ x: 0 }}
|
||||||
@ -97,7 +135,7 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
<Text wrap fontSize={4} variant="white">{roomName}</Text>
|
<Text wrap fontSize={4} variant="white">{roomName}</Text>
|
||||||
<Text fontSize={5} variant="muted">{roomOwner}</Text>
|
<Text fontSize={5} variant="muted">{roomOwner}</Text>
|
||||||
</div>
|
</div>
|
||||||
{ roomTags && roomTags.length > 0 &&
|
{roomTags && roomTags.length > 0 && (
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{roomTags.map((tag, index) => (
|
{roomTags.map((tag, index) => (
|
||||||
<Text
|
<Text
|
||||||
@ -111,10 +149,35 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
#{tag}
|
#{tag}
|
||||||
</Text>
|
</Text>
|
||||||
))}
|
))}
|
||||||
</div> }
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div> }
|
</motion.div>
|
||||||
|
)}
|
||||||
|
{isOpenHistory && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ x: -100 }}
|
||||||
|
animate={{ x: 0 }}
|
||||||
|
exit={{ x: -100 }}
|
||||||
|
transition={{ duration: 0.3 }}
|
||||||
|
className="nitro-room-tools-history"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col px-3 py-2 rounded nitro-room-history">
|
||||||
|
{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>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -379,6 +379,18 @@
|
|||||||
height: 22px;
|
height: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-chat-enablebubble {
|
||||||
|
background: url('@/assets/images/icons/enablebubble.png');
|
||||||
|
width: 17px;
|
||||||
|
height: 21px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-chat-disablebubble {
|
||||||
|
background: url('@/assets/images/icons/disablebubble.png');
|
||||||
|
width: 17px;
|
||||||
|
height: 21px;
|
||||||
|
}
|
||||||
|
|
||||||
.nitro-icon.icon-arrows {
|
.nitro-icon.icon-arrows {
|
||||||
background: url("@/assets/images/icons/arrows.png");
|
background: url("@/assets/images/icons/arrows.png");
|
||||||
width: 17px;
|
width: 17px;
|
||||||
|