FEATURE: migrated the chat window to svelte
This commit is contained in:
parent
e5f7c62e25
commit
3cfbcc6b02
24 changed files with 470 additions and 305 deletions
97
front/src/Components/Chat/Chat.svelte
Normal file
97
front/src/Components/Chat/Chat.svelte
Normal file
|
@ -0,0 +1,97 @@
|
|||
<script lang="ts">
|
||||
import { fly } from 'svelte/transition';
|
||||
import {chatMessagesStore, chatVisibilityStore} from "../../Stores/ChatStore";
|
||||
import ChatMessageForm from './ChatMessageForm.svelte';
|
||||
import ChatElement from './ChatElement.svelte';
|
||||
import {onMount} from "svelte";
|
||||
|
||||
let listDom: HTMLElement;
|
||||
|
||||
onMount(() => {
|
||||
listDom.addEventListener('onscroll', function(e: Event) {
|
||||
console.log(e);
|
||||
// Active list item is top-most fully-visible item
|
||||
//const visibleListItems = Array.from(document.getElementsByClassName('list-item')).map(inView.is);
|
||||
// Array.indexOf() will give us the first one in list, so the current active item
|
||||
//const topMostVisible = visibleListItems.indexOf(true);
|
||||
});
|
||||
})
|
||||
|
||||
function closeChat() {
|
||||
chatVisibilityStore.set(false);
|
||||
}
|
||||
function onKeyDown(e:KeyboardEvent) {
|
||||
if (e.key === 'Escape') {
|
||||
closeChat();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown}/>
|
||||
|
||||
|
||||
<aside class="chatWindow" transition:fly="{{ x: -1000, duration: 500 }}">
|
||||
<section class="chatWindowTitle">
|
||||
<h3>Here is your chat history <button on:click={closeChat}>❌</button></h3>
|
||||
|
||||
</section>
|
||||
<section class="messagesList">
|
||||
<ul bind:this={listDom}>
|
||||
{#each $chatMessagesStore as message}
|
||||
<li><ChatElement message={message}></ChatElement></li>
|
||||
{/each}
|
||||
</ul>
|
||||
</section>
|
||||
<section class="messageForm">
|
||||
<ChatMessageForm></ChatMessageForm>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
<style lang="scss">
|
||||
h3 {
|
||||
font-family: 'Whiteney';
|
||||
}
|
||||
aside.chatWindow {
|
||||
z-index:100;
|
||||
pointer-events: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
width:30vw;
|
||||
min-width: 350px;
|
||||
background: #051f33;
|
||||
color: whitesmoke;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
padding: 10px;
|
||||
|
||||
border-bottom-right-radius: 16px;
|
||||
border-top-right-radius: 16px;
|
||||
|
||||
h3 {
|
||||
background-color: #5f5f5f;
|
||||
border-radius: 8px;
|
||||
padding: 2px;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.chatWindowTitle {
|
||||
flex: 0 100px;
|
||||
}
|
||||
.messagesList {
|
||||
overflow-y: auto;
|
||||
flex: auto;
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
.messageForm {
|
||||
flex: 0 70px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
74
front/src/Components/Chat/ChatElement.svelte
Normal file
74
front/src/Components/Chat/ChatElement.svelte
Normal file
|
@ -0,0 +1,74 @@
|
|||
<script lang="ts">
|
||||
import {ChatMessageTypes} from "../../Stores/ChatStore";
|
||||
import type {ChatMessage} from "../../Stores/ChatStore";
|
||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
||||
import ChatPlayerName from './ChatPlayerName.svelte';
|
||||
import type {PlayerInterface} from "../../Phaser/Game/PlayerInterface";
|
||||
|
||||
export let message: ChatMessage;
|
||||
|
||||
$: author = message.author as PlayerInterface;
|
||||
$: targets = message.targets || [];
|
||||
$: texts = message.text || [];
|
||||
|
||||
function urlifyText(text: string): string {
|
||||
return HtmlUtils.urlify(text)
|
||||
}
|
||||
function renderDate(date: Date) {
|
||||
return date.toLocaleTimeString(navigator.language, {
|
||||
hour: '2-digit',
|
||||
minute:'2-digit'
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="chatElement">
|
||||
<div class="messagePart">
|
||||
{#if message.type === ChatMessageTypes.userIncoming}
|
||||
➡️: {#each targets as target}<ChatPlayerName player={target}></ChatPlayerName>{/each} ({renderDate(message.date)})
|
||||
{:else if message.type === ChatMessageTypes.userOutcoming}
|
||||
⬅️: {#each targets as target}<ChatPlayerName player={target}></ChatPlayerName>{/each} ({renderDate(message.date)})
|
||||
{:else if message.type === ChatMessageTypes.me}
|
||||
<h4>Me: ({renderDate(message.date)})</h4>
|
||||
{#each texts as text}
|
||||
<div><p class="my-text">{@html urlifyText(text)}</p></div>
|
||||
{/each}
|
||||
{:else}
|
||||
<h4><ChatPlayerName player={author}></ChatPlayerName>: ({renderDate(message.date)})</h4>
|
||||
{#each texts as text}
|
||||
<div><p class="other-text">{@html urlifyText(text)}</p></div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
h4, p {
|
||||
font-family: 'Whiteney';
|
||||
}
|
||||
div.chatElement {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.messagePart {
|
||||
flex-grow:1;
|
||||
max-width: 100%;
|
||||
|
||||
div > p {
|
||||
border-radius: 8px;
|
||||
margin-bottom: 10px;
|
||||
padding:6px;
|
||||
overflow-wrap: break-word;
|
||||
max-width: 100%;
|
||||
display: inline-block;
|
||||
&.other-text {
|
||||
background: gray;
|
||||
}
|
||||
|
||||
&.my-text {
|
||||
background: #6489ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
55
front/src/Components/Chat/ChatMessageForm.svelte
Normal file
55
front/src/Components/Chat/ChatMessageForm.svelte
Normal file
|
@ -0,0 +1,55 @@
|
|||
<script lang="ts">
|
||||
import {chatMessagesStore, chatInputFocusStore} from "../../Stores/ChatStore";
|
||||
|
||||
let newMessageText = '';
|
||||
|
||||
function onFocus() {
|
||||
chatInputFocusStore.set(true);
|
||||
}
|
||||
function onBlur() {
|
||||
chatInputFocusStore.set(false);
|
||||
}
|
||||
|
||||
function saveMessage() {
|
||||
if (!newMessageText) return;
|
||||
chatMessagesStore.addPersonnalMessage(newMessageText);
|
||||
newMessageText = '';
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault={saveMessage}>
|
||||
<input type="text" bind:value={newMessageText} placeholder="Type here" on:focus={onFocus} on:blur={onBlur} >
|
||||
<button type="submit">
|
||||
<img src="/static/images/send.png" alt="Send" width="20">
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<style lang="scss">
|
||||
form {
|
||||
display: flex;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
|
||||
input {
|
||||
flex: auto;
|
||||
background-color: #42464d;
|
||||
color: white;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
border: none;
|
||||
font-size: 22px;
|
||||
font-family: Whiteney;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #42464d;
|
||||
color: white;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
border: none;
|
||||
border-left: solid black 1px;
|
||||
font-size: 16px;
|
||||
font-family: Whiteney;
|
||||
}
|
||||
}
|
||||
</style>
|
37
front/src/Components/Chat/ChatPlayerName.svelte
Normal file
37
front/src/Components/Chat/ChatPlayerName.svelte
Normal file
|
@ -0,0 +1,37 @@
|
|||
<script lang="ts">
|
||||
import type {PlayerInterface} from "../../Phaser/Game/PlayerInterface";
|
||||
import {requestVisitCardsStore} from "../../Stores/GameStore";
|
||||
|
||||
export let player:PlayerInterface;
|
||||
let showMenu: boolean = false;
|
||||
|
||||
function openVisitCard() {
|
||||
if (player.visitCardUrl) {
|
||||
requestVisitCardsStore.set(player.visitCardUrl);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<span class="chatPlayerName" style="color: {player.color || 'white'}" on:click={() => showMenu = !showMenu}>
|
||||
{player.name}
|
||||
</span>
|
||||
|
||||
{#if showMenu}
|
||||
<ul class="selectMenu">
|
||||
<li><button class="text-btn" disabled={!player.visitCardUrl} on:click={openVisitCard}>Visit card</button></li>
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
.chatPlayerName:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
ul.selectMenu {
|
||||
background-color: whitesmoke;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
Loading…
Add table
Add a link
Reference in a new issue