Merge pull request #1620 from thecodingmachine/embedScreens

Improve UI & Cowebsites
This commit is contained in:
Alexis Faizeau 2022-01-27 16:50:10 +01:00 committed by GitHub
commit f1a674225a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
97 changed files with 3626 additions and 1821 deletions

View file

@ -83,7 +83,8 @@
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY, "SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
"TURN_SERVER": "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443", "TURN_SERVER": "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443",
"JITSI_PRIVATE_MODE": if env.SECRET_JITSI_KEY != '' then "true" else "false", "JITSI_PRIVATE_MODE": if env.SECRET_JITSI_KEY != '' then "true" else "false",
"START_ROOM_URL": "/_/global/maps-"+url+"/starter/map.json" "START_ROOM_URL": "/_/global/maps-"+url+"/starter/map.json",
"ICON_URL": "//icon-"+url,
} }
}, },
"uploader": { "uploader": {
@ -109,7 +110,15 @@
"redis": { "redis": {
"image": "redis:6", "image": "redis:6",
"ports": [6379] "ports": [6379]
} },
"iconserver": {
"image": "matthiasluedtke/iconserver:v3.13.0",
"host": {
"url": "icon-"+url,
"containerPort": 8080,
},
"ports": [8080]
},
}, },
"config": { "config": {
k8sextension(k8sConf):: k8sextension(k8sConf)::
@ -210,6 +219,16 @@
} }
} }
}, },
iconserver+: {
ingress+: {
spec+: {
tls+: [{
hosts: ["icon-"+url],
secretName: "certificate-tls"
}]
}
}
},
} }
} }
} }

View file

@ -52,17 +52,17 @@ WA.nav.goToRoom("/_/global/<path to global map>.json#start-layer-2")
### Opening/closing web page in Co-Websites ### Opening/closing web page in Co-Websites
``` ```
WA.nav.openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = "", position: number = 0): Promise<CoWebsite> WA.nav.openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = "", position: number, closable: boolean, lazy: boolean): Promise<CoWebsite>
``` ```
Opens the webpage at "url" in an iFrame (on the right side of the screen) or close that iFrame. `allowApi` allows the webpage to use the "IFrame API" and execute script (it is equivalent to putting the `openWebsiteAllowApi` property in the map). `allowPolicy` grants additional access rights to the iFrame. The `allowPolicy` parameter is turned into an [`allow` feature policy in the iFrame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allow), position in whitch slot the web page will be open. Opens the webpage at "url" in an iFrame (on the right side of the screen) or close that iFrame. `allowApi` allows the webpage to use the "IFrame API" and execute script (it is equivalent to putting the `openWebsiteAllowApi` property in the map). `allowPolicy` grants additional access rights to the iFrame. The `allowPolicy` parameter is turned into an [`allow` feature policy in the iFrame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allow), position in whitch slot the web page will be open, closable allow to close the webpage also you need to close it by the api and lazy
You can have only 5 co-wbesites open simultaneously. it's to add the cowebsite but don't load it.
Example: Example:
```javascript ```javascript
const coWebsite = await WA.nav.openCoWebSite('https://www.wikipedia.org/'); const coWebsite = await WA.nav.openCoWebSite('https://www.wikipedia.org/');
const coWebsiteWorkAdventure = await WA.nav.openCoWebSite('https://workadventu.re/', true, "", 1); const coWebsiteWorkAdventure = await WA.nav.openCoWebSite('https://workadventu.re/', true, "", 1, true, true);
// ... // ...
coWebsite.close(); coWebsite.close();
``` ```

View file

@ -1,4 +1,6 @@
index.html index.html
/js/ /js/
/fonts/
style.*.css style.*.css
!env-config.template.js !env-config.template.js
*.png

76
front/dist/index.ejs vendored

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><defs><image width="12" height="14" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAOAQMAAAAhc2+vAAAAAXNSR0IB2cksfwAAAAZQTFRFAAAA////pdmf3QAAAAJ0Uk5TAP9bkSK1AAAAJUlEQVR4nGNgOMDAoMDw/wMDCDgwMDQwQIAASBgE/j8ACRswAACLjwYPIknTggAAAABJRU5ErkJggg=="/><image width="12" height="12" id="img2" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMAgMAAAArG7R0AAAAAXNSR0IB2cksfwAAAAlQTFRFAAAA/////wAAzV63nAAAAAN0Uk5TAP8BHlUJOgAAACJJREFUeJxjYGAQYGBgYGEIDQ0F0xA+BwMDEi80NASqigEAOD8CVqGVgwsAAAAASUVORK5CYII="/></defs><style></style><use href="#img1" x="2" y="1" /><use href="#img2" x="2" y="2" /></svg>

After

Width:  |  Height:  |  Size: 717 B

View file

@ -15,6 +15,7 @@
"@typescript-eslint/eslint-plugin": "^5.6.0", "@typescript-eslint/eslint-plugin": "^5.6.0",
"@typescript-eslint/parser": "^5.6.0", "@typescript-eslint/parser": "^5.6.0",
"css-loader": "^5.2.4", "css-loader": "^5.2.4",
"css-minimizer-webpack-plugin": "^3.3.1",
"eslint": "^8.4.1", "eslint": "^8.4.1",
"eslint-plugin-svelte3": "^3.2.1", "eslint-plugin-svelte3": "^3.2.1",
"fork-ts-checker-webpack-plugin": "^6.5.0", "fork-ts-checker-webpack-plugin": "^6.5.0",

View file

@ -6,13 +6,14 @@ export const isOpenCoWebsiteEvent = new tg.IsInterface()
allowApi: tg.isOptional(tg.isBoolean), allowApi: tg.isOptional(tg.isBoolean),
allowPolicy: tg.isOptional(tg.isString), allowPolicy: tg.isOptional(tg.isString),
position: tg.isOptional(tg.isNumber), position: tg.isOptional(tg.isNumber),
closable: tg.isOptional(tg.isBoolean),
lazy: tg.isOptional(tg.isBoolean),
}) })
.get(); .get();
export const isCoWebsite = new tg.IsInterface() export const isCoWebsite = new tg.IsInterface()
.withProperties({ .withProperties({
id: tg.isString, id: tg.isString,
position: tg.isNumber,
}) })
.get(); .get();

View file

