1344 lines
28 KiB
Svelte
1344 lines
28 KiB
Svelte
<script>
|
||
import { getLastMessages, MessagePicToUrl, getAllChats, getPinnedMsg, getMessageById, uploadImages, getAllUsers, createNewChat, deleteChat } from '$lib/chat';
|
||
import { UserCheck } from '$lib/userFunction'
|
||
|
||
import Header from '../Header.svelte';
|
||
import createWebSocket from '$lib/websocket';
|
||
|
||
import { onMount, tick } from 'svelte';
|
||
import { fade, slide, fly, scale } from 'svelte/transition';
|
||
|
||
import formatDistanceToNow from 'date-fns/formatDistanceToNow';
|
||
import ruLocale from 'date-fns/locale/ru';
|
||
|
||
import { PUBLIC_WSS } from '$env/static/public';
|
||
|
||
console.clear();
|
||
|
||
let userId; //пользователь, который залогинен
|
||
let socket; //вебсокет
|
||
let token;
|
||
|
||
let messages = [] //массив сообщений, которые отображаются на сайте
|
||
let msgLoaded = 0
|
||
let messageText = '' //сообщения для отправки
|
||
let selectedFile // картинка для отправки
|
||
let imageToUpload = null
|
||
let messagePic //картинка для отправки
|
||
let flag = "send"
|
||
let answer = null
|
||
let chats = [] //массив чатов, доступных юзеру
|
||
let pinnedMsg = []
|
||
let chatId = null
|
||
let scrollableDiv;
|
||
let answerMessageTextShow = false
|
||
let answerMessageImgShow = false
|
||
let imageFile = undefined
|
||
let imageShow = false;
|
||
|
||
let answerMessage = ""
|
||
let answerMessageImg = ""
|
||
let currentChat;
|
||
let pickedChatName = ""
|
||
let pickedChatImg = ""
|
||
|
||
let warningMessage = ""
|
||
|
||
let inputArea //объект textarea
|
||
|
||
onMount(async () => {
|
||
|
||
const userData = await UserCheck();
|
||
userId = userData.id;
|
||
|
||
window.addEventListener('keydown', onEnterPress);
|
||
|
||
chats = await getAllChats()
|
||
if(chats == false){
|
||
chats = []
|
||
warningMessage = "чтобы пользоваться чатом, подтверди почту"
|
||
}
|
||
createNewChatButton = true
|
||
//console.log(chats, " чаты")
|
||
|
||
async function handleChatUrlChange() {
|
||
if (window.location.hash.startsWith('#id=')) {
|
||
|
||
chatId = window.location.hash.slice(4);
|
||
msgLoaded = 0
|
||
//console.log(chatId, " chatId")
|
||
|
||
currentChat = chats.find(chat => chat.chat_id == chatId)
|
||
if(currentChat == undefined){
|
||
window.location.href = '/chat'
|
||
}
|
||
//console.log(currentChat, " текущий чат")
|
||
pickedChatName = currentChat.chat_name
|
||
pickedChatImg = currentChat.avatar_image
|
||
|
||
messages = await getLastMessages(chatId,msgLoaded)
|
||
msgLoaded += 15
|
||
pinnedMsg = await getPinnedMsg(chatId)
|
||
|
||
token = localStorage.getItem('BPChat')
|
||
const websocketUrl = `${PUBLIC_WSS}/api/chat/ws/${chatId}`
|
||
|
||
if (socket){
|
||
console.log("Сокет есть")
|
||
socket.close();
|
||
socket = null
|
||
}
|
||
let tokenForSocket = token.split(" ")[1];
|
||
socket = createWebSocket(websocketUrl, tokenForSocket, async (message) => {
|
||
|
||
//console.log(message, "сообщение!!!!!")
|
||
if(message.flag === "pin" ){
|
||
|
||
//console.log("ЗАКРЕП!!!!!!!!!!!")
|
||
pinnedMsg = [message, ...pinnedMsg]
|
||
|
||
}
|
||
else if(message.flag === "delete"){
|
||
|
||
let messageToDelete = messages.findIndex(msg => msg.id === message.id)
|
||
messages.splice(messageToDelete,1)
|
||
messages = messages
|
||
|
||
} else if(message.flag === "unpin"){
|
||
|
||
const indexOfMassive = pinnedMsg.findIndex(msg => msg.id == message.id)
|
||
pinnedMsg.splice(indexOfMassive, 1)
|
||
pinnedMsg = pinnedMsg
|
||
|
||
} else {
|
||
|
||
|
||
messages = [message, ...messages]
|
||
|
||
}
|
||
messages = messages
|
||
|
||
})
|
||
}
|
||
}
|
||
handleChatUrlChange();
|
||
window.addEventListener('hashchange', handleChatUrlChange);
|
||
|
||
});
|
||
|
||
let isLoaded = false
|
||
|
||
async function sendMessage() {
|
||
|
||
let image = null
|
||
if(imageToUpload != null){
|
||
isLoaded = true
|
||
image = await uploadImages(imageToUpload)
|
||
isLoaded = false
|
||
}
|
||
if((messageText != "") || image != null){
|
||
|
||
//console.log(`${messageText} - текст, ${image} - картинка`)
|
||
if(messageText == "жопа"){
|
||
messageText = "жопа съела трусы O.O"
|
||
image = "https://images.black-phoenix.ru/static/images/images/%D0%B6%D0%BE%D0%BF%D0%B0%20%D1%81%D1%8A%D0%B5%D0%BB%D0%B0%20%D1%82%D1%80%D1%83%D1%81%D1%8B.jpg"
|
||
}
|
||
|
||
if(socket.readyState === WebSocket.OPEN){
|
||
|
||
socket.send(JSON.stringify({flag: flag,
|
||
message: messageText,
|
||
image_url: image,
|
||
answer: answer }));
|
||
|
||
messageText = ""
|
||
imageFile = undefined
|
||
imageShow = false
|
||
imageToUpload = null
|
||
answer = null
|
||
answerMessageTextShow = false
|
||
answerMessageImgShow = false
|
||
answerMessage = ""
|
||
answerMessageImg = ""
|
||
|
||
} else {
|
||
|
||
console.log("ноуп")
|
||
//console.log(socket)
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
function onEnterPress(event) {
|
||
if (event.key === "Enter" && !event.shiftKey) {
|
||
event.preventDefault();
|
||
//console.log("нажата ", messageText)
|
||
if(!isLoaded)
|
||
sendMessage()
|
||
}
|
||
}
|
||
|
||
let rows = 1
|
||
const maxRows = 10
|
||
|
||
function adjustTextareaHeight() {
|
||
const textarea = document.getElementById("msg");
|
||
//console.log(textarea.scrollHeight)
|
||
if (textarea) {
|
||
textarea.style.height = '1em'; //??
|
||
textarea.style.height = (textarea.scrollHeight > maxRows * 18) ? `${maxRows * 18}px` : `${textarea.scrollHeight}px`; // Limit height based on maxRows and font size
|
||
//console.log(textarea.scrollHeight)
|
||
}
|
||
|
||
}
|
||
|
||
function onInput(event) {
|
||
const lines = event.target.value.split("\n").length;
|
||
if (lines > maxRows) {
|
||
event.target.value = event.target.value.slice(0, event.target.value.lastIndexOf("\n")); // Prevent exceeding max lines
|
||
}
|
||
adjustTextareaHeight();
|
||
}
|
||
|
||
let x ;
|
||
let y ;
|
||
let helperDivBoolShow = false
|
||
let helperDiv
|
||
let pickedId
|
||
let PickedText = ""
|
||
let PickedImg = ""
|
||
let PickedName = ""
|
||
|
||
let pinOrNot = false
|
||
|
||
function helperDivShow(event, id, text, img, username) {
|
||
if(pinnedMsg != null){
|
||
pinOrNot = pinnedMsg.some(msg => msg.id == id)
|
||
//console.log(pinOrNot)
|
||
}
|
||
|
||
if (helperDiv) {
|
||
helperDivBoolShow = false
|
||
}
|
||
|
||
event.preventDefault();
|
||
helperDivBoolShow = true
|
||
|
||
PickedText = text
|
||
PickedImg = img
|
||
PickedName = username
|
||
pickedId = id
|
||
|
||
const setHelperDivPosition = () => {
|
||
if (helperDiv) {
|
||
const x = event.clientX;
|
||
const y = event.clientY;
|
||
helperDiv.style.left = `${x}px`;
|
||
helperDiv.style.top = `${y}px`;
|
||
//console.log(x, y);
|
||
}
|
||
};
|
||
|
||
// Используем setTimeout для того, чтобы убедиться, что элемент доступен в DOM
|
||
setTimeout(setHelperDivPosition, 0);
|
||
}
|
||
|
||
function hideHelperDiv(event){
|
||
|
||
if ((event.target !== helperDiv) && (helperDiv)) {
|
||
helperDivBoolShow = false
|
||
}
|
||
}
|
||
|
||
function ansFunc(){
|
||
|
||
inputArea.focus()
|
||
answerMessage = PickedText
|
||
answerMessageImg = PickedImg
|
||
|
||
//console.log(answerMessage, answerMessageImg)
|
||
answer = pickedId
|
||
if(answerMessage != "")
|
||
answerMessageTextShow = true
|
||
if(answerMessageImg != null)
|
||
answerMessageImgShow = true
|
||
//console.log(answerMessageTextShow, answerMessageImgShow)
|
||
}
|
||
|
||
async function pinFunc(event){
|
||
|
||
socket.send(JSON.stringify({"flag": "pin",
|
||
"user_id": userId,
|
||
"id": pickedId
|
||
}));
|
||
|
||
}
|
||
|
||
async function unpinFunc(event){
|
||
socket.send(JSON.stringify({"flag": "unpin",
|
||
"id": pickedId
|
||
}));
|
||
}
|
||
|
||
function delFunc(event){
|
||
socket.send(JSON.stringify({"flag": "delete",
|
||
"user_id": userId,
|
||
"id": pickedId
|
||
}));
|
||
pinnedMsg = pinnedMsg.filter(pinnedMsg => pinnedMsg.id !== pickedId)
|
||
}
|
||
|
||
function triggerFileInput() {
|
||
imageFile.click();
|
||
}
|
||
|
||
function handleFileChange(event) {
|
||
const file = event.target.files[0];
|
||
imageToUpload = file
|
||
if (file) {
|
||
const reader = new FileReader();
|
||
reader.onloadend = (e) => {
|
||
|
||
imageFile = e.target.result;
|
||
imageShow = true;
|
||
};
|
||
reader.readAsDataURL(file);
|
||
}
|
||
}
|
||
|
||
//афк
|
||
function handleFileChangeCopy(event) {
|
||
const file = event.target.files[0];
|
||
if (file) {
|
||
const reader = new FileReader();
|
||
reader.onloadend = (e) => {
|
||
|
||
imageFile = e.target.result;
|
||
imageShow = true;
|
||
imageToUpload = imageFile
|
||
};
|
||
|
||
}
|
||
}
|
||
|
||
function deleteImage(){
|
||
imageFile = undefined;
|
||
imageShow = false;
|
||
imageToUpload = null
|
||
}
|
||
|
||
function deleteAnswer(){
|
||
answerMessageTextShow = false
|
||
answerMessageImgShow = false
|
||
answerMessageImg = ""
|
||
answerMessage = ""
|
||
}
|
||
|
||
let oldScrollHeight = null;
|
||
let uploadingNewMsg = true
|
||
async function handleScroll(event) {
|
||
|
||
const { scrollTop, scrollHeight, clientHeight } = event.target
|
||
|
||
let topHeight = scrollTop*-1 + clientHeight + 1
|
||
|
||
//console.log(topHeight)
|
||
//console.log("высота дива - ", scrollHeight)
|
||
|
||
if (topHeight == scrollHeight) {
|
||
// если прокрутка достигла верхней части
|
||
|
||
|
||
const newMessages = await getLastMessages(chatId,msgLoaded)
|
||
messages = [ ...messages, ...newMessages ]
|
||
msgLoaded += newMessages.length
|
||
|
||
}
|
||
}
|
||
|
||
function scrollDown(){
|
||
scrollableDiv.scrollTop = scrollableDiv.scrollHeight
|
||
}
|
||
|
||
let createNewChatButton = false
|
||
let createNewChatShow = false
|
||
let nameToFind = ""
|
||
let newChatName = ""
|
||
let selectedUserId = "";
|
||
let users = []
|
||
|
||
async function startingCreateNewChat(){
|
||
createNewChatShow = true
|
||
users = await getAllUsers(nameToFind)
|
||
//console.log(users)
|
||
}
|
||
|
||
async function submtiCreateNewChat(){
|
||
token = localStorage.getItem('BPChat')
|
||
let newChatId = await createNewChat(newChatName, selectedUserId, token)
|
||
|
||
createNewChatShow = false
|
||
|
||
history.pushState(null, null, `/chat#id=${newChatId}`);
|
||
//handleRouteChange();
|
||
chats = await getAllChats()
|
||
}
|
||
|
||
function cancelCreateNewChat(){
|
||
createNewChatShow = false
|
||
selectedUserId = ""
|
||
}
|
||
|
||
function checkCheckBox(event){
|
||
const userId = event.target.value;
|
||
selectedUserId = userId;
|
||
|
||
}
|
||
|
||
async function lisinerNameToFine(event){
|
||
//console.log(event.target.value)
|
||
nameToFind = event.target.value
|
||
users = await getAllUsers(nameToFind)
|
||
//console.log(users)
|
||
}
|
||
|
||
let msgTime
|
||
let msgTimeShow = false
|
||
|
||
function msgTimeFunc(data, event){
|
||
let localeTime = new Date(data)
|
||
const formattedDate = formatDistanceToNow(new Date(localeTime), { addSuffix: true, locale: ruLocale });
|
||
msgTime = formattedDate
|
||
|
||
msgTimeShow = true
|
||
}
|
||
|
||
function msgTimeFuncOver(event){
|
||
msgTimeShow = false
|
||
}
|
||
|
||
async function deleteChatButt(chatId){
|
||
let result = await deleteChat(chatId,token)
|
||
const index = chats.findIndex(chat => chat.chat_id === chatId);
|
||
chats.splice(index, 1);
|
||
//console.log(index)
|
||
//console.log(result)
|
||
chats = await getAllChats()
|
||
}
|
||
</script>
|
||
|
||
<svelte:window on:click={hideHelperDiv} />
|
||
|
||
<body>
|
||
|
||
{#if createNewChatShow == true}
|
||
<div class="backgroundBlur" transition:fade></div>
|
||
|
||
<div class="newChatDiv" transition:fly={{y:-1000, duration:500}}>
|
||
<h1 class="">Новый чат</h1>
|
||
<div class="newChatInputDiv">
|
||
|
||
<h3>Название чата</h3>
|
||
<input class="newChatName" bind:value={newChatName} type="text">
|
||
|
||
<h4 class="newChatText">заблокируйте доступ к чату одному из пользователей</h4>
|
||
<input placeholder="Введите ник для поиска" type="text" class="nameToFind" on:input={lisinerNameToFine} name="nameToFind">
|
||
|
||
<div class="newChatCheckboxDiv">
|
||
{#each users as user}
|
||
<div class="newChatUser">
|
||
|
||
<input value="{user.id}" on:change="{checkCheckBox}"
|
||
type="radio" name="checkbox" class="radioButton" >
|
||
|
||
<img class="newChatAvatar" src="{user.avatar_image}" alt="ава">
|
||
<h3 for={user.id}>{user.username}</h3>
|
||
|
||
</div>
|
||
{/each}
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="newChatButtonDiv">
|
||
<button disabled={((selectedUserId == "") || (newChatName == ""))} on:click={submtiCreateNewChat}>Создать</button>
|
||
<button on:click={cancelCreateNewChat}>Отменить</button>
|
||
</div>
|
||
|
||
</div>
|
||
{/if}
|
||
|
||
<div class="grid">
|
||
|
||
<div class="headerDiv"><Header/></div>
|
||
|
||
<div>
|
||
|
||
<div class="gradient">
|
||
<div class="chatsDiv">
|
||
{#if createNewChatButton == true}
|
||
<button on:click={startingCreateNewChat} class="createChatDivLeft"
|
||
transition:fade={{ duration: 800 }}>
|
||
<h2 class="createNewChat">Создать новый чат</h2>
|
||
</button>
|
||
{/if}
|
||
|
||
|
||
{#each chats as chat}
|
||
<div class="chatDivLeft" class:chatDivLeftSelected="{chat.chat_id == chatId}"
|
||
transition:fade={{ duration: 800 }}>
|
||
<a class="aChatDivLeft" href={`/chat#id=${chat.chat_id}`}>
|
||
<img class="chatImage" src="{chat.avatar_image}" alt="аватарка">
|
||
<h2 class="chatName">{chat.chat_name}</h2>
|
||
{#if chat.created_by == userId}
|
||
<button class="deleteChat" on:click={deleteChatButt(chat.chat_id)}>x</button>
|
||
{/if}
|
||
</a>
|
||
</div>
|
||
{/each}
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="jopa">
|
||
|
||
<div class="gradient">
|
||
|
||
{#if msgTimeShow == true}
|
||
<div class="msgTime" transition:fade={{ duration: 100 }}>
|
||
<h3>{msgTime}</h3>
|
||
</div>
|
||
{/if}
|
||
|
||
<div class="chatDiv">
|
||
|
||
<img class="backgroundYtka" src="BPytka.png" alt="">
|
||
|
||
{#if helperDivBoolShow == true}
|
||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||
<div bind:this={helperDiv} id="helperDiv" class="helperDiv" on:contextmenu={(event) => event.preventDefault()}
|
||
transition:slide={{ duration: 500 }}>
|
||
<button on:click={ansFunc} class="helpDiv"><img class="helpImg" src="./icon/answer.png" alt="ans"><p class="ans">Ответить</p></button>
|
||
|
||
{#if pinOrNot == true}
|
||
<button on:click={unpinFunc} class="helpDiv"><img class="helpImg" src="./icon/pin.png" alt="pin"><p class="pin">Открепить</p></button>
|
||
{:else}
|
||
<button on:click={pinFunc} class="helpDiv"><img class="helpImg" src="./icon/pin.png" alt="pin"><p class="pin">Закрепить</p></button>
|
||
{/if}
|
||
|
||
<button on:click={delFunc} class="helpDiv"><img class="helpImg" src="./icon/trash.png" alt="del"><p class="del">Удалить</p></button>
|
||
</div>
|
||
{/if}
|
||
|
||
{#if warningMessage.length != 0}
|
||
<div class="warningMessage">
|
||
<h2 transition:fly={{y:1000, delay:200, duration:500}}>{warningMessage}</h2>
|
||
</div>
|
||
{/if}
|
||
|
||
|
||
{#if ((chatId != null) && (messages.length === 0))}
|
||
<div class="noMsgDiv">
|
||
<h2 class="noMsg1">В этом чате еще нет сообщений.</h2>
|
||
<h3 class="noMsg2">Кто же напишет первый?</h3>
|
||
</div>
|
||
{/if}
|
||
|
||
<div class="msgDiv" bind:this={scrollableDiv} on:scroll={handleScroll}>
|
||
{#each messages as message}
|
||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||
<div class="messageMain" on:contextmenu={helperDivShow(event,message.id, message.message, message.image_url, message.username)}
|
||
on:mouseover={msgTimeFunc(message.created_at)} on:mouseout={msgTimeFuncOver}
|
||
in:fade={{ duration: 600 }}>
|
||
|
||
<img class="messageAvatar" src="{message.avatar_image}" alt="ава">
|
||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||
<div class="messageDiv">
|
||
|
||
<div class="nameAnswerDiv">
|
||
<h3>{message.username}</h3>
|
||
|
||
{#if message.answer_message != null}
|
||
<img class="answerLogo" src="./icon/answerMsg.png" alt="разделитель">
|
||
{#if message.answer_image_url != null}
|
||
<img class="answerImg" src="{message.answer_image_url}" alt="ответная картинка">
|
||
{/if}
|
||
<p>{message.answer_message.substr(0, 20)}</p>
|
||
{/if}
|
||
|
||
</div>
|
||
|
||
<div class="messageMessage">
|
||
<p class="messageMsg">{message.message}</p>
|
||
{#if message.image_url != null}
|
||
<img src="{message.image_url}" alt="пикча" class="messageImage">
|
||
{/if}
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
{/each}
|
||
</div>
|
||
|
||
{#if (chatId != null)}
|
||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||
<div class="inputDiv">
|
||
|
||
{#if (answerMessageTextShow == true) || (answerMessageImgShow == true)}
|
||
<div class="answerMessageDiv" transition:slide={{ duration: 500 }}>
|
||
|
||
{#if answerMessageImgShow == true}
|
||
<img class="answerMessageImg" src="{answerMessageImg}" alt="картинка">
|
||
{/if}
|
||
|
||
<div class="answerTextDiv">
|
||
|
||
{#if answerMessageTextShow == true}
|
||
<div class="answerBlockDiv"><h4 class="answerMessage">{answerMessage.substr(0, 50)}</h4></div>
|
||
{/if}
|
||
<div class="answerBlockDiv"><h4 class="answerMessageName">{PickedName}</h4></div>
|
||
|
||
</div>
|
||
<button on:click={deleteAnswer} class="deleteAnswer">x</button>
|
||
</div>
|
||
{/if}
|
||
|
||
{#if imageShow == true}
|
||
<div class="imageDiv" transition:slide={{ duration: 500 }} >
|
||
<img src="{imageFile}" alt="" class="imageFile" >
|
||
<button on:click={deleteImage} class="imageDelete">x</button>
|
||
</div>
|
||
{/if}
|
||
|
||
<!-- svelte-ignore a11y-autofocus -->
|
||
<div class="textMsg">
|
||
<textarea autofocus placeholder="Введите сообщение" rows="{rows}" bind:value={messageText}
|
||
on:input={onInput} bind:this={inputArea} name="msg" id="msg"></textarea>
|
||
|
||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||
<div class="logoForImageDiv">
|
||
<img class="logoForImage" src="logoForImage.svg" alt=""
|
||
on:click={() => document.getElementById('fileInput').click()}>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<input type="file" accept="image/*" id="fileInput"
|
||
on:change={handleFileChange} style="display: none;">
|
||
|
||
</div>
|
||
{/if}
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="gradient">
|
||
{#if pinnedMsg == null}
|
||
<div class="noMsgDiv">
|
||
<h2 class="noMsg1">Тут ничего нет</h2>
|
||
<h3 class="noMsg2">Но если ты закрепишь сообщение, <br> тут что то изменится</h3>
|
||
</div>
|
||
{:else}
|
||
|
||
<div class="pinnedMain">
|
||
{#each pinnedMsg as msg}
|
||
<div class="pinDiv" transition:fade={{ duration: 500 }}>
|
||
<h3 class="pinName">{msg.username}</h3>
|
||
<div class="pinMsg">
|
||
<h3 class="pinnedMsg">{msg.message}</h3>
|
||
<img src="{msg.image_url}" class="pinImg" alt="">
|
||
</div>
|
||
<div class="pinAvatar"><img class="pinnedImg" src="{msg.avatar_image}" alt=""></div>
|
||
</div>
|
||
{/each}
|
||
</div>
|
||
{/if}
|
||
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div><h1> </h1></div>
|
||
<div><h1> </h1></div>
|
||
<di class="PS">
|
||
<h2>Made by:</h2>
|
||
<h3>Uniknow and urec56</h3>
|
||
</di>
|
||
</div>
|
||
</body>
|
||
|
||
<style lang="scss">
|
||
|
||
.warningMessage{
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
text-align: center;
|
||
height: 100%;
|
||
}
|
||
|
||
.chatName{
|
||
width: 100%;
|
||
}
|
||
|
||
.deleteChat{
|
||
position: absolute;
|
||
top: 20%;
|
||
right: 0;
|
||
transform: translate(-20%,-20%);
|
||
}
|
||
|
||
.messageForZIndex{
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
}
|
||
|
||
.msgTime{
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 15px;
|
||
transform: translate(-50%);
|
||
|
||
background-color: #101010aa;
|
||
padding: 5px;
|
||
border-radius: 10px;
|
||
|
||
z-index: 69;
|
||
pointer-events: none;
|
||
|
||
transition: 0.3s easy;
|
||
}
|
||
|
||
.newChatCheckboxDiv{
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
|
||
overflow: scroll;
|
||
overflow-x: hidden;
|
||
|
||
height: 100%;
|
||
padding-top: 5px;
|
||
|
||
}
|
||
|
||
.newChatAvatar{
|
||
width: 3rem;
|
||
border-radius: 15px;
|
||
}
|
||
|
||
.newChatText{
|
||
padding-top: 15px;
|
||
text-align: center;
|
||
}
|
||
|
||
.nameToFind{
|
||
background-color: var(--background);
|
||
outline: none;
|
||
|
||
border: 0;
|
||
border-bottom: 1px solid white;
|
||
}
|
||
|
||
.radioButton{
|
||
margin-right: 10px;
|
||
accent-color: var(--purple);
|
||
background-color: var(--background);
|
||
|
||
cursor: pointer;
|
||
appearance: none;
|
||
-webkit-appearance: none;
|
||
-moz-appearance: none;
|
||
|
||
width: 20px;
|
||
height: 20px;
|
||
|
||
border: 2px solid ;
|
||
border-radius: 4px;
|
||
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
.radioButton:checked{
|
||
transform: scale(1.2);
|
||
|
||
border-color: #ffffff;
|
||
border: 2px solid white;
|
||
|
||
background-image: var(--gradient);
|
||
background-color: #e0dede;
|
||
}
|
||
|
||
.newChatUser{
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
width: calc(50% - 2px);
|
||
padding-top: 5px;
|
||
padding-left: 2px;
|
||
|
||
}
|
||
|
||
.newChatInputDiv{
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 80%;
|
||
width: 90%;
|
||
}
|
||
|
||
.newChatButtonDiv{
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-around;
|
||
|
||
width: 100%;
|
||
}
|
||
|
||
.newChatName {
|
||
height: 2em;
|
||
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
|
||
border: 1px solid transparent;
|
||
background:
|
||
linear-gradient(#101010, #101010) padding-box,
|
||
var(--gradient) border-box;
|
||
border-radius: 10px;
|
||
|
||
box-shadow:
|
||
4px 4px 15px rgba($color: #5e2a83, $alpha: 0.38),
|
||
-4px -4px 15px rgba($color: #3d53fe, $alpha: 0.38);
|
||
outline: none;
|
||
}
|
||
|
||
.newChatName:focus {
|
||
transition: 0.5s ease-in;
|
||
box-shadow: 0 0 transparent;
|
||
}
|
||
.newChatName:not(:focus) {
|
||
transition: 0.5s ease-in-out;
|
||
box-shadow:
|
||
4px 4px 15px rgba($color: #5e2a83, $alpha: 0.38),
|
||
-4px -4px 15px rgba($color: #3d53fe, $alpha: 0.38);
|
||
}
|
||
|
||
.newChatDiv{
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
|
||
z-index: 727;
|
||
position: absolute;
|
||
top: 50%; left: 50%;
|
||
transform: translate(-50%,-50%);
|
||
|
||
width: 30%;
|
||
aspect-ratio: 10/13.1;
|
||
|
||
border-radius: 15px;
|
||
border: 1px solid transparent;
|
||
background:
|
||
linear-gradient(#101010, #101010) padding-box,
|
||
var(--gradient) border-box;
|
||
}
|
||
|
||
.answerLogo{
|
||
padding: 0 4px;
|
||
}
|
||
|
||
.backgroundYtka{
|
||
z-index: -1;
|
||
position: absolute;
|
||
padding: 15px;
|
||
height: 100%;
|
||
filter: blur(10px);
|
||
}
|
||
|
||
.jopa{
|
||
position: relative;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.pickedChatDiv{
|
||
display: flex;
|
||
flex-direction: row;
|
||
}
|
||
|
||
.pickedChatImg{
|
||
border-radius: 25px;
|
||
height: 75px;
|
||
}
|
||
|
||
.pickedChatName{
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.deleteAnswer{
|
||
padding: 0 15px 0 0;
|
||
}
|
||
|
||
.answerBlockDiv{
|
||
display: flex;
|
||
align-items: center;
|
||
padding-left:5px;
|
||
width: 80%;
|
||
height: 50%;
|
||
}
|
||
|
||
.answerMessage{
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.answerImg{
|
||
opacity: 0.8;
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 10px;
|
||
padding-bottom: 5px;
|
||
padding-right: 5px;
|
||
}
|
||
|
||
.answerTextDiv{
|
||
display: flex;
|
||
flex-direction: column-reverse;
|
||
justify-content: center;
|
||
align-items: center;
|
||
width: 100%;
|
||
}
|
||
|
||
.answerMessageName{
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.answerMessageImg{
|
||
height: 3rem;
|
||
border-radius: 15px;
|
||
}
|
||
|
||
.answerMessageDiv{
|
||
display: flex;
|
||
padding: 5px 0 5px 5px;
|
||
border-bottom: 1px solid rgba($color: #ffffff, $alpha: 0.10727) ;
|
||
}
|
||
|
||
.imageDiv{
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: row;
|
||
padding: 5px;
|
||
|
||
}
|
||
|
||
.imageDelete{
|
||
position: absolute;
|
||
right: 0;
|
||
top: 5px;
|
||
padding: 0 15px 0 0;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.textMsg{
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: center;
|
||
}
|
||
|
||
.imageFile{
|
||
border-radius: 12px;
|
||
height: 250px;
|
||
max-width: 90%;
|
||
}
|
||
|
||
.pinName{
|
||
margin: 0 0 5px 0;
|
||
}
|
||
|
||
.pinMsg{
|
||
width: 80%;
|
||
background-color: #ffffff0a;
|
||
border-radius: 15px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding-bottom: 55px;
|
||
}
|
||
|
||
.pinAvatar{
|
||
margin-top: -30px;
|
||
}
|
||
|
||
.pinImg{
|
||
max-width: 90%;
|
||
height: auto;
|
||
border-radius: 15px;
|
||
}
|
||
|
||
.pinnedImg{
|
||
width: 60px;
|
||
height: auto;
|
||
border-radius: 15px;
|
||
}
|
||
|
||
.pinnedMsg{
|
||
width: 90%;
|
||
margin-bottom: 10px;
|
||
text-align: center;
|
||
|
||
}
|
||
|
||
.pinDiv{
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 10px 0;
|
||
}
|
||
|
||
.pinnedMain{
|
||
display: flex;
|
||
flex-direction: column;
|
||
width: 100%;
|
||
height: 100%;
|
||
margin: 0 10px;
|
||
overflow: auto;
|
||
scroll-behavior: smooth;
|
||
|
||
}
|
||
|
||
.nameAnswerDiv > p{
|
||
opacity: 72.7%;
|
||
}
|
||
|
||
.ans{
|
||
color: #8ed46e;
|
||
}
|
||
.pin{
|
||
color: #ffffff;
|
||
}
|
||
.del{
|
||
color: #D15555 ;
|
||
}
|
||
|
||
.helpDiv > p{
|
||
font-weight: 500;
|
||
}
|
||
|
||
.helpDiv{
|
||
height: 30px;
|
||
|
||
display: flex;
|
||
flex-direction: row;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.helpImg{
|
||
max-width: 100%;
|
||
width: 25px;
|
||
height: 25px;
|
||
margin-right: 5px;
|
||
margin-left: -5px;
|
||
}
|
||
|
||
.helperDiv{
|
||
z-index: 727;
|
||
position: fixed;
|
||
width: 160px;
|
||
height: 90px;
|
||
padding: 5px;
|
||
|
||
transition: opacity 0.3s;
|
||
opacity: 1;
|
||
border-bottom-left-radius: 15px;
|
||
border-bottom-right-radius: 15px;
|
||
border-top-right-radius: 15px;
|
||
border-top-left-radius: 0;
|
||
|
||
border: 1px solid white;
|
||
background:
|
||
linear-gradient(rgba($color: #3C53FF, $alpha: 0.25),rgba($color: #7734AA, $alpha: 0.25));
|
||
backdrop-filter: blur(25px);
|
||
|
||
}
|
||
|
||
.nameAnswerDiv{
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
.chatsDiv{
|
||
display: flex;
|
||
align-items: center;
|
||
flex-direction: column;
|
||
width: calc(100% - 15px);
|
||
height: 100%;
|
||
overflow: scroll;;
|
||
}
|
||
|
||
.aChatDivLeft{
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
|
||
width: 100%;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.createChatDivLeft{
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
|
||
width: 95%;
|
||
height: 45px;
|
||
min-height: 45px;
|
||
|
||
margin-top: 10px;
|
||
font-size: 16px;
|
||
|
||
border-radius: 15px;
|
||
border: 1px solid transparent;
|
||
background:
|
||
linear-gradient(#101010, #101010) padding-box,
|
||
var(--gradient) border-box;
|
||
transition: 0.5s;
|
||
z-index: 1;
|
||
|
||
&:hover{
|
||
z-index: 0;
|
||
box-shadow:
|
||
4px 4px 15px rgba($color: #5e2a83, $alpha: 1.58),
|
||
-4px -4px 15px rgba($color: #3d53fe, $alpha: 1.58);
|
||
|
||
}
|
||
}
|
||
|
||
.chatDivLeftSelected{
|
||
z-index: 0;
|
||
box-shadow:
|
||
4px 4px 15px rgba($color: #5e2a83, $alpha: 1.58),
|
||
-4px -4px 15px rgba($color: #3d53fe, $alpha: 1.58);
|
||
}
|
||
|
||
.chatDivLeft{
|
||
position: relative;
|
||
|
||
display: flex;
|
||
flex-direction: row;
|
||
|
||
width: 95%;
|
||
height: 75px;
|
||
margin-top: 10px;
|
||
|
||
border-radius: 15px;
|
||
border: 1px solid transparent;
|
||
background:
|
||
linear-gradient(#101010, #101010) padding-box,
|
||
var(--gradient) border-box;
|
||
transition: 0.5s;
|
||
z-index: 1;
|
||
|
||
&:hover{
|
||
z-index: 0;
|
||
box-shadow:
|
||
4px 4px 15px rgba($color: #5e2a83, $alpha: 1.58),
|
||
-4px -4px 15px rgba($color: #3d53fe, $alpha: 1.58);
|
||
|
||
}
|
||
}
|
||
|
||
|
||
.chatImage{
|
||
height: 60px;
|
||
width: 60px;
|
||
border-radius: 15px;
|
||
margin: 0 10px;
|
||
padding: 5px 0 5px 0;
|
||
}
|
||
|
||
.logoForImage{
|
||
width: 2rem;
|
||
height: 2rem;
|
||
}
|
||
|
||
.logoForImageDiv{
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: flex-end;
|
||
margin-top: -7px;
|
||
width: 50px;
|
||
height: 100%;
|
||
}
|
||
|
||
.messageImage{
|
||
border-radius: 10px;
|
||
max-width: 500px;
|
||
max-height: 500px;
|
||
}
|
||
|
||
.messageMessage{
|
||
display: flex;
|
||
flex-direction: column;
|
||
max-width: 500px;
|
||
justify-content: space-between;
|
||
background-color: #7734AA;
|
||
border-radius: 15px;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.messageMsg{
|
||
padding: 5px;
|
||
}
|
||
|
||
.messageAvatar{
|
||
width: 60px;
|
||
height: 60px;
|
||
border-radius: 15px;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.messageMain{
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: row;
|
||
padding-top: 10px;
|
||
}
|
||
|
||
.msgDiv{
|
||
display: flex;
|
||
flex-direction: column-reverse;
|
||
height: 100%;
|
||
overflow: auto;
|
||
scroll-behavior: smooth;
|
||
padding: 0 5px;
|
||
}
|
||
|
||
.inputDiv{
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-self: center;
|
||
|
||
border-radius: 15px;
|
||
border: 1px solid transparent;
|
||
background:
|
||
linear-gradient(#101010, #101010) padding-box,
|
||
var(--gradient) border-box;
|
||
|
||
width: 98%;
|
||
margin-top: 3px;
|
||
}
|
||
|
||
#msg{
|
||
width: 100%;
|
||
height: 34px;
|
||
background-color: transparent;
|
||
border: 0;
|
||
line-height: 1em;
|
||
outline: none;
|
||
resize: none;
|
||
padding: 13px 0 0 5px;
|
||
}
|
||
|
||
.chatDiv{
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-content: center;
|
||
align-self: center;
|
||
|
||
width: 100%;
|
||
height: 99%;
|
||
|
||
z-index: 2;
|
||
margin: 0 10px 5px 10px;
|
||
}
|
||
.headerDiv{
|
||
grid-column: span 3;
|
||
z-index: 3;
|
||
}
|
||
|
||
.gradient{
|
||
z-index: 1;
|
||
border: 1px solid transparent;
|
||
background:
|
||
linear-gradient(#101010, #101010) padding-box,
|
||
var(--gradient) border-box;
|
||
border-radius: 15px;
|
||
border-bottom: 0;
|
||
|
||
width: 95%;
|
||
height: 95%;
|
||
|
||
display: flex;
|
||
align-self: center;
|
||
justify-content: center;
|
||
|
||
margin: auto;
|
||
position: relative;
|
||
}
|
||
|
||
.gradient::before{
|
||
content: '';
|
||
position: absolute;
|
||
background-image: url('./noise.png');
|
||
background-repeat: repeat;
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 15px;
|
||
opacity: 0.01;
|
||
pointer-events: none;
|
||
}
|
||
|
||
body{
|
||
position: relative;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
.grid{
|
||
display: grid;
|
||
grid-template-columns: 30% 40% 30%;
|
||
grid-template-rows: 10% 90% 10%;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
.grid > *{
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.noMsgDiv{
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
text-align: center;
|
||
|
||
height: 100%;
|
||
}
|
||
.noMsgDiv > h2{
|
||
padding-bottom: 10px;
|
||
}
|
||
|
||
.PS{
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
</style>
|