From e715ca42c4481a07e6dca0d4a8d8bb9ede96f9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Thu, 9 Sep 2021 11:35:17 +0200 Subject: [PATCH 1/9] Improving design of the test page --- maps/tests/index.html | 492 ++++++++++++++++++++++-------------------- 1 file changed, 258 insertions(+), 234 deletions(-) diff --git a/maps/tests/index.html b/maps/tests/index.html index 6ea6cf80..17f646bc 100644 --- a/maps/tests/index.html +++ b/maps/tests/index.html @@ -1,241 +1,266 @@ + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ResultTest
- Success Failure Pending - - Testing Jitsi special config parameters -
- Success Failure Pending - - Testing jitsiUrl property -
- Success Failure Pending - - Testing scripting API with an iFrame -
- Success Failure Pending - - Testing scripting API with a script -
- Success Failure Pending - - Testing goToPage script Api -
- Success Failure Pending - - Testing scripting API loadSound() function -
- Success Failure Pending - - Testing scripting API deprecated function -
- Success Failure Pending - - Testing auto-zoom of viewport -
- Success Failure Pending - - Testing zoom via mouse wheel -
- Success Failure Pending - - Testing movement on mobile -
- Success Failure Pending - - Testing video on mobile -
- Success Failure Pending - - Test energy consumption -
- Success Failure Pending - - Test the HelpCameraSettingScene -
- Success Failure Pending - - Test a iframe opened by a script can use Iframe API -
- Success Failure Pending - - Testing add a custom menu by scripting API -
- Success Failure Pending - - Testing return current player attributes in Scripting API + WA.onInit -
- Success Failure Pending - - Test listening player movement by Scripting API -
- Success Failure Pending - - Testing set a property on a layer by Scripting API -
- Success Failure Pending - - Testing show or hide a layer by Scripting API -
- Success Failure Pending - - Test animated tiles -
- Success Failure Pending - - Test start tile (S1) -
- Success Failure Pending - - Test start tile (S2) -
- Success Failure Pending - - Test set tiles -
- Success Failure Pending - - Testing scripting variables locally -
- Success Failure Pending - - Testing shared scripting variables -
- Success Failure Pending - - Testing trigger message API -
- Success Failure Pending - - Testing websites inside a map -
- Success Failure Pending - - Testing scripting API for websites inside a map -
- +
+

WorkAdventure test cases

+ + +

Map features / properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ResultTest
+ Success Failure Pending + + Testing Jitsi special config parameters +
+ Success Failure Pending + + Testing jitsiUrl property +
+ Success Failure Pending + + Test animated tiles +
+ Success Failure Pending + + Test start tile (S1) +
+ Success Failure Pending + + Test start tile (S2) +
+ Success Failure Pending + + Testing websites inside a map +
+

Iframe API

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Success Failure Pending + + Testing scripting API with an iFrame +
+ Success Failure Pending + + Testing scripting API with a script +
+ Success Failure Pending + + Testing goToPage script Api +
+ Success Failure Pending + + Testing scripting API loadSound() function +
+ Success Failure Pending + + Test a iframe opened by a script can use Iframe API +
+ Success Failure Pending + + Testing add a custom menu by scripting API +
+ Success Failure Pending + + Testing return current player attributes in Scripting API + WA.onInit +
+ Success Failure Pending + + Test listening player movement by Scripting API +
+ Success Failure Pending + + Testing set a property on a layer by Scripting API +
+ Success Failure Pending + + Testing show or hide a layer by Scripting API +
+ Success Failure Pending + + Test set tiles +
+ Success Failure Pending + + Testing scripting variables locally +
+ Success Failure Pending + + Testing shared scripting variables +
+ Success Failure Pending + + Testing trigger message API +
+ Success Failure Pending + + Testing scripting API deprecated function +
+ Success Failure Pending + + Testing scripting API for websites inside a map +
+

Mobile