@ -1,7 +1,7 @@
import { IframeApiContribution, sendToWorkadventure, queryWorkadventure } from "./IframeApiContribution"; import { IframeApiContribution, sendToWorkadventure, queryWorkadventure } from "./IframeApiContribution";
export class CoWebsite { export class CoWebsite {
constructor(private readonly id: string, public readonly position: number) {} constructor(private readonly id: string) {}
close() { close() {
return queryWorkadventure({ return queryWorkadventure({
@ -41,7 +41,14 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
}); });
} }
async openCoWebSite(url: string, allowApi?: boolean, allowPolicy?: string, position?: number): Promise<CoWebsite> { async openCoWebSite(
url: string,
allowApi?: boolean,
allowPolicy?: string,
position?: number,
closable?: boolean,
lazy?: boolean
): Promise<CoWebsite> {
const result = await queryWorkadventure({ const result = await queryWorkadventure({
type: "openCoWebsite", type: "openCoWebsite",
data: { data: {
@ -49,9 +56,11 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
allowApi, allowApi,
allowPolicy, allowPolicy,
position, position,
closable,
lazy,
}, },
}); });
return new CoWebsite(result.id, result.position); return new CoWebsite(result.id);
} }
async getCoWebSites(): Promise<CoWebsite[]> { async getCoWebSites(): Promise<CoWebsite[]> {
@ -59,7 +68,7 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
type: "getCoWebsites", type: "getCoWebsites",
data: undefined, data: undefined,
}); });
return result.map((cowebsiteEvent) => new CoWebsite(cowebsiteEvent.id, cowebsiteEvent.position)); return result.map((cowebsiteEvent) => new CoWebsite(cowebsiteEvent.id));
} }
/** /**

View file

@ -1,166 +1,52 @@
<script lang="typescript"> <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 type { Game } from "../Phaser/Game/Game";
import { chatVisibilityStore } from "../Stores/ChatStore"; import { chatVisibilityStore } from "../Stores/ChatStore";
import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStore"; import { customCharacterSceneVisibleStore } from "../Stores/CustomCharacterStore";
import HelpCameraSettingsPopup from "./HelpCameraSettings/HelpCameraSettingsPopup.svelte"; import { errorStore } from "../Stores/ErrorStore";
import { showLimitRoomModalStore, showShareLinkMapModalStore } from "../Stores/ModalStore"; import { loginSceneVisibleStore } from "../Stores/LoginSceneStore";
import LimitRoomModal from "./Modal/LimitRoomModal.svelte"; import { enableCameraSceneVisibilityStore } from "../Stores/MediaStore";
import ShareLinkMapModal from "./Modal/ShareLinkMapModal.svelte"; import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore";
import AudioPlaying from "./UI/AudioPlaying.svelte"; import { selectCompanionSceneVisibleStore } from "../Stores/SelectCompanionStore";
import { soundPlayingStore } from "../Stores/SoundPlayingStore"; 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 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; export let game: Game;
</script> </script>
<div> {#if $errorStore.length > 0}
{#if $loginSceneVisibleStore} <div>
<div class="scrollable"> <ErrorDialog />
<LoginScene {game} /> </div>
</div> {:else if $loginSceneVisibleStore}
{/if} <div class="scrollable">
{#if $selectCharacterSceneVisibleStore} <LoginScene {game} />
<div> </div>
<SelectCharacterScene {game} /> {:else if $selectCharacterSceneVisibleStore}
</div> <div>
{/if} <SelectCharacterScene {game} />
{#if $customCharacterSceneVisibleStore} </div>
<div> {:else if $customCharacterSceneVisibleStore}
<CustomCharacterScene {game} /> <div>
</div> <CustomCharacterScene {game} />
{/if} </div>
{#if $selectCompanionSceneVisibleStore} {:else if $selectCompanionSceneVisibleStore}
<div> <div>
<SelectCompanionScene {game} /> <SelectCompanionScene {game} />
</div> </div>
{/if} {:else if $enableCameraSceneVisibilityStore}
{#if $enableCameraSceneVisibilityStore} <div class="scrollable">
<div class="scrollable"> <EnableCameraScene {game} />
<EnableCameraScene {game} /> </div>
</div> {:else}
{/if} <MainLayout />
{#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 $chatVisibilityStore} {#if $chatVisibilityStore}
<Chat /> <Chat />
{/if} {/if}
{#if $warningContainerStore} {/if}
<WarningContainer />
{/if}
</div>

View file

@ -157,13 +157,16 @@
<style lang="scss"> <style lang="scss">
div.main-audio-manager.nes-container.is-rounded { div.main-audio-manager.nes-container.is-rounded {
position: relative; position: absolute;
top: 0.5rem; top: 1%;
max-height: clamp(150px, 10vh, 15vh); //replace @media for small screen max-height: clamp(150px, 10vh, 15vh); //replace @media for small screen
width: clamp(200px, 15vw, 15vw); width: clamp(200px, 15vw, 15vw);
padding: 3px 3px; padding: 3px 3px;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
left: 0;
right: 0;
z-index: 550;
background-color: rgb(0, 0, 0, 0.5); background-color: rgb(0, 0, 0, 0.5);
display: grid; display: grid;

View file

@ -9,10 +9,15 @@
import microphoneCloseImg from "./images/microphone-close.svg"; import microphoneCloseImg from "./images/microphone-close.svg";
import layoutPresentationImg from "./images/layout-presentation.svg"; import layoutPresentationImg from "./images/layout-presentation.svg";
import layoutChatImg from "./images/layout-chat.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 { LayoutMode } from "../WebRtc/LayoutManager";
import { peerStore } from "../Stores/PeerStore"; import { peerStore } from "../Stores/PeerStore";
import { onDestroy } from "svelte"; 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 { function screenSharingClick(): void {
if (isSilent) return; if (isSilent) return;
@ -42,10 +47,26 @@
} }
function switchLayoutMode() { function switchLayoutMode() {
if ($layoutModeStore === LayoutMode.Presentation) { if ($embedScreenLayout === LayoutMode.Presentation) {
$layoutModeStore = LayoutMode.VideoChat; $embedScreenLayout = LayoutMode.VideoChat;
} else { } 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,162 @@
onDestroy(unsubscribeIsSilent); onDestroy(unsubscribeIsSilent);
</script> </script>
<div> <div class="btn-cam-action">
<div class="btn-cam-action"> <div class="btn-layout" on:click={switchLayoutMode} class:hide={$peerStore.size === 0}>
<div class="btn-layout" on:click={switchLayoutMode} class:hide={$peerStore.size === 0}> {#if $embedScreenLayout === LayoutMode.Presentation}
{#if $layoutModeStore === LayoutMode.Presentation} <img class="noselect" src={layoutPresentationImg} style="padding: 2px" alt="Switch to mosaic mode" />
<img src={layoutPresentationImg} style="padding: 2px" alt="Switch to mosaic mode" /> {:else}
{:else} <img class="noselect" src={layoutChatImg} style="padding: 2px" alt="Switch to presentation mode" />
<img src={layoutChatImg} style="padding: 2px" alt="Switch to presentation mode" /> {/if}
{/if} </div>
</div>
<div <div
class="btn-monitor" class="btn-follow"
on:click={screenSharingClick} class:hide={($peerStore.size === 0 && $followStateStore === "off") || isSilent}
class:hide={!$screenSharingAvailableStore || isSilent} class:disabled={$followStateStore !== "off"}
class:enabled={$requestedScreenSharingState} on:click={followClick}
> >
{#if $requestedScreenSharingState && !isSilent} <img class="noselect" src={followImg} alt="" />
<img src={monitorImg} alt="Start screen sharing" /> </div>
{:else}
<img src={monitorCloseImg} alt="Stop screen sharing" /> <div
{/if} class="btn-monitor"
</div> on:click={screenSharingClick}
<div class="btn-video" on:click={cameraClick} class:disabled={!$requestedCameraState || isSilent}> class:hide={!$screenSharingAvailableStore || isSilent}
{#if $requestedCameraState && !isSilent} class:enabled={$requestedScreenSharingState}
<img src={cinemaImg} alt="Turn on webcam" /> >
{:else} {#if $requestedScreenSharingState && !isSilent}
<img src={cinemaCloseImg} alt="Turn off webcam" /> <img class="noselect" src={monitorImg} alt="Start screen sharing" />
{/if} {:else}
</div> <img class="noselect" src={monitorCloseImg} alt="Stop screen sharing" />
<div class="btn-micro" on:click={microphoneClick} class:disabled={!$requestedMicrophoneState || isSilent}> {/if}
{#if $requestedMicrophoneState && !isSilent} </div>
<img src={microphoneImg} alt="Turn on microphone" />
{:else} <div class="btn-video" on:click={cameraClick} class:disabled={!$requestedCameraState || isSilent}>
<img src={microphoneCloseImg} alt="Turn off microphone" /> {#if $requestedCameraState && !isSilent}
{/if} <img class="noselect" src={cinemaImg} alt="Turn on webcam" />
</div> {: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>
</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;
z-index: 251;
&: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>

View file

@ -43,7 +43,7 @@
<svelte:window on:keydown={onKeyDown} on:click={onClick} /> <svelte:window on:keydown={onKeyDown} on:click={onClick} />
<aside class="chatWindow" transition:fly={{ x: -1000, duration: 500 }} bind:this={chatWindowElement}> <aside class="chatWindow" transition:fly={{ x: -1000, duration: 500 }} bind:this={chatWindowElement}>
<p class="close-icon" on:click={closeChat}>&times</p> <p class="close-icon noselect" on:click={closeChat}>&times</p>
<section class="messagesList" bind:this={listDom}> <section class="messagesList" bind:this={listDom}>
<ul> <ul>
<li><p class="system-text">{$LL.chat.intro()}</p></li> <li><p class="system-text">{$LL.chat.intro()}</p></li>
@ -78,7 +78,7 @@
} }
aside.chatWindow { aside.chatWindow {
z-index: 100; z-index: 1000;
pointer-events: auto; pointer-events: auto;
position: absolute; position: absolute;
top: 0; top: 0;

View file

@ -83,6 +83,8 @@
</form> </form>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
form.customCharacterScene { form.customCharacterScene {
font-family: "Press Start 2P"; font-family: "Press Start 2P";
pointer-events: auto; pointer-events: auto;
@ -129,7 +131,7 @@
} }
} }
@media only screen and (max-width: 800px) { @include media-breakpoint-up(md) {
form.customCharacterScene button.customCharacterSceneButtonLeft { form.customCharacterScene button.customCharacterSceneButtonLeft {
left: 5vw; left: 5vw;
} }

View file

@ -0,0 +1,32 @@
<script lang="typescript">
import type { EmbedScreen } from "../../Stores/EmbedScreensStore";
import { streamableCollectionStore } from "../../Stores/StreamableCollectionStore";
import MediaBox from "../Video/MediaBox.svelte";
export let highlightedEmbedScreen: EmbedScreen | null;
export let full = false;
$: clickable = !full;
</script>
<aside class="cameras-container" class:full>
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
{#if !highlightedEmbedScreen || highlightedEmbedScreen.type !== "streamable" || (highlightedEmbedScreen.type === "streamable" && highlightedEmbedScreen.embed !== peer)}
<MediaBox streamable={peer} isClickable={clickable} />
{/if}
{/each}
</aside>
<style lang="scss">
.cameras-container {
flex: 0 0 25%;
overflow-y: auto;
overflow-x: hidden;
&:first-child {
margin-top: 2%;
}
&.full {
flex: 0 0 100%;
}
}
</style>

View file

@ -0,0 +1,272 @@
<script lang="typescript">
import { onMount } from "svelte";
import { ICON_URL } from "../../Enum/EnvironmentVariable";
import { coWebsitesNotAsleep, mainCoWebsite } from "../../Stores/CoWebsiteStore";
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
import type { CoWebsite } from "../../WebRtc/CoWebsiteManager";
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
export let index: number;
export let coWebsite: CoWebsite;
export let vertical: boolean;
let icon: HTMLImageElement;
let iconLoaded = false;
let state = coWebsite.state;
const coWebsiteUrl = coWebsite.iframe.src;
const urlObject = new URL(coWebsiteUrl);
onMount(() => {
icon.src = `${ICON_URL}/icon?url=${urlObject.hostname}&size=64..96..256&fallback_icon_color=14304c`;
icon.alt = urlObject.hostname;
icon.onload = () => {
iconLoaded = true;
};
});
async function onClick() {
if (vertical) {
coWebsiteManager.goToMain(coWebsite);
} else if ($mainCoWebsite) {
if ($mainCoWebsite.iframe.id === coWebsite.iframe.id) {
const coWebsites = $coWebsitesNotAsleep;
const newMain = $highlightedEmbedScreen ?? coWebsites.length > 1 ? coWebsites[1] : undefined;
if (newMain) {
coWebsiteManager.goToMain(coWebsite);
}
} else {
highlightedEmbedScreen.toggleHighlight({
type: "cowebsite",
embed: coWebsite,
});
}
}
if ($state === "asleep") {
await coWebsiteManager.loadCoWebsite(coWebsite);
}
coWebsiteManager.resizeAllIframes();
}
function noDrag() {
return false;
}
let isHighlight: boolean = false;
let isMain: boolean = false;
$: {
isMain = $mainCoWebsite !== undefined && $mainCoWebsite.iframe === coWebsite.iframe;
isHighlight =
$highlightedEmbedScreen !== null &&
$highlightedEmbedScreen.type === "cowebsite" &&
$highlightedEmbedScreen.embed.iframe === coWebsite.iframe;
}
</script>
<div
id={"cowebsite-thumbnail-" + index}
class="cowebsite-thumbnail nes-pointer"
class:asleep={$state === "asleep"}
class:loading={$state === "loading"}
class:ready={$state === "ready"}
class:displayed={isMain || isHighlight}
class:vertical
on:click={onClick}
>
<img
class="cowebsite-icon noselect nes-pointer"
class:hide={!iconLoaded}
bind:this={icon}
on:dragstart|preventDefault={noDrag}
alt=""
/>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="cowebsite-icon"
class:hide={iconLoaded}
style="margin: auto; background: rgba(0, 0, 0, 0) none repeat scroll 0% 0%; shape-rendering: auto;"
viewBox="0 0 100 100"
preserveAspectRatio="xMidYMid"
>
<rect x="19" y="19" width="20" height="20" fill="#14304c">
<animate
attributeName="fill"
values="#365dff;#14304c;#14304c"
keyTimes="0;0.125;1"
dur="1s"
repeatCount="indefinite"
begin="0s"
calcMode="discrete"
/>
</rect><rect x="40" y="19" width="20" height="20" fill="#14304c">
<animate
attributeName="fill"
values="#365dff;#14304c;#14304c"
keyTimes="0;0.125;1"
dur="1s"
repeatCount="indefinite"
begin="0.125s"
calcMode="discrete"
/>
</rect><rect x="61" y="19" width="20" height="20" fill="#14304c">
<animate
attributeName="fill"
values="#365dff;#14304c;#14304c"
keyTimes="0;0.125;1"
dur="1s"
repeatCount="indefinite"
begin="0.25s"
calcMode="discrete"
/>
</rect><rect x="19" y="40" width="20" height="20" fill="#14304c">
<animate
attributeName="fill"
values="#365dff;#14304c;#14304c"
keyTimes="0;0.125;1"
dur="1s"
repeatCount="indefinite"
begin="0.875s"
calcMode="discrete"
/>
</rect><rect x="61" y="40" width="20" height="20" fill="#14304c">
<animate
attributeName="fill"
values="#365dff;#14304c;#14304c"
keyTimes="0;0.125;1"
dur="1s"
repeatCount="indefinite"
begin="0.375s"
calcMode="discrete"
/>
</rect><rect x="19" y="61" width="20" height="20" fill="#14304c">
<animate
attributeName="fill"
values="#365dff;#14304c;#14304c"
keyTimes="0;0.125;1"
dur="1s"
repeatCount="indefinite"
begin="0.75s"
calcMode="discrete"
/>
</rect><rect x="40" y="61" width="20" height="20" fill="#14304c">
<animate
attributeName="fill"
values="#365dff;#14304c;#14304c"
keyTimes="0;0.125;1"
dur="1s"
repeatCount="indefinite"
begin="0.625s"
calcMode="discrete"
/>
</rect><rect x="61" y="61" width="20" height="20" fill="#14304c">
<animate
attributeName="fill"
values="#365dff;#14304c;#14304c"
keyTimes="0;0.125;1"
dur="1s"
repeatCount="indefinite"
begin="0.5s"
calcMode="discrete"
/>
</rect>
</svg>
</div>
<style lang="scss">
.cowebsite-thumbnail {
position: relative;
padding: 0;
background-color: rgba(#000000, 0.6);
margin: 12px;
margin-top: auto;
margin-bottom: auto;
&::before {
content: "";
position: absolute;
width: 58px;
height: 58px;
left: -8px;
top: -8px;
margin: 4px;
border-style: solid;
border-width: 4px;
border-image-slice: 3;
border-image-width: 3;
border-image-repeat: stretch;
border-image-source: url('data:image/svg+xml;utf8,<?xml version="1.0" encoding="UTF-8" ?><svg version="1.1" width="8" height="8" xmlns="http://www.w3.org/2000/svg"><path d="M3 1 h1 v1 h-1 z M4 1 h1 v1 h-1 z M2 2 h1 v1 h-1 z M5 2 h1 v1 h-1 z M1 3 h1 v1 h-1 z M6 3 h1 v1 h-1 z M1 4 h1 v1 h-1 z M6 4 h1 v1 h-1 z M2 5 h1 v1 h-1 z M5 5 h1 v1 h-1 z M3 6 h1 v1 h-1 z M4 6 h1 v1 h-1 z" fill="rgb(33,37,41)" /></svg>');
border-image-outset: 1;
}
&.vertical {
margin: 7px;
&::before {
width: 48px;
height: 48px;
}
.cowebsite-icon {
width: 40px;
height: 40px;
}
}
&.displayed {
&:not(.vertical) {
animation: activeThumbnail 300ms ease-in 0s forwards;
}
}
&.asleep {
filter: grayscale(100%);
--webkit-filter: grayscale(100%);
}
&.loading {
animation: 2500ms ease-in-out 0s infinite alternate backgroundLoading;
}
&.ready {
&::before {
border-image-source: url('data:image/svg+xml;utf8,<?xml version="1.0" encoding="UTF-8" ?><svg version="1.1" width="8" height="8" xmlns="http://www.w3.org/2000/svg"><path d="M3 1 h1 v1 h-1 z M4 1 h1 v1 h-1 z M2 2 h1 v1 h-1 z M5 2 h1 v1 h-1 z M1 3 h1 v1 h-1 z M6 3 h1 v1 h-1 z M1 4 h1 v1 h-1 z M6 4 h1 v1 h-1 z M2 5 h1 v1 h-1 z M5 5 h1 v1 h-1 z M3 6 h1 v1 h-1 z M4 6 h1 v1 h-1 z" fill="rgb(38, 74, 110)" /></svg>');
}
}
@keyframes backgroundLoading {
0% {
background-color: rgba(#000000, 0.6);
}
100% {
background-color: #25598e;
}
}
@keyframes activeThumbnail {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-15px);
}
}
.cowebsite-icon {
width: 50px;
height: 50px;
object-fit: cover;
&.hide {
display: none;
}
}
}
</style>

View file

@ -0,0 +1,42 @@
<script lang="typescript">
import { coWebsites } from "../../Stores/CoWebsiteStore";
import CoWebsiteThumbnail from "./CoWebsiteThumbnailSlot.svelte";
export let vertical = false;
</script>
{#if $coWebsites.length > 0}
<div id="cowebsite-thumbnail-container" class:vertical>
{#each [...$coWebsites.values()] as coWebsite, index (coWebsite.iframe.id)}
<CoWebsiteThumbnail {index} {coWebsite} {vertical} />
{/each}
</div>
{/if}
<style lang="scss">
#cowebsite-thumbnail-container {
pointer-events: all;
height: 100px;
width: 100%;
display: flex;
position: absolute;
bottom: 5px;
left: 2%;
overflow-x: auto;
overflow-y: hidden;
&.vertical {
height: auto !important;
width: auto !important;
bottom: auto !important;
left: auto !important;
position: relative;
overflow-x: hidden;
overflow-y: auto;
flex-direction: column;
align-items: center;
padding-top: 4px;
padding-bottom: 4px;
}
}
</style>

View file

@ -0,0 +1,22 @@
<script lang="typescript">
import PresentationLayout from "./Layouts/PresentationLayout.svelte";
import MozaicLayout from "./Layouts/MozaicLayout.svelte";
import { LayoutMode } from "../../WebRtc/LayoutManager";
import { embedScreenLayout } from "../../Stores/EmbedScreensStore";
</script>
<div id="embedScreensContainer">
{#if $embedScreenLayout === LayoutMode.Presentation}
<PresentationLayout />
{:else}
<MozaicLayout />
{/if}
</div>
<style lang="scss">
#embedScreensContainer {
display: flex;
padding-top: 2%;
height: 100%;
}
</style>

View file

@ -0,0 +1,61 @@
<script lang="ts">
import { onMount } from "svelte";
import { highlightedEmbedScreen } from "../../../Stores/EmbedScreensStore";
import { streamableCollectionStore } from "../../../Stores/StreamableCollectionStore";
import MediaBox from "../../Video/MediaBox.svelte";
let layoutDom: HTMLDivElement;
const resizeObserver = new ResizeObserver(() => {});
onMount(() => {
resizeObserver.observe(layoutDom);
highlightedEmbedScreen.removeHighlight();
});
</script>
<div id="mozaic-layout" bind:this={layoutDom}>
<div
class="media-container"
class:full-width={$streamableCollectionStore.size === 1 || $streamableCollectionStore.size === 2}
class:quarter={$streamableCollectionStore.size === 3 || $streamableCollectionStore.size === 4}
>
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
<MediaBox
streamable={peer}
mozaicFullWidth={$streamableCollectionStore.size === 1 || $streamableCollectionStore.size === 2}
mozaicQuarter={$streamableCollectionStore.size === 3 || $streamableCollectionStore.size === 4}
/>
{/each}
</div>
</div>
<style lang="scss">
#mozaic-layout {
height: 100%;
width: 100%;
overflow-y: auto;
overflow-x: hidden;
.media-container {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 33.3% 33.3% 33.3%;
align-items: center;
justify-content: center;
overflow-y: auto;
overflow-x: hidden;
&.full-width {
grid-template-columns: 100%;
grid-template-rows: 50% 50%;
}
&.quarter {
grid-template-columns: 50% 50%;
grid-template-rows: 50% 50%;
}
}
}
</style>

View file

@ -0,0 +1,143 @@
<script lang="ts">
import { highlightedEmbedScreen } from "../../../Stores/EmbedScreensStore";
import CamerasContainer from "../CamerasContainer.svelte";
import MediaBox from "../../Video/MediaBox.svelte";
import { coWebsiteManager } from "../../../WebRtc/CoWebsiteManager";
import { afterUpdate, onMount } from "svelte";
import { isMediaBreakpointDown, isMediaBreakpointUp } from "../../../Utils/BreakpointsUtils";
import { peerStore } from "../../../Stores/PeerStore";
function closeCoWebsite() {
if ($highlightedEmbedScreen?.type === "cowebsite") {
if ($highlightedEmbedScreen.embed.closable) {
coWebsiteManager.closeCoWebsite($highlightedEmbedScreen.embed).catch(() => {
console.error("Error during co-website highlighted closing");
});
} else {
coWebsiteManager.unloadCoWebsite($highlightedEmbedScreen.embed).catch(() => {
console.error("Error during co-website highlighted unloading");
});
}
}
}
afterUpdate(() => {
if ($highlightedEmbedScreen) {
coWebsiteManager.resizeAllIframes();
}
});
let layoutDom: HTMLDivElement;
let displayCoWebsiteContainer = isMediaBreakpointDown("lg");
let displayFullMedias = isMediaBreakpointUp("sm");
const resizeObserver = new ResizeObserver(() => {
displayCoWebsiteContainer = isMediaBreakpointDown("lg");
displayFullMedias = isMediaBreakpointUp("sm");
if (!displayCoWebsiteContainer && $highlightedEmbedScreen && $highlightedEmbedScreen.type === "cowebsite") {
highlightedEmbedScreen.removeHighlight();
}
if (displayFullMedias) {
highlightedEmbedScreen.removeHighlight();
}
});
onMount(() => {
resizeObserver.observe(layoutDom);
});
</script>
<div id="presentation-layout" bind:this={layoutDom} class:full-medias={displayFullMedias}>
{#if displayFullMedias}
<div id="full-medias">
<CamerasContainer full={true} highlightedEmbedScreen={$highlightedEmbedScreen} />
</div>
{:else}
<div id="embed-left-block" class:full={$peerStore.size === 0}>
<div id="main-embed-screen">
{#if $highlightedEmbedScreen}
{#if $highlightedEmbedScreen.type === "streamable"}
{#key $highlightedEmbedScreen.embed.uniqueId}
<MediaBox
isHightlighted={true}
isClickable={true}
streamable={$highlightedEmbedScreen.embed}
/>
{/key}
{:else if $highlightedEmbedScreen.type === "cowebsite"}
{#key $highlightedEmbedScreen.embed.iframe.id}
<div
id={"cowebsite-slot-" + $highlightedEmbedScreen.embed.iframe.id}
class="highlighted-cowebsite nes-container is-rounded"
>
<div class="actions">
<button type="button" class="nes-btn is-error close" on:click={closeCoWebsite}
>&times;</button
>
</div>
</div>
{/key}
{/if}
{/if}
</div>
</div>
{#if $peerStore.size > 0}
<CamerasContainer highlightedEmbedScreen={$highlightedEmbedScreen} />
{/if}
{/if}
</div>
<style lang="scss">
#presentation-layout {
height: 100%;
width: 100%;
display: flex;
&.full-medias {
overflow-y: auto;
overflow-x: hidden;
}
}
#embed-left-block {
display: flex;
flex-direction: column;
flex: 0 0 75%;
height: 100%;
width: 75%;
&.full {
flex: 0 0 98% !important;
width: 98% !important;
}
}
#main-embed-screen {
height: 100%;
margin-bottom: 3%;
.highlighted-cowebsite {
height: 100% !important;
width: 96%;
background-color: rgba(#000000, 0.6);
margin: 0 !important;
.actions {
z-index: 200;
position: relative;
display: flex;
flex-direction: row;
justify-content: end;
gap: 2%;
button {
pointer-events: all;
}
}
}
}
</style>

View file

@ -3,8 +3,8 @@
import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore"; import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore";
import { onDestroy, onMount } from "svelte"; import { onDestroy, onMount } from "svelte";
import { EmojiButton } from "@joeattardi/emoji-button"; import { EmojiButton } from "@joeattardi/emoji-button";
import { isMobile } from "../../Enum/EnvironmentVariable";
import LL from "../../i18n/i18n-svelte"; import LL from "../../i18n/i18n-svelte";
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
let emojiContainer: HTMLElement; let emojiContainer: HTMLElement;
let picker: EmojiButton; let picker: EmojiButton;
@ -20,7 +20,7 @@
"--secondary-text-color": "whitesmoke", "--secondary-text-color": "whitesmoke",
"--category-button-color": "whitesmoke", "--category-button-color": "whitesmoke",
}, },
emojisPerRow: isMobile() ? 6 : 8, emojisPerRow: isMediaBreakpointUp("md") ? 6 : 8,
autoFocusSearch: false, autoFocusSearch: false,
style: "twemoji", style: "twemoji",
showPreview: false, showPreview: false,
@ -86,6 +86,8 @@
height: 100%; height: 100%;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
position: absolute;
z-index: 300;
} }
.emote-menu { .emote-menu {

View file

@ -127,6 +127,8 @@
</form> </form>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
.enableCameraScene { .enableCameraScene {
pointer-events: auto; pointer-events: auto;
margin: 20px auto 0; margin: 20px auto 0;
@ -214,7 +216,7 @@
} }
} }
@media only screen and (max-width: 800px) { @include media-breakpoint-up(md) {
.enableCameraScene h2 { .enableCameraScene h2 {
font-size: 80%; font-size: 80%;
} }

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

View file

@ -1,9 +1,5 @@
<!--
vim: ft=typescript
-->
<script lang="ts"> <script lang="ts">
import { gameManager } from "../../Phaser/Game/GameManager"; import { gameManager } from "../../Phaser/Game/GameManager";
import followImg from "../images/follow.svg";
import { followStateStore, followRoleStore, followUsersStore } from "../../Stores/FollowStore"; import { followStateStore, followRoleStore, followUsersStore } from "../../Stores/FollowStore";
import LL from "../../i18n/i18n-svelte"; import LL from "../../i18n/i18n-svelte";
@ -14,10 +10,6 @@ vim: ft=typescript
return user ? user.PlayerValue : ""; return user ? user.PlayerValue : "";
} }
function sendFollowRequest() {
gameScene.CurrentPlayer.sendFollowRequest();
}
function acceptFollowRequest() { function acceptFollowRequest() {
gameScene.CurrentPlayer.startFollowing(); gameScene.CurrentPlayer.startFollowing();
} }
@ -83,7 +75,7 @@ vim: ft=typescript
{#if $followStateStore === "active" || $followStateStore === "ending"} {#if $followStateStore === "active" || $followStateStore === "ending"}
<div class="interact-status nes-container is-rounded"> <div class="interact-status nes-container is-rounded">
<section class="interact-status"> <section>
{#if $followRoleStore === "follower"} {#if $followRoleStore === "follower"}
<p>{$LL.follow.interactStatus.following({ leader: name($followUsersStore[0]) })}</p> <p>{$LL.follow.interactStatus.following({ leader: name($followUsersStore[0]) })}</p>
{:else if $followUsersStore.length === 0} {:else if $followUsersStore.length === 0}
@ -109,48 +101,27 @@ vim: ft=typescript
</div> </div>
{/if} {/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"> <style lang="scss">
@import "../../../style/breakpoints.scss";
.nes-container { .nes-container {
padding: 5px; padding: 5px;
} }
div.interact-status { .interact-status {
background-color: #333333; background-color: #333333;
color: whitesmoke; color: whitesmoke;
position: relative; position: absolute;
height: 2.7em; max-height: 2.7em;
width: 40vw; width: 40vw;
top: 87vh; top: 87vh;
margin: auto;
text-align: center; text-align: center;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
z-index: 400;
} }
div.interact-menu { div.interact-menu {
@ -158,10 +129,14 @@ vim: ft=typescript
background-color: #333333; background-color: #333333;
color: whitesmoke; color: whitesmoke;
position: relative; position: absolute;
width: 60vw; width: 60vw;
top: 60vh; top: 60vh;
margin: auto; left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
z-index: 150;
section.interact-menu-title { section.interact-menu-title {
margin-bottom: 20px; margin-bottom: 20px;
@ -189,23 +164,16 @@ vim: ft=typescript
} }
} }
.follow-menu-button { @include media-breakpoint-up(md) {
position: absolute; .interact-status {
bottom: 10px; width: 90vw;
left: 10px;
pointer-events: all;
}
@media only screen and (max-width: 800px) {
div.interact-status {
width: 100vw;
top: 78vh; top: 78vh;
font-size: 0.75em; font-size: 0.75em;
} }
div.interact-menu { div.interact-menu {
height: 21vh; max-height: 21vh;
width: 100vw; width: 90vw;
font-size: 0.75em; font-size: 0.75em;
} }
} }

View file

@ -22,7 +22,7 @@
<form <form
class="helpCameraSettings nes-container" class="helpCameraSettings nes-container"
on:submit|preventDefault={close} on:submit|preventDefault={close}
transition:fly={{ y: -900, duration: 500 }} transition:fly={{ y: -50, duration: 500 }}
> >
<section> <section>
<h2>{$LL.camera.help.title()}</h2> <h2>{$LL.camera.help.title()}</h2>
@ -55,9 +55,12 @@
background: #eceeee; background: #eceeee;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
margin-top: 10vh; left: 0;
right: 0;
margin-top: 4%;
max-height: 80vh; max-height: 80vh;
max-width: 80vw; max-width: 80vw;
z-index: 600;
overflow: auto; overflow: auto;
text-align: center; text-align: center;

View file

@ -21,9 +21,11 @@
left: 0; left: 0;
right: 0; right: 0;
bottom: 40px; bottom: 40px;
margin: 0 auto; margin-right: auto;
margin-left: auto;
padding: 0; padding: 0;
width: clamp(200px, 20vw, 20vw); width: clamp(200px, 20vw, 20vw);
z-index: 155;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -31,6 +33,10 @@
animation: moveMessage 0.5s; animation: moveMessage 0.5s;
animation-iteration-count: infinite; animation-iteration-count: infinite;
animation-timing-function: ease-in-out; animation-timing-function: ease-in-out;
div {
margin-bottom: 5%;
}
} }
div.nes-container.is-rounded { div.nes-container.is-rounded {

View file

@ -0,0 +1,170 @@
<script lang="typescript">
import { onMount } from "svelte";
import { audioManagerVisibilityStore } from "../Stores/AudioManagerStore";
import { embedScreenLayout, 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 { isMediaBreakpointDown, 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";
import { LayoutMode } from "../WebRtc/LayoutManager";
let mainLayout: HTMLDivElement;
let displayCoWebsiteContainerMd = isMediaBreakpointUp("md");
let displayCoWebsiteContainerLg = isMediaBreakpointDown("lg");
const resizeObserver = new ResizeObserver(() => {
displayCoWebsiteContainerMd = isMediaBreakpointUp("md");
displayCoWebsiteContainerLg = isMediaBreakpointDown("lg");
});
onMount(() => {
resizeObserver.observe(mainLayout);
});
</script>
<div id="main-layout" bind:this={mainLayout}>
<aside id="main-layout-left-aside">
{#if $menuIconVisiblilityStore}
<MenuIcon />
{/if}
{#if $embedScreenLayout === LayoutMode.VideoChat || displayCoWebsiteContainerMd}
<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 $warningContainerStore}
<WarningContainer />
{/if}
{#if $showReportScreenStore !== userReportEmpty}
<ReportMenu />
{/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 displayCoWebsiteContainerLg}
<CoWebsitesContainer />
{/if}
{#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: 120px calc(100% - 120px);
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>

View file

@ -100,6 +100,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
.string-HTML { .string-HTML {
white-space: pre-line; 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 { div.about-room-main {
section.container-overflow { section.container-overflow {
height: calc(100% - 120px); height: calc(100% - 120px);

View file

@ -67,6 +67,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
div.global-message-main { div.global-message-main {
height: calc(100% - 50px); height: calc(100% - 50px);
display: grid; 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 { .global-message-content {
height: calc(100% - 5px); height: calc(100% - 5px);
} }

View file

@ -36,6 +36,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
div.guest-main { div.guest-main {
height: calc(100% - 56px); 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 { div.guest-main {
section.share-url.not-mobile { section.share-url.not-mobile {
display: none; display: none;

View file

@ -125,6 +125,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
.nes-container { .nes-container {
padding: 5px; padding: 5px;
} }
@ -136,11 +138,15 @@
pointer-events: auto; pointer-events: auto;
height: 80%; height: 80%;
width: 75%; width: 75%;
top: 10%; top: 4%;
position: relative; left: 0;
z-index: 80; right: 0;
margin: auto; margin-left: auto;
margin-right: auto;
position: absolute;
z-index: 900;
display: grid; display: grid;
grid-template-columns: var(--size-first-columns-grid) calc(100% - var(--size-first-columns-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 { div.menu-container-main {
--size-first-columns-grid: 120px; --size-first-columns-grid: 120px;
height: 70%; height: 70%;
top: 55px; top: 55px;
width: 100%; width: 95%;
font-size: 0.5em; font-size: 0.5em;
div.menu-nav-sidebar { div.menu-nav-sidebar {

View file

@ -14,6 +14,7 @@
function showMenu() { function showMenu() {
menuVisiblilityStore.set(!get(menuVisiblilityStore)); menuVisiblilityStore.set(!get(menuVisiblilityStore));
} }
function showChat() { function showChat() {
chatVisibilityStore.set(true); chatVisibilityStore.set(true);
} }
@ -21,72 +22,97 @@
function register() { function register() {
window.open(`${ADMIN_URL}/second-step-register`, "_self"); window.open(`${ADMIN_URL}/second-step-register`, "_self");
} }
function showInvite() { function showInvite() {
showShareLinkMapModalStore.set(true); showShareLinkMapModalStore.set(true);
} }
function noDrag() {
return false;
}
</script> </script>
<svelte:window /> <svelte:window />
<main class="menuIcon"> <main class="menuIcon noselect">
{#if $limitMapStore} {#if $limitMapStore}
<img <img
src={logoInvite} src={logoInvite}
alt={$LL.menu.icon.open.invite()} alt={$LL.menu.icon.open.invite()}
class="nes-pointer" class="nes-pointer"
draggable="false"
on:dragstart|preventDefault={noDrag}
on:click|preventDefault={showInvite} on:click|preventDefault={showInvite}
/> />
<img <img
src={logoRegister} src={logoRegister}
alt={$LL.menu.icon.open.register()} alt={$LL.menu.icon.open.register()}
class="nes-pointer" class="nes-pointer"
draggable="false"
on:dragstart|preventDefault={noDrag}
on:click|preventDefault={register} on:click|preventDefault={register}
/> />
{:else} {:else}
<img src={logoWA} alt={$LL.menu.icon.open.menu()} class="nes-pointer" on:click|preventDefault={showMenu} /> <img
<img src={logoTalk} alt={$LL.menu.icon.open.chat()} class="nes-pointer" on:click|preventDefault={showChat} /> 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} {/if}
</main> </main>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
.menuIcon { .menuIcon {
display: inline-grid; display: flex;
z-index: 90; flex-direction: column;
align-items: center;
margin-top: 20%;
z-index: 800;
position: relative; position: relative;
margin: 25px;
img { img {
pointer-events: auto; pointer-events: auto;
width: 60px; width: 60px;
padding-top: 0; padding-top: 0;
margin: 3px; margin: 5%;
image-rendering: pixelated;
} }
} }
.menuIcon img:hover { .menuIcon img:hover {
transform: scale(1.2); transform: scale(1.2);
} }
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
@include media-breakpoint-up(sm) {
.menuIcon { .menuIcon {
display: inline-grid; margin-top: 10%;
z-index: 90;
position: relative;
margin: 25px;
img { img {
pointer-events: auto; pointer-events: auto;
width: 60px; width: 60px;
padding-top: 0; padding-top: 0;
margin: 3px;
} }
} }
.menuIcon img:hover { .menuIcon img:hover {
transform: scale(1.2); transform: scale(1.2);
} }
@media only screen and (max-width: 800px), only screen and (max-height: 800px) { }
.menuIcon {
margin: 3px; @include media-breakpoint-up(md) {
img { .menuIcon {
width: 50px; img {
} width: 50px;
} }
} }
} }

View file

@ -102,6 +102,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
div.customize-main { div.customize-main {
width: 100%; width: 100%;
display: inline-flex; 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 { div.customize-main.content section button {
width: 130px; width: 130px;
} }

View file

@ -2,11 +2,11 @@
import { localUserStore } from "../../Connexion/LocalUserStore"; import { localUserStore } from "../../Connexion/LocalUserStore";
import { videoConstraintStore } from "../../Stores/MediaStore"; import { videoConstraintStore } from "../../Stores/MediaStore";
import { HtmlUtils } from "../../WebRtc/HtmlUtils"; import { HtmlUtils } from "../../WebRtc/HtmlUtils";
import { isMobile } from "../../Enum/EnvironmentVariable";
import { menuVisiblilityStore } from "../../Stores/MenuStore"; import { menuVisiblilityStore } from "../../Stores/MenuStore";
import LL, { locale } from "../../i18n/i18n-svelte"; import LL, { locale } from "../../i18n/i18n-svelte";
import type { Locales } from "../../i18n/i18n-types"; import type { Locales } from "../../i18n/i18n-types";
import { displayableLocales, setCurrentLocale } from "../../i18n/locales"; import { displayableLocales, setCurrentLocale } from "../../i18n/locales";
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
let fullscreen: boolean = localUserStore.getFullscreen(); let fullscreen: boolean = localUserStore.getFullscreen();
let notification: boolean = localUserStore.getNotification() === "granted"; let notification: boolean = localUserStore.getNotification() === "granted";
@ -85,6 +85,8 @@
function closeMenu() { function closeMenu() {
menuVisiblilityStore.set(false); menuVisiblilityStore.set(false);
} }
const isMobile = isMediaBreakpointUp("md");
</script> </script>
<div class="settings-main" on:submit|preventDefault={saveSetting}> <div class="settings-main" on:submit|preventDefault={saveSetting}>
@ -93,22 +95,22 @@
<div class="nes-select is-dark"> <div class="nes-select is-dark">
<select bind:value={valueGame}> <select bind:value={valueGame}>
<option value={120} <option value={120}
>{isMobile() >{isMobile
? $LL.menu.settings.gameQuality.short.high() ? $LL.menu.settings.gameQuality.short.high()
: $LL.menu.settings.gameQuality.long.high()}</option : $LL.menu.settings.gameQuality.long.high()}</option
> >
<option value={60} <option value={60}
>{isMobile() >{isMobile
? $LL.menu.settings.gameQuality.short.medium() ? $LL.menu.settings.gameQuality.short.medium()
: $LL.menu.settings.gameQuality.long.medium()}</option : $LL.menu.settings.gameQuality.long.medium()}</option
> >
<option value={40} <option value={40}
>{isMobile() >{isMobile
? $LL.menu.settings.gameQuality.short.small() ? $LL.menu.settings.gameQuality.short.small()
: $LL.menu.settings.gameQuality.long.small()}</option : $LL.menu.settings.gameQuality.long.small()}</option
> >
<option value={20} <option value={20}
>{isMobile() >{isMobile
? $LL.menu.settings.gameQuality.short.minimum() ? $LL.menu.settings.gameQuality.short.minimum()
: $LL.menu.settings.gameQuality.long.minimum()}</option : $LL.menu.settings.gameQuality.long.minimum()}</option
> >
@ -120,22 +122,22 @@
<div class="nes-select is-dark"> <div class="nes-select is-dark">
<select bind:value={valueVideo}> <select bind:value={valueVideo}>
<option value={30} <option value={30}
>{isMobile() >{isMobile
? $LL.menu.settings.videoQuality.short.high() ? $LL.menu.settings.videoQuality.short.high()
: $LL.menu.settings.videoQuality.long.high()}</option : $LL.menu.settings.videoQuality.long.high()}</option
> >
<option value={20} <option value={20}
>{isMobile() >{isMobile
? $LL.menu.settings.videoQuality.short.medium() ? $LL.menu.settings.videoQuality.short.medium()
: $LL.menu.settings.videoQuality.long.medium()}</option : $LL.menu.settings.videoQuality.long.medium()}</option
> >
<option value={10} <option value={10}
>{isMobile() >{isMobile
? $LL.menu.settings.videoQuality.short.small() ? $LL.menu.settings.videoQuality.short.small()
: $LL.menu.settings.videoQuality.long.small()}</option : $LL.menu.settings.videoQuality.long.small()}</option
> >
<option value={5} <option value={5}
>{isMobile() >{isMobile
? $LL.menu.settings.videoQuality.short.minimum() ? $LL.menu.settings.videoQuality.short.minimum()
: $LL.menu.settings.videoQuality.long.minimum()}</option : $LL.menu.settings.videoQuality.long.minimum()}</option
> >
@ -199,6 +201,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
div.settings-main { div.settings-main {
height: calc(100% - 40px); height: calc(100% - 40px);
overflow-y: auto; 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 { div.settings-main {
section { section {
padding: 0; padding: 0;

View file

@ -32,6 +32,7 @@
max-width: 80vw; max-width: 80vw;
overflow: auto; overflow: auto;
text-align: center; text-align: center;
z-index: 500;
h2 { h2 {
font-family: "Press Start 2P"; font-family: "Press Start 2P";

View file

@ -75,6 +75,7 @@
max-width: 80vw; max-width: 80vw;
overflow: auto; overflow: auto;
text-align: center; text-align: center;
z-index: 450;
h2 { h2 {
font-family: "Press Start 2P"; font-family: "Press Start 2P";

View file

@ -2,7 +2,7 @@
import { obtainedMediaConstraintStore } from "../Stores/MediaStore"; import { obtainedMediaConstraintStore } from "../Stores/MediaStore";
import { localStreamStore, isSilentStore } from "../Stores/MediaStore"; import { localStreamStore, isSilentStore } from "../Stores/MediaStore";
import SoundMeterWidget from "./SoundMeterWidget.svelte"; import SoundMeterWidget from "./SoundMeterWidget.svelte";
import { onDestroy } from "svelte"; import { onDestroy, onMount } from "svelte";
import { srcObject } from "./Video/utils"; import { srcObject } from "./Video/utils";
import LL from "../i18n/i18n-svelte"; import LL from "../i18n/i18n-svelte";
@ -23,15 +23,75 @@
isSilent = value; 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); onDestroy(unsubscribeIsSilent);
</script> </script>
<div> <div
<div class="video-container div-myCamVideo" class:hide={!$obtainedMediaConstraintStore.video || isSilent}> class="nes-container is-rounded my-cam-video-container"
{#if $localStreamStore.type === "success" && $localStreamStore.stream} class:hide={($localStreamStore.type !== "success" || !$obtainedMediaConstraintStore.video) && !isSilent}
<video class="myCamVideo" use:srcObject={stream} autoplay muted playsinline /> bind:this={cameraContainer}
<SoundMeterWidget {stream} /> >
{/if} {#if isSilent}
</div> <div class="is-silent">{$LL.camera.my.silentZone()}</div>
<div class="is-silent" class:hide={isSilent}>{$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> </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: rgba(#000000, 0.6);
background-clip: content-box;
overflow: hidden;
line-height: 0;
z-index: 250;
&.nes-container.is-rounded {
border-image-outset: 1;
}
}
.my-cam-video-container.hide {
transform: translateX(200%);
}
.my-cam-video {
background-color: #00000099;
max-height: 20vh;
max-width: max(25vw, 150px);
width: 100%;
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
}
.is-silent {
font-size: 2em;
color: white;
padding: 40px 20px;
}
</style>

View file

@ -108,12 +108,16 @@
pointer-events: auto; pointer-events: auto;
background-color: #333333; background-color: #333333;
color: whitesmoke; color: whitesmoke;
z-index: 650;
position: relative; position: absolute;
height: 70vh; height: 70vh;
width: 50vw; width: 50vw;
top: 10vh; top: 4%;
margin: auto;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
section.report-menu-title { section.report-menu-title {
display: grid; display: grid;
@ -137,13 +141,4 @@
display: none; display: none;
} }
} }
@media only screen and (max-width: 800px) {
div.report-menu-main {
top: 21vh;
height: 60vh;
width: 100vw;
font-size: 0.5em;
}
}
</style> </style>

View file

@ -47,6 +47,8 @@
</form> </form>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
form.selectCompanionScene { form.selectCompanionScene {
font-family: "Press Start 2P"; font-family: "Press Start 2P";
pointer-events: auto; pointer-events: auto;
@ -85,7 +87,7 @@
} }
} }
@media only screen and (max-width: 800px) { @include media-breakpoint-up(md) {
form.selectCompanionScene button.selectCharacterButtonLeft { form.selectCompanionScene button.selectCharacterButtonLeft {
left: 5vw; left: 5vw;
} }

View file

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import { fly, fade } from "svelte/transition"; import { fly, fade } from "svelte/transition";
import { onMount } from "svelte"; import { onMount } from "svelte";
import { gameManager } from "../../Phaser/Game/GameManager";
import type { Message } from "../../Stores/TypeMessageStore/MessageStore"; import type { Message } from "../../Stores/TypeMessageStore/MessageStore";
import { banMessageStore } from "../../Stores/TypeMessageStore/BanMessageStore"; import { banMessageStore } from "../../Stores/TypeMessageStore/BanMessageStore";
import LL from "../../i18n/i18n-svelte"; import LL from "../../i18n/i18n-svelte";
@ -13,6 +14,8 @@
onMount(() => { onMount(() => {
timeToRead(); timeToRead();
const gameScene = gameManager.getCurrentGameScene();
gameScene.playSound("audio-report-message");
}); });
function timeToRead() { function timeToRead() {
@ -53,18 +56,19 @@
on:click|preventDefault={closeBanMessage}>{nameButton}</button on:click|preventDefault={closeBanMessage}>{nameButton}</button
> >
</div> </div>
<!-- svelte-ignore a11y-media-has-caption -->
<audio id="report-message" autoplay>
<source src="/resources/objects/report-message.mp3" type="audio/mp3" />
</audio>
</div> </div>
<style lang="scss"> <style lang="scss">
div.main-ban-message { div.main-ban-message {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: relative; position: absolute;
top: 15vh; top: 4%;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
z-index: 850;
height: 70vh; height: 70vh;
width: 60vw; width: 60vw;

View file

@ -11,3 +11,9 @@
</div> </div>
{/each} {/each}
</div> </div>
<style lang="scss">
.main-ban-message-container {
z-index: 800;
}
</style>

View file

@ -42,14 +42,17 @@
div.main-text-message { div.main-text-message {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: absolute;
max-height: 25vh; max-height: 25%;
width: 80vw; width: 60%;
margin-right: auto; margin-right: auto;
margin-left: auto; margin-left: auto;
margin-bottom: 16px; top: 6%;
margin-top: 0; left: 0;
right: 0;
padding-bottom: 0; padding-bottom: 0;
z-index: 240;
pointer-events: auto; pointer-events: auto;
background-color: #333333; background-color: #333333;

View file

@ -15,7 +15,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
div.main-text-message-container { .main-text-message-container {
padding-top: 16px; padding-top: 16px;
z-index: 800;
} }
</style> </style>

View file

@ -37,6 +37,7 @@
background-color: black; background-color: black;
border-radius: 30px 0 0 30px; border-radius: 30px 0 0 30px;
display: inline-flex; display: inline-flex;
z-index: 750;
img { img {
border-radius: 50%; border-radius: 50%;

View file

@ -25,11 +25,17 @@
<style lang="scss"> <style lang="scss">
div.error-div { div.error-div {
pointer-events: auto; pointer-events: auto;
margin-top: 10vh; margin-top: 4%;
margin-right: auto; margin-right: auto;
margin-left: auto; margin-left: auto;
left: 0;
right: 0;
position: absolute;
width: max-content; width: max-content;
max-width: 80vw; max-width: 80vw;
z-index: 230;
height: auto !important;
background-clip: padding-box;
.button-bar { .button-bar {
text-align: center; text-align: center;

View file

@ -1,15 +1,33 @@
<script lang="typescript"> <script lang="typescript">
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
import type { EmbedScreen } from "../../Stores/EmbedScreensStore";
import type { ScreenSharingLocalMedia } from "../../Stores/ScreenSharingStore"; import type { ScreenSharingLocalMedia } from "../../Stores/ScreenSharingStore";
import { videoFocusStore } from "../../Stores/VideoFocusStore"; import type { Streamable } from "../../Stores/StreamableCollectionStore";
import { srcObject } from "./utils"; import { srcObject } from "./utils";
export let clickable = false;
export let peer: ScreenSharingLocalMedia; export let peer: ScreenSharingLocalMedia;
let stream = peer.stream; let stream = peer.stream;
export let cssClass: string | undefined; export let cssClass: string | undefined;
let embedScreen: EmbedScreen;
if (stream) {
embedScreen = {
type: "streamable",
embed: stream as unknown as Streamable,
};
}
</script> </script>
<div class="video-container {cssClass ? cssClass : ''}" class:hide={!stream}> <div class="video-container {cssClass ? cssClass : ''}" class:hide={!stream}>
{#if 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} {/if}
</div> </div>

View file

@ -7,14 +7,110 @@
import type { Streamable } from "../../Stores/StreamableCollectionStore"; import type { Streamable } from "../../Stores/StreamableCollectionStore";
export let streamable: Streamable; export let streamable: Streamable;
export let isHightlighted = false;
export let isClickable = false;
export let mozaicFullWidth = false;
export let mozaicQuarter = false;
</script> </script>
<div class="media-container"> <div
{#if streamable instanceof VideoPeer} class="media-container nes-container is-rounded {isHightlighted ? 'hightlighted' : ''}"
<VideoMediaBox peer={streamable} /> class:clickable={isClickable}
{:else if streamable instanceof ScreenSharingPeer} class:mozaic-full-width={mozaicFullWidth}
<ScreenSharingMediaBox peer={streamable} /> class:mozaic-quarter={mozaicQuarter}
{:else} >
<LocalStreamMediaBox peer={streamable} cssClass="" /> <div>
{/if} {#if streamable instanceof VideoPeer}
<VideoMediaBox peer={streamable} clickable={isClickable} />
{:else if streamable instanceof ScreenSharingPeer}
<ScreenSharingMediaBox peer={streamable} clickable={isClickable} />
{:else}
<LocalStreamMediaBox peer={streamable} clickable={isClickable} cssClass="" />
{/if}
</div>
</div> </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;
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;
}
}
&.mozaic-full-width {
width: 95%;
max-width: 95%;
margin-left: 3%;
margin-right: 3%;
margin-top: auto;
margin-bottom: auto;
&:hover {
margin-top: auto;
margin-bottom: auto;
}
}
&.mozaic-quarter {
width: 95%;
max-width: 95%;
margin-top: auto;
margin-bottom: auto;
&:hover {
margin-top: auto;
margin-bottom: auto;
}
}
&.nes-container.is-rounded {
border-image-outset: 1;
}
&.clickable {
cursor: url("../../../style/images/cursor_pointer.png"), pointer;
}
> div {
background-color: rgba(0, 0, 0, 0.6);
display: flex;
width: 100%;
}
}
@include media-breakpoint-only(md) {
.media-container {
margin-top: 10%;
margin-bottom: 10%;
}
}
</style>

View file

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

View file

@ -1,12 +1,26 @@
<script lang="ts"> <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 type { ScreenSharingPeer } from "../../WebRtc/ScreenSharingPeer";
import { videoFocusStore } from "../../Stores/VideoFocusStore";
import { getColorByString, srcObject } from "./utils"; import { getColorByString, srcObject } from "./utils";
export let clickable = false;
export let peer: ScreenSharingPeer; export let peer: ScreenSharingPeer;
let streamStore = peer.streamStore; let streamStore = peer.streamStore;
let name = peer.userName; let name = peer.userName;
let statusStore = peer.statusStore; let statusStore = peer.statusStore;
let embedScreen: EmbedScreen;
if (peer) {
embedScreen = {
type: "streamable",
embed: peer as unknown as Streamable,
};
}
</script> </script>
<div class="video-container"> <div class="video-container">
@ -20,7 +34,12 @@
<i style="background-color: {getColorByString(name)};">{name}</i> <i style="background-color: {getColorByString(name)};">{name}</i>
{:else} {:else}
<!-- svelte-ignore a11y-media-has-caption --> <!-- 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} {/if}
</div> </div>

View file

@ -4,11 +4,17 @@
import microphoneCloseImg from "../images/microphone-close.svg"; import microphoneCloseImg from "../images/microphone-close.svg";
import reportImg from "./images/report.svg"; import reportImg from "./images/report.svg";
import blockSignImg from "./images/blockSign.svg"; import blockSignImg from "./images/blockSign.svg";
import { videoFocusStore } from "../../Stores/VideoFocusStore";
import { showReportScreenStore } from "../../Stores/ShowReportScreenStore"; import { showReportScreenStore } from "../../Stores/ShowReportScreenStore";
import { getColorByString, srcObject } from "./utils"; 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 Woka from "../Woka/Woka.svelte";
import { onMount } from "svelte";
import { isMediaBreakpointOnly } from "../../Utils/BreakpointsUtils";
export let clickable = false;
export let peer: VideoPeer; export let peer: VideoPeer;
let streamStore = peer.streamStore; let streamStore = peer.streamStore;
@ -19,9 +25,32 @@
function openReport(peer: VideoPeer): void { function openReport(peer: VideoPeer): void {
showReportScreenStore.set({ userId: peer.userId, userName: peer.userName }); 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> </script>
<div class="video-container"> <div class="video-container" class:no-clikable={!clickable} bind:this={videoContainer}>
{#if $statusStore === "connecting"} {#if $statusStore === "connecting"}
<div class="connecting-spinner" /> <div class="connecting-spinner" />
{/if} {/if}
@ -30,42 +59,64 @@
{/if} {/if}
<!-- {#if !$constraintStore || $constraintStore.video === false} --> <!-- {#if !$constraintStore || $constraintStore.video === false} -->
<i <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)};" 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> <div class="woka-icon"><Woka userId={peer.userId} placeholderSrc={""} /></div>
</i> </i>
<!-- {/if} --> <!-- {/if} -->
{#if $constraintStore && $constraintStore.audio === false} {#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} {/if}
<button class="report" on:click={() => openReport(peer)}> <button class="report" on:click={() => openReport(peer)}>
<img alt="Report this user" src={reportImg} /> <img alt="Report this user" draggable="false" on:dragstart|preventDefault={noDrag} src={reportImg} />
<span>Report/Block</span> <span class="noselect">Report/Block</span>
</button> </button>
<!-- svelte-ignore a11y-media-has-caption --> <!-- svelte-ignore a11y-media-has-caption -->
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)} /> <video
<img src={blockSignImg} class="block-logo" alt="Block" /> class:no-video={!$constraintStore || $constraintStore.video === false}
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} {#if $constraintStore && $constraintStore.audio !== false}
<SoundMeterWidget stream={$streamStore} /> <SoundMeterWidget stream={$streamStore} />
{/if} {/if}
</div> </div>
<style> <style lang="scss">
.container { .container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding-top: 15px; padding-top: 15px;
}
.minimized { &.has-video {
left: auto; left: auto;
transform: scale(0.5); transform: scale(0.5);
opacity: 0.5; opacity: 0.5;
} }
.woka-icon { &.minimized {
margin-right: 3px; transform: scale(0.5);
opacity: 0.5;
}
.woka-icon {
margin-right: 3px;
}
}
video.no-video {
visibility: collapse;
} }
</style> </style>

View file

@ -1,16 +1,16 @@
<script lang="ts"> <script lang="ts">
import { LayoutMode } from "../../WebRtc/LayoutManager"; // import {LayoutMode} from "../../WebRtc/LayoutManager";
import { layoutModeStore } from "../../Stores/StreamableCollectionStore"; // import {layoutModeStore} from "../../Stores/StreamableCollectionStore";
import PresentationLayout from "./PresentationLayout.svelte"; // import PresentationLayout from "./PresentationLayout.svelte";
import ChatLayout from "./ChatLayout.svelte"; // import ChatLayout from "./ChatLayout.svelte";
</script> </script>
<div class="video-overlay"> <div class="video-overlay">
{#if $layoutModeStore === LayoutMode.Presentation} <!-- {#if $layoutModeStore === LayoutMode.Presentation }
<PresentationLayout /> <PresentationLayout />
{:else} {:else}
<ChatLayout /> <ChatLayout />
{/if} {/if} -->
</div> </div>
<style lang="scss"> <style lang="scss">

View file

@ -57,6 +57,7 @@
height: 120px; height: 120px;
margin: auto; margin: auto;
animation: spin 2s linear infinite; animation: spin 2s linear infinite;
z-index: 350;
} }
@keyframes spin { @keyframes spin {

View file

@ -27,18 +27,22 @@
<style lang="scss"> <style lang="scss">
main.warningMain { main.warningMain {
pointer-events: auto; pointer-events: auto;
width: 100vw; width: 80%;
background-color: #f9e81e; background-color: #f9e81e;
color: #14304c; color: #14304c;
text-align: center; text-align: center;
position: absolute; position: absolute;
left: 50%;
top: 4%;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
transform: translate(-50%, 0); transform: translate(-50%, 0);
font-family: Lato; font-family: Lato;
min-width: 300px; min-width: 300px;
opacity: 0.9; opacity: 0.9;
z-index: 2; z-index: 700;
h2 { h2 {
padding: 5px; padding: 5px;
} }

View file

@ -22,10 +22,21 @@
src = source ?? placeholderSrc; src = source ?? placeholderSrc;
}); });
function noDrag() {
return false;
}
onDestroy(unsubscribe); onDestroy(unsubscribe);
</script> </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> <style>
img { img {

View file

@ -49,6 +49,8 @@
</form> </form>
<style lang="scss"> <style lang="scss">
@import "../../../style/breakpoints.scss";
form.selectCharacterScene { form.selectCharacterScene {
font-family: "Press Start 2P"; font-family: "Press Start 2P";
pointer-events: auto; pointer-events: auto;
@ -91,7 +93,7 @@
} }
} }
@media only screen and (max-width: 800px) { @include media-breakpoint-up(md) {
form.selectCharacterScene button.selectCharacterButtonLeft { form.selectCharacterScene button.selectCharacterButtonLeft {
left: 5vw; left: 5vw;
} }

View file

@ -42,8 +42,6 @@ export const DISABLE_ANONYMOUS: boolean = getEnv("DISABLE_ANONYMOUS") === "true"
export const OPID_LOGIN_SCREEN_PROVIDER = getEnv("OPID_LOGIN_SCREEN_PROVIDER"); export const OPID_LOGIN_SCREEN_PROVIDER = getEnv("OPID_LOGIN_SCREEN_PROVIDER");
const FALLBACK_LOCALE = getEnv("FALLBACK_LOCALE") || undefined; const FALLBACK_LOCALE = getEnv("FALLBACK_LOCALE") || undefined;
export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600;
export { export {
DEBUG_MODE, DEBUG_MODE,
START_ROOM_URL, START_ROOM_URL,

View file

@ -63,8 +63,6 @@ export class SoundMeter {
//this.slow = 0.95 * that.slow + 0.05 * that.instant; //this.slow = 0.95 * that.slow + 0.05 * that.instant;
//this.clip = clipcount / input.length; //this.clip = clipcount / input.length;
//console.log('instant', this.instant, 'clip', this.clip);
return this.instant; return this.instant;
} }

View file

@ -20,7 +20,6 @@ export enum GameMapProperties {
OPEN_WEBSITE = "openWebsite", OPEN_WEBSITE = "openWebsite",
OPEN_WEBSITE_ALLOW_API = "openWebsiteAllowApi", OPEN_WEBSITE_ALLOW_API = "openWebsiteAllowApi",
OPEN_WEBSITE_POLICY = "openWebsitePolicy", OPEN_WEBSITE_POLICY = "openWebsitePolicy",
OPEN_WEBSITE_WIDTH = "openWebsiteWidth",
OPEN_WEBSITE_POSITION = "openWebsitePosition", OPEN_WEBSITE_POSITION = "openWebsitePosition",
OPEN_WEBSITE_TRIGGER = "openWebsiteTrigger", OPEN_WEBSITE_TRIGGER = "openWebsiteTrigger",
OPEN_WEBSITE_TRIGGER_MESSAGE = "openWebsiteTriggerMessage", OPEN_WEBSITE_TRIGGER_MESSAGE = "openWebsiteTriggerMessage",

View file

@ -9,21 +9,21 @@ import { get } from "svelte/store";
import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager"; import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
import type { ITiledMapLayer } from "../Map/ITiledMap"; import type { ITiledMapLayer } from "../Map/ITiledMap";
import { GameMapProperties } from "./GameMapProperties"; import { GameMapProperties } from "./GameMapProperties";
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
enum OpenCoWebsiteState { enum OpenCoWebsiteState {
LOADING, ASLEEP,
OPENED, OPENED,
MUST_BE_CLOSE, MUST_BE_CLOSE,
} }
interface OpenCoWebsite { interface OpenCoWebsite {
coWebsite: CoWebsite | undefined; coWebsite: CoWebsite;
state: OpenCoWebsiteState; state: OpenCoWebsiteState;
} }
export class GameMapPropertiesListener { export class GameMapPropertiesListener {
private coWebsitesOpenByLayer = new Map<ITiledMapLayer, OpenCoWebsite>(); private coWebsitesOpenByLayer = new Map<ITiledMapLayer, OpenCoWebsite>();
private coWebsitesActionTriggerByLayer = new Map<ITiledMapLayer, string>();
constructor(private scene: GameScene, private gameMap: GameMap) {} constructor(private scene: GameScene, private gameMap: GameMap) {}
@ -64,10 +64,8 @@ export class GameMapPropertiesListener {
let openWebsiteProperty: string | undefined; let openWebsiteProperty: string | undefined;
let allowApiProperty: boolean | undefined; let allowApiProperty: boolean | undefined;
let websitePolicyProperty: string | undefined; let websitePolicyProperty: string | undefined;
let websiteWidthProperty: number | undefined;
let websitePositionProperty: number | undefined; let websitePositionProperty: number | undefined;
let websiteTriggerProperty: string | undefined; let websiteTriggerProperty: string | undefined;
let websiteTriggerMessageProperty: string | undefined;
layer.properties.forEach((property) => { layer.properties.forEach((property) => {
switch (property.name) { switch (property.name) {
@ -80,18 +78,12 @@ export class GameMapPropertiesListener {
case GameMapProperties.OPEN_WEBSITE_POLICY: case GameMapProperties.OPEN_WEBSITE_POLICY:
websitePolicyProperty = property.value as string | undefined; websitePolicyProperty = property.value as string | undefined;
break; break;
case GameMapProperties.OPEN_WEBSITE_WIDTH:
websiteWidthProperty = property.value as number | undefined;
break;
case GameMapProperties.OPEN_WEBSITE_POSITION: case GameMapProperties.OPEN_WEBSITE_POSITION:
websitePositionProperty = property.value as number | undefined; websitePositionProperty = property.value as number | undefined;
break; break;
case GameMapProperties.OPEN_WEBSITE_TRIGGER: case GameMapProperties.OPEN_WEBSITE_TRIGGER:
websiteTriggerProperty = property.value as string | undefined; websiteTriggerProperty = property.value as string | undefined;
break; break;
case GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE:
websiteTriggerMessageProperty = property.value as string | undefined;
break;
} }
}); });
@ -105,27 +97,30 @@ export class GameMapPropertiesListener {
return; return;
} }
const coWebsite = coWebsiteManager.addCoWebsite(
openWebsiteProperty,
this.scene.MapUrlFile,
allowApiProperty,
websitePolicyProperty,
websitePositionProperty,
false
);
this.coWebsitesOpenByLayer.set(layer, { this.coWebsitesOpenByLayer.set(layer, {
coWebsite: undefined, coWebsite: coWebsite,
state: OpenCoWebsiteState.LOADING, state: OpenCoWebsiteState.ASLEEP,
}); });
const openWebsiteFunction = () => { const openWebsiteFunction = () => {
coWebsiteManager coWebsiteManager
.loadCoWebsite( .loadCoWebsite(coWebsite)
openWebsiteProperty as string,
this.scene.MapUrlFile,
allowApiProperty,
websitePolicyProperty,
websiteWidthProperty,
websitePositionProperty
)
.then((coWebsite) => { .then((coWebsite) => {
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer); const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) { if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) {
coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => console.error(e)); coWebsiteManager.closeCoWebsite(coWebsite).catch(() => {
console.error("Error during a co-website closing");
});
this.coWebsitesOpenByLayer.delete(layer); this.coWebsitesOpenByLayer.delete(layer);
this.coWebsitesActionTriggerByLayer.delete(layer);
} else { } else {
this.coWebsitesOpenByLayer.set(layer, { this.coWebsitesOpenByLayer.set(layer, {
coWebsite, coWebsite,
@ -133,27 +128,17 @@ export class GameMapPropertiesListener {
}); });
} }
}) })
.catch((e) => console.error(e)); .catch(() => {
console.error("Error during loading a co-website: " + coWebsite.url);
});
layoutManagerActionStore.removeAction(actionUuid); layoutManagerActionStore.removeAction(actionUuid);
}; };
const forceTrigger = localUserStore.getForceCowebsiteTrigger(); if (
if (forceTrigger || websiteTriggerProperty === ON_ACTION_TRIGGER_BUTTON) { !localUserStore.getForceCowebsiteTrigger() &&
if (!websiteTriggerMessageProperty) { websiteTriggerProperty !== ON_ACTION_TRIGGER_BUTTON
websiteTriggerMessageProperty = "Press SPACE or touch here to open web site"; ) {
}
this.coWebsitesActionTriggerByLayer.set(layer, actionUuid);
layoutManagerActionStore.addAction({
uuid: actionUuid,
type: "message",
message: websiteTriggerMessageProperty,
callback: () => openWebsiteFunction(),
userInputManager: this.scene.userInputManager,
});
} else {
openWebsiteFunction(); openWebsiteFunction();
} }
}); });
@ -194,7 +179,7 @@ export class GameMapPropertiesListener {
return; return;
} }
if (coWebsiteOpen.state === OpenCoWebsiteState.LOADING) { if (coWebsiteOpen.state === OpenCoWebsiteState.ASLEEP) {
coWebsiteOpen.state = OpenCoWebsiteState.MUST_BE_CLOSE; coWebsiteOpen.state = OpenCoWebsiteState.MUST_BE_CLOSE;
} }
@ -203,26 +188,6 @@ export class GameMapPropertiesListener {
} }
this.coWebsitesOpenByLayer.delete(layer); this.coWebsitesOpenByLayer.delete(layer);
if (!websiteTriggerProperty) {
return;
}
const actionStore = get(layoutManagerActionStore);
const actionTriggerUuid = this.coWebsitesActionTriggerByLayer.get(layer);
if (!actionTriggerUuid) {
return;
}
const action =
actionStore && actionStore.length > 0
? actionStore.find((action) => action.uuid === actionTriggerUuid)
: undefined;
if (action) {
layoutManagerActionStore.removeAction(actionTriggerUuid);
}
}); });
}; };

View file

@ -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-in", "/resources/objects/webrtc-in.mp3");
this.load.audio("audio-webrtc-out", "/resources/objects/webrtc-out.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.sound.pauseOnBlur = false;
this.load.on(FILE_LOAD_ERROR, (file: { src: string }) => { this.load.on(FILE_LOAD_ERROR, (file: { src: string }) => {
@ -632,13 +632,9 @@ export class GameScene extends DirtyScene {
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => { this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
const newPeerNumber = peers.size; const newPeerNumber = peers.size;
if (newPeerNumber > oldPeerNumber) { if (newPeerNumber > oldPeerNumber) {
this.sound.play("audio-webrtc-in", { this.playSound("audio-webrtc-in");
volume: 0.2,
});
} else if (newPeerNumber < oldPeerNumber) { } else if (newPeerNumber < oldPeerNumber) {
this.sound.play("audio-webrtc-out", { this.playSound("audio-webrtc-out");
volume: 0.2,
});
} }
oldPeerNumber = newPeerNumber; oldPeerNumber = newPeerNumber;
}); });
@ -1265,21 +1261,21 @@ ${escapedMessage}
throw new Error("Unknown query source"); throw new Error("Unknown query source");
} }
const coWebsite = await coWebsiteManager.loadCoWebsite( const coWebsite = coWebsiteManager.addCoWebsite(
openCoWebsite.url, openCoWebsite.url,
iframeListener.getBaseUrlFromSource(source), iframeListener.getBaseUrlFromSource(source),
openCoWebsite.allowApi, openCoWebsite.allowApi,
openCoWebsite.allowPolicy, openCoWebsite.allowPolicy,
openCoWebsite.position openCoWebsite.position,
openCoWebsite.closable ?? true
); );
if (!coWebsite) { if (openCoWebsite.lazy !== undefined && !openCoWebsite.lazy) {
throw new Error("Error on opening co-website"); await coWebsiteManager.loadCoWebsite(coWebsite);
} }
return { return {
id: coWebsite.iframe.id, id: coWebsite.iframe.id,
position: coWebsite.position,
}; };
}); });
@ -1289,7 +1285,6 @@ ${escapedMessage}
return coWebsites.map((coWebsite: CoWebsite) => { return coWebsites.map((coWebsite: CoWebsite) => {
return { return {
id: coWebsite.iframe.id, 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 { public cleanupClosingScene(): void {
// stop playing audio, close any open website, stop any open Jitsi // stop playing audio, close any open website, stop any open Jitsi
coWebsiteManager.closeCoWebsites().catch((e) => console.error(e)); coWebsiteManager.closeCoWebsites().catch((e) => console.error(e));
@ -1602,7 +1603,7 @@ ${escapedMessage}
this.sharedVariablesManager?.close(); this.sharedVariablesManager?.close();
this.embeddedWebsiteManager?.close(); this.embeddedWebsiteManager?.close();
mediaManager.hideGameOverlay(); mediaManager.hideMyCamera();
for (const iframeEvents of this.iframeSubscriptionList) { for (const iframeEvents of this.iframeSubscriptionList) {
iframeEvents.unsubscribe(); iframeEvents.unsubscribe();
@ -2111,6 +2112,17 @@ ${escapedMessage}
biggestAvailableAreaStore.recompute(); 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 { public startJitsi(roomName: string, jwt?: string): void {
const allProps = this.gameMap.getCurrentProperties(); const allProps = this.gameMap.getCurrentProperties();
const jitsiConfig = this.safeParseJSONstring( const jitsiConfig = this.safeParseJSONstring(
@ -2122,28 +2134,21 @@ ${escapedMessage}
GameMapProperties.JITSI_INTERFACE_CONFIG GameMapProperties.JITSI_INTERFACE_CONFIG
); );
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined; const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
const jitsiWidth = allProps.get(GameMapProperties.JITSI_WIDTH) as number | undefined;
jitsiFactory jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl).catch(() => {
.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl, jitsiWidth) console.error("Cannot start a Jitsi co-website");
.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();
}); });
this.disableMediaBehaviors();
analyticsClient.enteredJitsi(roomName, this.room.id);
} }
public stopJitsi(): void { public stopJitsi(): void {
const silent = this.gameMap.getCurrentProperties().get(GameMapProperties.SILENT); const coWebsite = coWebsiteManager.searchJitsi();
this.connection?.setSilent(!!silent); if (coWebsite) {
jitsiFactory.stop(); coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => {
mediaManager.showGameOverlay(); console.error("Error during Jitsi co-website closing", e);
});
mediaManager.removeTriggerCloseJitsiFrameButton("close-jitsi"); }
} }
//todo: put this into an 'orchestrator' scene (EntryScene?) //todo: put this into an 'orchestrator' scene (EntryScene?)

View file

@ -11,10 +11,10 @@ import { areCharacterLayersValid } from "../../Connexion/LocalUser";
import { SelectCharacterSceneName } from "./SelectCharacterScene"; import { SelectCharacterSceneName } from "./SelectCharacterScene";
import { activeRowStore, customCharacterSceneVisibleStore } from "../../Stores/CustomCharacterStore"; import { activeRowStore, customCharacterSceneVisibleStore } from "../../Stores/CustomCharacterStore";
import { waScaleManager } from "../Services/WaScaleManager"; import { waScaleManager } from "../Services/WaScaleManager";
import { isMobile } from "../../Enum/EnvironmentVariable";
import { CustomizedCharacter } from "../Entity/CustomizedCharacter"; import { CustomizedCharacter } from "../Entity/CustomizedCharacter";
import { get } from "svelte/store"; import { get } from "svelte/store";
import { analyticsClient } from "../../Administration/AnalyticsClient"; import { analyticsClient } from "../../Administration/AnalyticsClient";
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
export const CustomizeSceneName = "CustomizeScene"; export const CustomizeSceneName = "CustomizeScene";
@ -67,12 +67,12 @@ export class CustomizeScene extends AbstractCharacterScene {
customCharacterSceneVisibleStore.set(true); customCharacterSceneVisibleStore.set(true);
this.events.addListener("wake", () => { this.events.addListener("wake", () => {
waScaleManager.saveZoom(); waScaleManager.saveZoom();
waScaleManager.zoomModifier = isMobile() ? 3 : 1; waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 3 : 1;
customCharacterSceneVisibleStore.set(true); customCharacterSceneVisibleStore.set(true);
}); });
waScaleManager.saveZoom(); waScaleManager.saveZoom();
waScaleManager.zoomModifier = isMobile() ? 3 : 1; waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 3 : 1;
this.Rectangle = this.add.rectangle( this.Rectangle = this.add.rectangle(
this.cameras.main.worldView.x + this.cameras.main.width / 2, this.cameras.main.worldView.x + this.cameras.main.width / 2,

View file

@ -12,8 +12,8 @@ import { touchScreenManager } from "../../Touch/TouchScreenManager";
import { PinchManager } from "../UserInput/PinchManager"; import { PinchManager } from "../UserInput/PinchManager";
import { selectCharacterSceneVisibleStore } from "../../Stores/SelectCharacterStore"; import { selectCharacterSceneVisibleStore } from "../../Stores/SelectCharacterStore";
import { waScaleManager } from "../Services/WaScaleManager"; import { waScaleManager } from "../Services/WaScaleManager";
import { isMobile } from "../../Enum/EnvironmentVariable";
import { analyticsClient } from "../../Administration/AnalyticsClient"; import { analyticsClient } from "../../Administration/AnalyticsClient";
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
//todo: put this constants in a dedicated file //todo: put this constants in a dedicated file
export const SelectCharacterSceneName = "SelectCharacterScene"; export const SelectCharacterSceneName = "SelectCharacterScene";
@ -60,7 +60,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
selectCharacterSceneVisibleStore.set(true); selectCharacterSceneVisibleStore.set(true);
this.events.addListener("wake", () => { this.events.addListener("wake", () => {
waScaleManager.saveZoom(); waScaleManager.saveZoom();
waScaleManager.zoomModifier = isMobile() ? 2 : 1; waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 2 : 1;
selectCharacterSceneVisibleStore.set(true); selectCharacterSceneVisibleStore.set(true);
}); });
@ -69,7 +69,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
} }
waScaleManager.saveZoom(); 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; const rectangleXStart = this.game.renderer.width / 2 - (this.nbCharactersPerRow / 2) * 32 + 16;
this.selectedRectangle = this.add.rectangle(rectangleXStart, 90, 32, 32).setStrokeStyle(2, 0xffffff); this.selectedRectangle = this.add.rectangle(rectangleXStart, 90, 32, 32).setStrokeStyle(2, 0xffffff);

View file

@ -9,7 +9,7 @@ import { touchScreenManager } from "../../Touch/TouchScreenManager";
import { PinchManager } from "../UserInput/PinchManager"; import { PinchManager } from "../UserInput/PinchManager";
import { selectCompanionSceneVisibleStore } from "../../Stores/SelectCompanionStore"; import { selectCompanionSceneVisibleStore } from "../../Stores/SelectCompanionStore";
import { waScaleManager } from "../Services/WaScaleManager"; import { waScaleManager } from "../Services/WaScaleManager";
import { isMobile } from "../../Enum/EnvironmentVariable"; import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
export const SelectCompanionSceneName = "SelectCompanionScene"; export const SelectCompanionSceneName = "SelectCompanionScene";
@ -44,7 +44,7 @@ export class SelectCompanionScene extends ResizableScene {
selectCompanionSceneVisibleStore.set(true); selectCompanionSceneVisibleStore.set(true);
waScaleManager.saveZoom(); waScaleManager.saveZoom();
waScaleManager.zoomModifier = isMobile() ? 2 : 1; waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 2 : 1;
if (touchScreenManager.supportTouchScreen) { if (touchScreenManager.supportTouchScreen) {
new PinchManager(this); new PinchManager(this);

View file

@ -37,19 +37,17 @@ export class WaScaleManager {
height: height * devicePixelRatio, height: height * devicePixelRatio,
}); });
if (gameSize.width == 0) { if (realSize.width !== 0 && gameSize.width !== 0 && devicePixelRatio !== 0) {
return; this.actualZoom = realSize.width / gameSize.width / devicePixelRatio;
} }
this.actualZoom = realSize.width / gameSize.width / devicePixelRatio; this.scaleManager.setZoom(this.actualZoom);
this.scaleManager.setZoom(realSize.width / gameSize.width / devicePixelRatio);
this.scaleManager.resize(gameSize.width, gameSize.height); this.scaleManager.resize(gameSize.width, gameSize.height);
// Override bug in canvas resizing in Phaser. Let's resize the canvas ourselves // Override bug in canvas resizing in Phaser. Let's resize the canvas ourselves
const style = this.scaleManager.canvas.style; const style = this.scaleManager.canvas.style;
style.width = Math.ceil(realSize.width / devicePixelRatio) + "px"; style.width = Math.ceil(realSize.width !== 0 ? realSize.width / devicePixelRatio : 0) + "px";
style.height = Math.ceil(realSize.height / devicePixelRatio) + "px"; style.height = Math.ceil(realSize.height !== 0 ? realSize.height / devicePixelRatio : 0) + "px";
// Resize the game element at the same size at the canvas // Resize the game element at the same size at the canvas
const gameStyle = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("game").style; const gameStyle = HtmlUtils.getElementByIdOrFail<HTMLDivElement>("game").style;

View file

@ -2,14 +2,14 @@ import { get, writable } from "svelte/store";
import type { Box } from "../WebRtc/LayoutManager"; import type { Box } from "../WebRtc/LayoutManager";
import { HtmlUtils } from "../WebRtc/HtmlUtils"; import { HtmlUtils } from "../WebRtc/HtmlUtils";
import { LayoutMode } from "../WebRtc/LayoutManager"; 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) * Tries to find the biggest available box of remaining space (this is a space where we can center the character)
*/ */
function findBiggestAvailableArea(): Box { function findBiggestAvailableArea(): Box {
const game = HtmlUtils.querySelectorOrFail<HTMLCanvasElement>("#game canvas"); 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 children = document.querySelectorAll<HTMLDivElement>("div.chat-mode > div");
const htmlChildren = Array.from(children.values()); const htmlChildren = Array.from(children.values());

View file

@ -0,0 +1,51 @@
import { derived, get, writable } from "svelte/store";
import type { CoWebsite } from "../WebRtc/CoWebsiteManager";
function createCoWebsiteStore() {
const { subscribe, set, update } = writable(Array<CoWebsite>());
set(Array<CoWebsite>());
return {
subscribe,
add: (coWebsite: CoWebsite, position?: number) => {
coWebsite.state.subscribe((value) => {
update((currentArray) => currentArray);
});
if (position || position === 0) {
update((currentArray) => {
if (position === 0) {
return [coWebsite, ...currentArray];
} else if (currentArray.length > position) {
const test = [...currentArray.splice(position, 0, coWebsite)];
return [...currentArray.splice(position, 0, coWebsite)];
}
return [...currentArray, coWebsite];
});
return;
}
update((currentArray) => [...currentArray, coWebsite]);
},
remove: (coWebsite: CoWebsite) => {
update((currentArray) => [
...currentArray.filter((currentCoWebsite) => currentCoWebsite.iframe.id !== coWebsite.iframe.id),
]);
},
empty: () => {
set(Array<CoWebsite>());
},
};
}
export const coWebsites = createCoWebsiteStore();
export const coWebsitesNotAsleep = derived([coWebsites], ([$coWebsites]) =>
$coWebsites.filter((coWebsite) => get(coWebsite.state) !== "asleep")
);
export const mainCoWebsite = derived([coWebsites], ([$coWebsites]) =>
$coWebsites.find((coWebsite) => get(coWebsite.state) !== "asleep")
);

View file

@ -0,0 +1,51 @@
import { derived, get, writable } from "svelte/store";
import type { CoWebsite } from "../WebRtc/CoWebsiteManager";
import { LayoutMode } from "../WebRtc/LayoutManager";
import { coWebsites } from "./CoWebsiteStore";
import { Streamable, streamableCollectionStore } from "./StreamableCollectionStore";
export type EmbedScreen =
| {
type: "streamable";
embed: Streamable;
}
| {
type: "cowebsite";
embed: CoWebsite;
};
function createHighlightedEmbedScreenStore() {
const { subscribe, set, update } = writable<EmbedScreen | null>(null);
return {
subscribe,
highlight: (embedScreen: EmbedScreen) => {
set(embedScreen);
},
removeHighlight: () => {
set(null);
},
toggleHighlight: (embedScreen: EmbedScreen) => {
update((currentEmbedScreen) =>
!currentEmbedScreen ||
embedScreen.type !== currentEmbedScreen.type ||
(embedScreen.type === "cowebsite" &&
currentEmbedScreen.type === "cowebsite" &&
embedScreen.embed.iframe.id !== currentEmbedScreen.embed.iframe.id) ||
(embedScreen.type === "streamable" &&
currentEmbedScreen.type === "streamable" &&
embedScreen.embed.uniqueId !== currentEmbedScreen.embed.uniqueId)
? embedScreen
: null
);
},
};
}
export const highlightedEmbedScreen = createHighlightedEmbedScreenStore();
export const embedScreenLayout = writable<LayoutMode>(LayoutMode.Presentation);
export const hasEmbedScreen = derived(
[streamableCollectionStore],
($values) => get(streamableCollectionStore).size + get(coWebsites).length > 0
);

View file

@ -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();

View file

@ -51,6 +51,6 @@ function createLayoutManagerAction() {
export const layoutManagerActionStore = createLayoutManagerAction(); export const layoutManagerActionStore = createLayoutManagerAction();
export const layoutManagerVisibilityStore = derived(layoutManagerActionStore, ($layoutManagerActionStore) => { export const layoutManagerActionVisibilityStore = derived(layoutManagerActionStore, ($layoutManagerActionStore) => {
return !!$layoutManagerActionStore.length; return !!$layoutManagerActionStore.length;
}); });

View file

@ -6,7 +6,7 @@ import { BrowserTooOldError } from "./Errors/BrowserTooOldError";
import { errorStore } from "./ErrorStore"; import { errorStore } from "./ErrorStore";
import { getNavigatorType, isIOS, NavigatorType } from "../WebRtc/DeviceUtils"; import { getNavigatorType, isIOS, NavigatorType } from "../WebRtc/DeviceUtils";
import { WebviewOnOldIOS } from "./Errors/WebviewOnOldIOS"; import { WebviewOnOldIOS } from "./Errors/WebviewOnOldIOS";
import { gameOverlayVisibilityStore } from "./GameOverlayStoreVisibility"; import { myCameraVisibilityStore } from "./MyCameraStoreVisibility";
import { peerStore } from "./PeerStore"; import { peerStore } from "./PeerStore";
import { privacyShutdownStore } from "./PrivacyShutdownStore"; import { privacyShutdownStore } from "./PrivacyShutdownStore";
import { MediaStreamConstraintsError } from "./Errors/MediaStreamConstraintsError"; import { MediaStreamConstraintsError } from "./Errors/MediaStreamConstraintsError";
@ -233,7 +233,7 @@ export const mediaStreamConstraintsStore = derived(
[ [
requestedCameraState, requestedCameraState,
requestedMicrophoneState, requestedMicrophoneState,
gameOverlayVisibilityStore, myCameraVisibilityStore,
enableCameraSceneVisibilityStore, enableCameraSceneVisibilityStore,
videoConstraintStore, videoConstraintStore,
audioConstraintStore, audioConstraintStore,
@ -245,7 +245,7 @@ export const mediaStreamConstraintsStore = derived(
[ [
$requestedCameraState, $requestedCameraState,
$requestedMicrophoneState, $requestedMicrophoneState,
$gameOverlayVisibilityStore, $myCameraVisibilityStore,
$enableCameraSceneVisibilityStore, $enableCameraSceneVisibilityStore,
$videoConstraintStore, $videoConstraintStore,
$audioConstraintStore, $audioConstraintStore,
@ -283,7 +283,7 @@ export const mediaStreamConstraintsStore = derived(
} }
// Disable webcam and microphone when in a Jitsi // Disable webcam and microphone when in a Jitsi
if ($gameOverlayVisibilityStore === false) { if ($myCameraVisibilityStore === false) {
currentVideoConstraint = false; currentVideoConstraint = false;
currentAudioConstraint = false; currentAudioConstraint = false;
} }

View 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);

View file

@ -1,7 +1,7 @@
import { derived, Readable, readable, writable } from "svelte/store"; import { derived, Readable, readable, writable } from "svelte/store";
import { peerStore } from "./PeerStore"; import { peerStore } from "./PeerStore";
import type { LocalStreamStoreValue } from "./MediaStore"; 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 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. * A store containing the media constraints we want to apply.
*/ */
export const screenSharingConstraintsStore = derived( export const screenSharingConstraintsStore = derived(
[requestedScreenSharingState, gameOverlayVisibilityStore, peerStore], [requestedScreenSharingState, myCameraVisibilityStore, peerStore],
([$requestedScreenSharingState, $gameOverlayVisibilityStore, $peerStore], set) => { ([$requestedScreenSharingState, $myCameraVisibilityStore, $peerStore], set) => {
let currentVideoConstraint: boolean | MediaTrackConstraints = true; let currentVideoConstraint: boolean | MediaTrackConstraints = true;
let currentAudioConstraint: boolean | MediaTrackConstraints = false; let currentAudioConstraint: boolean | MediaTrackConstraints = false;
@ -53,7 +53,7 @@ export const screenSharingConstraintsStore = derived(
} }
// Disable screen sharing when in a Jitsi // Disable screen sharing when in a Jitsi
if (!$gameOverlayVisibilityStore) { if (!$myCameraVisibilityStore) {
currentVideoConstraint = false; currentVideoConstraint = false;
currentAudioConstraint = false; currentAudioConstraint = false;
} }

View file

@ -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 { ScreenSharingLocalMedia, screenSharingLocalMedia } from "./ScreenSharingStore";
import { peerStore, screenSharingStreamStore } from "./PeerStore"; import { peerStore, screenSharingStreamStore } from "./PeerStore";
import type { RemotePeer } from "../WebRtc/SimplePeer"; import type { RemotePeer } from "../WebRtc/SimplePeer";
import { LayoutMode } from "../WebRtc/LayoutManager";
export type Streamable = RemotePeer | ScreenSharingLocalMedia; 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) * A store that contains everything that can produce a stream (so the peers + the local screen sharing stream)
*/ */

View file

@ -0,0 +1,112 @@
type InternalBreakpoint = {
beforeBreakpoint: InternalBreakpoint | undefined;
nextBreakpoint: InternalBreakpoint | undefined;
pixels: number;
};
function generateBreakpointsMap(): Map<string, InternalBreakpoint> {
// If is changed don't forget to also change it on SASS.
const breakpoints: { [key: string]: number } = {
xs: 0,
sm: 576,
md: 768,
lg: 992,
xl: 1200,
xxl: 1400,
};
let beforeBreakpoint: InternalBreakpoint | undefined;
let beforeBreakpointTag: string | undefined;
const mapRender = new Map<string, InternalBreakpoint>();
for (const breakpoint in breakpoints) {
const newBreakpoint = {
beforeBreakpoint: beforeBreakpoint,
nextBreakpoint: undefined,
pixels: breakpoints[breakpoint],
};
if (beforeBreakpointTag && beforeBreakpoint) {
beforeBreakpoint.nextBreakpoint = newBreakpoint;
mapRender.set(beforeBreakpointTag, beforeBreakpoint);
}
mapRender.set(breakpoint, {
beforeBreakpoint: beforeBreakpoint,
nextBreakpoint: undefined,
pixels: breakpoints[breakpoint],
});
beforeBreakpointTag = breakpoint;
beforeBreakpoint = newBreakpoint;
}
return mapRender;
}
const breakpoints = generateBreakpointsMap();
export type Breakpoint = "xs" | "sm" | "md" | "lg" | "xl" | "xxl";
export function isMediaBreakpointUp(breakpoint: Breakpoint): boolean {
if (breakpoint === "xxl") {
return true;
}
const breakpointObject = breakpoints.get(breakpoint);
if (!breakpointObject) {
throw new Error(`Unknown breakpoint: ${breakpoint}`);
}
if (!breakpointObject.nextBreakpoint) {
return false;
}
return breakpointObject.nextBreakpoint.pixels - 1 >= window.innerWidth;
}
export function isMediaBreakpointDown(breakpoint: Breakpoint): boolean {
if (breakpoint === "xs") {
return true;
}
const breakpointObject = breakpoints.get(breakpoint);
if (!breakpointObject) {
throw new Error(`Unknown breakpoint: ${breakpoint}`);
}
return breakpointObject.pixels <= window.innerWidth;
}
export function isMediaBreakpointOnly(breakpoint: Breakpoint): boolean {
const breakpointObject = breakpoints.get(breakpoint);
if (!breakpointObject) {
throw new Error(`Unknown breakpoint: ${breakpoint}`);
}
return (
breakpointObject.pixels <= window.innerWidth &&
(!breakpointObject.nextBreakpoint || breakpointObject.nextBreakpoint.pixels - 1 >= window.innerWidth)
);
}
export function isMediaBreakpointBetween(startBreakpoint: Breakpoint, endBreakpoint: Breakpoint): boolean {
const startBreakpointObject = breakpoints.get(startBreakpoint);
const endBreakpointObject = breakpoints.get(endBreakpoint);
if (!startBreakpointObject) {
throw new Error(`Unknown start breakpoint: ${startBreakpointObject}`);
}
if (!endBreakpointObject) {
throw new Error(`Unknown end breakpoint: ${endBreakpointObject}`);
}
return (
startBreakpointObject.pixels <= innerWidth &&
(!endBreakpointObject.nextBreakpoint || endBreakpointObject.nextBreakpoint.pixels - 1 >= window.innerWidth)
);
}

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,11 @@ export class HtmlUtils {
throw new Error("Cannot find HTML element with id '" + id + "'"); 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 { public static querySelectorOrFail<T extends HTMLElement>(selector: string): T {
const elem = document.querySelector<T>(selector); const elem = document.querySelector<T>(selector);
if (HtmlUtils.isHtmlElement<T>(elem)) { if (HtmlUtils.isHtmlElement<T>(elem)) {

View file

@ -7,6 +7,7 @@ interface jitsiConfigInterface {
startWithAudioMuted: boolean; startWithAudioMuted: boolean;
startWithVideoMuted: boolean; startWithVideoMuted: boolean;
prejoinPageEnabled: boolean; prejoinPageEnabled: boolean;
disableDeepLinking: boolean;
} }
interface JitsiOptions { interface JitsiOptions {
@ -40,6 +41,7 @@ const getDefaultConfig = (): jitsiConfigInterface => {
startWithAudioMuted: !get(requestedMicrophoneState), startWithAudioMuted: !get(requestedMicrophoneState),
startWithVideoMuted: !get(requestedCameraState), startWithVideoMuted: !get(requestedCameraState),
prejoinPageEnabled: false, prejoinPageEnabled: false,
disableDeepLinking: false,
}; };
}; };
@ -132,64 +134,112 @@ class JitsiFactory {
return slugify(instance.replace("/", "-") + "-" + roomName); return slugify(instance.replace("/", "-") + "-" + roomName);
} }
public start( public async start(
roomName: string, roomName: string,
playerName: string, playerName: string,
jwt?: string, jwt?: string,
config?: object, config?: object,
interfaceConfig?: object, interfaceConfig?: object,
jitsiUrl?: string, jitsiUrl?: string
jitsiWidth?: number ) {
): Promise<CoWebsite> { const coWebsite = coWebsiteManager.searchJitsi();
return coWebsiteManager.addCoWebsite(
async (cowebsiteDiv) => {
// Jitsi meet external API maintains some data in local storage
// which is sent via the appData URL parameter when joining a
// conference. Problem is that this data grows indefinitely. Thus
// after some time the URLs get so huge that loading the iframe
// becomes slow and eventually breaks completely. Thus lets just
// clear jitsi local storage before starting a new conference.
window.localStorage.removeItem("jitsiLocalStorage");
const domain = jitsiUrl || JITSI_URL; if (coWebsite) {
if (domain === undefined) { await coWebsiteManager.closeCoWebsite(coWebsite);
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map."); }
}
await this.loadJitsiScript(domain);
const options: JitsiOptions = { // Jitsi meet external API maintains some data in local storage
roomName: roomName, // which is sent via the appData URL parameter when joining a
jwt: jwt, // conference. Problem is that this data grows indefinitely. Thus
width: "100%", // after some time the URLs get so huge that loading the iframe
height: "100%", // becomes slow and eventually breaks completely. Thus lets just
parentNode: cowebsiteDiv, // clear jitsi local storage before starting a new conference.
configOverwrite: mergeConfig(config), window.localStorage.removeItem("jitsiLocalStorage");
interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig },
};
if (!options.jwt) {
delete options.jwt;
}
return new Promise((resolve, reject) => { const domain = jitsiUrl || JITSI_URL;
const doResolve = (): void => { if (domain === undefined) {
const iframe = cowebsiteDiv.querySelector<HTMLIFrameElement>('[id*="jitsi" i]'); throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
if (iframe === null) { }
throw new Error("Could not find Jitsi Iframe"); await this.loadJitsiScript(domain);
}
resolve(iframe);
};
options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations.
setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
this.jitsiApi.executeCommand("displayName", playerName);
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback); const options: JitsiOptions = {
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback); roomName: roomName,
jwt: jwt,
width: "100%",
height: "100%",
parentNode: coWebsiteManager.getCoWebsiteBuffer(),
configOverwrite: mergeConfig(config),
interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig },
};
if (!options.jwt) {
delete options.jwt;
}
const doResolve = (): void => {
const iframe = coWebsiteManager.getCoWebsiteBuffer().querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
if (iframe && this.jitsiApi) {
const coWebsite = coWebsiteManager.addCoWebsiteFromIframe(iframe, false, undefined, 0, false, true);
this.jitsiApi.addListener("videoConferenceLeft", () => {
this.closeOrUnload(coWebsite);
}); });
},
jitsiWidth, this.jitsiApi.addListener("readyToClose", () => {
0 this.closeOrUnload(coWebsite);
); });
}
coWebsiteManager.resizeAllIframes();
};
this.jitsiApi = undefined;
options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations.
setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
this.jitsiApi.executeCommand("displayName", playerName);
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
}
private closeOrUnload = function (coWebsite: CoWebsite) {
if (coWebsite.closable) {
coWebsiteManager.closeCoWebsite(coWebsite).catch(() => {
console.error("Error during closing a Jitsi Meet");
});
} else {
coWebsiteManager.unloadCoWebsite(coWebsite).catch(() => {
console.error("Error during unloading a Jitsi Meet");
});
}
};
public restart() {
if (!this.jitsiApi) {
return;
}
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
const coWebsite = coWebsiteManager.searchJitsi();
console.log("jitsi api ", this.jitsiApi);
console.log("iframe cowebsite", coWebsite?.iframe);
if (!coWebsite) {
this.destroy();
return;
}
this.jitsiApi.addListener("videoConferenceLeft", () => {
this.closeOrUnload(coWebsite);
});
this.jitsiApi.addListener("readyToClose", () => {
this.closeOrUnload(coWebsite);
});
} }
public stop() { public stop() {
@ -197,14 +247,16 @@ class JitsiFactory {
return; return;
} }
const jitsiCoWebsite = coWebsiteManager.searchJitsi();
if (jitsiCoWebsite) {
coWebsiteManager.closeJitsi().catch((e) => console.error(e));
}
this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback); this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback);
this.jitsiApi.removeListener("videoMuteStatusChanged", this.videoCallback); this.jitsiApi.removeListener("videoMuteStatusChanged", this.videoCallback);
}
public destroy() {
if (!this.jitsiApi) {
return;
}
this.stop();
this.jitsiApi?.dispose(); this.jitsiApi?.dispose();
} }

View file

@ -7,8 +7,7 @@ import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStor
export type StartScreenSharingCallback = (media: MediaStream) => void; export type StartScreenSharingCallback = (media: MediaStream) => void;
export type StopScreenSharingCallback = (media: MediaStream) => void; export type StopScreenSharingCallback = (media: MediaStream) => void;
import { cowebsiteCloseButtonId } from "./CoWebsiteManager"; import { myCameraVisibilityStore } from "../Stores/MyCameraStoreVisibility";
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
import { layoutManagerActionStore } from "../Stores/LayoutManagerStore"; import { layoutManagerActionStore } from "../Stores/LayoutManagerStore";
import { MediaStreamConstraintsError } from "../Stores/Errors/MediaStreamConstraintsError"; import { MediaStreamConstraintsError } from "../Stores/Errors/MediaStreamConstraintsError";
import { localUserStore } from "../Connexion/LocalUserStore"; import { localUserStore } from "../Connexion/LocalUserStore";
@ -20,8 +19,6 @@ export class MediaManager {
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>(); startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
stopScreenSharingCallBacks: Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>(); stopScreenSharingCallBacks: Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
private triggerCloseJistiFrame: Map<String, Function> = new Map<String, Function>();
private userInputManager?: UserInputManager; private userInputManager?: UserInputManager;
constructor() { constructor() {
@ -73,36 +70,12 @@ export class MediaManager {
}); });
} }
public showGameOverlay(): void { public showMyCamera(): void {
const gameOverlay = HtmlUtils.getElementByIdOrFail("game-overlay"); myCameraVisibilityStore.set(true);
gameOverlay.classList.add("active");
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
const functionTrigger = () => {
this.triggerCloseJitsiFrameButton();
};
buttonCloseFrame.removeEventListener("click", () => {
buttonCloseFrame.blur();
functionTrigger();
});
gameOverlayVisibilityStore.showGameOverlay();
} }
public hideGameOverlay(): void { public hideMyCamera(): void {
const gameOverlay = HtmlUtils.getElementByIdOrFail("game-overlay"); myCameraVisibilityStore.set(false);
gameOverlay.classList.remove("active");
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
const functionTrigger = () => {
this.triggerCloseJitsiFrameButton();
};
buttonCloseFrame.addEventListener("click", () => {
buttonCloseFrame.blur();
functionTrigger();
});
gameOverlayVisibilityStore.hideGameOverlay();
} }
private getScreenSharingId(userId: string): string { private getScreenSharingId(userId: string): string {
@ -179,20 +152,6 @@ export class MediaManager {
return connectingSpinnerDiv; 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) { public setUserInputManager(userInputManager: UserInputManager) {
this.userInputManager = userInputManager; this.userInputManager = userInputManager;
} }

View file

@ -3,9 +3,9 @@ import type { RoomConnection } from "../Connexion/RoomConnection";
import { MESSAGE_TYPE_CONSTRAINT, PeerStatus } from "./VideoPeer"; import { MESSAGE_TYPE_CONSTRAINT, PeerStatus } from "./VideoPeer";
import type { UserSimplePeerInterface } from "./SimplePeer"; import type { UserSimplePeerInterface } from "./SimplePeer";
import { Readable, readable } from "svelte/store"; import { Readable, readable } from "svelte/store";
import { videoFocusStore } from "../Stores/VideoFocusStore";
import { getIceServersConfig } from "../Components/Video/utils"; 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"); const Peer: SimplePeerNamespace.SimplePeer = require("simple-peer");
@ -43,7 +43,10 @@ export class ScreenSharingPeer extends Peer {
this.streamStore = readable<MediaStream | null>(null, (set) => { this.streamStore = readable<MediaStream | null>(null, (set) => {
const onStream = (stream: MediaStream | null) => { const onStream = (stream: MediaStream | null) => {
videoFocusStore.focus(this); highlightedEmbedScreen.highlight({
type: "streamable",
embed: this,
});
set(stream); set(stream);
}; };
const onData = (chunk: Buffer) => { const onData = (chunk: Buffer) => {
@ -177,7 +180,13 @@ export class ScreenSharingPeer extends Peer {
public stopPushingScreenSharingToRemoteUser(stream: MediaStream) { public stopPushingScreenSharingToRemoteUser(stream: MediaStream) {
this.removeStream(stream); this.removeStream(stream);
this.write( 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"),
})
)
); );
} }
} }

View file

@ -86,7 +86,7 @@ export class SimplePeer {
} }
); );
mediaManager.showGameOverlay(); mediaManager.showMyCamera();
//receive message start //receive message start
this.Connection.webRtcStartMessageStream.subscribe((message: UserSimplePeerInterface) => { this.Connection.webRtcStartMessageStream.subscribe((message: UserSimplePeerInterface) => {

View file

@ -9,7 +9,7 @@ import { localStreamStore, obtainedMediaConstraintStore, ObtainedMediaStreamCons
import { playersStore } from "../Stores/PlayersStore"; import { playersStore } from "../Stores/PlayersStore";
import { chatMessagesStore, newChatMessageSubject } from "../Stores/ChatStore"; import { chatMessagesStore, newChatMessageSubject } from "../Stores/ChatStore";
import { getIceServersConfig } from "../Components/Video/utils"; import { getIceServersConfig } from "../Components/Video/utils";
import { isMobile } from "../Enum/EnvironmentVariable"; import { isMediaBreakpointUp } from "../Utils/BreakpointsUtils";
const Peer: SimplePeerNamespace.SimplePeer = require("simple-peer"); const Peer: SimplePeerNamespace.SimplePeer = require("simple-peer");
@ -202,7 +202,7 @@ export class VideoPeer extends Peer {
JSON.stringify({ JSON.stringify({
type: MESSAGE_TYPE_CONSTRAINT, type: MESSAGE_TYPE_CONSTRAINT,
...constraints, ...constraints,
isMobile: isMobile(), isMobile: isMediaBreakpointUp("md"),
}) })
) )
); );

View file

@ -2,7 +2,7 @@ import "phaser";
import GameConfig = Phaser.Types.Core.GameConfig; import GameConfig = Phaser.Types.Core.GameConfig;
import "../style/index.scss"; import "../style/index.scss";
import { DEBUG_MODE, isMobile } from "./Enum/EnvironmentVariable"; import { DEBUG_MODE } from "./Enum/EnvironmentVariable";
import { LoginScene } from "./Phaser/Login/LoginScene"; import { LoginScene } from "./Phaser/Login/LoginScene";
import { ReconnectingScene } from "./Phaser/Reconnecting/ReconnectingScene"; import { ReconnectingScene } from "./Phaser/Reconnecting/ReconnectingScene";
import { SelectCharacterScene } from "./Phaser/Login/SelectCharacterScene"; import { SelectCharacterScene } from "./Phaser/Login/SelectCharacterScene";
@ -24,6 +24,7 @@ import App from "./Components/App.svelte";
import { HtmlUtils } from "./WebRtc/HtmlUtils"; import { HtmlUtils } from "./WebRtc/HtmlUtils";
import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer; import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer;
import { analyticsClient } from "./Administration/AnalyticsClient"; import { analyticsClient } from "./Administration/AnalyticsClient";
import { isMediaBreakpointUp } from "./Utils/BreakpointsUtils";
const { width, height } = coWebsiteManager.getGameSize(); const { width, height } = coWebsiteManager.getGameSize();
const valueGameQuality = localUserStore.getGameQualityValue(); const valueGameQuality = localUserStore.getGameQualityValue();
@ -90,7 +91,7 @@ const config: GameConfig = {
scene: [ scene: [
EntryScene, EntryScene,
LoginScene, LoginScene,
isMobile() ? SelectCharacterMobileScene : SelectCharacterScene, isMediaBreakpointUp("md") ? SelectCharacterMobileScene : SelectCharacterScene,
SelectCompanionScene, SelectCompanionScene,
EnableCameraScene, EnableCameraScene,
ReconnectingScene, ReconnectingScene,
@ -136,7 +137,6 @@ const config: GameConfig = {
}, },
}; };
//const game = new Phaser.Game(config);
const game = new Game(config); const game = new Game(config);
waScaleManager.setGame(game); waScaleManager.setGame(game);
@ -156,7 +156,7 @@ coWebsiteManager.onResize.subscribe(() => {
iframeListener.init(); iframeListener.init();
const app = new App({ const app = new App({
target: HtmlUtils.getElementByIdOrFail("svelte-overlay"), target: HtmlUtils.getElementByIdOrFail("game-overlay"),
props: { props: {
game: game, game: game,
}, },

View file

@ -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 { section.section-input-send-text {
--height-toolbar: 30%; --height-toolbar: 30%;

View file

@ -0,0 +1,102 @@
@use "sass:map";
// If you modify this breakpoints don't forget to change it also in TS utils.
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px
);
@function get-upper-breakpoint($breakpoint) {
@return map-get((
xs: map.get($grid-breakpoints, "sm"),
sm: map.get($grid-breakpoints, "md"),
md: map.get($grid-breakpoints, "lg"),
lg: map.get($grid-breakpoints, "xl"),
xl: map.get($grid-breakpoints, "xxl"),
xxl: null,
), $breakpoint);
}
@function get-under-breakpoint($breakpoint) {
@return map-get((
xs: null,
sm: map.get($grid-breakpoints, "xs"),
md: map.get($grid-breakpoints, "sm"),
lg: map.get($grid-breakpoints, "md"),
xl: map.get($grid-breakpoints, "lg"),
xxl: map.get($grid-breakpoints, "xl"),
), $breakpoint);
}
@mixin media-breakpoint-up($upTo) {
@if $upTo == 'xxl' {
@media only screen {
@content;
}
} @else {
$value: get-upper-breakpoint($upTo);
@if $value != null {
$value: $value - 1px;
@media only screen and (max-width: $value) {
@content;
}
}
}
}
@mixin media-breakpoint-down($downFrom) {
@if $downFrom == 'xs' {
@media only screen {
@content;
}
} @else {
$value: map.get($grid-breakpoints, $downFrom);
@if $value != null {
@media only screen and (min-width: $value) {
@content;
}
}
}
}
@mixin media-breakpoint-only($only) {
$maxValue: get-upper-breakpoint($only);
$minValue: map.get($grid-breakpoints, $only);
@if $minValue == null {
} @else if $maxValue != null {
$maxValue: $maxValue - 1px;
@media only screen and (min-width: $minValue) and (max-width: $maxValue) {
@content;
}
} @else {
@media only screen and (min-width: $minValue) {
@content;
}
}
}
@mixin media-breakpoint-between($start, $end) {
$maxValue: get-upper-breakpoint($end);
$minValue: map.get($grid-breakpoints, $start);
@if $minValue == null {
} @else if $maxValue != null {
$maxValue: $maxValue - 1px;
@media only screen and (min-width: $minValue) and (max-width: $maxValue) {
@content;
}
} @else {
@media only screen and (min-width: $minValue) {
@content;
}
}
}

View file

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

View file

@ -1,220 +1,3 @@
/* A potentially shared website could appear in an iframe in the cowebsite space. */ @import "cowebsite/global";
@import "cowebsite/short-screens";
#cowebsite { @import "cowebsite/wide-screens";
position: fixed;
z-index: 200;
transition: transform 0.5s;
background-color: whitesmoke;
display: none;
&.loading {
background-color: gray;
}
main {
iframe {
width: 100%;
height: 100%;
max-width: 100vw;
max-height: 100vh;
}
}
aside {
background: gray;
align-items: center;
display: flex;
flex-direction: column;
justify-content: space-between;
#cowebsite-aside-holder {
background: gray;
height: 20px;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
img {
width: 80%;
pointer-events: none;
}
}
#cowebsite-aside-buttons {
display: flex;
flex-direction: column;
margin-bottom: auto;
flex: 1;
justify-content: start;
}
.top-right-btn{
transform: scale(0.5);
cursor: url('./images/cursor_pointer.png'), pointer;
}
#cowebsite-sub-icons {
display: flex;
margin-top: auto;
visibility: hidden;
justify-content: end;
flex: 1;
}
}
&-container {
position: absolute;
display: none;
height: 100%;
width: 100%;
&-main {
padding: 2% 5%;
height: 50%;
}
&-sub {
position: absolute !important;
display: inline-flex;
justify-content: center;
align-items: center;
bottom: 23%;
height: 20% !important;
width: 100%;
}
}
&-slot-0 {
z-index: 70 !important;
background-color: whitesmoke;
}
@for $i from 1 through 4 {
&-slot-#{$i} {
transition: transform 0.5s;
position: relative;
height: 100%;
display: none;
background-color: #333333;
@if $i == 1 {
width: 100%;
} @else {
width: 33%;
margin: 5px;
}
.overlay {
width: 100%;
height: 100%;
z-index: 50;
position: absolute;
display: flex;
flex-direction: column;
.actions-move {
display: none;
flex-direction: row;
justify-content: center;
align-items: center;
position: absolute;
height: 100%;
width: 100%;
gap: 10%;
}
&:hover {
background-color: rgba($color: #333333, $alpha: 0.6);
.actions-move {
display: flex;
}
}
}
.actions {
pointer-events: all !important;
margin: 3% 2%;
display: flex;
flex-direction: row;
justify-content: end;
position: relative;
z-index: 50;
button {
width: 32px;
height: 32px;
margin: 8px;
display: flex;
justify-content: center;
align-items: center;
}
}
}
}
&-buffer {
iframe {
z-index: 45 !important;
pointer-events: none !important;
overflow: hidden;
border: 0;
position: absolute;
}
.main {
pointer-events: all !important;
z-index: 205 !important;
}
.sub-main {
pointer-events: all !important;
}
.thumbnail {
transform: scale(0.5, 0.5);
}
}
.pixel {
visibility: hidden;
height: 1px;
width: 1px;
}
}
@media (min-aspect-ratio: 1/1) {
#cowebsite {
right: 0;
top: 0;
width: 50%;
height: 100vh;
display: none;
&.loading {
transform: translateX(90%);
}
&.hidden {
transform: translateX(100%);
}
main {
width: 100%;
}
aside {
width: 30px;
img {
transform: rotate(90deg);
}
}
&-aside-holder {
cursor: ew-resize;
}
}
}

View file

@ -0,0 +1,127 @@
#cowebsite {
position: fixed;
z-index: 820;
transition: transform 0.5s;
background-color: rgba(10, 9, 9, 0.8);
display: none;
main {
iframe {
width: 100%;
height: 100%;
max-width: 100vw;
max-height: 100vh;
}
}
aside {
background: gray;
align-items: center;
display: flex;
flex-direction: column;
justify-content: space-between;
#cowebsite-aside-holder {
background: gray;
height: 20px;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
img {
width: 80%;
pointer-events: none;
}
}
#cowebsite-aside-buttons {
display: flex;
flex-direction: column;
margin-bottom: auto;
flex: 1;
justify-content: start;
#cowebsite-swipe {
display: none;
img {
transform: rotate(0deg) !important;
transform: scale(0.5);
}
}
}
.top-right-btn {
transform: scale(0.5);
cursor: url("./images/cursor_pointer.png"), pointer;
}
#cowebsite-other-actions {
display: flex;
margin-top: auto;
visibility: hidden;
justify-content: end;
flex: 1;
}
}
&-loader {
width: 20%;
#smoke {
@for $i from 1 through 3 {
#trail-#{$i} {
@for $y from 1 through 3 {
#trail-#{$i}-state-#{$y} {
visibility: hidden;
}
}
}
}
}
}
&-slot-main {
z-index: 70 !important;
background-color: rgba(10, 9, 9, 0);
display: flex;
justify-content: center;
align-items: center;
}
&-buffer {
iframe {
z-index: 45 !important;
pointer-events: none !important;
overflow: hidden;
border: 0;
position: absolute;
&.pixel {
height: 1px !important;
width: 1px !important;
}
}
.main {
pointer-events: all !important;
z-index: 821 !important;
}
.highlighted {
pointer-events: all !important;
padding: 4px;
}
.thumbnail {
transform: scale(0.5, 0.5);
}
}
.pixel {
visibility: hidden;
height: 1px;
width: 1px;
}
}

