Improve game overlay UI
This commit is contained in:
parent
5f1dd09cb9
commit
0bf1acfefb
@ -1,166 +1,52 @@
|
||||
<script lang="typescript">
|
||||
import MenuIcon from "./Menu/MenuIcon.svelte";
|
||||
import { menuIconVisiblilityStore, menuVisiblilityStore } from "../Stores/MenuStore";
|
||||
import { emoteMenuStore } from "../Stores/EmoteStore";
|
||||
import { enableCameraSceneVisibilityStore } from "../Stores/MediaStore";
|
||||
import CameraControls from "./CameraControls.svelte";
|
||||
import MyCamera from "./MyCamera.svelte";
|
||||
import SelectCompanionScene from "./SelectCompanion/SelectCompanionScene.svelte";
|
||||
import { selectCompanionSceneVisibleStore } from "../Stores/SelectCompanionStore";
|
||||
import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore";
|
||||
import SelectCharacterScene from "./selectCharacter/SelectCharacterScene.svelte";
|
||||
import { customCharacterSceneVisibleStore } from "../Stores/CustomCharacterStore";
|
||||
import { errorStore } from "../Stores/ErrorStore";
|
||||
import CustomCharacterScene from "./CustomCharacterScene/CustomCharacterScene.svelte";
|
||||
import LoginScene from "./Login/LoginScene.svelte";
|
||||
import Chat from "./Chat/Chat.svelte";
|
||||
import { loginSceneVisibleStore } from "../Stores/LoginSceneStore";
|
||||
import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte";
|
||||
import VisitCard from "./VisitCard/VisitCard.svelte";
|
||||
import { requestVisitCardsStore } from "../Stores/GameStore";
|
||||
|
||||
import type { Game } from "../Phaser/Game/Game";
|
||||
import { chatVisibilityStore } from "../Stores/ChatStore";
|
||||
import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStore";
|
||||
import HelpCameraSettingsPopup from "./HelpCameraSettings/HelpCameraSettingsPopup.svelte";
|
||||
import { showLimitRoomModalStore, showShareLinkMapModalStore } from "../Stores/ModalStore";
|
||||
import LimitRoomModal from "./Modal/LimitRoomModal.svelte";
|
||||
import ShareLinkMapModal from "./Modal/ShareLinkMapModal.svelte";
|
||||
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
||||
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
|
||||
import { customCharacterSceneVisibleStore } from "../Stores/CustomCharacterStore";
|
||||
import { errorStore } from "../Stores/ErrorStore";
|
||||
import { loginSceneVisibleStore } from "../Stores/LoginSceneStore";
|
||||
import { enableCameraSceneVisibilityStore } from "../Stores/MediaStore";
|
||||
import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore";
|
||||
import { selectCompanionSceneVisibleStore } from "../Stores/SelectCompanionStore";
|
||||
import Chat from "./Chat/Chat.svelte";
|
||||
import CustomCharacterScene from "./CustomCharacterScene/CustomCharacterScene.svelte";
|
||||
import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte";
|
||||
import LoginScene from "./Login/LoginScene.svelte";
|
||||
import MainLayout from "./MainLayout.svelte";
|
||||
import SelectCharacterScene from "./selectCharacter/SelectCharacterScene.svelte";
|
||||
import SelectCompanionScene from "./SelectCompanion/SelectCompanionScene.svelte";
|
||||
import ErrorDialog from "./UI/ErrorDialog.svelte";
|
||||
import Menu from "./Menu/Menu.svelte";
|
||||
import EmoteMenu from "./EmoteMenu/EmoteMenu.svelte";
|
||||
import VideoOverlay from "./Video/VideoOverlay.svelte";
|
||||
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
|
||||
import BanMessageContainer from "./TypeMessage/BanMessageContainer.svelte";
|
||||
import TextMessageContainer from "./TypeMessage/TextMessageContainer.svelte";
|
||||
import { banMessageStore } from "../Stores/TypeMessageStore/BanMessageStore";
|
||||
import { textMessageStore } from "../Stores/TypeMessageStore/TextMessageStore";
|
||||
import { warningContainerStore } from "../Stores/MenuStore";
|
||||
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
|
||||
import { layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore";
|
||||
import LayoutManager from "./LayoutManager/LayoutManager.svelte";
|
||||
import { audioManagerVisibilityStore } from "../Stores/AudioManagerStore";
|
||||
import AudioManager from "./AudioManager/AudioManager.svelte";
|
||||
import { showReportScreenStore, userReportEmpty } from "../Stores/ShowReportScreenStore";
|
||||
import ReportMenu from "./ReportMenu/ReportMenu.svelte";
|
||||
import { followStateStore } from "../Stores/FollowStore";
|
||||
import { peerStore } from "../Stores/PeerStore";
|
||||
import FollowMenu from "./FollowMenu/FollowMenu.svelte";
|
||||
|
||||
export let game: Game;
|
||||
</script>
|
||||
|
||||
<div>
|
||||
{#if $loginSceneVisibleStore}
|
||||
<div class="scrollable">
|
||||
<LoginScene {game} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $selectCharacterSceneVisibleStore}
|
||||
<div>
|
||||
<SelectCharacterScene {game} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $customCharacterSceneVisibleStore}
|
||||
<div>
|
||||
<CustomCharacterScene {game} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $selectCompanionSceneVisibleStore}
|
||||
<div>
|
||||
<SelectCompanionScene {game} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $enableCameraSceneVisibilityStore}
|
||||
<div class="scrollable">
|
||||
<EnableCameraScene {game} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $banMessageStore.length > 0}
|
||||
<div>
|
||||
<BanMessageContainer />
|
||||
</div>
|
||||
{:else if $textMessageStore.length > 0}
|
||||
<div>
|
||||
<TextMessageContainer />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $soundPlayingStore}
|
||||
<div>
|
||||
<AudioPlaying url={$soundPlayingStore} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $audioManagerVisibilityStore}
|
||||
<div>
|
||||
<AudioManager />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $layoutManagerVisibilityStore}
|
||||
<div>
|
||||
<LayoutManager />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $showReportScreenStore !== userReportEmpty}
|
||||
<div>
|
||||
<ReportMenu />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $followStateStore !== "off" || $peerStore.size > 0}
|
||||
<div>
|
||||
<FollowMenu />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $menuIconVisiblilityStore}
|
||||
<div>
|
||||
<MenuIcon />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $menuVisiblilityStore}
|
||||
<div>
|
||||
<Menu />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $emoteMenuStore}
|
||||
<div>
|
||||
<EmoteMenu />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $gameOverlayVisibilityStore}
|
||||
<div>
|
||||
<VideoOverlay />
|
||||
<MyCamera />
|
||||
<CameraControls />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $helpCameraSettingsVisibleStore}
|
||||
<div>
|
||||
<HelpCameraSettingsPopup />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $showLimitRoomModalStore}
|
||||
<div>
|
||||
<LimitRoomModal />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $showShareLinkMapModalStore}
|
||||
<div>
|
||||
<ShareLinkMapModal />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $requestVisitCardsStore}
|
||||
<VisitCard visitCardUrl={$requestVisitCardsStore} />
|
||||
{/if}
|
||||
{#if $errorStore.length > 0}
|
||||
<div>
|
||||
<ErrorDialog />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $errorStore.length > 0}
|
||||
<div>
|
||||
<ErrorDialog />
|
||||
</div>
|
||||
{:else if $loginSceneVisibleStore}
|
||||
<div class="scrollable">
|
||||
<LoginScene {game} />
|
||||
</div>
|
||||
{:else if $selectCharacterSceneVisibleStore}
|
||||
<div>
|
||||
<SelectCharacterScene {game} />
|
||||
</div>
|
||||
{:else if $customCharacterSceneVisibleStore}
|
||||
<div>
|
||||
<CustomCharacterScene {game} />
|
||||
</div>
|
||||
{:else if $selectCompanionSceneVisibleStore}
|
||||
<div>
|
||||
<SelectCompanionScene {game} />
|
||||
</div>
|
||||
{:else if $enableCameraSceneVisibilityStore}
|
||||
<div class="scrollable">
|
||||
<EnableCameraScene {game} />
|
||||
</div>
|
||||
{:else}
|
||||
<MainLayout />
|
||||
|
||||
{#if $chatVisibilityStore}
|
||||
<Chat />
|
||||
{/if}
|
||||
{#if $warningContainerStore}
|
||||
<WarningContainer />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -157,13 +157,16 @@
|
||||
|
||||
<style lang="scss">
|
||||
div.main-audio-manager.nes-container.is-rounded {
|
||||
position: relative;
|
||||
top: 0.5rem;
|
||||
position: absolute;
|
||||
top: 1%;
|
||||
max-height: clamp(150px, 10vh, 15vh); //replace @media for small screen
|
||||
width: clamp(200px, 15vw, 15vw);
|
||||
padding: 3px 3px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 200;
|
||||
|
||||
background-color: rgb(0, 0, 0, 0.5);
|
||||
display: grid;
|
||||
|
@ -9,10 +9,15 @@
|
||||
import microphoneCloseImg from "./images/microphone-close.svg";
|
||||
import layoutPresentationImg from "./images/layout-presentation.svg";
|
||||
import layoutChatImg from "./images/layout-chat.svg";
|
||||
import { layoutModeStore } from "../Stores/StreamableCollectionStore";
|
||||
import followImg from "./images/follow.svg";
|
||||
import { LayoutMode } from "../WebRtc/LayoutManager";
|
||||
import { peerStore } from "../Stores/PeerStore";
|
||||
import { onDestroy } from "svelte";
|
||||
import { embedScreenLayout } from "../Stores/EmbedScreensStore";
|
||||
import { followRoleStore, followStateStore, followUsersStore } from "../Stores/FollowStore";
|
||||
import { gameManager } from "../Phaser/Game/GameManager";
|
||||
|
||||
const gameScene = gameManager.getCurrentGameScene();
|
||||
|
||||
function screenSharingClick(): void {
|
||||
if (isSilent) return;
|
||||
@ -42,10 +47,26 @@
|
||||
}
|
||||
|
||||
function switchLayoutMode() {
|
||||
if ($layoutModeStore === LayoutMode.Presentation) {
|
||||
$layoutModeStore = LayoutMode.VideoChat;
|
||||
if ($embedScreenLayout === LayoutMode.Presentation) {
|
||||
$embedScreenLayout = LayoutMode.VideoChat;
|
||||
} else {
|
||||
$layoutModeStore = LayoutMode.Presentation;
|
||||
$embedScreenLayout = LayoutMode.Presentation;
|
||||
}
|
||||
}
|
||||
|
||||
function followClick() {
|
||||
switch ($followStateStore) {
|
||||
case "off":
|
||||
gameScene.connection?.emitFollowRequest();
|
||||
followRoleStore.set("leader");
|
||||
followStateStore.set("active");
|
||||
break;
|
||||
case "requesting":
|
||||
case "active":
|
||||
case "ending":
|
||||
gameScene.connection?.emitFollowAbort();
|
||||
followUsersStore.stopFollowing();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,40 +77,161 @@
|
||||
onDestroy(unsubscribeIsSilent);
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="btn-cam-action">
|
||||
<div class="btn-layout" on:click={switchLayoutMode} class:hide={$peerStore.size === 0}>
|
||||
{#if $layoutModeStore === LayoutMode.Presentation}
|
||||
<img src={layoutPresentationImg} style="padding: 2px" alt="Switch to mosaic mode" />
|
||||
{:else}
|
||||
<img src={layoutChatImg} style="padding: 2px" alt="Switch to presentation mode" />
|
||||
{/if}
|
||||
</div>
|
||||
<div
|
||||
class="btn-monitor"
|
||||
on:click={screenSharingClick}
|
||||
class:hide={!$screenSharingAvailableStore || isSilent}
|
||||
class:enabled={$requestedScreenSharingState}
|
||||
>
|
||||
{#if $requestedScreenSharingState && !isSilent}
|
||||
<img src={monitorImg} alt="Start screen sharing" />
|
||||
{:else}
|
||||
<img src={monitorCloseImg} alt="Stop screen sharing" />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="btn-video" on:click={cameraClick} class:disabled={!$requestedCameraState || isSilent}>
|
||||
{#if $requestedCameraState && !isSilent}
|
||||
<img src={cinemaImg} alt="Turn on webcam" />
|
||||
{:else}
|
||||
<img src={cinemaCloseImg} alt="Turn off webcam" />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="btn-micro" on:click={microphoneClick} class:disabled={!$requestedMicrophoneState || isSilent}>
|
||||
{#if $requestedMicrophoneState && !isSilent}
|
||||
<img src={microphoneImg} alt="Turn on microphone" />
|
||||
{:else}
|
||||
<img src={microphoneCloseImg} alt="Turn off microphone" />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="btn-cam-action">
|
||||
<div class="btn-layout" on:click={switchLayoutMode} class:hide={$peerStore.size === 0}>
|
||||
{#if $embedScreenLayout === LayoutMode.Presentation}
|
||||
<img class="noselect" src={layoutPresentationImg} style="padding: 2px" alt="Switch to mosaic mode" />
|
||||
{:else}
|
||||
<img class="noselect" src={layoutChatImg} style="padding: 2px" alt="Switch to presentation mode" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="btn-follow"
|
||||
class:hide={($peerStore.size === 0 && $followStateStore === "off") || isSilent}
|
||||
class:disabled={$followStateStore !== "off"}
|
||||
on:click={followClick}
|
||||
>
|
||||
<img class="noselect" src={followImg} alt="" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="btn-monitor"
|
||||
on:click={screenSharingClick}
|
||||
class:hide={!$screenSharingAvailableStore || isSilent}
|
||||
class:enabled={$requestedScreenSharingState}
|
||||
>
|
||||
{#if $requestedScreenSharingState && !isSilent}
|
||||
<img class="noselect" src={monitorImg} alt="Start screen sharing" />
|
||||
{:else}
|
||||
<img class="noselect" src={monitorCloseImg} alt="Stop screen sharing" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="btn-video" on:click={cameraClick} class:disabled={!$requestedCameraState || isSilent}>
|
||||
{#if $requestedCameraState && !isSilent}
|
||||
<img class="noselect" src={cinemaImg} alt="Turn on webcam" />
|
||||
{:else}
|
||||
<img class="noselect" src={cinemaCloseImg} alt="Turn off webcam" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="btn-micro" on:click={microphoneClick} class:disabled={!$requestedMicrophoneState || isSilent}>
|
||||
{#if $requestedMicrophoneState && !isSilent}
|
||||
<img class="noselect" src={microphoneImg} alt="Turn on microphone" />
|
||||
{:else}
|
||||
<img class="noselect" src={microphoneCloseImg} alt="Turn off microphone" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../style/breakpoints.scss";
|
||||
|
||||
.btn-cam-action {
|
||||
pointer-events: all;
|
||||
position: absolute;
|
||||
display: inline-flex;
|
||||
bottom: 10px;
|
||||
right: 15px;
|
||||
width: 360px;
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
align-content: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
&:hover {
|
||||
div.hide {
|
||||
transform: translateY(60px);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*btn animation*/
|
||||
.btn-cam-action div {
|
||||
cursor: url("../../style/images/cursor_pointer.png"), pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: solid 0px black;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
background: #666;
|
||||
box-shadow: 2px 2px 24px #444;
|
||||
border-radius: 48px;
|
||||
transform: translateY(15px);
|
||||
transition-timing-function: ease-in-out;
|
||||
transition: all 0.3s;
|
||||
margin: 0 4%;
|
||||
|
||||
&.hide {
|
||||
transform: translateY(60px);
|
||||
}
|
||||
}
|
||||
.btn-cam-action div.disabled {
|
||||
background: #d75555;
|
||||
}
|
||||
.btn-cam-action div.enabled {
|
||||
background: #73c973;
|
||||
}
|
||||
.btn-cam-action:hover div {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.btn-cam-action div:hover {
|
||||
background: #407cf7;
|
||||
box-shadow: 4px 4px 48px #666;
|
||||
transition: 120ms;
|
||||
}
|
||||
.btn-micro {
|
||||
pointer-events: auto;
|
||||
}
|
||||
.btn-video {
|
||||
pointer-events: auto;
|
||||
transition: all 0.25s;
|
||||
}
|
||||
.btn-monitor {
|
||||
pointer-events: auto;
|
||||
}
|
||||
.btn-layout {
|
||||
pointer-events: auto;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
.btn-cam-action div img {
|
||||
height: 22px;
|
||||
width: 30px;
|
||||
position: relative;
|
||||
cursor: url("../../style/images/cursor_pointer.png"), pointer;
|
||||
}
|
||||
|
||||
.btn-follow {
|
||||
pointer-events: auto;
|
||||
|
||||
img {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
}
|
||||
|
||||
@media (hover: none) {
|
||||
/**
|
||||
* If we cannot hover over elements, let's display camera button in full.
|
||||
*/
|
||||
.btn-cam-action {
|
||||
div {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
.btn-cam-action {
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 40%;
|
||||
max-height: 40px;
|
||||
|
||||
div {
|
||||
width: 20%;
|
||||
max-height: 44px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -43,7 +43,7 @@
|
||||
<svelte:window on:keydown={onKeyDown} on:click={onClick} />
|
||||
|
||||
<aside class="chatWindow" transition:fly={{ x: -1000, duration: 500 }} bind:this={chatWindowElement}>
|
||||
<p class="close-icon" on:click={closeChat}>×</p>
|
||||
<p class="close-icon noselect" on:click={closeChat}>×</p>
|
||||
<section class="messagesList" bind:this={listDom}>
|
||||
<ul>
|
||||
<li><p class="system-text">{$LL.chat.intro()}</p></li>
|
||||
@ -78,7 +78,7 @@
|
||||
}
|
||||
|
||||
aside.chatWindow {
|
||||
z-index: 100;
|
||||
z-index: 1000;
|
||||
pointer-events: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -83,6 +83,8 @@
|
||||
</form>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
form.customCharacterScene {
|
||||
font-family: "Press Start 2P";
|
||||
pointer-events: auto;
|
||||
@ -129,7 +131,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
form.customCharacterScene button.customCharacterSceneButtonLeft {
|
||||
left: 5vw;
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore";
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import { EmojiButton } from "@joeattardi/emoji-button";
|
||||
import { isMobile } from "../../Enum/EnvironmentVariable";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
|
||||
|
||||
let emojiContainer: HTMLElement;
|
||||
let picker: EmojiButton;
|
||||
@ -20,7 +20,7 @@
|
||||
"--secondary-text-color": "whitesmoke",
|
||||
"--category-button-color": "whitesmoke",
|
||||
},
|
||||
emojisPerRow: isMobile() ? 6 : 8,
|
||||
emojisPerRow: isMediaBreakpointUp("md") ? 6 : 8,
|
||||
autoFocusSearch: false,
|
||||
style: "twemoji",
|
||||
showPreview: false,
|
||||
@ -86,6 +86,8 @@
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
z-index: 101;
|
||||
}
|
||||
|
||||
.emote-menu {
|
||||
|
@ -127,6 +127,8 @@
|
||||
</form>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
.enableCameraScene {
|
||||
pointer-events: auto;
|
||||
margin: 20px auto 0;
|
||||
@ -214,7 +216,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
.enableCameraScene h2 {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
33
front/src/Components/FollowMenu/FollowButton.svelte
Normal file
33
front/src/Components/FollowMenu/FollowButton.svelte
Normal file
@ -0,0 +1,33 @@
|
||||
<script lang="typescript">
|
||||
import followImg from "../images/follow.svg";
|
||||
|
||||
export let hidden: Boolean;
|
||||
|
||||
let cancelButton = false;
|
||||
</script>
|
||||
|
||||
<div class="btn-follow" class:hide={hidden} class:cancel={cancelButton}>
|
||||
<img src={followImg} alt="" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.btn-follow {
|
||||
cursor: url("../../../style/images/cursor_pointer.png"), pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: solid 0px black;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
background: #666;
|
||||
box-shadow: 2px 2px 24px #444;
|
||||
border-radius: 48px;
|
||||
transform: translateY(15px);
|
||||
transition-timing-function: ease-in-out;
|
||||
margin: 0 4%;
|
||||
|
||||
img {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,9 +1,5 @@
|
||||
<!--
|
||||
vim: ft=typescript
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||
import followImg from "../images/follow.svg";
|
||||
import { followStateStore, followRoleStore, followUsersStore } from "../../Stores/FollowStore";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
|
||||
@ -14,10 +10,6 @@ vim: ft=typescript
|
||||
return user ? user.PlayerValue : "";
|
||||
}
|
||||
|
||||
function sendFollowRequest() {
|
||||
gameScene.CurrentPlayer.sendFollowRequest();
|
||||
}
|
||||
|
||||
function acceptFollowRequest() {
|
||||
gameScene.CurrentPlayer.startFollowing();
|
||||
}
|
||||
@ -83,7 +75,7 @@ vim: ft=typescript
|
||||
|
||||
{#if $followStateStore === "active" || $followStateStore === "ending"}
|
||||
<div class="interact-status nes-container is-rounded">
|
||||
<section class="interact-status">
|
||||
<section>
|
||||
{#if $followRoleStore === "follower"}
|
||||
<p>{$LL.follow.interactStatus.following({ leader: name($followUsersStore[0]) })}</p>
|
||||
{:else if $followUsersStore.length === 0}
|
||||
@ -109,48 +101,27 @@ vim: ft=typescript
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $followStateStore === "off"}
|
||||
<button
|
||||
type="button"
|
||||
class="nes-btn is-primary follow-menu-button"
|
||||
on:click|preventDefault={sendFollowRequest}
|
||||
title="Ask others to follow"><img class="background-img" src={followImg} alt="" /></button
|
||||
>
|
||||
{/if}
|
||||
|
||||
{#if $followStateStore === "active" || $followStateStore === "ending"}
|
||||
{#if $followRoleStore === "follower"}
|
||||
<button
|
||||
type="button"
|
||||
class="nes-btn is-error follow-menu-button"
|
||||
on:click|preventDefault={reset}
|
||||
title="Stop following"><img class="background-img" src={followImg} alt="" /></button
|
||||
>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
class="nes-btn is-error follow-menu-button"
|
||||
on:click|preventDefault={reset}
|
||||
title="Stop leading the way"><img class="background-img" src={followImg} alt="" /></button
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
.nes-container {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
div.interact-status {
|
||||
.interact-status {
|
||||
background-color: #333333;
|
||||
color: whitesmoke;
|
||||
|
||||
position: relative;
|
||||
height: 2.7em;
|
||||
position: absolute;
|
||||
max-height: 2.7em;
|
||||
width: 40vw;
|
||||
top: 87vh;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
z-index: 150;
|
||||
}
|
||||
|
||||
div.interact-menu {
|
||||
@ -158,10 +129,14 @@ vim: ft=typescript
|
||||
background-color: #333333;
|
||||
color: whitesmoke;
|
||||
|
||||
position: relative;
|
||||
position: absolute;
|
||||
width: 60vw;
|
||||
top: 60vh;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
z-index: 150;
|
||||
|
||||
section.interact-menu-title {
|
||||
margin-bottom: 20px;
|
||||
@ -189,23 +164,16 @@ vim: ft=typescript
|
||||
}
|
||||
}
|
||||
|
||||
.follow-menu-button {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
div.interact-status {
|
||||
width: 100vw;
|
||||
@include media-breakpoint-up(md) {
|
||||
.interact-status {
|
||||
width: 90vw;
|
||||
top: 78vh;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
div.interact-menu {
|
||||
height: 21vh;
|
||||
width: 100vw;
|
||||
max-height: 21vh;
|
||||
width: 90vw;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
<form
|
||||
class="helpCameraSettings nes-container"
|
||||
on:submit|preventDefault={close}
|
||||
transition:fly={{ y: -900, duration: 500 }}
|
||||
transition:fly={{ y: -50, duration: 500 }}
|
||||
>
|
||||
<section>
|
||||
<h2>{$LL.camera.help.title()}</h2>
|
||||
@ -55,9 +55,12 @@
|
||||
background: #eceeee;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 10vh;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-top: 4%;
|
||||
max-height: 80vh;
|
||||
max-width: 80vw;
|
||||
z-index: 250;
|
||||
overflow: auto;
|
||||
text-align: center;
|
||||
|
||||
|
@ -21,9 +21,11 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 40px;
|
||||
margin: 0 auto;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding: 0;
|
||||
width: clamp(200px, 20vw, 20vw);
|
||||
z-index: 155;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -31,6 +33,10 @@
|
||||
animation: moveMessage 0.5s;
|
||||
animation-iteration-count: infinite;
|
||||
animation-timing-function: ease-in-out;
|
||||
|
||||
div {
|
||||
margin-bottom: 5%;
|
||||
}
|
||||
}
|
||||
|
||||
div.nes-container.is-rounded {
|
163
front/src/Components/MainLayout.svelte
Normal file
163
front/src/Components/MainLayout.svelte
Normal file
@ -0,0 +1,163 @@
|
||||
<script lang="typescript">
|
||||
import { onMount } from "svelte";
|
||||
import { audioManagerVisibilityStore } from "../Stores/AudioManagerStore";
|
||||
import { hasEmbedScreen } from "../Stores/EmbedScreensStore";
|
||||
import { emoteMenuStore } from "../Stores/EmoteStore";
|
||||
import { myCameraVisibilityStore } from "../Stores/MyCameraStoreVisibility";
|
||||
import { requestVisitCardsStore } from "../Stores/GameStore";
|
||||
import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStore";
|
||||
import { layoutManagerActionVisibilityStore } from "../Stores/LayoutManagerStore";
|
||||
import { menuIconVisiblilityStore, menuVisiblilityStore, warningContainerStore } from "../Stores/MenuStore";
|
||||
import { showReportScreenStore, userReportEmpty } from "../Stores/ShowReportScreenStore";
|
||||
import AudioManager from "./AudioManager/AudioManager.svelte";
|
||||
import CameraControls from "./CameraControls.svelte";
|
||||
import EmbedScreensContainer from "./EmbedScreens/EmbedScreensContainer.svelte";
|
||||
import EmoteMenu from "./EmoteMenu/EmoteMenu.svelte";
|
||||
import HelpCameraSettingsPopup from "./HelpCameraSettings/HelpCameraSettingsPopup.svelte";
|
||||
import LayoutActionManager from "./LayoutActionManager/LayoutActionManager.svelte";
|
||||
import Menu from "./Menu/Menu.svelte";
|
||||
import MenuIcon from "./Menu/MenuIcon.svelte";
|
||||
import MyCamera from "./MyCamera.svelte";
|
||||
import ReportMenu from "./ReportMenu/ReportMenu.svelte";
|
||||
import VisitCard from "./VisitCard/VisitCard.svelte";
|
||||
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
|
||||
import { isMediaBreakpointUp } from "../Utils/BreakpointsUtils";
|
||||
import CoWebsitesContainer from "./EmbedScreens/CoWebsitesContainer.svelte";
|
||||
import FollowMenu from "./FollowMenu/FollowMenu.svelte";
|
||||
import { followStateStore } from "../Stores/FollowStore";
|
||||
import { peerStore } from "../Stores/PeerStore";
|
||||
import { banMessageStore } from "../Stores/TypeMessageStore/BanMessageStore";
|
||||
import BanMessageContainer from "./TypeMessage/BanMessageContainer.svelte";
|
||||
import { textMessageStore } from "../Stores/TypeMessageStore/TextMessageStore";
|
||||
import TextMessageContainer from "./TypeMessage/TextMessageContainer.svelte";
|
||||
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
|
||||
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
||||
import { showLimitRoomModalStore, showShareLinkMapModalStore } from "../Stores/ModalStore";
|
||||
import LimitRoomModal from "./Modal/LimitRoomModal.svelte";
|
||||
import ShareLinkMapModal from "./Modal/ShareLinkMapModal.svelte";
|
||||
|
||||
let mainLayout: HTMLDivElement;
|
||||
|
||||
let displayCoWebsiteContainer = isMediaBreakpointUp("md");
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
displayCoWebsiteContainer = isMediaBreakpointUp("md");
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
resizeObserver.observe(mainLayout);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="main-layout" bind:this={mainLayout}>
|
||||
<aside id="main-layout-left-aside">
|
||||
{#if $menuIconVisiblilityStore}
|
||||
<MenuIcon />
|
||||
{/if}
|
||||
|
||||
{#if displayCoWebsiteContainer}
|
||||
<CoWebsitesContainer vertical={true} />
|
||||
{/if}
|
||||
</aside>
|
||||
|
||||
<section id="main-layout-main">
|
||||
{#if $menuVisiblilityStore}
|
||||
<Menu />
|
||||
{/if}
|
||||
|
||||
{#if $banMessageStore.length > 0}
|
||||
<BanMessageContainer />
|
||||
{:else if $textMessageStore.length > 0}
|
||||
<TextMessageContainer />
|
||||
{/if}
|
||||
|
||||
{#if $soundPlayingStore}
|
||||
<AudioPlaying url={$soundPlayingStore} />
|
||||
{/if}
|
||||
|
||||
{#if $showReportScreenStore !== userReportEmpty}
|
||||
<ReportMenu />
|
||||
{/if}
|
||||
|
||||
{#if $warningContainerStore}
|
||||
<WarningContainer />
|
||||
{/if}
|
||||
|
||||
{#if $helpCameraSettingsVisibleStore}
|
||||
<HelpCameraSettingsPopup />
|
||||
{/if}
|
||||
|
||||
{#if $audioManagerVisibilityStore}
|
||||
<AudioManager />
|
||||
{/if}
|
||||
|
||||
{#if $showLimitRoomModalStore}
|
||||
<LimitRoomModal />
|
||||
{/if}
|
||||
|
||||
{#if $showShareLinkMapModalStore}
|
||||
<ShareLinkMapModal />
|
||||
{/if}
|
||||
|
||||
{#if $followStateStore !== "off" || $peerStore.size > 0}
|
||||
<FollowMenu />
|
||||
{/if}
|
||||
|
||||
{#if $requestVisitCardsStore}
|
||||
<VisitCard visitCardUrl={$requestVisitCardsStore} />
|
||||
{/if}
|
||||
|
||||
{#if $emoteMenuStore}
|
||||
<EmoteMenu />
|
||||
{/if}
|
||||
|
||||
{#if hasEmbedScreen}
|
||||
<EmbedScreensContainer />
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<section id="main-layout-baseline">
|
||||
{#if $layoutManagerActionVisibilityStore}
|
||||
<LayoutActionManager />
|
||||
{/if}
|
||||
|
||||
{#if $myCameraVisibilityStore}
|
||||
<MyCamera />
|
||||
<CameraControls />
|
||||
{/if}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../style/breakpoints.scss";
|
||||
|
||||
#main-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 7% 93%;
|
||||
grid-template-rows: 80% 20%;
|
||||
|
||||
&-left-aside {
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
&-baseline {
|
||||
grid-column: 1/3;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
#main-layout {
|
||||
grid-template-columns: 15% 85%;
|
||||
|
||||
&-left-aside {
|
||||
min-width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
#main-layout {
|
||||
grid-template-columns: 20% 80%;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -100,6 +100,8 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
.string-HTML {
|
||||
white-space: pre-line;
|
||||
}
|
||||
@ -126,7 +128,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
div.about-room-main {
|
||||
section.container-overflow {
|
||||
height: calc(100% - 120px);
|
||||
|
@ -67,6 +67,8 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
div.global-message-main {
|
||||
height: calc(100% - 50px);
|
||||
display: grid;
|
||||
@ -109,7 +111,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
.global-message-content {
|
||||
height: calc(100% - 5px);
|
||||
}
|
||||
|
@ -36,6 +36,8 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
div.guest-main {
|
||||
height: calc(100% - 56px);
|
||||
|
||||
@ -57,7 +59,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 900px), only screen and (max-height: 600px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
div.guest-main {
|
||||
section.share-url.not-mobile {
|
||||
display: none;
|
||||
|
@ -125,6 +125,8 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
.nes-container {
|
||||
padding: 5px;
|
||||
}
|
||||
@ -136,11 +138,15 @@
|
||||
pointer-events: auto;
|
||||
height: 80%;
|
||||
width: 75%;
|
||||
top: 10%;
|
||||
top: 4%;
|
||||
|
||||
position: relative;
|
||||
z-index: 80;
|
||||
margin: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
position: absolute;
|
||||
z-index: 900;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: var(--size-first-columns-grid) calc(100% - var(--size-first-columns-grid));
|
||||
@ -173,12 +179,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
div.menu-container-main {
|
||||
--size-first-columns-grid: 120px;
|
||||
height: 70%;
|
||||
top: 55px;
|
||||
width: 100%;
|
||||
width: 95%;
|
||||
font-size: 0.5em;
|
||||
|
||||
div.menu-nav-sidebar {
|
||||
|
@ -14,6 +14,7 @@
|
||||
function showMenu() {
|
||||
menuVisiblilityStore.set(!get(menuVisiblilityStore));
|
||||
}
|
||||
|
||||
function showChat() {
|
||||
chatVisibilityStore.set(true);
|
||||
}
|
||||
@ -21,72 +22,94 @@
|
||||
function register() {
|
||||
window.open(`${ADMIN_URL}/second-step-register`, "_self");
|
||||
}
|
||||
|
||||
function showInvite() {
|
||||
showShareLinkMapModalStore.set(true);
|
||||
}
|
||||
|
||||
function noDrag() {
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window />
|
||||
|
||||
<main class="menuIcon">
|
||||
<main class="menuIcon noselect">
|
||||
{#if $limitMapStore}
|
||||
<img
|
||||
src={logoInvite}
|
||||
alt={$LL.menu.icon.open.invite()}
|
||||
class="nes-pointer"
|
||||
draggable="false"
|
||||
on:dragstart|preventDefault={noDrag}
|
||||
on:click|preventDefault={showInvite}
|
||||
/>
|
||||
<img
|
||||
src={logoRegister}
|
||||
alt={$LL.menu.icon.open.register()}
|
||||
class="nes-pointer"
|
||||
draggable="false"
|
||||
on:dragstart|preventDefault={noDrag}
|
||||
on:click|preventDefault={register}
|
||||
/>
|
||||
{:else}
|
||||
<img src={logoWA} alt={$LL.menu.icon.open.menu()} class="nes-pointer" on:click|preventDefault={showMenu} />
|
||||
<img src={logoTalk} alt={$LL.menu.icon.open.chat()} class="nes-pointer" on:click|preventDefault={showChat} />
|
||||
<img
|
||||
src={logoWA}
|
||||
alt={$LL.menu.icon.open.menu()}
|
||||
class="nes-pointer"
|
||||
draggable="false"
|
||||
on:dragstart|preventDefault={noDrag}
|
||||
on:click|preventDefault={showMenu}
|
||||
/>
|
||||
<img
|
||||
src={logoTalk}
|
||||
alt={$LL.menu.icon.open.chat()}
|
||||
class="nes-pointer"
|
||||
draggable="false"
|
||||
on:dragstart|preventDefault={noDrag}
|
||||
on:click|preventDefault={showChat}
|
||||
/>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
.menuIcon {
|
||||
display: inline-grid;
|
||||
z-index: 90;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 20%;
|
||||
z-index: 800;
|
||||
position: relative;
|
||||
margin: 25px;
|
||||
|
||||
img {
|
||||
pointer-events: auto;
|
||||
width: 60px;
|
||||
padding-top: 0;
|
||||
margin: 3px;
|
||||
image-rendering: pixelated;
|
||||
margin: 5%;
|
||||
}
|
||||
}
|
||||
.menuIcon img:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||
@include media-breakpoint-up(sm) {
|
||||
.menuIcon {
|
||||
display: inline-grid;
|
||||
z-index: 90;
|
||||
position: relative;
|
||||
margin: 25px;
|
||||
margin-top: 10%;
|
||||
img {
|
||||
pointer-events: auto;
|
||||
width: 60px;
|
||||
padding-top: 0;
|
||||
margin: 3px;
|
||||
}
|
||||
}
|
||||
.menuIcon img:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||
.menuIcon {
|
||||
margin: 3px;
|
||||
img {
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
.menuIcon {
|
||||
img {
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,8 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
div.customize-main {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
@ -161,7 +163,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
div.customize-main.content section button {
|
||||
width: 130px;
|
||||
}
|
||||
|
@ -2,11 +2,11 @@
|
||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||
import { videoConstraintStore } from "../../Stores/MediaStore";
|
||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||
import { isMobile } from "../../Enum/EnvironmentVariable";
|
||||
import { menuVisiblilityStore } from "../../Stores/MenuStore";
|
||||
import LL, { locale } from "../../i18n/i18n-svelte";
|
||||
import type { Locales } from "../../i18n/i18n-types";
|
||||
import { displayableLocales, setCurrentLocale } from "../../i18n/locales";
|
||||
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
|
||||
|
||||
let fullscreen: boolean = localUserStore.getFullscreen();
|
||||
let notification: boolean = localUserStore.getNotification() === "granted";
|
||||
@ -85,6 +85,8 @@
|
||||
function closeMenu() {
|
||||
menuVisiblilityStore.set(false);
|
||||
}
|
||||
|
||||
const isMobile = isMediaBreakpointUp("md");
|
||||
</script>
|
||||
|
||||
<div class="settings-main" on:submit|preventDefault={saveSetting}>
|
||||
@ -93,22 +95,22 @@
|
||||
<div class="nes-select is-dark">
|
||||
<select bind:value={valueGame}>
|
||||
<option value={120}
|
||||
>{isMobile()
|
||||
>{isMobile
|
||||
? $LL.menu.settings.gameQuality.short.high()
|
||||
: $LL.menu.settings.gameQuality.long.high()}</option
|
||||
>
|
||||
<option value={60}
|
||||
>{isMobile()
|
||||
>{isMobile
|
||||
? $LL.menu.settings.gameQuality.short.medium()
|
||||
: $LL.menu.settings.gameQuality.long.medium()}</option
|
||||
>
|
||||
<option value={40}
|
||||
>{isMobile()
|
||||
>{isMobile
|
||||
? $LL.menu.settings.gameQuality.short.small()
|
||||
: $LL.menu.settings.gameQuality.long.small()}</option
|
||||
>
|
||||
<option value={20}
|
||||
>{isMobile()
|
||||
>{isMobile
|
||||
? $LL.menu.settings.gameQuality.short.minimum()
|
||||
: $LL.menu.settings.gameQuality.long.minimum()}</option
|
||||
>
|
||||
@ -120,22 +122,22 @@
|
||||
<div class="nes-select is-dark">
|
||||
<select bind:value={valueVideo}>
|
||||
<option value={30}
|
||||
>{isMobile()
|
||||
>{isMobile
|
||||
? $LL.menu.settings.videoQuality.short.high()
|
||||
: $LL.menu.settings.videoQuality.long.high()}</option
|
||||
>
|
||||
<option value={20}
|
||||
>{isMobile()
|
||||
>{isMobile
|
||||
? $LL.menu.settings.videoQuality.short.medium()
|
||||
: $LL.menu.settings.videoQuality.long.medium()}</option
|
||||
>
|
||||
<option value={10}
|
||||
>{isMobile()
|
||||
>{isMobile
|
||||
? $LL.menu.settings.videoQuality.short.small()
|
||||
: $LL.menu.settings.videoQuality.long.small()}</option
|
||||
>
|
||||
<option value={5}
|
||||
>{isMobile()
|
||||
>{isMobile
|
||||
? $LL.menu.settings.videoQuality.short.minimum()
|
||||
: $LL.menu.settings.videoQuality.long.minimum()}</option
|
||||
>
|
||||
@ -199,6 +201,8 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
div.settings-main {
|
||||
height: calc(100% - 40px);
|
||||
overflow-y: auto;
|
||||
@ -236,7 +240,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
div.settings-main {
|
||||
section {
|
||||
padding: 0;
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { obtainedMediaConstraintStore } from "../Stores/MediaStore";
|
||||
import { localStreamStore, isSilentStore } from "../Stores/MediaStore";
|
||||
import SoundMeterWidget from "./SoundMeterWidget.svelte";
|
||||
import { onDestroy } from "svelte";
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import { srcObject } from "./Video/utils";
|
||||
import LL from "../i18n/i18n-svelte";
|
||||
|
||||
@ -23,15 +23,77 @@
|
||||
isSilent = value;
|
||||
});
|
||||
|
||||
let cameraContainer: HTMLDivElement;
|
||||
|
||||
onMount(() => {
|
||||
cameraContainer.addEventListener("transitionend", () => {
|
||||
if (cameraContainer.classList.contains("hide")) {
|
||||
cameraContainer.style.visibility = "hidden";
|
||||
}
|
||||
});
|
||||
|
||||
cameraContainer.addEventListener("transitionstart", () => {
|
||||
if (!cameraContainer.classList.contains("hide")) {
|
||||
cameraContainer.style.visibility = "visible";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onDestroy(unsubscribeIsSilent);
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="video-container div-myCamVideo" class:hide={!$obtainedMediaConstraintStore.video || isSilent}>
|
||||
{#if $localStreamStore.type === "success" && $localStreamStore.stream}
|
||||
<video class="myCamVideo" use:srcObject={stream} autoplay muted playsinline />
|
||||
<SoundMeterWidget {stream} />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="is-silent" class:hide={isSilent}>{$LL.camera.my.silentZone()}</div>
|
||||
<div
|
||||
class="nes-container is-rounded my-cam-video-container"
|
||||
class:hide={($localStreamStore.type !== "success" || !$obtainedMediaConstraintStore.video) && !isSilent}
|
||||
bind:this={cameraContainer}
|
||||
>
|
||||
{#if isSilent}
|
||||
<div class="is-silent">{$LL.camera.my.silentZone()}</div>
|
||||
{:else if $localStreamStore.type === "success" && $localStreamStore.stream}
|
||||
<video class="my-cam-video" use:srcObject={stream} autoplay muted playsinline />
|
||||
<SoundMeterWidget {stream} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../style/breakpoints.scss";
|
||||
|
||||
.my-cam-video-container {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
bottom: 30px;
|
||||
max-height: 20%;
|
||||
transition: transform 1000ms;
|
||||
padding: 0;
|
||||
background-color: #00000099;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.my-cam-video-container.hide {
|
||||
transform: translateX(200%);
|
||||
}
|
||||
|
||||
.my-cam-video {
|
||||
background-color: #00000099;
|
||||
max-height: 20vh;
|
||||
width: 100%;
|
||||
-webkit-transform: scaleX(-1);
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.is-silent {
|
||||
font-size: 2em;
|
||||
color: white;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
.my-cam-video {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.my-cam-video-container.hide {
|
||||
right: -160px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -108,12 +108,16 @@
|
||||
pointer-events: auto;
|
||||
background-color: #333333;
|
||||
color: whitesmoke;
|
||||
|
||||
position: relative;
|
||||
z-index: 300;
|
||||
position: absolute;
|
||||
height: 70vh;
|
||||
width: 50vw;
|
||||
top: 10vh;
|
||||
margin: auto;
|
||||
top: 4%;
|
||||
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
section.report-menu-title {
|
||||
display: grid;
|
||||
@ -137,13 +141,4 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
div.report-menu-main {
|
||||
top: 21vh;
|
||||
height: 60vh;
|
||||
width: 100vw;
|
||||
font-size: 0.5em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -47,6 +47,8 @@
|
||||
</form>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
form.selectCompanionScene {
|
||||
font-family: "Press Start 2P";
|
||||
pointer-events: auto;
|
||||
@ -85,7 +87,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
form.selectCompanionScene button.selectCharacterButtonLeft {
|
||||
left: 5vw;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { fly, fade } from "svelte/transition";
|
||||
import { onMount } from "svelte";
|
||||
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||
import type { Message } from "../../Stores/TypeMessageStore/MessageStore";
|
||||
import { banMessageStore } from "../../Stores/TypeMessageStore/BanMessageStore";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
@ -13,6 +14,8 @@
|
||||
|
||||
onMount(() => {
|
||||
timeToRead();
|
||||
const gameScene = gameManager.getCurrentGameScene();
|
||||
gameScene.playSound("audio-report-message");
|
||||
});
|
||||
|
||||
function timeToRead() {
|
||||
@ -53,18 +56,19 @@
|
||||
on:click|preventDefault={closeBanMessage}>{nameButton}</button
|
||||
>
|
||||
</div>
|
||||
<!-- svelte-ignore a11y-media-has-caption -->
|
||||
<audio id="report-message" autoplay>
|
||||
<source src="/resources/objects/report-message.mp3" type="audio/mp3" />
|
||||
</audio>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
div.main-ban-message {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
top: 15vh;
|
||||
position: absolute;
|
||||
top: 4%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
z-index: 850;
|
||||
|
||||
height: 70vh;
|
||||
width: 60vw;
|
||||
|
@ -42,14 +42,17 @@
|
||||
div.main-text-message {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
|
||||
max-height: 25vh;
|
||||
width: 80vw;
|
||||
max-height: 25%;
|
||||
width: 60%;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
margin-bottom: 16px;
|
||||
margin-top: 0;
|
||||
top: 6%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-bottom: 0;
|
||||
z-index: 240;
|
||||
|
||||
pointer-events: auto;
|
||||
background-color: #333333;
|
||||
|
@ -25,11 +25,17 @@
|
||||
<style lang="scss">
|
||||
div.error-div {
|
||||
pointer-events: auto;
|
||||
margin-top: 10vh;
|
||||
margin-top: 4%;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
width: max-content;
|
||||
max-width: 80vw;
|
||||
z-index: 230;
|
||||
height: auto !important;
|
||||
background-clip: padding-box;
|
||||
|
||||
.button-bar {
|
||||
text-align: center;
|
||||
|
@ -1,15 +1,33 @@
|
||||
<script lang="typescript">
|
||||
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||
import type { EmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||
import type { ScreenSharingLocalMedia } from "../../Stores/ScreenSharingStore";
|
||||
import { videoFocusStore } from "../../Stores/VideoFocusStore";
|
||||
import type { Streamable } from "../../Stores/StreamableCollectionStore";
|
||||
import { srcObject } from "./utils";
|
||||
|
||||
export let clickable = false;
|
||||
|
||||
export let peer: ScreenSharingLocalMedia;
|
||||
let stream = peer.stream;
|
||||
export let cssClass: string | undefined;
|
||||
let embedScreen: EmbedScreen;
|
||||
|
||||
if (stream) {
|
||||
embedScreen = {
|
||||
type: "streamable",
|
||||
embed: stream as unknown as Streamable,
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="video-container {cssClass ? cssClass : ''}" class:hide={!stream}>
|
||||
{#if stream}
|
||||
<video use:srcObject={stream} autoplay muted playsinline on:click={() => videoFocusStore.toggleFocus(peer)} />
|
||||
<video
|
||||
use:srcObject={stream}
|
||||
autoplay
|
||||
muted
|
||||
playsinline
|
||||
on:click={() => (clickable ? highlightedEmbedScreen.toggleHighlight(embedScreen) : null)}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -7,14 +7,65 @@
|
||||
import type { Streamable } from "../../Stores/StreamableCollectionStore";
|
||||
|
||||
export let streamable: Streamable;
|
||||
export let isHightlighted = false;
|
||||
export let clickable = false;
|
||||
</script>
|
||||
|
||||
<div class="media-container">
|
||||
<div class="media-container nes-container is-rounded {isHightlighted ? 'hightlighted' : ''}" class:clickable>
|
||||
{#if streamable instanceof VideoPeer}
|
||||
<VideoMediaBox peer={streamable} />
|
||||
<VideoMediaBox peer={streamable} {clickable} />
|
||||
{:else if streamable instanceof ScreenSharingPeer}
|
||||
<ScreenSharingMediaBox peer={streamable} />
|
||||
<ScreenSharingMediaBox peer={streamable} {clickable} />
|
||||
{:else}
|
||||
<LocalStreamMediaBox peer={streamable} cssClass="" />
|
||||
<LocalStreamMediaBox peer={streamable} {clickable} cssClass="" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
.media-container {
|
||||
display: flex;
|
||||
margin-top: 4%;
|
||||
margin-bottom: 4%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
transition: margin-left 0.2s, margin-right 0.2s, margin-bottom 0.2s, margin-top 0.2s, max-height 0.2s,
|
||||
max-width 0.2s;
|
||||
pointer-events: auto;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
padding: 0;
|
||||
max-height: 85%;
|
||||
max-width: 85%;
|
||||
|
||||
&:hover {
|
||||
margin-top: 2%;
|
||||
margin-bottom: 2%;
|
||||
}
|
||||
|
||||
&.hightlighted {
|
||||
margin-top: 0% !important;
|
||||
margin-bottom: 0% !important;
|
||||
margin-left: 0% !important;
|
||||
|
||||
max-height: 100% !important;
|
||||
max-width: 96% !important;
|
||||
|
||||
&:hover {
|
||||
margin-top: 0% !important;
|
||||
margin-bottom: 0% !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.clickable {
|
||||
cursor: url("../../../style/images/cursor_pointer.png"), pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-only(md) {
|
||||
.media-container {
|
||||
margin-top: 10%;
|
||||
margin-bottom: 10%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,26 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { streamableCollectionStore } from "../../Stores/StreamableCollectionStore";
|
||||
import { videoFocusStore } from "../../Stores/VideoFocusStore";
|
||||
import { afterUpdate } from "svelte";
|
||||
import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStore";
|
||||
import MediaBox from "./MediaBox.svelte";
|
||||
|
||||
afterUpdate(() => {
|
||||
biggestAvailableAreaStore.recompute();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="main-section">
|
||||
{#if $videoFocusStore}
|
||||
{#key $videoFocusStore.uniqueId}
|
||||
<MediaBox streamable={$videoFocusStore} />
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
|
||||
{#if peer !== $videoFocusStore}
|
||||
<MediaBox streamable={peer} />
|
||||
{/if}
|
||||
{/each}
|
||||
</aside>
|
@ -1,12 +1,26 @@
|
||||
<script lang="ts">
|
||||
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||
import type { EmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||
import type { Streamable } from "../../Stores/StreamableCollectionStore";
|
||||
|
||||
import type { ScreenSharingPeer } from "../../WebRtc/ScreenSharingPeer";
|
||||
import { videoFocusStore } from "../../Stores/VideoFocusStore";
|
||||
import { getColorByString, srcObject } from "./utils";
|
||||
|
||||
export let clickable = false;
|
||||
|
||||
export let peer: ScreenSharingPeer;
|
||||
let streamStore = peer.streamStore;
|
||||
let name = peer.userName;
|
||||
let statusStore = peer.statusStore;
|
||||
|
||||
let embedScreen: EmbedScreen;
|
||||
|
||||
if (peer) {
|
||||
embedScreen = {
|
||||
type: "streamable",
|
||||
embed: peer as unknown as Streamable,
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="video-container">
|
||||
@ -20,7 +34,12 @@
|
||||
<i style="background-color: {getColorByString(name)};">{name}</i>
|
||||
{:else}
|
||||
<!-- svelte-ignore a11y-media-has-caption -->
|
||||
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)} />
|
||||
<video
|
||||
use:srcObject={$streamStore}
|
||||
autoplay
|
||||
playsinline
|
||||
on:click={() => (clickable ? highlightedEmbedScreen.toggleHighlight(embedScreen) : null)}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
@ -4,11 +4,17 @@
|
||||
import microphoneCloseImg from "../images/microphone-close.svg";
|
||||
import reportImg from "./images/report.svg";
|
||||
import blockSignImg from "./images/blockSign.svg";
|
||||
import { videoFocusStore } from "../../Stores/VideoFocusStore";
|
||||
import { showReportScreenStore } from "../../Stores/ShowReportScreenStore";
|
||||
import { getColorByString, srcObject } from "./utils";
|
||||
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||
import type { EmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||
import type { Streamable } from "../../Stores/StreamableCollectionStore";
|
||||
|
||||
import Woka from "../Woka/Woka.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { isMediaBreakpointOnly } from "../../Utils/BreakpointsUtils";
|
||||
|
||||
export let clickable = false;
|
||||
|
||||
export let peer: VideoPeer;
|
||||
let streamStore = peer.streamStore;
|
||||
@ -19,9 +25,32 @@
|
||||
function openReport(peer: VideoPeer): void {
|
||||
showReportScreenStore.set({ userId: peer.userId, userName: peer.userName });
|
||||
}
|
||||
|
||||
let embedScreen: EmbedScreen;
|
||||
let videoContainer: HTMLDivElement;
|
||||
let minimized = isMediaBreakpointOnly("md");
|
||||
|
||||
if (peer) {
|
||||
embedScreen = {
|
||||
type: "streamable",
|
||||
embed: peer as unknown as Streamable,
|
||||
};
|
||||
}
|
||||
|
||||
function noDrag() {
|
||||
return false;
|
||||
}
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
minimized = isMediaBreakpointOnly("md");
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
resizeObserver.observe(videoContainer);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="video-container">
|
||||
<div class="video-container" class:no-clikable={!clickable} bind:this={videoContainer}>
|
||||
{#if $statusStore === "connecting"}
|
||||
<div class="connecting-spinner" />
|
||||
{/if}
|
||||
@ -30,42 +59,60 @@
|
||||
{/if}
|
||||
<!-- {#if !$constraintStore || $constraintStore.video === false} -->
|
||||
<i
|
||||
class="container {!$constraintStore || $constraintStore.video === false ? '' : 'minimized'}"
|
||||
class="container"
|
||||
class:has-video={$constraintStore && $constraintStore.video === true}
|
||||
class:minimized={(!$constraintStore || $constraintStore.video !== true) && minimized}
|
||||
style="background-color: {getColorByString(name)};"
|
||||
>
|
||||
<span>{peer.userName}</span>
|
||||
<span style="noselect">{peer.userName}</span>
|
||||
<div class="woka-icon"><Woka userId={peer.userId} placeholderSrc={""} /></div>
|
||||
</i>
|
||||
<!-- {/if} -->
|
||||
{#if $constraintStore && $constraintStore.audio === false}
|
||||
<img src={microphoneCloseImg} class="active" alt="Muted" />
|
||||
<img
|
||||
src={microphoneCloseImg}
|
||||
class="active noselect"
|
||||
draggable="false"
|
||||
on:dragstart|preventDefault={noDrag}
|
||||
alt="Muted"
|
||||
/>
|
||||
{/if}
|
||||
<button class="report" on:click={() => openReport(peer)}>
|
||||
<img alt="Report this user" src={reportImg} />
|
||||
<span>Report/Block</span>
|
||||
<img alt="Report this user" draggable="false" on:dragstart|preventDefault={noDrag} src={reportImg} />
|
||||
<span class="noselect">Report/Block</span>
|
||||
</button>
|
||||
<!-- svelte-ignore a11y-media-has-caption -->
|
||||
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)} />
|
||||
<img src={blockSignImg} class="block-logo" alt="Block" />
|
||||
<video
|
||||
use:srcObject={$streamStore}
|
||||
autoplay
|
||||
playsinline
|
||||
on:click={() => (clickable ? highlightedEmbedScreen.toggleHighlight(embedScreen) : null)}
|
||||
/>
|
||||
<img src={blockSignImg} draggable="false" on:dragstart|preventDefault={noDrag} class="block-logo" alt="Block" />
|
||||
{#if $constraintStore && $constraintStore.audio !== false}
|
||||
<SoundMeterWidget stream={$streamStore} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="scss">
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.minimized {
|
||||
left: auto;
|
||||
transform: scale(0.5);
|
||||
opacity: 0.5;
|
||||
}
|
||||
&.has-video {
|
||||
left: auto;
|
||||
transform: scale(0.5);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.woka-icon {
|
||||
margin-right: 3px;
|
||||
&.minimized {
|
||||
transform: scale(0.5);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.woka-icon {
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,16 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { LayoutMode } from "../../WebRtc/LayoutManager";
|
||||
import { layoutModeStore } from "../../Stores/StreamableCollectionStore";
|
||||
import PresentationLayout from "./PresentationLayout.svelte";
|
||||
import ChatLayout from "./ChatLayout.svelte";
|
||||
// import {LayoutMode} from "../../WebRtc/LayoutManager";
|
||||
// import {layoutModeStore} from "../../Stores/StreamableCollectionStore";
|
||||
// import PresentationLayout from "./PresentationLayout.svelte";
|
||||
// import ChatLayout from "./ChatLayout.svelte";
|
||||
</script>
|
||||
|
||||
<div class="video-overlay">
|
||||
{#if $layoutModeStore === LayoutMode.Presentation}
|
||||
<!-- {#if $layoutModeStore === LayoutMode.Presentation }
|
||||
<PresentationLayout />
|
||||
{:else}
|
||||
<ChatLayout />
|
||||
{/if}
|
||||
{/if} -->
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -57,6 +57,7 @@
|
||||
height: 120px;
|
||||
margin: auto;
|
||||
animation: spin 2s linear infinite;
|
||||
z-index: 102;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
|
@ -27,18 +27,22 @@
|
||||
<style lang="scss">
|
||||
main.warningMain {
|
||||
pointer-events: auto;
|
||||
width: 100vw;
|
||||
background-color: #f9e81e;
|
||||
color: #14304c;
|
||||
width: 80%;
|
||||
background-color: #F9E81E;
|
||||
color: #14304C;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
|
||||
top: 4%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
transform: translate(-50%, 0);
|
||||
font-family: Lato;
|
||||
min-width: 300px;
|
||||
opacity: 0.9;
|
||||
z-index: 2;
|
||||
|
||||
z-index: 270;
|
||||
h2 {
|
||||
padding: 5px;
|
||||
}
|
||||
|
@ -22,10 +22,21 @@
|
||||
src = source ?? placeholderSrc;
|
||||
});
|
||||
|
||||
function noDrag() {
|
||||
return false;
|
||||
}
|
||||
|
||||
onDestroy(unsubscribe);
|
||||
</script>
|
||||
|
||||
<img {src} alt="" class="nes-pointer" style="--theme-width: {width}; --theme-height: {height}" />
|
||||
<img
|
||||
{src}
|
||||
alt=""
|
||||
class="nes-pointer noselect"
|
||||
style="--theme-width: {width}; --theme-height: {height}"
|
||||
draggable="false"
|
||||
on:dragstart|preventDefault={noDrag}
|
||||
/>
|
||||
|
||||
<style>
|
||||
img {
|
||||
|
@ -49,6 +49,8 @@
|
||||
</form>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../style/breakpoints.scss";
|
||||
|
||||
form.selectCharacterScene {
|
||||
font-family: "Press Start 2P";
|
||||
pointer-events: auto;
|
||||
@ -91,7 +93,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
form.selectCharacterScene button.selectCharacterButtonLeft {
|
||||
left: 5vw;
|
||||
}
|
||||
|
@ -42,8 +42,6 @@ export const DISABLE_ANONYMOUS: boolean = getEnv("DISABLE_ANONYMOUS") === "true"
|
||||
export const OPID_LOGIN_SCREEN_PROVIDER = getEnv("OPID_LOGIN_SCREEN_PROVIDER");
|
||||
const FALLBACK_LOCALE = getEnv("FALLBACK_LOCALE") || undefined;
|
||||
|
||||
export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600;
|
||||
|
||||
export {
|
||||
DEBUG_MODE,
|
||||
START_ROOM_URL,
|
||||
|
@ -63,8 +63,6 @@ export class SoundMeter {
|
||||
//this.slow = 0.95 * that.slow + 0.05 * that.instant;
|
||||
//this.clip = clipcount / input.length;
|
||||
|
||||
//console.log('instant', this.instant, 'clip', this.clip);
|
||||
|
||||
return this.instant;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@ export enum GameMapProperties {
|
||||
OPEN_WEBSITE = "openWebsite",
|
||||
OPEN_WEBSITE_ALLOW_API = "openWebsiteAllowApi",
|
||||
OPEN_WEBSITE_POLICY = "openWebsitePolicy",
|
||||
OPEN_WEBSITE_WIDTH = "openWebsiteWidth",
|
||||
OPEN_WEBSITE_POSITION = "openWebsitePosition",
|
||||
OPEN_WEBSITE_TRIGGER = "openWebsiteTrigger",
|
||||
OPEN_WEBSITE_TRIGGER_MESSAGE = "openWebsiteTriggerMessage",
|
||||
|
@ -252,7 +252,7 @@ export class GameScene extends DirtyScene {
|
||||
}
|
||||
this.load.audio("audio-webrtc-in", "/resources/objects/webrtc-in.mp3");
|
||||
this.load.audio("audio-webrtc-out", "/resources/objects/webrtc-out.mp3");
|
||||
//this.load.audio('audio-report-message', '/resources/objects/report-message.mp3');
|
||||
this.load.audio("audio-report-message", "/resources/objects/report-message.mp3");
|
||||
this.sound.pauseOnBlur = false;
|
||||
|
||||
this.load.on(FILE_LOAD_ERROR, (file: { src: string }) => {
|
||||
@ -632,13 +632,9 @@ export class GameScene extends DirtyScene {
|
||||
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
|
||||
const newPeerNumber = peers.size;
|
||||
if (newPeerNumber > oldPeerNumber) {
|
||||
this.sound.play("audio-webrtc-in", {
|
||||
volume: 0.2,
|
||||
});
|
||||
this.playSound("audio-webrtc-in");
|
||||
} else if (newPeerNumber < oldPeerNumber) {
|
||||
this.sound.play("audio-webrtc-out", {
|
||||
volume: 0.2,
|
||||
});
|
||||
this.playSound("audio-webrtc-out");
|
||||
}
|
||||
oldPeerNumber = newPeerNumber;
|
||||
});
|
||||
@ -1265,21 +1261,21 @@ ${escapedMessage}
|
||||
throw new Error("Unknown query source");
|
||||
}
|
||||
|
||||
const coWebsite = await coWebsiteManager.loadCoWebsite(
|
||||
const coWebsite = coWebsiteManager.addCoWebsite(
|
||||
openCoWebsite.url,
|
||||
iframeListener.getBaseUrlFromSource(source),
|
||||
openCoWebsite.allowApi,
|
||||
openCoWebsite.allowPolicy,
|
||||
openCoWebsite.position
|
||||
openCoWebsite.position,
|
||||
openCoWebsite.closable ?? true
|
||||
);
|
||||
|
||||
if (!coWebsite) {
|
||||
throw new Error("Error on opening co-website");
|
||||
if (openCoWebsite.lazy !== undefined && !openCoWebsite.lazy) {
|
||||
await coWebsiteManager.loadCoWebsite(coWebsite);
|
||||
}
|
||||
|
||||
return {
|
||||
id: coWebsite.iframe.id,
|
||||
position: coWebsite.position,
|
||||
};
|
||||
});
|
||||
|
||||
@ -1289,7 +1285,6 @@ ${escapedMessage}
|
||||
return coWebsites.map((coWebsite: CoWebsite) => {
|
||||
return {
|
||||
id: coWebsite.iframe.id,
|
||||
position: coWebsite.position,
|
||||
};
|
||||
});
|
||||
});
|
||||
@ -1565,6 +1560,12 @@ ${escapedMessage}
|
||||
}
|
||||
}
|
||||
|
||||
public playSound(sound: string) {
|
||||
this.sound.play(sound, {
|
||||
volume: 0.2,
|
||||
});
|
||||
}
|
||||
|
||||
public cleanupClosingScene(): void {
|
||||
// stop playing audio, close any open website, stop any open Jitsi
|
||||
coWebsiteManager.closeCoWebsites().catch((e) => console.error(e));
|
||||
@ -1602,7 +1603,7 @@ ${escapedMessage}
|
||||
this.sharedVariablesManager?.close();
|
||||
this.embeddedWebsiteManager?.close();
|
||||
|
||||
mediaManager.hideGameOverlay();
|
||||
mediaManager.hideMyCamera();
|
||||
|
||||
for (const iframeEvents of this.iframeSubscriptionList) {
|
||||
iframeEvents.unsubscribe();
|
||||
@ -2111,6 +2112,17 @@ ${escapedMessage}
|
||||
biggestAvailableAreaStore.recompute();
|
||||
}
|
||||
|
||||
public enableMediaBehaviors() {
|
||||
const silent = this.gameMap.getCurrentProperties().get(GameMapProperties.SILENT);
|
||||
this.connection?.setSilent(!!silent);
|
||||
mediaManager.showMyCamera();
|
||||
}
|
||||
|
||||
public disableMediaBehaviors() {
|
||||
this.connection?.setSilent(true);
|
||||
mediaManager.hideMyCamera();
|
||||
}
|
||||
|
||||
public startJitsi(roomName: string, jwt?: string): void {
|
||||
const allProps = this.gameMap.getCurrentProperties();
|
||||
const jitsiConfig = this.safeParseJSONstring(
|
||||
@ -2122,28 +2134,21 @@ ${escapedMessage}
|
||||
GameMapProperties.JITSI_INTERFACE_CONFIG
|
||||
);
|
||||
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
|
||||
const jitsiWidth = allProps.get(GameMapProperties.JITSI_WIDTH) as number | undefined;
|
||||
|
||||
jitsiFactory
|
||||
.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl, jitsiWidth)
|
||||
.catch((e) => console.error(e));
|
||||
this.connection?.setSilent(true);
|
||||
mediaManager.hideGameOverlay();
|
||||
analyticsClient.enteredJitsi(roomName, this.room.id);
|
||||
|
||||
//permit to stop jitsi when user close iframe
|
||||
mediaManager.addTriggerCloseJitsiFrameButton("close-jitsi", () => {
|
||||
this.stopJitsi();
|
||||
jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl).catch(() => {
|
||||
console.error("Cannot start a Jitsi co-website");
|
||||
});
|
||||
this.disableMediaBehaviors();
|
||||
analyticsClient.enteredJitsi(roomName, this.room.id);
|
||||
}
|
||||
|
||||
public stopJitsi(): void {
|
||||
const silent = this.gameMap.getCurrentProperties().get(GameMapProperties.SILENT);
|
||||
this.connection?.setSilent(!!silent);
|
||||
jitsiFactory.stop();
|
||||
mediaManager.showGameOverlay();
|
||||
|
||||
mediaManager.removeTriggerCloseJitsiFrameButton("close-jitsi");
|
||||
const coWebsite = coWebsiteManager.searchJitsi();
|
||||
if (coWebsite) {
|
||||
coWebsiteManager.closeCoWebsite(coWebsite).catch(() => {
|
||||
console.error("Error during Jitsi co-website closing");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//todo: put this into an 'orchestrator' scene (EntryScene?)
|
||||
|
@ -11,10 +11,10 @@ import { areCharacterLayersValid } from "../../Connexion/LocalUser";
|
||||
import { SelectCharacterSceneName } from "./SelectCharacterScene";
|
||||
import { activeRowStore, customCharacterSceneVisibleStore } from "../../Stores/CustomCharacterStore";
|
||||
import { waScaleManager } from "../Services/WaScaleManager";
|
||||
import { isMobile } from "../../Enum/EnvironmentVariable";
|
||||
import { CustomizedCharacter } from "../Entity/CustomizedCharacter";
|
||||
import { get } from "svelte/store";
|
||||
import { analyticsClient } from "../../Administration/AnalyticsClient";
|
||||
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
|
||||
|
||||
export const CustomizeSceneName = "CustomizeScene";
|
||||
|
||||
@ -67,12 +67,12 @@ export class CustomizeScene extends AbstractCharacterScene {
|
||||
customCharacterSceneVisibleStore.set(true);
|
||||
this.events.addListener("wake", () => {
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMobile() ? 3 : 1;
|
||||
waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 3 : 1;
|
||||
customCharacterSceneVisibleStore.set(true);
|
||||
});
|
||||
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMobile() ? 3 : 1;
|
||||
waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 3 : 1;
|
||||
|
||||
this.Rectangle = this.add.rectangle(
|
||||
this.cameras.main.worldView.x + this.cameras.main.width / 2,
|
||||
|
@ -12,8 +12,8 @@ import { touchScreenManager } from "../../Touch/TouchScreenManager";
|
||||
import { PinchManager } from "../UserInput/PinchManager";
|
||||
import { selectCharacterSceneVisibleStore } from "../../Stores/SelectCharacterStore";
|
||||
import { waScaleManager } from "../Services/WaScaleManager";
|
||||
import { isMobile } from "../../Enum/EnvironmentVariable";
|
||||
import { analyticsClient } from "../../Administration/AnalyticsClient";
|
||||
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
|
||||
|
||||
//todo: put this constants in a dedicated file
|
||||
export const SelectCharacterSceneName = "SelectCharacterScene";
|
||||
@ -60,7 +60,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
||||
selectCharacterSceneVisibleStore.set(true);
|
||||
this.events.addListener("wake", () => {
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMobile() ? 2 : 1;
|
||||
waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 2 : 1;
|
||||
selectCharacterSceneVisibleStore.set(true);
|
||||
});
|
||||
|
||||
@ -69,7 +69,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
||||
}
|
||||
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMobile() ? 2 : 1;
|
||||
waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 2 : 1;
|
||||
|
||||
const rectangleXStart = this.game.renderer.width / 2 - (this.nbCharactersPerRow / 2) * 32 + 16;
|
||||
this.selectedRectangle = this.add.rectangle(rectangleXStart, 90, 32, 32).setStrokeStyle(2, 0xffffff);
|
||||
|
@ -9,7 +9,7 @@ import { touchScreenManager } from "../../Touch/TouchScreenManager";
|
||||
import { PinchManager } from "../UserInput/PinchManager";
|
||||
import { selectCompanionSceneVisibleStore } from "../../Stores/SelectCompanionStore";
|
||||
import { waScaleManager } from "../Services/WaScaleManager";
|
||||
import { isMobile } from "../../Enum/EnvironmentVariable";
|
||||
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
|
||||
|
||||
export const SelectCompanionSceneName = "SelectCompanionScene";
|
||||
|
||||
@ -44,7 +44,7 @@ export class SelectCompanionScene extends ResizableScene {
|
||||
selectCompanionSceneVisibleStore.set(true);
|
||||
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMobile() ? 2 : 1;
|
||||
waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 2 : 1;
|
||||
|
||||
if (touchScreenManager.supportTouchScreen) {
|
||||
new PinchManager(this);
|
||||
|
@ -37,19 +37,17 @@ export class WaScaleManager {
|
||||
height: height * devicePixelRatio,
|
||||
});
|
||||
|
||||
if (gameSize.width == 0) {
|
||||
return;
|
||||
if (realSize.width !== 0 && gameSize.width !== 0 && devicePixelRatio !== 0) {
|
||||
this.actualZoom = realSize.width / gameSize.width / devicePixelRatio;
|
||||
}
|
||||
|
||||
this.actualZoom = realSize.width / gameSize.width / devicePixelRatio;
|
||||
|
||||
this.scaleManager.setZoom(realSize.width / gameSize.width / devicePixelRatio);
|
||||
this.scaleManager.setZoom(this.actualZoom);
|
||||
this.scaleManager.resize(gameSize.width, gameSize.height);
|
||||
|
||||
// Override bug in canvas resizing in Phaser. Let's resize the canvas ourselves
|
||||
const style = this.scaleManager.canvas.style;
|
||||
style.width = Math.ceil(realSize.width / devicePixelRatio) + "px";
|
||||
style.height = Math.ceil(realSize.height / devicePixelRatio) + "px";
|
||||
style.width = Math.ceil(realSize.width !== 0 ? realSize.width / devicePixelRatio : 0) + "px";
|
||||
style.height = Math.ceil(realSize.height !== 0 ? realSize.height / devicePixelRatio : 0) + "px";
|
||||
|
||||
// Resize the game element at the same size at the canvas
|
||||
const gameStyle = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("game").style;
|
||||
|
@ -2,14 +2,14 @@ import { get, writable } from "svelte/store";
|
||||
import type { Box } from "../WebRtc/LayoutManager";
|
||||
import { HtmlUtils } from "../WebRtc/HtmlUtils";
|
||||
import { LayoutMode } from "../WebRtc/LayoutManager";
|
||||
import { layoutModeStore } from "./StreamableCollectionStore";
|
||||
import { embedScreenLayout } from "./EmbedScreensStore";
|
||||
|
||||
/**
|
||||
* Tries to find the biggest available box of remaining space (this is a space where we can center the character)
|
||||
*/
|
||||
function findBiggestAvailableArea(): Box {
|
||||
const game = HtmlUtils.querySelectorOrFail<HTMLCanvasElement>("#game canvas");
|
||||
if (get(layoutModeStore) === LayoutMode.VideoChat) {
|
||||
if (get(embedScreenLayout) === LayoutMode.VideoChat) {
|
||||
const children = document.querySelectorAll<HTMLDivElement>("div.chat-mode > div");
|
||||
const htmlChildren = Array.from(children.values());
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
/**
|
||||
* A store that contains whether the game overlay is shown or not.
|
||||
* Typically, the overlay is hidden when entering Jitsi meet.
|
||||
*/
|
||||
function createGameOverlayVisibilityStore() {
|
||||
const { subscribe, set, update } = writable(false);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
showGameOverlay: () => set(true),
|
||||
hideGameOverlay: () => set(false),
|
||||
};
|
||||
}
|
||||
|
||||
export const gameOverlayVisibilityStore = createGameOverlayVisibilityStore();
|
@ -51,6 +51,6 @@ function createLayoutManagerAction() {
|
||||
|
||||
export const layoutManagerActionStore = createLayoutManagerAction();
|
||||
|
||||
export const layoutManagerVisibilityStore = derived(layoutManagerActionStore, ($layoutManagerActionStore) => {
|
||||
export const layoutManagerActionVisibilityStore = derived(layoutManagerActionStore, ($layoutManagerActionStore) => {
|
||||
return !!$layoutManagerActionStore.length;
|
||||
});
|
||||
|
@ -6,7 +6,7 @@ import { BrowserTooOldError } from "./Errors/BrowserTooOldError";
|
||||
import { errorStore } from "./ErrorStore";
|
||||
import { getNavigatorType, isIOS, NavigatorType } from "../WebRtc/DeviceUtils";
|
||||
import { WebviewOnOldIOS } from "./Errors/WebviewOnOldIOS";
|
||||
import { gameOverlayVisibilityStore } from "./GameOverlayStoreVisibility";
|
||||
import { myCameraVisibilityStore } from "./MyCameraStoreVisibility";
|
||||
import { peerStore } from "./PeerStore";
|
||||
import { privacyShutdownStore } from "./PrivacyShutdownStore";
|
||||
import { MediaStreamConstraintsError } from "./Errors/MediaStreamConstraintsError";
|
||||
@ -233,7 +233,7 @@ export const mediaStreamConstraintsStore = derived(
|
||||
[
|
||||
requestedCameraState,
|
||||
requestedMicrophoneState,
|
||||
gameOverlayVisibilityStore,
|
||||
myCameraVisibilityStore,
|
||||
enableCameraSceneVisibilityStore,
|
||||
videoConstraintStore,
|
||||
audioConstraintStore,
|
||||
@ -245,7 +245,7 @@ export const mediaStreamConstraintsStore = derived(
|
||||
[
|
||||
$requestedCameraState,
|
||||
$requestedMicrophoneState,
|
||||
$gameOverlayVisibilityStore,
|
||||
$myCameraVisibilityStore,
|
||||
$enableCameraSceneVisibilityStore,
|
||||
$videoConstraintStore,
|
||||
$audioConstraintStore,
|
||||
@ -283,7 +283,7 @@ export const mediaStreamConstraintsStore = derived(
|
||||
}
|
||||
|
||||
// Disable webcam and microphone when in a Jitsi
|
||||
if ($gameOverlayVisibilityStore === false) {
|
||||
if ($myCameraVisibilityStore === false) {
|
||||
currentVideoConstraint = false;
|
||||
currentAudioConstraint = false;
|
||||
}
|
||||
|
8
front/src/Stores/MyCameraStoreVisibility.ts
Normal file
8
front/src/Stores/MyCameraStoreVisibility.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
/**
|
||||
* A store that contains whether my camera & actions is shown or not.
|
||||
* Typically, the overlay is hidden when entering Jitsi meet.
|
||||
*/
|
||||
|
||||
export const myCameraVisibilityStore = writable(false);
|
@ -1,7 +1,7 @@
|
||||
import { derived, Readable, readable, writable } from "svelte/store";
|
||||
import { peerStore } from "./PeerStore";
|
||||
import type { LocalStreamStoreValue } from "./MediaStore";
|
||||
import { gameOverlayVisibilityStore } from "./GameOverlayStoreVisibility";
|
||||
import { myCameraVisibilityStore } from "./MyCameraStoreVisibility";
|
||||
|
||||
declare const navigator: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
@ -41,8 +41,8 @@ let previousComputedAudioConstraint: boolean | MediaTrackConstraints = false;
|
||||
* A store containing the media constraints we want to apply.
|
||||
*/
|
||||
export const screenSharingConstraintsStore = derived(
|
||||
[requestedScreenSharingState, gameOverlayVisibilityStore, peerStore],
|
||||
([$requestedScreenSharingState, $gameOverlayVisibilityStore, $peerStore], set) => {
|
||||
[requestedScreenSharingState, myCameraVisibilityStore, peerStore],
|
||||
([$requestedScreenSharingState, $myCameraVisibilityStore, $peerStore], set) => {
|
||||
let currentVideoConstraint: boolean | MediaTrackConstraints = true;
|
||||
let currentAudioConstraint: boolean | MediaTrackConstraints = false;
|
||||
|
||||
@ -53,7 +53,7 @@ export const screenSharingConstraintsStore = derived(
|
||||
}
|
||||
|
||||
// Disable screen sharing when in a Jitsi
|
||||
if (!$gameOverlayVisibilityStore) {
|
||||
if (!$myCameraVisibilityStore) {
|
||||
currentVideoConstraint = false;
|
||||
currentAudioConstraint = false;
|
||||
}
|
||||
|
@ -1,13 +1,10 @@
|
||||
import { derived, get, Readable, writable } from "svelte/store";
|
||||
import { derived, get, Readable } from "svelte/store";
|
||||
import { ScreenSharingLocalMedia, screenSharingLocalMedia } from "./ScreenSharingStore";
|
||||
import { peerStore, screenSharingStreamStore } from "./PeerStore";
|
||||
import type { RemotePeer } from "../WebRtc/SimplePeer";
|
||||
import { LayoutMode } from "../WebRtc/LayoutManager";
|
||||
|
||||
export type Streamable = RemotePeer | ScreenSharingLocalMedia;
|
||||
|
||||
export const layoutModeStore = writable<LayoutMode>(LayoutMode.Presentation);
|
||||
|
||||
/**
|
||||
* A store that contains everything that can produce a stream (so the peers + the local screen sharing stream)
|
||||
*/
|
||||
|
@ -7,6 +7,11 @@ export class HtmlUtils {
|
||||
throw new Error("Cannot find HTML element with id '" + id + "'");
|
||||
}
|
||||
|
||||
public static getElementById<T extends HTMLElement>(id: string): T | undefined {
|
||||
const elem = document.getElementById(id);
|
||||
return HtmlUtils.isHtmlElement<T>(elem) ? elem : undefined;
|
||||
}
|
||||
|
||||
public static querySelectorOrFail<T extends HTMLElement>(selector: string): T {
|
||||
const elem = document.querySelector<T>(selector);
|
||||
if (HtmlUtils.isHtmlElement<T>(elem)) {
|
||||
|
@ -7,8 +7,7 @@ import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStor
|
||||
export type StartScreenSharingCallback = (media: MediaStream) => void;
|
||||
export type StopScreenSharingCallback = (media: MediaStream) => void;
|
||||
|
||||
import { cowebsiteCloseButtonId } from "./CoWebsiteManager";
|
||||
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
|
||||
import { myCameraVisibilityStore } from "../Stores/MyCameraStoreVisibility";
|
||||
import { layoutManagerActionStore } from "../Stores/LayoutManagerStore";
|
||||
import { MediaStreamConstraintsError } from "../Stores/Errors/MediaStreamConstraintsError";
|
||||
import { localUserStore } from "../Connexion/LocalUserStore";
|
||||
@ -20,8 +19,6 @@ export class MediaManager {
|
||||
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
||||
stopScreenSharingCallBacks: Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
|
||||
|
||||
private triggerCloseJistiFrame: Map<String, Function> = new Map<String, Function>();
|
||||
|
||||
private userInputManager?: UserInputManager;
|
||||
|
||||
constructor() {
|
||||
@ -73,36 +70,12 @@ export class MediaManager {
|
||||
});
|
||||
}
|
||||
|
||||
public showGameOverlay(): void {
|
||||
const gameOverlay = HtmlUtils.getElementByIdOrFail("game-overlay");
|
||||
gameOverlay.classList.add("active");
|
||||
|
||||
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
||||
const functionTrigger = () => {
|
||||
this.triggerCloseJitsiFrameButton();
|
||||
};
|
||||
buttonCloseFrame.removeEventListener("click", () => {
|
||||
buttonCloseFrame.blur();
|
||||
functionTrigger();
|
||||
});
|
||||
|
||||
gameOverlayVisibilityStore.showGameOverlay();
|
||||
public showMyCamera(): void {
|
||||
myCameraVisibilityStore.set(true);
|
||||
}
|
||||
|
||||
public hideGameOverlay(): void {
|
||||
const gameOverlay = HtmlUtils.getElementByIdOrFail("game-overlay");
|
||||
gameOverlay.classList.remove("active");
|
||||
|
||||
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
|
||||
const functionTrigger = () => {
|
||||
this.triggerCloseJitsiFrameButton();
|
||||
};
|
||||
buttonCloseFrame.addEventListener("click", () => {
|
||||
buttonCloseFrame.blur();
|
||||
functionTrigger();
|
||||
});
|
||||
|
||||
gameOverlayVisibilityStore.hideGameOverlay();
|
||||
public hideMyCamera(): void {
|
||||
myCameraVisibilityStore.set(false);
|
||||
}
|
||||
|
||||
private getScreenSharingId(userId: string): string {
|
||||
@ -179,20 +152,6 @@ export class MediaManager {
|
||||
return connectingSpinnerDiv;
|
||||
}
|
||||
|
||||
public addTriggerCloseJitsiFrameButton(id: String, Function: Function) {
|
||||
this.triggerCloseJistiFrame.set(id, Function);
|
||||
}
|
||||
|
||||
public removeTriggerCloseJitsiFrameButton(id: String) {
|
||||
this.triggerCloseJistiFrame.delete(id);
|
||||
}
|
||||
|
||||
private triggerCloseJitsiFrameButton(): void {
|
||||
for (const callback of this.triggerCloseJistiFrame.values()) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
public setUserInputManager(userInputManager: UserInputManager) {
|
||||
this.userInputManager = userInputManager;
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ import type { RoomConnection } from "../Connexion/RoomConnection";
|
||||
import { MESSAGE_TYPE_CONSTRAINT, PeerStatus } from "./VideoPeer";
|
||||
import type { UserSimplePeerInterface } from "./SimplePeer";
|
||||
import { Readable, readable } from "svelte/store";
|
||||
import { videoFocusStore } from "../Stores/VideoFocusStore";
|
||||
import { getIceServersConfig } from "../Components/Video/utils";
|
||||
import { isMobile } from "../Enum/EnvironmentVariable";
|
||||
import { highlightedEmbedScreen } from "../Stores/EmbedScreensStore";
|
||||
import { isMediaBreakpointUp } from "../Utils/BreakpointsUtils";
|
||||
|
||||
const Peer: SimplePeerNamespace.SimplePeer = require("simple-peer");
|
||||
|
||||
@ -43,7 +43,10 @@ export class ScreenSharingPeer extends Peer {
|
||||
|
||||
this.streamStore = readable<MediaStream | null>(null, (set) => {
|
||||
const onStream = (stream: MediaStream | null) => {
|
||||
videoFocusStore.focus(this);
|
||||
highlightedEmbedScreen.highlight({
|
||||
type: "streamable",
|
||||
embed: this,
|
||||
});
|
||||
set(stream);
|
||||
};
|
||||
const onData = (chunk: Buffer) => {
|
||||
@ -177,7 +180,13 @@ export class ScreenSharingPeer extends Peer {
|
||||
public stopPushingScreenSharingToRemoteUser(stream: MediaStream) {
|
||||
this.removeStream(stream);
|
||||
this.write(
|
||||
new Buffer(JSON.stringify({ type: MESSAGE_TYPE_CONSTRAINT, streamEnded: true, isMobile: isMobile() }))
|
||||
new Buffer(
|
||||
JSON.stringify({
|
||||
type: MESSAGE_TYPE_CONSTRAINT,
|
||||
streamEnded: true,
|
||||
isMobile: isMediaBreakpointUp("md"),
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ export class SimplePeer {
|
||||
}
|
||||
);
|
||||
|
||||
mediaManager.showGameOverlay();
|
||||
mediaManager.showMyCamera();
|
||||
|
||||
//receive message start
|
||||
this.Connection.webRtcStartMessageStream.subscribe((message: UserSimplePeerInterface) => {
|
||||
|
@ -9,7 +9,7 @@ import { localStreamStore, obtainedMediaConstraintStore, ObtainedMediaStreamCons
|
||||
import { playersStore } from "../Stores/PlayersStore";
|
||||
import { chatMessagesStore, newChatMessageSubject } from "../Stores/ChatStore";
|
||||
import { getIceServersConfig } from "../Components/Video/utils";
|
||||
import { isMobile } from "../Enum/EnvironmentVariable";
|
||||
import { isMediaBreakpointUp } from "../Utils/BreakpointsUtils";
|
||||
|
||||
const Peer: SimplePeerNamespace.SimplePeer = require("simple-peer");
|
||||
|
||||
@ -202,7 +202,7 @@ export class VideoPeer extends Peer {
|
||||
JSON.stringify({
|
||||
type: MESSAGE_TYPE_CONSTRAINT,
|
||||
...constraints,
|
||||
isMobile: isMobile(),
|
||||
isMobile: isMediaBreakpointUp("md"),
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -2,7 +2,7 @@ import "phaser";
|
||||
import GameConfig = Phaser.Types.Core.GameConfig;
|
||||
import "../style/index.scss";
|
||||
|
||||
import { DEBUG_MODE, isMobile } from "./Enum/EnvironmentVariable";
|
||||
import { DEBUG_MODE } from "./Enum/EnvironmentVariable";
|
||||
import { LoginScene } from "./Phaser/Login/LoginScene";
|
||||
import { ReconnectingScene } from "./Phaser/Reconnecting/ReconnectingScene";
|
||||
import { SelectCharacterScene } from "./Phaser/Login/SelectCharacterScene";
|
||||
@ -24,6 +24,7 @@ import App from "./Components/App.svelte";
|
||||
import { HtmlUtils } from "./WebRtc/HtmlUtils";
|
||||
import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer;
|
||||
import { analyticsClient } from "./Administration/AnalyticsClient";
|
||||
import { isMediaBreakpointUp } from "./Utils/BreakpointsUtils";
|
||||
|
||||
const { width, height } = coWebsiteManager.getGameSize();
|
||||
const valueGameQuality = localUserStore.getGameQualityValue();
|
||||
@ -90,7 +91,7 @@ const config: GameConfig = {
|
||||
scene: [
|
||||
EntryScene,
|
||||
LoginScene,
|
||||
isMobile() ? SelectCharacterMobileScene : SelectCharacterScene,
|
||||
isMediaBreakpointUp("md") ? SelectCharacterMobileScene : SelectCharacterScene,
|
||||
SelectCompanionScene,
|
||||
EnableCameraScene,
|
||||
ReconnectingScene,
|
||||
@ -136,7 +137,6 @@ const config: GameConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
//const game = new Phaser.Game(config);
|
||||
const game = new Game(config);
|
||||
|
||||
waScaleManager.setGame(game);
|
||||
@ -156,7 +156,7 @@ coWebsiteManager.onResize.subscribe(() => {
|
||||
iframeListener.init();
|
||||
|
||||
const app = new App({
|
||||
target: HtmlUtils.getElementByIdOrFail("svelte-overlay"),
|
||||
target: HtmlUtils.getElementByIdOrFail("game-overlay"),
|
||||
props: {
|
||||
game: game,
|
||||
},
|
||||
|
@ -30,7 +30,7 @@ section.section-input-send-text {
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||
@include media-breakpoint-up(md) {
|
||||
section.section-input-send-text {
|
||||
--height-toolbar: 30%;
|
||||
|
||||
|
@ -1,136 +0,0 @@
|
||||
@media (max-aspect-ratio: 1/1) {
|
||||
|
||||
#main-container {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
|
||||
#cowebsite {
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
|
||||
&.loading {
|
||||
transform: translateY(-90%);
|
||||
}
|
||||
&.hidden {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
main {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
aside {
|
||||
height: 50px;
|
||||
cursor: ns-resize;
|
||||
flex-direction: row-reverse;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
#cowebsite-aside-holder {
|
||||
pointer-events: none;
|
||||
height: 100%;
|
||||
|
||||
img {
|
||||
height: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
#cowebsite-sub-icons {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 0;
|
||||
height: 100%;
|
||||
visibility: visible;
|
||||
|
||||
img {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
cursor: pointer !important;
|
||||
border-radius: 50%;
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
&>div {
|
||||
display: flex;
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
#cowebsite-aside-buttons {
|
||||
flex-direction: row-reverse;
|
||||
margin-left: auto;
|
||||
margin-bottom: 0;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
img {
|
||||
cursor: ns-resize;
|
||||
}
|
||||
|
||||
#cowebsite-fullscreen {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.top-right-btn {
|
||||
img {
|
||||
width: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:960px) and (max-height:768px) {
|
||||
#cowebsite {
|
||||
|
||||
&-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
aside {
|
||||
#cowebsite-sub-icons {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 0;
|
||||
height: 100%;
|
||||
visibility: visible;
|
||||
|
||||
img {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
cursor: pointer !important;
|
||||
border-radius: 50%;
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
&>div {
|
||||
display: flex;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
cursor: ns-resize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,5 @@
|
||||
@import "~@fontsource/press-start-2p/index.css";
|
||||
|
||||
@font-face {
|
||||
font-family: "Twemoji Mozilla";
|
||||
src: url("./fonts/TwemojiMozilla.ttf") format('truetype');
|
||||
}
|
||||
|
||||
*{
|
||||
font-family: PixelFont-7,monospace;
|
||||
}
|
||||
|
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
@charset 'UTF-8';
|
||||
@import "breakpoints";
|
||||
@import "cowebsite.scss";
|
||||
@import "cowebsite-mobile.scss";
|
||||
@import "style";
|
||||
@import "mobile-style.scss";
|
||||
@import "fonts.scss";
|
||||
@import "style";
|
||||
@import "TextGlobalMessageSvelte-Style";
|
||||
|
@ -1,48 +0,0 @@
|
||||
@media (hover: none) {
|
||||
/**
|
||||
* If we cannot hover over elements, let's display camera button in full.
|
||||
*/
|
||||
.btn-cam-action {
|
||||
div {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 700px),
|
||||
screen and (max-height: 700px){
|
||||
video.myCamVideo {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.div-myCamVideo.hide {
|
||||
right: -160px;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 20%;
|
||||
min-width: 200px;
|
||||
position: absolute;
|
||||
display: block;
|
||||
right: 0;
|
||||
height: 80%;
|
||||
|
||||
&> div {
|
||||
min-width: 200px;
|
||||
max-height: 21vh;
|
||||
}
|
||||
|
||||
.video-container{
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.main-section {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
||||
& > div {
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
@ -36,15 +36,22 @@ body .message-info.warning{
|
||||
}
|
||||
|
||||
.video-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
transition: all 0.2s ease;
|
||||
background-color: #00000099;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
width: 100%;
|
||||
|
||||
&.no-clikable {
|
||||
video {
|
||||
cursor: url('./images/cursor_normal.png'), pointer;
|
||||
}
|
||||
}
|
||||
|
||||
video {
|
||||
height: fit-content;
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
|
||||
&.mobile{
|
||||
@ -146,35 +153,6 @@ body .message-info.warning{
|
||||
}
|
||||
}
|
||||
|
||||
.video-container.div-myCamVideo{
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.div-myCamVideo {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
bottom: 30px;
|
||||
border-radius: 15px 15px 15px 15px;
|
||||
max-height: 20%;
|
||||
transition: right 350ms;
|
||||
}
|
||||
|
||||
.div-myCamVideo.hide {
|
||||
right: -20vw;
|
||||
}
|
||||
|
||||
video.myCamVideo{
|
||||
background-color: #00000099;
|
||||
max-height: 20vh;
|
||||
width: 15vw;
|
||||
-webkit-transform: scaleX(-1);
|
||||
transform: scaleX(-1);
|
||||
border-radius: 15px 15px 15px 15px;
|
||||
/*width: 200px;*/
|
||||
/*height: 113px;*/
|
||||
}
|
||||
|
||||
.sound-progress{
|
||||
display: none;
|
||||
position: absolute;
|
||||
@ -211,94 +189,6 @@ video.myCamVideo{
|
||||
top: calc(50% - 20px);
|
||||
}
|
||||
|
||||
.btn-cam-action {
|
||||
pointer-events: all;
|
||||
position: absolute;
|
||||
display: inline-flex;
|
||||
bottom: 10px;
|
||||
right: 15px;
|
||||
width: 240px;
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
justify-items: center;
|
||||
}
|
||||
/*btn animation*/
|
||||
.btn-cam-action div{
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: solid 0px black;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
background: #666;
|
||||
box-shadow: 2px 2px 24px #444;
|
||||
border-radius: 48px;
|
||||
transform: translateY(15px);
|
||||
transition-timing-function: ease-in-out;
|
||||
margin: 0 4%;
|
||||
}
|
||||
.btn-cam-action div.disabled {
|
||||
background: #d75555;
|
||||
}
|
||||
.btn-cam-action div.enabled {
|
||||
background: #73c973;
|
||||
}
|
||||
.btn-cam-action:hover div{
|
||||
transform: translateY(0);
|
||||
}
|
||||
.btn-cam-action div:hover{
|
||||
background: #407cf7;
|
||||
box-shadow: 4px 4px 48px #666;
|
||||
transition: 120ms;
|
||||
}
|
||||
.btn-micro{
|
||||
pointer-events: auto;
|
||||
transition: all .3s;
|
||||
/*right: 44px;*/
|
||||
}
|
||||
.btn-video{
|
||||
pointer-events: auto;
|
||||
transition: all .25s;
|
||||
/*right: 134px;*/
|
||||
}
|
||||
.btn-monitor{
|
||||
pointer-events: auto;
|
||||
transition: all .2s;
|
||||
/*right: 224px;*/
|
||||
}
|
||||
.btn-monitor.hide {
|
||||
transform: translateY(60px);
|
||||
}
|
||||
.btn-cam-action:hover .btn-monitor.hide{
|
||||
transform: translateY(60px);
|
||||
}
|
||||
.btn-layout{
|
||||
pointer-events: auto;
|
||||
transition: all .15s;
|
||||
}
|
||||
.btn-layout.hide {
|
||||
transform: translateY(60px);
|
||||
}
|
||||
.btn-cam-action:hover .btn-layout.hide{
|
||||
transform: translateY(60px);
|
||||
}
|
||||
.btn-copy{
|
||||
pointer-events: auto;
|
||||
transition: all .3s;
|
||||
right: 44px;
|
||||
opacity: 1;
|
||||
}
|
||||
.btn-cam-action div img{
|
||||
height: 22px;
|
||||
width: 30px;
|
||||
position: relative;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
}
|
||||
|
||||
/* Spinner */
|
||||
.connecting-spinner {
|
||||
/*display: inline-block;*/
|
||||
@ -369,26 +259,6 @@ body {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@media (min-aspect-ratio: 1/1) {
|
||||
.game-overlay {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar > div {
|
||||
max-height: 21%;
|
||||
}
|
||||
|
||||
.sidebar > div:hover {
|
||||
max-height: 25%;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#game {
|
||||
position: relative; /* Position relative is needed for the game-overlay. */
|
||||
|
||||
@ -486,96 +356,6 @@ input[type=range]:focus::-ms-fill-upper {
|
||||
background: #FFFFFF;
|
||||
}
|
||||
|
||||
|
||||
.game-overlay {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
/* TODO: DO WE NEED FLEX HERE???? WE WANT A SIDEBAR OF EXACTLY 25% (note: flex useful for direction!!!) */
|
||||
}
|
||||
|
||||
.game-overlay + div {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.game-overlay + div > div {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.game-overlay.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.game-overlay video {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.main-section {
|
||||
flex: 0 0 75%;
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.main-section > div {
|
||||
margin: 2%;
|
||||
flex-basis: 96%;
|
||||
transition: margin-left 0.2s, margin-right 0.2s, margin-bottom 0.2s, margin-top 0.2s, flex-basis 0.2s;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
pointer-events: auto;
|
||||
/*flex-shrink: 2;*/
|
||||
}
|
||||
|
||||
.main-section > div:hover {
|
||||
margin: 0%;
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
flex: 0 0 25%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.sidebar > div {
|
||||
margin: 2%;
|
||||
transition: margin-left 0.2s, margin-right 0.2s, margin-bottom 0.2s, margin-top 0.2s, max-height 0.2s, max-width 0.2s;
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
border-radius: 15px 15px 15px 15px;
|
||||
pointer-events: auto;
|
||||
|
||||
video {
|
||||
max-height: 21vh;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar > div:hover {
|
||||
margin: 0%;
|
||||
}
|
||||
|
||||
.sidebar > div video {
|
||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
||||
}
|
||||
|
||||
/* Let's make sure videos are vertically centered if they need to be cropped */
|
||||
.media-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.chat-mode {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
|
||||
align-items: flex-start;
|
||||
|
||||
padding: 1%;
|
||||
}
|
||||
|
||||
.chat-mode > div {
|
||||
margin: 1%;
|
||||
max-height: 96%;
|
||||
@ -1061,13 +841,22 @@ div.action.danger p.action-body{
|
||||
}
|
||||
|
||||
|
||||
#svelte-overlay {
|
||||
#game-overlay {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
|
||||
& + div {
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
& + div > div {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
& > div {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
@ -1085,22 +874,10 @@ div.action.danger p.action-body{
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.is-silent {
|
||||
position: absolute;
|
||||
bottom: 40px;
|
||||
border-radius: 15px 15px 15px 15px;
|
||||
max-height: 20%;
|
||||
transition: right 350ms;
|
||||
right: -300px;
|
||||
background-color: black;
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
padding: 30px 20px;
|
||||
}
|
||||
div.is-silent.hide {
|
||||
right: 15px;
|
||||
&.hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
div.emoji-picker {
|
||||
@ -1121,8 +898,3 @@ div.emoji-picker {
|
||||
user-select: none; /* Non-prefixed version, currently
|
||||
supported by Chrome, Edge, Opera and Firefox */
|
||||
}
|
||||
|
||||
.pixel {
|
||||
height: 1px !important;
|
||||
width: 1px !important;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user