New menu svelte

This commit is contained in:
GRL 2021-08-09 14:49:17 +02:00
parent 2cd5b7f0a8
commit 56fa2e49f6
28 changed files with 685 additions and 477 deletions

View file

@ -1,6 +1,6 @@
<script lang="typescript">
import MenuIcon from "./Menu/MenuIcon.svelte";
import {menuIconVisible, menuVisible} from "../Stores/MenuStore";
import {menuIconVisiblilityStore, menuVisiblilityStore} from "../Stores/MenuStore";
import {enableCameraSceneVisibilityStore} from "../Stores/MediaStore";
import CameraControls from "./CameraControls.svelte";
import MyCamera from "./MyCamera.svelte";
@ -28,8 +28,6 @@
import Menu from "./Menu/Menu.svelte";
import VideoOverlay from "./Video/VideoOverlay.svelte";
import {gameOverlayVisibilityStore} from "../Stores/GameOverlayStoreVisibility";
import {consoleGlobalMessageManagerVisibleStore} from "../Stores/ConsoleGlobalMessageManagerStore";
import ConsoleGlobalMessageManager from "./ConsoleGlobalMessageManager/ConsoleGlobalMessageManager.svelte";
import AdminMessage from "./TypeMessage/BanMessage.svelte";
import TextMessage from "./TypeMessage/TextMessage.svelte";
import {banMessageVisibleStore} from "../Stores/TypeMessageStore/BanMessageStore";
@ -89,19 +87,16 @@
<LayoutManager></LayoutManager>
</div>
{/if}
{#if $menuIconVisible}
{#if $menuIconVisiblilityStore}
<div>
<MenuIcon></MenuIcon>
</div>
{/if}
{#if $menuVisible}
{#if $menuVisiblilityStore}
<div>
<Menu></Menu>
</div>
{/if}
{#if $gameOverlayVisibilityStore}
<div>
<VideoOverlay></VideoOverlay>
@ -109,11 +104,6 @@
<CameraControls></CameraControls>
</div>
{/if}
{#if $consoleGlobalMessageManagerVisibleStore}
<div>
<ConsoleGlobalMessageManager></ConsoleGlobalMessageManager>
</div>
{/if}
{#if $helpCameraSettingsVisibleStore}
<div>
<HelpCameraSettingsPopup></HelpCameraSettingsPopup>

View file

@ -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>

View file

@ -0,0 +1,123 @@
<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 = 'The map has not a name.';
let mapDescription: string = "The creator of the map didn't use the property to describe the map.";
let mapCopyright: string = "There is not copyright and this 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');
}
</script>
<div class="about-room-main">
<section class="share-url">
<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="presentation-map">
<p>This room use this map : </p>
<h3>{mapName}</h3>
<p class="string-HTML">{mapDescription}</p>
</section>
<section class="copyright">
<h3 class="nes-pointer" on:click={() => expandedMapCopyright = !expandedMapCopyright}>Copyrights of the map</h3>
<p class="string-HTML" hidden="{!expandedMapCopyright}">{mapCopyright}</p>
<h3 class="nes-pointer" on:click={() => expandedTilesetCopyright = !expandedTilesetCopyright}>Copyrights of the tilesets</h3>
<section hidden="{!expandedTilesetCopyright}">
{#each tilesetCopyright as copyright}
<p class="string-HTML">{copyright}</p>
{:else}
<p>None of the tilesets of this map have a property copyright. 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);
display: grid;
grid-template-rows: 20% 40% 30%;
section.share-url {
text-align: center;
input {
width: 85%;
border-radius: 32px;
padding: 3px;
}
input::selection {
background-color: #209cee;
}
}
section.presentation-map {
h3 {
width: 100%;
text-align: center;
}
p {
max-height: calc(100% - 36px);
overflow: auto;
}
}
section.copyright {
text-align: center;
h3:hover {
background-color: #3c3e40;
border-radius: 32px;
}
p {
max-height: calc(100% - 36px);
overflow: auto;
}
section {
max-height: calc(100% - 36px);
overflow: auto;
}
}
}
</style>

View file

@ -1,17 +1,14 @@
<script lang="ts">
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
import type { GameManager } from "../../Phaser/Game/GameManager";
import { consoleGlobalMessageManagerFocusStore, consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
import { gameManager } from "../../Phaser/Game/GameManager";
import { AdminMessageEventTypes } from "../../Connexion/AdminMessagesService";
import uploadFile from "../images/music-file.svg";
import type {PlayGlobalMessageInterface} from "../../Connexion/ConnexionModels";
import type { PlayGlobalMessageInterface } from "../../Connexion/ConnexionModels";
interface EventTargetFiles extends EventTarget {
files: Array<File>;
}
export let gameManager: GameManager;
let gameScene = gameManager.getCurrentGameScene();
let fileInput: HTMLInputElement;
let fileName: string;
@ -43,7 +40,6 @@
}
inputAudio.value = '';
gameScene.connection?.emitGlobalMessage(audioGlobalMessage);
disableConsole();
}
}
@ -74,11 +70,6 @@
return '';
}
}
function disableConsole() {
consoleGlobalMessageManagerVisibleStore.set(false);
consoleGlobalMessageManagerFocusStore.set(false);
}
</script>
@ -103,24 +94,17 @@
img {
flex: 1 1 auto;
max-height: 80%;
margin-bottom: 20px;
}
p {
flex: 1 1 auto;
margin-bottom: 5px;
color: whitesmoke;
font-size: 1rem;
&.err {
color: #ce372b;
}
}
input {
display: none;
}

View file

@ -0,0 +1,83 @@
<script lang="ts">
import discordImg from '../images/discord_64x64.png'
import facebookImg from '../images/facebook_64x64.png'
import instagramImg from '../images/instagram_64x64.png'
import linkedinImg from '../images/linkedin_64x64.png'
import twitterImg from '../images/twitter_64x64.png'
import youtubeImg from '../images/youtube_64x64.png'
</script>
<div class="contact-main">
<section>
<p>
The WorkAdventure team is always available to help you.
If you have any questions, problems, new features or improvements ideas, or if you just want to give us your feedback,
do not hesitate to contact us.
</p>
</section>
<section>
<h3>Our Office</h3>
<p>
The WorkAdventure team has its own offices in ... WorkAdventure!
Do not hesitate to come see and talk to us.
</p>
<a href="https://play.staging.workadventu.re/@tcm/workadventure/wa-village" target="_blank">Visit us</a>
</section>
<section>
<h3>Our Mail</h3>
<p>Although we offer a solution to reduce their use, we have an email address that allows us to receive all your requests.</p>
<a href="mailto:hello@workadventu.re" target="_blank">hello@workadventu.re</a>
</section>
<section>
<h3>Our web site</h3>
<p>If you want to know more about us, follow the link to our web site.</p>
<a href="https://workadventu.re/about-us" target="_blank">About us</a>
</section>
<section>
<h3>Our social media</h3>
<a href="https://discord.gg/YGtngdh9gt" target="_blank">
<img src="{discordImg}" alt="{'Discord'}">
</a>
<a href="https://www.facebook.com/workadventure.WA" target="_blank">
<img src="{facebookImg}" alt="{'Facebook'}">
</a>
<a href="https://www.instagram.com/workadventure_/" target="_blank">
<img src="{instagramImg}" alt="{'Instagram'}">
</a>
<a href="https://www.linkedin.com/company/workadventure-by-tcm/" target="_blank">
<img src="{linkedinImg}" alt="{'LinkedIn'}">
</a>
<a href="https://twitter.com/Workadventure_" target="_blank">
<img src="{twitterImg}" alt="{'Twitter'}">
</a>
<a href="https://www.youtube.com/channel/UCXJ9igV-kb9gw1ftR33y5tA" target="_blank">
<img src="{youtubeImg}" alt="{'Youtube'}">
</a>
</section>
</div>
<style lang="scss">
div.contact-main {
height: calc(100% - 56px);
width: 100%;
display: grid;
grid-template-rows: 18% 21% 24% 21% 16%;
section {
text-align: center;
padding: 4px 5px;
p {
margin: 0;
}
img {
height: 50px;
width: 50px;
}
}
}
</style>

View file

@ -0,0 +1,51 @@
<script lang="ts">
function goToCreateMapPage() {
//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
//TODO: go to getting started ? or map-building ? or two different buttons ?
const sparkHost = "https://workadventu.re/getting-started";
window.open(sparkHost, "_blank");
}
function goToScriptingApiPage() {
//The redirection must be only on workadventu.re domain
//The scripting API function could change on other domain and that could break map created with the old function
const sparkHost = "https://workadventu.re/map-building/scripting";
window.open(sparkHost, "_blank");
}
</script>
<div class="create-map-main">
<section class="create-map-building">
<h3>Create your map</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.
Or create your own map from scratch.
</p>
<button type="button" class="nes-btn is-primary" on:click={goToCreateMapPage}>Create a map</button>
</section>
<section class="create-map-scripting">
<h3>Use the scripting API</h3>
<p>Make your map more interactive, more alive and totally unique with the scripting API.</p>
<p>(Programming skills are required to use the scripting API).</p>
<button type="button" class="nes-btn" on:click={goToScriptingApiPage}>Use a script</button>
</section>
</div>
<style lang="scss">
div.create-map-main {
height: calc(100% - 56px);
text-align: center;
display: grid;
grid-template-rows: 50% 50%;
}
</style>

View file

@ -1,121 +0,0 @@
<script lang="typescript">
import {localUserStore} from "../../Connexion/LocalUserStore";
import {videoConstraintStore} from "../../Stores/MediaStore";
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();// TODO edit that
}
if (valueVideo !== previewValueVideo) {
previewValueVideo = valueVideo;
videoConstraintStore.setFrameRate(valueVideo);
}
}
function toggleFullscreen() {
const body = document.querySelector('body')
if (body) {
if (document.fullscreenElement ?? document.fullscreen) {
document.exitFullscreen()
} else {
body.requestFullscreen();
}
}
}
</script>
<form class="gameQuality" on:submit|preventDefault={saveSetting}>
<section>
<h5>Game quality</h5>
<p class="cautiousText">(Editing these settings will restart the game)</p>
<select bind:value={valueGame} class="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>
</section>
<section>
<h5>Video quality</h5>
<select bind:value={valueVideo} class="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>
</section>
<section class="action">
<button type="submit" class="gameQualityFormSubmit">Save</button>
</section>
<section>
<button class="toggleFullscreen" on:click|preventDefault={toggleFullscreen}>Toggle fullscreen</button>
</section>
</form>
<style lang="scss">
.gameQuality {
color: black;
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 select {
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%;
}
.gameQuality section {
margin: 10px;
}
.gameQuality section.action{
text-align: center;
}
.gameQuality button {
margin: 10px;
background-color: black;
color: white;
border-radius: 7px;
padding-bottom: 4px;
}
.gameQuality button.gameQualityFormCancel {
background-color: #c7c7c700;
color: #292929;
}
</style>

View file

@ -0,0 +1,105 @@
<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% - 56px);
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";
}
}
}
}
</style>