View file

@ -0,0 +1,84 @@
@include media-breakpoint-up(md) {
#main-container {
display: flex;
flex-direction: column-reverse;
}
#cowebsite {
left: 0;
top: 0;
width: 100%;
height: 50%;
display: flex;
flex-direction: column-reverse;
visibility: collapse;
transform: translateY(-100%);
&.loading {
visibility: visible;
transform: translateY(0%);
}
&.opened {
visibility: visible;
transform: translateY(0%);
}
&.closing {
visibility: visible;
}
&-loader {
height: 20%;
}
main {
height: 100%;
}
aside {
height: 50px;
flex-direction: row-reverse;
align-items: center;
display: flex;
justify-content: space-between;
#cowebsite-aside-holder {
height: 100%;
cursor: ns-resize;
img {
height: 100%;
}
}
#cowebsite-aside-buttons {
flex-direction: row-reverse;
margin-left: auto;
margin-bottom: 0;
justify-content: end;
}
#cowebsite-fullscreen {
padding-top: 0;
}
#cowebsite-other-actions {
display: inline-flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 0;
height: 100%;
visibility: visible;
}
.top-right-btn {
img {
width: 15px;
}
}
}
}
}

View file

@ -0,0 +1,41 @@
@include media-breakpoint-down(lg) {
#cowebsite {
right: 0;
top: 0;
width: 50%;
height: 100vh;
display: flex;
visibility: collapse;
transform: translateX(100%);
&.loading {
visibility: visible;
transform: translateX(0%);
}
&.opened {
visibility: visible;
transform: translateX(0%);
}
&.closing {
visibility: visible;
}
main {
width: 100%;
}
aside {
width: 30px;
img {
transform: rotate(90deg);
}
}
&-aside-holder {
cursor: ew-resize;
}
}
}

