📣 Updated the Left toolbar also added hide all chat

This commit is contained in:
duckietm 2025-03-20 11:56:52 +01:00
parent 5252d73e56
commit 6f30fe5f29
13 changed files with 191 additions and 55 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

View File

@ -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 />

View 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 }} />);
}

View File

@ -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 } } />

View File

@ -2,40 +2,35 @@ 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();
} }
return !prevValue; return !prevValue;
}); });
@ -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;
@ -50,41 +49,80 @@ export const RoomToolsWidgetView: FC<{}> = props =>
CreateLinkEvent('navigator/toggle-room-link'); CreateLinkEvent('navigator/toggle-room-link');
return; return;
case 'navigator_search_tag': case 'navigator_search_tag':
CreateLinkEvent(`navigator/search/${ value }`); CreateLinkEvent(`navigator/search/${value}`);
SendMessageComposer(new NavigatorSearchComposer('hotel_view', `tag:${ value }`)); SendMessageComposer(new NavigatorSearchComposer('hotel_view', `tag:${value}`));
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; return;
} }
}; };
useMessageEvent<GetGuestRoomResultEvent>(GetGuestRoomResultEvent, event => const onChangeRoomHistory = (roomId: number, roomName: string) => {
{ let newStorage = JSON.parse(window.localStorage.getItem('nitro.room.history') || '[]');
const parser = event.getParser(); if (newStorage.some((room: { roomId: number }) => room.roomId === roomId)) return;
if(!parser.roomEnter || (parser.data.roomId !== roomSession.roomId)) return;
if(roomName !== parser.data.roomName) setRoomName(parser.data.roomName); if (newStorage.length >= 10) newStorage.shift();
if(roomOwner !== parser.data.ownerName) setRoomOwner(parser.data.ownerName); newStorage = [...newStorage, { roomId, roomName }];
if(roomTags !== parser.data.tags) setRoomTags(parser.data.tags);
setRoomHistory(newStorage);
SetLocalStorage('nitro.room.history', newStorage);
};
useMessageEvent<GetGuestRoomResultEvent>(GetGuestRoomResultEvent, event => {
const parser = event.getParser();
if (!parser.roomEnter || (parser.data.roomId !== roomSession.roomId)) return;
if (roomName !== parser.data.roomName) setRoomName(parser.data.roomName);
if (roomOwner !== parser.data.ownerName) setRoomOwner(parser.data.ownerName);
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="cursor-pointer nitro-icon icon-cog" title={ LocalizeText('room.settings.button.text') } onClick={ () => handleToolClick('settings') } /> <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={ 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-cog" title={LocalizeText('room.settings.button.text')} onClick={() => handleToolClick('settings')} />
<div className="cursor-pointer nitro-icon icon-chat-history" title={ LocalizeText('room.chathistory.button.text') } onClick={ () => handleToolClick('chat_history') } /> <div className={classNames('cursor-pointer', 'nitro-icon', (!isZoomedIn && 'icon-zoom-less'), (isZoomedIn && 'icon-zoom-more'))} title={LocalizeText('room.zoom.button.text')} onClick={() => handleToolClick('zoom')} />
{ navigatorData.canRate && <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-like-room" title={ LocalizeText('room.like.button.text') } onClick={ () => handleToolClick('like_room') } /> } <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')} />
{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 }}
@ -94,27 +132,52 @@ export const RoomToolsWidgetView: FC<{}> = props =>
<div className="flex flex-col items-center justify-center"> <div className="flex flex-col items-center justify-center">
<div className="flex flex-col px-3 py-2 rounded nitro-room-tools-info"> <div className="flex flex-col px-3 py-2 rounded nitro-room-tools-info">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<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
key={ index } key={index}
pointer pointer
small small
className="p-1 rounded bg-primary" className="p-1 rounded bg-primary"
variant="white" variant="white"
onClick={ () => handleToolClick('navigator_search_tag', tag) } onClick={() => handleToolClick('navigator_search_tag', tag)}
> >
#{ 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>

View File

@ -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;