diff --git a/front/package.json b/front/package.json index 38c0570f..44d3fb22 100644 --- a/front/package.json +++ b/front/package.json @@ -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", diff --git a/front/src/Administration/AnalyticsClient.ts b/front/src/Administration/AnalyticsClient.ts index f3cde793..f73a1981 100644 --- a/front/src/Administration/AnalyticsClient.ts +++ b/front/src/Administration/AnalyticsClient.ts @@ -1,13 +1,12 @@ -import {POSTHOG_API_KEY, POSTHOG_URL} from "../Enum/EnvironmentVariable"; +import { POSTHOG_API_KEY, POSTHOG_URL } from "../Enum/EnvironmentVariable"; class AnalyticsClient { - // eslint-disable-next-line @typescript-eslint/no-explicit-any private posthogPromise: Promise; 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 => { - posthog.identify(uuid, { uuid, wa: true }); - }).catch(); + this.posthogPromise + .then((posthog) => { + posthog.identify(uuid, { uuid, wa: true }); + }) + .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(); diff --git a/front/src/Components/App.svelte b/front/src/Components/App.svelte index 8b033e5f..1fbcf76a 100644 --- a/front/src/Components/App.svelte +++ b/front/src/Components/App.svelte @@ -1,6 +1,7 @@ + + + +
+
+
+ + \ No newline at end of file diff --git a/front/src/Connexion/EmoteEventStream.ts b/front/src/Connexion/EmoteEventStream.ts index e8d01095..32f1daa0 100644 --- a/front/src/Connexion/EmoteEventStream.ts +++ b/front/src/Connexion/EmoteEventStream.ts @@ -2,15 +2,15 @@ import { Subject } from "rxjs"; interface EmoteEvent { userId: number; - emoteName: string; + emote: string; } class EmoteEventStream { private _stream: Subject = 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 }); } } diff --git a/front/src/Enum/EnvironmentVariable.ts b/front/src/Enum/EnvironmentVariable.ts index e724599c..c0c19f1c 100644 --- a/front/src/Enum/EnvironmentVariable.ts +++ b/front/src/Enum/EnvironmentVariable.ts @@ -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; diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 3f85d6e5..c2e89cb2 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -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,53 +289,48 @@ 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) { - this.emoteTween = this.scene?.tweens.add({ - targets: this.emote, - props: { - y: emoteY * 1.3, - scale: scalingFactor * 1.1, - }, - duration: 250, - yoyo: true, - repeat: 1, - completeDelay: 200, - onComplete: () => { - this.startExitTransition(emoteY); - }, - }); + private startPulseTransition(emoteY: number) { + if (this.emote) { + this.emoteTween = this.scene?.tweens.add({ + targets: this.emote, + props: { + y: emoteY * 1.3, + scale: this.emote.scale * 1.1, + }, + duration: 250, + yoyo: true, + repeat: 1, + completeDelay: 200, + onComplete: () => { + this.startExitTransition(emoteY); + }, + }); + } } private startExitTransition(emoteY: number) { diff --git a/front/src/Phaser/Game/EmoteManager.ts b/front/src/Phaser/Game/EmoteManager.ts index 7c6acd5b..06e8b099 100644 --- a/front/src/Phaser/Game/EmoteManager.ts +++ b/front/src/Phaser/Game/EmoteManager.ts @@ -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((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 { - 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 { - 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(); diff --git a/front/src/Phaser/Game/GameManager.ts b/front/src/Phaser/Game/GameManager.ts index 1bf18d8d..2539a368 100644 --- a/front/src/Phaser/Game/GameManager.ts +++ b/front/src/Phaser/Game/GameManager.ts @@ -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); } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index d28c795a..6e5a9902 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -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 { 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; 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, ...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); diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index c4e68dd3..3edcdcde 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -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(); - } } diff --git a/front/src/Stores/EmoteStore.ts b/front/src/Stores/EmoteStore.ts new file mode 100644 index 00000000..d41e92a8 --- /dev/null +++ b/front/src/Stores/EmoteStore.ts @@ -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(null); +export const emoteMenuStore = createEmoteMenuStore(); diff --git a/front/src/Stores/MenuStore.ts b/front/src/Stores/MenuStore.ts index 4a30a4e7..82e4b283 100644 --- a/front/src/Stores/MenuStore.ts +++ b/front/src/Stores/MenuStore.ts @@ -2,13 +2,13 @@ import { get, writable } from "svelte/store"; import Timeout = NodeJS.Timeout; import { userIsAdminStore } from "./GameStore"; import { CONTACT_URL } from "../Enum/EnvironmentVariable"; -import {analyticsClient} from "../Administration/AnalyticsClient"; +import { analyticsClient } from "../Administration/AnalyticsClient"; 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); diff --git a/front/src/index.ts b/front/src/index.ts index 9842e65d..7ef30340 100644 --- a/front/src/index.ts +++ b/front/src/index.ts @@ -23,7 +23,7 @@ import { Game } from "./Phaser/Game/Game"; import App from "./Components/App.svelte"; import { HtmlUtils } from "./WebRtc/HtmlUtils"; import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer; -import {analyticsClient} from "./Administration/AnalyticsClient"; +import { analyticsClient } from "./Administration/AnalyticsClient"; const { width, height } = coWebsiteManager.getGameSize(); const valueGameQuality = localUserStore.getGameQualityValue(); diff --git a/front/style/fonts.scss b/front/style/fonts.scss index 526f6615..018dfa0d 100644 --- a/front/style/fonts.scss +++ b/front/style/fonts.scss @@ -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"; } diff --git a/front/style/fonts/TwemojiMozilla.ttf b/front/style/fonts/TwemojiMozilla.ttf new file mode 100644 index 00000000..6091c679 Binary files /dev/null and b/front/style/fonts/TwemojiMozilla.ttf differ diff --git a/front/style/style.scss b/front/style/style.scss index f66875e3..7584a4b5 100644 --- a/front/style/style.scss +++ b/front/style/style.scss @@ -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; + } +} \ No newline at end of file diff --git a/front/webpack.config.ts b/front/webpack.config.ts index f2e4e7cc..cf414bd2 100644 --- a/front/webpack.config.ts +++ b/front/webpack.config.ts @@ -7,7 +7,7 @@ import MiniCssExtractPlugin from "mini-css-extract-plugin"; import sveltePreprocess from "svelte-preprocess"; import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"; import NodePolyfillPlugin from "node-polyfill-webpack-plugin"; -import {POSTHOG_API_KEY, PROFILE_URL} from "./src/Enum/EnvironmentVariable"; +import { POSTHOG_API_KEY, PROFILE_URL } from "./src/Enum/EnvironmentVariable"; const mode = process.env.NODE_ENV ?? "development"; const buildNpmTypingsForApi = !!process.env.BUILD_TYPINGS; diff --git a/front/yarn.lock b/front/yarn.lock index 68cca0cf..cf69f111 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -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==