Merge branch 'develop' of github.com:thecodingmachine/workadventure
This commit is contained in:
commit
e806325da9
1
front/dist/index.tmpl.html
vendored
1
front/dist/index.tmpl.html
vendored
@ -32,7 +32,6 @@
|
|||||||
<title>Partey</title>
|
<title>Partey</title>
|
||||||
</head>
|
</head>
|
||||||
<body id="body" style="margin: 0; background-color: #000">
|
<body id="body" style="margin: 0; background-color: #000">
|
||||||
|
|
||||||
<div class="main-container" id="main-container">
|
<div class="main-container" id="main-container">
|
||||||
<!-- Create the editor container -->
|
<!-- Create the editor container -->
|
||||||
<div id="game" class="game">
|
<div id="game" class="game">
|
||||||
|
64
front/dist/resources/html/gameMenu.html
vendored
64
front/dist/resources/html/gameMenu.html
vendored
@ -1,64 +0,0 @@
|
|||||||
<style>
|
|
||||||
#gameMenu main{
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
#gameMenu section {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
section#socialLinks{
|
|
||||||
position: absolute;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
section#socialLinks img{
|
|
||||||
width: 32px;
|
|
||||||
cursor: url('/resources/logos/cursor_pointer.png'), pointer;
|
|
||||||
}
|
|
||||||
@media only screen and (max-height: 700px) {
|
|
||||||
#gameMenu main {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: flex-end;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
#gameMenu section{
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
section#socialLinks{
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div id="gameMenu" hidden>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<section>
|
|
||||||
<button id="shareButton" class="nes-btn">Share url</button>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<button id="changeSkinButton" class="nes-btn">Edit skin</button>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<button id="changeCompanionButton" class="nes-btn">Edit companion</button>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<button id="editGameSettingsButton" class="nes-btn">Settings</button>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<button id="toggleFullscreen" class="nes-btn">Toggle fullscreen</button>
|
|
||||||
</section>
|
|
||||||
<!-- TODO activate authentication -->
|
|
||||||
<section hidden>
|
|
||||||
<button id="oidcLogin" class="nes-btn">we.bstly Login</button>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<button id="enableNotification" class="nes-btn">Enable notifications</button>
|
|
||||||
</section>
|
|
||||||
<section id="adminConsoleSection" hidden>
|
|
||||||
<button id="adminConsoleButton" class="nes-btn">Admin console</button>
|
|
||||||
</section>
|
|
||||||
<section id="socialLinks" hidden>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
21
front/dist/resources/html/gameMenuIcon.html
vendored
21
front/dist/resources/html/gameMenuIcon.html
vendored
@ -1,21 +0,0 @@
|
|||||||
<style>
|
|
||||||
#menuIcon button img{
|
|
||||||
width: 8px;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
#menuIcon section {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
@media only screen and (max-height: 700px) {
|
|
||||||
#menuIcon section {
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<main id="menuIcon" hidden>
|
|
||||||
<section>
|
|
||||||
<button id="openMenuButton" class="nes-btn is-dark">
|
|
||||||
<img src="/static/images/menu.svg">
|
|
||||||
</button>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
62
front/dist/resources/html/gameQualityMenu.html
vendored
62
front/dist/resources/html/gameQualityMenu.html
vendored
@ -1,62 +0,0 @@
|
|||||||
<style>
|
|
||||||
#gameQuality {
|
|
||||||
background: #eceeee;
|
|
||||||
border: 1px solid #42464b;
|
|
||||||
border-radius: 6px;
|
|
||||||
margin: 20px auto 0;
|
|
||||||
width: 50vw;
|
|
||||||
max-width: 300px;
|
|
||||||
}
|
|
||||||
#gameQuality .cautiousText {
|
|
||||||
font-size: 50%;
|
|
||||||
}
|
|
||||||
#gameQuality h1 {
|
|
||||||
background-image: linear-gradient(top, #f1f3f3, #d4dae0);
|
|
||||||
border-bottom: 1px solid #a6abaf;
|
|
||||||
border-radius: 6px 6px 0 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: #727678;
|
|
||||||
display: block;
|
|
||||||
height: 43px;
|
|
||||||
padding-top: 10px;
|
|
||||||
margin: 0;
|
|
||||||
text-align: center;
|
|
||||||
text-shadow: 0 -1px 0 rgba(0,0,0,0.2), 0 1px 0 #fff;
|
|
||||||
}
|
|
||||||
#gameQuality section {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
#gameQuality section.action{
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<form id="gameQuality" hidden>
|
|
||||||
<section>
|
|
||||||
<h5>Game quality</h3>
|
|
||||||
<p class="cautiousText">(Editing these settings will restart the game)</p>
|
|
||||||
<div class="nes-select">
|
|
||||||
<select id="select-game-quality">
|
|
||||||
<option value="120">High video quality (120 fps)</option>
|
|
||||||
<option value="60">Medium video quality (60 fps, recommended)</option>
|
|
||||||
<option value="40">Minimum video quality (40 fps)</option>
|
|
||||||
<option value="20">Small video quality (20 fps)</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h5>Video quality</h3>
|
|
||||||
<div class="nes-select">
|
|
||||||
<select id="select-video-quality">
|
|
||||||
<option value="30">High video quality (30 fps)</option>
|
|
||||||
<option value="20">Medium video quality (20 fps, recommended)</option>
|
|
||||||
<option value="10">Minimum video quality (10 fps)</option>
|
|
||||||
<option value="5">Small video quality (5 fps)</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="action">
|
|
||||||
<button type="submit" class="nes-btn" id="gameQualityFormSubmit" >Save</button>
|
|
||||||
<button type="reset" class="close nes-btn is-error" id="gameQualityFormCancel">Cancel</button>
|
|
||||||
</section>
|
|
||||||
</form>
|
|
103
front/dist/resources/html/gameReport.html
vendored
103
front/dist/resources/html/gameReport.html
vendored
@ -1,103 +0,0 @@
|
|||||||
<style>
|
|
||||||
#gameReport {
|
|
||||||
margin: 2px auto 0;
|
|
||||||
width: 298px;
|
|
||||||
}
|
|
||||||
#gameReport h1 {
|
|
||||||
border-bottom: 1px solid #a6abaf;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: block;
|
|
||||||
height: 43px;
|
|
||||||
padding-top: 10px;
|
|
||||||
margin: 0;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
#gameReport h3 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
#gameReport textarea {
|
|
||||||
font-size: 70%;
|
|
||||||
background: linear-gradient(top, #d6d7d7, #dee0e0);
|
|
||||||
border: 1px solid #a1a3a3;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 1px #fff;
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: #696969;
|
|
||||||
height: 100px;
|
|
||||||
transition: box-shadow 0.3s;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
#gameReport section {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
#gameReport section.action{
|
|
||||||
text-align: center;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
#gameReport button {
|
|
||||||
margin-top: 10px;
|
|
||||||
font-size: 60%;
|
|
||||||
padding: 3px 10px 3px 10px;
|
|
||||||
}
|
|
||||||
#gameReport button#gameReportFormCancel {
|
|
||||||
display: block;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
#gameReport section a{
|
|
||||||
text-align: center;
|
|
||||||
font-size: 12px;
|
|
||||||
margin: 0 6px;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
#gameReport section h6,
|
|
||||||
#gameReport section h5{
|
|
||||||
margin: 1px;
|
|
||||||
}
|
|
||||||
#gameReport section.text-center{
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
#gameReport p{
|
|
||||||
font-size: 8px;
|
|
||||||
margin: 3px 0 0 0;
|
|
||||||
}
|
|
||||||
#gameReport form p{
|
|
||||||
margin: 0px 70px;
|
|
||||||
}
|
|
||||||
#gameReport section p.err{
|
|
||||||
color: red;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#gameReport section p.info{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<main id="gameReport" class="nes-container is-dark" hidden>
|
|
||||||
<section>
|
|
||||||
<button id="gameReportFormCancel" class="nes-btn is-dark">X</button>
|
|
||||||
<h1>Moderate <span id="nameReported"></span></h1>
|
|
||||||
<p id="askActionP">What action do you want to take?</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h3>Block: </h3>
|
|
||||||
<p>Block any communication from and to this user. This can be reverted.</p>
|
|
||||||
<section class="action">
|
|
||||||
<button id="toggleBlockButton" class="nes-btn is-error">Block this user</button>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
<section id="reportSection" hidden>
|
|
||||||
<h3>Report: </h3>
|
|
||||||
<p>Send a report message to the administrators of this room. They may later ban this user.</p>
|
|
||||||
<form>
|
|
||||||
<section>
|
|
||||||
<h6>Your message: </h6>
|
|
||||||
<textarea type="text" name="report" id="gameReportInput"></textarea>
|
|
||||||
<p class="err" id="gameReportErr"></p>
|
|
||||||
</section>
|
|
||||||
<section class="action">
|
|
||||||
<button type="submit" id="gameReportFormSubmit" class="nes-btn is-error">Report this user</button>
|
|
||||||
</section>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
|
|
96
front/dist/resources/html/gameShare.html
vendored
96
front/dist/resources/html/gameShare.html
vendored
@ -1,96 +0,0 @@
|
|||||||
<style>
|
|
||||||
#gameShare {
|
|
||||||
background: #eceeee;
|
|
||||||
border: 1px solid #42464b;
|
|
||||||
border-radius: 6px;
|
|
||||||
margin: 20px auto 0;
|
|
||||||
width: 50vw;
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
#gameShare h1 {
|
|
||||||
background-image: linear-gradient(top, #f1f3f3, #d4dae0);
|
|
||||||
border-bottom: 1px solid #a6abaf;
|
|
||||||
border-radius: 6px 6px 0 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: #727678;
|
|
||||||
display: block;
|
|
||||||
height: 43px;
|
|
||||||
padding-top: 10px;
|
|
||||||
margin: 0;
|
|
||||||
text-align: center;
|
|
||||||
text-shadow: 0 -1px 0 rgba(0,0,0,0.2), 0 1px 0 #fff;
|
|
||||||
}
|
|
||||||
#gameShare input {
|
|
||||||
font-size: 70%;
|
|
||||||
background: linear-gradient(top, #d6d7d7, #dee0e0);
|
|
||||||
border: 1px solid #a1a3a3;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 1px #fff;
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: #696969;
|
|
||||||
height: 30px;
|
|
||||||
transition: box-shadow 0.3s;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
#gameShare section {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
#gameShare section.action{
|
|
||||||
text-align: center;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
#gameShare button {
|
|
||||||
margin: 10px;
|
|
||||||
background-color: black;
|
|
||||||
color: white;
|
|
||||||
border-radius: 7px;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
width: 60px;
|
|
||||||
}
|
|
||||||
#gameShare button#gameShareFormCancel {
|
|
||||||
background-color: #c7c7c700;
|
|
||||||
color: #292929;
|
|
||||||
}
|
|
||||||
#gameShare section a{
|
|
||||||
text-align: center;
|
|
||||||
font-size: 12px;
|
|
||||||
margin: 0 6px;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
#gameShare section h6,
|
|
||||||
#gameShare section h5{
|
|
||||||
margin: 1px;
|
|
||||||
}
|
|
||||||
#gameShare section.text-center{
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
#gameShare section p{
|
|
||||||
font-size: 8px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
#gameShare section p.err{
|
|
||||||
color: red;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#gameShare section p.info{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#gameShare section input#gameShareLink{
|
|
||||||
background-color: #a1a3a3;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<form id="gameShare" hidden>
|
|
||||||
<section class="text-center">
|
|
||||||
<h5>Share this link !</h5>
|
|
||||||
<p class="info" id="gameShareInfo"></p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h6>Link</h6>
|
|
||||||
<input type="text" name="email" id="gameShareLink" readonly>
|
|
||||||
</section>
|
|
||||||
<section class="action">
|
|
||||||
<button type="submit" id="gameShareFormSubmit">Copy</button>
|
|
||||||
<button type="submit" id="gameShareFormCancel">Close</button>
|
|
||||||
</section>
|
|
||||||
</form>
|
|
BIN
front/dist/resources/logos/tcm_full.png
vendored
Normal file
BIN
front/dist/resources/logos/tcm_full.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 300 B |
BIN
front/dist/resources/logos/tcm_short.png
vendored
Normal file
BIN
front/dist/resources/logos/tcm_short.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 216 B |
@ -1,5 +1,6 @@
|
|||||||
import * as tg from "generic-type-guard";
|
import * as tg from "generic-type-guard";
|
||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
|
import { subMenusStore } from "../../../Stores/MenuStore";
|
||||||
|
|
||||||
export const isMenuItemRegisterEvent = new tg.IsInterface()
|
export const isMenuItemRegisterEvent = new tg.IsInterface()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
@ -18,9 +19,6 @@ export const isMenuItemRegisterIframeEvent = new tg.IsInterface()
|
|||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
const _registerMenuCommandStream: Subject<string> = new Subject();
|
|
||||||
export const registerMenuCommandStream = _registerMenuCommandStream.asObservable();
|
|
||||||
|
|
||||||
export function handleMenuItemRegistrationEvent(event: MenuItemRegisterEvent) {
|
export function handleMenuItemRegistrationEvent(event: MenuItemRegisterEvent) {
|
||||||
_registerMenuCommandStream.next(event.menutItem);
|
subMenusStore.addMenu(event.menutItem);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
|
|||||||
import type { SetVariableEvent } from "./Events/SetVariableEvent";
|
import type { SetVariableEvent } from "./Events/SetVariableEvent";
|
||||||
import { ModifyEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent";
|
import { ModifyEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent";
|
||||||
import { EmbeddedWebsite } from "./iframe/Room/EmbeddedWebsite";
|
import { EmbeddedWebsite } from "./iframe/Room/EmbeddedWebsite";
|
||||||
|
import { subMenusStore } from "../Stores/MenuStore";
|
||||||
|
|
||||||
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
||||||
query: IframeQueryMap[T]["query"],
|
query: IframeQueryMap[T]["query"],
|
||||||
@ -96,12 +97,6 @@ class IframeListener {
|
|||||||
private readonly _setPropertyStream: Subject<SetPropertyEvent> = new Subject();
|
private readonly _setPropertyStream: Subject<SetPropertyEvent> = new Subject();
|
||||||
public readonly setPropertyStream = this._setPropertyStream.asObservable();
|
public readonly setPropertyStream = this._setPropertyStream.asObservable();
|
||||||
|
|
||||||
private readonly _registerMenuCommandStream: Subject<string> = new Subject();
|
|
||||||
public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable();
|
|
||||||
|
|
||||||
private readonly _unregisterMenuCommandStream: Subject<string> = new Subject();
|
|
||||||
public readonly unregisterMenuCommandStream = this._unregisterMenuCommandStream.asObservable();
|
|
||||||
|
|
||||||
private readonly _playSoundStream: Subject<PlaySoundEvent> = new Subject();
|
private readonly _playSoundStream: Subject<PlaySoundEvent> = new Subject();
|
||||||
public readonly playSoundStream = this._playSoundStream.asObservable();
|
public readonly playSoundStream = this._playSoundStream.asObservable();
|
||||||
|
|
||||||
@ -267,7 +262,7 @@ class IframeListener {
|
|||||||
const data = payload.data.menutItem;
|
const data = payload.data.menutItem;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.iframeCloseCallbacks.get(iframe).push(() => {
|
this.iframeCloseCallbacks.get(iframe).push(() => {
|
||||||
this._unregisterMenuCommandStream.next(data);
|
subMenusStore.removeMenu(data);
|
||||||
});
|
});
|
||||||
handleMenuItemRegistrationEvent(payload.data);
|
handleMenuItemRegistrationEvent(payload.data);
|
||||||
} else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) {
|
} else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) {
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
|
import MenuIcon from "./Menu/MenuIcon.svelte";
|
||||||
|
import {menuIconVisiblilityStore, menuVisiblilityStore} from "../Stores/MenuStore";
|
||||||
import {enableCameraSceneVisibilityStore} from "../Stores/MediaStore";
|
import {enableCameraSceneVisibilityStore} from "../Stores/MediaStore";
|
||||||
import CameraControls from "./CameraControls.svelte";
|
import CameraControls from "./CameraControls.svelte";
|
||||||
import MyCamera from "./MyCamera.svelte";
|
import MyCamera from "./MyCamera.svelte";
|
||||||
@ -23,10 +25,9 @@
|
|||||||
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
||||||
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
|
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
|
||||||
import ErrorDialog from "./UI/ErrorDialog.svelte";
|
import ErrorDialog from "./UI/ErrorDialog.svelte";
|
||||||
|
import Menu from "./Menu/Menu.svelte";
|
||||||
import VideoOverlay from "./Video/VideoOverlay.svelte";
|
import VideoOverlay from "./Video/VideoOverlay.svelte";
|
||||||
import {gameOverlayVisibilityStore} from "../Stores/GameOverlayStoreVisibility";
|
import {gameOverlayVisibilityStore} from "../Stores/GameOverlayStoreVisibility";
|
||||||
import {consoleGlobalMessageManagerVisibleStore} from "../Stores/ConsoleGlobalMessageManagerStore";
|
|
||||||
import ConsoleGlobalMessageManager from "./ConsoleGlobalMessageManager/ConsoleGlobalMessageManager.svelte";
|
|
||||||
import AdminMessage from "./TypeMessage/BanMessage.svelte";
|
import AdminMessage from "./TypeMessage/BanMessage.svelte";
|
||||||
import TextMessage from "./TypeMessage/TextMessage.svelte";
|
import TextMessage from "./TypeMessage/TextMessage.svelte";
|
||||||
import {banMessageVisibleStore} from "../Stores/TypeMessageStore/BanMessageStore";
|
import {banMessageVisibleStore} from "../Stores/TypeMessageStore/BanMessageStore";
|
||||||
@ -37,6 +38,8 @@
|
|||||||
import LayoutManager from "./LayoutManager/LayoutManager.svelte";
|
import LayoutManager from "./LayoutManager/LayoutManager.svelte";
|
||||||
import {audioManagerVisibilityStore} from "../Stores/AudioManagerStore";
|
import {audioManagerVisibilityStore} from "../Stores/AudioManagerStore";
|
||||||
import AudioManager from "./AudioManager/AudioManager.svelte"
|
import AudioManager from "./AudioManager/AudioManager.svelte"
|
||||||
|
import { showReportScreenStore, userReportEmpty } from "../Stores/ShowReportScreenStore";
|
||||||
|
import ReportMenu from "./ReportMenu/ReportMenu.svelte";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
|
|
||||||
@ -93,6 +96,21 @@
|
|||||||
<LayoutManager></LayoutManager>
|
<LayoutManager></LayoutManager>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if $showReportScreenStore !== userReportEmpty}
|
||||||
|
<div>
|
||||||
|
<ReportMenu></ReportMenu>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if $menuIconVisiblilityStore}
|
||||||
|
<div>
|
||||||
|
<MenuIcon></MenuIcon>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if $menuVisiblilityStore}
|
||||||
|
<div>
|
||||||
|
<Menu></Menu>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if $gameOverlayVisibilityStore}
|
{#if $gameOverlayVisibilityStore}
|
||||||
<div>
|
<div>
|
||||||
<VideoOverlay></VideoOverlay>
|
<VideoOverlay></VideoOverlay>
|
||||||
@ -100,11 +118,6 @@
|
|||||||
<CameraControls></CameraControls>
|
<CameraControls></CameraControls>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $consoleGlobalMessageManagerVisibleStore}
|
|
||||||
<div>
|
|
||||||
<ConsoleGlobalMessageManager></ConsoleGlobalMessageManager>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{#if $helpCameraSettingsVisibleStore}
|
{#if $helpCameraSettingsVisibleStore}
|
||||||
<div>
|
<div>
|
||||||
<HelpCameraSettingsPopup></HelpCameraSettingsPopup>
|
<HelpCameraSettingsPopup></HelpCameraSettingsPopup>
|
||||||
|
@ -1,150 +0,0 @@
|
|||||||
<script lang="typescript">
|
|
||||||
import { fly } from 'svelte/transition';
|
|
||||||
import InputTextGlobalMessage from "./InputTextGlobalMessage.svelte";
|
|
||||||
import UploadAudioGlobalMessage from "./UploadAudioGlobalMessage.svelte";
|
|
||||||
import { gameManager } from "../../Phaser/Game/GameManager";
|
|
||||||
import { consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
|
|
||||||
|
|
||||||
let inputSendTextActive = true;
|
|
||||||
let uploadMusicActive = false;
|
|
||||||
let handleSendText: { sendTextMessage(broadcast: boolean): void };
|
|
||||||
let handleSendAudio: { sendAudioMessage(broadcast: boolean): Promise<void> };
|
|
||||||
let broadcastToWorld = false;
|
|
||||||
|
|
||||||
function closeConsoleGlobalMessage() {
|
|
||||||
consoleGlobalMessageManagerVisibleStore.set(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
function onKeyDown(e:KeyboardEvent) {
|
|
||||||
if (e.key === 'Escape') {
|
|
||||||
closeConsoleGlobalMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function inputSendTextActivate() {
|
|
||||||
inputSendTextActive = true;
|
|
||||||
uploadMusicActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function inputUploadMusicActivate() {
|
|
||||||
uploadMusicActive = true;
|
|
||||||
inputSendTextActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function send() {
|
|
||||||
if (inputSendTextActive) {
|
|
||||||
handleSendText.sendTextMessage(broadcastToWorld);
|
|
||||||
}
|
|
||||||
if (uploadMusicActive) {
|
|
||||||
handleSendAudio.sendAudioMessage(broadcastToWorld);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svelte:window on:keydown={onKeyDown}/>
|
|
||||||
|
|
||||||
<div class="console-global-message">
|
|
||||||
<div class="menu-console-global-message nes-container is-rounded" transition:fly="{{ x: -1000, duration: 500 }}">
|
|
||||||
<button type="button" class="nes-btn {inputSendTextActive ? 'is-disabled' : ''}" on:click|preventDefault={inputSendTextActivate}>Message</button>
|
|
||||||
<button type="button" class="nes-btn {uploadMusicActive ? 'is-disabled' : ''}" on:click|preventDefault={inputUploadMusicActivate}>Audio</button>
|
|
||||||
</div>
|
|
||||||
<div class="main-console-global-message nes-container is-rounded" transition:fly="{{ y: -1000, duration: 500 }}">
|
|
||||||
<div class="title-console-global-message">
|
|
||||||
<h2>Global Message</h2>
|
|
||||||
<button type="button" class="nes-btn is-error" on:click|preventDefault={closeConsoleGlobalMessage}><i class="nes-icon close is-small"></i></button>
|
|
||||||
</div>
|
|
||||||
<div class="content-console-global-message">
|
|
||||||
{#if inputSendTextActive}
|
|
||||||
<InputTextGlobalMessage gameManager={gameManager} bind:handleSending={handleSendText}/>
|
|
||||||
{/if}
|
|
||||||
{#if uploadMusicActive}
|
|
||||||
<UploadAudioGlobalMessage gameManager={gameManager} bind:handleSending={handleSendAudio}/>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div class="footer-console-global-message">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" class="nes-checkbox is-dark nes-pointer" bind:checked={broadcastToWorld}>
|
|
||||||
<span>Broadcast to all rooms of the world</span>
|
|
||||||
</label>
|
|
||||||
<button class="nes-btn is-primary" on:click|preventDefault={send}>Send</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
|
|
||||||
.nes-container {
|
|
||||||
padding: 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.console-global-message {
|
|
||||||
top: 20vh;
|
|
||||||
width: 50vw;
|
|
||||||
height: 50vh;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
pointer-events: auto;
|
|
||||||
|
|
||||||
div.menu-console-global-message {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
max-width: 180px;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
background-color: #333333;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 136px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div.main-console-global-message {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
background-color: #333333;
|
|
||||||
|
|
||||||
div.title-console-global-message {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
height: 50px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
color: whitesmoke;
|
|
||||||
|
|
||||||
.nes-btn {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div.content-console-global-message {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
max-height: calc(100% - 120px);
|
|
||||||
}
|
|
||||||
|
|
||||||
div.footer-console-global-message {
|
|
||||||
height: 50px;
|
|
||||||
margin-top: 10px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
label {
|
|
||||||
margin: 0;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
max-width: 30%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
147
front/src/Components/Menu/AboutRoomSubMenu.svelte
Normal file
147
front/src/Components/Menu/AboutRoomSubMenu.svelte
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
|
||||||
|
let gameScene = gameManager.getCurrentGameScene();
|
||||||
|
|
||||||
|
let HTMLShareLink: HTMLInputElement;
|
||||||
|
let expandedMapCopyright = false;
|
||||||
|
let expandedTilesetCopyright = false;
|
||||||
|
|
||||||
|
let mapName: string = "";
|
||||||
|
let mapDescription: string = "";
|
||||||
|
let mapCopyright: string = "The map creator did not declare a copyright for the map.";
|
||||||
|
let tilesetCopyright: string[] = [];
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (gameScene.mapFile.properties !== undefined) {
|
||||||
|
const propertyName = gameScene.mapFile.properties.find((property) => property.name === 'mapName')
|
||||||
|
if ( propertyName !== undefined && typeof propertyName.value === 'string') {
|
||||||
|
mapName = propertyName.value;
|
||||||
|
}
|
||||||
|
const propertyDescription = gameScene.mapFile.properties.find((property) => property.name === 'mapDescription')
|
||||||
|
if (propertyDescription !== undefined && typeof propertyDescription.value === 'string') {
|
||||||
|
mapDescription = propertyDescription.value;
|
||||||
|
}
|
||||||
|
const propertyCopyright = gameScene.mapFile.properties.find((property) => property.name === 'mapCopyright')
|
||||||
|
if (propertyCopyright !== undefined && typeof propertyCopyright.value === 'string') {
|
||||||
|
mapCopyright = propertyCopyright.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const tileset of gameScene.mapFile.tilesets) {
|
||||||
|
if (tileset.properties !== undefined) {
|
||||||
|
const propertyTilesetCopyright = tileset.properties.find((property) => property.name === 'tilesetCopyright')
|
||||||
|
if (propertyTilesetCopyright !== undefined && typeof propertyTilesetCopyright.value === 'string') {
|
||||||
|
tilesetCopyright = [...tilesetCopyright, propertyTilesetCopyright.value]; //Assignment needed to trigger Svelte's reactivity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function copyLink() {
|
||||||
|
HTMLShareLink.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function shareLink() {
|
||||||
|
const shareData = {url: location.toString()};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await navigator.share(shareData);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error: ' + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="about-room-main">
|
||||||
|
<section class="share-url not-mobile">
|
||||||
|
<h3>Share the link of the room !</h3>
|
||||||
|
<input type="text" readonly bind:this={HTMLShareLink} value={location.toString()}>
|
||||||
|
<button type="button" class="nes-btn is-primary" on:click={copyLink}>Copy</button>
|
||||||
|
</section>
|
||||||
|
<section class="is-mobile">
|
||||||
|
<h3>Share the link of the room !</h3>
|
||||||
|
<button type="button" class="nes-btn is-primary" on:click={shareLink}>Share</button>
|
||||||
|
</section>
|
||||||
|
<h2>Information on the map</h2>
|
||||||
|
<section class="container-overflow">
|
||||||
|
<h3>{mapName}</h3>
|
||||||
|
<p class="string-HTML">{mapDescription}</p>
|
||||||
|
<h3 class="nes-pointer hoverable" on:click={() => expandedMapCopyright = !expandedMapCopyright}>Copyrights of the map</h3>
|
||||||
|
<p class="string-HTML" hidden="{!expandedMapCopyright}">{mapCopyright}</p>
|
||||||
|
<h3 class="nes-pointer hoverable" on:click={() => expandedTilesetCopyright = !expandedTilesetCopyright}>Copyrights of the tilesets</h3>
|
||||||
|
<section hidden="{!expandedTilesetCopyright}">
|
||||||
|
{#each tilesetCopyright as copyright}
|
||||||
|
<p class="string-HTML">{copyright}</p>
|
||||||
|
{:else}
|
||||||
|
<p>The map creator did not declare a copyright for the tilesets. Warning, This doesn't mean that those tilesets have no license.</p>
|
||||||
|
{/each}
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.string-HTML{
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.about-room-main {
|
||||||
|
height: calc(100% - 56px);
|
||||||
|
|
||||||
|
section.share-url {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 85%;
|
||||||
|
border-radius: 32px;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
input::selection {
|
||||||
|
background-color: #209cee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section.is-mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2, h3 {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3.hoverable:hover {
|
||||||
|
background-color: #3c3e40;
|
||||||
|
border-radius: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.container-overflow {
|
||||||
|
height: calc(100% - 220px);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||||
|
div.about-room-main {
|
||||||
|
section.share-url.not-mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.is-mobile {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.container-overflow {
|
||||||
|
height: calc(100% - 120px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,17 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||||
import type { GameManager } from "../../Phaser/Game/GameManager";
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
import { consoleGlobalMessageManagerFocusStore, consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
|
|
||||||
import { AdminMessageEventTypes } from "../../Connexion/AdminMessagesService";
|
import { AdminMessageEventTypes } from "../../Connexion/AdminMessagesService";
|
||||||
import uploadFile from "../images/music-file.svg";
|
import uploadFile from "../images/music-file.svg";
|
||||||
import type {PlayGlobalMessageInterface} from "../../Connexion/ConnexionModels";
|
import type { PlayGlobalMessageInterface } from "../../Connexion/ConnexionModels";
|
||||||
|
|
||||||
interface EventTargetFiles extends EventTarget {
|
interface EventTargetFiles extends EventTarget {
|
||||||
files: Array<File>;
|
files: Array<File>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export let gameManager: GameManager;
|
|
||||||
|
|
||||||
let gameScene = gameManager.getCurrentGameScene();
|
let gameScene = gameManager.getCurrentGameScene();
|
||||||
let fileInput: HTMLInputElement;
|
let fileInput: HTMLInputElement;
|
||||||
let fileName: string;
|
let fileName: string;
|
||||||
@ -43,7 +40,6 @@
|
|||||||
}
|
}
|
||||||
inputAudio.value = '';
|
inputAudio.value = '';
|
||||||
gameScene.connection?.emitGlobalMessage(audioGlobalMessage);
|
gameScene.connection?.emitGlobalMessage(audioGlobalMessage);
|
||||||
disableConsole();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,11 +70,6 @@
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableConsole() {
|
|
||||||
consoleGlobalMessageManagerVisibleStore.set(false);
|
|
||||||
consoleGlobalMessageManagerFocusStore.set(false);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@ -103,24 +94,17 @@
|
|||||||
|
|
||||||
img {
|
img {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
|
||||||
max-height: 80%;
|
max-height: 80%;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
flex: 1 1 auto;
|
|
||||||
|
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
|
||||||
&.err {
|
&.err {
|
||||||
color: #ce372b;
|
color: #ce372b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
15
front/src/Components/Menu/ContactSubMenu.svelte
Normal file
15
front/src/Components/Menu/ContactSubMenu.svelte
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {CONTACT_URL} from "../../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<iframe title="contact" src="{CONTACT_URL}"></iframe>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
iframe {
|
||||||
|
border: none;
|
||||||
|
height: calc(100% - 56px);
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
51
front/src/Components/Menu/CreateMapSubMenu.svelte
Normal file
51
front/src/Components/Menu/CreateMapSubMenu.svelte
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
function goToGettingStarted() {
|
||||||
|
const sparkHost = "https://workadventu.re/getting-started";
|
||||||
|
window.open(sparkHost, "_blank");
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToBuildingMap() {
|
||||||
|
const sparkHost = "https://workadventu.re/map-building";
|
||||||
|
window.open(sparkHost, "_blank");
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="create-map-main">
|
||||||
|
<section class="container-overflow">
|
||||||
|
<section>
|
||||||
|
<h3>Getting started</h3>
|
||||||
|
<p>
|
||||||
|
WorkAdventure allows you to create an online space to communicate spontaneously with others.
|
||||||
|
And it all starts with creating your own space. Choose from a large selection of prefabricated maps by our team.
|
||||||
|
</p>
|
||||||
|
<button type="button" class="nes-btn is-primary" on:click={goToGettingStarted}>Getting started</button>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h3>Create your map</h3>
|
||||||
|
<p>You can also create your own custom map by following the step of the documentation.</p>
|
||||||
|
<button type="button" class="nes-btn" on:click={goToBuildingMap}>Create your map</button>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.create-map-main {
|
||||||
|
height: calc(100% - 56px);
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
section {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.container-overflow {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
118
front/src/Components/Menu/GlobalMessagesSubMenu.svelte
Normal file
118
front/src/Components/Menu/GlobalMessagesSubMenu.svelte
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import TextGlobalMessage from './TextGlobalMessage.svelte';
|
||||||
|
import AudioGlobalMessage from './AudioGlobalMessage.svelte';
|
||||||
|
|
||||||
|
let handleSendText: { sendTextMessage(broadcast: boolean): void };
|
||||||
|
let handleSendAudio: { sendAudioMessage(broadcast: boolean): Promise<void> };
|
||||||
|
|
||||||
|
let inputSendTextActive = true;
|
||||||
|
let uploadAudioActive = !inputSendTextActive;
|
||||||
|
let broadcastToWorld = false;
|
||||||
|
|
||||||
|
function activateInputText() {
|
||||||
|
inputSendTextActive = true;
|
||||||
|
uploadAudioActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateUploadAudio() {
|
||||||
|
inputSendTextActive = false;
|
||||||
|
uploadAudioActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send() {
|
||||||
|
if (inputSendTextActive) {
|
||||||
|
handleSendText.sendTextMessage(broadcastToWorld);
|
||||||
|
}
|
||||||
|
if (uploadAudioActive) {
|
||||||
|
handleSendAudio.sendAudioMessage(broadcastToWorld);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="global-message-main">
|
||||||
|
<div class="global-message-subOptions">
|
||||||
|
<section>
|
||||||
|
<button type="button" class="nes-btn {inputSendTextActive ? 'is-disabled' : ''}" on:click|preventDefault={activateInputText}>Text</button>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<button type="button" class="nes-btn {uploadAudioActive ? 'is-disabled' : ''}" on:click|preventDefault={activateUploadAudio}>Audio</button>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="global-message-content">
|
||||||
|
{#if inputSendTextActive}
|
||||||
|
<TextGlobalMessage bind:handleSending={handleSendText}/>
|
||||||
|
{/if}
|
||||||
|
{#if uploadAudioActive}
|
||||||
|
<AudioGlobalMessage bind:handleSending={handleSendAudio}/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="global-message-footer">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" class="nes-checkbox is-dark nes-pointer" bind:checked={broadcastToWorld}>
|
||||||
|
<span>Broadcast to all rooms of the world</span>
|
||||||
|
</label>
|
||||||
|
<section>
|
||||||
|
<button class="nes-btn is-primary" on:click|preventDefault={send}>Send</button>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.global-message-main {
|
||||||
|
height: calc(100% - 50px);
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 15% 65% 20%;
|
||||||
|
|
||||||
|
div.global-message-subOptions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 50% 50%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.global-message-footer {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 50% 50%;
|
||||||
|
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||||
|
.global-message-content {
|
||||||
|
height: calc(100% - 5px);
|
||||||
|
}
|
||||||
|
.global-message-footer {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
label {
|
||||||
|
width: calc(100% - 10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
132
front/src/Components/Menu/Menu.svelte
Normal file
132
front/src/Components/Menu/Menu.svelte
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<script lang="typescript">
|
||||||
|
import {fly} from "svelte/transition";
|
||||||
|
import SettingsSubMenu from "./SettingsSubMenu.svelte";
|
||||||
|
import ProfileSubMenu from "./ProfileSubMenu.svelte";
|
||||||
|
import CreateMapSubMenu from "./CreateMapSubMenu.svelte";
|
||||||
|
import AboutRoomSubMenu from "./AboutRoomSubMenu.svelte";
|
||||||
|
import GlobalMessageSubMenu from "./GlobalMessagesSubMenu.svelte";
|
||||||
|
import ContactSubMenu from "./ContactSubMenu.svelte";
|
||||||
|
import {menuVisiblilityStore, SubMenusInterface, subMenusStore} from "../../Stores/MenuStore";
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
import {get} from "svelte/store";
|
||||||
|
import {sendMenuClickedEvent} from "../../Api/iframe/Ui/MenuItem";
|
||||||
|
|
||||||
|
let activeSubMenu: string = SubMenusInterface.settings;
|
||||||
|
let activeComponent: typeof SettingsSubMenu = SettingsSubMenu;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
switchMenu(SubMenusInterface.settings);
|
||||||
|
})
|
||||||
|
|
||||||
|
function switchMenu(menu: string) {
|
||||||
|
if (get(subMenusStore).find((subMenu) => subMenu === menu)) {
|
||||||
|
activeSubMenu = menu;
|
||||||
|
switch (menu) {
|
||||||
|
case SubMenusInterface.settings:
|
||||||
|
activeComponent = SettingsSubMenu;
|
||||||
|
break;
|
||||||
|
case SubMenusInterface.profile:
|
||||||
|
activeComponent = ProfileSubMenu;
|
||||||
|
break;
|
||||||
|
case SubMenusInterface.createMap:
|
||||||
|
activeComponent = CreateMapSubMenu;
|
||||||
|
break;
|
||||||
|
case SubMenusInterface.aboutRoom:
|
||||||
|
activeComponent = AboutRoomSubMenu;
|
||||||
|
break;
|
||||||
|
case SubMenusInterface.globalMessages:
|
||||||
|
activeComponent = GlobalMessageSubMenu;
|
||||||
|
break;
|
||||||
|
case SubMenusInterface.contact:
|
||||||
|
activeComponent = ContactSubMenu;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sendMenuClickedEvent(menu);
|
||||||
|
menuVisiblilityStore.set(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else throw ("There is no menu called " + menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeMenu() {
|
||||||
|
menuVisiblilityStore.set(false);
|
||||||
|
}
|
||||||
|
function onKeyDown(e:KeyboardEvent) {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
closeMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:keydown={onKeyDown}/>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="menu-container-main">
|
||||||
|
<div class="menu-nav-sidebar nes-container is-rounded" transition:fly="{{ x: -1000, duration: 500 }}">
|
||||||
|
<h2>Menu</h2>
|
||||||
|
<nav>
|
||||||
|
{#each $subMenusStore as submenu}
|
||||||
|
<button type="button" class="nes-btn {activeSubMenu === submenu ? 'is-disabled' : ''}" on:click|preventDefault={() => switchMenu(submenu)}>
|
||||||
|
{submenu}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div class="menu-submenu-container nes-container is-rounded" transition:fly="{{ y: -1000, duration: 500 }}">
|
||||||
|
<h2>{activeSubMenu}</h2>
|
||||||
|
<svelte:component this={activeComponent}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.nes-container {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu-container-main {
|
||||||
|
--size-first-columns-grid: 200px;
|
||||||
|
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
pointer-events: auto;
|
||||||
|
height: 80vh;
|
||||||
|
width: 75vw;
|
||||||
|
top: 10vh;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: var(--size-first-columns-grid) calc(100% - var(--size-first-columns-grid));
|
||||||
|
grid-template-rows: 100%;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu-nav-sidebar {
|
||||||
|
background-color: #333333;
|
||||||
|
color: whitesmoke;
|
||||||
|
|
||||||
|
nav button {
|
||||||
|
width: calc(100% - 10px);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu-submenu-container {
|
||||||
|
background-color: #333333;
|
||||||
|
color: whitesmoke;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px) {
|
||||||
|
div.menu-container-main {
|
||||||
|
--size-first-columns-grid: 120px;
|
||||||
|
height: 70vh;
|
||||||
|
top: 55px;
|
||||||
|
width: 100vw;
|
||||||
|
font-size: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,29 +1,39 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
|
import logoWA from "../images/menu.svg"
|
||||||
|
import {menuVisiblilityStore} from "../../Stores/MenuStore";
|
||||||
|
import {get} from "svelte/store";
|
||||||
|
|
||||||
|
function showMenu(){
|
||||||
|
menuVisiblilityStore.set(!get(menuVisiblilityStore))
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(e: KeyboardEvent) {
|
||||||
|
if (e.key === "Tab") {
|
||||||
|
showMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main class="menuIcon">
|
<svelte:window on:keydown={onKeyDown}/>
|
||||||
<section>
|
|
||||||
<button>
|
<main class="menuIcon nes-btn is-dark" on:click|preventDefault={showMenu}>
|
||||||
<img src="/static/images/menu.svg" alt="Open menu">
|
<img src={logoWA} alt="open menu" class="nes-pointer" >
|
||||||
</button>
|
|
||||||
</section>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.menuIcon button {
|
.menuIcon {
|
||||||
padding: 2px 8px;
|
pointer-events: auto;
|
||||||
img {
|
margin: 25px;
|
||||||
width: 14px;
|
img {
|
||||||
padding-top: 0;
|
width: 24px;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.menuIcon section {
|
}
|
||||||
margin: 10px;
|
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||||
}
|
.menuIcon {
|
||||||
@media only screen and (max-height: 700px) {
|
margin: 6px;
|
||||||
.menuIcon section {
|
img {
|
||||||
margin: 2px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
78
front/src/Components/Menu/ProfileSubMenu.svelte
Normal file
78
front/src/Components/Menu/ProfileSubMenu.svelte
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<script lang="typescript">
|
||||||
|
import {gameManager} from "../../Phaser/Game/GameManager";
|
||||||
|
import {SelectCompanionScene, SelectCompanionSceneName} from "../../Phaser/Login/SelectCompanionScene";
|
||||||
|
import {menuIconVisiblilityStore, menuVisiblilityStore} from "../../Stores/MenuStore";
|
||||||
|
import {selectCompanionSceneVisibleStore} from "../../Stores/SelectCompanionStore";
|
||||||
|
import {LoginScene, LoginSceneName} from "../../Phaser/Login/LoginScene";
|
||||||
|
import {loginSceneVisibleStore} from "../../Stores/LoginSceneStore";
|
||||||
|
import {selectCharacterSceneVisibleStore} from "../../Stores/SelectCharacterStore";
|
||||||
|
import {SelectCharacterScene, SelectCharacterSceneName} from "../../Phaser/Login/SelectCharacterScene";
|
||||||
|
//import {connectionManager} from "../../Connexion/ConnectionManager";
|
||||||
|
|
||||||
|
|
||||||
|
function disableMenuStores(){
|
||||||
|
menuVisiblilityStore.set(false);
|
||||||
|
menuIconVisiblilityStore.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openEditCompanionScene(){
|
||||||
|
disableMenuStores();
|
||||||
|
selectCompanionSceneVisibleStore.set(true);
|
||||||
|
gameManager.leaveGame(SelectCompanionSceneName,new SelectCompanionScene());
|
||||||
|
}
|
||||||
|
|
||||||
|
function openEditNameScene(){
|
||||||
|
disableMenuStores();
|
||||||
|
loginSceneVisibleStore.set(true);
|
||||||
|
gameManager.leaveGame(LoginSceneName,new LoginScene());
|
||||||
|
}
|
||||||
|
|
||||||
|
function openEditSkinScene(){
|
||||||
|
disableMenuStores();
|
||||||
|
selectCharacterSceneVisibleStore.set(true);
|
||||||
|
gameManager.leaveGame(SelectCharacterSceneName,new SelectCharacterScene());
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Uncomment when login will be completely developed
|
||||||
|
/*function clickLogin() {
|
||||||
|
connectionManager.loadOpenIDScreen();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="customize-main">
|
||||||
|
<section>
|
||||||
|
<button type="button" class="nes-btn" on:click|preventDefault={openEditNameScene}>Edit Name</button>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<button type="button" class="nes-btn is-rounded" on:click|preventDefault={openEditSkinScene}>Edit Skin</button>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<button type="button" class="nes-btn" on:click|preventDefault={openEditCompanionScene}>Edit Companion</button>
|
||||||
|
</section>
|
||||||
|
<!-- <section>
|
||||||
|
<button type="button" class="nes-btn is-primary" on:click|preventDefault={clickLogin}>Login</button>
|
||||||
|
</section>-->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.customize-main{
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 50px;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px) {
|
||||||
|
div.customize-main section button {
|
||||||
|
width: 130px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
140
front/src/Components/Menu/SettingsSubMenu.svelte
Normal file
140
front/src/Components/Menu/SettingsSubMenu.svelte
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<script lang="typescript">
|
||||||
|
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||||
|
import {videoConstraintStore} from "../../Stores/MediaStore";
|
||||||
|
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
||||||
|
import {isMobile} from "../../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
|
let fullscreen : boolean = localUserStore.getFullscreen();
|
||||||
|
let notification : boolean = localUserStore.getNotification() === 'granted';
|
||||||
|
let valueGame : number = localUserStore.getGameQualityValue();
|
||||||
|
let valueVideo : number = localUserStore.getVideoQualityValue();
|
||||||
|
let previewValueGame = valueGame;
|
||||||
|
let previewValueVideo = valueVideo;
|
||||||
|
|
||||||
|
function saveSetting(){
|
||||||
|
if (valueGame !== previewValueGame) {
|
||||||
|
previewValueGame = valueGame;
|
||||||
|
localUserStore.setGameQualityValue(valueGame);
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueVideo !== previewValueVideo) {
|
||||||
|
previewValueVideo = valueVideo;
|
||||||
|
videoConstraintStore.setFrameRate(valueVideo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeFullscreen() {
|
||||||
|
const body = HtmlUtils.querySelectorOrFail('body');
|
||||||
|
if (body) {
|
||||||
|
if (document.fullscreenElement !== null && !fullscreen) {
|
||||||
|
document.exitFullscreen()
|
||||||
|
} else {
|
||||||
|
body.requestFullscreen();
|
||||||
|
}
|
||||||
|
localUserStore.setFullscreen(fullscreen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeNotification() {
|
||||||
|
if (Notification.permission === 'granted') {
|
||||||
|
localUserStore.setNotification(notification ? 'granted' : 'denied');
|
||||||
|
} else {
|
||||||
|
Notification.requestPermission().then((response) => {
|
||||||
|
if (response === 'granted') {
|
||||||
|
localUserStore.setNotification(notification ? 'granted' : 'denied');
|
||||||
|
} else {
|
||||||
|
localUserStore.setNotification('denied');
|
||||||
|
notification = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="settings-main" on:submit|preventDefault={saveSetting}>
|
||||||
|
<section>
|
||||||
|
<h3>Game quality</h3>
|
||||||
|
<div class="nes-select is-dark">
|
||||||
|
<select bind:value={valueGame}>
|
||||||
|
<option value="{120}">{isMobile() ? 'High (120 fps)' : 'High video quality (120 fps)'}</option>
|
||||||
|
<option value="{60}">{isMobile() ? 'Medium (60 fps)' : 'Medium video quality (60 fps, recommended)'}</option>
|
||||||
|
<option value="{40}">{isMobile() ? 'Minimum (40 fps)' : 'Minimum video quality (40 fps)'}</option>
|
||||||
|
<option value="{20}">{isMobile() ? 'Small (20 fps)' : 'Small video quality (20 fps)'}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h3>Video quality</h3>
|
||||||
|
<div class="nes-select is-dark">
|
||||||
|
<select bind:value={valueVideo}>
|
||||||
|
<option value="{30}">{isMobile() ? 'High (30 fps)' : 'High video quality (30 fps)'}</option>
|
||||||
|
<option value="{20}">{isMobile() ? 'Medium (20 fps)' : 'Medium video quality (20 fps, recommended)'}</option>
|
||||||
|
<option value="{10}">{isMobile() ? 'Minimum (10 fps)' : 'Minimum video quality (10 fps)'}</option>
|
||||||
|
<option value="{5}">{isMobile() ? 'Small (5 fps)' : 'Small video quality (5 fps)'}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="settings-section-save">
|
||||||
|
<p>(Saving these settings will restart the game)</p>
|
||||||
|
<button type="button" class="nes-btn is-primary" on:click|preventDefault={saveSetting}>Save</button>
|
||||||
|
</section>
|
||||||
|
<section class="settings-section-noSaveOption">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" class="nes-checkbox is-dark" bind:checked={fullscreen} on:change={changeFullscreen}/>
|
||||||
|
<span>Fullscreen</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" class="nes-checkbox is-dark" bind:checked={notification} on:change={changeNotification}>
|
||||||
|
<span>Notifications</span>
|
||||||
|
</label>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.settings-main {
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
|
||||||
|
section {
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px 20px 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
div.nes-select select:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
section.settings-section-save {
|
||||||
|
text-align: center;
|
||||||
|
p {
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
section.settings-section-noSaveOption {
|
||||||
|
--nb-noSaveOptions: 2; //number of sub-element in the section
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: calc(100% / var(--nb-noSaveOptions)) calc(100% / var(--nb-noSaveOptions)); //Same size for every sub-element
|
||||||
|
|
||||||
|
label {
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||||
|
div.settings-main {
|
||||||
|
section {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.settings-section-noSaveOption {
|
||||||
|
height: 80px;
|
||||||
|
grid-template-columns: none;
|
||||||
|
grid-template-rows: calc(100% / var(--nb-noSaveOptions)) calc(100% / var(--nb-noSaveOptions)); //Same size for every sub-element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { consoleGlobalMessageManagerFocusStore, consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
|
import { menuInputFocusStore } from "../../Stores/MenuStore";
|
||||||
import {onDestroy, onMount} from "svelte";
|
import { onDestroy, onMount } from "svelte";
|
||||||
import type { GameManager } from "../../Phaser/Game/GameManager";
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
import { AdminMessageEventTypes } from "../../Connexion/AdminMessagesService";
|
import { AdminMessageEventTypes } from "../../Connexion/AdminMessagesService";
|
||||||
import type { Quill } from "quill";
|
import type { Quill } from "quill";
|
||||||
import type { PlayGlobalMessageInterface } from "../../Connexion/ConnexionModels";
|
import type { PlayGlobalMessageInterface } from "../../Connexion/ConnexionModels";
|
||||||
@ -24,19 +24,15 @@
|
|||||||
[{'font': []}],
|
[{'font': []}],
|
||||||
[{'align': []}],
|
[{'align': []}],
|
||||||
|
|
||||||
['clean'],
|
['clean'], // remove formatting button
|
||||||
|
|
||||||
['link', 'image', 'video']
|
['link', 'image', 'video']
|
||||||
// remove formatting button
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export let gameManager: GameManager;
|
|
||||||
|
|
||||||
const gameScene = gameManager.getCurrentGameScene();
|
const gameScene = gameManager.getCurrentGameScene();
|
||||||
let quill: Quill;
|
|
||||||
let INPUT_CONSOLE_MESSAGE: HTMLDivElement;
|
|
||||||
|
|
||||||
const MESSAGE_TYPE = AdminMessageEventTypes.admin;
|
const MESSAGE_TYPE = AdminMessageEventTypes.admin;
|
||||||
|
let quill: Quill;
|
||||||
|
let QUILL_EDITOR: HTMLDivElement;
|
||||||
|
|
||||||
export const handleSending = {
|
export const handleSending = {
|
||||||
sendTextMessage(broadcastToWorld: boolean) {
|
sendTextMessage(broadcastToWorld: boolean) {
|
||||||
@ -53,39 +49,31 @@
|
|||||||
|
|
||||||
quill.deleteText(0, quill.getLength());
|
quill.deleteText(0, quill.getLength());
|
||||||
gameScene.connection?.emitGlobalMessage(textGlobalMessage);
|
gameScene.connection?.emitGlobalMessage(textGlobalMessage);
|
||||||
disableConsole();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Quill
|
//Quill
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
|
||||||
// Import quill
|
// Import quill
|
||||||
const {default: Quill} = await import("quill"); // eslint-disable-line @typescript-eslint/no-explicit-any
|
const {default: Quill} = await import("quill"); // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
|
||||||
quill = new Quill(INPUT_CONSOLE_MESSAGE, {
|
quill = new Quill(QUILL_EDITOR, {
|
||||||
placeholder: 'Enter your message here...',
|
placeholder: 'Enter your message here...',
|
||||||
theme: 'snow',
|
theme: 'snow',
|
||||||
modules: {
|
modules: {
|
||||||
toolbar: toolbarOptions
|
toolbar: toolbarOptions
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
menuInputFocusStore.set(true);
|
||||||
consoleGlobalMessageManagerFocusStore.set(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
consoleGlobalMessageManagerFocusStore.set(false);
|
menuInputFocusStore.set(false);
|
||||||
})
|
})
|
||||||
|
|
||||||
function disableConsole() {
|
|
||||||
consoleGlobalMessageManagerVisibleStore.set(false);
|
|
||||||
consoleGlobalMessageManagerFocusStore.set(false);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="section-input-send-text">
|
<section class="section-input-send-text">
|
||||||
<div class="input-send-text" bind:this={INPUT_CONSOLE_MESSAGE}></div>
|
<div class="input-send-text" bind:this={QUILL_EDITOR}></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
44
front/src/Components/ReportMenu/BlockSubMenu.svelte
Normal file
44
front/src/Components/ReportMenu/BlockSubMenu.svelte
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {blackListManager} from "../../WebRtc/BlackListManager";
|
||||||
|
import {showReportScreenStore, userReportEmpty} from "../../Stores/ShowReportScreenStore";
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
|
||||||
|
export let userUUID: string | undefined;
|
||||||
|
export let userName: string;
|
||||||
|
let userIsBlocked = false;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (userUUID === undefined) {
|
||||||
|
userIsBlocked = false;
|
||||||
|
console.error("There is no user to block");
|
||||||
|
} else {
|
||||||
|
userIsBlocked = blackListManager.isBlackListed(userUUID);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function blockUser(): void {
|
||||||
|
if (userUUID === undefined) {
|
||||||
|
console.error("There is no user to block");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blackListManager.isBlackListed(userUUID)
|
||||||
|
? blackListManager.cancelBlackList(userUUID)
|
||||||
|
: blackListManager.blackList(userUUID);
|
||||||
|
showReportScreenStore.set(userReportEmpty); //close the report menu
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="block-container">
|
||||||
|
<h3>Block</h3>
|
||||||
|
<p>Block any communication from and to {userName}. This can be reverted.</p>
|
||||||
|
<button type="button" class="nes-btn is-error" on:click|preventDefault={blockUser}>
|
||||||
|
{userIsBlocked ? 'Unblock this user' : 'Block this user'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.block-container {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
141
front/src/Components/ReportMenu/ReportMenu.svelte
Normal file
141
front/src/Components/ReportMenu/ReportMenu.svelte
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {showReportScreenStore, userReportEmpty} from "../../Stores/ShowReportScreenStore";
|
||||||
|
import BlockSubMenu from "./BlockSubMenu.svelte";
|
||||||
|
import ReportSubMenu from "./ReportSubMenu.svelte";
|
||||||
|
import {onDestroy, onMount} from "svelte";
|
||||||
|
import type {Unsubscriber} from "svelte/store";
|
||||||
|
import {playersStore} from "../../Stores/PlayersStore";
|
||||||
|
import {connectionManager} from "../../Connexion/ConnectionManager";
|
||||||
|
import {GameConnexionTypes} from "../../Url/UrlManager";
|
||||||
|
import {get} from "svelte/store";
|
||||||
|
|
||||||
|
let blockActive = true;
|
||||||
|
let reportActive = !blockActive;
|
||||||
|
let anonymous: boolean = false;
|
||||||
|
let userUUID: string | undefined = playersStore.getPlayerById(get(showReportScreenStore).userId)?.userUuid;
|
||||||
|
let userName = "No name";
|
||||||
|
let unsubscriber: Unsubscriber
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
unsubscriber = showReportScreenStore.subscribe((reportScreenStore) => {
|
||||||
|
if (reportScreenStore != null) {
|
||||||
|
userName = reportScreenStore.userName;
|
||||||
|
userUUID = playersStore.getPlayerById(reportScreenStore.userId)?.userUuid;
|
||||||
|
if (userUUID === undefined) {
|
||||||
|
console.error("Could not find UUID for user with ID " + reportScreenStore.userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
anonymous = connectionManager.getConnexionType === GameConnexionTypes.anonymous;
|
||||||
|
})
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if (unsubscriber) {
|
||||||
|
unsubscriber();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
showReportScreenStore.set(userReportEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateBlock() {
|
||||||
|
blockActive = true;
|
||||||
|
reportActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateReport() {
|
||||||
|
blockActive = false;
|
||||||
|
reportActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(e:KeyboardEvent) {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:keydown={onKeyDown}/>
|
||||||
|
|
||||||
|
<div class="report-menu-main nes-container is-rounded">
|
||||||
|
<section class="report-menu-title">
|
||||||
|
<h2>Moderate {userName}</h2>
|
||||||
|
<section class="justify-center">
|
||||||
|
<button type="button" class="nes-btn" on:click|preventDefault={close}>X</button>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
<section class="report-menu-action {anonymous ? 'hidden' : ''}">
|
||||||
|
<section class="justify-center">
|
||||||
|
<button type="button" class="nes-btn {blockActive ? 'is-disabled' : ''}" on:click|preventDefault={activateBlock}>Block</button>
|
||||||
|
</section>
|
||||||
|
<section class="justify-center">
|
||||||
|
<button type="button" class="nes-btn {reportActive ? 'is-disabled' : ''}" on:click|preventDefault={activateReport}>Report</button>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
<section class="report-menu-content">
|
||||||
|
{#if blockActive}
|
||||||
|
<BlockSubMenu userUUID="{userUUID}" userName="{userName}"/>
|
||||||
|
{:else if reportActive}
|
||||||
|
<ReportSubMenu userUUID="{userUUID}"/>
|
||||||
|
{:else }
|
||||||
|
<p>ERROR : There is no action selected.</p>
|
||||||
|
{/if}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.nes-container {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.justify-center {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.report-menu-main {
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
pointer-events: auto;
|
||||||
|
background-color: #333333;
|
||||||
|
color: whitesmoke;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
height: 70vh;
|
||||||
|
width: 50vw;
|
||||||
|
top: 10vh;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
section.report-menu-title {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: calc(100% - 45px) 40px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section.report-menu-action {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 50% 50%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.report-menu-action.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px) {
|
||||||
|
div.report-menu-main {
|
||||||
|
top: 21vh;
|
||||||
|
height: 60vh;
|
||||||
|
width: 100vw;
|
||||||
|
font-size: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
55
front/src/Components/ReportMenu/ReportSubMenu.svelte
Normal file
55
front/src/Components/ReportMenu/ReportSubMenu.svelte
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {showReportScreenStore, userReportEmpty} from "../../Stores/ShowReportScreenStore";
|
||||||
|
import {gameManager} from "../../Phaser/Game/GameManager";
|
||||||
|
|
||||||
|
export let userUUID: string | undefined;
|
||||||
|
let reportMessage: string;
|
||||||
|
let hiddenError = true;
|
||||||
|
|
||||||
|
function submitReport() {
|
||||||
|
if (reportMessage === '') {
|
||||||
|
hiddenError = true;
|
||||||
|
} else {
|
||||||
|
hiddenError = false;
|
||||||
|
if( userUUID === undefined) {
|
||||||
|
console.error('User UUID is not valid.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gameManager.getCurrentGameScene().connection?.emitReportPlayerMessage(userUUID, reportMessage);
|
||||||
|
showReportScreenStore.set(userReportEmpty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="report-container-main">
|
||||||
|
<h3>Report</h3>
|
||||||
|
<p>Send a report message to the administrators of this room. They may later ban this user.</p>
|
||||||
|
<form>
|
||||||
|
<section>
|
||||||
|
<label>
|
||||||
|
<span>Your message: </span>
|
||||||
|
<textarea type="text" class="nes-textarea" bind:value={reportMessage}></textarea>
|
||||||
|
</label>
|
||||||
|
<p hidden="{hiddenError}">Report message cannot to be empty.</p>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<button type="submit" class="nes-btn is-error" on:click={submitReport}>Report this user</button>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.report-container-main {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
height: clamp(100px, 15vh, 300px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-height: 630px) {
|
||||||
|
div.report-container-main textarea {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
@ -16,6 +16,7 @@ const lastRoomUrl = "lastRoomUrl";
|
|||||||
const authToken = "authToken";
|
const authToken = "authToken";
|
||||||
const state = "state";
|
const state = "state";
|
||||||
const nonce = "nonce";
|
const nonce = "nonce";
|
||||||
|
const notification = "notificationPermission";
|
||||||
|
|
||||||
const cacheAPIIndex = "workavdenture-cache";
|
const cacheAPIIndex = "workavdenture-cache";
|
||||||
|
|
||||||
@ -143,6 +144,14 @@ class LocalUserStore {
|
|||||||
return localStorage.getItem(authToken);
|
return localStorage.getItem(authToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setNotification(value: string): void {
|
||||||
|
localStorage.setItem(notification, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
getNotification(): string | null {
|
||||||
|
return localStorage.getItem(notification);
|
||||||
|
}
|
||||||
|
|
||||||
generateState(): string {
|
generateState(): string {
|
||||||
const newState = uuidv4();
|
const newState = uuidv4();
|
||||||
localStorage.setItem(state, newState);
|
localStorage.setItem(state, newState);
|
||||||
|
@ -18,6 +18,7 @@ export const MAX_USERNAME_LENGTH = parseInt(process.env.MAX_USERNAME_LENGTH || "
|
|||||||
export const MAX_PER_GROUP = parseInt(process.env.MAX_PER_GROUP || "4");
|
export const MAX_PER_GROUP = parseInt(process.env.MAX_PER_GROUP || "4");
|
||||||
export const DISPLAY_TERMS_OF_USE = process.env.DISPLAY_TERMS_OF_USE == "true";
|
export const DISPLAY_TERMS_OF_USE = process.env.DISPLAY_TERMS_OF_USE == "true";
|
||||||
export const NODE_ENV = process.env.NODE_ENV || "development";
|
export const NODE_ENV = process.env.NODE_ENV || "development";
|
||||||
|
export const CONTACT_URL = process.env.CONTACT_URL || undefined;
|
||||||
|
|
||||||
export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600;
|
export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600;
|
||||||
|
|
||||||
|
@ -1,48 +1,63 @@
|
|||||||
import ImageFrameConfig = Phaser.Types.Loader.FileTypes.ImageFrameConfig;
|
import ImageFrameConfig = Phaser.Types.Loader.FileTypes.ImageFrameConfig;
|
||||||
|
import { DirtyScene } from "../Game/DirtyScene";
|
||||||
|
|
||||||
const LogoNameIndex: string = 'logoLoading';
|
const LogoNameIndex: string = "logoLoading";
|
||||||
const TextName: string = 'Loading...';
|
const TextName: string = "Loading...";
|
||||||
const LogoResource: string = 'resources/logos/logo.png';
|
const LogoResource: string = "resources/logos/logo.png";
|
||||||
const LogoFrame: ImageFrameConfig = {frameWidth: 307, frameHeight: 59};
|
const LogoFrame: ImageFrameConfig = { frameWidth: 307, frameHeight: 59 };
|
||||||
|
|
||||||
export const addLoader = (scene: Phaser.Scene): void => {
|
export const addLoader = (scene: Phaser.Scene): void => {
|
||||||
// If there is nothing to load, do not display the loader.
|
// If there is nothing to load, do not display the loader.
|
||||||
if (scene.load.list.entries.length === 0) {
|
if (scene.load.list.entries.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let loadingText: Phaser.GameObjects.Text|null = null;
|
let loadingText: Phaser.GameObjects.Text | null = null;
|
||||||
const loadingBarWidth: number = Math.floor(scene.game.renderer.width / 3);
|
const loadingBarWidth: number = Math.floor(scene.game.renderer.width / 3);
|
||||||
const loadingBarHeight: number = 16;
|
const loadingBarHeight: number = 16;
|
||||||
const padding: number = 5;
|
const padding: number = 5;
|
||||||
|
|
||||||
const promiseLoadLogoTexture = new Promise<Phaser.GameObjects.Image>((res) => {
|
const promiseLoadLogoTexture = new Promise<Phaser.GameObjects.Image>((res) => {
|
||||||
if(scene.load.textureManager.exists(LogoNameIndex)){
|
if (scene.load.textureManager.exists(LogoNameIndex)) {
|
||||||
return res(scene.add.image(scene.game.renderer.width / 2, scene.game.renderer.height / 2 - 150, LogoNameIndex));
|
return res(
|
||||||
}else{
|
scene.add.image(scene.game.renderer.width / 2, scene.game.renderer.height / 2 - 150, LogoNameIndex)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
//add loading if logo image is not ready
|
//add loading if logo image is not ready
|
||||||
loadingText = scene.add.text(scene.game.renderer.width / 2, scene.game.renderer.height / 2 - 50, TextName);
|
loadingText = scene.add.text(scene.game.renderer.width / 2, scene.game.renderer.height / 2 - 50, TextName);
|
||||||
}
|
}
|
||||||
scene.load.spritesheet(LogoNameIndex, LogoResource, LogoFrame);
|
scene.load.spritesheet(LogoNameIndex, LogoResource, LogoFrame);
|
||||||
scene.load.once(`filecomplete-spritesheet-${LogoNameIndex}`, () => {
|
scene.load.once(`filecomplete-spritesheet-${LogoNameIndex}`, () => {
|
||||||
if(loadingText){
|
if (loadingText) {
|
||||||
loadingText.destroy();
|
loadingText.destroy();
|
||||||
}
|
}
|
||||||
return res(scene.add.image(scene.game.renderer.width / 2, scene.game.renderer.height / 2 - 150, LogoNameIndex));
|
return res(
|
||||||
|
scene.add.image(scene.game.renderer.width / 2, scene.game.renderer.height / 2 - 150, LogoNameIndex)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const progressContainer = scene.add.graphics();
|
const progressContainer = scene.add.graphics();
|
||||||
const progress = scene.add.graphics();
|
const progress = scene.add.graphics();
|
||||||
progressContainer.fillStyle(0x444444, 0.8);
|
progressContainer.fillStyle(0x444444, 0.8);
|
||||||
progressContainer.fillRect((scene.game.renderer.width - loadingBarWidth) / 2 - padding, scene.game.renderer.height / 2 + 50 - padding, loadingBarWidth + padding * 2, loadingBarHeight + padding * 2);
|
progressContainer.fillRect(
|
||||||
|
(scene.game.renderer.width - loadingBarWidth) / 2 - padding,
|
||||||
|
scene.game.renderer.height / 2 + 50 - padding,
|
||||||
|
loadingBarWidth + padding * 2,
|
||||||
|
loadingBarHeight + padding * 2
|
||||||
|
);
|
||||||
|
|
||||||
scene.load.on('progress', (value: number) => {
|
scene.load.on("progress", (value: number) => {
|
||||||
progress.clear();
|
progress.clear();
|
||||||
progress.fillStyle(0xBBBBBB, 1);
|
progress.fillStyle(0xbbbbbb, 1);
|
||||||
progress.fillRect((scene.game.renderer.width - loadingBarWidth) / 2, scene.game.renderer.height / 2 + 50, loadingBarWidth * value, loadingBarHeight);
|
progress.fillRect(
|
||||||
|
(scene.game.renderer.width - loadingBarWidth) / 2,
|
||||||
|
scene.game.renderer.height / 2 + 50,
|
||||||
|
loadingBarWidth * value,
|
||||||
|
loadingBarHeight
|
||||||
|
);
|
||||||
});
|
});
|
||||||
scene.load.on('complete', () => {
|
scene.load.on("complete", () => {
|
||||||
if(loadingText){
|
if (loadingText) {
|
||||||
loadingText.destroy();
|
loadingText.destroy();
|
||||||
}
|
}
|
||||||
promiseLoadLogoTexture.then((resLoadingImage: Phaser.GameObjects.Image) => {
|
promiseLoadLogoTexture.then((resLoadingImage: Phaser.GameObjects.Image) => {
|
||||||
@ -50,5 +65,8 @@ export const addLoader = (scene: Phaser.Scene): void => {
|
|||||||
});
|
});
|
||||||
progress.destroy();
|
progress.destroy();
|
||||||
progressContainer.destroy();
|
progressContainer.destroy();
|
||||||
|
if (scene instanceof DirtyScene) {
|
||||||
|
scene.markDirty();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { GameScene } from "./GameScene";
|
import { GameScene } from "./GameScene";
|
||||||
import { connectionManager } from "../../Connexion/ConnectionManager";
|
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||||
import type { Room } from "../../Connexion/Room";
|
import type { Room } from "../../Connexion/Room";
|
||||||
import { MenuScene, MenuSceneName } from "../Menu/MenuScene";
|
|
||||||
import { LoginSceneName } from "../Login/LoginScene";
|
import { LoginSceneName } from "../Login/LoginScene";
|
||||||
import { SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
import { SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
||||||
import { EnableCameraSceneName } from "../Login/EnableCameraScene";
|
import { EnableCameraSceneName } from "../Login/EnableCameraScene";
|
||||||
@ -10,6 +9,7 @@ import { get } from "svelte/store";
|
|||||||
import { requestedCameraState, requestedMicrophoneState } from "../../Stores/MediaStore";
|
import { requestedCameraState, requestedMicrophoneState } from "../../Stores/MediaStore";
|
||||||
import { helpCameraSettingsVisibleStore } from "../../Stores/HelpCameraSettingsStore";
|
import { helpCameraSettingsVisibleStore } from "../../Stores/HelpCameraSettingsStore";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
|
import { menuIconVisiblilityStore } from "../../Stores/MenuStore";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class should be responsible for any scene starting/stopping
|
* This class should be responsible for any scene starting/stopping
|
||||||
@ -19,8 +19,9 @@ export class GameManager {
|
|||||||
private characterLayers: string[] | null;
|
private characterLayers: string[] | null;
|
||||||
private companion: string | null;
|
private companion: string | null;
|
||||||
private startRoom!: Room;
|
private startRoom!: Room;
|
||||||
private scenePlugin!: Phaser.Scenes.ScenePlugin;
|
|
||||||
currentGameSceneName: string | null = null;
|
currentGameSceneName: string | null = null;
|
||||||
|
// Note: this scenePlugin is the scenePlugin of the EntryScene. We should always provide a key in methods called on this scenePlugin.
|
||||||
|
private scenePlugin!: Phaser.Scenes.ScenePlugin;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.playerName = localUserStore.getName();
|
this.playerName = localUserStore.getName();
|
||||||
@ -89,7 +90,6 @@ export class GameManager {
|
|||||||
public goToStartingMap(): void {
|
public goToStartingMap(): void {
|
||||||
console.log("starting " + (this.currentGameSceneName || this.startRoom.key));
|
console.log("starting " + (this.currentGameSceneName || this.startRoom.key));
|
||||||
this.scenePlugin.start(this.currentGameSceneName || this.startRoom.key);
|
this.scenePlugin.start(this.currentGameSceneName || this.startRoom.key);
|
||||||
this.scenePlugin.launch(MenuSceneName);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!localUserStore.getHelpCameraSettingsShown() &&
|
!localUserStore.getHelpCameraSettingsShown() &&
|
||||||
@ -102,8 +102,7 @@ export class GameManager {
|
|||||||
|
|
||||||
public gameSceneIsCreated(scene: GameScene) {
|
public gameSceneIsCreated(scene: GameScene) {
|
||||||
this.currentGameSceneName = scene.scene.key;
|
this.currentGameSceneName = scene.scene.key;
|
||||||
const menuScene: MenuScene = scene.scene.get(MenuSceneName) as MenuScene;
|
menuIconVisiblilityStore.set(true);
|
||||||
menuScene.revealMenuIcon();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,7 +114,7 @@ export class GameManager {
|
|||||||
const gameScene: GameScene = this.scenePlugin.get(this.currentGameSceneName) as GameScene;
|
const gameScene: GameScene = this.scenePlugin.get(this.currentGameSceneName) as GameScene;
|
||||||
gameScene.cleanupClosingScene();
|
gameScene.cleanupClosingScene();
|
||||||
gameScene.createSuccessorGameScene(false, false);
|
gameScene.createSuccessorGameScene(false, false);
|
||||||
this.scenePlugin.sleep(MenuSceneName);
|
menuIconVisiblilityStore.set(false);
|
||||||
if (!this.scenePlugin.get(targetSceneName)) {
|
if (!this.scenePlugin.get(targetSceneName)) {
|
||||||
this.scenePlugin.add(targetSceneName, sceneClass, false);
|
this.scenePlugin.add(targetSceneName, sceneClass, false);
|
||||||
}
|
}
|
||||||
@ -128,7 +127,7 @@ export class GameManager {
|
|||||||
tryResumingGame(fallbackSceneName: string) {
|
tryResumingGame(fallbackSceneName: string) {
|
||||||
if (this.currentGameSceneName) {
|
if (this.currentGameSceneName) {
|
||||||
this.scenePlugin.start(this.currentGameSceneName);
|
this.scenePlugin.start(this.currentGameSceneName);
|
||||||
this.scenePlugin.wake(MenuSceneName);
|
menuIconVisiblilityStore.set(true);
|
||||||
} else {
|
} else {
|
||||||
this.scenePlugin.run(fallbackSceneName);
|
this.scenePlugin.run(fallbackSceneName);
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,6 @@ import type { ActionableItem } from "../Items/ActionableItem";
|
|||||||
import type { ItemFactoryInterface } from "../Items/ItemFactoryInterface";
|
import type { ItemFactoryInterface } from "../Items/ItemFactoryInterface";
|
||||||
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
||||||
import type { ITiledMap, ITiledMapLayer, ITiledMapProperty, ITiledMapObject, ITiledTileSet } from "../Map/ITiledMap";
|
import type { ITiledMap, ITiledMapLayer, ITiledMapProperty, ITiledMapObject, ITiledTileSet } from "../Map/ITiledMap";
|
||||||
import { MenuScene, MenuSceneName } from "../Menu/MenuScene";
|
|
||||||
import { PlayerAnimationDirections } from "../Player/Animation";
|
import { PlayerAnimationDirections } from "../Player/Animation";
|
||||||
import { hasMovedEventName, Player, requestEmoteEventName } from "../Player/Player";
|
import { hasMovedEventName, Player, requestEmoteEventName } from "../Player/Player";
|
||||||
import { ErrorSceneName } from "../Reconnecting/ErrorScene";
|
import { ErrorSceneName } from "../Reconnecting/ErrorScene";
|
||||||
@ -1359,9 +1358,6 @@ export class GameScene extends DirtyScene {
|
|||||||
urlManager.pushStartLayerNameToUrl(roomUrl.hash);
|
urlManager.pushStartLayerNameToUrl(roomUrl.hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
const menuScene: MenuScene = this.scene.get(MenuSceneName) as MenuScene;
|
|
||||||
menuScene.reset();
|
|
||||||
|
|
||||||
if (!targetRoom.isEqual(this.room)) {
|
if (!targetRoom.isEqual(this.room)) {
|
||||||
if (this.scene.get(targetRoom.key) === null) {
|
if (this.scene.get(targetRoom.key) === null) {
|
||||||
console.error("next room not loaded", targetRoom.key);
|
console.error("next room not loaded", targetRoom.key);
|
||||||
|
@ -1,13 +1,4 @@
|
|||||||
import { gameManager } from "../Game/GameManager";
|
import { gameManager } from "../Game/GameManager";
|
||||||
import { TextField } from "../Components/TextField";
|
|
||||||
import Image = Phaser.GameObjects.Image;
|
|
||||||
import { mediaManager } from "../../WebRtc/MediaManager";
|
|
||||||
import { SoundMeter } from "../Components/SoundMeter";
|
|
||||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
|
||||||
import { touchScreenManager } from "../../Touch/TouchScreenManager";
|
|
||||||
import { PinchManager } from "../UserInput/PinchManager";
|
|
||||||
import Zone = Phaser.GameObjects.Zone;
|
|
||||||
import { MenuScene } from "../Menu/MenuScene";
|
|
||||||
import { ResizableScene } from "./ResizableScene";
|
import { ResizableScene } from "./ResizableScene";
|
||||||
import { enableCameraSceneVisibilityStore } from "../../Stores/MediaStore";
|
import { enableCameraSceneVisibilityStore } from "../../Stores/MediaStore";
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ import type { CompanionResourceDescriptionInterface } from "../Companion/Compani
|
|||||||
import { getAllCompanionResources } from "../Companion/CompanionTexturesLoadingManager";
|
import { getAllCompanionResources } from "../Companion/CompanionTexturesLoadingManager";
|
||||||
import { touchScreenManager } from "../../Touch/TouchScreenManager";
|
import { touchScreenManager } from "../../Touch/TouchScreenManager";
|
||||||
import { PinchManager } from "../UserInput/PinchManager";
|
import { PinchManager } from "../UserInput/PinchManager";
|
||||||
import { MenuScene } from "../Menu/MenuScene";
|
|
||||||
import { selectCompanionSceneVisibleStore } from "../../Stores/SelectCompanionStore";
|
import { selectCompanionSceneVisibleStore } from "../../Stores/SelectCompanionStore";
|
||||||
import { waScaleManager } from "../Services/WaScaleManager";
|
import { waScaleManager } from "../Services/WaScaleManager";
|
||||||
import { isMobile } from "../../Enum/EnvironmentVariable";
|
import { isMobile } from "../../Enum/EnvironmentVariable";
|
||||||
|
@ -1,430 +0,0 @@
|
|||||||
import { LoginScene, LoginSceneName } from "../Login/LoginScene";
|
|
||||||
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
|
||||||
import { SelectCompanionScene, SelectCompanionSceneName } from "../Login/SelectCompanionScene";
|
|
||||||
import { gameManager } from "../Game/GameManager";
|
|
||||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
|
||||||
import { gameReportKey, gameReportRessource, ReportMenu } from "./ReportMenu";
|
|
||||||
import { connectionManager } from "../../Connexion/ConnectionManager";
|
|
||||||
import { GameConnexionTypes } from "../../Url/UrlManager";
|
|
||||||
import { menuIconVisible } from "../../Stores/MenuStore";
|
|
||||||
import { videoConstraintStore } from "../../Stores/MediaStore";
|
|
||||||
import { showReportScreenStore } from "../../Stores/ShowReportScreenStore";
|
|
||||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
|
||||||
import { iframeListener } from "../../Api/IframeListener";
|
|
||||||
import { Subscription } from "rxjs";
|
|
||||||
import { registerMenuCommandStream } from "../../Api/Events/ui/MenuItemRegisterEvent";
|
|
||||||
import { sendMenuClickedEvent } from "../../Api/iframe/Ui/MenuItem";
|
|
||||||
import { consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
|
|
||||||
import { get } from "svelte/store";
|
|
||||||
import { playersStore } from "../../Stores/PlayersStore";
|
|
||||||
import { mediaManager } from "../../WebRtc/MediaManager";
|
|
||||||
import { chatVisibilityStore } from "../../Stores/ChatStore";
|
|
||||||
import { ADMIN_URL } from "../../Enum/EnvironmentVariable";
|
|
||||||
|
|
||||||
export const MenuSceneName = "MenuScene";
|
|
||||||
const gameMenuKey = "gameMenu";
|
|
||||||
const gameMenuIconKey = "gameMenuIcon";
|
|
||||||
const gameSettingsMenuKey = "gameSettingsMenu";
|
|
||||||
const gameShare = "gameShare";
|
|
||||||
|
|
||||||
const closedSideMenuX = -1000;
|
|
||||||
const openedSideMenuX = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The scene that manages the game menu, rendered using a DOM element.
|
|
||||||
*/
|
|
||||||
export class MenuScene extends Phaser.Scene {
|
|
||||||
private menuElement!: Phaser.GameObjects.DOMElement;
|
|
||||||
private gameQualityMenuElement!: Phaser.GameObjects.DOMElement;
|
|
||||||
private gameShareElement!: Phaser.GameObjects.DOMElement;
|
|
||||||
private gameReportElement!: ReportMenu;
|
|
||||||
private sideMenuOpened = false;
|
|
||||||
private settingsMenuOpened = false;
|
|
||||||
private gameShareOpened = false;
|
|
||||||
private gameQualityValue: number;
|
|
||||||
private videoQualityValue: number;
|
|
||||||
private menuButton!: Phaser.GameObjects.DOMElement;
|
|
||||||
private subscriptions = new Subscription();
|
|
||||||
constructor() {
|
|
||||||
super({ key: MenuSceneName });
|
|
||||||
|
|
||||||
this.gameQualityValue = localUserStore.getGameQualityValue();
|
|
||||||
this.videoQualityValue = localUserStore.getVideoQualityValue();
|
|
||||||
|
|
||||||
this.subscriptions.add(
|
|
||||||
registerMenuCommandStream.subscribe((menuCommand) => {
|
|
||||||
this.addMenuOption(menuCommand);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
this.subscriptions.add(
|
|
||||||
iframeListener.unregisterMenuCommandStream.subscribe((menuCommand) => {
|
|
||||||
this.destroyMenu(menuCommand);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
const addedMenuItems = [...this.menuElement.node.querySelectorAll(".fromApi")];
|
|
||||||
for (let index = addedMenuItems.length - 1; index >= 0; index--) {
|
|
||||||
addedMenuItems[index].remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public addMenuOption(menuText: string) {
|
|
||||||
const wrappingSection = document.createElement("section");
|
|
||||||
const escapedHtml = HtmlUtils.escapeHtml(menuText);
|
|
||||||
wrappingSection.innerHTML = `<button class="fromApi" id="${escapedHtml}">${escapedHtml}</button>`;
|
|
||||||
const menuItemContainer = this.menuElement.node.querySelector("#gameMenu main");
|
|
||||||
if (menuItemContainer) {
|
|
||||||
menuItemContainer.querySelector(`#${escapedHtml}.fromApi`)?.remove();
|
|
||||||
menuItemContainer.insertBefore(wrappingSection, menuItemContainer.querySelector("#socialLinks"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
preload() {
|
|
||||||
this.load.html(gameMenuKey, "resources/html/gameMenu.html");
|
|
||||||
this.load.html(gameMenuIconKey, "resources/html/gameMenuIcon.html");
|
|
||||||
this.load.html(gameSettingsMenuKey, "resources/html/gameQualityMenu.html");
|
|
||||||
this.load.html(gameShare, "resources/html/gameShare.html");
|
|
||||||
this.load.html(gameReportKey, gameReportRessource);
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
menuIconVisible.set(true);
|
|
||||||
this.menuElement = this.add.dom(closedSideMenuX, 30).createFromCache(gameMenuKey);
|
|
||||||
this.menuElement.setOrigin(0);
|
|
||||||
MenuScene.revealMenusAfterInit(this.menuElement, "gameMenu");
|
|
||||||
|
|
||||||
if (mediaManager.hasNotification()) {
|
|
||||||
HtmlUtils.getElementByIdOrFail("enableNotification").hidden = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const middleX = window.innerWidth / 3 - 298;
|
|
||||||
this.gameQualityMenuElement = this.add.dom(middleX, -400).createFromCache(gameSettingsMenuKey);
|
|
||||||
MenuScene.revealMenusAfterInit(this.gameQualityMenuElement, "gameQuality");
|
|
||||||
|
|
||||||
this.gameShareElement = this.add.dom(middleX, -400).createFromCache(gameShare);
|
|
||||||
MenuScene.revealMenusAfterInit(this.gameShareElement, gameShare);
|
|
||||||
this.gameShareElement.addListener("click");
|
|
||||||
this.gameShareElement.on("click", (event: MouseEvent) => {
|
|
||||||
event.preventDefault();
|
|
||||||
if ((event?.target as HTMLInputElement).id === "gameShareFormSubmit") {
|
|
||||||
this.copyLink();
|
|
||||||
} else if ((event?.target as HTMLInputElement).id === "gameShareFormCancel") {
|
|
||||||
this.closeGameShare();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.gameReportElement = new ReportMenu(
|
|
||||||
this,
|
|
||||||
connectionManager.getConnexionType === GameConnexionTypes.anonymous
|
|
||||||
);
|
|
||||||
showReportScreenStore.subscribe((user) => {
|
|
||||||
if (user !== null) {
|
|
||||||
this.closeAll();
|
|
||||||
const uuid = playersStore.getPlayerById(user.userId)?.userUuid;
|
|
||||||
if (uuid === undefined) {
|
|
||||||
throw new Error("Could not find UUID for user with ID " + user.userId);
|
|
||||||
}
|
|
||||||
this.gameReportElement.open(uuid, user.userName);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.input.keyboard.on("keyup-TAB", () => {
|
|
||||||
this.sideMenuOpened ? this.closeSideMenu() : this.openSideMenu();
|
|
||||||
});
|
|
||||||
this.menuButton = this.add.dom(0, 0).createFromCache(gameMenuIconKey);
|
|
||||||
this.menuButton.addListener("click");
|
|
||||||
this.menuButton.on("click", () => {
|
|
||||||
this.sideMenuOpened ? this.closeSideMenu() : this.openSideMenu();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.menuElement.addListener("click");
|
|
||||||
this.menuElement.on("click", this.onMenuClick.bind(this));
|
|
||||||
|
|
||||||
chatVisibilityStore.subscribe((v) => {
|
|
||||||
this.menuButton.setVisible(!v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//todo put this method in a parent menuElement class
|
|
||||||
static revealMenusAfterInit(menuElement: Phaser.GameObjects.DOMElement, rootDomId: string) {
|
|
||||||
//Dom elements will appear inside the viewer screen when creating before being moved out of it, which create a flicker effect.
|
|
||||||
//To prevent this, we put a 'hidden' attribute on the root element, we remove it only after the init is done.
|
|
||||||
setTimeout(() => {
|
|
||||||
(menuElement.getChildByID(rootDomId) as HTMLElement).hidden = false;
|
|
||||||
}, 250);
|
|
||||||
}
|
|
||||||
|
|
||||||
public revealMenuIcon(): void {
|
|
||||||
//TODO fix me: add try catch because at the same time, 'this.menuButton' variable doesn't exist and there is error on 'getChildByID' function
|
|
||||||
try {
|
|
||||||
(this.menuButton.getChildByID("menuIcon") as HTMLElement).hidden = false;
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
openSideMenu() {
|
|
||||||
if (this.sideMenuOpened) return;
|
|
||||||
this.closeAll();
|
|
||||||
this.sideMenuOpened = true;
|
|
||||||
this.menuButton.getChildByID("openMenuButton").innerHTML = "X";
|
|
||||||
const connection = gameManager.getCurrentGameScene().connection;
|
|
||||||
if (connection && connection.isAdmin()) {
|
|
||||||
const adminSection = this.menuElement.getChildByID("adminConsoleSection") as HTMLElement;
|
|
||||||
adminSection.hidden = false;
|
|
||||||
}
|
|
||||||
//TODO bind with future metadata of card
|
|
||||||
//if (connectionManager.getConnexionType === GameConnexionTypes.anonymous){
|
|
||||||
const adminSection = this.menuElement.getChildByID("socialLinks") as HTMLElement;
|
|
||||||
adminSection.hidden = false;
|
|
||||||
//}
|
|
||||||
this.tweens.add({
|
|
||||||
targets: this.menuElement,
|
|
||||||
x: openedSideMenuX,
|
|
||||||
duration: 500,
|
|
||||||
ease: "Power3",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private closeSideMenu(): void {
|
|
||||||
if (!this.sideMenuOpened) return;
|
|
||||||
this.sideMenuOpened = false;
|
|
||||||
this.closeAll();
|
|
||||||
this.menuButton.getChildByID("openMenuButton").innerHTML = `<img src="/static/images/menu.svg">`;
|
|
||||||
consoleGlobalMessageManagerVisibleStore.set(false);
|
|
||||||
this.tweens.add({
|
|
||||||
targets: this.menuElement,
|
|
||||||
x: closedSideMenuX,
|
|
||||||
duration: 500,
|
|
||||||
ease: "Power3",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private openGameSettingsMenu(): void {
|
|
||||||
if (this.settingsMenuOpened) {
|
|
||||||
this.closeGameQualityMenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//close all
|
|
||||||
this.closeAll();
|
|
||||||
|
|
||||||
this.settingsMenuOpened = true;
|
|
||||||
|
|
||||||
const gameQualitySelect = this.gameQualityMenuElement.getChildByID("select-game-quality") as HTMLInputElement;
|
|
||||||
gameQualitySelect.value = "" + this.gameQualityValue;
|
|
||||||
const videoQualitySelect = this.gameQualityMenuElement.getChildByID("select-video-quality") as HTMLInputElement;
|
|
||||||
videoQualitySelect.value = "" + this.videoQualityValue;
|
|
||||||
|
|
||||||
this.gameQualityMenuElement.addListener("click");
|
|
||||||
this.gameQualityMenuElement.on("click", (event: MouseEvent) => {
|
|
||||||
event.preventDefault();
|
|
||||||
if ((event?.target as HTMLInputElement).id === "gameQualityFormSubmit") {
|
|
||||||
const gameQualitySelect = this.gameQualityMenuElement.getChildByID(
|
|
||||||
"select-game-quality"
|
|
||||||
) as HTMLInputElement;
|
|
||||||
const videoQualitySelect = this.gameQualityMenuElement.getChildByID(
|
|
||||||
"select-video-quality"
|
|
||||||
) as HTMLInputElement;
|
|
||||||
this.saveSetting(parseInt(gameQualitySelect.value), parseInt(videoQualitySelect.value));
|
|
||||||
} else if ((event?.target as HTMLInputElement).id === "gameQualityFormCancel") {
|
|
||||||
this.closeGameQualityMenu();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let middleY = this.scale.height / 2 - 392 / 2;
|
|
||||||
if (middleY < 0) {
|
|
||||||
middleY = 0;
|
|
||||||
}
|
|
||||||
let middleX = this.scale.width / 2 - 457 / 2;
|
|
||||||
if (middleX < 0) {
|
|
||||||
middleX = 0;
|
|
||||||
}
|
|
||||||
this.tweens.add({
|
|
||||||
targets: this.gameQualityMenuElement,
|
|
||||||
y: middleY,
|
|
||||||
x: middleX,
|
|
||||||
duration: 1000,
|
|
||||||
ease: "Power3",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private closeGameQualityMenu(): void {
|
|
||||||
if (!this.settingsMenuOpened) return;
|
|
||||||
this.settingsMenuOpened = false;
|
|
||||||
|
|
||||||
this.gameQualityMenuElement.removeListener("click");
|
|
||||||
this.tweens.add({
|
|
||||||
targets: this.gameQualityMenuElement,
|
|
||||||
y: -400,
|
|
||||||
duration: 1000,
|
|
||||||
ease: "Power3",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private openGameShare(): void {
|
|
||||||
if (this.gameShareOpened) {
|
|
||||||
this.closeGameShare();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//close all
|
|
||||||
this.closeAll();
|
|
||||||
|
|
||||||
const gameShareLink = this.gameShareElement.getChildByID("gameShareLink") as HTMLInputElement;
|
|
||||||
gameShareLink.value = location.toString();
|
|
||||||
|
|
||||||
this.gameShareOpened = true;
|
|
||||||
|
|
||||||
let middleY = this.scale.height / 2 - 85;
|
|
||||||
if (middleY < 0) {
|
|
||||||
middleY = 0;
|
|
||||||
}
|
|
||||||
let middleX = this.scale.width / 2 - 200;
|
|
||||||
if (middleX < 0) {
|
|
||||||
middleX = 0;
|
|
||||||
}
|
|
||||||
this.tweens.add({
|
|
||||||
targets: this.gameShareElement,
|
|
||||||
y: middleY,
|
|
||||||
x: middleX,
|
|
||||||
duration: 1000,
|
|
||||||
ease: "Power3",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private closeGameShare(): void {
|
|
||||||
const gameShareInfo = this.gameShareElement.getChildByID("gameShareInfo") as HTMLParagraphElement;
|
|
||||||
gameShareInfo.innerText = "";
|
|
||||||
gameShareInfo.style.display = "none";
|
|
||||||
this.gameShareOpened = false;
|
|
||||||
this.tweens.add({
|
|
||||||
targets: this.gameShareElement,
|
|
||||||
y: -400,
|
|
||||||
duration: 1000,
|
|
||||||
ease: "Power3",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private onMenuClick(event: MouseEvent) {
|
|
||||||
const htmlMenuItem = event?.target as HTMLInputElement;
|
|
||||||
if (htmlMenuItem.classList.contains("not-button")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
if (htmlMenuItem.classList.contains("fromApi")) {
|
|
||||||
sendMenuClickedEvent(htmlMenuItem.id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ((event?.target as HTMLInputElement).id) {
|
|
||||||
case "changeNameButton":
|
|
||||||
this.closeSideMenu();
|
|
||||||
gameManager.leaveGame(LoginSceneName, new LoginScene());
|
|
||||||
break;
|
|
||||||
case "sparkButton":
|
|
||||||
this.gotToCreateMapPage();
|
|
||||||
break;
|
|
||||||
case "changeSkinButton":
|
|
||||||
this.closeSideMenu();
|
|
||||||
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
|
|
||||||
break;
|
|
||||||
case "changeCompanionButton":
|
|
||||||
this.closeSideMenu();
|
|
||||||
gameManager.leaveGame(SelectCompanionSceneName, new SelectCompanionScene());
|
|
||||||
break;
|
|
||||||
case "closeButton":
|
|
||||||
this.closeSideMenu();
|
|
||||||
break;
|
|
||||||
case "shareButton":
|
|
||||||
this.openGameShare();
|
|
||||||
break;
|
|
||||||
case "editGameSettingsButton":
|
|
||||||
this.openGameSettingsMenu();
|
|
||||||
break;
|
|
||||||
case "oidcLogin":
|
|
||||||
connectionManager.loadOpenIDScreen();
|
|
||||||
break;
|
|
||||||
case "toggleFullscreen":
|
|
||||||
this.toggleFullscreen();
|
|
||||||
break;
|
|
||||||
case "enableNotification":
|
|
||||||
this.enableNotification();
|
|
||||||
break;
|
|
||||||
case "adminConsoleButton":
|
|
||||||
if (get(consoleGlobalMessageManagerVisibleStore)) {
|
|
||||||
consoleGlobalMessageManagerVisibleStore.set(false);
|
|
||||||
} else {
|
|
||||||
consoleGlobalMessageManagerVisibleStore.set(true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async copyLink() {
|
|
||||||
await navigator.clipboard.writeText(location.toString());
|
|
||||||
const gameShareInfo = this.gameShareElement.getChildByID("gameShareInfo") as HTMLParagraphElement;
|
|
||||||
gameShareInfo.innerText = "Link copied, you can share it now!";
|
|
||||||
gameShareInfo.style.display = "block";
|
|
||||||
}
|
|
||||||
|
|
||||||
private saveSetting(valueGame: number, valueVideo: number) {
|
|
||||||
if (valueGame !== this.gameQualityValue) {
|
|
||||||
this.gameQualityValue = valueGame;
|
|
||||||
localUserStore.setGameQualityValue(valueGame);
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
if (valueVideo !== this.videoQualityValue) {
|
|
||||||
this.videoQualityValue = valueVideo;
|
|
||||||
localUserStore.setVideoQualityValue(valueVideo);
|
|
||||||
videoConstraintStore.setFrameRate(valueVideo);
|
|
||||||
}
|
|
||||||
this.closeGameQualityMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
private gotToCreateMapPage() {
|
|
||||||
//const sparkHost = 'https://'+window.location.host.replace('play.', '')+'/choose-map.html';
|
|
||||||
//TODO fix me: this button can to send us on WorkAdventure BO.
|
|
||||||
//const sparkHost = ADMIN_URL + "/getting-started";
|
|
||||||
|
|
||||||
//The redirection must be only on workadventu.re domain
|
|
||||||
//To day the domain staging cannot be use by customer
|
|
||||||
const sparkHost = "https://workadventu.re/getting-started";
|
|
||||||
window.open(sparkHost, "_blank");
|
|
||||||
}
|
|
||||||
|
|
||||||
private closeAll() {
|
|
||||||
this.closeGameQualityMenu();
|
|
||||||
this.closeGameShare();
|
|
||||||
this.gameReportElement.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private toggleFullscreen() {
|
|
||||||
const body = document.querySelector("body");
|
|
||||||
if (body) {
|
|
||||||
if (document.fullscreenElement ?? document.fullscreen) {
|
|
||||||
document.exitFullscreen();
|
|
||||||
} else {
|
|
||||||
body.requestFullscreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroyMenu(menu: string) {
|
|
||||||
this.menuElement.getChildByID(menu).remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
public isDirty(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private enableNotification() {
|
|
||||||
mediaManager.requestNotification().then(() => {
|
|
||||||
if (mediaManager.hasNotification()) {
|
|
||||||
HtmlUtils.getElementByIdOrFail("enableNotification").hidden = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
import { MenuScene } from "./MenuScene";
|
|
||||||
import { gameManager } from "../Game/GameManager";
|
|
||||||
import { blackListManager } from "../../WebRtc/BlackListManager";
|
|
||||||
import { playersStore } from "../../Stores/PlayersStore";
|
|
||||||
|
|
||||||
export const gameReportKey = "gameReport";
|
|
||||||
export const gameReportRessource = "resources/html/gameReport.html";
|
|
||||||
|
|
||||||
export class ReportMenu extends Phaser.GameObjects.DOMElement {
|
|
||||||
private opened: boolean = false;
|
|
||||||
|
|
||||||
private userUuid!: string;
|
|
||||||
private userName!: string | undefined;
|
|
||||||
private anonymous: boolean;
|
|
||||||
|
|
||||||
constructor(scene: Phaser.Scene, anonymous: boolean) {
|
|
||||||
super(scene, -2000, -2000);
|
|
||||||
this.anonymous = anonymous;
|
|
||||||
this.createFromCache(gameReportKey);
|
|
||||||
|
|
||||||
if (this.anonymous) {
|
|
||||||
const divToHide = this.getChildByID("reportSection") as HTMLElement;
|
|
||||||
divToHide.hidden = true;
|
|
||||||
const textToHide = this.getChildByID("askActionP") as HTMLElement;
|
|
||||||
textToHide.hidden = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
scene.add.existing(this);
|
|
||||||
MenuScene.revealMenusAfterInit(this, gameReportKey);
|
|
||||||
|
|
||||||
this.addListener("click");
|
|
||||||
this.on("click", (event: MouseEvent) => {
|
|
||||||
event.preventDefault();
|
|
||||||
if ((event?.target as HTMLInputElement).id === "gameReportFormSubmit") {
|
|
||||||
this.submitReport();
|
|
||||||
} else if ((event?.target as HTMLInputElement).id === "gameReportFormCancel") {
|
|
||||||
this.close();
|
|
||||||
} else if ((event?.target as HTMLInputElement).id === "toggleBlockButton") {
|
|
||||||
this.toggleBlock();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public open(userUuid: string, userName: string | undefined): void {
|
|
||||||
if (this.opened) {
|
|
||||||
this.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.userUuid = userUuid;
|
|
||||||
this.userName = userName;
|
|
||||||
|
|
||||||
const mainEl = this.getChildByID("gameReport") as HTMLElement;
|
|
||||||
this.x = this.getCenteredX(mainEl);
|
|
||||||
this.y = this.getHiddenY(mainEl);
|
|
||||||
|
|
||||||
const gameTitleReport = this.getChildByID("nameReported") as HTMLElement;
|
|
||||||
gameTitleReport.innerText = userName || "";
|
|
||||||
|
|
||||||
const blockButton = this.getChildByID("toggleBlockButton") as HTMLElement;
|
|
||||||
blockButton.innerText = blackListManager.isBlackListed(this.userUuid) ? "Unblock this user" : "Block this user";
|
|
||||||
|
|
||||||
this.opened = true;
|
|
||||||
|
|
||||||
gameManager.getCurrentGameScene().userInputManager.disableControls();
|
|
||||||
|
|
||||||
this.scene.tweens.add({
|
|
||||||
targets: this,
|
|
||||||
y: this.getCenteredY(mainEl),
|
|
||||||
duration: 1000,
|
|
||||||
ease: "Power3",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public close(): void {
|
|
||||||
gameManager.getCurrentGameScene().userInputManager.restoreControls();
|
|
||||||
this.opened = false;
|
|
||||||
const mainEl = this.getChildByID("gameReport") as HTMLElement;
|
|
||||||
this.scene.tweens.add({
|
|
||||||
targets: this,
|
|
||||||
y: this.getHiddenY(mainEl),
|
|
||||||
duration: 1000,
|
|
||||||
ease: "Power3",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//todo: into a parent class?
|
|
||||||
private getCenteredX(mainEl: HTMLElement): number {
|
|
||||||
return window.innerWidth / 4 - mainEl.clientWidth / 2;
|
|
||||||
}
|
|
||||||
private getHiddenY(mainEl: HTMLElement): number {
|
|
||||||
return -mainEl.clientHeight - 50;
|
|
||||||
}
|
|
||||||
private getCenteredY(mainEl: HTMLElement): number {
|
|
||||||
return window.innerHeight / 4 - mainEl.clientHeight / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
private toggleBlock(): void {
|
|
||||||
!blackListManager.isBlackListed(this.userUuid)
|
|
||||||
? blackListManager.blackList(this.userUuid)
|
|
||||||
: blackListManager.cancelBlackList(this.userUuid);
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private submitReport(): void {
|
|
||||||
const gamePError = this.getChildByID("gameReportErr") as HTMLParagraphElement;
|
|
||||||
gamePError.innerText = "";
|
|
||||||
gamePError.style.display = "none";
|
|
||||||
const gameTextArea = this.getChildByID("gameReportInput") as HTMLInputElement;
|
|
||||||
if (!gameTextArea || !gameTextArea.value) {
|
|
||||||
gamePError.innerText = "Report message cannot to be empty.";
|
|
||||||
gamePError.style.display = "block";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gameManager.getCurrentGameScene().connection?.emitReportPlayerMessage(this.userUuid, gameTextArea.value);
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
}
|
|
@ -170,7 +170,7 @@ function createVideoConstraintStore() {
|
|||||||
setFrameRate: (frameRate: number) =>
|
setFrameRate: (frameRate: number) =>
|
||||||
update((constraints) => {
|
update((constraints) => {
|
||||||
constraints.frameRate = { ideal: frameRate };
|
constraints.frameRate = { ideal: frameRate };
|
||||||
|
localUserStore.setVideoQualityValue(frameRate);
|
||||||
return constraints;
|
return constraints;
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { writable } from "svelte/store";
|
import { get, writable } from "svelte/store";
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
|
import { userIsAdminStore } from "./GameStore";
|
||||||
|
import { CONTACT_URL } from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
export const menuIconVisible = writable(false);
|
export const menuIconVisiblilityStore = writable(false);
|
||||||
|
export const menuVisiblilityStore = writable(false);
|
||||||
|
export const menuInputFocusStore = writable(false);
|
||||||
|
|
||||||
let warningContainerTimeout: Timeout | null = null;
|
let warningContainerTimeout: Timeout | null = null;
|
||||||
function createWarningContainerStore() {
|
function createWarningContainerStore() {
|
||||||
@ -21,3 +25,58 @@ function createWarningContainerStore() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const warningContainerStore = createWarningContainerStore();
|
export const warningContainerStore = createWarningContainerStore();
|
||||||
|
|
||||||
|
export enum SubMenusInterface {
|
||||||
|
settings = "Settings",
|
||||||
|
profile = "Profile",
|
||||||
|
createMap = "Create a Map",
|
||||||
|
aboutRoom = "About the Room",
|
||||||
|
globalMessages = "Global Messages",
|
||||||
|
contact = "Contact",
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSubMenusStore() {
|
||||||
|
const { subscribe, update } = writable<string[]>([
|
||||||
|
SubMenusInterface.settings,
|
||||||
|
SubMenusInterface.profile,
|
||||||
|
SubMenusInterface.createMap,
|
||||||
|
SubMenusInterface.aboutRoom,
|
||||||
|
SubMenusInterface.globalMessages,
|
||||||
|
SubMenusInterface.contact,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
addMenu(menuCommand: string) {
|
||||||
|
update((menuList: string[]) => {
|
||||||
|
if (!menuList.find((menu) => menu === menuCommand)) {
|
||||||
|
menuList.push(menuCommand);
|
||||||
|
}
|
||||||
|
return menuList;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeMenu(menuCommand: string) {
|
||||||
|
update((menuList: string[]) => {
|
||||||
|
const index = menuList.findIndex((menu) => menu === menuCommand);
|
||||||
|
if (index !== -1) {
|
||||||
|
menuList.splice(index, 1);
|
||||||
|
}
|
||||||
|
return menuList;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const subMenusStore = createSubMenusStore();
|
||||||
|
|
||||||
|
function checkSubMenuToShow() {
|
||||||
|
if (!get(userIsAdminStore)) {
|
||||||
|
subMenusStore.removeMenu(SubMenusInterface.globalMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CONTACT_URL === undefined) {
|
||||||
|
subMenusStore.removeMenu(SubMenusInterface.contact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkSubMenuToShow();
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
export const showReportScreenStore = writable<{ userId: number; userName: string } | null>(null);
|
export const userReportEmpty = {
|
||||||
|
userId: 0,
|
||||||
|
userName: "Empty",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const showReportScreenStore = writable<{ userId: number; userName: string }>(userReportEmpty);
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { derived } from "svelte/store";
|
import { derived } from "svelte/store";
|
||||||
import { consoleGlobalMessageManagerFocusStore } from "./ConsoleGlobalMessageManagerStore";
|
import { menuInputFocusStore } from "./MenuStore";
|
||||||
import { chatInputFocusStore } from "./ChatStore";
|
import { chatInputFocusStore } from "./ChatStore";
|
||||||
|
|
||||||
//derived from the focus on Menu, ConsoleGlobal, Chat and ...
|
//derived from the focus on Menu, ConsoleGlobal, Chat and ...
|
||||||
export const enableUserInputsStore = derived(
|
export const enableUserInputsStore = derived(
|
||||||
[consoleGlobalMessageManagerFocusStore, chatInputFocusStore],
|
[menuInputFocusStore, chatInputFocusStore],
|
||||||
([$consoleGlobalMessageManagerFocusStore, $chatInputFocusStore]) => {
|
([$menuInputFocusStore, $chatInputFocusStore]) => {
|
||||||
return !$consoleGlobalMessageManagerFocusStore && !$chatInputFocusStore;
|
return !$menuInputFocusStore && !$chatInputFocusStore;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -11,6 +11,7 @@ import { cowebsiteCloseButtonId } from "./CoWebsiteManager";
|
|||||||
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
|
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
|
||||||
import { layoutManagerActionStore, layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore";
|
import { layoutManagerActionStore, layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
import { localUserStore } from "../Connexion/LocalUserStore";
|
||||||
|
|
||||||
export class MediaManager {
|
export class MediaManager {
|
||||||
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
||||||
@ -187,7 +188,11 @@ export class MediaManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public hasNotification(): boolean {
|
public hasNotification(): boolean {
|
||||||
return Notification.permission === "granted";
|
if (Notification.permission === "granted") {
|
||||||
|
return localUserStore.getNotification() === "granted";
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public requestNotification() {
|
public requestNotification() {
|
||||||
|
@ -13,7 +13,6 @@ import WebFontLoaderPlugin from "phaser3-rex-plugins/plugins/webfontloader-plugi
|
|||||||
import OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js";
|
import OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js";
|
||||||
import { EntryScene } from "./Phaser/Login/EntryScene";
|
import { EntryScene } from "./Phaser/Login/EntryScene";
|
||||||
import { coWebsiteManager } from "./WebRtc/CoWebsiteManager";
|
import { coWebsiteManager } from "./WebRtc/CoWebsiteManager";
|
||||||
import { MenuScene } from "./Phaser/Menu/MenuScene";
|
|
||||||
import { localUserStore } from "./Connexion/LocalUserStore";
|
import { localUserStore } from "./Connexion/LocalUserStore";
|
||||||
import { ErrorScene } from "./Phaser/Reconnecting/ErrorScene";
|
import { ErrorScene } from "./Phaser/Reconnecting/ErrorScene";
|
||||||
import { iframeListener } from "./Api/IframeListener";
|
import { iframeListener } from "./Api/IframeListener";
|
||||||
@ -97,7 +96,6 @@ const config: GameConfig = {
|
|||||||
ReconnectingScene,
|
ReconnectingScene,
|
||||||
ErrorScene,
|
ErrorScene,
|
||||||
CustomizeScene,
|
CustomizeScene,
|
||||||
MenuScene,
|
|
||||||
],
|
],
|
||||||
//resolution: window.devicePixelRatio / 2,
|
//resolution: window.devicePixelRatio / 2,
|
||||||
fps: fps,
|
fps: fps,
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
//InputTextGlobalMessage
|
//TextGlobalMessage
|
||||||
section.section-input-send-text {
|
section.section-input-send-text {
|
||||||
|
--height-toolbar: 15%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.ql-toolbar{
|
.ql-toolbar{
|
||||||
max-height: 100px;
|
height: var(--height-toolbar);
|
||||||
|
|
||||||
background: whitesmoke;
|
background: whitesmoke;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.input-send-text{
|
div.input-send-text{
|
||||||
height: calc(100% - 100px);
|
height: calc(100% - var(--height-toolbar));
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
@ -29,3 +29,13 @@ section.section-input-send-text {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||||
|
section.section-input-send-text {
|
||||||
|
--height-toolbar: 30%;
|
||||||
|
|
||||||
|
.ql-toolbar {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,4 +5,4 @@
|
|||||||
@import "style";
|
@import "style";
|
||||||
@import "mobile-style.scss";
|
@import "mobile-style.scss";
|
||||||
@import "fonts.scss";
|
@import "fonts.scss";
|
||||||
@import "inputTextGlobalMessageSvelte-Style.scss";
|
@import "TextGlobalMessageSvelte-Style";
|
||||||
|
@ -190,6 +190,7 @@ module.exports = {
|
|||||||
PUSHER_URL: undefined,
|
PUSHER_URL: undefined,
|
||||||
UPLOADER_URL: null,
|
UPLOADER_URL: null,
|
||||||
ADMIN_URL: undefined,
|
ADMIN_URL: undefined,
|
||||||
|
CONTACT_URL: null,
|
||||||
DEBUG_MODE: null,
|
DEBUG_MODE: null,
|
||||||
STUN_SERVER: null,
|
STUN_SERVER: null,
|
||||||
TURN_SERVER: null,
|
TURN_SERVER: null,
|
||||||
|
Loading…
Reference in New Issue
Block a user