View file

@ -1,80 +1,103 @@
<script lang="typescript">
import GameQualityMenu from "./GameQualityMenu.svelte";
import EditProfileMenu from "./EditProfileMenu.svelte";
import {fly} from "svelte/transition";
import type { SvelteComponent } from "svelte";
import SettingsSubMenu from "./SettingsSubMenu.svelte";
import CreateMapSubMenu from "./CreateMapSubMenu.svelte";
import ProfileSubMenu from "./ProfileSubMenu.svelte";
import ContactSubMenu from "./ContactSubMenu.svelte";
import AboutRoomSubMenu from "./AboutRoomSubMenu.svelte";
import GlobalMessagesSubMenu from "./GlobalMessagesSubMenu.svelte";
import {menuVisiblilityStore} from "../../Stores/MenuStore";
enum SubMenus {
settings = 1,
editProfile,
shareUrl,
}
//TODO: When we register a new custom menu we need to add it here
const SubMenus = new Map<string, typeof SvelteComponent>([
['Settings', SettingsSubMenu],
['Profile', ProfileSubMenu],
['Create a Map', CreateMapSubMenu],
['About the room', AboutRoomSubMenu],
['Global Messages', GlobalMessagesSubMenu], //Remove if player has not the admin tag
['Contact', ContactSubMenu] //Always last (except custom)
]);
let activeSubMenu: SubMenus = 2;
let activeSubMenu = 'Settings';
let activeComponent = SubMenus.get(activeSubMenu);
function switchMenu(menu: SubMenus) {
activeSubMenu = menu;
}
function 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 = "https://workadventu.re/getting-started";
window.open(sparkHost, "_blank");
}
</script>
<aside class="menuContainer">
<section class="menuNav">
<nav>
<ul>
<li class:active={activeSubMenu === SubMenus.settings } on:click={() => switchMenu(SubMenus.settings)}>Settings</li>
<li class:active={activeSubMenu === SubMenus.shareUrl } on:click={() => switchMenu(SubMenus.shareUrl)}>Share Url</li>
<li class:active={activeSubMenu === SubMenus.editProfile } on:click={() => switchMenu(SubMenus.editProfile)}>Edit Profile</li>
<li on:click={() => gotToCreateMapPage()}>Create Map</li>
<li>Go to Menu</li>
</ul>
</nav>
</section>
<section class="subMenuContainer">
{#if activeSubMenu === SubMenus.settings}
<GameQualityMenu></GameQualityMenu>
{:else if activeSubMenu === SubMenus.editProfile}
<EditProfileMenu></EditProfileMenu>
{/if}
</section>
</aside>
<style lang="scss">
aside.menuContainer{
pointer-events: auto;
background: #7a7a7a;
position: absolute;
width: 30vw;
height: 70vh;
border-radius: 8px;
display: flex;
padding:5px;
color: white;
}
section.menuNav{
width:30%;
border-right:white solid 4px;
nav{
ul{
padding: 10px;
list-style: none;
li{
cursor: pointer;
}
li.active{
background: #6f6f6f ;
}
}
function switchMenu(menu: string) {
if (SubMenus.has(menu)) {
activeSubMenu = menu
activeComponent = SubMenus.get(activeSubMenu);
}
}
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 [...SubMenus] as [submenuKey, submenuComponent]}
<button type="button" class="nes-btn {activeComponent === submenuComponent ? 'is-disabled' : ''}" on:click|preventDefault={() => switchMenu(submenuKey)}>{submenuKey}</button>
{/each}
</nav>
</div>
<div class="menu-submenu-container nes-container is-rounded" transition:fly="{{ y: -1000, duration: 500 }}">
<h2>{activeSubMenu}</h2>
{#if activeComponent}
<svelte:component this="{activeComponent}"/>
{/if}
</div>
</div>
<style lang="scss">
.nes-container {
padding: 5px;
}
div.menu-container-main {
--size-first-columns-grid: 15%; //TODO: clamp value
font-family: "Press Start 2P";
pointer-events: auto;
height: 70vh;
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;
}
}
</style>

View file

@ -1,39 +1,29 @@
<script lang="typescript">
import {menuVisible} from "../../Stores/MenuStore";
let isOpen : Boolean = false;
import {menuVisiblilityStore} from "../../Stores/MenuStore";
import {get} from "svelte/store";
function openMenu(){
isOpen = !isOpen; //Devrait être dans le store/menuVisible.set(isOPen);/
if(isOpen) menuVisible.set(true);
else menuVisible.set(false);
menuVisiblilityStore.set(!get(menuVisiblilityStore))
}
</script>
<main class="menuIcon">
<section>
<button on:click|preventDefault={openMenu}>
<img src="/static/images/logo-WA-min.png" alt="open menu">
</button>
</section>
<img src="/static/images/logo-WA-min.png" alt="open menu" on:click|preventDefault={openMenu}>
</main>
<style lang="scss">
.menuIcon button {
pointer-events: auto;
border-radius: 200px;
img {
width: 60px;
padding-top: 0;
cursor: url('/resources/logos/cursor_pointer.png'), pointer;
}
.menuIcon {
pointer-events: auto;
margin: 25px;
img {
width: 60px;
padding-top: 0;
//cursor: url('/resources/logos/cursor_pointer.png'), pointer;
}
.menuIcon section {
margin: 25px;
}
@media only screen and (max-height: 700px) {
.menuIcon section {
margin: 100px;
}
}
@media only screen and (max-height: 700px) {
.menuIcon {
margin: 100px;
}
}
</style>

View file

@ -1,27 +1,20 @@
<script lang="typescript">
import {gameManager} from "../../Phaser/Game/GameManager";
import {SelectCompanionScene, SelectCompanionSceneName} from "../../Phaser/Login/SelectCompanionScene";
import {menuIconVisible, menuVisible} from "../../Stores/MenuStore";
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";
enum EditState {
name = 1,
skin,
companion,
}
let currentEditState: EditState = 2;
import {connectionManager} from "../../Connexion/ConnectionManager";
function disableMenuStores(){
menuVisible.set(false);
menuIconVisible.set(false);
menuVisiblilityStore.set(false);
menuIconVisiblilityStore.set(false);
}
function openEditCompanionScene(){
disableMenuStores();
selectCompanionSceneVisibleStore.set(true);
@ -40,34 +33,41 @@
gameManager.leaveGame(SelectCharacterSceneName,new SelectCharacterScene());
}
</script>
<form class="EditProfile">
<section>
<h5>Edit your profile</h5>
</section>
<section>
<button type="submit" class="EditName" on:click|preventDefault={openEditNameScene}>Edit Name</button>
</section>
<section class="action">
<button type="submit" class="EditSkin" on:click|preventDefault={openEditSkinScene}>Edit Skin</button>
</section>
<section>
<button class="EditCompanion" on:click|preventDefault={openEditCompanionScene} >Edit Companion</button>
</section>
</form>
<style lang="scss">
.EditProfile {
color: black;
background: #eceeee;
border: 1px solid #42464b;
border-radius: 6px;
margin: 20px auto 0;
width: 50vw;
max-width: 300px;
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{
display: grid;
grid-template-rows: 33% 33% 33%; //TODO: clamp values
section {
display: flex;
justify-content: center;
align-items: center;
button {
height: 50px; //TODO: clamp value
width: 250px; //TODO: clamp value
}
}
}
</style>

View file

@ -0,0 +1,127 @@
<script lang="typescript">
import {localUserStore} from "../../Connexion/LocalUserStore";
import {videoConstraintStore} from "../../Stores/MediaStore";
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
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();// TODO edit that
}
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>
<select bind:value={valueGame}>
<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>
</section>
<section>
<h3>Video quality</h3>
<select bind:value={valueVideo}>
<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>
</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% - 56px);
display: grid;
grid-template-rows: 25% 25% 25% 20%;
section {
width: 100%; //TODO clamp value
padding: 20px 20px 0;
text-align: center;
select {
border-radius: 16px;
padding: 10px;
margin: 5px;
}
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;
}
}
}
</style>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { consoleGlobalMessageManagerFocusStore, consoleGlobalMessageManagerVisibleStore } from "../../Stores/ConsoleGlobalMessageManagerStore";
import {onDestroy, onMount} from "svelte";
import type { GameManager } from "../../Phaser/Game/GameManager";
import { menuInputFocusStore } from "../../Stores/MenuStore";
import { onDestroy, onMount } from "svelte";
import { gameManager } from "../../Phaser/Game/GameManager";
import { AdminMessageEventTypes } from "../../Connexion/AdminMessagesService";
import type { Quill } from "quill";
import type { PlayGlobalMessageInterface } from "../../Connexion/ConnexionModels";
@ -30,13 +30,10 @@
// remove formatting button
];
export let gameManager: GameManager;
const gameScene = gameManager.getCurrentGameScene();
let quill: Quill;
let INPUT_CONSOLE_MESSAGE: HTMLDivElement;
const MESSAGE_TYPE = AdminMessageEventTypes.admin;
let quill: Quill;
let QUILL_EDITOR: HTMLDivElement;
export const handleSending = {
sendTextMessage(broadcastToWorld: boolean) {
@ -53,39 +50,31 @@
quill.deleteText(0, quill.getLength());
gameScene.connection?.emitGlobalMessage(textGlobalMessage);
disableConsole();
}
}
//Quill
onMount(async () => {
// Import quill
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...',
theme: 'snow',
modules: {
toolbar: toolbarOptions
},
});
consoleGlobalMessageManagerFocusStore.set(true);
menuInputFocusStore.set(true);
});
onDestroy(() => {
consoleGlobalMessageManagerFocusStore.set(false);
menuInputFocusStore.set(false);
})
function disableConsole() {
consoleGlobalMessageManagerVisibleStore.set(false);
consoleGlobalMessageManagerFocusStore.set(false);
}
</script>
<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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