+ + + + + + + + + +
+ Success Failure Pending + + Testing movement on mobile +
+ Success Failure Pending + + Testing video on mobile +
+

WebRTC

+ + + + + + + + + +
+ Success Failure Pending + + Test energy consumption +
+ Success Failure Pending + + Test the HelpCameraSettingScene +
+

Others

+ + + + + + + + + + + + + +
+ Success Failure Pending + + Test energy consumption +
+ Success Failure Pending + + Testing auto-zoom of viewport +
+ Success Failure Pending + + Testing zoom via mouse wheel +
+
- From 9f310383bafb886a86ae8d58f2942cf91e9907d1 Mon Sep 17 00:00:00 2001 From: TabascoEye Date: Thu, 9 Sep 2021 22:58:30 +0200 Subject: [PATCH 2/9] explain new property jitsiWidth --- docs/maps/meeting-rooms.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/maps/meeting-rooms.md b/docs/maps/meeting-rooms.md index 97d1b96f..719e0630 100644 --- a/docs/maps/meeting-rooms.md +++ b/docs/maps/meeting-rooms.md @@ -11,6 +11,7 @@ In order to create Jitsi meet zones: * You must create a specific layer. * In layer properties, you MUST add a "`jitsiRoom`" property (of type "`string`"). The value of the property is the name of the room in Jitsi. Note: the name of the room will be "slugified" and prepended with the name of the instance of the map (so that different instances of the map have different rooms) +* You may also use "jitsiWidth" property (of type "number" between 0 and 100) to control the width of the iframe containing the meeting room. ## Triggering of the "Jitsi meet" action From d071f5fa901362168430e2d4f983957472a24464 Mon Sep 17 00:00:00 2001 From: Kharhamel Date: Thu, 9 Sep 2021 16:51:02 +0200 Subject: [PATCH 3/9] FIX: the video element should not have a bigger height than its container --- front/src/Components/Video/VideoMediaBox.svelte | 10 +--------- front/src/WebRtc/VideoPeer.ts | 4 ---- front/style/mobile-style.scss | 1 - front/style/style.scss | 7 +++++-- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/front/src/Components/Video/VideoMediaBox.svelte b/front/src/Components/Video/VideoMediaBox.svelte index 924bb13a..cc7fb424 100644 --- a/front/src/Components/Video/VideoMediaBox.svelte +++ b/front/src/Components/Video/VideoMediaBox.svelte @@ -7,8 +7,6 @@ import {videoFocusStore} from "../../Stores/VideoFocusStore"; import {showReportScreenStore} from "../../Stores/ShowReportScreenStore"; import {getColorByString, srcObject} from "./utils"; - import {obtainedMediaConstraintIsMobileStore} from "../../Stores/MediaStore"; - import {onDestroy} from "svelte"; export let peer: VideoPeer; let streamStore = peer.streamStore; @@ -20,12 +18,6 @@ showReportScreenStore.set({ userId:peer.userId, userName: peer.userName }); } - let isMobile : boolean|null; - const unsubscribe = obtainedMediaConstraintIsMobileStore.subscribe(value => { - isMobile = value; - }); - onDestroy(unsubscribe); -
@@ -45,7 +37,7 @@ Report this user Report/Block - + {#if $constraintStore && $constraintStore.audio !== false} diff --git a/front/src/WebRtc/VideoPeer.ts b/front/src/WebRtc/VideoPeer.ts index b66a27fe..990adb4e 100644 --- a/front/src/WebRtc/VideoPeer.ts +++ b/front/src/WebRtc/VideoPeer.ts @@ -7,7 +7,6 @@ import type { UserSimplePeerInterface } from "./SimplePeer"; import { readable, Readable, Unsubscriber } from "svelte/store"; import { localStreamStore, - obtainedMediaConstraintIsMobileStore, obtainedMediaConstraintStore, ObtainedMediaStreamConstraints, } from "../Stores/MediaStore"; @@ -162,9 +161,6 @@ export class VideoPeer extends Peer { } else { mediaManager.disabledVideoByUserId(this.userId); } - if (message.isMobile != undefined) { - obtainedMediaConstraintIsMobileStore.set(message.isMobile); - } } else if (message.type === MESSAGE_TYPE_MESSAGE) { if (!blackListManager.isBlackListed(this.userUuid)) { chatMessagesStore.addExternalMessage(this.userId, message.message); diff --git a/front/style/mobile-style.scss b/front/style/mobile-style.scss index 7f1e770f..ad91b8dc 100644 --- a/front/style/mobile-style.scss +++ b/front/style/mobile-style.scss @@ -40,7 +40,6 @@ .main-section { position: absolute; width: 100%; - min-width: 400px; & > div { z-index: 2; diff --git a/front/style/style.scss b/front/style/style.scss index d02b7e11..f66875e3 100644 --- a/front/style/style.scss +++ b/front/style/style.scss @@ -44,7 +44,7 @@ body .message-info.warning{ video { width: 100%; height: 100%; - max-height: 90vh; + object-fit: cover; cursor: url('./images/cursor_pointer.png'), pointer; &.mobile{ @@ -76,7 +76,6 @@ body .message-info.warning{ left: 5px; bottom: 5px; padding: 10px; - z-index: 2; &.active { display: block !important; @@ -547,6 +546,10 @@ input[type=range]:focus::-ms-fill-upper { cursor: url('./images/cursor_pointer.png'), pointer; border-radius: 15px 15px 15px 15px; pointer-events: auto; + + video { + max-height: 21vh; + } } .sidebar > div:hover { From 7cabf64b115f711c4300b19004c224eb3ea228ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Fri, 10 Sep 2021 16:40:09 +0200 Subject: [PATCH 4/9] Adding more tests --- maps/tests/inactive_tabs.json | 82 +++++++++++++++++++++++++++++++++++ maps/tests/index.html | 16 +++++++ maps/tests/reconnection.json | 82 +++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 maps/tests/inactive_tabs.json create mode 100644 maps/tests/reconnection.json diff --git a/maps/tests/inactive_tabs.json b/maps/tests/inactive_tabs.json new file mode 100644 index 00000000..f2aab52e --- /dev/null +++ b/maps/tests/inactive_tabs.json @@ -0,0 +1,82 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":10, + "id":1, + "name":"floor", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":2, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":3, + "name":"floorLayer", + "objects":[ + { + "height":261.73266830836, + "id":3, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":11, + "text":"Test:\nOpen WorkAdventure in 1 tab in Chrome and 1 tab in Firefox. Keep the Firefox tab open and open another tab in Chrome on any website (so that the WA Chrome tab is not visible). Do not enter in a bubble. Wait 6 minutes. (you can check time waited in a \"chrome:\/\/discards\" special tab.\n\nResult:\nOn the Firefox tab, the user of the Chrome tab is still visible. You can speak to the other user in a bubble.\n\nHere, we are checking that the Chrome does not \"freeze\" the non visible tab.\n\nRe-run this test with Safari, Edge and Firefox as the browsers with the hidden tabs", + "wrap":true + }, + "type":"", + "visible":true, + "width":252.4375, + "x":46.5894222943362, + "y":34.2876372135732 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":8, + "nextobjectid":5, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"2021.03.23", + "tileheight":32, + "tilesets":[ + { + "columns":11, + "firstgid":1, + "image":"tileset1.png", + "imageheight":352, + "imagewidth":352, + "margin":0, + "name":"tileset1", + "spacing":0, + "tilecount":121, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.5, + "width":10 +} \ No newline at end of file diff --git a/maps/tests/index.html b/maps/tests/index.html index 17f646bc..20f48274 100644 --- a/maps/tests/index.html +++ b/maps/tests/index.html @@ -235,6 +235,22 @@

Others

+ + + + + + + +
+ Success Failure Pending + + Test reconnection +
+ Success Failure Pending + + Test inactive tabs on Chrome +
Success Failure Pending diff --git a/maps/tests/reconnection.json b/maps/tests/reconnection.json new file mode 100644 index 00000000..495ae39c --- /dev/null +++ b/maps/tests/reconnection.json @@ -0,0 +1,82 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":10, + "id":1, + "name":"floor", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":2, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":3, + "name":"floorLayer", + "objects":[ + { + "height":261.73266830836, + "id":3, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":11, + "text":"Test:\nTest to be run on a remote site (not locally)\nOpen WorkAdventure in 2 tabs.\nClose the network connection (close Wifi, ...)\n\nResult:\nAfter a few seconds, WorkAdventure displays a \"reconnecting scene\"\n\nTest:\nResume network connection, without switching tabs (one tab on front)\n\nResult:\nWorkAdventure reconnects automatically. From the tab that resumed, you can connect to the other tab (that is not visible), therefore testing that the invisible tab has resumed too.", + "wrap":true + }, + "type":"", + "visible":true, + "width":252.4375, + "x":46.5894222943362, + "y":34.2876372135732 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":8, + "nextobjectid":5, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"2021.03.23", + "tileheight":32, + "tilesets":[ + { + "columns":11, + "firstgid":1, + "image":"tileset1.png", + "imageheight":352, + "imagewidth":352, + "margin":0, + "name":"tileset1", + "spacing":0, + "tilecount":121, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.5, + "width":10 +} \ No newline at end of file From 05646718a95a02a8285c954001e1f86628fa3c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Fri, 10 Sep 2021 18:30:36 +0200 Subject: [PATCH 5/9] Fix disconnects after 5 minutes in Chrome This commit increases idle timeout for websocket connection Issue: after 5 minutes of inactive tab (hidden tab) in Chrome, WorkAdventure was disconnected. I believe Google was going in "intensive throttling" mode (see https://developer.chrome.com/blog/timer-throttling-in-chrome-88/#intensive-throttling) This means setTimeouts are run only once per minute. And I believe the "keep alive" must be implemented with a "setTimeout" (one way or another even if I can't find a trace of this in the code). This would mean that the browser would send keep alive requests only once per minute. But the pusher is configured to shut the connection after 30 seconds of idle activity. Therefore, the pusher disconnects inactive Chrome tabs. By raising the Pusher idle timer to 2 minutes, we give a chance to Chrome to send a ping to the server in time (since Chrome won't send more than 1 ping per minute). --- back/src/Enum/EnvironmentVariable.ts | 1 - pusher/src/Enum/EnvironmentVariable.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/back/src/Enum/EnvironmentVariable.ts b/back/src/Enum/EnvironmentVariable.ts index 92f62b0b..493f97a2 100644 --- a/back/src/Enum/EnvironmentVariable.ts +++ b/back/src/Enum/EnvironmentVariable.ts @@ -9,7 +9,6 @@ const JITSI_ISS = process.env.JITSI_ISS || ""; const SECRET_JITSI_KEY = process.env.SECRET_JITSI_KEY || ""; const HTTP_PORT = parseInt(process.env.HTTP_PORT || "8080") || 8080; const GRPC_PORT = parseInt(process.env.GRPC_PORT || "50051") || 50051; -export const SOCKET_IDLE_TIMER = parseInt(process.env.SOCKET_IDLE_TIMER as string) || 30; // maximum time (in second) without activity before a socket is closed export const TURN_STATIC_AUTH_SECRET = process.env.TURN_STATIC_AUTH_SECRET || ""; export const MAX_PER_GROUP = parseInt(process.env.MAX_PER_GROUP || "4"); export const REDIS_HOST = process.env.REDIS_HOST || undefined; diff --git a/pusher/src/Enum/EnvironmentVariable.ts b/pusher/src/Enum/EnvironmentVariable.ts index 4a078d90..ab1ce110 100644 --- a/pusher/src/Enum/EnvironmentVariable.ts +++ b/pusher/src/Enum/EnvironmentVariable.ts @@ -9,7 +9,7 @@ const JITSI_URL: string | undefined = process.env.JITSI_URL === "" ? undefined : const JITSI_ISS = process.env.JITSI_ISS || ""; const SECRET_JITSI_KEY = process.env.SECRET_JITSI_KEY || ""; const PUSHER_HTTP_PORT = parseInt(process.env.PUSHER_HTTP_PORT || "8080") || 8080; -export const SOCKET_IDLE_TIMER = parseInt(process.env.SOCKET_IDLE_TIMER as string) || 30; // maximum time (in second) without activity before a socket is closed +export const SOCKET_IDLE_TIMER = parseInt(process.env.SOCKET_IDLE_TIMER as string) || 120; // maximum time (in second) without activity before a socket is closed. Should be greater than 60 seconds in order to cope for Chrome intensive throttling (https://developer.chrome.com/blog/timer-throttling-in-chrome-88/#intensive-throttling) export const FRONT_URL = process.env.FRONT_URL || "http://localhost"; export const OPID_CLIENT_ID = process.env.OPID_CLIENT_ID || ""; From 94517c0f4b61950839936ca9847648550b89efc9 Mon Sep 17 00:00:00 2001 From: TabascoEye Date: Fri, 10 Sep 2021 23:17:04 +0200 Subject: [PATCH 6/9] add the possibilities of "onaction" and message to new "openTab" property --- .../Phaser/Game/GameMapPropertiesListener.ts | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/front/src/Phaser/Game/GameMapPropertiesListener.ts b/front/src/Phaser/Game/GameMapPropertiesListener.ts index db100935..950e1ebc 100644 --- a/front/src/Phaser/Game/GameMapPropertiesListener.ts +++ b/front/src/Phaser/Game/GameMapPropertiesListener.ts @@ -13,9 +13,27 @@ export class GameMapPropertiesListener { constructor(private scene: GameScene, private gameMap: GameMap) {} register() { - this.gameMap.onPropertyChange("openTab", (newValue) => { + this.gameMap.onPropertyChange("openTab", (newValue, oldvalue, allProps) => { + if (newValue === undefined) { + layoutManagerActionStore.removeAction("openTab"); + } if (typeof newValue == "string" && newValue.length) { - scriptUtils.openTab(newValue); + const openWebsiteTriggerValue = allProps.get(TRIGGER_WEBSITE_PROPERTIES); + if (openWebsiteTriggerValue && openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) { + let message = allProps.get(WEBSITE_MESSAGE_PROPERTIES); + if (message === undefined) { + message = "Press SPACE or touch here to open web site in new tab"; + } + layoutManagerActionStore.addAction({ + uuid: "openTab", + type: "message", + message: message, + callback: () => scriptUtils.openTab(newValue), + userInputManager: this.scene.userInputManager, + }); + } else { + scriptUtils.openTab(newValue); + } } }); this.gameMap.onPropertyChange("openWebsite", (newValue, oldValue, allProps) => { From f0b83663f6909b5763d82f1bb977c058a94c1038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 13 Sep 2021 10:06:08 +0200 Subject: [PATCH 7/9] Fixing broken sound controls Because of the rework of the menu, the clickable zone for the menu was extending at the complete top of the screen, which caused interactive items at the top of the screen (like sound controls) to be broken. This commit fixes this. --- front/src/Components/Menu/MenuIcon.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/src/Components/Menu/MenuIcon.svelte b/front/src/Components/Menu/MenuIcon.svelte index 2da9e870..92a52ba3 100644 --- a/front/src/Components/Menu/MenuIcon.svelte +++ b/front/src/Components/Menu/MenuIcon.svelte @@ -22,9 +22,9 @@