Merge branch 'develop' of github.com:thecodingmachine/workadventure
This commit is contained in:
@@ -1,23 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { fly } from 'svelte/transition';
|
||||
import { fly } from "svelte/transition";
|
||||
import { chatMessagesStore, chatVisibilityStore } from "../../Stores/ChatStore";
|
||||
import ChatMessageForm from './ChatMessageForm.svelte';
|
||||
import ChatElement from './ChatElement.svelte';
|
||||
import {afterUpdate, beforeUpdate, onMount} from "svelte";
|
||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
||||
|
||||
import ChatMessageForm from "./ChatMessageForm.svelte";
|
||||
import ChatElement from "./ChatElement.svelte";
|
||||
import { afterUpdate, beforeUpdate, onMount } from "svelte";
|
||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||
|
||||
let listDom: HTMLElement;
|
||||
let chatWindowElement: HTMLElement;
|
||||
let handleFormBlur: { blur():void };
|
||||
let handleFormBlur: { blur(): void };
|
||||
let autoscroll: boolean;
|
||||
|
||||
beforeUpdate(() => {
|
||||
autoscroll = listDom && (listDom.offsetHeight + listDom.scrollTop) > (listDom.scrollHeight - 20);
|
||||
autoscroll = listDom && listDom.offsetHeight + listDom.scrollTop > listDom.scrollHeight - 20;
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
listDom.scrollTo(0, listDom.scrollHeight);
|
||||
})
|
||||
});
|
||||
|
||||
afterUpdate(() => {
|
||||
if (autoscroll) listDom.scrollTo(0, listDom.scrollHeight);
|
||||
@@ -32,78 +32,81 @@
|
||||
function closeChat() {
|
||||
chatVisibilityStore.set(false);
|
||||
}
|
||||
function onKeyDown(e:KeyboardEvent) {
|
||||
if (e.key === 'Escape') {
|
||||
function onKeyDown(e: KeyboardEvent) {
|
||||
if (e.key === "Escape") {
|
||||
closeChat();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} on:click={onClick}/>
|
||||
<svelte:window on:keydown={onKeyDown} on:click={onClick} />
|
||||
|
||||
|
||||
<aside class="chatWindow nes-container is-rounded is-dark" transition:fly="{{ x: -1000, duration: 500 }}" bind:this={chatWindowElement}>
|
||||
<aside class="chatWindow nes-container is-rounded is-dark" transition:fly={{ x: -1000, duration: 500 }}
|
||||
bind:this={chatWindowElement}>
|
||||
<p class="close-icon" on:click={closeChat}>×</p>
|
||||
<section class="messagesList" bind:this={listDom}>
|
||||
<ul>
|
||||
<li><p class="system-text">Here is your chat history: </p></li>
|
||||
{#each $chatMessagesStore as message, i}
|
||||
<li><ChatElement message={message} line={i}></ChatElement></li>
|
||||
{/each}
|
||||
<li><p class="system-text">Here is your chat history:</p></li>
|
||||
{#each $chatMessagesStore as message, i}
|
||||
<li><ChatElement {message} line={i} /></li>
|
||||
{/each}
|
||||
</ul>
|
||||
</section>
|
||||
<section class="messageForm">
|
||||
<ChatMessageForm bind:handleForm={handleFormBlur}></ChatMessageForm>
|
||||
<ChatMessageForm bind:handleForm={handleFormBlur} />
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
<style lang="scss">
|
||||
p.close-icon {
|
||||
position: absolute;
|
||||
padding: 4px;
|
||||
right: 12px;
|
||||
font-size: 30px;
|
||||
line-height: 25px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
padding: 4px;
|
||||
right: 12px;
|
||||
font-size: 30px;
|
||||
line-height: 25px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
p.system-text {
|
||||
border-radius: 8px;
|
||||
margin-bottom: 10px;
|
||||
padding:6px;
|
||||
overflow-wrap: break-word;
|
||||
max-width: 100%;
|
||||
display: inline-block;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 10px;
|
||||
padding: 6px;
|
||||
overflow-wrap: break-word;
|
||||
max-width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
aside.chatWindow {
|
||||
z-index:100;
|
||||
pointer-events: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
width:30vw;
|
||||
min-width: 350px;
|
||||
color: whitesmoke;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
|
||||
.messagesList {
|
||||
margin-top: 35px;
|
||||
overflow-y: auto;
|
||||
flex: auto;
|
||||
z-index: 100;
|
||||
pointer-events: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
width: 30vw;
|
||||
min-width: 350px;
|
||||
color: whitesmoke;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
margin: 0;
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
border-bottom-right-radius: 16px;
|
||||
border-top-right-radius: 16px;
|
||||
|
||||
.messagesList {
|
||||
margin-top: 35px;
|
||||
overflow-y: auto;
|
||||
flex: auto;
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
.messageForm {
|
||||
flex: 0 70px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
}
|
||||
.messageForm {
|
||||
flex: 0 70px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,47 +1,55 @@
|
||||
<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";
|
||||
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;
|
||||
export let line: number;
|
||||
const chatStyleLink = "color: white; text-decoration: underline;";
|
||||
|
||||
|
||||
$: author = message.author as PlayerInterface;
|
||||
$: targets = message.targets || [];
|
||||
$: texts = message.text || [];
|
||||
|
||||
|
||||
function urlifyText(text: string): string {
|
||||
return HtmlUtils.urlify(text, chatStyleLink);
|
||||
}
|
||||
function renderDate(date: Date) {
|
||||
return date.toLocaleTimeString(navigator.language, {
|
||||
hour: '2-digit',
|
||||
minute:'2-digit'
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
}
|
||||
function isLastIteration(index: number) {
|
||||
return targets.length -1 === index;
|
||||
return targets.length - 1 === index;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="chatElement">
|
||||
<div class="messagePart">
|
||||
{#if message.type === ChatMessageTypes.userIncoming}
|
||||
>> {#each targets as target, index}<ChatPlayerName player={target} line={line}></ChatPlayerName>{#if !isLastIteration(index)}, {/if}{/each} entered <span class="date">({renderDate(message.date)})</span>
|
||||
>> {#each targets as target, index}<ChatPlayerName
|
||||
player={target}
|
||||
{line}
|
||||
/>{#if !isLastIteration(index)}, {/if}{/each} entered
|
||||
<span class="date">({renderDate(message.date)})</span>
|
||||
{:else if message.type === ChatMessageTypes.userOutcoming}
|
||||
<< {#each targets as target, index}<ChatPlayerName player={target} line={line}></ChatPlayerName>{#if !isLastIteration(index)}, {/if}{/each} left <span class="date">({renderDate(message.date)})</span>
|
||||
<< {#each targets as target, index}<ChatPlayerName
|
||||
player={target}
|
||||
{line}
|
||||
/>{#if !isLastIteration(index)}, {/if}{/each} left
|
||||
<span class="date">({renderDate(message.date)})</span>
|
||||
{:else if message.type === ChatMessageTypes.me}
|
||||
<h4>Me: <span class="date">({renderDate(message.date)})</span></h4>
|
||||
{#each texts as text}
|
||||
<div><p class="my-text nes-balloon from-left is-dark">{@html urlifyText(text)}</p></div>
|
||||
<div><p class="my-text">{@html urlifyText(text)}</p></div>
|
||||
{/each}
|
||||
{:else}
|
||||
<h4><ChatPlayerName player={author} line={line}></ChatPlayerName>: <span class="date">({renderDate(message.date)})</span></h4>
|
||||
<h4><ChatPlayerName player={author} {line} />: <span class="date">({renderDate(message.date)})</span></h4>
|
||||
{#each texts as text}
|
||||
<div><p class="other-text nes-balloon from-right is-dark">{@html urlifyText(text)}</p></div>
|
||||
<div><p class="other-text">{@html urlifyText(text)}</p></div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
@@ -49,29 +57,33 @@
|
||||
|
||||
<style lang="scss">
|
||||
div.chatElement {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.messagePart {
|
||||
flex-grow:1;
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
|
||||
span.date {
|
||||
font-size: 80%;
|
||||
color: gray;
|
||||
.messagePart {
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
|
||||
span.date {
|
||||
font-size: 80%;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
div > p {
|
||||
border-radius: 8px;
|
||||
margin-bottom: 10px;
|
||||
padding: 6px;
|
||||
overflow-wrap: break-word;
|
||||
max-width: 100%;
|
||||
display: inline-block;
|
||||
&.other-text {
|
||||
background: gray;
|
||||
}
|
||||
|
||||
&.other-text {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div > p {
|
||||
overflow-wrap: break-word;
|
||||
max-width: 100%;
|
||||
display: inline-block;
|
||||
min-width: 75px;
|
||||
padding: 5px;
|
||||
|
||||
&.other-text {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<script lang="ts">
|
||||
import {chatMessagesStore, chatInputFocusStore} from "../../Stores/ChatStore";
|
||||
import { chatMessagesStore, chatInputFocusStore } from "../../Stores/ChatStore";
|
||||
|
||||
export const handleForm = {
|
||||
blur() {
|
||||
inputElement.blur();
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
let inputElement: HTMLElement;
|
||||
let newMessageText = '';
|
||||
|
||||
let newMessageText = "";
|
||||
|
||||
function onFocus() {
|
||||
chatInputFocusStore.set(true);
|
||||
}
|
||||
@@ -19,14 +19,14 @@
|
||||
function saveMessage() {
|
||||
if (!newMessageText) return;
|
||||
chatMessagesStore.addPersonnalMessage(newMessageText);
|
||||
newMessageText = '';
|
||||
newMessageText = "";
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault={saveMessage}>
|
||||
<input class="nes-input is-dark" type="text" bind:value={newMessageText} placeholder="Enter your message..." on:focus={onFocus} on:blur={onBlur} bind:this={inputElement}>
|
||||
<button class="nes-btn" type="submit">
|
||||
<img src="/static/images/send.png" alt="Send" width="20">
|
||||
<img src="/static/images/send.png" alt="Send" width="20" />
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -36,4 +36,4 @@
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type {PlayerInterface} from "../../Phaser/Game/PlayerInterface";
|
||||
import {chatSubMenuVisibilityStore} from "../../Stores/ChatStore";
|
||||
import {onDestroy, onMount} from "svelte";
|
||||
import type {Unsubscriber} from "svelte/store";
|
||||
import type { PlayerInterface } from "../../Phaser/Game/PlayerInterface";
|
||||
import { chatSubMenuVisibilityStore } from "../../Stores/ChatStore";
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import type { Unsubscriber } from "svelte/store";
|
||||
import ChatSubMenu from "./ChatSubMenu.svelte";
|
||||
|
||||
export let player: PlayerInterface;
|
||||
@@ -17,35 +17,33 @@
|
||||
|
||||
onMount(() => {
|
||||
chatSubMenuVisivilytUnsubcribe = chatSubMenuVisibilityStore.subscribe((newValue) => {
|
||||
isSubMenuOpen = (newValue === player.name + line);
|
||||
})
|
||||
})
|
||||
isSubMenuOpen = newValue === player.name + line;
|
||||
});
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
chatSubMenuVisivilytUnsubcribe();
|
||||
})
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<span class="subMenu">
|
||||
<span class="chatPlayerName" style="color: {player.color || 'white'}" on:click={openSubMenu}>
|
||||
{player.name}
|
||||
{player.name}
|
||||
</span>
|
||||
{#if isSubMenuOpen}
|
||||
<ChatSubMenu player={player}/>
|
||||
<ChatSubMenu {player} />
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
span.subMenu {
|
||||
display: inline-block;
|
||||
}
|
||||
span.chatPlayerName {
|
||||
margin-left: 3px;
|
||||
}
|
||||
.chatPlayerName:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
span.subMenu {
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
span.chatPlayerName {
|
||||
margin-left: 3px;
|
||||
}
|
||||
.chatPlayerName:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<script lang="ts">
|
||||
import type {PlayerInterface} from "../../Phaser/Game/PlayerInterface";
|
||||
import {requestVisitCardsStore} from "../../Stores/GameStore";
|
||||
import type { PlayerInterface } from "../../Phaser/Game/PlayerInterface";
|
||||
import { requestVisitCardsStore } from "../../Stores/GameStore";
|
||||
|
||||
export let player: PlayerInterface;
|
||||
|
||||
|
||||
function openVisitCard() {
|
||||
if (player.visitCardUrl) {
|
||||
requestVisitCardsStore.set(player.visitCardUrl);
|
||||
@@ -17,17 +16,16 @@
|
||||
<li><button class="text-btn" disabled>Add friend</button></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
ul.selectMenu {
|
||||
background-color: whitesmoke;
|
||||
position: absolute;
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
list-style-type: none;
|
||||
ul.selectMenu {
|
||||
background-color: whitesmoke;
|
||||
position: absolute;
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
text-align: center;
|
||||
li {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user