From d7121d4192586a27c49142dfd06fa3e862923229 Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Tue, 28 Dec 2021 11:28:53 +0100 Subject: [PATCH 01/16] Add fonts & png files built to the gitignore file --- front/dist/.gitignore | 2 ++ front/dist/index.ejs | 76 +++++-------------------------------------- 2 files changed, 11 insertions(+), 67 deletions(-) diff --git a/front/dist/.gitignore b/front/dist/.gitignore index 0561f7a5..bc766e57 100644 --- a/front/dist/.gitignore +++ b/front/dist/.gitignore @@ -1,4 +1,6 @@ index.html /js/ +/fonts/ style.*.css !env-config.template.js +*.png diff --git a/front/dist/index.ejs b/front/dist/index.ejs index 29b8e6cb..07732877 100644 --- a/front/dist/index.ejs +++ b/front/dist/index.ejs @@ -37,65 +37,9 @@
-
-
-
-
- - -
-
-
- -
-
-
-
- -
-
- - -
-
-
- -
-
-
- -
-
- - -
-
-
- -
-
-
- -
-
- - -
-
-
-
-
-
-
-
-
- - -
+
- - -
-
- - From 56d8f62dd07e575c30fc39b01ef1c45fd65f8b44 Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Wed, 5 Jan 2022 09:54:20 +0100 Subject: [PATCH 02/16] Add a new test map for co-website with trigger property --- .../CoWebsite/cowebsite_property_trigger.json | 194 ++++++++++++++++++ maps/tests/index.html | 8 + 2 files changed, 202 insertions(+) create mode 100644 maps/tests/CoWebsite/cowebsite_property_trigger.json diff --git a/maps/tests/CoWebsite/cowebsite_property_trigger.json b/maps/tests/CoWebsite/cowebsite_property_trigger.json new file mode 100644 index 00000000..183fad3a --- /dev/null +++ b/maps/tests/CoWebsite/cowebsite_property_trigger.json @@ -0,0 +1,194 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":10, + "id":1, + "name":"floor", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":2, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34], + "height":10, + "id":8, + "name":"firstCoWebsite", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"https:\/\/workadventu.re" + }, + { + "name":"openWebsiteClosable", + "type":"bool", + "value":true + }, + { + "name":"openWebsiteTrigger", + "type":"string", + "value":"onaction" + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 23, 23, 23, 23, 23], + "height":10, + "id":11, + "name":"secondCoWebsite", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"https:\/\/wikipedia.org" + }, + { + "name":"openWebsiteClosable", + "type":"bool", + "value":true + }, + { + "name":"openWebsiteTrigger", + "type":"string", + "value":"onaction" + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12], + "height":10, + "id":10, + "name":"terCoWebsite", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"https:\/\/www.typescriptlang.org\/" + }, + { + "name":"openWebsiteClosable", + "type":"bool", + "value":true + }, + { + "name":"openWebsiteTrigger", + "type":"string", + "value":"onaction" + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 111, 111, 111, 111, 0, 0, 0, 0, 0, 111, 111, 111, 111, 111, 0, 0, 0, 0, 0, 111, 111, 111, 111, 111, 0, 0, 0, 0, 0, 111, 111, 111, 111, 111], + "height":10, + "id":12, + "name":"quatCoWebsite", + "opacity":1, + "properties":[ + { + "name":"openWebsite", + "type":"string", + "value":"https:\/\/svelte.dev\/" + }, + { + "name":"openWebsiteClosable", + "type":"bool", + "value":true + }, + { + "name":"openWebsiteTrigger", + "type":"string", + "value":"onaction" + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":3, + "name":"floorLayer", + "objects":[ + { + "height":141, + "id":1, + "name":"Tests", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "pixelsize":11, + "text":"Test:\nWalk on the blue carpet, an iframe open, walk on the white carpet another one to open another one\nResult:\n2 co-websites must be opened\n\nTest:\nGo outside of carpets\nResult:\nAll co-websites must disapeared", + "wrap":true + }, + "type":"", + "visible":true, + "width":316.770833333333, + "x":0.28125, + "y":187.833333333333 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":13, + "nextobjectid":3, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.7.2", + "tileheight":32, + "tilesets":[ + { + "columns":11, + "firstgid":1, + "image":"tileset1.png", + "imageheight":352, + "imagewidth":352, + "margin":0, + "name":"tileset1", + "spacing":0, + "tilecount":121, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":"1.6", + "width":10 +} \ No newline at end of file diff --git a/maps/tests/index.html b/maps/tests/index.html index d27d7804..b4391fee 100644 --- a/maps/tests/index.html +++ b/maps/tests/index.html @@ -326,6 +326,14 @@ Open co-websites by map property + + + Success Failure Pending + + + Open co-websites by map property trigger + + Success Failure Pending From 9695064e8250ee564f601a135c2a0a9830307bd2 Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Wed, 5 Jan 2022 09:56:10 +0100 Subject: [PATCH 03/16] Implement breakpoints utils on SCSS and JS --- front/src/Utils/BreakpointsUtils.ts | 112 ++++++++++++++++++++++++++++ front/style/breakpoints.scss | 102 +++++++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 front/src/Utils/BreakpointsUtils.ts create mode 100644 front/style/breakpoints.scss diff --git a/front/src/Utils/BreakpointsUtils.ts b/front/src/Utils/BreakpointsUtils.ts new file mode 100644 index 00000000..3cefb37d --- /dev/null +++ b/front/src/Utils/BreakpointsUtils.ts @@ -0,0 +1,112 @@ +type InternalBreakpoint = { + beforeBreakpoint: InternalBreakpoint | undefined; + nextBreakpoint: InternalBreakpoint | undefined; + pixels: number; +}; + +function generateBreakpointsMap(): Map { + // 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(); + + 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) + ); +} diff --git a/front/style/breakpoints.scss b/front/style/breakpoints.scss new file mode 100644 index 00000000..8b988d66 --- /dev/null +++ b/front/style/breakpoints.scss @@ -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; + } + } +} From 5f1dd09cb96f835c261b7af56c4a252cdae8f2a4 Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Wed, 5 Jan 2022 09:58:57 +0100 Subject: [PATCH 04/16] Implement minimizer for css/scss --- front/package.json | 1 + front/webpack.config.ts | 33 +-- front/yarn.lock | 549 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 555 insertions(+), 28 deletions(-) diff --git a/front/package.json b/front/package.json index 564e1485..9a17f4a0 100644 --- a/front/package.json +++ b/front/package.json @@ -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", diff --git a/front/webpack.config.ts b/front/webpack.config.ts index e5b338fc..3185b0a6 100644 --- a/front/webpack.config.ts +++ b/front/webpack.config.ts @@ -2,6 +2,7 @@ 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"; @@ -79,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)$/, @@ -185,6 +162,10 @@ module.exports = { extensions: [".tsx", ".ts", ".js", ".svelte"], mainFields: ["svelte", "browser", "module", "main"], }, + optimization: { + minimize: true, + minimizer: [new CssMinimizerPlugin(), "..."], + }, output: { filename: (pathData) => { // Add a content hash only for the main bundle. diff --git a/front/yarn.lock b/front/yarn.lock index 1758ebd3..89a8a568 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -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" @@ -1952,6 +2116,15 @@ dom-serializer@0: domelementtype "^2.0.1" entities "^2.0.0" +dom-serializer@^1.0.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + domain-browser@^4.19.0: version "4.19.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1" @@ -1962,7 +2135,7 @@ domelementtype@1, domelementtype@^1.3.1: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== -domelementtype@^2.0.1: +domelementtype@^2.0.1, domelementtype@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== @@ -1974,6 +2147,13 @@ domhandler@^2.3.0: dependencies: domelementtype "1" +domhandler@^4.2.0, domhandler@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" + integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== + dependencies: + domelementtype "^2.2.0" + domutils@^1.5.1, domutils@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" @@ -1982,6 +2162,15 @@ domutils@^1.5.1, domutils@^1.7.0: dom-serializer "0" domelementtype "1" +domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + dot-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" @@ -2007,6 +2196,11 @@ electron-to-chromium@^1.3.723: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.728.tgz#dbedd6373f595ae10a13d146b66bece4c1afa5bd" 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" @@ -3541,6 +3735,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" @@ -3568,6 +3771,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 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" @@ -3659,6 +3867,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" @@ -3747,11 +3960,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" @@ -3830,6 +4053,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" @@ -4036,6 +4264,11 @@ nanoid@^3.1.23: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== +nanoid@^3.1.30: + version "3.1.30" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" + integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -4121,6 +4354,11 @@ node-releases@^1.1.71: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" 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" @@ -4143,6 +4381,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 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" @@ -4179,6 +4422,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" @@ -4549,6 +4799,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" @@ -4621,6 +4876,103 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" 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" @@ -4649,6 +5001,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" @@ -4657,6 +5099,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" @@ -4671,6 +5142,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" @@ -4998,6 +5478,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" @@ -5190,6 +5675,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" @@ -5250,6 +5745,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" @@ -5470,6 +5972,11 @@ source-list-map@^2.0.0, source-list-map@^2.0.1: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== +source-map-js@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" + integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== + source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -5565,6 +6072,11 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: 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" @@ -5731,6 +6243,14 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 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" @@ -5752,6 +6272,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" @@ -5801,6 +6328,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" @@ -5868,6 +6408,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" @@ -6496,7 +7041,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== From 0bf1acfefbf20240c8fb79dbfac8ffdcbecf4c5d Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Wed, 5 Jan 2022 10:27:40 +0100 Subject: [PATCH 05/16] Improve game overlay UI --- front/src/Components/App.svelte | 196 +++---------- .../AudioManager/AudioManager.svelte | 7 +- front/src/Components/CameraControls.svelte | 220 +++++++++++--- front/src/Components/Chat/Chat.svelte | 4 +- .../CustomCharacterScene.svelte | 4 +- .../src/Components/EmoteMenu/EmoteMenu.svelte | 6 +- .../EnableCamera/EnableCameraScene.svelte | 4 +- .../Components/FollowMenu/FollowButton.svelte | 33 +++ .../Components/FollowMenu/FollowMenu.svelte | 76 ++--- .../HelpCameraSettingsPopup.svelte | 7 +- .../LayoutActionManager.svelte} | 8 +- front/src/Components/MainLayout.svelte | 163 +++++++++++ .../Components/Menu/AboutRoomSubMenu.svelte | 4 +- .../Menu/GlobalMessagesSubMenu.svelte | 4 +- front/src/Components/Menu/GuestSubMenu.svelte | 4 +- front/src/Components/Menu/Menu.svelte | 18 +- front/src/Components/Menu/MenuIcon.svelte | 63 ++-- .../src/Components/Menu/ProfileSubMenu.svelte | 4 +- .../Components/Menu/SettingsSubMenu.svelte | 24 +- front/src/Components/MyCamera.svelte | 80 ++++- .../Components/ReportMenu/ReportMenu.svelte | 21 +- .../SelectCompanionScene.svelte | 4 +- .../Components/TypeMessage/BanMessage.svelte | 16 +- .../Components/TypeMessage/TextMessage.svelte | 11 +- front/src/Components/UI/ErrorDialog.svelte | 8 +- .../Video/LocalStreamMediaBox.svelte | 22 +- front/src/Components/Video/MediaBox.svelte | 59 +++- .../Video/PresentationLayout.svelte | 26 -- .../Video/ScreenSharingMediaBox.svelte | 23 +- .../src/Components/Video/VideoMediaBox.svelte | 83 ++++-- .../src/Components/Video/VideoOverlay.svelte | 12 +- .../src/Components/VisitCard/VisitCard.svelte | 1 + .../WarningContainer/WarningContainer.svelte | 16 +- front/src/Components/Woka/Woka.svelte | 13 +- .../SelectCharacterScene.svelte | 4 +- front/src/Enum/EnvironmentVariable.ts | 2 - front/src/Phaser/Components/SoundMeter.ts | 2 - front/src/Phaser/Game/GameMapProperties.ts | 1 - front/src/Phaser/Game/GameScene.ts | 67 +++-- front/src/Phaser/Login/CustomizeScene.ts | 6 +- .../src/Phaser/Login/SelectCharacterScene.ts | 6 +- .../src/Phaser/Login/SelectCompanionScene.ts | 4 +- front/src/Phaser/Services/WaScaleManager.ts | 12 +- front/src/Stores/BiggestAvailableAreaStore.ts | 4 +- .../src/Stores/GameOverlayStoreVisibility.ts | 17 -- front/src/Stores/LayoutManagerStore.ts | 2 +- front/src/Stores/MediaStore.ts | 8 +- front/src/Stores/MyCameraStoreVisibility.ts | 8 + front/src/Stores/ScreenSharingStore.ts | 8 +- front/src/Stores/StreamableCollectionStore.ts | 5 +- front/src/WebRtc/HtmlUtils.ts | 5 + front/src/WebRtc/MediaManager.ts | 51 +--- front/src/WebRtc/ScreenSharingPeer.ts | 17 +- front/src/WebRtc/SimplePeer.ts | 2 +- front/src/WebRtc/VideoPeer.ts | 4 +- front/src/index.ts | 8 +- .../style/TextGlobalMessageSvelte-Style.scss | 2 +- front/style/cowebsite-mobile.scss | 136 --------- front/style/fonts.scss | 5 - front/style/fonts/TwemojiMozilla.ttf | Bin 1324332 -> 0 bytes front/style/index.scss | 6 +- front/style/mobile-style.scss | 48 --- front/style/style.scss | 276 ++---------------- 63 files changed, 976 insertions(+), 984 deletions(-) create mode 100644 front/src/Components/FollowMenu/FollowButton.svelte rename front/src/Components/{LayoutManager/LayoutManager.svelte => LayoutActionManager/LayoutActionManager.svelte} (91%) create mode 100644 front/src/Components/MainLayout.svelte delete mode 100644 front/src/Components/Video/PresentationLayout.svelte delete mode 100644 front/src/Stores/GameOverlayStoreVisibility.ts create mode 100644 front/src/Stores/MyCameraStoreVisibility.ts delete mode 100644 front/style/cowebsite-mobile.scss delete mode 100644 front/style/fonts/TwemojiMozilla.ttf delete mode 100644 front/style/mobile-style.scss diff --git a/front/src/Components/App.svelte b/front/src/Components/App.svelte index a1277ed2..620884cf 100644 --- a/front/src/Components/App.svelte +++ b/front/src/Components/App.svelte @@ -1,166 +1,52 @@ -
- {#if $loginSceneVisibleStore} -
- -
- {/if} - {#if $selectCharacterSceneVisibleStore} -
- -
- {/if} - {#if $customCharacterSceneVisibleStore} -
- -
- {/if} - {#if $selectCompanionSceneVisibleStore} -
- -
- {/if} - {#if $enableCameraSceneVisibilityStore} -
- -
- {/if} - {#if $banMessageStore.length > 0} -
- -
- {:else if $textMessageStore.length > 0} -
- -
- {/if} - {#if $soundPlayingStore} -
- -
- {/if} - {#if $audioManagerVisibilityStore} -
- -
- {/if} - {#if $layoutManagerVisibilityStore} -
- -
- {/if} - {#if $showReportScreenStore !== userReportEmpty} -
- -
- {/if} - {#if $followStateStore !== "off" || $peerStore.size > 0} -
- -
- {/if} - {#if $menuIconVisiblilityStore} -
- -
- {/if} - {#if $menuVisiblilityStore} -
- -
- {/if} - {#if $emoteMenuStore} -
- -
- {/if} - {#if $gameOverlayVisibilityStore} -
- - - -
- {/if} - {#if $helpCameraSettingsVisibleStore} -
- -
- {/if} - {#if $showLimitRoomModalStore} -
- -
- {/if} - {#if $showShareLinkMapModalStore} -
- -
- {/if} - {#if $requestVisitCardsStore} - - {/if} - {#if $errorStore.length > 0} -
- -
- {/if} +{#if $errorStore.length > 0} +
+ +
+{:else if $loginSceneVisibleStore} +
+ +
+{:else if $selectCharacterSceneVisibleStore} +
+ +
+{:else if $customCharacterSceneVisibleStore} +
+ +
+{:else if $selectCompanionSceneVisibleStore} +
+ +
+{:else if $enableCameraSceneVisibilityStore} +
+ +
+{:else} + + {#if $chatVisibilityStore} {/if} - {#if $warningContainerStore} - - {/if} -
+{/if} diff --git a/front/src/Components/AudioManager/AudioManager.svelte b/front/src/Components/AudioManager/AudioManager.svelte index 3385d6da..87b949c7 100644 --- a/front/src/Components/AudioManager/AudioManager.svelte +++ b/front/src/Components/AudioManager/AudioManager.svelte @@ -157,13 +157,16 @@ diff --git a/front/src/Components/Chat/Chat.svelte b/front/src/Components/Chat/Chat.svelte index c4756a36..cd9b90b5 100644 --- a/front/src/Components/Chat/Chat.svelte +++ b/front/src/Components/Chat/Chat.svelte @@ -43,7 +43,7 @@
diff --git a/front/src/Components/ReportMenu/ReportMenu.svelte b/front/src/Components/ReportMenu/ReportMenu.svelte index 3934f21b..caf1ff76 100644 --- a/front/src/Components/ReportMenu/ReportMenu.svelte +++ b/front/src/Components/ReportMenu/ReportMenu.svelte @@ -108,12 +108,16 @@ pointer-events: auto; background-color: #333333; color: whitesmoke; - - position: relative; + z-index: 300; + 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; - } - } diff --git a/front/src/Components/SelectCompanion/SelectCompanionScene.svelte b/front/src/Components/SelectCompanion/SelectCompanionScene.svelte index dd14914b..aadc9ed6 100644 --- a/front/src/Components/SelectCompanion/SelectCompanionScene.svelte +++ b/front/src/Components/SelectCompanion/SelectCompanionScene.svelte @@ -47,6 +47,8 @@ diff --git a/front/src/Components/Video/PresentationLayout.svelte b/front/src/Components/Video/PresentationLayout.svelte deleted file mode 100644 index 82a7c989..00000000 --- a/front/src/Components/Video/PresentationLayout.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - -
- {#if $videoFocusStore} - {#key $videoFocusStore.uniqueId} - - {/key} - {/if} -
- diff --git a/front/src/Components/Video/ScreenSharingMediaBox.svelte b/front/src/Components/Video/ScreenSharingMediaBox.svelte index b6a227ef..022770bb 100644 --- a/front/src/Components/Video/ScreenSharingMediaBox.svelte +++ b/front/src/Components/Video/ScreenSharingMediaBox.svelte @@ -1,12 +1,26 @@
@@ -20,7 +34,12 @@ {name} {:else} -
diff --git a/front/src/Components/Video/VideoMediaBox.svelte b/front/src/Components/Video/VideoMediaBox.svelte index aec1b0ce..a724f704 100644 --- a/front/src/Components/Video/VideoMediaBox.svelte +++ b/front/src/Components/Video/VideoMediaBox.svelte @@ -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); + }); -
+
{#if $statusStore === "connecting"}
{/if} @@ -30,42 +59,60 @@ {/if} - {peer.userName} + {peer.userName}
{#if $constraintStore && $constraintStore.audio === false} - Muted + Muted {/if} -
- diff --git a/front/src/Components/Video/VideoOverlay.svelte b/front/src/Components/Video/VideoOverlay.svelte index ba316feb..7cf19aa4 100644 --- a/front/src/Components/Video/VideoOverlay.svelte +++ b/front/src/Components/Video/VideoOverlay.svelte @@ -1,16 +1,16 @@
- {#if $layoutModeStore === LayoutMode.Presentation} +
diff --git a/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte b/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte new file mode 100644 index 00000000..a3895a52 --- /dev/null +++ b/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte @@ -0,0 +1,100 @@ + + +
+ +
+ + diff --git a/front/src/Components/EmbedScreens/CoWebsitesContainer.svelte b/front/src/Components/EmbedScreens/CoWebsitesContainer.svelte new file mode 100644 index 00000000..95000daf --- /dev/null +++ b/front/src/Components/EmbedScreens/CoWebsitesContainer.svelte @@ -0,0 +1,34 @@ + + +{#if $coWebsiteThumbails.length > 0} +
+ {#each [...$coWebsiteThumbails.values()] as coWebsite, index (coWebsite.iframe.id)} + + {/each} +
+{/if} + + diff --git a/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte b/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte new file mode 100644 index 00000000..79c59a58 --- /dev/null +++ b/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte @@ -0,0 +1,22 @@ + + +
+ {#if $embedScreenLayout === LayoutMode.Presentation} + + {:else} + + {/if} +
+ + diff --git a/front/src/Components/EmbedScreens/Layouts/MozaicLayout.svelte b/front/src/Components/EmbedScreens/Layouts/MozaicLayout.svelte new file mode 100644 index 00000000..25ff16c8 --- /dev/null +++ b/front/src/Components/EmbedScreens/Layouts/MozaicLayout.svelte @@ -0,0 +1,61 @@ + + +
+
+ {#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)} + + {/each} +
+
+ + diff --git a/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte b/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte new file mode 100644 index 00000000..8cecfe12 --- /dev/null +++ b/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte @@ -0,0 +1,169 @@ + + +
+ {#if displayFullMedias} +
+ +
+ {:else} +
+
+ {#if $highlightedEmbedScreen} + {#if $highlightedEmbedScreen.type === "streamable"} + {#key $highlightedEmbedScreen.embed.uniqueId} + + {/key} + {:else if $highlightedEmbedScreen.type === "cowebsite"} + {#key $highlightedEmbedScreen.embed.iframe.id} +
+
+ + + +
+
+ {/key} + {/if} + {/if} +
+ + {#if displayCoWebsiteContainer} + + {/if} +
+ + {#if $peerStore.size > 0} + + {/if} + {/if} +
+ + diff --git a/front/src/Components/EmoteMenu/EmoteMenu.svelte b/front/src/Components/EmoteMenu/EmoteMenu.svelte index 24f08812..ac068484 100644 --- a/front/src/Components/EmoteMenu/EmoteMenu.svelte +++ b/front/src/Components/EmoteMenu/EmoteMenu.svelte @@ -87,7 +87,7 @@ justify-content: center; align-items: center; position: absolute; - z-index: 101; + z-index: 300; } .emote-menu { diff --git a/front/src/Components/FollowMenu/FollowMenu.svelte b/front/src/Components/FollowMenu/FollowMenu.svelte index bc054443..0a0f5b68 100644 --- a/front/src/Components/FollowMenu/FollowMenu.svelte +++ b/front/src/Components/FollowMenu/FollowMenu.svelte @@ -121,7 +121,7 @@ right: 0; margin-left: auto; margin-right: auto; - z-index: 150; + z-index: 400; } div.interact-menu { diff --git a/front/src/Components/HelpCameraSettings/HelpCameraSettingsPopup.svelte b/front/src/Components/HelpCameraSettings/HelpCameraSettingsPopup.svelte index 2401399a..d4bb4ae0 100644 --- a/front/src/Components/HelpCameraSettings/HelpCameraSettingsPopup.svelte +++ b/front/src/Components/HelpCameraSettings/HelpCameraSettingsPopup.svelte @@ -60,7 +60,7 @@ margin-top: 4%; max-height: 80vh; max-width: 80vw; - z-index: 250; + z-index: 600; overflow: auto; text-align: center; diff --git a/front/src/Components/MainLayout.svelte b/front/src/Components/MainLayout.svelte index b6bfecda..6175f540 100644 --- a/front/src/Components/MainLayout.svelte +++ b/front/src/Components/MainLayout.svelte @@ -1,7 +1,7 @@ -
+
{#if streamable instanceof VideoPeer} - + {:else if streamable instanceof ScreenSharingPeer} - + {:else} - + {/if}
@@ -57,6 +64,32 @@ } } + &.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; + } + } + &.clickable { cursor: url("../../../style/images/cursor_pointer.png"), pointer; } diff --git a/front/src/Components/VisitCard/VisitCard.svelte b/front/src/Components/VisitCard/VisitCard.svelte index 94f19f93..57911638 100644 --- a/front/src/Components/VisitCard/VisitCard.svelte +++ b/front/src/Components/VisitCard/VisitCard.svelte @@ -57,7 +57,7 @@ height: 120px; margin: auto; animation: spin 2s linear infinite; - z-index: 102; + z-index: 350; } @keyframes spin { diff --git a/front/src/Components/WarningContainer/WarningContainer.svelte b/front/src/Components/WarningContainer/WarningContainer.svelte index c85d3bd7..b5def355 100644 --- a/front/src/Components/WarningContainer/WarningContainer.svelte +++ b/front/src/Components/WarningContainer/WarningContainer.svelte @@ -42,7 +42,7 @@ font-family: Lato; min-width: 300px; opacity: 0.9; - z-index: 270; + z-index: 700; h2 { padding: 5px; } diff --git a/front/src/Phaser/Game/GameMapPropertiesListener.ts b/front/src/Phaser/Game/GameMapPropertiesListener.ts index f6c28862..fec982d1 100644 --- a/front/src/Phaser/Game/GameMapPropertiesListener.ts +++ b/front/src/Phaser/Game/GameMapPropertiesListener.ts @@ -9,21 +9,21 @@ import { get } from "svelte/store"; import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager"; import type { ITiledMapLayer } from "../Map/ITiledMap"; import { GameMapProperties } from "./GameMapProperties"; +import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore"; enum OpenCoWebsiteState { - LOADING, + ASLEEP, OPENED, MUST_BE_CLOSE, } interface OpenCoWebsite { - coWebsite: CoWebsite | undefined; + coWebsite: CoWebsite; state: OpenCoWebsiteState; } export class GameMapPropertiesListener { private coWebsitesOpenByLayer = new Map(); - private coWebsitesActionTriggerByLayer = new Map(); constructor(private scene: GameScene, private gameMap: GameMap) {} @@ -64,10 +64,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) { @@ -80,18 +78,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; } }); @@ -105,27 +97,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, @@ -133,27 +128,17 @@ export class GameMapPropertiesListener { }); } }) - .catch((e) => console.error(e)); + .catch(() => { + console.error("Error during loading a co-website: " + coWebsite.url); + }); layoutManagerActionStore.removeAction(actionUuid); }; - const forceTrigger = localUserStore.getForceCowebsiteTrigger(); - if (forceTrigger || websiteTriggerProperty === ON_ACTION_TRIGGER_BUTTON) { - if (!websiteTriggerMessageProperty) { - websiteTriggerMessageProperty = "Press SPACE or touch here to open web site"; - } - - this.coWebsitesActionTriggerByLayer.set(layer, actionUuid); - - layoutManagerActionStore.addAction({ - uuid: actionUuid, - type: "message", - message: websiteTriggerMessageProperty, - callback: () => openWebsiteFunction(), - userInputManager: this.scene.userInputManager, - }); - } else { + if ( + !localUserStore.getForceCowebsiteTrigger() && + websiteTriggerProperty !== ON_ACTION_TRIGGER_BUTTON + ) { openWebsiteFunction(); } }); @@ -194,7 +179,7 @@ export class GameMapPropertiesListener { return; } - if (coWebsiteOpen.state === OpenCoWebsiteState.LOADING) { + if (coWebsiteOpen.state === OpenCoWebsiteState.ASLEEP) { coWebsiteOpen.state = OpenCoWebsiteState.MUST_BE_CLOSE; } @@ -203,26 +188,6 @@ export class GameMapPropertiesListener { } this.coWebsitesOpenByLayer.delete(layer); - - if (!websiteTriggerProperty) { - return; - } - - const actionStore = get(layoutManagerActionStore); - const actionTriggerUuid = this.coWebsitesActionTriggerByLayer.get(layer); - - if (!actionTriggerUuid) { - return; - } - - const action = - actionStore && actionStore.length > 0 - ? actionStore.find((action) => action.uuid === actionTriggerUuid) - : undefined; - - if (action) { - layoutManagerActionStore.removeAction(actionTriggerUuid); - } }); }; diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 9b93ce5b..5b10f5c3 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -2145,8 +2145,8 @@ ${escapedMessage} public stopJitsi(): void { const coWebsite = coWebsiteManager.searchJitsi(); if (coWebsite) { - coWebsiteManager.closeCoWebsite(coWebsite).catch(() => { - console.error("Error during Jitsi co-website closing"); + coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => { + console.error("Error during Jitsi co-website closing", e); }); } } diff --git a/front/src/Stores/CoWebsiteStore.ts b/front/src/Stores/CoWebsiteStore.ts new file mode 100644 index 00000000..57779e58 --- /dev/null +++ b/front/src/Stores/CoWebsiteStore.ts @@ -0,0 +1,66 @@ +import { derived, get, writable } from "svelte/store"; +import type { CoWebsite } from "../WebRtc/CoWebsiteManager"; +import { highlightedEmbedScreen } from "./EmbedScreensStore"; + +function createCoWebsiteStore() { + const { subscribe, set, update } = writable(Array()); + + set(Array()); + + 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()); + }, + }; +} + +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") +); + +export const coWebsiteThumbails = derived( + [coWebsites, highlightedEmbedScreen, mainCoWebsite], + ([$coWebsites, highlightedEmbedScreen, $mainCoWebsite]) => + $coWebsites.filter((coWebsite, index) => { + return ( + (!$mainCoWebsite || $mainCoWebsite.iframe.id !== coWebsite.iframe.id) && + (!highlightedEmbedScreen || + highlightedEmbedScreen.type !== "cowebsite" || + (highlightedEmbedScreen.type === "cowebsite" && + highlightedEmbedScreen.embed.iframe.id !== coWebsite.iframe.id)) + ); + }) +); diff --git a/front/src/Stores/EmbedScreensStore.ts b/front/src/Stores/EmbedScreensStore.ts new file mode 100644 index 00000000..0db7c675 --- /dev/null +++ b/front/src/Stores/EmbedScreensStore.ts @@ -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(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.Presentation); + +export const hasEmbedScreen = derived( + [streamableCollectionStore], + ($values) => get(streamableCollectionStore).size + get(coWebsites).length > 0 +); diff --git a/front/src/WebRtc/CoWebsiteManager.ts b/front/src/WebRtc/CoWebsiteManager.ts index 92629dd6..ae61f35d 100644 --- a/front/src/WebRtc/CoWebsiteManager.ts +++ b/front/src/WebRtc/CoWebsiteManager.ts @@ -2,7 +2,13 @@ import { HtmlUtils } from "./HtmlUtils"; import { Subject } from "rxjs"; import { iframeListener } from "../Api/IframeListener"; import { waScaleManager } from "../Phaser/Services/WaScaleManager"; -import { ICON_URL } from "../Enum/EnvironmentVariable"; +import { coWebsites, coWebsitesNotAsleep, mainCoWebsite } from "../Stores/CoWebsiteStore"; +import { get, Writable, writable } from "svelte/store"; +import { embedScreenLayout, highlightedEmbedScreen } from "../Stores/EmbedScreensStore"; +import { isMediaBreakpointDown } from "../Utils/BreakpointsUtils"; +import { jitsiFactory } from "./JitsiFactory"; +import { gameManager } from "../Phaser/Game/GameManager"; +import { LayoutMode } from "./LayoutManager"; enum iframeStates { closed = 1, @@ -11,16 +17,15 @@ enum iframeStates { } const cowebsiteDomId = "cowebsite"; // the id of the whole container. -const cowebsiteContainerDomId = "cowebsite-container"; // the id of the whole container. -const cowebsiteMainDomId = "cowebsite-slot-0"; // the id of the parent div of the iframe. +const gameOverlayDomId = "game-overlay"; const cowebsiteBufferDomId = "cowebsite-buffer"; // the id of the container who contains cowebsite iframes. -const cowebsiteAsideDomId = "cowebsite-aside"; // the id of the parent div of the iframe. const cowebsiteAsideHolderDomId = "cowebsite-aside-holder"; -const cowebsiteSubIconsDomId = "cowebsite-sub-icons"; +const cowebsiteLoaderDomId = "cowebsite-loader"; export const cowebsiteCloseButtonId = "cowebsite-close"; const cowebsiteFullScreenButtonId = "cowebsite-fullscreen"; const cowebsiteOpenFullScreenImageId = "cowebsite-fullscreen-open"; const cowebsiteCloseFullScreenImageId = "cowebsite-fullscreen-close"; +const cowebsiteSlotBaseDomId = "cowebsite-slot-"; const animationTime = 500; //time used by the css transitions, in ms. interface TouchMoveCoordinates { @@ -28,15 +33,16 @@ interface TouchMoveCoordinates { y: number; } +export type CoWebsiteState = "asleep" | "loading" | "ready"; + export type CoWebsite = { iframe: HTMLIFrameElement; - icon: HTMLDivElement; - position: number; -}; - -type CoWebsiteSlot = { - container: HTMLElement; - position: number; + url: URL; + state: Writable; + closable: boolean; + allowPolicy: string | undefined; + allowApi: boolean | undefined; + jitsi?: boolean; }; class CoWebsiteManager { @@ -50,18 +56,17 @@ class CoWebsiteManager { */ private currentOperationPromise: Promise = Promise.resolve(); private cowebsiteDom: HTMLDivElement; - private cowebsiteContainerDom: HTMLDivElement; private resizing: boolean = false; - private cowebsiteMainDom: HTMLDivElement; + private gameOverlayDom: HTMLDivElement; private cowebsiteBufferDom: HTMLDivElement; - private cowebsiteAsideDom: HTMLDivElement; private cowebsiteAsideHolderDom: HTMLDivElement; - private cowebsiteSubIconsDom: HTMLDivElement; + private cowebsiteLoaderDom: HTMLDivElement; private previousTouchMoveCoordinates: TouchMoveCoordinates | null = null; //only use on touchscreens to track touch movement - private coWebsites: CoWebsite[] = []; - - private slots: CoWebsiteSlot[]; + private loaderAnimationInterval: { + interval: NodeJS.Timeout | undefined; + trails: number[] | undefined; + }; private resizeObserver = new ResizeObserver((entries) => { this.resizeAllIframes(); @@ -97,59 +102,39 @@ class CoWebsiteManager { constructor() { this.cowebsiteDom = HtmlUtils.getElementByIdOrFail(cowebsiteDomId); - this.cowebsiteContainerDom = HtmlUtils.getElementByIdOrFail(cowebsiteContainerDomId); - this.cowebsiteMainDom = HtmlUtils.getElementByIdOrFail(cowebsiteMainDomId); + this.gameOverlayDom = HtmlUtils.getElementByIdOrFail(gameOverlayDomId); this.cowebsiteBufferDom = HtmlUtils.getElementByIdOrFail(cowebsiteBufferDomId); - this.cowebsiteAsideDom = HtmlUtils.getElementByIdOrFail(cowebsiteAsideDomId); this.cowebsiteAsideHolderDom = HtmlUtils.getElementByIdOrFail(cowebsiteAsideHolderDomId); - this.cowebsiteSubIconsDom = HtmlUtils.getElementByIdOrFail(cowebsiteSubIconsDomId); - this.initResizeListeners(); + this.cowebsiteLoaderDom = HtmlUtils.getElementByIdOrFail(cowebsiteLoaderDomId); + + this.loaderAnimationInterval = { + interval: undefined, + trails: undefined, + }; + + this.holderListeners(); + this.transitionListeners(); this.resizeObserver.observe(this.cowebsiteDom); - this.resizeObserver.observe(this.cowebsiteContainerDom); - - this.slots = [ - { - container: this.cowebsiteMainDom, - position: 0, - }, - { - container: HtmlUtils.getElementByIdOrFail("cowebsite-slot-1"), - position: 1, - }, - { - container: HtmlUtils.getElementByIdOrFail("cowebsite-slot-2"), - position: 2, - }, - { - container: HtmlUtils.getElementByIdOrFail("cowebsite-slot-3"), - position: 3, - }, - { - container: HtmlUtils.getElementByIdOrFail("cowebsite-slot-4"), - position: 4, - }, - ]; - - this.slots.forEach((slot) => { - this.resizeObserver.observe(slot.container); - }); - - this.initActionsListeners(); + this.resizeObserver.observe(this.gameOverlayDom); const buttonCloseCoWebsites = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId); buttonCloseCoWebsites.addEventListener("click", () => { - if (this.isSmallScreen() && this.coWebsites.length > 1) { - const coWebsite = this.getCoWebsiteByPosition(0); + const coWebsite = this.getMainCoWebsite(); - if (coWebsite) { - this.removeCoWebsiteFromStack(coWebsite); - return; - } + if (!coWebsite) { + throw new Error("Undefined main co-website on closing"); } - buttonCloseCoWebsites.blur(); - this.closeCoWebsites().catch((e) => console.error(e)); + if (coWebsite.closable) { + this.closeCoWebsite(coWebsite).catch(() => { + console.error("Error during closing a co-website by a button"); + }); + } else { + this.unloadCoWebsite(coWebsite).catch(() => { + console.error("Error during unloading a co-website by a button"); + }); + } }); const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId); @@ -159,20 +144,17 @@ class CoWebsiteManager { }); } + public getCoWebsiteBuffer(): HTMLDivElement { + return this.cowebsiteBufferDom; + } + public getDevicePixelRatio(): number { //on chrome engines, movementX and movementY return global screens coordinates while other browser return pixels //so on chrome-based browser we need to adjust using 'devicePixelRatio' return window.navigator.userAgent.includes("Firefox") ? 1 : window.devicePixelRatio; } - private isSmallScreen(): boolean { - return ( - window.matchMedia("(max-aspect-ratio: 1/1)").matches || - window.matchMedia("(max-width:960px) and (max-height:768px)").matches - ); - } - - private initResizeListeners() { + private holderListeners() { const movecallback = (event: MouseEvent | TouchEvent) => { let x, y; if (event.type === "mousemove") { @@ -187,13 +169,48 @@ class CoWebsiteManager { y = last.y - previous.y; } - this.verticalMode ? (this.height += y) : (this.width -= x); + if (this.verticalMode) { + const tempValue = this.height + y; + let maxHeight = 60 * window.innerHeight; + if (maxHeight !== 0) { + maxHeight = Math.round(maxHeight / 100); + } + + if (tempValue < this.cowebsiteAsideHolderDom.offsetHeight) { + this.height = this.cowebsiteAsideHolderDom.offsetHeight; + } else if (tempValue > maxHeight) { + this.height = maxHeight; + } else { + this.height = tempValue; + } + } else { + const tempValue = this.width - x; + let maxWidth = 75 * window.innerWidth; + if (maxWidth !== 0) { + maxWidth = Math.round(maxWidth / 100); + } + + if (tempValue < this.cowebsiteAsideHolderDom.offsetWidth) { + this.width = this.cowebsiteAsideHolderDom.offsetWidth; + } else if (tempValue > maxWidth) { + this.width = maxWidth; + } else { + this.width = tempValue; + } + } this.fire(); }; this.cowebsiteAsideHolderDom.addEventListener("mousedown", (event) => { if (this.isFullScreen) return; - this.cowebsiteMainDom.style.display = "none"; + const coWebsite = this.getMainCoWebsite(); + + if (!coWebsite) { + this.closeMain(); + return; + } + + coWebsite.iframe.style.display = "none"; this.resizing = true; document.addEventListener("mousemove", movecallback); }); @@ -201,14 +218,28 @@ class CoWebsiteManager { document.addEventListener("mouseup", (event) => { if (!this.resizing || this.isFullScreen) return; document.removeEventListener("mousemove", movecallback); - this.cowebsiteMainDom.style.display = "block"; + const coWebsite = this.getMainCoWebsite(); + + if (!coWebsite) { + this.resizing = false; + this.closeMain(); + return; + } + + coWebsite.iframe.style.display = "flex"; this.resizing = false; - this.cowebsiteMainDom.style.display = "flex"; }); this.cowebsiteAsideHolderDom.addEventListener("touchstart", (event) => { if (this.isFullScreen) return; - this.cowebsiteMainDom.style.display = "none"; + const coWebsite = this.getMainCoWebsite(); + + if (!coWebsite) { + this.closeMain(); + return; + } + + coWebsite.iframe.style.display = "none"; this.resizing = true; const touchEvent = event.touches[0]; this.previousTouchMoveCoordinates = { x: touchEvent.pageX, y: touchEvent.pageY }; @@ -219,30 +250,81 @@ class CoWebsiteManager { if (!this.resizing || this.isFullScreen) return; this.previousTouchMoveCoordinates = null; document.removeEventListener("touchmove", movecallback); - this.cowebsiteMainDom.style.display = "block"; + const coWebsite = this.getMainCoWebsite(); + + if (!coWebsite) { + this.closeMain(); + this.resizing = false; + return; + } + + coWebsite.iframe.style.display = "flex"; this.resizing = false; - this.cowebsiteMainDom.style.display = "flex"; + }); + } + + private transitionListeners() { + this.cowebsiteDom.addEventListener("transitionend", (event) => { + if (this.cowebsiteDom.classList.contains("loading")) { + this.fire(); + } + + if (this.cowebsiteDom.classList.contains("closing")) { + this.cowebsiteDom.classList.remove("closing"); + if (this.loaderAnimationInterval.interval) { + clearInterval(this.loaderAnimationInterval.interval); + } + this.loaderAnimationInterval.trails = undefined; + } }); } private closeMain(): void { - this.cowebsiteDom.classList.remove("loaded"); //edit the css class to trigger the transition - this.cowebsiteDom.classList.add("hidden"); + this.toggleFullScreenIcon(true); + this.cowebsiteDom.classList.add("closing"); + this.cowebsiteDom.classList.remove("opened"); this.openedMain = iframeStates.closed; this.resetStyleMain(); - this.cowebsiteDom.style.display = "none"; + this.fire(); } + private loadMain(): void { - this.cowebsiteDom.style.display = "flex"; - this.cowebsiteDom.classList.remove("hidden"); //edit the css class to trigger the transition - this.cowebsiteDom.classList.add("loading"); + this.loaderAnimationInterval.interval = setInterval(() => { + if (!this.loaderAnimationInterval.trails) { + this.loaderAnimationInterval.trails = [0, 1, 2]; + } + + for (let trail = 1; trail < this.loaderAnimationInterval.trails.length + 1; trail++) { + for (let state = 0; state < 4; state++) { + // const newState = this.loaderAnimationInterval.frames + trail -1; + const stateDom = this.cowebsiteLoaderDom.querySelector( + `#trail-${trail}-state-${state}` + ) as SVGPolygonElement; + + if (!stateDom) { + continue; + } + + stateDom.style.visibility = + this.loaderAnimationInterval.trails[trail - 1] !== 0 && + this.loaderAnimationInterval.trails[trail - 1] >= state + ? "visible" + : "hidden"; + } + } + + this.loaderAnimationInterval.trails = this.loaderAnimationInterval.trails.map((trail) => + trail === 3 ? 0 : trail + 1 + ); + }, 200); + this.cowebsiteDom.classList.add("opened"); this.openedMain = iframeStates.loading; } + private openMain(): void { this.cowebsiteDom.addEventListener("transitionend", () => { this.resizeAllIframes(); }); - this.cowebsiteDom.classList.remove("loading", "hidden"); //edit the css class to trigger the transition this.openedMain = iframeStates.opened; this.resetStyleMain(); } @@ -252,335 +334,321 @@ class CoWebsiteManager { this.cowebsiteDom.style.height = ""; } - private initActionsListeners() { - this.slots.forEach((slot: CoWebsiteSlot) => { - const expandButton = slot.container.querySelector(".expand"); - const highlightButton = slot.container.querySelector(".hightlight"); - const closeButton = slot.container.querySelector(".close"); - - if (expandButton) { - expandButton.addEventListener("click", (event) => { - event.preventDefault(); - const coWebsite = this.getCoWebsiteByPosition(slot.position); - - if (!coWebsite) { - return; - } - - this.moveRightPreviousCoWebsite(coWebsite, 0); - }); - } - - if (highlightButton) { - highlightButton.addEventListener("click", (event) => { - event.preventDefault(); - const coWebsite = this.getCoWebsiteByPosition(slot.position); - - if (!coWebsite) { - return; - } - - this.moveRightPreviousCoWebsite(coWebsite, 1); - }); - } - - if (closeButton) { - closeButton.addEventListener("click", (event) => { - event.preventDefault(); - const coWebsite = this.getCoWebsiteByPosition(slot.position); - - if (!coWebsite) { - return; - } - - this.removeCoWebsiteFromStack(coWebsite); - }); - } - }); - } - public getCoWebsites(): CoWebsite[] { - return this.coWebsites; + return get(coWebsites); } public getCoWebsiteById(coWebsiteId: string): CoWebsite | undefined { - return this.coWebsites.find((coWebsite: CoWebsite) => coWebsite.iframe.id === coWebsiteId); - } - - private getSlotByPosition(position: number): CoWebsiteSlot | undefined { - return this.slots.find((slot: CoWebsiteSlot) => slot.position === position); + return get(coWebsites).find((coWebsite: CoWebsite) => coWebsite.iframe.id === coWebsiteId); } private getCoWebsiteByPosition(position: number): CoWebsite | undefined { - return this.coWebsites.find((coWebsite: CoWebsite) => coWebsite.position === position); - } - - private setIframeOffset(coWebsite: CoWebsite, slot: CoWebsiteSlot) { - const bounding = slot.container.getBoundingClientRect(); - - if (coWebsite.iframe.classList.contains("thumbnail")) { - coWebsite.iframe.style.width = (bounding.right - bounding.left) * 2 + "px"; - coWebsite.iframe.style.height = (bounding.bottom - bounding.top) * 2 + "px"; - coWebsite.iframe.style.top = bounding.top - Math.floor(bounding.height * 0.5) + "px"; - coWebsite.iframe.style.left = bounding.left - Math.floor(bounding.width * 0.5) + "px"; - } else { - coWebsite.iframe.style.top = bounding.top + "px"; - coWebsite.iframe.style.left = bounding.left + "px"; - coWebsite.iframe.style.width = bounding.right - bounding.left + "px"; - coWebsite.iframe.style.height = bounding.bottom - bounding.top + "px"; - } - } - - private resizeAllIframes() { - this.coWebsites.forEach((coWebsite: CoWebsite) => { - const slot = this.getSlotByPosition(coWebsite.position); - - if (slot) { - this.setIframeOffset(coWebsite, slot); + let i = 0; + return get(coWebsites).find((coWebsite: CoWebsite) => { + if (i === position) { + return coWebsite; } + + i++; + return false; }); } - private moveCoWebsite(coWebsite: CoWebsite, newPosition: number) { - const oldSlot = this.getSlotByPosition(coWebsite.position); - const newSlot = this.getSlotByPosition(newPosition); + private getMainCoWebsite(): CoWebsite | undefined { + return get(mainCoWebsite); + } - if (!newSlot) { + private getPositionByCoWebsite(coWebsite: CoWebsite): number { + return get(coWebsites).findIndex((currentCoWebsite) => currentCoWebsite.iframe.id === coWebsite.iframe.id); + } + + private getSlotByCowebsite(coWebsite: CoWebsite): HTMLDivElement | undefined { + const index = this.getPositionByCoWebsite(coWebsite); + if (index === -1) { + return undefined; + } + + let id = cowebsiteSlotBaseDomId; + + if (index === 0) { + id += "main"; + } else { + id += coWebsite.iframe.id; + } + + const slot = HtmlUtils.getElementById(id); + + return slot; + } + + private setIframeOffset(coWebsite: CoWebsite) { + const coWebsiteSlot = this.getSlotByCowebsite(coWebsite); + + if (!coWebsiteSlot) { return; } - coWebsite.iframe.scrolling = newPosition === 0 || newPosition === 1 ? "yes" : "no"; + const bounding = coWebsiteSlot.getBoundingClientRect(); - if (newPosition === 0) { - coWebsite.iframe.classList.add("main"); - coWebsite.icon.style.display = "none"; - } else { - coWebsite.iframe.classList.remove("main"); - coWebsite.icon.style.display = "flex"; + coWebsite.iframe.style.top = bounding.top + "px"; + coWebsite.iframe.style.left = bounding.left + "px"; + coWebsite.iframe.style.width = bounding.right - bounding.left + "px"; + coWebsite.iframe.style.height = bounding.bottom - bounding.top + "px"; + } + + public resizeAllIframes() { + const mainCoWebsite = this.getCoWebsiteByPosition(0); + const highlightEmbed = get(highlightedEmbedScreen); + + get(coWebsites).forEach((coWebsite) => { + const notMain = !mainCoWebsite || (mainCoWebsite && mainCoWebsite.iframe.id !== coWebsite.iframe.id); + const notHighlighEmbed = + !highlightEmbed || + (highlightEmbed && + (highlightEmbed.type !== "cowebsite" || + (highlightEmbed.type === "cowebsite" && + highlightEmbed.embed.iframe.id !== coWebsite.iframe.id))); + + if (coWebsite.iframe.classList.contains("main") && notMain) { + coWebsite.iframe.classList.remove("main"); + } + + if (coWebsite.iframe.classList.contains("highlighted") && notHighlighEmbed) { + coWebsite.iframe.classList.remove("highlighted"); + coWebsite.iframe.classList.add("pixel"); + coWebsite.iframe.style.top = "-1px"; + coWebsite.iframe.style.left = "-1px"; + } + + if (notMain && notHighlighEmbed) { + coWebsite.iframe.classList.add("pixel"); + coWebsite.iframe.style.top = "-1px"; + coWebsite.iframe.style.left = "-1px"; + } + + this.setIframeOffset(coWebsite); + }); + + if (mainCoWebsite) { + mainCoWebsite.iframe.classList.add("main"); + mainCoWebsite.iframe.classList.remove("pixel"); } - if (newPosition === 1) { - coWebsite.iframe.classList.add("sub-main"); - } else { - coWebsite.iframe.classList.remove("sub-main"); + if (highlightEmbed && highlightEmbed.type === "cowebsite") { + highlightEmbed.embed.iframe.classList.add("highlighted"); + highlightEmbed.embed.iframe.classList.remove("pixel"); + } + } + + private removeHighlightCoWebsite(coWebsite: CoWebsite) { + const highlighted = get(highlightedEmbedScreen); + + if (highlighted && highlighted.type === "cowebsite" && highlighted.embed.iframe.id === coWebsite.iframe.id) { + highlightedEmbedScreen.removeHighlight(); + } + } + + private removeCoWebsiteFromStack(coWebsite: CoWebsite) { + this.removeHighlightCoWebsite(coWebsite); + coWebsites.remove(coWebsite); + + if (get(coWebsites).length < 1) { + this.closeMain(); } - if (newPosition >= 2) { - coWebsite.iframe.classList.add("thumbnail"); - } else { - coWebsite.iframe.classList.remove("thumbnail"); + coWebsite.iframe.remove(); + } + + public goToMain(coWebsite: CoWebsite) { + const mainCoWebsite = this.getMainCoWebsite(); + coWebsites.remove(coWebsite); + coWebsites.add(coWebsite, 0); + + if ( + isMediaBreakpointDown("lg") && + get(embedScreenLayout) === LayoutMode.Presentation && + mainCoWebsite && + mainCoWebsite.iframe.id !== coWebsite.iframe.id && + get(mainCoWebsite.state) !== "asleep" + ) { + highlightedEmbedScreen.toggleHighlight({ + type: "cowebsite", + embed: mainCoWebsite, + }); } - coWebsite.position = newPosition; - - if (oldSlot && !this.getCoWebsiteByPosition(oldSlot.position)) { - oldSlot.container.style.display = "none"; - } - - this.displayCowebsiteContainer(); - - newSlot.container.style.display = "block"; - - coWebsite.iframe.classList.remove("pixel"); - this.resizeAllIframes(); } - private displayCowebsiteContainer() { - if (this.coWebsites.find((cowebsite) => cowebsite.position > 0)) { - this.cowebsiteContainerDom.style.display = "block"; - } else { - this.cowebsiteContainerDom.style.display = "none"; - } - } - - private moveLeftPreviousCoWebsite(coWebsite: CoWebsite, newPosition: number) { - const nextCoWebsite = this.getCoWebsiteByPosition(coWebsite.position + 1); - - this.moveCoWebsite(coWebsite, newPosition); - - if (nextCoWebsite) { - this.moveLeftPreviousCoWebsite(nextCoWebsite, nextCoWebsite.position - 1); - } - } - - private moveRightPreviousCoWebsite(coWebsite: CoWebsite, newPosition: number) { - if (newPosition >= 5) { - return; - } - - const currentCoWebsite = this.getCoWebsiteByPosition(newPosition); - - this.moveCoWebsite(coWebsite, newPosition); - - if (newPosition === 4 || !currentCoWebsite || currentCoWebsite.iframe.id === coWebsite.iframe.id) { - return; - } - - if (!currentCoWebsite) { - return; - } - - this.moveRightPreviousCoWebsite(currentCoWebsite, currentCoWebsite.position + 1); - } - - private removeCoWebsiteFromStack(coWebsite: CoWebsite) { - this.coWebsites = this.coWebsites.filter( - (coWebsiteToRemove: CoWebsite) => coWebsiteToRemove.iframe.id !== coWebsite.iframe.id - ); - - if (this.coWebsites.length < 1) { - this.closeMain(); - } - - if (coWebsite.position > 0) { - const slot = this.getSlotByPosition(coWebsite.position); - if (slot) { - slot.container.style.display = "none"; - } - } - - const previousCoWebsite = this.coWebsites.find( - (coWebsiteToCheck: CoWebsite) => coWebsite.position + 1 === coWebsiteToCheck.position - ); - - if (previousCoWebsite) { - this.moveLeftPreviousCoWebsite(previousCoWebsite, coWebsite.position); - } - - this.displayCowebsiteContainer(); - - coWebsite.icon.remove(); - coWebsite.iframe.remove(); - } - public searchJitsi(): CoWebsite | undefined { - return this.coWebsites.find((coWebsite: CoWebsite) => coWebsite.iframe.id.toLowerCase().includes("jitsi")); + return get(coWebsites).find((coWebsite: CoWebsite) => coWebsite.jitsi); } - private generateCoWebsiteIcon(iframe: HTMLIFrameElement): HTMLDivElement { - const icon = document.createElement("div"); - icon.id = "cowebsite-icon-" + iframe.id; - icon.style.display = "none"; + private initialiseCowebsite(coWebsite: CoWebsite, position: number | undefined) { + if (coWebsite.allowPolicy) { + coWebsite.iframe.allow = coWebsite.allowPolicy; + } - const iconImage = document.createElement("img"); - iconImage.src = `${ICON_URL}/icon?url=${iframe.src}&size=16..30..256`; - const url = new URL(iframe.src); - iconImage.alt = url.hostname; + if (coWebsite.allowApi) { + iframeListener.registerIframe(coWebsite.iframe); + } - icon.appendChild(iconImage); + coWebsite.iframe.classList.add("pixel"); - return icon; + const coWebsitePosition = position === undefined ? get(coWebsites).length : position; + coWebsites.add(coWebsite, coWebsitePosition); } - public loadCoWebsite( + private generateUniqueId() { + let id = undefined; + do { + id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7); + } while (this.getCoWebsiteById(id)); + + return id; + } + + public addCoWebsite( url: string, base: string, allowApi?: boolean, allowPolicy?: string, - widthPercent?: number, - position?: number - ): Promise { - return this.addCoWebsite( - (iframeBuffer) => { - const iframe = document.createElement("iframe"); - iframe.src = new URL(url, base).toString(); + position?: number, + closable?: boolean + ): CoWebsite { + const iframe = document.createElement("iframe"); + const fullUrl = new URL(url, base); + iframe.src = fullUrl.toString(); + iframe.id = this.generateUniqueId(); - if (allowPolicy) { - iframe.allow = allowPolicy; - } + const newCoWebsite: CoWebsite = { + iframe, + url: fullUrl, + state: writable("asleep" as CoWebsiteState), + closable: closable ?? false, + allowPolicy, + allowApi, + }; - if (allowApi) { - iframeListener.registerIframe(iframe); - } + this.initialiseCowebsite(newCoWebsite, position); - iframeBuffer.appendChild(iframe); - - return iframe; - }, - widthPercent, - position - ); + return newCoWebsite; } - public async addCoWebsite( - callback: (iframeBuffer: HTMLDivElement) => PromiseLike | HTMLIFrameElement, - widthPercent?: number, - position?: number - ): Promise { + public addCoWebsiteFromIframe( + iframe: HTMLIFrameElement, + allowApi?: boolean, + allowPolicy?: string, + position?: number, + closable?: boolean, + jitsi?: boolean + ): CoWebsite { + if (get(coWebsitesNotAsleep).length < 1) { + this.loadMain(); + } + + iframe.id = this.generateUniqueId(); + + const newCoWebsite: CoWebsite = { + iframe, + url: new URL(iframe.src), + state: writable("ready" as CoWebsiteState), + closable: closable ?? false, + allowPolicy, + allowApi, + jitsi, + }; + + if (position === 0) { + this.openMain(); + setTimeout(() => { + this.fire(); + }, animationTime); + } + + this.initialiseCowebsite(newCoWebsite, position); + + return newCoWebsite; + } + + public loadCoWebsite(coWebsite: CoWebsite): Promise { + if (get(coWebsitesNotAsleep).length < 1) { + coWebsites.remove(coWebsite); + coWebsites.add(coWebsite, 0); + this.loadMain(); + } + + coWebsite.state.set("loading"); + + const mainCoWebsite = this.getMainCoWebsite(); + return new Promise((resolve, reject) => { - if (this.coWebsites.length < 1) { - this.loadMain(); - } else if (this.coWebsites.length === 5) { - throw new Error("Too many websites"); + const onloadPromise = new Promise((resolve) => { + coWebsite.iframe.onload = () => { + coWebsite.state.set("ready"); + resolve(); + }; + }); + + const onTimeoutPromise = new Promise((resolve) => { + setTimeout(() => resolve(), 2000); + }); + + this.cowebsiteBufferDom.appendChild(coWebsite.iframe); + + if (coWebsite.jitsi) { + const gameScene = gameManager.getCurrentGameScene(); + gameScene.disableMediaBehaviors(); } - Promise.resolve(callback(this.cowebsiteBufferDom)) - .then((iframe) => { - iframe?.classList.add("pixel"); + this.currentOperationPromise = this.currentOperationPromise + .then(() => Promise.race([onloadPromise, onTimeoutPromise])) + .then(() => { + if (mainCoWebsite && mainCoWebsite.iframe.id === coWebsite.iframe.id) { + this.openMain(); - if (!iframe.id) { - do { - iframe.id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7); - } while (this.getCoWebsiteById(iframe.id)); + setTimeout(() => { + this.fire(); + }, animationTime); } - const onloadPromise = new Promise((resolve) => { - iframe.onload = () => resolve(); - }); - - const icon = this.generateCoWebsiteIcon(iframe); - - const coWebsite = { - iframe, - icon, - position: position ?? this.coWebsites.length, - }; - - // Iframe management on mobile - icon.addEventListener("click", () => { - if (this.isSmallScreen()) { - this.moveRightPreviousCoWebsite(coWebsite, 0); - } - }); - - this.coWebsites.push(coWebsite); - this.cowebsiteSubIconsDom.appendChild(icon); - - const onTimeoutPromise = new Promise((resolve) => { - setTimeout(() => resolve(), 2000); - }); - - this.currentOperationPromise = this.currentOperationPromise - .then(() => Promise.race([onloadPromise, onTimeoutPromise])) - .then(() => { - if (coWebsite.position === 0) { - this.openMain(); - if (widthPercent) { - this.widthPercent = widthPercent; - } - - setTimeout(() => { - this.fire(); - position !== undefined - ? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position) - : this.moveCoWebsite(coWebsite, coWebsite.position); - }, animationTime); - } else { - position !== undefined - ? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position) - : this.moveCoWebsite(coWebsite, coWebsite.position); - } - - return resolve(coWebsite); - }) - .catch((err) => { - console.error("Error loadCoWebsite => ", err); - this.removeCoWebsiteFromStack(coWebsite); - return reject(); - }); + return resolve(coWebsite); }) - .catch((e) => console.error("Error loadCoWebsite => ", e)); + .catch((err) => { + console.error("Error on co-website loading => ", err); + this.removeCoWebsiteFromStack(coWebsite); + return reject(); + }); + }); + } + + public unloadCoWebsite(coWebsite: CoWebsite): Promise { + return new Promise((resolve, reject) => { + this.removeHighlightCoWebsite(coWebsite); + + coWebsite.iframe.parentNode?.removeChild(coWebsite.iframe); + coWebsite.state.set("asleep"); + coWebsites.remove(coWebsite); + + if (coWebsite.jitsi) { + jitsiFactory.stop(); + const gameScene = gameManager.getCurrentGameScene(); + gameScene.enableMediaBehaviors(); + } + + const mainCoWebsite = this.getMainCoWebsite(); + + if (mainCoWebsite) { + this.removeHighlightCoWebsite(mainCoWebsite); + this.goToMain(mainCoWebsite); + this.resizeAllIframes(); + } else { + this.closeMain(); + } + + coWebsites.add(coWebsite, get(coWebsites).length); + + resolve(); }); } @@ -588,13 +656,17 @@ class CoWebsiteManager { this.currentOperationPromise = this.currentOperationPromise.then( () => new Promise((resolve) => { - if (this.coWebsites.length === 1) { - if (this.openedMain === iframeStates.closed) resolve(); //this method may be called twice, in case of iframe error for example - this.closeMain(); + if (coWebsite.jitsi) { + jitsiFactory.stop(); + const gameScene = gameManager.getCurrentGameScene(); + gameScene.enableMediaBehaviors(); + } + + if (get(coWebsites).length === 1) { this.fire(); } - if (coWebsite) { + if (coWebsite.allowApi) { iframeListener.unregisterIframe(coWebsite.iframe); } @@ -605,27 +677,19 @@ class CoWebsiteManager { return this.currentOperationPromise; } - public async closeJitsi() { - const jitsi = this.searchJitsi(); - if (jitsi) { - return this.closeCoWebsite(jitsi); - } - } - - public async closeCoWebsites(): Promise { - await this.currentOperationPromise; - - const promises: Promise[] = []; - this.coWebsites.forEach((coWebsite: CoWebsite) => { - promises.push(this.closeCoWebsite(coWebsite)); - }); - await Promise.all(promises); - // TODO: this.currentOperationPromise does not point any more on the last promise - return; + public closeCoWebsites(): Promise { + return (this.currentOperationPromise = this.currentOperationPromise.then(() => { + get(coWebsites).forEach((coWebsite: CoWebsite) => { + this.closeCoWebsite(coWebsite).catch(() => { + console.error("Error during closing a co-website"); + }); + }); + })); + return this.currentOperationPromise; } public getGameSize(): { width: number; height: number } { - if (this.openedMain !== iframeStates.opened) { + if (this.openedMain === iframeStates.closed) { return { width: window.innerWidth, height: window.innerHeight, @@ -651,19 +715,27 @@ class CoWebsiteManager { } private fullscreen(): void { - const openFullscreenImage = HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId); - const closeFullScreenImage = HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId); - if (this.isFullScreen) { + this.toggleFullScreenIcon(true); this.resetStyleMain(); this.fire(); //we don't trigger a resize of the phaser game since it won't be visible anyway. + } else { + this.toggleFullScreenIcon(false); + this.verticalMode ? (this.height = window.innerHeight) : (this.width = window.innerWidth); + //we don't trigger a resize of the phaser game since it won't be visible anyway. + } + } + + private toggleFullScreenIcon(visible: boolean) { + const openFullscreenImage = HtmlUtils.getElementByIdOrFail(cowebsiteOpenFullScreenImageId); + const closeFullScreenImage = HtmlUtils.getElementByIdOrFail(cowebsiteCloseFullScreenImageId); + + if (visible) { this.cowebsiteAsideHolderDom.style.visibility = "visible"; openFullscreenImage.style.display = "inline"; closeFullScreenImage.style.display = "none"; } else { - this.verticalMode ? (this.height = window.innerHeight) : (this.width = window.innerWidth); - //we don't trigger a resize of the phaser game since it won't be visible anyway. this.cowebsiteAsideHolderDom.style.visibility = "hidden"; openFullscreenImage.style.display = "none"; closeFullScreenImage.style.display = "inline"; diff --git a/front/src/WebRtc/JitsiFactory.ts b/front/src/WebRtc/JitsiFactory.ts index c067a255..8f9524a2 100644 --- a/front/src/WebRtc/JitsiFactory.ts +++ b/front/src/WebRtc/JitsiFactory.ts @@ -132,64 +132,64 @@ 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 { - 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('[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); - }); - }, - jitsiWidth, - 0 - ); + 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('[id*="jitsi" i]'); + if (iframe) { + coWebsiteManager.addCoWebsiteFromIframe(iframe, false, undefined, 0, false, true); + } + + coWebsiteManager.resizeAllIframes(); + }; + + 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); } public stop() { @@ -197,12 +197,6 @@ 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); this.jitsiApi?.dispose(); diff --git a/front/style/cowebsite.scss b/front/style/cowebsite.scss index a6af21ee..529bcae1 100644 --- a/front/style/cowebsite.scss +++ b/front/style/cowebsite.scss @@ -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"; diff --git a/front/style/cowebsite/_global.scss b/front/style/cowebsite/_global.scss new file mode 100644 index 00000000..b9d8e2ee --- /dev/null +++ b/front/style/cowebsite/_global.scss @@ -0,0 +1,119 @@ +#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; + } + + .top-right-btn { + transform: scale(0.5); + cursor: url("./images/cursor_pointer.png"), pointer; + } + + #cowebsite-other-actions { + display: flex; + margin-top: auto; + visibility: hidden; + justify-content: end; + flex: 1; + } + } + + &-loader { + width: 20%; + + #smoke { + @for $i from 1 through 3 { + #trail-#{$i} { + @for $y from 1 through 3 { + #trail-#{$i}-state-#{$y} { + visibility: hidden; + } + } + } + } + } + } + + &-slot-main { + z-index: 70 !important; + background-color: rgba(10, 9, 9, 0); + display: flex; + justify-content: center; + align-items: center; + } + + &-buffer { + iframe { + z-index: 45 !important; + pointer-events: none !important; + overflow: hidden; + border: 0; + position: absolute; + + &.pixel { + height: 1px !important; + width: 1px !important; + } + } + + .main { + pointer-events: all !important; + z-index: 821 !important; + } + + .highlighted { + pointer-events: all !important; + padding: 4px; + } + + .thumbnail { + transform: scale(0.5, 0.5); + } + } + + .pixel { + visibility: hidden; + height: 1px; + width: 1px; + } +} diff --git a/front/style/cowebsite/_short-screens.scss b/front/style/cowebsite/_short-screens.scss new file mode 100644 index 00000000..89a5d123 --- /dev/null +++ b/front/style/cowebsite/_short-screens.scss @@ -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; + } + } + } + } +} diff --git a/front/style/cowebsite/_wide-screens.scss b/front/style/cowebsite/_wide-screens.scss new file mode 100644 index 00000000..432a4dec --- /dev/null +++ b/front/style/cowebsite/_wide-screens.scss @@ -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; + } + } +} From 4436db0d3df202b98399f634432bd1f84e038063 Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Mon, 10 Jan 2022 10:43:57 +0100 Subject: [PATCH 07/16] Add new cowebsite properties on documention --- docs/maps/api-nav.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/maps/api-nav.md b/docs/maps/api-nav.md index 47ee416e..2743d1ad 100644 --- a/docs/maps/api-nav.md +++ b/docs/maps/api-nav.md @@ -52,17 +52,17 @@ WA.nav.goToRoom("/_/global/.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 +WA.nav.openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = "", position: number, closable: boolean, lazy: boolean): Promise ``` -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(); ``` From 873c33505437e48c1c98db4d4a88d5cd6b16862f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 11 Jan 2022 13:52:38 +0100 Subject: [PATCH 08/16] Removing too wide border in videos --- front/src/Components/MyCamera.svelte | 17 ++++------- front/src/Components/Video/MediaBox.svelte | 29 ++++++++++++++----- .../src/Components/Video/VideoMediaBox.svelte | 4 +++ 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/front/src/Components/MyCamera.svelte b/front/src/Components/MyCamera.svelte index c9062008..06a86e58 100644 --- a/front/src/Components/MyCamera.svelte +++ b/front/src/Components/MyCamera.svelte @@ -65,8 +65,12 @@ max-height: 20%; transition: transform 1000ms; padding: 0; - background-color: #00000099; overflow: hidden; + line-height: 0; + + &.nes-container.is-rounded { + border-image-outset: 1; + } } .my-cam-video-container.hide { @@ -76,6 +80,7 @@ .my-cam-video { background-color: #00000099; max-height: 20vh; + max-width: max(25vw, 150px); width: 100%; -webkit-transform: scaleX(-1); transform: scaleX(-1); @@ -86,14 +91,4 @@ color: white; padding: 40px 20px; } - - @include media-breakpoint-up(md) { - .my-cam-video { - width: 150px; - } - - .my-cam-video-container.hide { - right: -160px; - } - } diff --git a/front/src/Components/Video/MediaBox.svelte b/front/src/Components/Video/MediaBox.svelte index a59420c2..eca34aa5 100644 --- a/front/src/Components/Video/MediaBox.svelte +++ b/front/src/Components/Video/MediaBox.svelte @@ -5,6 +5,7 @@ import { ScreenSharingPeer } from "../../WebRtc/ScreenSharingPeer"; import LocalStreamMediaBox from "./LocalStreamMediaBox.svelte"; import type { Streamable } from "../../Stores/StreamableCollectionStore"; + import PixelContainer from "../Container/PixelContainer.svelte"; export let streamable: Streamable; export let isHightlighted = false; @@ -19,13 +20,15 @@ class:mozaic-full-width={mozaicFullWidth} class:mozaic-quarter={mozaicQuarter} > - {#if streamable instanceof VideoPeer} - - {:else if streamable instanceof ScreenSharingPeer} - - {:else} - - {/if} +
+ {#if streamable instanceof VideoPeer} + + {:else if streamable instanceof ScreenSharingPeer} + + {:else} + + {/if} +
From 78e816c6fb282e193912a0773e8ef64e8c971f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 11 Jan 2022 13:53:01 +0100 Subject: [PATCH 09/16] Removing optimization in dev to get back normal compilation times in watch mode --- front/webpack.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/webpack.config.ts b/front/webpack.config.ts index 3185b0a6..d6e54c68 100644 --- a/front/webpack.config.ts +++ b/front/webpack.config.ts @@ -163,7 +163,7 @@ module.exports = { mainFields: ["svelte", "browser", "module", "main"], }, optimization: { - minimize: true, + minimize: isProduction, minimizer: [new CssMinimizerPlugin(), "..."], }, output: { From 06dca9813c1a2d652e43819ff3a065d2e0843b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Wed, 12 Jan 2022 15:36:24 +0100 Subject: [PATCH 10/16] Removing weird border in cowebsites and cowebsite button --- .../CoWebsiteThumbnailSlot.svelte | 28 ++++++++++++++++++- .../Layouts/PresentationLayout.svelte | 6 +++- front/src/Components/Video/MediaBox.svelte | 1 - 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte b/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte index a3895a52..2fee5fd0 100644 --- a/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte +++ b/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte @@ -46,7 +46,7 @@
diff --git a/front/src/Components/Video/MediaBox.svelte b/front/src/Components/Video/MediaBox.svelte index eca34aa5..2abfa953 100644 --- a/front/src/Components/Video/MediaBox.svelte +++ b/front/src/Components/Video/MediaBox.svelte @@ -5,7 +5,6 @@ import { ScreenSharingPeer } from "../../WebRtc/ScreenSharingPeer"; import LocalStreamMediaBox from "./LocalStreamMediaBox.svelte"; import type { Streamable } from "../../Stores/StreamableCollectionStore"; - import PixelContainer from "../Container/PixelContainer.svelte"; export let streamable: Streamable; export let isHightlighted = false; From a4b4710f878532495fa6c938ce60f9b0420225f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 17 Jan 2022 10:04:54 +0100 Subject: [PATCH 11/16] Menu bar for buttons --- .../dist/resources/logos/cowebsite-swipe.svg | 1 + front/src/Components/CameraControls.svelte | 1 + .../CoWebsiteThumbnailSlot.svelte | 115 ++++++++++++------ .../EmbedScreens/CoWebsitesContainer.svelte | 16 ++- .../Layouts/PresentationLayout.svelte | 34 +----- front/src/Components/MainLayout.svelte | 14 ++- front/src/Components/MyCamera.svelte | 3 + front/src/Stores/CoWebsiteStore.ts | 15 --- front/src/WebRtc/CoWebsiteManager.ts | 33 ++++- front/style/cowebsite/_global.scss | 8 ++ 10 files changed, 146 insertions(+), 94 deletions(-) create mode 100644 front/dist/resources/logos/cowebsite-swipe.svg diff --git a/front/dist/resources/logos/cowebsite-swipe.svg b/front/dist/resources/logos/cowebsite-swipe.svg new file mode 100644 index 00000000..1d4f9ebc --- /dev/null +++ b/front/dist/resources/logos/cowebsite-swipe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/Components/CameraControls.svelte b/front/src/Components/CameraControls.svelte index adac23b0..32f4e2fc 100644 --- a/front/src/Components/CameraControls.svelte +++ b/front/src/Components/CameraControls.svelte @@ -139,6 +139,7 @@ text-align: center; align-content: center; justify-content: flex-end; + z-index: 251; &:hover { div.hide { diff --git a/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte b/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte index 2fee5fd0..a668bcf6 100644 --- a/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte +++ b/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte @@ -2,7 +2,7 @@ import { onMount } from "svelte"; import { ICON_URL } from "../../Enum/EnvironmentVariable"; - import { mainCoWebsite } from "../../Stores/CoWebsiteStore"; + import { coWebsitesNotAsleep, mainCoWebsite } from "../../Stores/CoWebsiteStore"; import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore"; import type { CoWebsite } from "../../WebRtc/CoWebsiteManager"; import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager"; @@ -22,14 +22,22 @@ icon.alt = urlObject.hostname; }); - async function toggleHighlightEmbedScreen() { + async function onClick() { if (vertical) { coWebsiteManager.goToMain(coWebsite); } else if ($mainCoWebsite) { - highlightedEmbedScreen.toggleHighlight({ - type: "cowebsite", - embed: coWebsite, - }); + 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") { @@ -42,6 +50,16 @@ 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; + }
diff --git a/front/src/Components/EmbedScreens/CoWebsitesContainer.svelte b/front/src/Components/EmbedScreens/CoWebsitesContainer.svelte index 95000daf..03cca902 100644 --- a/front/src/Components/EmbedScreens/CoWebsitesContainer.svelte +++ b/front/src/Components/EmbedScreens/CoWebsitesContainer.svelte @@ -1,13 +1,13 @@ -{#if $coWebsiteThumbails.length > 0} +{#if $coWebsites.length > 0}
- {#each [...$coWebsiteThumbails.values()] as coWebsite, index (coWebsite.iframe.id)} + {#each [...$coWebsites.values()] as coWebsite, index (coWebsite.iframe.id)} {/each}
@@ -16,13 +16,21 @@ diff --git a/front/src/Components/MainLayout.svelte b/front/src/Components/MainLayout.svelte index 6175f540..cf273e50 100644 --- a/front/src/Components/MainLayout.svelte +++ b/front/src/Components/MainLayout.svelte @@ -21,7 +21,7 @@ import ReportMenu from "./ReportMenu/ReportMenu.svelte"; import VisitCard from "./VisitCard/VisitCard.svelte"; import WarningContainer from "./WarningContainer/WarningContainer.svelte"; - import { isMediaBreakpointUp } from "../Utils/BreakpointsUtils"; + import { isMediaBreakpointDown, isMediaBreakpointUp } from "../Utils/BreakpointsUtils"; import CoWebsitesContainer from "./EmbedScreens/CoWebsitesContainer.svelte"; import FollowMenu from "./FollowMenu/FollowMenu.svelte"; import { followStateStore } from "../Stores/FollowStore"; @@ -39,10 +39,12 @@ let mainLayout: HTMLDivElement; - let displayCoWebsiteContainer = isMediaBreakpointUp("md"); + let displayCoWebsiteContainerMd = isMediaBreakpointUp("md"); + let displayCoWebsiteContainerLg = isMediaBreakpointDown("lg"); const resizeObserver = new ResizeObserver(() => { - displayCoWebsiteContainer = isMediaBreakpointUp("md"); + displayCoWebsiteContainerMd = isMediaBreakpointUp("md"); + displayCoWebsiteContainerLg = isMediaBreakpointDown("lg"); }); onMount(() => { @@ -56,7 +58,7 @@ {/if} - {#if $embedScreenLayout === LayoutMode.VideoChat || displayCoWebsiteContainer} + {#if $embedScreenLayout === LayoutMode.VideoChat || displayCoWebsiteContainerMd} {/if} @@ -118,6 +120,10 @@
+ {#if displayCoWebsiteContainerLg} + + {/if} + {#if $layoutManagerActionVisibilityStore} {/if} diff --git a/front/src/Components/MyCamera.svelte b/front/src/Components/MyCamera.svelte index 06a86e58..e84d763d 100644 --- a/front/src/Components/MyCamera.svelte +++ b/front/src/Components/MyCamera.svelte @@ -65,8 +65,11 @@ 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; diff --git a/front/src/Stores/CoWebsiteStore.ts b/front/src/Stores/CoWebsiteStore.ts index 57779e58..4227c405 100644 --- a/front/src/Stores/CoWebsiteStore.ts +++ b/front/src/Stores/CoWebsiteStore.ts @@ -1,6 +1,5 @@ import { derived, get, writable } from "svelte/store"; import type { CoWebsite } from "../WebRtc/CoWebsiteManager"; -import { highlightedEmbedScreen } from "./EmbedScreensStore"; function createCoWebsiteStore() { const { subscribe, set, update } = writable(Array()); @@ -50,17 +49,3 @@ export const coWebsitesNotAsleep = derived([coWebsites], ([$coWebsites]) => export const mainCoWebsite = derived([coWebsites], ([$coWebsites]) => $coWebsites.find((coWebsite) => get(coWebsite.state) !== "asleep") ); - -export const coWebsiteThumbails = derived( - [coWebsites, highlightedEmbedScreen, mainCoWebsite], - ([$coWebsites, highlightedEmbedScreen, $mainCoWebsite]) => - $coWebsites.filter((coWebsite, index) => { - return ( - (!$mainCoWebsite || $mainCoWebsite.iframe.id !== coWebsite.iframe.id) && - (!highlightedEmbedScreen || - highlightedEmbedScreen.type !== "cowebsite" || - (highlightedEmbedScreen.type === "cowebsite" && - highlightedEmbedScreen.embed.iframe.id !== coWebsite.iframe.id)) - ); - }) -); diff --git a/front/src/WebRtc/CoWebsiteManager.ts b/front/src/WebRtc/CoWebsiteManager.ts index ae61f35d..70f70227 100644 --- a/front/src/WebRtc/CoWebsiteManager.ts +++ b/front/src/WebRtc/CoWebsiteManager.ts @@ -25,6 +25,7 @@ export const cowebsiteCloseButtonId = "cowebsite-close"; const cowebsiteFullScreenButtonId = "cowebsite-fullscreen"; const cowebsiteOpenFullScreenImageId = "cowebsite-fullscreen-open"; const cowebsiteCloseFullScreenImageId = "cowebsite-fullscreen-close"; +const cowebsiteSwipeButtonId = "cowebsite-swipe"; const cowebsiteSlotBaseDomId = "cowebsite-slot-"; const animationTime = 500; //time used by the css transitions, in ms. @@ -118,8 +119,8 @@ class CoWebsiteManager { this.resizeObserver.observe(this.cowebsiteDom); this.resizeObserver.observe(this.gameOverlayDom); - const buttonCloseCoWebsites = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId); - buttonCloseCoWebsites.addEventListener("click", () => { + const buttonCloseCoWebsite = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId); + buttonCloseCoWebsite.addEventListener("click", () => { const coWebsite = this.getMainCoWebsite(); if (!coWebsite) { @@ -142,6 +143,24 @@ class CoWebsiteManager { buttonFullScreenFrame.blur(); this.fullscreen(); }); + + const buttonSwipe = HtmlUtils.getElementByIdOrFail(cowebsiteSwipeButtonId); + + highlightedEmbedScreen.subscribe((value) => { + if (!value || value.type !== "cowebsite") { + buttonSwipe.style.display = "none"; + return; + } + + buttonSwipe.style.display = "block"; + }); + + buttonSwipe.addEventListener("click", () => { + const highlightedEmbed = get(highlightedEmbedScreen); + if (highlightedEmbed?.type === "cowebsite") { + this.goToMain(highlightedEmbed.embed); + } + }); } public getCoWebsiteBuffer(): HTMLDivElement { @@ -671,6 +690,16 @@ class CoWebsiteManager { } this.removeCoWebsiteFromStack(coWebsite); + + const mainCoWebsite = this.getMainCoWebsite(); + + if (mainCoWebsite) { + this.removeHighlightCoWebsite(mainCoWebsite); + this.goToMain(mainCoWebsite); + this.resizeAllIframes(); + } else { + this.closeMain(); + } resolve(); }) ); diff --git a/front/style/cowebsite/_global.scss b/front/style/cowebsite/_global.scss index b9d8e2ee..52ca1e75 100644 --- a/front/style/cowebsite/_global.scss +++ b/front/style/cowebsite/_global.scss @@ -42,6 +42,14 @@ margin-bottom: auto; flex: 1; justify-content: start; + + #cowebsite-swipe { + display: none; + img { + transform: rotate(0deg) !important; + transform: scale(0.5); + } + } } .top-right-btn { From b9ca630a1505223ce28f693960ae35cc3116e4ad Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Tue, 18 Jan 2022 14:37:35 +0100 Subject: [PATCH 12/16] Jitsi cowebsite close on hangup --- front/src/WebRtc/CoWebsiteManager.ts | 3 +- front/src/WebRtc/JitsiFactory.ts | 62 +++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/front/src/WebRtc/CoWebsiteManager.ts b/front/src/WebRtc/CoWebsiteManager.ts index 70f70227..9ca20545 100644 --- a/front/src/WebRtc/CoWebsiteManager.ts +++ b/front/src/WebRtc/CoWebsiteManager.ts @@ -618,6 +618,7 @@ class CoWebsiteManager { if (coWebsite.jitsi) { const gameScene = gameManager.getCurrentGameScene(); gameScene.disableMediaBehaviors(); + jitsiFactory.restart(); } this.currentOperationPromise = this.currentOperationPromise @@ -676,7 +677,7 @@ class CoWebsiteManager { () => new Promise((resolve) => { if (coWebsite.jitsi) { - jitsiFactory.stop(); + jitsiFactory.destroy(); const gameScene = gameManager.getCurrentGameScene(); gameScene.enableMediaBehaviors(); } diff --git a/front/src/WebRtc/JitsiFactory.ts b/front/src/WebRtc/JitsiFactory.ts index 8f9524a2..b273a64c 100644 --- a/front/src/WebRtc/JitsiFactory.ts +++ b/front/src/WebRtc/JitsiFactory.ts @@ -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, }; }; @@ -176,13 +178,23 @@ class JitsiFactory { const doResolve = (): void => { const iframe = coWebsiteManager.getCoWebsiteBuffer().querySelector('[id*="jitsi" i]'); - if (iframe) { - coWebsiteManager.addCoWebsiteFromIframe(iframe, false, undefined, 0, false, true); + if (iframe && this.jitsiApi) { + const coWebsite = coWebsiteManager.addCoWebsiteFromIframe(iframe, false, undefined, 0, false, true); + + this.jitsiApi.addListener("videoConferenceLeft", () => { + this.closeOrUnload(coWebsite); + }); + + 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); @@ -192,6 +204,44 @@ class JitsiFactory { 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() { if (!this.jitsiApi) { return; @@ -199,6 +249,14 @@ class JitsiFactory { this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback); this.jitsiApi.removeListener("videoMuteStatusChanged", this.videoCallback); + } + + public destroy() { + if (!this.jitsiApi) { + return; + } + + this.stop(); this.jitsiApi?.dispose(); } From 68489956391bf00bf273d4540dc41926fcccdf3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 25 Jan 2022 14:52:37 +0100 Subject: [PATCH 13/16] Adding Icon server to CD env. --- deeployer.libsonnet | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/deeployer.libsonnet b/deeployer.libsonnet index 0bbda264..91b79623 100644 --- a/deeployer.libsonnet +++ b/deeployer.libsonnet @@ -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 @@ } } }, + icon+: { + ingress+: { + spec+: { + tls+: [{ + hosts: ["icon-"+url], + secretName: "certificate-tls" + }] + } + } + }, } } } From 0dc6f41562e61103ae178e3368f2034fa73893fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 25 Jan 2022 15:27:44 +0100 Subject: [PATCH 14/16] Fixing server name in K8S deployment --- deeployer.libsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deeployer.libsonnet b/deeployer.libsonnet index 91b79623..4012b186 100644 --- a/deeployer.libsonnet +++ b/deeployer.libsonnet @@ -219,7 +219,7 @@ } } }, - icon+: { + iconserver+: { ingress+: { spec+: { tls+: [{ From b01b8b53eb668ed62cb913fcee6372d18d1e61f1 Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Tue, 25 Jan 2022 15:24:36 +0100 Subject: [PATCH 15/16] Lowercase warning container hex colors --- front/src/Components/WarningContainer/WarningContainer.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/front/src/Components/WarningContainer/WarningContainer.svelte b/front/src/Components/WarningContainer/WarningContainer.svelte index b5def355..dd740eb5 100644 --- a/front/src/Components/WarningContainer/WarningContainer.svelte +++ b/front/src/Components/WarningContainer/WarningContainer.svelte @@ -28,8 +28,8 @@ main.warningMain { pointer-events: auto; width: 80%; - background-color: #F9E81E; - color: #14304C; + background-color: #f9e81e; + color: #14304c; text-align: center; position: absolute; From 9efb718545138ce70f9403f5be1bfc92887cf684 Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Thu, 27 Jan 2022 15:59:19 +0100 Subject: [PATCH 16/16] Display a loader while cowebsite icon is loading --- .../CoWebsiteThumbnailSlot.svelte | 107 +++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte b/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte index a668bcf6..afb1179c 100644 --- a/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte +++ b/front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte @@ -12,6 +12,7 @@ export let vertical: boolean; let icon: HTMLImageElement; + let iconLoaded = false; let state = coWebsite.state; const coWebsiteUrl = coWebsite.iframe.src; @@ -20,6 +21,9 @@ onMount(() => { icon.src = `${ICON_URL}/icon?url=${urlObject.hostname}&size=64..96..256&fallback_icon_color=14304c`; icon.alt = urlObject.hostname; + icon.onload = () => { + iconLoaded = true; + }; }); async function onClick() { @@ -72,7 +76,104 @@ class:vertical on:click={onClick} > - + + + + + + + + + + + + + + + + + + + +