mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-27 08:00:51 +01:00
Chat works
This commit is contained in:
parent
9f04da5157
commit
091c7d9f90
@ -7,7 +7,7 @@ import { DispatchTouchEvent } from '../../api/nitro/room/DispatchTouchEvent';
|
|||||||
import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine';
|
import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine';
|
||||||
import { RoomViewProps } from './RoomView.types';
|
import { RoomViewProps } from './RoomView.types';
|
||||||
import { ChatInputView } from './widgets/chat-input/ChatInputView';
|
import { ChatInputView } from './widgets/chat-input/ChatInputView';
|
||||||
import { ChatWidgetsView } from './widgets/chat/ChatWidgetsView';
|
import { ChatWidgetView } from './widgets/chat/ChatWidgetView';
|
||||||
import { FurnitureWidgetsView } from './widgets/furniture/FurnitureWidgetsView';
|
import { FurnitureWidgetsView } from './widgets/furniture/FurnitureWidgetsView';
|
||||||
|
|
||||||
export function RoomView(props: RoomViewProps): JSX.Element
|
export function RoomView(props: RoomViewProps): JSX.Element
|
||||||
@ -92,7 +92,7 @@ export function RoomView(props: RoomViewProps): JSX.Element
|
|||||||
<>
|
<>
|
||||||
<ChatInputView />
|
<ChatInputView />
|
||||||
<FurnitureWidgetsView events={ events } />
|
<FurnitureWidgetsView events={ events } />
|
||||||
<ChatWidgetsView />
|
<ChatWidgetView />
|
||||||
</> }
|
</> }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
@import './chat/ChatWidgetsView';
|
@import './chat/ChatWidgetView';
|
||||||
@import './chat-input/ChatInputView';
|
@import './chat-input/ChatInputView';
|
||||||
@import './furniture/FurnitureWidgets';
|
@import './furniture/FurnitureWidgets';
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { createRef, FC, MouseEvent, useCallback, useEffect, useState } from 'react';
|
import { FC, MouseEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
import { GetRoomSession } from '../../../../api';
|
||||||
import { SendChatTypingMessage } from '../../../../api/nitro/session/SendChatTypingMessage';
|
import { SendChatTypingMessage } from '../../../../api/nitro/session/SendChatTypingMessage';
|
||||||
|
import { GetConfiguration } from '../../../../utils/GetConfiguration';
|
||||||
import { LocalizeText } from '../../../../utils/LocalizeText';
|
import { LocalizeText } from '../../../../utils/LocalizeText';
|
||||||
import { ChatInputViewProps } from './ChatInputView.types';
|
import { ChatInputMessageType, ChatInputViewProps } from './ChatInputView.types';
|
||||||
|
|
||||||
// const chatModeIdShout = LocalizeText('widgets.chatinput.mode.shout');
|
|
||||||
// const chatModeIdSpeak = LocalizeText('widgets.chatinput.mode.speak');
|
|
||||||
// const maxChatLength = GetConfiguration<number>('chat.input.maxlength', 100);
|
|
||||||
|
|
||||||
let lastContent = '';
|
let lastContent = '';
|
||||||
|
|
||||||
@ -15,9 +13,27 @@ export const ChatInputView: FC<ChatInputViewProps> = props =>
|
|||||||
const [ chatValue, setChatValue ] = useState<string>('');
|
const [ chatValue, setChatValue ] = useState<string>('');
|
||||||
const [ selectedUsername, setSelectedUsername ] = useState('');
|
const [ selectedUsername, setSelectedUsername ] = useState('');
|
||||||
const [ isTyping, setIsTyping ] = useState(false);
|
const [ isTyping, setIsTyping ] = useState(false);
|
||||||
const [ maxCharacters, setMaxCharacters ] = useState<number>(100);
|
const inputRef = useRef<HTMLInputElement>();
|
||||||
|
|
||||||
const inputRef = createRef<HTMLInputElement>();
|
const chatModeIdWhisper = useMemo(() =>
|
||||||
|
{
|
||||||
|
return LocalizeText('widgets.chatinput.mode.whisper');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const chatModeIdShout = useMemo(() =>
|
||||||
|
{
|
||||||
|
return LocalizeText('widgets.chatinput.mode.shout');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const chatModeIdSpeak = useMemo(() =>
|
||||||
|
{
|
||||||
|
return LocalizeText('widgets.chatinput.mode.speak');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const maxChatLength = useMemo(() =>
|
||||||
|
{
|
||||||
|
return GetConfiguration<number>('chat.input.maxlength', 100);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const anotherInputHasFocus = useCallback(() =>
|
const anotherInputHasFocus = useCallback(() =>
|
||||||
{
|
{
|
||||||
@ -49,16 +65,78 @@ export const ChatInputView: FC<ChatInputViewProps> = props =>
|
|||||||
});
|
});
|
||||||
}, [ selectedUsername ]);
|
}, [ selectedUsername ]);
|
||||||
|
|
||||||
const sendChatValue = useCallback((shiftKey: boolean = false) =>
|
const sendChat = useCallback((text: string, chatType: number, recipientName: string = '', styleId: number = 0) =>
|
||||||
{
|
{
|
||||||
if(!chatValue || (chatValue === '')) return;
|
setChatValue('');
|
||||||
}, [ chatValue ]);
|
|
||||||
|
switch(chatType)
|
||||||
|
{
|
||||||
|
case ChatInputMessageType.CHAT_DEFAULT:
|
||||||
|
GetRoomSession().sendChatMessage(text, styleId);
|
||||||
|
return;
|
||||||
|
case ChatInputMessageType.CHAT_WHISPER:
|
||||||
|
GetRoomSession().sendWhisperMessage(recipientName, text, styleId);
|
||||||
|
return;
|
||||||
|
case ChatInputMessageType.CHAT_SHOUT:
|
||||||
|
GetRoomSession().sendShoutMessage(text, styleId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const sendChatValue = useCallback((value: string, shiftKey: boolean = false) =>
|
||||||
|
{
|
||||||
|
if(!value || (value === '')) return;
|
||||||
|
|
||||||
|
let chatType = (shiftKey ? ChatInputMessageType.CHAT_SHOUT : ChatInputMessageType.CHAT_DEFAULT);
|
||||||
|
let text = value;
|
||||||
|
|
||||||
|
const parts = text.split(' ');
|
||||||
|
|
||||||
|
let recipientName = '';
|
||||||
|
let append = '';
|
||||||
|
|
||||||
|
switch(parts[0])
|
||||||
|
{
|
||||||
|
case chatModeIdWhisper:
|
||||||
|
chatType = ChatInputMessageType.CHAT_WHISPER;
|
||||||
|
recipientName = parts[1];
|
||||||
|
append = (chatModeIdWhisper + ' ' + recipientName + ' ');
|
||||||
|
|
||||||
|
parts.shift();
|
||||||
|
parts.shift();
|
||||||
|
break;
|
||||||
|
case chatModeIdShout:
|
||||||
|
chatType = ChatInputMessageType.CHAT_SHOUT;
|
||||||
|
|
||||||
|
parts.shift();
|
||||||
|
break;
|
||||||
|
case chatModeIdSpeak:
|
||||||
|
chatType = ChatInputMessageType.CHAT_DEFAULT;
|
||||||
|
|
||||||
|
parts.shift();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
text = parts.join(' ');
|
||||||
|
|
||||||
|
if(text.length <= maxChatLength)
|
||||||
|
{
|
||||||
|
// if(this.needsStyleUpdate)
|
||||||
|
// {
|
||||||
|
// Nitro.instance.sessionDataManager.sendChatStyleUpdate(this.currentStyle);
|
||||||
|
|
||||||
|
// this.needsStyleUpdate = false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
let currentStyle = 1;
|
||||||
|
|
||||||
|
sendChat(text, chatType, recipientName, currentStyle);
|
||||||
|
}
|
||||||
|
}, [ chatModeIdWhisper, chatModeIdShout, chatModeIdSpeak, maxChatLength, sendChat ]);
|
||||||
|
|
||||||
const onKeyDownEvent = useCallback((event: KeyboardEvent) =>
|
const onKeyDownEvent = useCallback((event: KeyboardEvent) =>
|
||||||
{
|
{
|
||||||
if(!inputRef.current) return;
|
if(!inputRef.current || anotherInputHasFocus()) return;
|
||||||
|
|
||||||
if(anotherInputHasFocus()) return;
|
|
||||||
|
|
||||||
if(document.activeElement !== inputRef.current) setInputFocus();
|
if(document.activeElement !== inputRef.current) setInputFocus();
|
||||||
|
|
||||||
@ -68,7 +146,7 @@ export const ChatInputView: FC<ChatInputViewProps> = props =>
|
|||||||
checkSpecialKeywordForInput();
|
checkSpecialKeywordForInput();
|
||||||
return;
|
return;
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
sendChatValue(event.shiftKey);
|
sendChatValue((event.target as HTMLInputElement).value, event.shiftKey);
|
||||||
return;
|
return;
|
||||||
case 'Backspace':
|
case 'Backspace':
|
||||||
return;
|
return;
|
||||||
@ -141,8 +219,7 @@ export const ChatInputView: FC<ChatInputViewProps> = props =>
|
|||||||
<div className="nitro-chat-input">
|
<div className="nitro-chat-input">
|
||||||
<div className="chatinput-container">
|
<div className="chatinput-container">
|
||||||
<div className="input-sizer">
|
<div className="input-sizer">
|
||||||
<input ref={ inputRef } type="text" className="chat-input" placeholder={ LocalizeText('widgets.chatinput.default') } value={ chatValue } maxLength={ maxCharacters } onChange={ event => { event.target.parentElement.dataset.value = event.target.value; setChatValue(event.target.value) } } onMouseDown={ onInputMouseDownEvent } />
|
<input ref={ inputRef } type="text" className="chat-input" placeholder={ LocalizeText('widgets.chatinput.default') } value={ chatValue } maxLength={ maxChatLength } onChange={ event => { event.target.parentElement.dataset.value = event.target.value; setChatValue(event.target.value) } } onMouseDown={ onInputMouseDownEvent } />
|
||||||
{/* <input #chatInputView type="text" class="chat-input" placeholder="{{ 'widgets.chatinput.default' | translate }}" (input)="chatInputView.parentElement.dataset.value = chatInputView.value" [disabled]="floodBlocked" [maxLength]="inputMaxLength" /> */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>, document.getElementById('toolbar-chat-input-container'))
|
</div>, document.getElementById('toolbar-chat-input-container'))
|
||||||
|
@ -2,3 +2,10 @@ export interface ChatInputViewProps
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ChatInputMessageType
|
||||||
|
{
|
||||||
|
public static CHAT_DEFAULT: number = 0;
|
||||||
|
public static CHAT_WHISPER: number = 1;
|
||||||
|
public static CHAT_SHOUT: number = 2;
|
||||||
|
}
|
||||||
|
16
src/views/room/widgets/chat/ChatWidgetView.scss
Normal file
16
src/views/room/widgets/chat/ChatWidgetView.scss
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
.nitro-chat-widget {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
top: 0;
|
||||||
|
height: 270px;
|
||||||
|
z-index: $chat-zindex;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
@import './message/ChatWidgetMessageView';
|
||||||
|
}
|
177
src/views/room/widgets/chat/ChatWidgetView.tsx
Normal file
177
src/views/room/widgets/chat/ChatWidgetView.tsx
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import { RoomObjectCategory, RoomSessionChatEvent } from 'nitro-renderer';
|
||||||
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { GetRoomEngine, GetRoomSession } from '../../../../api';
|
||||||
|
import { useRoomSessionManagerEvent } from '../../../../hooks/events/nitro/session/room-session-manager-event';
|
||||||
|
import { ChatWidgetViewProps } from './ChatWidgetView.types';
|
||||||
|
import { ChatWidgetMessageView } from './message/ChatWidgetMessageView';
|
||||||
|
import { ChatBubbleMessage } from './utils/ChatBubbleMessage';
|
||||||
|
import { GetBubbleLocation } from './utils/ChatWidgetUtilities';
|
||||||
|
|
||||||
|
export function ChatWidgetView(props: ChatWidgetViewProps): JSX.Element
|
||||||
|
{
|
||||||
|
const {} = props;
|
||||||
|
const [ chatMessages, setChatMessages ] = useState<ChatBubbleMessage[]>([]);
|
||||||
|
const elementRef = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
const removeLastHiddenChat = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(!chatMessages.length) return;
|
||||||
|
|
||||||
|
const lastChat = chatMessages[chatMessages.length - 1];
|
||||||
|
|
||||||
|
if((lastChat.lastTop > -(lastChat.height))) return;
|
||||||
|
|
||||||
|
setChatMessages(prevValue =>
|
||||||
|
{
|
||||||
|
const newMessages = [ ...prevValue ];
|
||||||
|
|
||||||
|
newMessages.splice((newMessages.length - 1), 1);
|
||||||
|
|
||||||
|
return newMessages;
|
||||||
|
});
|
||||||
|
}, [ chatMessages ]);
|
||||||
|
|
||||||
|
const moveChatUp = useCallback((chat: ChatBubbleMessage, amount: number) =>
|
||||||
|
{
|
||||||
|
if(!chat.elementRef) return;
|
||||||
|
|
||||||
|
let y = chat.elementRef.offsetHeight;
|
||||||
|
|
||||||
|
if(amount > 0) y = amount;
|
||||||
|
|
||||||
|
let top = (chat.elementRef.offsetTop - y);
|
||||||
|
|
||||||
|
chat.lastTop = top;
|
||||||
|
chat.elementRef.style.top = (top + 'px');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const moveAllChatsUp = useCallback((amount: number) =>
|
||||||
|
{
|
||||||
|
chatMessages.forEach(chat => moveChatUp(chat, amount));
|
||||||
|
}, [ chatMessages, moveChatUp ]);
|
||||||
|
|
||||||
|
const makeRoom = useCallback((amount: number = 0, skipLast: boolean = false) =>
|
||||||
|
{
|
||||||
|
const lastChat = chatMessages[chatMessages.length - 1];
|
||||||
|
|
||||||
|
if(!lastChat) return;
|
||||||
|
|
||||||
|
const lowestPoint = ((lastChat.lastTop + lastChat.height) - 1);
|
||||||
|
const requiredSpace = ((amount || lastChat.height) + 1);
|
||||||
|
const spaceAvailable = (elementRef.current.offsetHeight - lowestPoint);
|
||||||
|
|
||||||
|
if(spaceAvailable < requiredSpace)
|
||||||
|
{
|
||||||
|
amount = (requiredSpace - spaceAvailable);
|
||||||
|
|
||||||
|
chatMessages.forEach((chat, index) =>
|
||||||
|
{
|
||||||
|
if(skipLast && (index === (chatMessages.length - 1))) return;
|
||||||
|
|
||||||
|
moveChatUp(chat, amount)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [ chatMessages, moveChatUp ]);
|
||||||
|
|
||||||
|
const addChat = useCallback((chat: ChatBubbleMessage) =>
|
||||||
|
{
|
||||||
|
setChatMessages(prevValue =>
|
||||||
|
{
|
||||||
|
return [ ...prevValue, chat ]
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onRoomSessionChatEvent = useCallback((event: RoomSessionChatEvent) =>
|
||||||
|
{
|
||||||
|
const roomObject = GetRoomEngine().getRoomObject(event.session.roomId, event.objectId, RoomObjectCategory.UNIT);
|
||||||
|
|
||||||
|
if(!roomObject) return;
|
||||||
|
|
||||||
|
const canvasId = 1;
|
||||||
|
|
||||||
|
const roomGeometry = GetRoomEngine().getRoomInstanceGeometry(event.session.roomId, canvasId);
|
||||||
|
|
||||||
|
if(!roomGeometry) return;
|
||||||
|
|
||||||
|
const objectLocation = roomObject.getLocation();
|
||||||
|
const bubbleLocation = GetBubbleLocation(event.session.roomId, objectLocation, canvasId);
|
||||||
|
const userData = GetRoomSession().userDataManager.getUserDataByIndex(event.objectId);
|
||||||
|
|
||||||
|
let username = '';
|
||||||
|
let avatarColor = '';
|
||||||
|
let imageUrl: string = null;
|
||||||
|
let chatType = event.chatType;
|
||||||
|
let styleId = event.style;
|
||||||
|
let userType = 0;
|
||||||
|
let petType = -1;
|
||||||
|
let text = event.message;
|
||||||
|
|
||||||
|
if(userData)
|
||||||
|
{
|
||||||
|
userType = userData.type;
|
||||||
|
|
||||||
|
const figure = userData.figure;
|
||||||
|
|
||||||
|
// switch(userType)
|
||||||
|
// {
|
||||||
|
// case RoomObjectType.PET:
|
||||||
|
// image = this.getPetImage(figure, 2, true, 64, roomObject.model.getValue<string>(RoomObjectVariable.FIGURE_POSTURE));
|
||||||
|
// petType = new PetFigureData(figure).typeId;
|
||||||
|
// break;
|
||||||
|
// case RoomObjectType.USER:
|
||||||
|
// image = this.getUserImage(figure);
|
||||||
|
// break;
|
||||||
|
// case RoomObjectType.RENTABLE_BOT:
|
||||||
|
// case RoomObjectType.BOT:
|
||||||
|
// styleId = SystemChatStyleEnum.BOT;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
//avatarColor = this._avatarColorCache.get(figure);
|
||||||
|
username = userData.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chatMessage = new ChatBubbleMessage(
|
||||||
|
text,
|
||||||
|
username,
|
||||||
|
bubbleLocation,
|
||||||
|
chatType,
|
||||||
|
styleId,
|
||||||
|
imageUrl,
|
||||||
|
avatarColor
|
||||||
|
);
|
||||||
|
|
||||||
|
addChat(chatMessage);
|
||||||
|
}, [ addChat ]);
|
||||||
|
|
||||||
|
useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onRoomSessionChatEvent);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
const interval = setInterval(() => moveAllChatsUp(15), 500);
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
{
|
||||||
|
if(interval) clearInterval(interval);
|
||||||
|
}
|
||||||
|
}, [ chatMessages, moveAllChatsUp ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
const interval = setInterval(() => removeLastHiddenChat(), 500);
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
{
|
||||||
|
if(interval) clearInterval(interval);
|
||||||
|
}
|
||||||
|
}, [ removeLastHiddenChat ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={ elementRef } className="nitro-chat-widget">
|
||||||
|
{ chatMessages && (chatMessages.length > 0) && chatMessages.map((chat, index) =>
|
||||||
|
{
|
||||||
|
return <ChatWidgetMessageView key={ index } chat={ chat } makeRoom={ makeRoom } />
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
4
src/views/room/widgets/chat/ChatWidgetView.types.ts
Normal file
4
src/views/room/widgets/chat/ChatWidgetView.types.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface ChatWidgetViewProps
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
.nitro-chat-widget {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
import { ChatWidgetsViewProps } from './ChatWidgetsView.types';
|
|
||||||
import { ChatMessagesWidgetView } from './messages/ChatMessagesWidgetView';
|
|
||||||
|
|
||||||
export function ChatWidgetsView(props: ChatWidgetsViewProps): JSX.Element
|
|
||||||
{
|
|
||||||
const {} = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="nitro-chat-widget">
|
|
||||||
<ChatMessagesWidgetView />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
export interface ChatWidgetsViewProps
|
|
||||||
{}
|
|
904
src/views/room/widgets/chat/message/ChatWidgetMessageView.scss
Normal file
904
src/views/room/widgets/chat/message/ChatWidgetMessageView.scss
Normal file
@ -0,0 +1,904 @@
|
|||||||
|
@keyframes bounceIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(.3);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
transform: scale(.9);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble-container {
|
||||||
|
position: absolute;
|
||||||
|
width: fit-content;
|
||||||
|
transition: top 0.2s ease 0s;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: all;
|
||||||
|
|
||||||
|
// -webkit-animation-duration: 0.2s;
|
||||||
|
// animation-duration: 0.2s;
|
||||||
|
// -webkit-animation-fill-mode: both;
|
||||||
|
// animation-fill-mode: both;
|
||||||
|
// -webkit-animation-name: bounceIn;
|
||||||
|
// animation-name: bounceIn;
|
||||||
|
|
||||||
|
.user-container-bg {
|
||||||
|
position: absolute;
|
||||||
|
top: -1px;
|
||||||
|
left: 1px;
|
||||||
|
width: 30px;
|
||||||
|
height: calc(100% - 0.5px);
|
||||||
|
border-radius: 7px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-bubble {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
word-break: break-word;
|
||||||
|
max-width: 350px;
|
||||||
|
min-height: 25px;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
|
||||||
|
border-image-slice: 17 6 6 29 fill;
|
||||||
|
border-image-width: 17px 6px 6px 29px;
|
||||||
|
border-image-outset: 2px 0px 0px 0px;
|
||||||
|
border-image-repeat: repeat repeat;
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
|
||||||
|
width: 9px;
|
||||||
|
height: 6px;
|
||||||
|
bottom: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.type-0 { // normal
|
||||||
|
.message {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.type-1 { // whisper
|
||||||
|
.message {
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
color: #595959;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.type-2 { // shout
|
||||||
|
.message {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-0 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_0_transparent.png');
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png');
|
||||||
|
bottom: -5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-1 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_1.png');
|
||||||
|
|
||||||
|
border-image-slice: 18 6 6 29 fill;
|
||||||
|
border-image-width: 18px 6px 6px 29px;
|
||||||
|
border-image-outset: 3px 0px 0px 0px;
|
||||||
|
|
||||||
|
.user-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-2, &.bubble-31 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_2.png');
|
||||||
|
|
||||||
|
.user-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
color: rgba($white, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
color: rgba($white, 1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_2_31_pointer.png');
|
||||||
|
height: 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-3 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_3.png');
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_3_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-4 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_4.png');
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_4_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-5 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_5.png');
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_5_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-6 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_6.png');
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_6_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-7 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_7.png');
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_7_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-8 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_8.png');
|
||||||
|
|
||||||
|
border-image-slice: 20 6 6 27 fill;
|
||||||
|
border-image-width: 20px 6px 6px 27px;
|
||||||
|
border-image-outset: 5px 0px 0px 0px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_8_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-9 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_9.png');
|
||||||
|
|
||||||
|
border-image-slice: 17 18 12 19 fill;
|
||||||
|
border-image-width: 17px 18px 12px 19px;
|
||||||
|
border-image-outset: 7px 7px 0px 9px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_9_pointer.png');
|
||||||
|
width: 7px;
|
||||||
|
height: 10px;
|
||||||
|
bottom: -6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-10 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_10.png');
|
||||||
|
|
||||||
|
border-image-slice: 29 18 8 37 fill;
|
||||||
|
border-image-width: 29px 18px 8px 37px;
|
||||||
|
border-image-outset: 12px 7px 1px 5px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 24px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_10_pointer.png');
|
||||||
|
width: 7px;
|
||||||
|
height: 8px;
|
||||||
|
bottom: -3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-11 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_11.png');
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_11_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-12 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_12.png');
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_12_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-13 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_13.png');
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_13_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-14 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_14.png');
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_14_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-15 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_15.png');
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_15_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-16 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_16.png');
|
||||||
|
|
||||||
|
border-image-slice: 13 6 10 31 fill;
|
||||||
|
border-image-width: 13px 6px 10px 31px;
|
||||||
|
border-image-outset: 6px 0px 0px 0px;
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_16_pointer.png');
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-17 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_17.png');
|
||||||
|
|
||||||
|
border-image-slice: 24 6 8 35 fill;
|
||||||
|
border-image-width: 24px 6px 8px 35px;
|
||||||
|
border-image-outset: 9px 0px 2px 5px;
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_17_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-18 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_18.png');
|
||||||
|
|
||||||
|
border-image-slice: 7 16 8 16 fill;
|
||||||
|
border-image-width: 7px 16px 8px 16px;
|
||||||
|
border-image-outset: 3px 10px 2px 11px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_18_pointer.png');
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-19 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_19.png');
|
||||||
|
|
||||||
|
border-image-slice: 17 6 9 19 fill;
|
||||||
|
border-image-width: 17px 6px 9px 19px;
|
||||||
|
border-image-outset: 5px 0px 0px 8px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_19_20_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-20 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_20.png');
|
||||||
|
|
||||||
|
border-image-slice: 18 6 8 19 fill;
|
||||||
|
border-image-width: 18px 6px 8px 19px;
|
||||||
|
border-image-outset: 5px 0px 0px 8px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_19_20_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-21 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_21.png');
|
||||||
|
|
||||||
|
border-image-slice: 20 6 12 24 fill;
|
||||||
|
border-image-width: 20px 6px 12px 24px;
|
||||||
|
border-image-outset: 13px 2px 1px 3px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_21_pointer.png');
|
||||||
|
bottom: -4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-22 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_22.png');
|
||||||
|
|
||||||
|
border-image-slice: 18 19 11 33 fill;
|
||||||
|
border-image-width: 18px 19px 11px 33px;
|
||||||
|
border-image-outset: 7px 1px 1px 5px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_22_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-23 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_23.png');
|
||||||
|
|
||||||
|
border-image-slice: 16 6 7 32 fill;
|
||||||
|
border-image-width: 16px 6px 7px 32px;
|
||||||
|
border-image-outset: 5px 0px 0px 3px;
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_23_37_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-24 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_24.png');
|
||||||
|
|
||||||
|
border-image-slice: 23 8 6 40 fill;
|
||||||
|
border-image-width: 23px 8px 6px 40px;
|
||||||
|
border-image-outset: 6px 0px 0px 6px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 30px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_24_pointer.png');
|
||||||
|
bottom: -4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-25 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_25.png');
|
||||||
|
|
||||||
|
border-image-slice: 10 13 8 28 fill;
|
||||||
|
border-image-width: 10px 13px 8px 28px;
|
||||||
|
border-image-outset: 6px 3px 2px 0px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_25_pointer.png');
|
||||||
|
height: 9px;
|
||||||
|
bottom: -7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-26 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_26.png');
|
||||||
|
|
||||||
|
border-image-slice: 16 9 8 29 fill;
|
||||||
|
border-image-width: 16px 9px 8px 29px;
|
||||||
|
border-image-outset: 2px 2px 2px 0px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
color: #c59432;
|
||||||
|
text-shadow: 1px 1px rgba(0, 0, 0, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_26_pointer.png');
|
||||||
|
height: 10px;
|
||||||
|
bottom: -6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-27 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_27.png');
|
||||||
|
|
||||||
|
border-image-slice: 25 6 5 36 fill;
|
||||||
|
border-image-width: 25px 6px 5px 36px;
|
||||||
|
border-image-outset: 8px 0px 0px 5px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 30px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_27_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-28 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_28.png');
|
||||||
|
|
||||||
|
border-image-slice: 16 7 7 27 fill;
|
||||||
|
border-image-width: 16px 7px 7px 27px;
|
||||||
|
border-image-outset: 3px 0px 0px 0px;
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_28_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-29 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_29.png');
|
||||||
|
|
||||||
|
border-image-slice: 10 7 15 31 fill;
|
||||||
|
border-image-width: 10px 7px 15px 31px;
|
||||||
|
border-image-outset: 2px 0px 0px 1px;
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_29_pointer.png');
|
||||||
|
bottom: -4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-30 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_30.png');
|
||||||
|
|
||||||
|
.user-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_30_pointer.png');
|
||||||
|
height: 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-32 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_32.png');
|
||||||
|
|
||||||
|
border-image-slice: 15 7 7 30 fill;
|
||||||
|
border-image-width: 15px 7px 7px 30px;
|
||||||
|
border-image-outset: 2px 0px 0px 0px;
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_32_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-33 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_33_34.png');
|
||||||
|
|
||||||
|
border-image-slice: 7 6 6 39 fill;
|
||||||
|
border-image-width: 7px 6px 6px 39px;
|
||||||
|
border-image-outset: 2px 0px 0px 0px;
|
||||||
|
|
||||||
|
.user-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
left: 9px;
|
||||||
|
top: 2px;
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_33_extra.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-34 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_33_34.png');
|
||||||
|
|
||||||
|
border-image-slice: 7 6 6 39 fill;
|
||||||
|
border-image-width: 7px 6px 6px 39px;
|
||||||
|
border-image-outset: 2px 0px 0px 0px;
|
||||||
|
|
||||||
|
&.type-1 {
|
||||||
|
|
||||||
|
.message {
|
||||||
|
font-style: unset;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
margin-left: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
left: 9px;
|
||||||
|
top: 2px;
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_34_extra.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-35 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_35.png');
|
||||||
|
|
||||||
|
border-image-slice: 19 6 5 29 fill;
|
||||||
|
border-image-width: 19px 6px 5px 29px;
|
||||||
|
border-image-outset: 4px 0px 0px 0px;
|
||||||
|
|
||||||
|
.user-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_35_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-36 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_36.png');
|
||||||
|
|
||||||
|
border-image-slice: 17 7 5 30 fill;
|
||||||
|
border-image-width: 17px 7px 5px 30px;
|
||||||
|
border-image-outset: 2px 0px 0px 0px;
|
||||||
|
|
||||||
|
.user-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
width: 13px;
|
||||||
|
height: 18px;
|
||||||
|
left: 5px;
|
||||||
|
top: 2px;
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_36_extra.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_36_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-37 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_37.png');
|
||||||
|
|
||||||
|
border-image-slice: 16 6 7 32 fill;
|
||||||
|
border-image-width: 16px 6px 7px 32px;
|
||||||
|
border-image-outset: 5px 0px 0px 3px;
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_23_37_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-38 {
|
||||||
|
border-image-source: url('../../../../../assets/images/chat/chatbubbles/bubble_38.png');
|
||||||
|
|
||||||
|
border-image-slice: 17 7 5 30 fill;
|
||||||
|
border-image-width: 17px 7px 5px 30px;
|
||||||
|
border-image-outset: 2px 0px 0px 0px;
|
||||||
|
|
||||||
|
.user-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
left: 3px;
|
||||||
|
top: 2px;
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_38_extra.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_38_pointer.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-container {
|
||||||
|
z-index: 3;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
max-height: 24px;
|
||||||
|
image-rendering: -webkit-optimize-contrast;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.user-image {
|
||||||
|
position: absolute;
|
||||||
|
top: -48px;
|
||||||
|
left: -32.5px;
|
||||||
|
width: 90px;
|
||||||
|
height: 130px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
transform: scale(0.5) translateZ(0);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-content {
|
||||||
|
padding: 5px 6px 5px 4px;
|
||||||
|
margin-left: 27px;
|
||||||
|
line-height: 1;
|
||||||
|
color: $black;
|
||||||
|
min-height: 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-bubble-icon {
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
|
||||||
|
&.bubble-0 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_0.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-1 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_1.png');
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-2, &.bubble-31 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_2.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-3 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_3.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-4 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_4.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-5 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_5.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-6 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_6.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-7 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_7.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-8 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_8.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-9 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_9.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-10 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_10.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-11 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_11.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-12 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_12.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-13 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_13.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-14 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_14.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-15 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_15.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-16 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_16.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-17 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_17.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-18 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_18.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-19 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_19.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-20 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_20.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-21 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_21.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-22 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_22.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-23 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_23.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-24 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_24.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-25 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_25.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-26 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_26.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-27 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_27.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-28 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_28.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-29 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_29.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-30 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_30.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-32 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_32.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-33 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_33_34.png');
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
left: 11px;
|
||||||
|
top: 10px;
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_33_extra.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-34 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_33_34.png');
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
left: 11px;
|
||||||
|
top: 10px;
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_34_extra.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-35 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_35.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-36 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_36.png');
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
width: 13px;
|
||||||
|
height: 18px;
|
||||||
|
left: 13px;
|
||||||
|
top: 10px;
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_36_extra.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-37 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_35.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bubble-38 {
|
||||||
|
background-image: url('../../../../../assets/images/chat/chatbubbles/bubble_38.png');
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
left: 11px;
|
||||||
|
top: 10px;
|
||||||
|
background: url('../../../../../assets/images/chat/chatbubbles/bubble_38_extra.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
import { FC, MouseEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { ChatWidgetMessageViewProps } from './ChatWidgetMessageView.types';
|
||||||
|
|
||||||
|
export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { chat = null, makeRoom = null } = props;
|
||||||
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
|
const elementRef = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
const onClick = useCallback((event: MouseEvent) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
const element = elementRef.current;
|
||||||
|
|
||||||
|
if(!element) return;
|
||||||
|
|
||||||
|
const width = element.offsetWidth;
|
||||||
|
const height = element.offsetHeight;
|
||||||
|
|
||||||
|
chat.width = width;
|
||||||
|
chat.height = height;
|
||||||
|
chat.elementRef = element;
|
||||||
|
|
||||||
|
if(isVisible || !chat) return;
|
||||||
|
|
||||||
|
let left = chat.lastLeft;
|
||||||
|
let top = chat.lastTop;
|
||||||
|
|
||||||
|
if(!left && !top)
|
||||||
|
{
|
||||||
|
left = (chat.location.x - (width / 2));
|
||||||
|
top = (element.parentElement.offsetHeight - height);
|
||||||
|
}
|
||||||
|
|
||||||
|
chat.lastLeft = left;
|
||||||
|
chat.lastTop = top;
|
||||||
|
|
||||||
|
element.style.left = (left + 'px');
|
||||||
|
element.style.top = (top + 'px');
|
||||||
|
|
||||||
|
makeRoom(0, true);
|
||||||
|
setIsVisible(true);
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
{
|
||||||
|
chat.elementRef = null;
|
||||||
|
}
|
||||||
|
}, [ isVisible, elementRef, chat, makeRoom ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={ elementRef } className="bubble-container" style={ { visibility: (isVisible ? 'visible' : 'hidden') } }>
|
||||||
|
{ (chat.styleId === 0) && <div className="user-container-bg" style={ { backgroundColor: chat.color } } /> }
|
||||||
|
<div className={ 'chat-bubble bubble-' + chat.styleId + ' type-' + chat.type } onClick={ onClick }>
|
||||||
|
<div className="user-container">
|
||||||
|
{ (chat.imageUrl && (chat.imageUrl !== '')) && <div className="user-image" style={ { backgroundImage: 'url(' + chat.imageUrl + ')' } } /> }
|
||||||
|
</div>
|
||||||
|
<div className="chat-content">
|
||||||
|
<b className="username mr-1">{ chat.username }</b><span className="message"> { chat.text }</span>
|
||||||
|
</div>
|
||||||
|
<div className="pointer"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { ChatBubbleMessage } from '../utils/ChatBubbleMessage';
|
||||||
|
|
||||||
|
export interface ChatWidgetMessageViewProps
|
||||||
|
{
|
||||||
|
chat: ChatBubbleMessage;
|
||||||
|
makeRoom: (amount?: number, skipLast?: boolean) => void;
|
||||||
|
}
|
25
src/views/room/widgets/chat/utils/ChatBubbleMessage.ts
Normal file
25
src/views/room/widgets/chat/utils/ChatBubbleMessage.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { INitroPoint } from 'nitro-renderer';
|
||||||
|
|
||||||
|
export class ChatBubbleMessage
|
||||||
|
{
|
||||||
|
public static BUBBLE_COUNTER: number = -1;
|
||||||
|
|
||||||
|
public id: number = -1;
|
||||||
|
public width: number = 0;
|
||||||
|
public height: number = 0;
|
||||||
|
public lastTop: number = 0;
|
||||||
|
public lastLeft: number = 0;
|
||||||
|
public elementRef: HTMLDivElement = null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public text: string = '',
|
||||||
|
public username: string = '',
|
||||||
|
public location: INitroPoint = null,
|
||||||
|
public type: number = 0,
|
||||||
|
public styleId: number = 0,
|
||||||
|
public imageUrl: string = null,
|
||||||
|
public color: string = null
|
||||||
|
) {
|
||||||
|
this.id = ++ChatBubbleMessage.BUBBLE_COUNTER;
|
||||||
|
}
|
||||||
|
}
|
32
src/views/room/widgets/chat/utils/ChatWidgetUtilities.ts
Normal file
32
src/views/room/widgets/chat/utils/ChatWidgetUtilities.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { INitroPoint, IVector3D, NitroPoint } from 'nitro-renderer';
|
||||||
|
import { GetRoomEngine } from '../../../../../api';
|
||||||
|
|
||||||
|
export function GetBubbleLocation(roomId: number, userLocation: IVector3D, canvasId = 1): INitroPoint
|
||||||
|
{
|
||||||
|
const geometry = GetRoomEngine().getRoomInstanceGeometry(roomId, canvasId);
|
||||||
|
const scale = GetRoomEngine().getRoomInstanceRenderingCanvasScale(roomId, canvasId);
|
||||||
|
|
||||||
|
let x = ((document.body.offsetWidth * scale) / 2);
|
||||||
|
let y = ((document.body.offsetHeight * scale) / 2);
|
||||||
|
|
||||||
|
if(geometry && userLocation)
|
||||||
|
{
|
||||||
|
const screenPoint = geometry.getScreenPoint(userLocation);
|
||||||
|
|
||||||
|
if(screenPoint)
|
||||||
|
{
|
||||||
|
x = (x + (screenPoint.x * scale));
|
||||||
|
y = (y + (screenPoint.y * scale));
|
||||||
|
|
||||||
|
const offsetPoint = GetRoomEngine().getRoomInstanceRenderingCanvasOffset(roomId, canvasId);
|
||||||
|
|
||||||
|
if(offsetPoint)
|
||||||
|
{
|
||||||
|
x = (x + offsetPoint.x);
|
||||||
|
y = (y + offsetPoint.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NitroPoint(x, y);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user