Merge pull request #1437 from Lurkars/twemojiEmoteMenuSvelte

Twemoji emote menu svelte (upgrade of #1301)
This commit is contained in:
Kharhamel 2021-09-20 14:33:16 +02:00 committed by GitHub
commit 9b13a6780c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 355 additions and 169 deletions

View File

@ -40,6 +40,7 @@
},
"dependencies": {
"@fontsource/press-start-2p": "^4.3.0",
"@joeattardi/emoji-button": "^4.6.0",
"@types/simple-peer": "^9.11.1",
"@types/socket.io-client": "^1.4.32",
"axios": "^0.21.1",

View File

@ -1,13 +1,12 @@
import { POSTHOG_API_KEY, POSTHOG_URL } from "../Enum/EnvironmentVariable";
class AnalyticsClient {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private posthogPromise: Promise<any>;
constructor() {
if (POSTHOG_API_KEY && POSTHOG_URL) {
this.posthogPromise = import('posthog-js').then(({default: posthog}) => {
this.posthogPromise = import("posthog-js").then(({ default: posthog }) => {
posthog.init(POSTHOG_API_KEY, { api_host: POSTHOG_URL, disable_cookie: true });
return posthog;
});
@ -17,45 +16,59 @@ class AnalyticsClient {
}
identifyUser(uuid: string) {
this.posthogPromise.then(posthog => {
this.posthogPromise
.then((posthog) => {
posthog.identify(uuid, { uuid, wa: true });
}).catch();
})
.catch();
}
loggedWithSso() {
this.posthogPromise.then(posthog => {
posthog.capture('wa-logged-sso');
}).catch();
this.posthogPromise
.then((posthog) => {
posthog.capture("wa-logged-sso");
})
.catch();
}
loggedWithToken() {
this.posthogPromise.then(posthog => {
posthog.capture('wa-logged-token');
}).catch();
this.posthogPromise
.then((posthog) => {
posthog.capture("wa-logged-token");
})
.catch();
}
enteredRoom(roomId: string) {
this.posthogPromise.then(posthog => {
posthog.capture('$pageView', {roomId});
}).catch();
this.posthogPromise
.then((posthog) => {
posthog.capture("$pageView", { roomId });
})
.catch();
}
openedMenu() {
this.posthogPromise.then(posthog => {
posthog.capture('wa-opened-menu');
}).catch();
this.posthogPromise
.then((posthog) => {
posthog.capture("wa-opened-menu");
})
.catch();
}
launchEmote(emote: string) {
this.posthogPromise.then(posthog => {
posthog.capture('wa-emote-launch', {emote});
}).catch();
this.posthogPromise
.then((posthog) => {
posthog.capture("wa-emote-launch", { emote });
})
.catch();
}
enteredJitsi(roomName: string, roomId: string) {
this.posthogPromise.then(posthog => {
posthog.capture('wa-entered-jitsi', {roomName, roomId});
}).catch();
this.posthogPromise
.then((posthog) => {
posthog.capture("wa-entered-jitsi", { roomName, roomId });
})
.catch();
}
}
export const analyticsClient = new AnalyticsClient();

View File

@ -1,6 +1,7 @@
<script lang="typescript">
import MenuIcon from "./Menu/MenuIcon.svelte";
import {menuIconVisiblilityStore, menuVisiblilityStore} from "../Stores/MenuStore";
import {emoteMenuVisiblilityStore} from "../Stores/EmoteStore";
import {enableCameraSceneVisibilityStore} from "../Stores/MediaStore";
import CameraControls from "./CameraControls.svelte";
import MyCamera from "./MyCamera.svelte";
@ -26,6 +27,7 @@
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
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 AdminMessage from "./TypeMessage/BanMessage.svelte";
@ -111,6 +113,11 @@
<Menu></Menu>
</div>
{/if}
{#if $emoteMenuVisiblilityStore}
<div>
<EmoteMenu></EmoteMenu>
</div>
{/if}
{#if $gameOverlayVisibilityStore}
<div>
<VideoOverlay></VideoOverlay>

View File

@ -0,0 +1,75 @@
<script lang="typescript">
import type { Unsubscriber } from "svelte/store";
import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore";
import { onDestroy, onMount } from "svelte";
import { EmojiButton } from '@joeattardi/emoji-button';
import { isMobile } from "../../Enum/EnvironmentVariable";
let emojiContainer: HTMLElement;
let picker: EmojiButton;
let unsubscriber: Unsubscriber | null = null;
onMount(() => {
picker = new EmojiButton({
rootElement: emojiContainer,
styleProperties: {
'--font': 'Press Start 2P'
},
emojisPerRow: isMobile() ? 6 : 8,
autoFocusSearch: false
});
picker.on("emoji", (selection) => {
emoteStore.set(selection.emoji);
});
picker.on("hidden", () => {
emoteMenuStore.closeEmoteMenu();
});
unsubscriber = emoteMenuStore.subscribe((isEmoteMenuVisible) => {
if (isEmoteMenuVisible && !picker.isPickerVisible()) {
picker.showPicker(emojiContainer);
} else {
picker.hidePicker();
}
})
})
function onKeyDown(e:KeyboardEvent) {
if (e.key === 'Escape') {
emoteMenuStore.closeEmoteMenu();
}
}
onDestroy(() => {
if (unsubscriber) {
unsubscriber();
}
picker.destroyPicker();
})
</script>
<svelte:window on:keydown={onKeyDown}/>
<div class="emote-menu-container">
<div class="emote-menu" bind:this={emojiContainer}></div>
</div>
<style lang="scss">
.emote-menu-container {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
}
.emote-menu {
pointer-events: all;
}
</style>

View File

@ -2,15 +2,15 @@ import { Subject } from "rxjs";
interface EmoteEvent {
userId: number;
emoteName: string;
emote: string;
}
class EmoteEventStream {
private _stream: Subject<EmoteEvent> = new Subject();
public stream = this._stream.asObservable();
fire(userId: number, emoteName: string) {
this._stream.next({ userId, emoteName });
fire(userId: number, emote: string) {
this._stream.next({ userId, emote });
}
}

View File

@ -20,7 +20,7 @@ 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_API_KEY: string = (process.env.POSTHOG_API_KEY as string) || "";
export const POSTHOG_URL = process.env.POSTHOG_URL || undefined;
export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600;

View File

@ -32,7 +32,7 @@ export abstract class Character extends Container {
//private teleportation: Sprite;
private invisible: boolean;
public companion?: Companion;
private emote: Phaser.GameObjects.Sprite | null = null;
private emote: Phaser.GameObjects.Text | null = null;
private emoteTween: Phaser.Tweens.Tween | null = null;
scene: GameScene;
@ -289,44 +289,38 @@ export abstract class Character extends Container {
isSilentStore.set(false);
}
playEmote(emoteKey: string) {
playEmote(emote: string) {
this.cancelPreviousEmote();
const scalingFactor = waScaleManager.uiScalingFactor * 0.05;
const emoteY = -30 - scalingFactor * 10;
const emoteY = -45;
this.playerName.setVisible(false);
this.emote = new Sprite(this.scene, 0, 0, emoteKey);
this.emote = new Text(this.scene, -10, 0, emote, { fontFamily: '"twemoji"', fontSize: "20px" });
this.emote.setAlpha(0);
this.emote.setScale(0.1 * scalingFactor);
this.add(this.emote);
this.scene.sys.updateList.add(this.emote);
this.createStartTransition(scalingFactor, emoteY);
this.createStartTransition(emoteY);
}
private createStartTransition(scalingFactor: number, emoteY: number) {
private createStartTransition(emoteY: number) {
this.emoteTween = this.scene?.tweens.add({
targets: this.emote,
props: {
scale: scalingFactor,
alpha: 1,
y: emoteY,
},
ease: "Power2",
duration: 500,
onComplete: () => {
this.startPulseTransition(emoteY, scalingFactor);
this.startPulseTransition(emoteY);
},
});
}
private startPulseTransition(emoteY: number, scalingFactor: number) {
private startPulseTransition(emoteY: number) {
if (this.emote) {
this.emoteTween = this.scene?.tweens.add({
targets: this.emote,
props: {
y: emoteY * 1.3,
scale: scalingFactor * 1.1,
scale: this.emote.scale * 1.1,
},
duration: 250,
yoyo: true,
@ -337,6 +331,7 @@ export abstract class Character extends Container {
},
});
}
}
private startExitTransition(emoteY: number) {
this.emoteTween = this.scene?.tweens.add({

View File

@ -1,24 +1,7 @@
import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures";
import { emoteEventStream } from "../../Connexion/EmoteEventStream";
import type { GameScene } from "./GameScene";
import type { RadialMenuItem } from "../Components/RadialMenu";
import LoaderPlugin = Phaser.Loader.LoaderPlugin;
import type { Subscription } from "rxjs";
interface RegisteredEmote extends BodyResourceDescriptionInterface {
name: string;
img: string;
}
export const emotes: { [key: string]: RegisteredEmote } = {
"emote-heart": { name: "emote-heart", img: "resources/emotes/heart-emote.png" },
"emote-clap": { name: "emote-clap", img: "resources/emotes/clap-emote.png" },
"emote-hand": { name: "emote-hand", img: "resources/emotes/hand-emote.png" },
"emote-thanks": { name: "emote-thanks", img: "resources/emotes/thanks-emote.png" },
"emote-thumb-up": { name: "emote-thumb-up", img: "resources/emotes/thumb-up-emote.png" },
"emote-thumb-down": { name: "emote-thumb-down", img: "resources/emotes/thumb-down-emote.png" },
};
export class EmoteManager {
private subscription: Subscription;
@ -26,47 +9,10 @@ export class EmoteManager {
this.subscription = emoteEventStream.stream.subscribe((event) => {
const actor = this.scene.MapPlayersByKey.get(event.userId);
if (actor) {
this.lazyLoadEmoteTexture(event.emoteName).then((emoteKey) => {
actor.playEmote(emoteKey);
});
actor.playEmote(event.emote);
}
});
}
createLoadingPromise(loadPlugin: LoaderPlugin, playerResourceDescriptor: BodyResourceDescriptionInterface) {
return new Promise<string>((res) => {
if (loadPlugin.textureManager.exists(playerResourceDescriptor.name)) {
return res(playerResourceDescriptor.name);
}
loadPlugin.image(playerResourceDescriptor.name, playerResourceDescriptor.img);
loadPlugin.once("filecomplete-image-" + playerResourceDescriptor.name, () =>
res(playerResourceDescriptor.name)
);
});
}
lazyLoadEmoteTexture(textureKey: string): Promise<string> {
const emoteDescriptor = emotes[textureKey];
if (emoteDescriptor === undefined) {
throw "Emote not found!";
}
const loadPromise = this.createLoadingPromise(this.scene.load, emoteDescriptor);
this.scene.load.start();
return loadPromise;
}
getMenuImages(): Promise<RadialMenuItem[]> {
const promises = [];
for (const key in emotes) {
const promise = this.lazyLoadEmoteTexture(key).then((textureKey) => {
return {
image: textureKey,
name: textureKey,
};
});
promises.push(promise);
}
return Promise.all(promises);
}
destroy() {
this.subscription.unsubscribe();

View File

@ -9,6 +9,7 @@ import { get } from "svelte/store";
import { requestedCameraState, requestedMicrophoneState } from "../../Stores/MediaStore";
import { helpCameraSettingsVisibleStore } from "../../Stores/HelpCameraSettingsStore";
import { menuIconVisiblilityStore } from "../../Stores/MenuStore";
import { emoteMenuVisiblilityStore } from "../../Stores/EmoteStore";
/**
* This class should be responsible for any scene starting/stopping
@ -111,6 +112,7 @@ export class GameManager {
public gameSceneIsCreated(scene: GameScene) {
this.currentGameSceneName = scene.scene.key;
menuIconVisiblilityStore.set(true);
emoteMenuVisiblilityStore.set(true);
}
/**
@ -123,6 +125,7 @@ export class GameManager {
gameScene.cleanupClosingScene();
gameScene.createSuccessorGameScene(false, false);
menuIconVisiblilityStore.set(false);
emoteMenuVisiblilityStore.set(false);
if (!this.scenePlugin.get(targetSceneName)) {
this.scenePlugin.add(targetSceneName, sceneClass, false);
}
@ -136,6 +139,7 @@ export class GameManager {
if (this.currentGameSceneName) {
this.scenePlugin.start(this.currentGameSceneName);
menuIconVisiblilityStore.set(true);
emoteMenuVisiblilityStore.set(true);
} else {
this.scenePlugin.run(fallbackSceneName);
}

View File

@ -82,6 +82,7 @@ import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStor
import { SharedVariablesManager } from "./SharedVariablesManager";
import { playersStore } from "../../Stores/PlayersStore";
import { chatVisibilityStore } from "../../Stores/ChatStore";
import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore";
import {
audioManagerFileStore,
audioManagerVisibilityStore,
@ -93,8 +94,8 @@ import { userIsAdminStore } from "../../Stores/GameStore";
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
import { GameMapPropertiesListener } from "./GameMapPropertiesListener";
import type { RadialMenuItem } from "../Components/RadialMenu";
import { analyticsClient } from "../../Administration/AnalyticsClient";
import { get } from "svelte/store";
export interface GameSceneInitInterface {
initPosition: PointInterface | null;
@ -172,6 +173,8 @@ export class GameScene extends DirtyScene {
private iframeSubscriptionList!: Array<Subscription>;
private peerStoreUnsubscribe!: () => void;
private chatVisibilityUnsubscribe!: () => void;
private emoteUnsubscribe!: () => void;
private emoteMenuUnsubscribe!: () => void;
private biggestAvailableAreaStoreUnsubscribe!: () => void;
MapUrlFile: string;
roomUrl: string;
@ -616,6 +619,22 @@ export class GameScene extends DirtyScene {
this.openChatIcon.setVisible(!v);
});
this.emoteUnsubscribe = emoteStore.subscribe((emoteKey) => {
if (emoteKey) {
this.CurrentPlayer?.playEmote(emoteKey);
this.connection?.emitEmoteEvent(emoteKey);
emoteStore.set(null);
}
});
this.emoteMenuUnsubscribe = emoteMenuStore.subscribe((emoteMenu) => {
if (emoteMenu) {
this.userInputManager.disableControls();
} else {
this.userInputManager.restoreControls();
}
});
Promise.all([this.connectionAnswerPromise as Promise<unknown>, ...scriptPromises]).then(() => {
this.scene.wake();
});
@ -1306,6 +1325,8 @@ ${escapedMessage}
this.emoteManager.destroy();
this.peerStoreUnsubscribe();
this.chatVisibilityUnsubscribe();
this.emoteUnsubscribe();
this.emoteMenuUnsubscribe();
this.biggestAvailableAreaStoreUnsubscribe();
iframeListener.unregisterAnswerer("getState");
iframeListener.unregisterAnswerer("loadTileset");
@ -1436,9 +1457,13 @@ ${escapedMessage}
if (pointer.wasTouch && (pointer.event as TouchEvent).touches.length > 1) {
return; //we don't want the menu to open when pinching on a touch screen.
}
this.emoteManager
.getMenuImages()
.then((emoteMenuElements) => this.CurrentPlayer.openOrCloseEmoteMenu(emoteMenuElements));
// toggle EmoteMenu
if (get(emoteMenuStore)) {
emoteMenuStore.closeEmoteMenu();
} else {
emoteMenuStore.openEmoteMenu();
}
});
this.CurrentPlayer.on(requestEmoteEventName, (emoteKey: string) => {
this.connection?.emitEmoteEvent(emoteKey);

View File

@ -3,7 +3,8 @@ import type { GameScene } from "../Game/GameScene";
import { UserInputEvent, UserInputManager } from "../UserInput/UserInputManager";
import { Character } from "../Entity/Character";
import { userMovingStore } from "../../Stores/GameStore";
import { RadialMenu, RadialMenuClickEvent, RadialMenuItem } from "../Components/RadialMenu";
import { get } from "svelte/store";
import { emoteMenuStore } from "../../Stores/EmoteStore";
export const hasMovedEventName = "hasMoved";
export const requestEmoteEventName = "requestEmote";
@ -11,8 +12,6 @@ export const requestEmoteEventName = "requestEmote";
export class Player extends Character {
private previousDirection: string = PlayerAnimationDirections.Down;
private wasMoving: boolean = false;
private emoteMenu: RadialMenu | null = null;
private updateListener: () => void;
constructor(
Scene: GameScene,
@ -30,14 +29,6 @@ export class Player extends Character {
//the current player model should be push away by other players to prevent conflict
this.getBody().setImmovable(false);
this.updateListener = () => {
if (this.emoteMenu) {
this.emoteMenu.x = this.x;
this.emoteMenu.y = this.y;
}
};
this.scene.events.addListener("postupdate", this.updateListener);
}
moveUser(delta: number): void {
@ -93,40 +84,4 @@ export class Player extends Character {
public isMoving(): boolean {
return this.wasMoving;
}
openOrCloseEmoteMenu(emotes: RadialMenuItem[]) {
if (this.emoteMenu) {
this.closeEmoteMenu();
} else {
this.openEmoteMenu(emotes);
}
}
openEmoteMenu(emotes: RadialMenuItem[]): void {
this.cancelPreviousEmote();
this.emoteMenu = new RadialMenu(this.scene, this.x, this.y, emotes);
this.emoteMenu.on(RadialMenuClickEvent, (item: RadialMenuItem) => {
this.closeEmoteMenu();
this.emit(requestEmoteEventName, item.name);
this.playEmote(item.name);
});
}
isSilent() {
super.isSilent();
}
noSilent() {
super.noSilent();
}
closeEmoteMenu(): void {
if (!this.emoteMenu) return;
this.emoteMenu.destroy();
this.emoteMenu = null;
}
destroy() {
this.scene.events.removeListener("postupdate", this.updateListener);
super.destroy();
}
}

View File

@ -0,0 +1,19 @@
import { writable } from "svelte/store";
function createEmoteMenuStore() {
const { subscribe, set } = writable(false);
return {
subscribe,
openEmoteMenu() {
set(true);
},
closeEmoteMenu() {
set(false);
},
};
}
export const emoteMenuVisiblilityStore = writable(false);
export const emoteStore = writable<string | null>(null);
export const emoteMenuStore = createEmoteMenuStore();

View File

@ -8,7 +8,7 @@ export const menuIconVisiblilityStore = writable(false);
export const menuVisiblilityStore = writable(false);
menuVisiblilityStore.subscribe((value) => {
if (value) analyticsClient.openedMenu();
})
});
export const menuInputFocusStore = writable(false);
export const userIsConnected = writable(false);

View File

@ -1,5 +1,14 @@
@import "~@fontsource/press-start-2p/index.css";
@font-face {
font-family: "Twemoji Mozilla";
src: url("./fonts/TwemojiMozilla.ttf") format('truetype');
}
*{
font-family: PixelFont-7,monospace;
}
.nes-btn {
font-family: "Press Start 2P";
}

Binary file not shown.

View File

@ -1102,3 +1102,16 @@ div.is-silent {
div.is-silent.hide {
right: 15px;
}
.emote-menu .emoji-picker .emoji-picker__emoji {
font-family: "Twemoji Mozilla" !important;
}
div.emoji-picker {
background-color: #333;
border-radius: 1em;
input.emoji-picker__search {
border-radius: 1em;
}
}

View File

@ -62,6 +62,48 @@
resolved "https://registry.yarnpkg.com/@fontsource/press-start-2p/-/press-start-2p-4.3.0.tgz#37124387f7fbfe7792b5fc9a1906b80d9aeda4c6"
integrity sha512-gmS4070EoZp5/6NUJ+tBnvtDiSmFcR+S+ClAOJ8NGFXDWOkO12yMnyGJEJaDCNCAMX0s2TQCcmr6qWKx5ad3RQ==
"@fortawesome/fontawesome-common-types@^0.2.35":
version "0.2.35"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.35.tgz#01dd3d054da07a00b764d78748df20daf2b317e9"
integrity sha512-IHUfxSEDS9dDGqYwIW7wTN6tn/O8E0n5PcAHz9cAaBoZw6UpG20IG/YM3NNLaGPwPqgjBAFjIURzqoQs3rrtuw==
"@fortawesome/fontawesome-svg-core@^1.2.28":
version "1.2.35"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.35.tgz#85aea8c25645fcec88d35f2eb1045c38d3e65cff"
integrity sha512-uLEXifXIL7hnh2sNZQrIJWNol7cTVIzwI+4qcBIq9QWaZqUblm0IDrtSqbNg+3SQf8SMGHkiSigD++rHmCHjBg==
dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.35"
"@fortawesome/free-regular-svg-icons@^5.13.0":
version "5.15.3"
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.3.tgz#1ec4f2410ff638db549c5c5484fc60b66407dbe6"
integrity sha512-q4/p8Xehy9qiVTdDWHL4Z+o5PCLRChePGZRTXkl+/Z7erDVL8VcZUuqzJjs6gUz6czss4VIPBRdCz6wP37/zMQ==
dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.35"
"@fortawesome/free-solid-svg-icons@^5.13.0":
version "5.15.3"
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.3.tgz#52eebe354f60dc77e0bde934ffc5c75ffd04f9d8"
integrity sha512-XPeeu1IlGYqz4VWGRAT5ukNMd4VHUEEJ7ysZ7pSSgaEtNvSo+FLurybGJVmiqkQdK50OkSja2bfZXOeyMGRD8Q==
dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.35"
"@joeattardi/emoji-button@^4.6.0":
version "4.6.0"
resolved "https://registry.yarnpkg.com/@joeattardi/emoji-button/-/emoji-button-4.6.0.tgz#93a78abb19c61ce9dcc464d15f373743b15cd2a2"
integrity sha512-KwOE1j+YxX47JmT0pXNCa+9Ai4Wf2fmABtvuxy6JBJ5QV0HdoThRKjL6CxAreVwwLbNQ/PDoR36xpc5QJjLXPA==
dependencies:
"@fortawesome/fontawesome-svg-core" "^1.2.28"
"@fortawesome/free-regular-svg-icons" "^5.13.0"
"@fortawesome/free-solid-svg-icons" "^5.13.0"
"@popperjs/core" "^2.4.0"
"@types/twemoji" "^12.1.1"
focus-trap "^5.1.0"
fuzzysort "^1.1.4"
tiny-emitter "^2.1.0"
tslib "^2.0.0"
twemoji "^13.0.0"
"@nodelib/fs.scandir@2.1.4":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69"
@ -83,6 +125,10 @@
"@nodelib/fs.scandir" "2.1.4"
fastq "^1.6.0"
"@popperjs/core@^2.4.0":
version "2.9.2"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.2.tgz#adea7b6953cbb34651766b0548468e743c6a2353"
integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q==
"@sentry/types@^6.11.0":
version "6.12.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853"
@ -289,6 +335,11 @@
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.7.tgz#545158342f949e8fd3bfd813224971ecddc3fac4"
integrity sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ==
"@types/twemoji@^12.1.1":
version "12.1.2"
resolved "https://registry.yarnpkg.com/@types/twemoji/-/twemoji-12.1.2.tgz#52578fd22665311e6a78d04f800275449d51c97e"
integrity sha512-3eMyKenMi0R1CeKzBYtk/Z2JIHsTMQrIrTah0q54o45pHTpWVNofU2oHx0jS8tqsDRhis2TbB6238WP9oh2l2w==
"@types/uglify-js@*":
version "3.13.0"
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.0.tgz#1cad8df1fb0b143c5aba08de5712ea9d1ff71124"
@ -2381,6 +2432,14 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469"
integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
focus-trap@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-5.1.0.tgz#64a0bfabd95c382103397dbc96bfef3a3cf8e5ad"
integrity sha512-CkB/nrO55069QAUjWFBpX6oc+9V90Qhgpe6fBWApzruMq5gnlh90Oo7iSSDK7pKiV5ugG6OY2AXM5mxcmL3lwQ==
dependencies:
tabbable "^4.0.0"
xtend "^4.0.1"
follow-redirects@^1.0.0, follow-redirects@^1.10.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43"
@ -2432,6 +2491,15 @@ fresh@0.5.2:
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
fs-extra@^8.0.1:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-extra@^9.0.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
@ -2475,6 +2543,11 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
fuzzysort@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/fuzzysort/-/fuzzysort-1.1.4.tgz#a0510206ed44532cbb52cf797bf5a3cb12acd4ba"
integrity sha512-JzK/lHjVZ6joAg3OnCjylwYXYVjRiwTY6Yb25LvfpJHK8bjisfnZJ5bY8aVWwTwCXgxPNgLAtmHL+Hs5q1ddLQ==
generic-type-guard@^3.2.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/generic-type-guard/-/generic-type-guard-3.4.1.tgz#0896dc018de915c890562a34763858076e4676da"
@ -3346,6 +3419,22 @@ json5@^2.1.2:
dependencies:
minimist "^1.2.5"
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"
jsonfile@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-5.0.0.tgz#e6b718f73da420d612823996fdf14a03f6ff6922"
integrity sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==
dependencies:
universalify "^0.1.2"
optionalDependencies:
graceful-fs "^4.1.6"
jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
@ -5503,6 +5592,11 @@ svelte@^3.38.2:
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.38.2.tgz#55e5c681f793ae349b5cc2fe58e5782af4275ef5"
integrity sha512-q5Dq0/QHh4BLJyEVWGe7Cej5NWs040LWjMbicBGZ+3qpFWJ1YObRmUDZKbbovddLC9WW7THTj3kYbTOFmU9fbg==
tabbable@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261"
integrity sha512-H1XoH1URcBOa/rZZWxLxHCtOdVUEev+9vo5YdYhC9tCY4wnybX+VQrCYuy9ubkg69fCBxCONJOSLGfw0DWMffQ==
table@^6.0.4:
version "6.7.1"
resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2"
@ -5577,6 +5671,11 @@ timers-browserify@^2.0.12:
dependencies:
setimmediate "^1.0.4"
tiny-emitter@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
to-array@0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
@ -5656,6 +5755,11 @@ tslib@^1.8.1, tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
tslib@^2.0.3, tslib@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
@ -5673,6 +5777,21 @@ tty-browserify@^0.0.1:
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"
integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==
twemoji-parser@13.1.0:
version "13.1.0"
resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-13.1.0.tgz#65e7e449c59258791b22ac0b37077349127e3ea4"
integrity sha512-AQOzLJpYlpWMy8n+0ATyKKZzWlZBJN+G0C+5lhX7Ftc2PeEVdUU/7ns2Pn2vVje26AIZ/OHwFoUbdv6YYD/wGg==
twemoji@^13.0.0:
version "13.1.0"
resolved "https://registry.yarnpkg.com/twemoji/-/twemoji-13.1.0.tgz#65bb71e966dae56f0d42c30176f04cbdae109913"
integrity sha512-e3fZRl2S9UQQdBFLYXtTBT6o4vidJMnpWUAhJA+yLGR+kaUTZAt3PixC0cGvvxWSuq2MSz/o0rJraOXrWw/4Ew==
dependencies:
fs-extra "^8.0.1"
jsonfile "^5.0.0"
twemoji-parser "13.1.0"
universalify "^0.1.2"
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@ -5733,6 +5852,11 @@ union-value@^1.0.0:
is-extendable "^0.1.1"
set-value "^2.0.1"
universalify@^0.1.0, universalify@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
@ -6130,7 +6254,7 @@ xmlhttprequest-ssl@~1.6.2:
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz#03b713873b01659dfa2c1c5d056065b27ddc2de6"
integrity sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==
xtend@^4.0.2:
xtend@^4.0.1, xtend@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==