View file

@ -1,10 +1,5 @@
@import "~@fontsource/press-start-2p/index.css"; @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; font-family: PixelFont-7,monospace;
} }

Binary file not shown.

View file

@ -1,6 +1,6 @@
@charset 'UTF-8';
@import "breakpoints";
@import "cowebsite.scss"; @import "cowebsite.scss";
@import "cowebsite-mobile.scss";
@import "style";
@import "mobile-style.scss";
@import "fonts.scss"; @import "fonts.scss";
@import "style";
@import "TextGlobalMessageSvelte-Style"; @import "TextGlobalMessageSvelte-Style";

View file

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

View file

@ -36,15 +36,22 @@ body .message-info.warning{
} }
.video-container { .video-container {
position: relative; display: flex;
transition: all 0.2s ease; transition: all 0.2s ease;
background-color: #00000099;
cursor: url('./images/cursor_pointer.png'), pointer; cursor: url('./images/cursor_pointer.png'), pointer;
width: 100%;
&.no-clikable {
video {
cursor: url('./images/cursor_normal.png'), pointer;
}
}
video { video {
height: fit-content;
max-height: 100%;
max-width: 100%;
width: 100%; width: 100%;
height: 100%;
object-fit: cover;
cursor: url('./images/cursor_pointer.png'), pointer; cursor: url('./images/cursor_pointer.png'), pointer;
&.mobile{ &.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{ .sound-progress{
display: none; display: none;
position: absolute; position: absolute;
@ -211,94 +189,6 @@ video.myCamVideo{
top: calc(50% - 20px); 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 */ /* Spinner */
.connecting-spinner { .connecting-spinner {
/*display: inline-block;*/ /*display: inline-block;*/
@ -369,26 +259,6 @@ body {
position: absolute; 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 { #game {
position: relative; /* Position relative is needed for the game-overlay. */ position: relative; /* Position relative is needed for the game-overlay. */
@ -486,96 +356,6 @@ input[type=range]:focus::-ms-fill-upper {
background: #FFFFFF; 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 { .chat-mode > div {
margin: 1%; margin: 1%;
max-height: 96%; max-height: 96%;
@ -1061,13 +841,22 @@ div.action.danger p.action-body{
} }
#svelte-overlay { #game-overlay {
position: absolute; position: absolute;
width: 100%; width: 100%;
height: 100%; height: 100%;
pointer-events: none; pointer-events: none;
user-select: none; user-select: none;
& + div {
pointer-events: none;
z-index: 2;
}
& + div > div {
pointer-events: auto;
}
& > div { & > div {
position: relative; position: relative;
width: 100%; width: 100%;
@ -1085,22 +874,10 @@ div.action.danger p.action-body{
pointer-events: auto; pointer-events: auto;
} }
} }
}
div.is-silent { &.hide {
position: absolute; visibility: hidden;
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;
} }
div.emoji-picker { div.emoji-picker {
@ -1121,8 +898,3 @@ div.emoji-picker {
user-select: none; /* Non-prefixed version, currently user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */ supported by Chrome, Edge, Opera and Firefox */
} }
.pixel {
height: 1px !important;
width: 1px !important;
}

View file

@ -2,6 +2,7 @@ import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
import fs from 'fs/promises'; import fs from 'fs/promises';
import HtmlWebpackPlugin from "html-webpack-plugin"; import HtmlWebpackPlugin from "html-webpack-plugin";
import MiniCssExtractPlugin from "mini-css-extract-plugin"; import MiniCssExtractPlugin from "mini-css-extract-plugin";
import CssMinimizerPlugin from "css-minimizer-webpack-plugin";
import NodePolyfillPlugin from "node-polyfill-webpack-plugin"; import NodePolyfillPlugin from "node-polyfill-webpack-plugin";
import path from "path"; import path from "path";
import sveltePreprocess from "svelte-preprocess"; import sveltePreprocess from "svelte-preprocess";
@ -79,33 +80,9 @@ module.exports = {
}, },
}, },
{ {
test: /\.scss$/, test: /\.(sc|c)ss$/,
exclude: /node_modules/, exclude: /node_modules/,
use: [ use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
//url: false,
sourceMap: true,
},
},
"sass-loader",
],
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
//url: false,
sourceMap: true,
},
},
],
}, },
{ {
test: /\.(html|svelte)$/, test: /\.(html|svelte)$/,
@ -185,6 +162,10 @@ module.exports = {
extensions: [".tsx", ".ts", ".js", ".svelte"], extensions: [".tsx", ".ts", ".js", ".svelte"],
mainFields: ["svelte", "browser", "module", "main"], mainFields: ["svelte", "browser", "module", "main"],
}, },
optimization: {
minimize: isProduction,
minimizer: [new CssMinimizerPlugin(), "..."],
},
output: { output: {
filename: (pathData) => { filename: (pathData) => {
// Add a content hash only for the main bundle. // Add a content hash only for the main bundle.

View file

@ -208,6 +208,11 @@
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853"
integrity sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA== integrity sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA==
"@trysound/sax@0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
"@tsconfig/node10@^1.0.7": "@tsconfig/node10@^1.0.7":
version "1.0.8" version "1.0.8"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
@ -774,11 +779,25 @@ ajv-errors@^1.0.0:
resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d"
integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==
ajv-formats@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==
dependencies:
ajv "^8.0.0"
ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
version "3.5.2" version "3.5.2"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
ajv-keywords@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16"
integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==
dependencies:
fast-deep-equal "^3.1.3"
ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5:
version "6.12.6" version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
@ -789,6 +808,21 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5:
json-schema-traverse "^0.4.1" json-schema-traverse "^0.4.1"
uri-js "^4.2.2" uri-js "^4.2.2"
ajv@^8.0.0, ajv@^8.8.0:
version "8.8.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb"
integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==
dependencies:
fast-deep-equal "^3.1.1"
json-schema-traverse "^1.0.0"
require-from-string "^2.0.2"
uri-js "^4.2.2"
alphanum-sort@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
ansi-colors@^3.0.0: ansi-colors@^3.0.0:
version "3.2.4" version "3.2.4"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
@ -1212,6 +1246,17 @@ browserify-zlib@^0.2.0:
dependencies: dependencies:
pako "~1.0.5" pako "~1.0.5"
browserslist@^4.0.0, browserslist@^4.16.0, browserslist@^4.16.6:
version "4.19.1"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3"
integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==
dependencies:
caniuse-lite "^1.0.30001286"
electron-to-chromium "^1.4.17"
escalade "^3.1.1"
node-releases "^2.0.1"
picocolors "^1.0.0"
browserslist@^4.14.5: browserslist@^4.14.5:
version "4.16.6" version "4.16.6"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2"
@ -1307,6 +1352,21 @@ camelcase@^6.2.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
caniuse-api@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==
dependencies:
browserslist "^4.0.0"
caniuse-lite "^1.0.0"
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001286:
version "1.0.30001292"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001292.tgz#4a55f61c06abc9595965cfd77897dc7bc1cdc456"
integrity sha512-jnT4Tq0Q4ma+6nncYQVe7d73kmDmE9C3OGTx3MvW7lBM/eY1S1DZTMBON7dqV481RhNiS5OxD7k9JQvmDOTirw==
caniuse-lite@^1.0.30001219: caniuse-lite@^1.0.30001219:
version "1.0.30001228" version "1.0.30001228"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa"
@ -1483,6 +1543,11 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
colord@^2.9.1:
version "2.9.2"
resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1"
integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==
colorette@^1.2.1, colorette@^1.2.2: colorette@^1.2.1, colorette@^1.2.2:
version "1.2.2" version "1.2.2"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
@ -1692,6 +1757,13 @@ crypto-browserify@^3.12.0:
randombytes "^2.0.0" randombytes "^2.0.0"
randomfill "^1.0.3" randomfill "^1.0.3"
css-declaration-sorter@^6.0.3:
version "6.1.3"
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz#e9852e4cf940ba79f509d9425b137d1f94438dc2"
integrity sha512-SvjQjNRZgh4ULK1LDJ2AduPKUKxIqmtU7ZAyi47BTV+M90Qvxr9AB6lKlLbDUfXqI9IQeYA8LbAsCZPpJEV3aA==
dependencies:
timsort "^0.3.0"
css-loader@^5.2.4: css-loader@^5.2.4:
version "5.2.4" version "5.2.4"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.4.tgz#e985dcbce339812cb6104ef3670f08f9893a1536" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.4.tgz#e985dcbce339812cb6104ef3670f08f9893a1536"
@ -1709,6 +1781,18 @@ css-loader@^5.2.4:
schema-utils "^3.0.0" schema-utils "^3.0.0"
semver "^7.3.5" semver "^7.3.5"
css-minimizer-webpack-plugin@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.3.1.tgz#5afc4507a4ec13dd223f043cda8953ee0bf6ecfa"
integrity sha512-SHA7Hu/EiF0dOwdmV2+agvqYpG+ljlUa7Dvn1AVOmSH3N8KOERoaM9lGpstz9nGsoTjANGyUXdrxl/EwdMScRg==
dependencies:
cssnano "^5.0.6"
jest-worker "^27.0.2"
postcss "^8.3.5"
schema-utils "^4.0.0"
serialize-javascript "^6.0.0"
source-map "^0.6.1"
css-select@^2.0.2: css-select@^2.0.2:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef"
@ -1719,16 +1803,96 @@ css-select@^2.0.2:
domutils "^1.7.0" domutils "^1.7.0"
nth-check "^1.0.2" nth-check "^1.0.2"
css-select@^4.1.3:
version "4.2.1"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd"
integrity sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==
dependencies:
boolbase "^1.0.0"
css-what "^5.1.0"
domhandler "^4.3.0"
domutils "^2.8.0"
nth-check "^2.0.1"
css-tree@^1.1.2, css-tree@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
dependencies:
mdn-data "2.0.14"
source-map "^0.6.1"
css-what@^3.2.1: css-what@^3.2.1:
version "3.4.2" version "3.4.2"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4"
integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==
css-what@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe"
integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==
cssesc@^3.0.0: cssesc@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
cssnano-preset-default@^5.1.9:
version "5.1.9"
resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.9.tgz#79628ac48eccbdad570f70b4018cc38d43d1b7df"
integrity sha512-RhkEucqlQ+OxEi14K1p8gdXcMQy1mSpo7P1oC44oRls7BYIj8p+cht4IFBFV3W4iOjTP8EUB33XV1fX9KhDzyA==
dependencies:
css-declaration-sorter "^6.0.3"
cssnano-utils "^2.0.1"
postcss-calc "^8.0.0"
postcss-colormin "^5.2.2"
postcss-convert-values "^5.0.2"
postcss-discard-comments "^5.0.1"
postcss-discard-duplicates "^5.0.1"
postcss-discard-empty "^5.0.1"
postcss-discard-overridden "^5.0.1"
postcss-merge-longhand "^5.0.4"
postcss-merge-rules "^5.0.3"
postcss-minify-font-values "^5.0.1"
postcss-minify-gradients "^5.0.3"
postcss-minify-params "^5.0.2"
postcss-minify-selectors "^5.1.0"
postcss-normalize-charset "^5.0.1"
postcss-normalize-display-values "^5.0.1"
postcss-normalize-positions "^5.0.1"
postcss-normalize-repeat-style "^5.0.1"
postcss-normalize-string "^5.0.1"
postcss-normalize-timing-functions "^5.0.1"
postcss-normalize-unicode "^5.0.1"
postcss-normalize-url "^5.0.4"
postcss-normalize-whitespace "^5.0.1"
postcss-ordered-values "^5.0.2"
postcss-reduce-initial "^5.0.2"
postcss-reduce-transforms "^5.0.1"
postcss-svgo "^5.0.3"
postcss-unique-selectors "^5.0.2"
cssnano-utils@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-2.0.1.tgz#8660aa2b37ed869d2e2f22918196a9a8b6498ce2"
integrity sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ==
cssnano@^5.0.6:
version "5.0.14"
resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.14.tgz#99bc550f663b48c38e9b8e0ae795697c9de84b47"
integrity sha512-qzhRkFvBhv08tbyKCIfWbxBXmkIpLl1uNblt8SpTHkgLfON5OCPX/CCnkdNmEosvo8bANQYmTTMEgcVBlisHaw==
dependencies:
cssnano-preset-default "^5.1.9"
lilconfig "^2.0.3"
yaml "^1.10.2"
csso@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
dependencies:
css-tree "^1.1.2"
dataloader@^1.4.0: dataloader@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.4.0.tgz#bca11d867f5d3f1b9ed9f737bd15970c65dff5c8" resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.4.0.tgz#bca11d867f5d3f1b9ed9f737bd15970c65dff5c8"
@ -1952,6 +2116,15 @@ dom-serializer@0:
domelementtype "^2.0.1" domelementtype "^2.0.1"
entities "^2.0.0" entities "^2.0.0"
dom-serializer@^1.0.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91"
integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==
dependencies:
domelementtype "^2.0.1"
domhandler "^4.2.0"
entities "^2.0.0"
domain-browser@^4.19.0: domain-browser@^4.19.0:
version "4.19.0" version "4.19.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1"
@ -1962,7 +2135,7 @@ domelementtype@1, domelementtype@^1.3.1:
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
domelementtype@^2.0.1: domelementtype@^2.0.1, domelementtype@^2.2.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
@ -1974,6 +2147,13 @@ domhandler@^2.3.0:
dependencies: dependencies:
domelementtype "1" domelementtype "1"
domhandler@^4.2.0, domhandler@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626"
integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==
dependencies:
domelementtype "^2.2.0"
domutils@^1.5.1, domutils@^1.7.0: domutils@^1.5.1, domutils@^1.7.0:
version "1.7.0" version "1.7.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
@ -1982,6 +2162,15 @@ domutils@^1.5.1, domutils@^1.7.0:
dom-serializer "0" dom-serializer "0"
domelementtype "1" domelementtype "1"
domutils@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
dependencies:
dom-serializer "^1.0.1"
domelementtype "^2.2.0"
domhandler "^4.2.0"
dot-case@^3.0.4: dot-case@^3.0.4:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
@ -2007,6 +2196,11 @@ electron-to-chromium@^1.3.723:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.728.tgz#dbedd6373f595ae10a13d146b66bece4c1afa5bd" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.728.tgz#dbedd6373f595ae10a13d146b66bece4c1afa5bd"
integrity sha512-SHv4ziXruBpb1Nz4aTuqEHBYi/9GNCJMYIJgDEXrp/2V01nFXMNFUTli5Z85f5ivSkioLilQatqBYFB44wNJrA== integrity sha512-SHv4ziXruBpb1Nz4aTuqEHBYi/9GNCJMYIJgDEXrp/2V01nFXMNFUTli5Z85f5ivSkioLilQatqBYFB44wNJrA==
electron-to-chromium@^1.4.17:
version "1.4.28"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.28.tgz#fef0e92e281df6d568f482d8d53c34ca5374de48"
integrity sha512-Gzbf0wUtKfyPaqf0Plz+Ctinf9eQIzxEqBHwSvbGfeOm9GMNdLxyu1dNiCUfM+x6r4BE0xUJNh3Nmg9gfAtTmg==
elliptic@^6.5.3: elliptic@^6.5.3:
version "6.5.4" version "6.5.4"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
@ -3541,6 +3735,15 @@ jest-worker@^26.6.2:
merge-stream "^2.0.0" merge-stream "^2.0.0"
supports-color "^7.0.0" supports-color "^7.0.0"
jest-worker@^27.0.2:
version "27.4.5"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.5.tgz#d696e3e46ae0f24cff3fa7195ffba22889262242"
integrity sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
supports-color "^8.0.0"
js-tokens@^4.0.0: js-tokens@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -3568,6 +3771,11 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema-traverse@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
json-stable-stringify-without-jsonify@^1.0.1: json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
@ -3659,6 +3867,11 @@ levn@^0.4.1:
prelude-ls "^1.2.1" prelude-ls "^1.2.1"
type-check "~0.4.0" type-check "~0.4.0"
lilconfig@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082"
integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==
lines-and-columns@^1.1.6: lines-and-columns@^1.1.6:
version "1.1.6" version "1.1.6"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
@ -3747,11 +3960,21 @@ lodash.isequal@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
lodash.merge@^4.6.2: lodash.merge@^4.6.2:
version "4.6.2" version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20: lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20:
version "4.17.21" version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
@ -3830,6 +4053,11 @@ md5.js@^1.3.4:
inherits "^2.0.1" inherits "^2.0.1"
safe-buffer "^5.1.2" safe-buffer "^5.1.2"
mdn-data@2.0.14:
version "2.0.14"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
media-typer@0.3.0: media-typer@0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -4036,6 +4264,11 @@ nanoid@^3.1.23:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c"
integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==
nanoid@^3.1.30:
version "3.1.30"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362"
integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==
nanomatch@^1.2.9: nanomatch@^1.2.9:
version "1.2.13" version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@ -4121,6 +4354,11 @@ node-releases@^1.1.71:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe"
integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==
node-releases@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==
normalize-package-data@^2.3.2: normalize-package-data@^2.3.2:
version "2.5.0" version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@ -4143,6 +4381,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
normalize-url@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
npm-run-all@^4.1.5: npm-run-all@^4.1.5:
version "4.1.5" version "4.1.5"
resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba"
@ -4179,6 +4422,13 @@ nth-check@^1.0.2:
dependencies: dependencies:
boolbase "~1.0.0" boolbase "~1.0.0"
nth-check@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2"
integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==
dependencies:
boolbase "^1.0.0"
object-assign@^4.0.1: object-assign@^4.0.1:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@ -4549,6 +4799,11 @@ phaser@^3.54.0:
eventemitter3 "^4.0.7" eventemitter3 "^4.0.7"
path "^0.12.7" path "^0.12.7"
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
version "2.2.3" version "2.2.3"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d"
@ -4621,6 +4876,103 @@ posix-character-classes@^0.1.0:
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
postcss-calc@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.0.0.tgz#a05b87aacd132740a5db09462a3612453e5df90a"
integrity sha512-5NglwDrcbiy8XXfPM11F3HeC6hoT9W7GUH/Zi5U/p7u3Irv4rHhdDcIZwG0llHXV4ftsBjpfWMXAnXNl4lnt8g==
dependencies:
postcss-selector-parser "^6.0.2"
postcss-value-parser "^4.0.2"
postcss-colormin@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.2.tgz#019cd6912bef9e7e0924462c5e4ffae241e2f437"
integrity sha512-tSEe3NpqWARUTidDlF0LntPkdlhXqfDFuA1yslqpvvGAfpZ7oBaw+/QXd935NKm2U9p4PED0HDZlzmMk7fVC6g==
dependencies:
browserslist "^4.16.6"
caniuse-api "^3.0.0"
colord "^2.9.1"
postcss-value-parser "^4.2.0"
postcss-convert-values@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz#879b849dc3677c7d6bc94b6a2c1a3f0808798059"
integrity sha512-KQ04E2yadmfa1LqXm7UIDwW1ftxU/QWZmz6NKnHnUvJ3LEYbbcX6i329f/ig+WnEByHegulocXrECaZGLpL8Zg==
dependencies:
postcss-value-parser "^4.1.0"
postcss-discard-comments@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz#9eae4b747cf760d31f2447c27f0619d5718901fe"
integrity sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg==
postcss-discard-duplicates@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz#68f7cc6458fe6bab2e46c9f55ae52869f680e66d"
integrity sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA==
postcss-discard-empty@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz#ee136c39e27d5d2ed4da0ee5ed02bc8a9f8bf6d8"
integrity sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw==
postcss-discard-overridden@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz#454b41f707300b98109a75005ca4ab0ff2743ac6"
integrity sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q==
postcss-merge-longhand@^5.0.4:
version "5.0.4"
resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz#41f4f3270282ea1a145ece078b7679f0cef21c32"
integrity sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw==
dependencies:
postcss-value-parser "^4.1.0"
stylehacks "^5.0.1"
postcss-merge-rules@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.3.tgz#b5cae31f53129812a77e3eb1eeee448f8cf1a1db"
integrity sha512-cEKTMEbWazVa5NXd8deLdCnXl+6cYG7m2am+1HzqH0EnTdy8fRysatkaXb2dEnR+fdaDxTvuZ5zoBdv6efF6hg==
dependencies:
browserslist "^4.16.6"
caniuse-api "^3.0.0"
cssnano-utils "^2.0.1"
postcss-selector-parser "^6.0.5"
postcss-minify-font-values@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz#a90cefbfdaa075bd3dbaa1b33588bb4dc268addf"
integrity sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA==
dependencies:
postcss-value-parser "^4.1.0"
postcss-minify-gradients@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.3.tgz#f970a11cc71e08e9095e78ec3a6b34b91c19550e"
integrity sha512-Z91Ol22nB6XJW+5oe31+YxRsYooxOdFKcbOqY/V8Fxse1Y3vqlNRpi1cxCqoACZTQEhl+xvt4hsbWiV5R+XI9Q==
dependencies:
colord "^2.9.1"
cssnano-utils "^2.0.1"
postcss-value-parser "^4.1.0"
postcss-minify-params@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.2.tgz#1b644da903473fbbb18fbe07b8e239883684b85c"
integrity sha512-qJAPuBzxO1yhLad7h2Dzk/F7n1vPyfHfCCh5grjGfjhi1ttCnq4ZXGIW77GSrEbh9Hus9Lc/e/+tB4vh3/GpDg==
dependencies:
alphanum-sort "^1.0.2"
browserslist "^4.16.6"
cssnano-utils "^2.0.1"
postcss-value-parser "^4.1.0"
postcss-minify-selectors@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz#4385c845d3979ff160291774523ffa54eafd5a54"
integrity sha512-NzGBXDa7aPsAcijXZeagnJBKBPMYLaJJzB8CQh6ncvyl2sIndLVWfbcDi0SBjRWk5VqEjXvf8tYwzoKf4Z07og==
dependencies:
alphanum-sort "^1.0.2"
postcss-selector-parser "^6.0.5"
postcss-modules-extract-imports@^3.0.0: postcss-modules-extract-imports@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
@ -4649,6 +5001,96 @@ postcss-modules-values@^4.0.0:
dependencies: dependencies:
icss-utils "^5.0.0" icss-utils "^5.0.0"
postcss-normalize-charset@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz#121559d1bebc55ac8d24af37f67bd4da9efd91d0"
integrity sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg==
postcss-normalize-display-values@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz#62650b965981a955dffee83363453db82f6ad1fd"
integrity sha512-uupdvWk88kLDXi5HEyI9IaAJTE3/Djbcrqq8YgjvAVuzgVuqIk3SuJWUisT2gaJbZm1H9g5k2w1xXilM3x8DjQ==
dependencies:
cssnano-utils "^2.0.1"
postcss-value-parser "^4.1.0"
postcss-normalize-positions@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz#868f6af1795fdfa86fbbe960dceb47e5f9492fe5"
integrity sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg==
dependencies:
postcss-value-parser "^4.1.0"
postcss-normalize-repeat-style@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz#cbc0de1383b57f5bb61ddd6a84653b5e8665b2b5"
integrity sha512-syZ2itq0HTQjj4QtXZOeefomckiV5TaUO6ReIEabCh3wgDs4Mr01pkif0MeVwKyU/LHEkPJnpwFKRxqWA/7O3w==
dependencies:
cssnano-utils "^2.0.1"
postcss-value-parser "^4.1.0"
postcss-normalize-string@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz#d9eafaa4df78c7a3b973ae346ef0e47c554985b0"
integrity sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA==
dependencies:
postcss-value-parser "^4.1.0"
postcss-normalize-timing-functions@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz#8ee41103b9130429c6cbba736932b75c5e2cb08c"
integrity sha512-cPcBdVN5OsWCNEo5hiXfLUnXfTGtSFiBU9SK8k7ii8UD7OLuznzgNRYkLZow11BkQiiqMcgPyh4ZqXEEUrtQ1Q==
dependencies:
cssnano-utils "^2.0.1"
postcss-value-parser "^4.1.0"
postcss-normalize-unicode@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz#82d672d648a411814aa5bf3ae565379ccd9f5e37"
integrity sha512-kAtYD6V3pK0beqrU90gpCQB7g6AOfP/2KIPCVBKJM2EheVsBQmx/Iof+9zR9NFKLAx4Pr9mDhogB27pmn354nA==
dependencies:
browserslist "^4.16.0"
postcss-value-parser "^4.1.0"
postcss-normalize-url@^5.0.4:
version "5.0.4"
resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.4.tgz#3b0322c425e31dd275174d0d5db0e466f50810fb"
integrity sha512-cNj3RzK2pgQQyNp7dzq0dqpUpQ/wYtdDZM3DepPmFjCmYIfceuD9VIAcOdvrNetjIU65g1B4uwdP/Krf6AFdXg==
dependencies:
normalize-url "^6.0.1"
postcss-value-parser "^4.2.0"
postcss-normalize-whitespace@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz#b0b40b5bcac83585ff07ead2daf2dcfbeeef8e9a"
integrity sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA==
dependencies:
postcss-value-parser "^4.1.0"
postcss-ordered-values@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz#1f351426977be00e0f765b3164ad753dac8ed044"
integrity sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ==
dependencies:
cssnano-utils "^2.0.1"
postcss-value-parser "^4.1.0"
postcss-reduce-initial@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz#fa424ce8aa88a89bc0b6d0f94871b24abe94c048"
integrity sha512-v/kbAAQ+S1V5v9TJvbGkV98V2ERPdU6XvMcKMjqAlYiJ2NtsHGlKYLPjWWcXlaTKNxooId7BGxeraK8qXvzKtw==
dependencies:
browserslist "^4.16.6"
caniuse-api "^3.0.0"
postcss-reduce-transforms@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz#93c12f6a159474aa711d5269923e2383cedcf640"
integrity sha512-a//FjoPeFkRuAguPscTVmRQUODP+f3ke2HqFNgGPwdYnpeC29RZdCBvGRGTsKpMURb/I3p6jdKoBQ2zI+9Q7kA==
dependencies:
cssnano-utils "^2.0.1"
postcss-value-parser "^4.1.0"
postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
version "6.0.6" version "6.0.6"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea"
@ -4657,6 +5099,35 @@ postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
cssesc "^3.0.0" cssesc "^3.0.0"
util-deprecate "^1.0.2" util-deprecate "^1.0.2"
postcss-selector-parser@^6.0.5:
version "6.0.8"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz#f023ed7a9ea736cd7ef70342996e8e78645a7914"
integrity sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==
dependencies:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
postcss-svgo@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.3.tgz#d945185756e5dfaae07f9edb0d3cae7ff79f9b30"
integrity sha512-41XZUA1wNDAZrQ3XgWREL/M2zSw8LJPvb5ZWivljBsUQAGoEKMYm6okHsTjJxKYI4M75RQEH4KYlEM52VwdXVA==
dependencies:
postcss-value-parser "^4.1.0"
svgo "^2.7.0"
postcss-unique-selectors@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz#5d6893daf534ae52626708e0d62250890108c0c1"
integrity sha512-w3zBVlrtZm7loQWRPVC0yjUwwpty7OM6DnEHkxcSQXO1bMS3RJ+JUS5LFMSDZHJcvGsRwhZinCWVqn8Kej4EDA==
dependencies:
alphanum-sort "^1.0.2"
postcss-selector-parser "^6.0.5"
postcss-value-parser@^4.0.2, postcss-value-parser@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss-value-parser@^4.1.0: postcss-value-parser@^4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
@ -4671,6 +5142,15 @@ postcss@^8.2.10:
nanoid "^3.1.23" nanoid "^3.1.23"
source-map "^0.6.1" source-map "^0.6.1"
postcss@^8.3.5:
version "8.4.5"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95"
integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==
dependencies:
nanoid "^3.1.30"
picocolors "^1.0.0"
source-map-js "^1.0.1"
posthog-js@^1.14.1: posthog-js@^1.14.1:
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.14.1.tgz#68553b9074c686784b994b3f433ad035b241deaa" resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.14.1.tgz#68553b9074c686784b994b3f433ad035b241deaa"
@ -4998,6 +5478,11 @@ require-directory@^2.1.1:
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
require-from-string@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
require-main-filename@^2.0.0: require-main-filename@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
@ -5190,6 +5675,16 @@ schema-utils@^3.0.0:
ajv "^6.12.5" ajv "^6.12.5"
ajv-keywords "^3.5.2" ajv-keywords "^3.5.2"
schema-utils@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7"
integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==
dependencies:
"@types/json-schema" "^7.0.9"
ajv "^8.8.0"
ajv-formats "^2.1.1"
ajv-keywords "^5.0.0"
select-hose@^2.0.0: select-hose@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@ -5250,6 +5745,13 @@ serialize-javascript@^5.0.1:
dependencies: dependencies:
randombytes "^2.1.0" randombytes "^2.1.0"
serialize-javascript@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
dependencies:
randombytes "^2.1.0"
serve-index@^1.9.1: serve-index@^1.9.1:
version "1.9.1" version "1.9.1"
resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
@ -5470,6 +5972,11 @@ source-list-map@^2.0.0, source-list-map@^2.0.1:
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
source-map-js@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf"
integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==
source-map-resolve@^0.5.0: source-map-resolve@^0.5.0:
version "0.5.3" version "0.5.3"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
@ -5565,6 +6072,11 @@ split-string@^3.0.1, split-string@^3.0.2:
dependencies: dependencies:
extend-shallow "^3.0.0" extend-shallow "^3.0.0"
stable@^0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
standardized-audio-context@^25.2.4: standardized-audio-context@^25.2.4:
version "25.2.4" version "25.2.4"
resolved "https://registry.yarnpkg.com/standardized-audio-context/-/standardized-audio-context-25.2.4.tgz#d64dbdd70615171ec90d1b7151a0d945af94cf3d" resolved "https://registry.yarnpkg.com/standardized-audio-context/-/standardized-audio-context-25.2.4.tgz#d64dbdd70615171ec90d1b7151a0d945af94cf3d"
@ -5731,6 +6243,14 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
stylehacks@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb"
integrity sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA==
dependencies:
browserslist "^4.16.0"
postcss-selector-parser "^6.0.4"
supports-color@^5.3.0: supports-color@^5.3.0:
version "5.5.0" version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@ -5752,6 +6272,13 @@ supports-color@^7.0.0, supports-color@^7.1.0:
dependencies: dependencies:
has-flag "^4.0.0" has-flag "^4.0.0"
supports-color@^8.0.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
svelte-check@^2.1.0: svelte-check@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/svelte-check/-/svelte-check-2.1.0.tgz#3ee8ad86068256346ebca862bbee8417a757fc53" resolved "https://registry.yarnpkg.com/svelte-check/-/svelte-check-2.1.0.tgz#3ee8ad86068256346ebca862bbee8417a757fc53"
@ -5801,6 +6328,19 @@ svelte@^3.38.2:
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.38.2.tgz#55e5c681f793ae349b5cc2fe58e5782af4275ef5" resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.38.2.tgz#55e5c681f793ae349b5cc2fe58e5782af4275ef5"
integrity sha512-q5Dq0/QHh4BLJyEVWGe7Cej5NWs040LWjMbicBGZ+3qpFWJ1YObRmUDZKbbovddLC9WW7THTj3kYbTOFmU9fbg== integrity sha512-q5Dq0/QHh4BLJyEVWGe7Cej5NWs040LWjMbicBGZ+3qpFWJ1YObRmUDZKbbovddLC9WW7THTj3kYbTOFmU9fbg==
svgo@^2.7.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
dependencies:
"@trysound/sax" "0.2.0"
commander "^7.2.0"
css-select "^4.1.3"
css-tree "^1.1.3"
csso "^4.2.0"
picocolors "^1.0.0"
stable "^0.1.8"
tabbable@^4.0.0: tabbable@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261" resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261"
@ -5868,6 +6408,11 @@ timers-browserify@^2.0.12:
dependencies: dependencies:
setimmediate "^1.0.4" setimmediate "^1.0.4"
timsort@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
tiny-emitter@^2.1.0: tiny-emitter@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
@ -6496,7 +7041,7 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@^1.10.0, yaml@^1.7.2: yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2:
version "1.10.2" version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==

View file

@ -0,0 +1,194 @@
{ "compressionlevel":-1,
"height":10,
"infinite":false,
"layers":[
{
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
"height":10,
"id":1,
"name":"floor",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":10,
"x":0,
"y":0
},
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":10,
"id":2,
"name":"start",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":10,
"x":0,
"y":0
},
{
"data":[0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34],
"height":10,
"id":8,
"name":"firstCoWebsite",
"opacity":1,
"properties":[
{
"name":"openWebsite",
"type":"string",
"value":"https:\/\/workadventu.re"
},
{
"name":"openWebsiteClosable",
"type":"bool",
"value":true
},
{
"name":"openWebsiteTrigger",
"type":"string",
"value":"onaction"
}],
"type":"tilelayer",
"visible":true,
"width":10,
"x":0,
"y":0
},
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23],
"height":10,
"id":11,
"name":"secondCoWebsite",
"opacity":1,
"properties":[
{
"name":"openWebsite",
"type":"string",
"value":"https:\/\/wikipedia.org"
},
{
"name":"openWebsiteClosable",
"type":"bool",
"value":true
},
{
"name":"openWebsiteTrigger",
"type":"string",
"value":"onaction"
}],
"type":"tilelayer",
"visible":true,
"width":10,
"x":0,
"y":0
},
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12],
"height":10,
"id":10,
"name":"terCoWebsite",
"opacity":1,
"properties":[
{
"name":"openWebsite",
"type":"string",
"value":"https:\/\/www.typescriptlang.org\/"
},
{
"name":"openWebsiteClosable",
"type":"bool",
"value":true
},
{
"name":"openWebsiteTrigger",
"type":"string",
"value":"onaction"
}],
"type":"tilelayer",
"visible":true,
"width":10,
"x":0,
"y":0
},
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 111, 111, 111, 111, 0, 0, 0, 0, 0, 111, 111, 111, 111, 111, 0, 0, 0, 0, 0, 111, 111, 111, 111, 111, 0, 0, 0, 0, 0, 111, 111, 111, 111, 111],
"height":10,
"id":12,
"name":"quatCoWebsite",
"opacity":1,
"properties":[
{
"name":"openWebsite",
"type":"string",
"value":"https:\/\/svelte.dev\/"
},
{
"name":"openWebsiteClosable",
"type":"bool",
"value":true
},
{
"name":"openWebsiteTrigger",
"type":"string",
"value":"onaction"
}],
"type":"tilelayer",
"visible":true,
"width":10,
"x":0,
"y":0
},
{
"draworder":"topdown",
"id":3,
"name":"floorLayer",
"objects":[
{
"height":141,
"id":1,
"name":"Tests",
"rotation":0,
"text":
{
"fontfamily":"Sans Serif",
"pixelsize":11,
"text":"Test:\nWalk on the blue carpet, an iframe open, walk on the white carpet another one to open another one\nResult:\n2 co-websites must be opened\n\nTest:\nGo outside of carpets\nResult:\nAll co-websites must disapeared",
"wrap":true
},
"type":"",
"visible":true,
"width":316.770833333333,
"x":0.28125,
"y":187.833333333333
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"x":0,
"y":0
}],
"nextlayerid":13,
"nextobjectid":3,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.7.2",
"tileheight":32,
"tilesets":[
{
"columns":11,
"firstgid":1,
"image":"tileset1.png",
"imageheight":352,
"imagewidth":352,
"margin":0,
"name":"tileset1",
"spacing":0,
"tilecount":121,
"tileheight":32,
"tilewidth":32
}],
"tilewidth":32,
"type":"map",
"version":"1.6",
"width":10
}

View file

@ -326,6 +326,14 @@
<a href="#" class="testLink" data-testmap="CoWebsite/cowebsite_property.json" target="_blank">Open co-websites by map property</a> <a href="#" class="testLink" data-testmap="CoWebsite/cowebsite_property.json" target="_blank">Open co-websites by map property</a>
</td> </td>
</tr> </tr>
<tr>
<td>
<input type="radio" name="test-cowebsite-property-trigger"> Success <input type="radio" name="test-cowebsite-property-trigger"> Failure <input type="radio" name="test-cowebsite-property-trigger" checked> Pending
</td>
<td>
<a href="#" class="testLink" data-testmap="CoWebsite/cowebsite_property_trigger.json" target="_blank">Open co-websites by map property trigger</a>
</td>
</tr>
<tr> <tr>
<td> <td>
<input type="radio" name="test-cowebsite-api"> Success <input type="radio" name="test-cowebsite-api"> Failure <input type="radio" name="test-cowebsite-api" checked> Pending <input type="radio" name="test-cowebsite-api"> Success <input type="radio" name="test-cowebsite-api"> Failure <input type="radio" name="test-cowebsite-api" checked> Pending