Merge branch 'develop' of github.com:thecodingmachine/workadventure

This commit is contained in:
_Bastler 2022-01-27 19:08:57 +01:00
commit 6783598244
102 changed files with 3792 additions and 2048 deletions

View File

@ -83,7 +83,8 @@
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
"TURN_SERVER": "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443",
"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": {
@ -109,7 +110,15 @@
"redis": {
"image": "redis:6",
"ports": [6379]
}
},
"iconserver": {
"image": "matthiasluedtke/iconserver:v3.13.0",
"host": {
"url": "icon-"+url,
"containerPort": 8080,
},
"ports": [8080]
},
},
"config": {
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
```
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.
You can have only 5 co-wbesites open simultaneously.
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
it's to add the cowebsite but don't load it.
Example:
```javascript
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();
```

View File

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

27
front/dist/env-config.template.js vendored Normal file
View File

@ -0,0 +1,27 @@
window.env = {
SKIP_RENDER_OPTIMIZATIONS: '${SKIP_RENDER_OPTIMIZATIONS}',
DISABLE_NOTIFICATIONS: '${DISABLE_NOTIFICATIONS}',
PUSHER_URL: '${PUSHER_URL}',
UPLOADER_URL: '${UPLOADER_URL}',
ADMIN_URL: '${ADMIN_URL}',
CONTACT_URL: '${CONTACT_URL}',
PROFILE_URL: '${PROFILE_URL}',
ICON_URL: '${ICON_URL}',
DEBUG_MODE: '${DEBUG_MODE}',
STUN_SERVER: '${STUN_SERVER}',
TURN_SERVER: '${TURN_SERVER}',
TURN_USER: '${TURN_USER}',
TURN_PASSWORD: '${TURN_PASSWORD}',
JITSI_URL: '${JITSI_URL}',
JITSI_PRIVATE_MODE: '${JITSI_PRIVATE_MODE}',
START_ROOM_URL: '${START_ROOM_URL}',
MAX_USERNAME_LENGTH: '${MAX_USERNAME_LENGTH}',
MAX_PER_GROUP: '${MAX_PER_GROUP}',
DISPLAY_TERMS_OF_USE: '${DISPLAY_TERMS_OF_USE}',
POSTHOG_API_KEY: '${POSTHOG_API_KEY}',
POSTHOG_URL: '${POSTHOG_URL}',
NODE_ENV: '${NODE_ENV}',
DISABLE_ANONYMOUS: '${DISABLE_ANONYMOUS}',
OPID_LOGIN_SCREEN_PROVIDER: '${OPID_LOGIN_SCREEN_PROVIDER}',
FALLBACK_LOCALE: '${FALLBACK_LOCALE}',
};

68
front/dist/index.ejs vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,124 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- TRACK CODE -->
<!-- END TRACK CODE -->
<link rel="apple-touch-icon" sizes="57x57" href="static/images/favicons/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="static/images/favicons/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="static/images/favicons/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="static/images/favicons/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="static/images/favicons/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="static/images/favicons/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="static/images/favicons/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="static/images/favicons/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="static/images/favicons/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="static/images/favicons/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="static/images/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="static/images/favicons/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/images/favicons/favicon-16x16.png">
<link rel="manifest" href="static/images/favicons/manifest.json">
<meta name="msapplication-TileColor" content="#000000">
<meta name="msapplication-TileImage" content="static/images/favicons/ms-icon-144x144.png">
<meta name="theme-color" content="#000000">
<base href="/">
<title>Partey</title>
</head>
<body id="body" style="margin: 0; background-color: #000">
<div class="main-container" id="main-container">
<!-- Create the editor container -->
<div id="game" class="game">
<div id="cowebsite-container">
<div id="cowebsite-container-main">
<div id="cowebsite-slot-1">
<div class="actions">
<button type="button" class="nes-btn is-primary expand">></button>
<button type="button" class="nes-btn is-error close">&times;</button>
</div>
</div>
</div>
<div id="cowebsite-container-sub">
<div id="cowebsite-slot-2">
<div class="overlay">
<div class="actions">
<button type="button" title="Close" class="nes-btn is-error close">&times;</button>
</div>
<div class="actions-move">
<button type="button" title="Expand" class="nes-btn is-primary expand">></button>
<button type="button" title="Hightlight" class="nes-btn is-secondary hightlight">&Xi;</button>
</div>
</div>
</div>
<div id="cowebsite-slot-3">
<div class="overlay">
<div class="actions">
<button type="button" title="Close" class="nes-btn is-error close">&times;</button>
</div>
<div class="actions-move">
<button type="button" title="Expand" class="nes-btn is-primary expand">></button>
<button type="button" title="Hightlight" class="nes-btn is-secondary hightlight">&Xi;</button>
</div>
</div>
</div>
<div id="cowebsite-slot-4">
<div class="overlay">
<div class="actions">
<button type="button" title="Close" class="nes-btn is-error close">&times;</button>
</div>
<div class="actions-move">
<button type="button" title="Expand" class="nes-btn is-primary expand">></button>
<button type="button" title="Hightlight" class="nes-btn is-secondary hightlight">&Xi;</button>
</div>
</div>
</div>
</div>
</div>
<div id="svelte-overlay"></div>
<div id="game-overlay" class="game-overlay">
<div id="main-section" class="main-section">
</div>
<aside id="sidebar" class="sidebar">
</aside>
<div id="chat-mode" class="chat-mode three-col" style="display: none;">
</div>
</div>
</div>
<div id="cowebsite" class="cowebsite hidden">
<aside id="cowebsite-aside" class="noselect">
<div id="cowebsite-aside-buttons">
<button class="top-right-btn nes-btn is-error" id="cowebsite-close" alt="close all co-websites">
&times;
</button>
<button class="top-right-btn nes-btn is-primary" id="cowebsite-fullscreen" alt="fullscreen mode">
<img id="cowebsite-fullscreen-close" style="display: none;" src="resources/logos/fullscreen-exit.svg"/>
<img id="cowebsite-fullscreen-open" src="resources/logos/fullscreen.svg"/>
</button>
</div>
<div id="cowebsite-aside-holder">
<img src="/static/images/menu.svg" alt="hold to resize"/>
</div>
<div id="cowebsite-sub-icons"></div>
</aside>
<main id="cowebsite-slot-0"></main>
</div>
<div id="cowebsite-buffer"></div>
</div>
<div id="activeScreenSharing" class="active-screen-sharing active">
</div>
<audio id="report-message">
<source src="/resources/objects/report-message.mp3" type="audio/mp3">
</audio>
</body>
</html>

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/parser": "^5.6.0",
"css-loader": "^5.2.4",
"css-minimizer-webpack-plugin": "^3.3.1",
"eslint": "^8.4.1",
"eslint-plugin-svelte3": "^3.2.1",
"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),
allowPolicy: tg.isOptional(tg.isString),
position: tg.isOptional(tg.isNumber),
closable: tg.isOptional(tg.isBoolean),
lazy: tg.isOptional(tg.isBoolean),
})
.get();
export const isCoWebsite = new tg.IsInterface()
.withProperties({
id: tg.isString,
position: tg.isNumber,
})
.get();

View File

@ -1,7 +1,7 @@
import { IframeApiContribution, sendToWorkadventure, queryWorkadventure } from "./IframeApiContribution";
export class CoWebsite {
constructor(private readonly id: string, public readonly position: number) {}
constructor(private readonly id: string) {}
close() {
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({
type: "openCoWebsite",
data: {
@ -49,9 +56,11 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
allowApi,
allowPolicy,
position,
closable,
lazy,
},
});
return new CoWebsite(result.id, result.position);
return new CoWebsite(result.id);
}
async getCoWebSites(): Promise<CoWebsite[]> {
@ -59,7 +68,7 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
type: "getCoWebsites",
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">
import MenuIcon from "./Menu/MenuIcon.svelte";
import { menuIconVisiblilityStore, menuVisiblilityStore } from "../Stores/MenuStore";
import { emoteMenuStore } from "../Stores/EmoteStore";
import { enableCameraSceneVisibilityStore } from "../Stores/MediaStore";
import CameraControls from "./CameraControls.svelte";
import MyCamera from "./MyCamera.svelte";
import SelectCompanionScene from "./SelectCompanion/SelectCompanionScene.svelte";
import { selectCompanionSceneVisibleStore } from "../Stores/SelectCompanionStore";
import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore";
import SelectCharacterScene from "./selectCharacter/SelectCharacterScene.svelte";
import { customCharacterSceneVisibleStore } from "../Stores/CustomCharacterStore";
import { errorStore } from "../Stores/ErrorStore";
import CustomCharacterScene from "./CustomCharacterScene/CustomCharacterScene.svelte";
import LoginScene from "./Login/LoginScene.svelte";
import Chat from "./Chat/Chat.svelte";
import { loginSceneVisibleStore } from "../Stores/LoginSceneStore";
import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte";
import VisitCard from "./VisitCard/VisitCard.svelte";
import { requestVisitCardsStore } from "../Stores/GameStore";
import type { Game } from "../Phaser/Game/Game";
import { chatVisibilityStore } from "../Stores/ChatStore";
import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStore";
import HelpCameraSettingsPopup from "./HelpCameraSettings/HelpCameraSettingsPopup.svelte";
import { showLimitRoomModalStore, showShareLinkMapModalStore } from "../Stores/ModalStore";
import LimitRoomModal from "./Modal/LimitRoomModal.svelte";
import ShareLinkMapModal from "./Modal/ShareLinkMapModal.svelte";
import AudioPlaying from "./UI/AudioPlaying.svelte";
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
import { customCharacterSceneVisibleStore } from "../Stores/CustomCharacterStore";
import { errorStore } from "../Stores/ErrorStore";
import { loginSceneVisibleStore } from "../Stores/LoginSceneStore";
import { enableCameraSceneVisibilityStore } from "../Stores/MediaStore";
import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore";
import { selectCompanionSceneVisibleStore } from "../Stores/SelectCompanionStore";
import Chat from "./Chat/Chat.svelte";
import CustomCharacterScene from "./CustomCharacterScene/CustomCharacterScene.svelte";
import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte";
import LoginScene from "./Login/LoginScene.svelte";
import MainLayout from "./MainLayout.svelte";
import SelectCharacterScene from "./selectCharacter/SelectCharacterScene.svelte";
import SelectCompanionScene from "./SelectCompanion/SelectCompanionScene.svelte";
import ErrorDialog from "./UI/ErrorDialog.svelte";
import Menu from "./Menu/Menu.svelte";
import EmoteMenu from "./EmoteMenu/EmoteMenu.svelte";
import VideoOverlay from "./Video/VideoOverlay.svelte";
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
import BanMessageContainer from "./TypeMessage/BanMessageContainer.svelte";
import TextMessageContainer from "./TypeMessage/TextMessageContainer.svelte";
import { banMessageStore } from "../Stores/TypeMessageStore/BanMessageStore";
import { textMessageStore } from "../Stores/TypeMessageStore/TextMessageStore";
import { warningContainerStore } from "../Stores/MenuStore";
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
import { layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore";
import LayoutManager from "./LayoutManager/LayoutManager.svelte";
import { audioManagerVisibilityStore } from "../Stores/AudioManagerStore";
import AudioManager from "./AudioManager/AudioManager.svelte";
import { showReportScreenStore, userReportEmpty } from "../Stores/ShowReportScreenStore";
import ReportMenu from "./ReportMenu/ReportMenu.svelte";
import { followStateStore } from "../Stores/FollowStore";
import { peerStore } from "../Stores/PeerStore";
import FollowMenu from "./FollowMenu/FollowMenu.svelte";
export let game: Game;
</script>
<div>
{#if $loginSceneVisibleStore}
<div class="scrollable">
<LoginScene {game} />
</div>
{/if}
{#if $selectCharacterSceneVisibleStore}
<div>
<SelectCharacterScene {game} />
</div>
{/if}
{#if $customCharacterSceneVisibleStore}
<div>
<CustomCharacterScene {game} />
</div>
{/if}
{#if $selectCompanionSceneVisibleStore}
<div>
<SelectCompanionScene {game} />
</div>
{/if}
{#if $enableCameraSceneVisibilityStore}
<div class="scrollable">
<EnableCameraScene {game} />
</div>
{/if}
{#if $banMessageStore.length > 0}
<div>
<BanMessageContainer />
</div>
{:else if $textMessageStore.length > 0}
<div>
<TextMessageContainer />
</div>
{/if}
{#if $soundPlayingStore}
<div>
<AudioPlaying url={$soundPlayingStore} />
</div>
{/if}
{#if $audioManagerVisibilityStore}
<div>
<AudioManager />
</div>
{/if}
{#if $layoutManagerVisibilityStore}
<div>
<LayoutManager />
</div>
{/if}
{#if $showReportScreenStore !== userReportEmpty}
<div>
<ReportMenu />
</div>
{/if}
{#if $followStateStore !== "off" || $peerStore.size > 0}
<div>
<FollowMenu />
</div>
{/if}
{#if $menuIconVisiblilityStore}
<div>
<MenuIcon />
</div>
{/if}
{#if $menuVisiblilityStore}
<div>
<Menu />
</div>
{/if}
{#if $emoteMenuStore}
<div>
<EmoteMenu />
</div>
{/if}
{#if $gameOverlayVisibilityStore}
<div>
<VideoOverlay />
<MyCamera />
<CameraControls />
</div>
{/if}
{#if $helpCameraSettingsVisibleStore}
<div>
<HelpCameraSettingsPopup />
</div>
{/if}
{#if $showLimitRoomModalStore}
<div>
<LimitRoomModal />
</div>
{/if}
{#if $showShareLinkMapModalStore}
<div>
<ShareLinkMapModal />
</div>
{/if}
{#if $requestVisitCardsStore}
<VisitCard visitCardUrl={$requestVisitCardsStore} />
{/if}
{#if $errorStore.length > 0}
<div>
<ErrorDialog />
</div>
{/if}
{#if $errorStore.length > 0}
<div>
<ErrorDialog />
</div>
{:else if $loginSceneVisibleStore}
<div class="scrollable">
<LoginScene {game} />
</div>
{:else if $selectCharacterSceneVisibleStore}
<div>
<SelectCharacterScene {game} />
</div>
{:else if $customCharacterSceneVisibleStore}
<div>
<CustomCharacterScene {game} />
</div>
{:else if $selectCompanionSceneVisibleStore}
<div>
<SelectCompanionScene {game} />
</div>
{:else if $enableCameraSceneVisibilityStore}
<div class="scrollable">
<EnableCameraScene {game} />
</div>
{:else}
<MainLayout />
{#if $chatVisibilityStore}
<Chat />
{/if}
{#if $warningContainerStore}
<WarningContainer />
{/if}
</div>
{/if}

View File

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

View File

@ -9,10 +9,15 @@
import microphoneCloseImg from "./images/microphone-close.svg";
import layoutPresentationImg from "./images/layout-presentation.svg";
import layoutChatImg from "./images/layout-chat.svg";
import { layoutModeStore } from "../Stores/StreamableCollectionStore";
import followImg from "./images/follow.svg";
import { LayoutMode } from "../WebRtc/LayoutManager";
import { peerStore } from "../Stores/PeerStore";
import { onDestroy } from "svelte";
import { embedScreenLayout } from "../Stores/EmbedScreensStore";
import { followRoleStore, followStateStore, followUsersStore } from "../Stores/FollowStore";
import { gameManager } from "../Phaser/Game/GameManager";
const gameScene = gameManager.getCurrentGameScene();
function screenSharingClick(): void {
if (isSilent) return;
@ -42,10 +47,26 @@
}
function switchLayoutMode() {
if ($layoutModeStore === LayoutMode.Presentation) {
$layoutModeStore = LayoutMode.VideoChat;
if ($embedScreenLayout === LayoutMode.Presentation) {
$embedScreenLayout = LayoutMode.VideoChat;
} else {
$layoutModeStore = LayoutMode.Presentation;
$embedScreenLayout = LayoutMode.Presentation;
}
}
function followClick() {
switch ($followStateStore) {
case "off":
gameScene.connection?.emitFollowRequest();
followRoleStore.set("leader");
followStateStore.set("active");
break;
case "requesting":
case "active":
case "ending":
gameScene.connection?.emitFollowAbort();
followUsersStore.stopFollowing();
break;
}
}
@ -56,41 +77,156 @@
onDestroy(unsubscribeIsSilent);
</script>
<div>
<div class="btn-cam-action">
<div class="btn-layout nes-btn is-dark" on:click={switchLayoutMode} class:hide={$peerStore.size === 0}>
{#if $layoutModeStore === LayoutMode.Presentation}
<img src={layoutPresentationImg} style="padding: 2px" alt="Switch to mosaic mode" />
{:else}
<img src={layoutChatImg} style="padding: 2px" alt="Switch to presentation mode" />
{/if}
</div>
<div
class="btn-monitor nes-btn is-dark"
on:click={screenSharingClick}
class:hide={!$screenSharingAvailableStore || isSilent}
class:enabled={$requestedScreenSharingState}
>
{#if $requestedScreenSharingState && !isSilent}
<img src={monitorImg} alt="Start screen sharing" />
{:else}
<img src={monitorCloseImg} alt="Stop screen sharing" />
{/if}
</div>
<div class="btn-video nes-btn is-dark" on:click={cameraClick} class:disabled={!$requestedCameraState ||
isSilent}>
{#if $requestedCameraState && !isSilent}
<img src={cinemaImg} alt="Turn on webcam" />
{:else}
<img src={cinemaCloseImg} alt="Turn off webcam" />
{/if}
</div>
<div class="btn-micro nes-btn is-dark" on:click={microphoneClick} class:disabled={!$requestedMicrophoneState || isSilent}>
{#if $requestedMicrophoneState && !isSilent}
<img src={microphoneImg} alt="Turn on microphone" />
{:else}
<img src={microphoneCloseImg} alt="Turn off microphone" />
{/if}
</div>
<div class="btn-cam-action">
<div class="btn-layout nes-btn is-dark" on:click={switchLayoutMode} class:hide={$peerStore.size === 0}>
{#if $embedScreenLayout === LayoutMode.Presentation}
<img class="noselect" src={layoutPresentationImg} style="padding: 2px" alt="Switch to mosaic mode" />
{:else}
<img class="noselect" src={layoutChatImg} style="padding: 2px" alt="Switch to presentation mode" />
{/if}
</div>
<div
class="btn-follow nes-btn is-dark"
class:hide={($peerStore.size === 0 && $followStateStore === "off") || isSilent}
class:disabled={$followStateStore !== "off"}
on:click={followClick}
>
<img class="noselect" src={followImg} alt="" />
</div>
<div
class="btn-monitor nes-btn is-dark"
on:click={screenSharingClick}
class:hide={!$screenSharingAvailableStore || isSilent}
class:enabled={$requestedScreenSharingState}
>
{#if $requestedScreenSharingState && !isSilent}
<img class="noselect" src={monitorImg} alt="Start screen sharing" />
{:else}
<img class="noselect" src={monitorCloseImg} alt="Stop screen sharing" />
{/if}
</div>
<div class="btn-video nes-btn is-dark" on:click={cameraClick} class:disabled={!$requestedCameraState || isSilent}>
{#if $requestedCameraState && !isSilent}
<img class="noselect" src={cinemaImg} alt="Turn on webcam" />
{:else}
<img class="noselect" src={cinemaCloseImg} alt="Turn off webcam" />
{/if}
</div>
<div class="btn-micro nes-btn is-dark" on:click={microphoneClick} class:disabled={!$requestedMicrophoneState || isSilent}>
{#if $requestedMicrophoneState && !isSilent}
<img class="noselect" src={microphoneImg} alt="Turn on microphone" />
{:else}
<img class="noselect" src={microphoneCloseImg} alt="Turn off microphone" />
{/if}
</div>
</div>
<style lang="scss">
@import "../../style/breakpoints.scss";
.btn-cam-action {
pointer-events: all;
position: absolute;
display: inline-flex;
bottom: 10px;
right: 15px;
width: 360px;
height: 40px;
text-align: center;
align-content: center;
justify-content: flex-end;
z-index: 251;
&:hover {
div.hide {
transform: translateY(60px);
}
}
}
/*btn animation*/
.btn-cam-action div {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
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;
}
.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

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

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>
<style lang="scss">
@import "../../../style/breakpoints.scss";
.string-HTML {
white-space: pre-line;
}
@ -126,7 +128,7 @@
}
}
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
@include media-breakpoint-up(md) {
div.about-room-main {
section.container-overflow {
height: calc(100% - 120px);

View File

@ -67,6 +67,8 @@
</div>
<style lang="scss">
@import "../../../style/breakpoints.scss";
div.global-message-main {
height: calc(100% - 50px);
display: grid;
@ -109,7 +111,7 @@
}
}
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
@include media-breakpoint-up(md) {
.global-message-content {
height: calc(100% - 5px);
}

View File

@ -36,6 +36,8 @@
</div>
<style lang="scss">
@import "../../../style/breakpoints.scss";
div.guest-main {
height: calc(100% - 56px);
@ -57,7 +59,7 @@
}
}
@media only screen and (max-width: 900px), only screen and (max-height: 600px) {
@include media-breakpoint-up(md) {
div.guest-main {
section.share-url.not-mobile {
display: none;

View File

@ -129,6 +129,8 @@
</div>
<style lang="scss">
@import "../../../style/breakpoints.scss";
.nes-container {
padding: 5px;
}
@ -140,11 +142,15 @@
pointer-events: auto;
height: 80%;
width: 75%;
top: 10%;
top: 4%;
position: relative;
z-index: 80;
margin: auto;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
position: absolute;
z-index: 900;
display: grid;
grid-template-columns: var(--size-first-columns-grid) calc(100% - var(--size-first-columns-grid));
@ -177,12 +183,12 @@
}
}
@media only screen and (max-width: 800px) {
@include media-breakpoint-up(md) {
div.menu-container-main {
--size-first-columns-grid: 120px;
height: 70%;
top: 55px;
width: 100%;
width: 95%;
font-size: 0.5em;
div.menu-nav-sidebar {

View File

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

View File

@ -13,7 +13,6 @@
import { EnableCameraScene, EnableCameraSceneName } from "../../Phaser/Login/EnableCameraScene";
import { enableCameraSceneVisibilityStore } from "../../Stores/MediaStore";
import btnProfileSubMenuCamera from "../images/btn-menu-profile-camera.svg";
import btnProfileSubMenuIdentity from "../images/btn-menu-profile-identity.svg";
import btnProfileSubMenuCompanion from "../images/btn-menu-profile-companion.svg";
import Woka from "../Woka/Woka.svelte";
import Companion from "../Companion/Companion.svelte";
@ -104,6 +103,8 @@
</div>
<style lang="scss">
@import "../../../style/breakpoints.scss";
div.customize-main {
width: 100%;
display: inline-flex;
@ -163,7 +164,7 @@
}
}
@media only screen and (max-width: 800px) {
@include media-breakpoint-up(md) {
div.customize-main.content section button {
width: 130px;
}

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
import { obtainedMediaConstraintStore } from "../Stores/MediaStore";
import { localStreamStore, isSilentStore } from "../Stores/MediaStore";
import SoundMeterWidget from "./SoundMeterWidget.svelte";
import { onDestroy } from "svelte";
import { onDestroy, onMount } from "svelte";
import { srcObject } from "./Video/utils";
import LL from "../i18n/i18n-svelte";
@ -23,16 +23,75 @@
isSilent = value;
});
let cameraContainer: HTMLDivElement;
onMount(() => {
cameraContainer.addEventListener("transitionend", () => {
if (cameraContainer.classList.contains("hide")) {
cameraContainer.style.visibility = "hidden";
}
});
cameraContainer.addEventListener("transitionstart", () => {
if (!cameraContainer.classList.contains("hide")) {
cameraContainer.style.visibility = "visible";
}
});
});
onDestroy(unsubscribeIsSilent);
</script>
<div>
<div class="video-container nes-container is-rounded is-dark div-myCamVideo"
class:hide={!$obtainedMediaConstraintStore.video || isSilent}>
{#if $localStreamStore.type === "success" && $localStreamStore.stream}
<video class="myCamVideo" use:srcObject={stream} autoplay muted playsinline />
<SoundMeterWidget {stream} />
{/if}
</div>
<div class="nes-container is-dark is-silent" class:hide={isSilent}>{$LL.camera.my.silentZone()}</div>
<div
class="nes-container is-rounded my-cam-video-container"
class:hide={($localStreamStore.type !== "success" || !$obtainedMediaConstraintStore.video) && !isSilent}
bind:this={cameraContainer}
>
{#if isSilent}
<div class="is-silent">{$LL.camera.my.silentZone()}</div>
{:else if $localStreamStore.type === "success" && $localStreamStore.stream}
<video class="my-cam-video" use:srcObject={stream} autoplay muted playsinline />
<SoundMeterWidget {stream} />
{/if}
</div>
<style lang="scss">
@import "../../style/breakpoints.scss";
.my-cam-video-container {
position: absolute;
right: 15px;
bottom: 30px;
max-height: 20%;
transition: transform 1000ms;
padding: 0;
background-color: 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;
background-color: #333333;
color: whitesmoke;
position: relative;
z-index: 650;
position: absolute;
height: 70vh;
width: 50vw;
top: 10vh;
margin: auto;
top: 4%;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
section.report-menu-title {
display: grid;
@ -137,13 +141,4 @@
display: none;
}
}
@media only screen and (max-width: 800px) {
div.report-menu-main {
top: 21vh;
height: 60vh;
width: 100vw;
font-size: 0.5em;
}
}
</style>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,14 +7,106 @@
import type { Streamable } from "../../Stores/StreamableCollectionStore";
export let streamable: Streamable;
export let isHightlighted = false;
export let isClickable = false;
export let mozaicFullWidth = false;
export let mozaicQuarter = false;
</script>
<div class="media-container">
{#if streamable instanceof VideoPeer}
<VideoMediaBox peer={streamable} />
{:else if streamable instanceof ScreenSharingPeer}
<ScreenSharingMediaBox peer={streamable} />
{:else}
<LocalStreamMediaBox peer={streamable} cssClass="" />
{/if}
<div
class="media-container nes-container is-rounded {isHightlighted ? 'hightlighted' : ''}"
class:clickable={isClickable}
class:mozaic-full-width={mozaicFullWidth}
class:mozaic-quarter={mozaicQuarter}
>
<div>
{#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>
<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;
}
> 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">
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
import type { EmbedScreen } from "../../Stores/EmbedScreensStore";
import type { Streamable } from "../../Stores/StreamableCollectionStore";
import type { ScreenSharingPeer } from "../../WebRtc/ScreenSharingPeer";
import { videoFocusStore } from "../../Stores/VideoFocusStore";
import { getColorByString, srcObject } from "./utils";
export let clickable = false;
export let peer: ScreenSharingPeer;
let streamStore = peer.streamStore;
let name = peer.userName;
let statusStore = peer.statusStore;
let embedScreen: EmbedScreen;
if (peer) {
embedScreen = {
type: "streamable",
embed: peer as unknown as Streamable,
};
}
</script>
<div class="video-container">
@ -20,7 +34,12 @@
<i style="background-color: {getColorByString(name)};">{name}</i>
{:else}
<!-- svelte-ignore a11y-media-has-caption -->
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)} />
<video
use:srcObject={$streamStore}
autoplay
playsinline
on:click={() => (clickable ? highlightedEmbedScreen.toggleHighlight(embedScreen) : null)}
/>
{/if}
</div>

View File

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

View File

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

View File

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

View File

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

View File

@ -22,10 +22,21 @@
src = source ?? placeholderSrc;
});
function noDrag() {
return false;
}
onDestroy(unsubscribe);
</script>
<img {src} alt="" class="nes-pointer" style="--theme-width: {width}; --theme-height: {height}" />
<img
{src}
alt=""
class="nes-pointer noselect"
style="--theme-width: {width}; --theme-height: {height}"
draggable="false"
on:dragstart|preventDefault={noDrag}
/>
<style>
img {

View File

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

View File

@ -1,33 +1,46 @@
const DEBUG_MODE: boolean = process.env.DEBUG_MODE == "true";
const START_ROOM_URL: string =
process.env.START_ROOM_URL || "/_/global/maps.workadventure.localhost/Floor1/floor1.json";
const PUSHER_URL = process.env.PUSHER_URL || "//pusher.workadventure.localhost";
export const ADMIN_URL = process.env.ADMIN_URL || "//workadventu.re";
const UPLOADER_URL = process.env.UPLOADER_URL || "//uploader.workadventure.localhost";
const ICON_URL = process.env.ICON_URL || "//icon.workadventure.localhost";
const STUN_SERVER: string = process.env.STUN_SERVER || "stun:stun.l.google.com:19302";
const TURN_SERVER: string = process.env.TURN_SERVER || "";
const SKIP_RENDER_OPTIMIZATIONS: boolean = process.env.SKIP_RENDER_OPTIMIZATIONS == "true";
const DISABLE_NOTIFICATIONS: boolean = process.env.DISABLE_NOTIFICATIONS == "true";
const TURN_USER: string = process.env.TURN_USER || "";
const TURN_PASSWORD: string = process.env.TURN_PASSWORD || "";
const JITSI_URL: string | undefined = process.env.JITSI_URL === "" ? undefined : process.env.JITSI_URL;
const JITSI_PRIVATE_MODE: boolean = process.env.JITSI_PRIVATE_MODE == "true";
declare global {
interface Window {
env?: Record<string, string>;
}
}
const getEnv = (key: string): string | undefined => {
if (global.window?.env) {
return global.window.env[key];
}
if (global.process?.env) {
return global.process.env[key];
}
return;
};
const DEBUG_MODE: boolean = getEnv("DEBUG_MODE") == "true";
const START_ROOM_URL: string = getEnv("START_ROOM_URL") || "/_/global/maps.workadventure.localhost/Floor1/floor1.json";
const PUSHER_URL = getEnv("PUSHER_URL") || "//pusher.workadventure.localhost";
export const ADMIN_URL = getEnv("ADMIN_URL") || "//workadventu.re";
const UPLOADER_URL = getEnv("UPLOADER_URL") || "//uploader.workadventure.localhost";
const ICON_URL = getEnv("ICON_URL") || "//icon.workadventure.localhost";
const STUN_SERVER: string = getEnv("STUN_SERVER") || "stun:stun.l.google.com:19302";
const TURN_SERVER: string = getEnv("TURN_SERVER") || "";
const SKIP_RENDER_OPTIMIZATIONS: boolean = getEnv("SKIP_RENDER_OPTIMIZATIONS") == "true";
const DISABLE_NOTIFICATIONS: boolean = getEnv("DISABLE_NOTIFICATIONS") == "true";
const TURN_USER: string = getEnv("TURN_USER") || "";
const TURN_PASSWORD: string = getEnv("TURN_PASSWORD") || "";
const JITSI_URL: string | undefined = getEnv("JITSI_URL") === "" ? undefined : getEnv("JITSI_URL");
const JITSI_PRIVATE_MODE: boolean = getEnv("JITSI_PRIVATE_MODE") == "true";
const POSITION_DELAY = 200; // Wait 200ms between sending position events
const MAX_EXTRAPOLATION_TIME = 100; // Extrapolate a maximum of 250ms if no new movement is sent by the player
export const MAX_USERNAME_LENGTH = parseInt(process.env.MAX_USERNAME_LENGTH || "") || 8;
export const MAX_PER_GROUP = parseInt(process.env.MAX_PER_GROUP || "4");
export const DISPLAY_TERMS_OF_USE = process.env.DISPLAY_TERMS_OF_USE == "true";
export const NODE_ENV = process.env.NODE_ENV || "development";
export const CONTACT_URL = process.env.CONTACT_URL || undefined;
export const PROFILE_URL = process.env.PROFILE_URL || undefined;
export const POSTHOG_API_KEY: string = (process.env.POSTHOG_API_KEY as string) || "";
export const POSTHOG_URL = process.env.POSTHOG_URL || undefined;
export const DISABLE_ANONYMOUS: boolean = process.env.DISABLE_ANONYMOUS === "true";
export const OPID_LOGIN_SCREEN_PROVIDER = process.env.OPID_LOGIN_SCREEN_PROVIDER;
const FALLBACK_LOCALE = process.env.FALLBACK_LOCALE || undefined;
export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600;
export const MAX_USERNAME_LENGTH = parseInt(getEnv("MAX_USERNAME_LENGTH") || "") || 8;
export const MAX_PER_GROUP = parseInt(getEnv("MAX_PER_GROUP") || "4");
export const DISPLAY_TERMS_OF_USE = getEnv("DISPLAY_TERMS_OF_USE") == "true";
export const NODE_ENV = getEnv("NODE_ENV") || "development";
export const CONTACT_URL = getEnv("CONTACT_URL") || undefined;
export const PROFILE_URL = getEnv("PROFILE_URL") || undefined;
export const POSTHOG_API_KEY: string = (getEnv("POSTHOG_API_KEY") as string) || "";
export const POSTHOG_URL = getEnv("POSTHOG_URL") || undefined;
export const DISABLE_ANONYMOUS: boolean = getEnv("DISABLE_ANONYMOUS") === "true";
export const OPID_LOGIN_SCREEN_PROVIDER = getEnv("OPID_LOGIN_SCREEN_PROVIDER");
const FALLBACK_LOCALE = getEnv("FALLBACK_LOCALE") || undefined;
export {
DEBUG_MODE,

View File

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

View File

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

View File

@ -2,33 +2,29 @@ import type { GameScene } from "./GameScene";
import type { GameMap } from "./GameMap";
import { scriptUtils } from "../../Api/ScriptUtils";
import type { CoWebsite } from "../../WebRtc/CoWebsiteManager";
import { coWebsiteManager, CoWebsiteState } from "../../WebRtc/CoWebsiteManager";
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
import { localUserStore } from "../../Connexion/LocalUserStore";
import { get } from "svelte/store";
import { ON_ACTION_TRIGGER_BUTTON, ON_ACTION_TRIGGER_DISABLE } from "../../WebRtc/LayoutManager";
import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
import type { ITiledMapLayer } from "../Map/ITiledMap";
import { GameMapProperties } from "./GameMapProperties";
import { iframeListener } from "../../Api/IframeListener";
import type { Subscription } from "rxjs";
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
import { LL } from "../../i18n/i18n-svelte";
enum OpenCoWebsiteState {
LOADING,
ASLEEP,
OPENED,
MUST_BE_CLOSE,
TRIGGER,
}
interface OpenCoWebsite {
coWebsite: CoWebsite | undefined;
coWebsite: CoWebsite;
state: OpenCoWebsiteState;
}
export class GameMapPropertiesListener {
private coWebsitesOpenByLayer = new Map<ITiledMapLayer, OpenCoWebsite>();
private coWebsitesIframeListeners = new Map<ITiledMapLayer, Subscription>();
private coWebsitesActionTriggerByLayer = new Map<ITiledMapLayer, string>();
constructor(private scene: GameScene, private gameMap: GameMap) {}
@ -69,10 +65,8 @@ export class GameMapPropertiesListener {
let openWebsiteProperty: string | undefined;
let allowApiProperty: boolean | undefined;
let websitePolicyProperty: string | undefined;
let websiteWidthProperty: number | undefined;
let websitePositionProperty: number | undefined;
let websiteTriggerProperty: string | undefined;
let websiteTriggerMessageProperty: string | undefined;
layer.properties.forEach((property) => {
switch (property.name) {
@ -85,18 +79,12 @@ export class GameMapPropertiesListener {
case GameMapProperties.OPEN_WEBSITE_POLICY:
websitePolicyProperty = property.value as string | undefined;
break;
case GameMapProperties.OPEN_WEBSITE_WIDTH:
websiteWidthProperty = property.value as number | undefined;
break;
case GameMapProperties.OPEN_WEBSITE_POSITION:
websitePositionProperty = property.value as number | undefined;
break;
case GameMapProperties.OPEN_WEBSITE_TRIGGER:
websiteTriggerProperty = property.value as string | undefined;
break;
case GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE:
websiteTriggerMessageProperty = property.value as string | undefined;
break;
}
});
@ -110,27 +98,30 @@ export class GameMapPropertiesListener {
return;
}
const coWebsite = coWebsiteManager.addCoWebsite(
openWebsiteProperty,
this.scene.MapUrlFile,
allowApiProperty,
websitePolicyProperty,
websitePositionProperty,
false
);
this.coWebsitesOpenByLayer.set(layer, {
coWebsite: undefined,
state: OpenCoWebsiteState.LOADING,
coWebsite: coWebsite,
state: OpenCoWebsiteState.ASLEEP,
});
const openWebsiteFunction = () => {
coWebsiteManager
.loadCoWebsite(
openWebsiteProperty as string,
this.scene.MapUrlFile,
allowApiProperty,
websitePolicyProperty,
websiteWidthProperty,
websitePositionProperty
)
.loadCoWebsite(coWebsite)
.then((coWebsite) => {
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
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.coWebsitesActionTriggerByLayer.delete(layer);
} else {
this.coWebsitesOpenByLayer.set(layer, {
coWebsite,
@ -138,57 +129,17 @@ export class GameMapPropertiesListener {
});
}
})
.catch((e) => console.error(e));
.catch(() => {
console.error("Error during loading a co-website: " + coWebsite.url);
});
layoutManagerActionStore.removeAction(actionUuid);
};
const createWebsiteTrigger = () => {
if (!websiteTriggerMessageProperty) {
websiteTriggerMessageProperty = get(LL).message.openWebsiteTrigger();
}
this.coWebsitesOpenByLayer.set(layer, {
coWebsite: undefined,
state: OpenCoWebsiteState.TRIGGER,
});
this.coWebsitesActionTriggerByLayer.set(layer, actionUuid);
layoutManagerActionStore.addAction({
uuid: actionUuid,
type: "message",
message: websiteTriggerMessageProperty,
callback: () => openWebsiteFunction(),
userInputManager: this.scene.userInputManager,
});
};
this.coWebsitesIframeListeners.set(
layer,
iframeListener.unregisterIFrameStream.subscribe(() => {
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
if (
coWebsiteOpen?.coWebsite?.state == CoWebsiteState.CLOSED &&
(!websiteTriggerProperty || websiteTriggerProperty !== ON_ACTION_TRIGGER_DISABLE)
) {
createWebsiteTrigger();
}
})
);
const forceTrigger = localUserStore.getForceCowebsiteTrigger();
if (
forceTrigger ||
(websiteTriggerProperty && websiteTriggerProperty === ON_ACTION_TRIGGER_BUTTON)
!localUserStore.getForceCowebsiteTrigger() &&
websiteTriggerProperty !== ON_ACTION_TRIGGER_BUTTON
) {
createWebsiteTrigger();
} else {
this.coWebsitesOpenByLayer.set(layer, {
coWebsite: undefined,
state: OpenCoWebsiteState.LOADING,
});
openWebsiteFunction();
}
});
@ -223,29 +174,14 @@ export class GameMapPropertiesListener {
return;
}
const coWebsiteIframeListener = this.coWebsitesIframeListeners.get(layer);
if (coWebsiteIframeListener) {
coWebsiteIframeListener.unsubscribe();
this.coWebsitesIframeListeners.delete(layer);
}
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
if (!coWebsiteOpen) {
return;
}
if (coWebsiteOpen.state === OpenCoWebsiteState.LOADING) {
if (coWebsiteOpen.state === OpenCoWebsiteState.ASLEEP) {
coWebsiteOpen.state = OpenCoWebsiteState.MUST_BE_CLOSE;
return;
}
if (
coWebsiteOpen.state !== OpenCoWebsiteState.OPENED &&
coWebsiteOpen.state !== OpenCoWebsiteState.TRIGGER
) {
return;
}
if (coWebsiteOpen.coWebsite !== undefined) {
@ -253,22 +189,6 @@ export class GameMapPropertiesListener {
}
this.coWebsitesOpenByLayer.delete(layer);
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

@ -255,7 +255,7 @@ export class GameScene extends DirtyScene {
}
this.load.audio("audio-webrtc-in", "/resources/objects/webrtc-in.mp3");
this.load.audio("audio-webrtc-out", "/resources/objects/webrtc-out.mp3");
//this.load.audio('audio-report-message', '/resources/objects/report-message.mp3');
this.load.audio("audio-report-message", "/resources/objects/report-message.mp3");
this.sound.pauseOnBlur = false;
this.load.on(FILE_LOAD_ERROR, (file: { src: string }) => {
@ -650,13 +650,9 @@ export class GameScene extends DirtyScene {
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
const newPeerNumber = peers.size;
if (newPeerNumber > oldPeerNumber) {
this.sound.play("audio-webrtc-in", {
volume: 0.2,
});
this.playSound("audio-webrtc-in");
} else if (newPeerNumber < oldPeerNumber) {
this.sound.play("audio-webrtc-out", {
volume: 0.2,
});
this.playSound("audio-webrtc-out");
}
oldPeerNumber = newPeerNumber;
});
@ -1296,21 +1292,21 @@ export class GameScene extends DirtyScene {
throw new Error("Unknown query source");
}
const coWebsite = await coWebsiteManager.loadCoWebsite(
const coWebsite = coWebsiteManager.addCoWebsite(
openCoWebsite.url,
iframeListener.getBaseUrlFromSource(source),
openCoWebsite.allowApi,
openCoWebsite.allowPolicy,
openCoWebsite.position
openCoWebsite.position,
openCoWebsite.closable ?? true
);
if (!coWebsite) {
throw new Error("Error on opening co-website");
if (openCoWebsite.lazy !== undefined && !openCoWebsite.lazy) {
await coWebsiteManager.loadCoWebsite(coWebsite);
}
return {
id: coWebsite.iframe.id,
position: coWebsite.position,
};
});
@ -1320,7 +1316,6 @@ export class GameScene extends DirtyScene {
return coWebsites.map((coWebsite: CoWebsite) => {
return {
id: coWebsite.iframe.id,
position: coWebsite.position,
};
});
});
@ -1610,6 +1605,12 @@ export class GameScene extends DirtyScene {
}
}
public playSound(sound: string) {
this.sound.play(sound, {
volume: 0.2,
});
}
public cleanupClosingScene(): void {
// stop playing audio, close any open website, stop any open Jitsi
coWebsiteManager.closeCoWebsites().catch((e) => console.error(e));
@ -1647,7 +1648,7 @@ export class GameScene extends DirtyScene {
this.sharedVariablesManager?.close();
this.embeddedWebsiteManager?.close();
mediaManager.hideGameOverlay();
mediaManager.hideMyCamera();
for (const iframeEvents of this.iframeSubscriptionList) {
iframeEvents.unsubscribe();
@ -2156,6 +2157,17 @@ export class GameScene extends DirtyScene {
biggestAvailableAreaStore.recompute();
}
public enableMediaBehaviors() {
const silent = this.gameMap.getCurrentProperties().get(GameMapProperties.SILENT);
this.connection?.setSilent(!!silent);
mediaManager.showMyCamera();
}
public disableMediaBehaviors() {
this.connection?.setSilent(true);
mediaManager.hideMyCamera();
}
public startJitsi(roomName: string, jwt?: string): void {
const allProps = this.gameMap.getCurrentProperties();
const jitsiConfig = this.safeParseJSONstring(
@ -2167,71 +2179,26 @@ export class GameScene extends DirtyScene {
GameMapProperties.JITSI_INTERFACE_CONFIG
);
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
const jitsiWidth = allProps.get(GameMapProperties.JITSI_WIDTH) as number | undefined;
const jitsiKeepCircle = allProps.get("jitsiKeepCircle") as boolean | false;
jitsiFactory
.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl, jitsiWidth)
.catch((e) => console.error(e));
this.connection?.setSilent(true);
mediaManager.hideGameOverlay();
if (jitsiKeepCircle) {
const silent = this.gameMap.getCurrentProperties().get("silent");
this.connection?.setSilent(!!silent);
mediaManager.showGameOverlay();
}
analyticsClient.enteredJitsi(roomName, this.room.id);
//permit to stop jitsi when user close iframe
mediaManager.addTriggerCloseJitsiFrameButton("close-jitsi", () => {
this.stopJitsi();
jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl).catch(() => {
console.error("Cannot start a Jitsi co-website");
});
if (allProps.get("jitsiKeepCircle") as boolean | false) {
this.enableMediaBehaviors();
} else {
this.disableMediaBehaviors();
}
analyticsClient.enteredJitsi(roomName, this.room.id);
}
public stopJitsi(): void {
const silent = this.gameMap.getCurrentProperties().get(GameMapProperties.SILENT);
this.connection?.setSilent(!!silent);
jitsiFactory.stop();
mediaManager.showGameOverlay();
const allProps = this.gameMap.getCurrentProperties();
if (allProps.get("jitsiRoom") === undefined) {
layoutManagerActionStore.removeAction("jitsi");
} else {
const openJitsiRoomFunction = () => {
const roomName = jitsiFactory.getRoomName(
allProps.get(GameMapProperties.JITSI_ROOM) as string,
this.instance
);
const jitsiUrl = allProps.get(GameMapProperties.JITSI_URL) as string | undefined;
if (JITSI_PRIVATE_MODE && !jitsiUrl) {
const adminTag = allProps.get(GameMapProperties.JITSI_ADMIN_ROOM_TAG) as string | undefined;
this.connection && this.connection.emitQueryJitsiJwtMessage(roomName, adminTag);
} else {
this.startJitsi(roomName, undefined);
}
layoutManagerActionStore.removeAction("jitsi");
};
let message = allProps.get(GameMapProperties.JITSI_TRIGGER_MESSAGE);
if (message === undefined) {
message = "Press SPACE or touch here to enter Jitsi Meet room";
}
layoutManagerActionStore.addAction({
uuid: "jitsi",
type: "message",
message: message,
callback: () => openJitsiRoomFunction(),
userInputManager: this.userInputManager,
const coWebsite = coWebsiteManager.searchJitsi();
if (coWebsite) {
coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => {
console.error("Error during Jitsi co-website closing", e);
});
}
mediaManager.removeTriggerCloseJitsiFrameButton("close-jitsi");
}
//todo: put this into an 'orchestrator' scene (EntryScene?)

View File

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

View File

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

View File

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

View File

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

View File

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

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 layoutManagerVisibilityStore = derived(layoutManagerActionStore, ($layoutManagerActionStore) => {
export const layoutManagerActionVisibilityStore = derived(layoutManagerActionStore, ($layoutManagerActionStore) => {
return !!$layoutManagerActionStore.length;
});

View File

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

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 { peerStore } from "./PeerStore";
import type { LocalStreamStoreValue } from "./MediaStore";
import { gameOverlayVisibilityStore } from "./GameOverlayStoreVisibility";
import { myCameraVisibilityStore } from "./MyCameraStoreVisibility";
declare const navigator: any; // eslint-disable-line @typescript-eslint/no-explicit-any
@ -41,8 +41,8 @@ let previousComputedAudioConstraint: boolean | MediaTrackConstraints = false;
* A store containing the media constraints we want to apply.
*/
export const screenSharingConstraintsStore = derived(
[requestedScreenSharingState, gameOverlayVisibilityStore, peerStore],
([$requestedScreenSharingState, $gameOverlayVisibilityStore, $peerStore], set) => {
[requestedScreenSharingState, myCameraVisibilityStore, peerStore],
([$requestedScreenSharingState, $myCameraVisibilityStore, $peerStore], set) => {
let currentVideoConstraint: boolean | MediaTrackConstraints = true;
let currentAudioConstraint: boolean | MediaTrackConstraints = false;
@ -53,7 +53,7 @@ export const screenSharingConstraintsStore = derived(
}
// Disable screen sharing when in a Jitsi
if (!$gameOverlayVisibilityStore) {
if (!$myCameraVisibilityStore) {
currentVideoConstraint = false;
currentAudioConstraint = false;
}

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

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

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

View File

@ -7,6 +7,7 @@ interface jitsiConfigInterface {
startWithAudioMuted: boolean;
startWithVideoMuted: boolean;
prejoinPageEnabled: boolean;
disableDeepLinking: boolean;
}
interface JitsiOptions {
@ -40,6 +41,7 @@ const getDefaultConfig = (): jitsiConfigInterface => {
startWithAudioMuted: !get(requestedMicrophoneState),
startWithVideoMuted: !get(requestedCameraState),
prejoinPageEnabled: false,
disableDeepLinking: false,
};
};
@ -135,64 +137,112 @@ class JitsiFactory {
return slugify(instance.replace("/", "-") + "-" + roomName);
}
public start(
public async start(
roomName: string,
playerName: string,
jwt?: string,
config?: object,
interfaceConfig?: object,
jitsiUrl?: string,
jitsiWidth?: number
): Promise<CoWebsite> {
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");
jitsiUrl?: string
) {
const coWebsite = coWebsiteManager.searchJitsi();
const domain = jitsiUrl || JITSI_URL;
if (domain === undefined) {
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
}
await this.loadJitsiScript(domain);
if (coWebsite) {
await coWebsiteManager.closeCoWebsite(coWebsite);
}
const options: JitsiOptions = {
roomName: roomName,
jwt: jwt,
width: "100%",
height: "100%",
parentNode: cowebsiteDiv,
configOverwrite: mergeConfig(config),
interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig },
};
if (!options.jwt) {
delete options.jwt;
}
// 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");
return new Promise((resolve, reject) => {
const doResolve = (): void => {
const iframe = cowebsiteDiv.querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
if (iframe === null) {
throw new Error("Could not find Jitsi Iframe");
}
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);
const domain = jitsiUrl || JITSI_URL;
if (domain === undefined) {
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
}
await this.loadJitsiScript(domain);
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
const options: JitsiOptions = {
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,
0
);
this.jitsiApi.addListener("readyToClose", () => {
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() {
@ -200,14 +250,16 @@ class JitsiFactory {
return;
}
const jitsiCoWebsite = coWebsiteManager.searchJitsi();
if (jitsiCoWebsite) {
coWebsiteManager.closeJitsi().catch((e) => console.error(e));
}
this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback);
this.jitsiApi.removeListener("videoMuteStatusChanged", this.videoCallback);
}
public destroy() {
if (!this.jitsiApi) {
return;
}
this.stop();
this.jitsiApi?.dispose();
}

View File

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

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@ const error: NonNullable<Translation["error"]> = {
title: "Verbindungen zurückgewiesen",
subTitle: "Du kannst diese Welt nicht betreten. Versuche es später noch einmal {error}.",
details:
"Für weitere Information kannst du die Administratoren kontaktieren oder melde dich bei uns unter: prty.bstly.de",
"Für weitere Information kannst du die Administratoren kontaktieren oder melde dich bei uns unter: prty@bstly.de",
},
connectionRetry: {
unableConnect:

View File

@ -4,15 +4,15 @@ import audio from "./audio";
import camera from "./camera";
import chat from "./chat";
import companion from "./companion";
import emoji from "./emoji";
import error from "./error";
import follow from "./follow";
import login from "./login";
import menu from "./menu";
import message from "./message";
import menu from "./menu";
import report from "./report";
import warning from "./warning";
import woka from "./woka";
import emoji from "./emoji";
const de_DE: Translation = {
...en_US,

View File

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

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 {
--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. */
#cowebsite {
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;
}
}
}
@import "cowebsite/global";
@import "cowebsite/short-screens";
@import "cowebsite/wide-screens";

View File

@ -0,0 +1,126 @@
#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);
}
#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";
@font-face {
font-family: "Twemoji Mozilla";
src: url("./fonts/TwemojiMozilla.ttf") format('truetype');
}
*{
font-family: "Press Start 2P",monospace;
}

Binary file not shown.

View File

@ -1,9 +1,9 @@
@import "~nes.css/css/nes.min.css";
@import "nes.custom.css";
@import "quill.snow.css";
@charset 'UTF-8';
@import "breakpoints";
@import "cowebsite.scss";
@import "cowebsite-mobile.scss";
@import "style";
@import "mobile-style.scss";
@import "fonts.scss";
@import "style";
@import "TextGlobalMessageSvelte-Style";

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

@ -32,14 +32,16 @@ body .message-info.warning{
}
.video-container {
position: relative;
display: flex;
transition: all 0.2s ease;
height: 100%;
width: 100%;
video {
height: fit-content;
max-height: 100%;
max-width: 100%;
width: 100%;
height: 100%;
object-fit: cover;
&.mobile{
width: 100%;
@ -130,31 +132,6 @@ body .message-info.warning{
}
}
.video-container.div-myCamVideo{
border: none;
}
.div-myCamVideo {
position: absolute !important;
right: 15px;
bottom: 30px;
max-height: 20%;
transition: right 350ms;
}
.div-myCamVideo.hide {
right: -20vw;
}
video.myCamVideo{
max-height: 20vh;
width: 15vw;
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
/*width: 200px;*/
/*height: 113px;*/
}
.sound-progress{
display: none;
position: absolute;
@ -191,89 +168,6 @@ video.myCamVideo{
top: calc(50% - 20px);
}
.btn-cam-action {
pointer-events: all;
position: absolute;
display: inline-flex;
bottom: 10px;
right: 15px;
width: 240px;
height: 40px;
text-align: center;
align-content: center;
align-items: center;
justify-content: flex-end;
justify-items: center;
}
/*btn animation*/
.btn-cam-action div{
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
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;
pointer-events: all;
}
/* Spinner */
.connecting-spinner {
/*display: inline-block;*/
@ -344,26 +238,6 @@ body {
position: absolute;
}
@media (min-aspect-ratio: 1/1) {
.game-overlay {
flex-direction: row;
}
.sidebar {
flex-direction: column;
}
.sidebar > div {
max-height: 21%;
}
.sidebar > div:hover {
max-height: 25%;
}
}
#game {
position: relative; /* Position relative is needed for the game-overlay. */
@ -461,89 +335,6 @@ input[type=range]:focus::-ms-fill-upper {
background: #FFFFFF;
}
.game-overlay {
display: none;
position: absolute;
width: 100%;
height: 100%;
pointer-events: none;
/* TODO: DO WE NEED FLEX HERE???? WE WANT A SIDEBAR OF EXACTLY 25% (note: flex useful for direction!!!) */
}
.game-overlay + div {
pointer-events: none;
}
.game-overlay + div > div {
pointer-events: auto;
}
.game-overlay.active {
display: flex;
}
.game-overlay video {
width: 100%;
}
.main-section {
flex: 0 0 75%;
display: flex;
justify-content: start;
align-items: flex-start;
flex-wrap: wrap;
}
.main-section > div {
margin: 2%;
flex-basis: 96%;
transition: margin-left 0.2s, margin-right 0.2s, margin-bottom 0.2s, margin-top 0.2s, flex-basis 0.2s;
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;
pointer-events: auto;
video {
max-height: 21vh;
}
}
.sidebar > div:hover {
margin: 0%;
}
/* Let's make sure videos are vertically centered if they need to be cropped */
.media-container {
display: flex;
flex-direction: column;
overflow: hidden;
}
.chat-mode {
display: grid;
width: 100%;
align-items: flex-start;
padding: 1%;
}
.chat-mode > div {
margin: 1%;
max-height: 96%;
@ -1020,13 +811,22 @@ div.action.danger p.action-body{
}
#svelte-overlay {
#game-overlay {
position: absolute;
width: 100%;
height: 100%;
pointer-events: none;
user-select: none;
& + div {
pointer-events: none;
z-index: 2;
}
& + div > div {
pointer-events: auto;
}
& > div {
position: relative;
width: 100%;
@ -1044,19 +844,10 @@ div.action.danger p.action-body{
pointer-events: auto;
}
}
}
div.is-silent {
position: absolute !important;
bottom: 40px;
max-height: 20%;
transition: right 350ms;
right: -1000px;
font-size: 20px;
padding: 30px 20px;
}
div.is-silent.hide {
right: 15px;
&.hide {
visibility: hidden;
}
}
@ -1085,11 +876,6 @@ div.is-silent.hide {
supported by Chrome, Edge, Opera and Firefox */
}
.pixel {
height: 1px !important;
width: 1px !important;
}
.emote-menu .emoji-picker .emoji-picker__emoji {
font-family: 'Twemoji Mozilla' !important;
}
}

View File

@ -1,8 +1,7 @@
#!/usr/bin/env bash
set -x
set -o nounset errexit
template_file_index=dist/index.tmpl.html
generated_file_index=dist/index.tmpl.html.tmp
index_file=dist/index.html
tmp_trackcodefile=/tmp/trackcode
# To inject tracking code, you have two choices:
@ -21,6 +20,6 @@ if [[ "${GA_TRACKING_ID:-}" != "" || "${INSERT_ANALYTICS:-NO}" != "NO" ]]; then
sed "s#<!-- TRACKING NUMBER -->#${GA_TRACKING_ID:-}#g" "${ANALYTICS_CODE_PATH}" > "$tmp_trackcodefile"
fi
echo "Templating ${generated_file_index} from ${template_file_index}"
sed "/<!-- TRACK CODE -->/r ${tmp_trackcodefile}" "${template_file_index}" > "${generated_file_index}"
echo "Templating ${index_file}"
sed --in-place "/<!-- TRACK CODE -->/r ${tmp_trackcodefile}" "${index_file}"
rm "${tmp_trackcodefile}"

View File

@ -1,6 +1,8 @@
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
import fs from 'fs/promises';
import HtmlWebpackPlugin from "html-webpack-plugin";
import MiniCssExtractPlugin from "mini-css-extract-plugin";
import CssMinimizerPlugin from "css-minimizer-webpack-plugin";
import NodePolyfillPlugin from "node-polyfill-webpack-plugin";
import path from "path";
import sveltePreprocess from "svelte-preprocess";
@ -33,6 +35,35 @@ module.exports = {
disableDotRule: true,
},
liveReload: process.env.LIVE_RELOAD != "0" && process.env.LIVE_RELOAD != "false",
before: (app) => {
let appConfigContent = '';
const TEMPLATE_PATH = path.join(__dirname, 'dist', 'env-config.template.js');
function renderTemplateWithEnvVars(content: string): string {
let result = content;
const regex = /\$\{([a-zA-Z_]+[a-zA-Z0-9_]*?)\}/g;
let matched: RegExpExecArray | null;
while ((matched = regex.exec(content))) {
result = result.replace(`\${${matched[1]}}`, process.env[matched[1]] || '');
}
return result;
}
void (async () => {
const content = (await fs.readFile(TEMPLATE_PATH)).toString();
appConfigContent = renderTemplateWithEnvVars(content);
})();
app.get('/env-config.js', (_, response) => {
response.setHeader('Content-Type', 'application/javascript; charset=utf-8');
response.setHeader('Cache-Control', 'no-cache');
response.setHeader('Content-Length', Buffer.byteLength(appConfigContent, 'utf8'));
response.send(appConfigContent);
});
},
},
module: {
rules: [
@ -49,33 +80,9 @@ module.exports = {
},
},
{
test: /\.scss$/,
test: /\.(sc|c)ss$/,
exclude: /node_modules/,
use: [
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,
},
},
],
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
{
test: /\.(html|svelte)$/,
@ -155,6 +162,10 @@ module.exports = {
extensions: [".tsx", ".ts", ".js", ".svelte"],
mainFields: ["svelte", "browser", "module", "main"],
},
optimization: {
minimize: isProduction,
minimizer: [new CssMinimizerPlugin(), "..."],
},
output: {
filename: (pathData) => {
// Add a content hash only for the main bundle.
@ -173,7 +184,7 @@ module.exports = {
}),
new MiniCssExtractPlugin({ filename: "[name].[contenthash].css" }),
new HtmlWebpackPlugin({
template: "./dist/index.tmpl.html.tmp",
template: "./dist/index.ejs",
minify: {
collapseWhitespace: true,
keepClosingSlash: true,
@ -189,33 +200,5 @@ module.exports = {
Phaser: "phaser",
}),
new NodePolyfillPlugin(),
new webpack.EnvironmentPlugin({
API_URL: null,
SKIP_RENDER_OPTIMIZATIONS: false,
DISABLE_NOTIFICATIONS: false,
PUSHER_URL: undefined,
UPLOADER_URL: null,
ADMIN_URL: null,
CONTACT_URL: null,
PROFILE_URL: null,
ICON_URL: null,
DEBUG_MODE: null,
STUN_SERVER: null,
TURN_SERVER: null,
TURN_USER: null,
TURN_PASSWORD: null,
JITSI_URL: null,
JITSI_PRIVATE_MODE: null,
START_ROOM_URL: null,
MAX_USERNAME_LENGTH: 8,
MAX_PER_GROUP: 4,
DISPLAY_TERMS_OF_USE: false,
POSTHOG_API_KEY: null,
POSTHOG_URL: null,
NODE_ENV: mode,
DISABLE_ANONYMOUS: false,
OPID_LOGIN_SCREEN_PROVIDER: null,
FALLBACK_LANGUAGE: null,
}),
],
} as Configuration & WebpackDevServer.Configuration;

View File

@ -208,6 +208,11 @@
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853"
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":
version "1.0.8"
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"
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:
version "3.5.2"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
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:
version "6.12.6"
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"
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:
version "3.2.4"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
@ -1212,6 +1246,17 @@ browserify-zlib@^0.2.0:
dependencies:
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:
version "4.16.6"
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"
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:
version "1.0.30001228"
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"
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:
version "1.2.2"
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"
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:
version "5.2.4"
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"
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:
version "2.1.0"
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"
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:
version "3.4.2"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4"
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:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
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:
version "1.4.0"
resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.4.0.tgz#bca11d867f5d3f1b9ed9f737bd15970c65dff5c8"
@ -1983,10 +2147,10 @@ domhandler@^2.3.0:
dependencies:
domelementtype "1"
domhandler@^4.0.0, domhandler@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
domhandler@^4.0.0, 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"
@ -1998,10 +2162,10 @@ domutils@^1.5.1, domutils@^1.7.0:
dom-serializer "0"
domelementtype "1"
domutils@^2.5.2:
version "2.6.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.6.0.tgz#2e15c04185d43fb16ae7057cb76433c6edb938b7"
integrity sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==
domutils@^2.5.2, 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"
@ -2032,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"
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:
version "6.5.4"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
@ -3581,6 +3750,15 @@ jest-worker@^26.6.2:
merge-stream "^2.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:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -3608,6 +3786,11 @@ json-schema-traverse@^0.4.1:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
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:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
@ -3699,6 +3882,11 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
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:
version "1.1.6"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
@ -3787,11 +3975,21 @@ lodash.isequal@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
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:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
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:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
@ -3870,6 +4068,11 @@ md5.js@^1.3.4:
inherits "^2.0.1"
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:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -4071,7 +4274,7 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
nanoid@^3.1.23:
nanoid@^3.1.23, nanoid@^3.1.30:
version "3.2.0"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c"
integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==
@ -4166,6 +4369,11 @@ node-releases@^1.1.71:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe"
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:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
@ -4188,6 +4396,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"
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:
version "4.1.5"
resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba"
@ -4224,6 +4437,13 @@ nth-check@^1.0.2:
dependencies:
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:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@ -4599,6 +4819,11 @@ phaser@^3.54.0:
eventemitter3 "^4.0.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:
version "2.2.3"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d"
@ -4671,6 +4896,103 @@ posix-character-classes@^0.1.0:
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
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:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
@ -4699,6 +5021,96 @@ postcss-modules-values@^4.0.0:
dependencies:
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:
version "6.0.6"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea"
@ -4707,6 +5119,35 @@ postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
cssesc "^3.0.0"
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:
version "4.1.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
@ -4730,6 +5171,15 @@ postcss@^8.2.10:
nanoid "^3.1.23"
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:
version "1.14.1"
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.14.1.tgz#68553b9074c686784b994b3f433ad035b241deaa"
@ -5057,6 +5507,11 @@ require-directory@^2.1.1:
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
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:
version "2.0.0"
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
@ -5262,6 +5717,16 @@ schema-utils@^3.0.0:
ajv "^6.12.5"
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:
version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@ -5322,6 +5787,13 @@ serialize-javascript@^5.0.1:
dependencies:
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:
version "1.9.1"
resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
@ -5547,6 +6019,11 @@ source-map-js@^0.6.2:
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
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:
version "0.5.3"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
@ -5642,6 +6119,11 @@ split-string@^3.0.1, split-string@^3.0.2:
dependencies:
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:
version "25.2.4"
resolved "https://registry.yarnpkg.com/standardized-audio-context/-/standardized-audio-context-25.2.4.tgz#d64dbdd70615171ec90d1b7151a0d945af94cf3d"
@ -5808,6 +6290,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"
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:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@ -5829,6 +6319,13 @@ supports-color@^7.0.0, supports-color@^7.1.0:
dependencies:
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:
version "2.1.0"
resolved "https://registry.yarnpkg.com/svelte-check/-/svelte-check-2.1.0.tgz#3ee8ad86068256346ebca862bbee8417a757fc53"
@ -5878,6 +6375,19 @@ svelte@^3.38.2:
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.38.2.tgz#55e5c681f793ae349b5cc2fe58e5782af4275ef5"
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:
version "4.0.0"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261"
@ -5945,6 +6455,11 @@ timers-browserify@^2.0.12:
dependencies:
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:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
@ -6573,7 +7088,7 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
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"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==

Some files were not shown because too many files have changed in this diff Show More