View file

@ -16,6 +16,7 @@ const lastRoomUrl = "lastRoomUrl";
const authToken = "authToken";
const state = "state";
const nonce = "nonce";
const notification = "notificationPermission";
class LocalUserStore {
saveUser(localUser: LocalUser) {
@ -128,6 +129,14 @@ class LocalUserStore {
return localStorage.getItem(authToken);
}
setNotification(value: string): void {
localStorage.setItem(notification, value);
}
getNotification(): string | null {
return localStorage.getItem(notification);
}
generateState(): string {
const newState = uuidv4();
localStorage.setItem(state, newState);

View file

@ -9,7 +9,7 @@ import { localUserStore } from "../../Connexion/LocalUserStore";
import { get } from "svelte/store";
import { requestedCameraState, requestedMicrophoneState } from "../../Stores/MediaStore";
import { helpCameraSettingsVisibleStore } from "../../Stores/HelpCameraSettingsStore";
import { menuIconVisible } from "../../Stores/MenuStore";
import { menuIconVisiblilityStore } from "../../Stores/MenuStore";
/**
* This class should be responsible for any scene starting/stopping
@ -100,7 +100,7 @@ export class GameManager {
this.currentGameSceneName = scene.scene.key;
const menuScene: MenuScene = scene.scene.get(MenuSceneName) as MenuScene;
menuScene.revealMenuIcon();
menuIconVisible.set(true);
menuIconVisiblilityStore.set(true);
}
/**

View file

@ -6,7 +6,7 @@ import { localUserStore } from "../../Connexion/LocalUserStore";
import { gameReportKey, gameReportRessource, ReportMenu } from "./ReportMenu";
import { connectionManager } from "../../Connexion/ConnectionManager";
import { GameConnexionTypes } from "../../Url/UrlManager";
import { menuIconVisible, menuVisible } from "../../Stores/MenuStore";
import { menuIconVisiblilityStore, menuVisiblilityStore } from "../../Stores/MenuStore";
import { videoConstraintStore } from "../../Stores/MediaStore";
import { showReportScreenStore } from "../../Stores/ShowReportScreenStore";
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
@ -163,7 +163,7 @@ export class MenuScene extends Phaser.Scene {
}
openSideMenu() {
menuVisible.set(true);
menuVisiblilityStore.set(true);
if (this.sideMenuOpened) return;
/*this.closeAll();
@ -188,7 +188,7 @@ export class MenuScene extends Phaser.Scene {
}
private closeSideMenu(): void {
menuVisible.set(false);
menuVisiblilityStore.set(false);
/* if (!this.sideMenuOpened) return;
this.sideMenuOpened = false;
this.closeAll();

View file

@ -1,8 +1,9 @@
import { writable } from "svelte/store";
import Timeout = NodeJS.Timeout;
export const menuIconVisible = writable(false);
export const menuVisible = writable(false);
export const menuIconVisiblilityStore = writable(false);
export const menuVisiblilityStore = writable(false);
export const menuInputFocusStore = writable(false);
let warningContainerTimeout: Timeout | null = null;
function createWarningContainerStore() {

View file

@ -1,11 +1,11 @@
import { derived } from "svelte/store";
import { consoleGlobalMessageManagerFocusStore } from "./ConsoleGlobalMessageManagerStore";
import { menuInputFocusStore } from "./MenuStore";
import { chatInputFocusStore } from "./ChatStore";
//derived from the focus on Menu, ConsoleGlobal, Chat and ...
export const enableUserInputsStore = derived(
[consoleGlobalMessageManagerFocusStore, chatInputFocusStore],
([$consoleGlobalMessageManagerFocusStore, $chatInputFocusStore]) => {
return !$consoleGlobalMessageManagerFocusStore && !$chatInputFocusStore;
[menuInputFocusStore, chatInputFocusStore],
([$menuInputFocusStore, $chatInputFocusStore]) => {
return !$menuInputFocusStore && !$chatInputFocusStore;
}
);

View file

@ -11,6 +11,7 @@ import { cowebsiteCloseButtonId } from "./CoWebsiteManager";
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
import { layoutManagerActionStore, layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore";
import { get } from "svelte/store";
import { localUserStore } from "../Connexion/LocalUserStore";
export class MediaManager {
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
@ -181,7 +182,11 @@ export class MediaManager {
}
public hasNotification(): boolean {
return Notification.permission === "granted";
if (Notification.permission === "granted") {
return localUserStore.getNotification() === "granted";
} else {
return false;
}
}
public requestNotification() {

View file

@ -1,15 +1,15 @@
//InputTextGlobalMessage
//TextGlobalMessage
section.section-input-send-text {
--height-toolbar: 15%;
height: 100%;
.ql-toolbar{
max-height: 100px;
height: var(--height-toolbar);
background: whitesmoke;
}
div.input-send-text{
height: calc(100% - 100px);
height: calc(100% - var(--height-toolbar));
overflow: auto;
color: whitesmoke;

View file

@ -3,4 +3,4 @@
@import "style";
@import "mobile-style.scss";
@import "fonts.scss";
@import "inputTextGlobalMessageSvelte-Style.scss";
@import "TextGlobalMessageSvelte-Style";

View file

@ -1,5 +1,4 @@
*{
font-family: Lato;
cursor: url('./images/cursor_normal.png'), auto;
}
* a, button, select{