Merge branch 'develop' of github.com:thecodingmachine/workadventure
This commit is contained in:
commit
13e854c4c4
15
.github/workflows/end_to_end_tests.yml
vendored
15
.github/workflows/end_to_end_tests.yml
vendored
@ -20,6 +20,15 @@ jobs:
|
|||||||
- name: "Checkout"
|
- name: "Checkout"
|
||||||
uses: "actions/checkout@v2.0.0"
|
uses: "actions/checkout@v2.0.0"
|
||||||
|
|
||||||
|
- name: "Setup NodeJS"
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: '14.x'
|
||||||
|
|
||||||
|
- name: "Install dependencies"
|
||||||
|
run: npm install
|
||||||
|
working-directory: "tests"
|
||||||
|
|
||||||
- name: "Setup .env file"
|
- name: "Setup .env file"
|
||||||
run: cp .env.template .env
|
run: cp .env.template .env
|
||||||
|
|
||||||
@ -27,10 +36,10 @@ jobs:
|
|||||||
run: sudo chown 1000:1000 -R .
|
run: sudo chown 1000:1000 -R .
|
||||||
|
|
||||||
- name: "Start environment"
|
- name: "Start environment"
|
||||||
run: docker-compose up -d
|
run: LIVE_RELOAD=0 docker-compose up -d
|
||||||
|
|
||||||
- name: "Wait for environment to build (and downloading testcafe image)"
|
- name: "Wait for environment to build (and downloading testcafe image)"
|
||||||
run: (docker-compose -f docker-compose.testcafe.yml pull &) && docker-compose logs -f --tail=0 front | grep -q "Compiled successfully"
|
run: (docker-compose -f docker-compose.testcafe.yml build &) && docker-compose logs -f --tail=0 front | grep -q "Compiled successfully"
|
||||||
|
|
||||||
# - name: "temp debug: display logs"
|
# - name: "temp debug: display logs"
|
||||||
# run: docker-compose logs
|
# run: docker-compose logs
|
||||||
@ -42,7 +51,7 @@ jobs:
|
|||||||
# run: docker-compose logs -f pusher | grep -q "WorkAdventure starting on port"
|
# run: docker-compose logs -f pusher | grep -q "WorkAdventure starting on port"
|
||||||
|
|
||||||
- name: "Run tests"
|
- name: "Run tests"
|
||||||
run: docker-compose -f docker-compose.testcafe.yml up --exit-code-from testcafe
|
run: PROJECT_DIR=$(pwd) docker-compose -f docker-compose.testcafe.yml up --exit-code-from testcafe
|
||||||
|
|
||||||
- name: Upload failed tests
|
- name: Upload failed tests
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
|
@ -59,9 +59,43 @@ $ docker-compose exec back yarn run pretty
|
|||||||
|
|
||||||
WorkAdventure is based on a video game engine (Phaser), and video games are not the easiest programs to unit test.
|
WorkAdventure is based on a video game engine (Phaser), and video games are not the easiest programs to unit test.
|
||||||
|
|
||||||
Nevertheless, if your code can be unit tested, please provide a unit test (we use Jasmine).
|
Nevertheless, if your code can be unit tested, please provide a unit test (we use Jasmine), or an end-to-end test (we use Testcafe).
|
||||||
|
|
||||||
If you are providing a new feature, you should setup a test map in the `maps/tests` directory. The test map should contain
|
If you are providing a new feature, you should setup a test map in the `maps/tests` directory. The test map should contain
|
||||||
some description text describing how to test the feature. Finally, you should modify the `maps/tests/index.html` file
|
some description text describing how to test the feature.
|
||||||
to add a reference to your newly created test map.
|
|
||||||
|
|
||||||
|
* if the features is meant to be manually tested, you should modify the `maps/tests/index.html` file to add a reference
|
||||||
|
to your newly created test map
|
||||||
|
* if the features can be automatically tested, please provide a testcafe test
|
||||||
|
|
||||||
|
#### Running testcafe tests
|
||||||
|
|
||||||
|
End-to-end tests are available in the "/tests" directory.
|
||||||
|
|
||||||
|
To run these tests locally:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ LIVE_RELOAD=0 docker-compose up -d
|
||||||
|
$ cd tests
|
||||||
|
$ npm install
|
||||||
|
$ npm run test
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: If your tests fail on a Javascript error in "sockjs", this is due to the
|
||||||
|
Webpack live reload. The Webpack live reload feature is conflicting with testcafe. This is why we recommend starting
|
||||||
|
WorkAdventure with the `LIVE_RELOAD=0` environment variable.
|
||||||
|
|
||||||
|
End-to-end tests can take a while to run. To run only one test, use:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ npm run test -- tests/[name of the test file].ts
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also run the tests inside a container (but you will not have visual feedbacks on your test, so we recommend using
|
||||||
|
the local tests).
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ LIVE_RELOAD=0 docker-compose up -d
|
||||||
|
# Wait 2-3 minutes for the environment to start, then:
|
||||||
|
$ PROJECT_DIR=$(pwd) docker-compose -f docker-compose.testcafe.yml up
|
||||||
|
```
|
||||||
|
@ -12,43 +12,52 @@ export class DebugController {
|
|||||||
|
|
||||||
getDump() {
|
getDump() {
|
||||||
this.App.get("/dump", (res: HttpResponse, req: HttpRequest) => {
|
this.App.get("/dump", (res: HttpResponse, req: HttpRequest) => {
|
||||||
const query = parse(req.getQuery());
|
(async () => {
|
||||||
|
const query = parse(req.getQuery());
|
||||||
|
|
||||||
if (query.token !== ADMIN_API_TOKEN) {
|
if (query.token !== ADMIN_API_TOKEN) {
|
||||||
return res.writeStatus("401 Unauthorized").end("Invalid token sent!");
|
return res.writeStatus("401 Unauthorized").end("Invalid token sent!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
.writeStatus("200 OK")
|
.writeStatus("200 OK")
|
||||||
.writeHeader("Content-Type", "application/json")
|
.writeHeader("Content-Type", "application/json")
|
||||||
.end(
|
.end(
|
||||||
stringify(socketManager.getWorlds(), (key: unknown, value: unknown) => {
|
stringify(
|
||||||
if (key === "listeners") {
|
await Promise.all(socketManager.getWorlds().values()),
|
||||||
return "Listeners";
|
(key: unknown, value: unknown) => {
|
||||||
}
|
if (key === "listeners") {
|
||||||
if (key === "socket") {
|
return "Listeners";
|
||||||
return "Socket";
|
}
|
||||||
}
|
if (key === "socket") {
|
||||||
if (key === "batchedMessages") {
|
return "Socket";
|
||||||
return "BatchedMessages";
|
}
|
||||||
}
|
if (key === "batchedMessages") {
|
||||||
if (value instanceof Map) {
|
return "BatchedMessages";
|
||||||
const obj: any = {}; // eslint-disable-line @typescript-eslint/no-explicit-any
|
}
|
||||||
for (const [mapKey, mapValue] of value.entries()) {
|
if (value instanceof Map) {
|
||||||
obj[mapKey] = mapValue;
|
const obj: any = {}; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
for (const [mapKey, mapValue] of value.entries()) {
|
||||||
|
obj[mapKey] = mapValue;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
} else if (value instanceof Set) {
|
||||||
|
const obj: Array<unknown> = [];
|
||||||
|
for (const [setKey, setValue] of value.entries()) {
|
||||||
|
obj.push(setValue);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return obj;
|
)
|
||||||
} else if (value instanceof Set) {
|
);
|
||||||
const obj: Array<unknown> = [];
|
})().catch((e) => {
|
||||||
for (const [setKey, setValue] of value.entries()) {
|
console.error(e);
|
||||||
obj.push(setValue);
|
res.writeStatus("500");
|
||||||
}
|
res.end("An error occurred");
|
||||||
return obj;
|
});
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
version: "3"
|
version: "3.5"
|
||||||
services:
|
services:
|
||||||
testcafe:
|
testcafe:
|
||||||
image: testcafe/testcafe:1.17.1
|
build: tests/
|
||||||
working_dir: /tests
|
working_dir: /project/tests
|
||||||
|
command:
|
||||||
|
- --dev
|
||||||
|
# Run as root to have the right to access /var/run/docker.sock
|
||||||
|
user: root
|
||||||
environment:
|
environment:
|
||||||
BROWSER: "chromium --use-fake-device-for-media-stream"
|
BROWSER: "chromium --use-fake-device-for-media-stream"
|
||||||
|
PROJECT_DIR: ${PROJECT_DIR}
|
||||||
|
ADMIN_API_TOKEN: ${ADMIN_API_TOKEN}
|
||||||
volumes:
|
volumes:
|
||||||
- ./tests:/tests
|
- ./:/project
|
||||||
- ./maps:/maps
|
- ./maps:/maps
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
# security_opt:
|
# security_opt:
|
||||||
# - seccomp:unconfined
|
# - seccomp:unconfined
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
version: "3"
|
version: "3.5"
|
||||||
services:
|
services:
|
||||||
reverse-proxy:
|
reverse-proxy:
|
||||||
image: traefik:v2.0
|
image: traefik:v2.5
|
||||||
command:
|
command:
|
||||||
- --api.insecure=true
|
- --api.insecure=true
|
||||||
- --providers.docker
|
- --providers.docker
|
||||||
- --entryPoints.web.address=:80
|
- --entryPoints.web.address=:80
|
||||||
- --entryPoints.websecure.address=:443
|
- --entryPoints.websecure.address=:443
|
||||||
|
- "--providers.docker.exposedbydefault=false"
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
- "443:443"
|
- "443:443"
|
||||||
# The Web UI (enabled by --api.insecure=true)
|
# The Web UI (enabled by --api.insecure=true)
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
depends_on:
|
#depends_on:
|
||||||
- back
|
# - back
|
||||||
- front
|
# - front
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
networks:
|
networks:
|
||||||
@ -51,10 +52,12 @@ services:
|
|||||||
MAX_USERNAME_LENGTH: "$MAX_USERNAME_LENGTH"
|
MAX_USERNAME_LENGTH: "$MAX_USERNAME_LENGTH"
|
||||||
DISABLE_ANONYMOUS: "$DISABLE_ANONYMOUS"
|
DISABLE_ANONYMOUS: "$DISABLE_ANONYMOUS"
|
||||||
OPID_LOGIN_SCREEN_PROVIDER: "$OPID_LOGIN_SCREEN_PROVIDER"
|
OPID_LOGIN_SCREEN_PROVIDER: "$OPID_LOGIN_SCREEN_PROVIDER"
|
||||||
|
LIVE_RELOAD: "$LIVE_RELOAD:-true"
|
||||||
command: yarn run start
|
command: yarn run start
|
||||||
volumes:
|
volumes:
|
||||||
- ./front:/usr/src/app
|
- ./front:/usr/src/app
|
||||||
labels:
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.front.rule=Host(`play.workadventure.localhost`)"
|
- "traefik.http.routers.front.rule=Host(`play.workadventure.localhost`)"
|
||||||
- "traefik.http.routers.front.entryPoints=web"
|
- "traefik.http.routers.front.entryPoints=web"
|
||||||
- "traefik.http.services.front.loadbalancer.server.port=8080"
|
- "traefik.http.services.front.loadbalancer.server.port=8080"
|
||||||
@ -87,6 +90,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./pusher:/usr/src/app
|
- ./pusher:/usr/src/app
|
||||||
labels:
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.pusher.rule=Host(`pusher.workadventure.localhost`)"
|
- "traefik.http.routers.pusher.rule=Host(`pusher.workadventure.localhost`)"
|
||||||
- "traefik.http.routers.pusher.entryPoints=web"
|
- "traefik.http.routers.pusher.entryPoints=web"
|
||||||
- "traefik.http.services.pusher.loadbalancer.server.port=8080"
|
- "traefik.http.services.pusher.loadbalancer.server.port=8080"
|
||||||
@ -111,6 +115,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./maps:/var/www/html
|
- ./maps:/var/www/html
|
||||||
labels:
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.maps.rule=Host(`maps.workadventure.localhost`)"
|
- "traefik.http.routers.maps.rule=Host(`maps.workadventure.localhost`)"
|
||||||
- "traefik.http.routers.maps.entryPoints=web,traefik"
|
- "traefik.http.routers.maps.entryPoints=web,traefik"
|
||||||
- "traefik.http.services.maps.loadbalancer.server.port=80"
|
- "traefik.http.services.maps.loadbalancer.server.port=80"
|
||||||
@ -142,6 +147,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./back:/usr/src/app
|
- ./back:/usr/src/app
|
||||||
labels:
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.back.rule=Host(`api.workadventure.localhost`)"
|
- "traefik.http.routers.back.rule=Host(`api.workadventure.localhost`)"
|
||||||
- "traefik.http.routers.back.entryPoints=web"
|
- "traefik.http.routers.back.entryPoints=web"
|
||||||
- "traefik.http.services.back.loadbalancer.server.port=8080"
|
- "traefik.http.services.back.loadbalancer.server.port=8080"
|
||||||
@ -160,6 +166,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./uploader:/usr/src/app
|
- ./uploader:/usr/src/app
|
||||||
labels:
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.uploader.rule=Host(`uploader.workadventure.localhost`)"
|
- "traefik.http.routers.uploader.rule=Host(`uploader.workadventure.localhost`)"
|
||||||
- "traefik.http.routers.uploader.entryPoints=web"
|
- "traefik.http.routers.uploader.entryPoints=web"
|
||||||
- "traefik.http.services.uploader.loadbalancer.server.port=8080"
|
- "traefik.http.services.uploader.loadbalancer.server.port=8080"
|
||||||
@ -187,6 +194,7 @@ services:
|
|||||||
redisinsight:
|
redisinsight:
|
||||||
image: redislabs/redisinsight:latest
|
image: redislabs/redisinsight:latest
|
||||||
labels:
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.redisinsight.rule=Host(`redis.workadventure.localhost`)"
|
- "traefik.http.routers.redisinsight.rule=Host(`redis.workadventure.localhost`)"
|
||||||
- "traefik.http.routers.redisinsight.entryPoints=web"
|
- "traefik.http.routers.redisinsight.entryPoints=web"
|
||||||
- "traefik.http.services.redisinsight.loadbalancer.server.port=8001"
|
- "traefik.http.services.redisinsight.loadbalancer.server.port=8001"
|
||||||
@ -198,6 +206,7 @@ services:
|
|||||||
icon:
|
icon:
|
||||||
image: matthiasluedtke/iconserver:v3.13.0
|
image: matthiasluedtke/iconserver:v3.13.0
|
||||||
labels:
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.icon.rule=Host(`icon.workadventure.localhost`)"
|
- "traefik.http.routers.icon.rule=Host(`icon.workadventure.localhost`)"
|
||||||
- "traefik.http.routers.icon.entryPoints=web"
|
- "traefik.http.routers.icon.entryPoints=web"
|
||||||
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
- "traefik.http.services.icon.loadbalancer.server.port=8080"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
module.exports = {
|
||||||
"root": true,
|
"root": true,
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
@ -18,10 +18,18 @@
|
|||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2018,
|
"ecmaVersion": 2018,
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
"project": "./tsconfig.json"
|
"project": "./tsconfig.json",
|
||||||
|
"extraFileExtensions": [".svelte"]
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@typescript-eslint"
|
"@typescript-eslint",
|
||||||
|
"svelte3"
|
||||||
|
],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["*.svelte"],
|
||||||
|
"processor": "svelte3/svelte3"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
@ -34,5 +42,9 @@
|
|||||||
"@typescript-eslint/no-unsafe-return": "off",
|
"@typescript-eslint/no-unsafe-return": "off",
|
||||||
"@typescript-eslint/no-unsafe-member-access": "off",
|
"@typescript-eslint/no-unsafe-member-access": "off",
|
||||||
"@typescript-eslint/restrict-template-expressions": "off"
|
"@typescript-eslint/restrict-template-expressions": "off"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"svelte3/typescript": true,
|
||||||
|
"svelte3/ignore-styles": () => true
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 120,
|
"printWidth": 120,
|
||||||
"tabWidth": 4
|
"tabWidth": 4,
|
||||||
|
"plugins": ["prettier-plugin-svelte"]
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
"@typescript-eslint/parser": "^4.23.0",
|
"@typescript-eslint/parser": "^4.23.0",
|
||||||
"css-loader": "^5.2.4",
|
"css-loader": "^5.2.4",
|
||||||
"eslint": "^7.26.0",
|
"eslint": "^7.26.0",
|
||||||
"file-loader": "^6.2.0",
|
"eslint-plugin-svelte3": "^3.2.1",
|
||||||
"fork-ts-checker-webpack-plugin": "^6.2.9",
|
"fork-ts-checker-webpack-plugin": "^6.2.9",
|
||||||
"html-webpack-plugin": "^5.3.1",
|
"html-webpack-plugin": "^5.3.1",
|
||||||
"jasmine": "^3.5.0",
|
"jasmine": "^3.5.0",
|
||||||
@ -25,6 +25,7 @@
|
|||||||
"node-polyfill-webpack-plugin": "^1.1.2",
|
"node-polyfill-webpack-plugin": "^1.1.2",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^2.3.1",
|
"prettier": "^2.3.1",
|
||||||
|
"prettier-plugin-svelte": "^2.5.0",
|
||||||
"sass": "^1.32.12",
|
"sass": "^1.32.12",
|
||||||
"sass-loader": "^11.1.0",
|
"sass-loader": "^11.1.0",
|
||||||
"svelte": "^3.38.2",
|
"svelte": "^3.38.2",
|
||||||
@ -56,6 +57,7 @@
|
|||||||
"queue-typescript": "^1.0.1",
|
"queue-typescript": "^1.0.1",
|
||||||
"quill": "1.3.6",
|
"quill": "1.3.6",
|
||||||
"quill-delta-to-html": "^0.12.0",
|
"quill-delta-to-html": "^0.12.0",
|
||||||
|
"retry-axios": "^2.6.0",
|
||||||
"rxjs": "^6.6.3",
|
"rxjs": "^6.6.3",
|
||||||
"sanitize-html": "^2.5.0",
|
"sanitize-html": "^2.5.0",
|
||||||
"simple-peer": "^9.11.0",
|
"simple-peer": "^9.11.0",
|
||||||
@ -70,17 +72,21 @@
|
|||||||
"build": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" NODE_ENV=production webpack",
|
"build": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" NODE_ENV=production webpack",
|
||||||
"build-typings": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" NODE_ENV=production BUILD_TYPINGS=1 webpack",
|
"build-typings": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" NODE_ENV=production BUILD_TYPINGS=1 webpack",
|
||||||
"test": "cross-env TS_NODE_PROJECT=\"tsconfig-for-jasmine.json\" ts-node node_modules/jasmine/bin/jasmine --config=jasmine.json",
|
"test": "cross-env TS_NODE_PROJECT=\"tsconfig-for-jasmine.json\" ts-node node_modules/jasmine/bin/jasmine --config=jasmine.json",
|
||||||
"lint": "node_modules/.bin/eslint src/ . --ext .ts",
|
"lint": "node_modules/.bin/eslint src/ tests/ --ext .ts,.svelte",
|
||||||
"fix": "node_modules/.bin/eslint --fix src/ . --ext .ts",
|
"fix": "node_modules/.bin/eslint --fix src/ tests/ --ext .ts,.svelte",
|
||||||
"precommit": "lint-staged",
|
"precommit": "lint-staged",
|
||||||
"svelte-check-watch": "svelte-check --fail-on-warnings --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore\" --watch",
|
"svelte-check-watch": "svelte-check --fail-on-warnings --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore\" --watch",
|
||||||
"svelte-check": "svelte-check --fail-on-warnings --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore\"",
|
"svelte-check": "svelte-check --fail-on-warnings --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore\"",
|
||||||
"pretty": "yarn prettier --write 'src/**/*.{ts,tsx}'",
|
"pretty": "yarn prettier --write 'src/**/*.{ts,svelte}'",
|
||||||
"pretty-check": "yarn prettier --check 'src/**/*.{ts,tsx}'"
|
"pretty-check": "yarn prettier --check 'src/**/*.{ts,svelte}'"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.ts": [
|
"*.svelte": [
|
||||||
"prettier --write"
|
"yarn run svelte-check"
|
||||||
|
],
|
||||||
|
"*.{ts,svelte}": [
|
||||||
|
"yarn run fix",
|
||||||
|
"yarn run pretty"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,147 +1,146 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import MenuIcon from "./Menu/MenuIcon.svelte";
|
import MenuIcon from "./Menu/MenuIcon.svelte";
|
||||||
import {menuIconVisiblilityStore, menuVisiblilityStore} from "../Stores/MenuStore";
|
import { menuIconVisiblilityStore, menuVisiblilityStore } from "../Stores/MenuStore";
|
||||||
import {emoteMenuStore} from "../Stores/EmoteStore";
|
import { emoteMenuStore } from "../Stores/EmoteStore";
|
||||||
import {enableCameraSceneVisibilityStore} from "../Stores/MediaStore";
|
import { enableCameraSceneVisibilityStore } from "../Stores/MediaStore";
|
||||||
import CameraControls from "./CameraControls.svelte";
|
import CameraControls from "./CameraControls.svelte";
|
||||||
import MyCamera from "./MyCamera.svelte";
|
import MyCamera from "./MyCamera.svelte";
|
||||||
import SelectCompanionScene from "./SelectCompanion/SelectCompanionScene.svelte";
|
import SelectCompanionScene from "./SelectCompanion/SelectCompanionScene.svelte";
|
||||||
import {selectCompanionSceneVisibleStore} from "../Stores/SelectCompanionStore";
|
import { selectCompanionSceneVisibleStore } from "../Stores/SelectCompanionStore";
|
||||||
import {selectCharacterSceneVisibleStore} from "../Stores/SelectCharacterStore";
|
import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore";
|
||||||
import SelectCharacterScene from "./selectCharacter/SelectCharacterScene.svelte";
|
import SelectCharacterScene from "./selectCharacter/SelectCharacterScene.svelte";
|
||||||
import {customCharacterSceneVisibleStore} from "../Stores/CustomCharacterStore";
|
import { customCharacterSceneVisibleStore } from "../Stores/CustomCharacterStore";
|
||||||
import {errorStore} from "../Stores/ErrorStore";
|
import { errorStore } from "../Stores/ErrorStore";
|
||||||
import CustomCharacterScene from "./CustomCharacterScene/CustomCharacterScene.svelte";
|
import CustomCharacterScene from "./CustomCharacterScene/CustomCharacterScene.svelte";
|
||||||
import LoginScene from "./Login/LoginScene.svelte";
|
import LoginScene from "./Login/LoginScene.svelte";
|
||||||
import Chat from "./Chat/Chat.svelte";
|
import Chat from "./Chat/Chat.svelte";
|
||||||
import {loginSceneVisibleStore} from "../Stores/LoginSceneStore";
|
import { loginSceneVisibleStore } from "../Stores/LoginSceneStore";
|
||||||
import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte";
|
import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte";
|
||||||
import VisitCard from "./VisitCard/VisitCard.svelte";
|
import VisitCard from "./VisitCard/VisitCard.svelte";
|
||||||
import {requestVisitCardsStore} from "../Stores/GameStore";
|
import { requestVisitCardsStore } from "../Stores/GameStore";
|
||||||
|
|
||||||
import type {Game} from "../Phaser/Game/Game";
|
import type { Game } from "../Phaser/Game/Game";
|
||||||
import {chatVisibilityStore} from "../Stores/ChatStore";
|
import { chatVisibilityStore } from "../Stores/ChatStore";
|
||||||
import {helpCameraSettingsVisibleStore} from "../Stores/HelpCameraSettingsStore";
|
import { helpCameraSettingsVisibleStore } from "../Stores/HelpCameraSettingsStore";
|
||||||
import HelpCameraSettingsPopup from "./HelpCameraSettings/HelpCameraSettingsPopup.svelte";
|
import HelpCameraSettingsPopup from "./HelpCameraSettings/HelpCameraSettingsPopup.svelte";
|
||||||
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
||||||
import {soundPlayingStore} from "../Stores/SoundPlayingStore";
|
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
|
||||||
import ErrorDialog from "./UI/ErrorDialog.svelte";
|
import ErrorDialog from "./UI/ErrorDialog.svelte";
|
||||||
import Menu from "./Menu/Menu.svelte";
|
import Menu from "./Menu/Menu.svelte";
|
||||||
import EmoteMenu from "./EmoteMenu/EmoteMenu.svelte";
|
import EmoteMenu from "./EmoteMenu/EmoteMenu.svelte";
|
||||||
import VideoOverlay from "./Video/VideoOverlay.svelte";
|
import VideoOverlay from "./Video/VideoOverlay.svelte";
|
||||||
import {gameOverlayVisibilityStore} from "../Stores/GameOverlayStoreVisibility";
|
import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility";
|
||||||
import AdminMessage from "./TypeMessage/BanMessage.svelte";
|
import AdminMessage from "./TypeMessage/BanMessage.svelte";
|
||||||
import TextMessage from "./TypeMessage/TextMessage.svelte";
|
import TextMessage from "./TypeMessage/TextMessage.svelte";
|
||||||
import {banMessageVisibleStore} from "../Stores/TypeMessageStore/BanMessageStore";
|
import { banMessageVisibleStore } from "../Stores/TypeMessageStore/BanMessageStore";
|
||||||
import {textMessageVisibleStore} from "../Stores/TypeMessageStore/TextMessageStore";
|
import { textMessageVisibleStore } from "../Stores/TypeMessageStore/TextMessageStore";
|
||||||
import {warningContainerStore} from "../Stores/MenuStore";
|
import { warningContainerStore } from "../Stores/MenuStore";
|
||||||
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
|
import WarningContainer from "./WarningContainer/WarningContainer.svelte";
|
||||||
import {layoutManagerVisibilityStore} from "../Stores/LayoutManagerStore";
|
import { layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore";
|
||||||
import LayoutManager from "./LayoutManager/LayoutManager.svelte";
|
import LayoutManager from "./LayoutManager/LayoutManager.svelte";
|
||||||
import {audioManagerVisibilityStore} from "../Stores/AudioManagerStore";
|
import { audioManagerVisibilityStore } from "../Stores/AudioManagerStore";
|
||||||
import AudioManager from "./AudioManager/AudioManager.svelte"
|
import AudioManager from "./AudioManager/AudioManager.svelte";
|
||||||
import { showReportScreenStore, userReportEmpty } from "../Stores/ShowReportScreenStore";
|
import { showReportScreenStore, userReportEmpty } from "../Stores/ShowReportScreenStore";
|
||||||
import ReportMenu from "./ReportMenu/ReportMenu.svelte";
|
import ReportMenu from "./ReportMenu/ReportMenu.svelte";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{#if $loginSceneVisibleStore}
|
{#if $loginSceneVisibleStore}
|
||||||
<div class="scrollable">
|
<div class="scrollable">
|
||||||
<LoginScene game={game}></LoginScene>
|
<LoginScene {game} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $selectCharacterSceneVisibleStore}
|
{#if $selectCharacterSceneVisibleStore}
|
||||||
<div>
|
<div>
|
||||||
<SelectCharacterScene game={ game }></SelectCharacterScene>
|
<SelectCharacterScene {game} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $customCharacterSceneVisibleStore}
|
{#if $customCharacterSceneVisibleStore}
|
||||||
<div>
|
<div>
|
||||||
<CustomCharacterScene game={ game }></CustomCharacterScene>
|
<CustomCharacterScene {game} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $selectCompanionSceneVisibleStore}
|
{#if $selectCompanionSceneVisibleStore}
|
||||||
<div>
|
<div>
|
||||||
<SelectCompanionScene game={ game }></SelectCompanionScene>
|
<SelectCompanionScene {game} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $enableCameraSceneVisibilityStore}
|
{#if $enableCameraSceneVisibilityStore}
|
||||||
<div class="scrollable">
|
<div class="scrollable">
|
||||||
<EnableCameraScene game={game}></EnableCameraScene>
|
<EnableCameraScene {game} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $banMessageVisibleStore}
|
{#if $banMessageVisibleStore}
|
||||||
<div>
|
<div>
|
||||||
<AdminMessage></AdminMessage>
|
<AdminMessage />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $textMessageVisibleStore}
|
{#if $textMessageVisibleStore}
|
||||||
<div>
|
<div>
|
||||||
<TextMessage></TextMessage>
|
<TextMessage />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $soundPlayingStore}
|
{#if $soundPlayingStore}
|
||||||
<div>
|
<div>
|
||||||
<AudioPlaying url={$soundPlayingStore} />
|
<AudioPlaying url={$soundPlayingStore} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $audioManagerVisibilityStore}
|
{#if $audioManagerVisibilityStore}
|
||||||
<div>
|
<div>
|
||||||
<AudioManager></AudioManager>
|
<AudioManager />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $layoutManagerVisibilityStore}
|
{#if $layoutManagerVisibilityStore}
|
||||||
<div>
|
<div>
|
||||||
<LayoutManager></LayoutManager>
|
<LayoutManager />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $showReportScreenStore !== userReportEmpty}
|
{#if $showReportScreenStore !== userReportEmpty}
|
||||||
<div>
|
<div>
|
||||||
<ReportMenu></ReportMenu>
|
<ReportMenu />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $menuIconVisiblilityStore}
|
{#if $menuIconVisiblilityStore}
|
||||||
<div>
|
<div>
|
||||||
<MenuIcon></MenuIcon>
|
<MenuIcon />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $menuVisiblilityStore}
|
{#if $menuVisiblilityStore}
|
||||||
<div>
|
<div>
|
||||||
<Menu></Menu>
|
<Menu />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $emoteMenuStore}
|
{#if $emoteMenuStore}
|
||||||
<div>
|
<div>
|
||||||
<EmoteMenu></EmoteMenu>
|
<EmoteMenu />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $gameOverlayVisibilityStore}
|
{#if $gameOverlayVisibilityStore}
|
||||||
<div>
|
<div>
|
||||||
<VideoOverlay></VideoOverlay>
|
<VideoOverlay />
|
||||||
<MyCamera></MyCamera>
|
<MyCamera />
|
||||||
<CameraControls></CameraControls>
|
<CameraControls />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $helpCameraSettingsVisibleStore}
|
{#if $helpCameraSettingsVisibleStore}
|
||||||
<div>
|
<div>
|
||||||
<HelpCameraSettingsPopup></HelpCameraSettingsPopup>
|
<HelpCameraSettingsPopup />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $requestVisitCardsStore}
|
{#if $requestVisitCardsStore}
|
||||||
<VisitCard visitCardUrl={$requestVisitCardsStore}></VisitCard>
|
<VisitCard visitCardUrl={$requestVisitCardsStore} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if $errorStore.length > 0}
|
{#if $errorStore.length > 0}
|
||||||
<div>
|
<div>
|
||||||
<ErrorDialog></ErrorDialog>
|
<ErrorDialog />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $chatVisibilityStore}
|
{#if $chatVisibilityStore}
|
||||||
<Chat></Chat>
|
<Chat />
|
||||||
{/if}
|
{/if}
|
||||||
{#if $warningContainerStore}
|
{#if $warningContainerStore}
|
||||||
<WarningContainer></WarningContainer>
|
<WarningContainer />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||||
import type { audioManagerVolume } from "../../Stores/AudioManagerStore";
|
import type { audioManagerVolume } from "../../Stores/AudioManagerStore";
|
||||||
import {
|
import { audioManagerFileStore, audioManagerVolumeStore } from "../../Stores/AudioManagerStore";
|
||||||
audioManagerFileStore,
|
|
||||||
audioManagerVolumeStore,
|
|
||||||
} from "../../Stores/AudioManagerStore";
|
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
import type { Unsubscriber } from "svelte/store";
|
import type { Unsubscriber } from "svelte/store";
|
||||||
import { onDestroy, onMount } from "svelte";
|
import { onDestroy, onMount } from "svelte";
|
||||||
@ -41,8 +38,8 @@
|
|||||||
HTMLAudioPlayer.muted = audioManager.muted;
|
HTMLAudioPlayer.muted = audioManager.muted;
|
||||||
HTMLAudioPlayer.loop = audioManager.loop;
|
HTMLAudioPlayer.loop = audioManager.loop;
|
||||||
updateVolumeUI();
|
updateVolumeUI();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
if (unsubscriberFileStore) {
|
if (unsubscriberFileStore) {
|
||||||
@ -51,24 +48,24 @@
|
|||||||
if (unsubscriberVolumeStore) {
|
if (unsubscriberVolumeStore) {
|
||||||
unsubscriberVolumeStore();
|
unsubscriberVolumeStore();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
function updateVolumeUI() {
|
function updateVolumeUI() {
|
||||||
if (get(audioManagerVolumeStore).muted) {
|
if (get(audioManagerVolumeStore).muted) {
|
||||||
audioPlayerVolumeIcon.classList.add('muted');
|
audioPlayerVolumeIcon.classList.add("muted");
|
||||||
audioPlayerVol.value = "0";
|
audioPlayerVol.value = "0";
|
||||||
} else {
|
} else {
|
||||||
let volume = HTMLAudioPlayer.volume;
|
let volume = HTMLAudioPlayer.volume;
|
||||||
audioPlayerVol.value = "" + volume;
|
audioPlayerVol.value = "" + volume;
|
||||||
audioPlayerVolumeIcon.classList.remove('muted');
|
audioPlayerVolumeIcon.classList.remove("muted");
|
||||||
if (volume < 0.3) {
|
if (volume < 0.3) {
|
||||||
audioPlayerVolumeIcon.classList.add('low');
|
audioPlayerVolumeIcon.classList.add("low");
|
||||||
} else if (volume < 0.7) {
|
} else if (volume < 0.7) {
|
||||||
audioPlayerVolumeIcon.classList.remove('low');
|
audioPlayerVolumeIcon.classList.remove("low");
|
||||||
audioPlayerVolumeIcon.classList.add('mid');
|
audioPlayerVolumeIcon.classList.add("mid");
|
||||||
} else {
|
} else {
|
||||||
audioPlayerVolumeIcon.classList.remove('low');
|
audioPlayerVolumeIcon.classList.remove("low");
|
||||||
audioPlayerVolumeIcon.classList.remove('mid');
|
audioPlayerVolumeIcon.classList.remove("mid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,45 +94,67 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div class="main-audio-manager nes-container is-rounded">
|
<div class="main-audio-manager nes-container is-rounded">
|
||||||
<div class="audio-manager-player-volume">
|
<div class="audio-manager-player-volume">
|
||||||
<span id="audioplayer_volume_icon_playing" alt="player volume" bind:this={audioPlayerVolumeIcon}
|
<span
|
||||||
on:click={onMute}>
|
id="audioplayer_volume_icon_playing"
|
||||||
<svg width="2em" height="2em" viewBox="0 0 16 16" class="bi bi-volume-up" fill="white"
|
alt="player volume"
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
bind:this={audioPlayerVolumeIcon}
|
||||||
<path fill-rule="evenodd"
|
on:click={onMute}
|
||||||
d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06zM6 5.04L4.312 6.39A.5.5 0 0 1 4 6.5H2v3h2a.5.5 0 0 1 .312.11L6 10.96V5.04z" />
|
>
|
||||||
|
<svg
|
||||||
|
width="2em"
|
||||||
|
height="2em"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
class="bi bi-volume-up"
|
||||||
|
fill="white"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06zM6 5.04L4.312 6.39A.5.5 0 0 1 4 6.5H2v3h2a.5.5 0 0 1 .312.11L6 10.96V5.04z"
|
||||||
|
/>
|
||||||
<g id="audioplayer_volume_icon_playing_high">
|
<g id="audioplayer_volume_icon_playing_high">
|
||||||
<path
|
<path
|
||||||
d="M11.536 14.01A8.473 8.473 0 0 0 14.026 8a8.473 8.473 0 0 0-2.49-6.01l-.708.707A7.476 7.476 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303l.708.707z" />
|
d="M11.536 14.01A8.473 8.473 0 0 0 14.026 8a8.473 8.473 0 0 0-2.49-6.01l-.708.707A7.476 7.476 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303l.708.707z"
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
<g id="audioplayer_volume_icon_playing_mid">
|
<g id="audioplayer_volume_icon_playing_mid">
|
||||||
<path
|
<path
|
||||||
d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.483 5.483 0 0 1 11.025 8a5.483 5.483 0 0 1-1.61 3.89l.706.706z" />
|
d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.483 5.483 0 0 1 11.025 8a5.483 5.483 0 0 1-1.61 3.89l.706.706z"
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
<g id="audioplayer_volume_icon_playing_low">
|
<g id="audioplayer_volume_icon_playing_low">
|
||||||
<path
|
<path
|
||||||
d="M8.707 11.182A4.486 4.486 0 0 0 10.025 8a4.486 4.486 0 0 0-1.318-3.182L8 5.525A3.489 3.489 0 0 1 9.025 8 3.49 3.49 0 0 1 8 10.475l.707.707z" />
|
d="M8.707 11.182A4.486 4.486 0 0 0 10.025 8a4.486 4.486 0 0 0-1.318-3.182L8 5.525A3.489 3.489 0 0 1 9.025 8 3.49 3.49 0 0 1 8 10.475l.707.707z"
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<input type="range" min="0" max="1" step="0.025" bind:this={audioPlayerVol} on:change={setVolume} on:keydown={disallowKeys}>
|
<input
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="1"
|
||||||
|
step="0.025"
|
||||||
|
bind:this={audioPlayerVol}
|
||||||
|
on:change={setVolume}
|
||||||
|
on:keydown={disallowKeys}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="audio-manager-reduce-conversation">
|
<div class="audio-manager-reduce-conversation">
|
||||||
<label>
|
<label>
|
||||||
reduce in conversations
|
reduce in conversations
|
||||||
<input type="checkbox" bind:checked={decreaseWhileTalking} on:change={setDecrease}>
|
<input type="checkbox" bind:checked={decreaseWhileTalking} on:change={setDecrease} />
|
||||||
</label>
|
</label>
|
||||||
<section class="audio-manager-file">
|
<section class="audio-manager-file">
|
||||||
|
<!-- svelte-ignore a11y-media-has-caption -->
|
||||||
<audio class="audio-manager-audioplayer" bind:this={HTMLAudioPlayer}>
|
<audio class="audio-manager-audioplayer" bind:this={HTMLAudioPlayer}>
|
||||||
<source src={$audioManagerFileStore}>
|
<source src={$audioManagerFileStore} />
|
||||||
</audio>
|
</audio>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.main-audio-manager.nes-container.is-rounded {
|
div.main-audio-manager.nes-container.is-rounded {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import {requestedScreenSharingState, screenSharingAvailableStore} from "../Stores/ScreenSharingStore";
|
import { requestedScreenSharingState, screenSharingAvailableStore } from "../Stores/ScreenSharingStore";
|
||||||
import {isSilentStore, requestedCameraState, requestedMicrophoneState} from "../Stores/MediaStore";
|
import { isSilentStore, requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
|
||||||
import monitorImg from "./images/monitor.svg";
|
import monitorImg from "./images/monitor.svg";
|
||||||
import monitorCloseImg from "./images/monitor-close.svg";
|
import monitorCloseImg from "./images/monitor-close.svg";
|
||||||
import cinemaImg from "./images/cinema.svg";
|
import cinemaImg from "./images/cinema.svg";
|
||||||
@ -9,10 +9,10 @@
|
|||||||
import microphoneCloseImg from "./images/microphone-close.svg";
|
import microphoneCloseImg from "./images/microphone-close.svg";
|
||||||
import layoutPresentationImg from "./images/layout-presentation.svg";
|
import layoutPresentationImg from "./images/layout-presentation.svg";
|
||||||
import layoutChatImg from "./images/layout-chat.svg";
|
import layoutChatImg from "./images/layout-chat.svg";
|
||||||
import {layoutModeStore} from "../Stores/StreamableCollectionStore";
|
import { layoutModeStore } from "../Stores/StreamableCollectionStore";
|
||||||
import {LayoutMode} from "../WebRtc/LayoutManager";
|
import { LayoutMode } from "../WebRtc/LayoutManager";
|
||||||
import {peerStore} from "../Stores/PeerStore";
|
import { peerStore } from "../Stores/PeerStore";
|
||||||
import {onDestroy} from "svelte";
|
import { onDestroy } from "svelte";
|
||||||
|
|
||||||
function screenSharingClick(): void {
|
function screenSharingClick(): void {
|
||||||
if (isSilent) return;
|
if (isSilent) return;
|
||||||
@ -50,7 +50,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let isSilent: boolean;
|
let isSilent: boolean;
|
||||||
const unsubscribeIsSilent = isSilentStore.subscribe(value => {
|
const unsubscribeIsSilent = isSilentStore.subscribe((value) => {
|
||||||
isSilent = value;
|
isSilent = value;
|
||||||
});
|
});
|
||||||
onDestroy(unsubscribeIsSilent);
|
onDestroy(unsubscribeIsSilent);
|
||||||
@ -58,36 +58,38 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="btn-cam-action">
|
<div class="btn-cam-action">
|
||||||
<div class="btn-layout nes-btn is-dark" on:click={switchLayoutMode} class:hide={$peerStore.size===0}>
|
<div class="btn-layout nes-btn is-dark" on:click={switchLayoutMode} class:hide={$peerStore.size === 0}>
|
||||||
{#if $layoutModeStore === LayoutMode.Presentation }
|
{#if $layoutModeStore === LayoutMode.Presentation}
|
||||||
<img src={layoutPresentationImg} style="padding: 2px" alt="Switch to mosaic mode">
|
<img src={layoutPresentationImg} style="padding: 2px" alt="Switch to mosaic mode" />
|
||||||
{:else}
|
{:else}
|
||||||
<img src={layoutChatImg} style="padding: 2px" alt="Switch to presentation mode">
|
<img src={layoutChatImg} style="padding: 2px" alt="Switch to presentation mode" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-micro nes-btn is-dark" on:click={microphoneClick} class:disabled={!$requestedMicrophoneState ||
|
<div
|
||||||
isSilent}>
|
class="btn-monitor nes-btn is-dark"
|
||||||
{#if $requestedMicrophoneState && !isSilent}
|
on:click={screenSharingClick}
|
||||||
<img src={microphoneImg} alt="Turn on microphone">
|
class:hide={!$screenSharingAvailableStore || isSilent}
|
||||||
|
class:enabled={$requestedScreenSharingState}
|
||||||
|
>
|
||||||
|
{#if $requestedScreenSharingState && !isSilent}
|
||||||
|
<img src={monitorImg} alt="Start screen sharing" />
|
||||||
{:else}
|
{:else}
|
||||||
|
<img src={monitorCloseImg} alt="Stop screen sharing" />
|
||||||
<img src={microphoneCloseImg} alt="Turn off microphone">
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-video nes-btn is-dark" on:click={cameraClick} class:disabled={!$requestedCameraState ||
|
<div class="btn-video nes-btn is-dark" on:click={cameraClick} class:disabled={!$requestedCameraState ||
|
||||||
isSilent}>
|
isSilent}>
|
||||||
{#if $requestedCameraState && !isSilent}
|
{#if $requestedCameraState && !isSilent}
|
||||||
<img src={cinemaImg} alt="Turn on webcam">
|
<img src={cinemaImg} alt="Turn on webcam" />
|
||||||
{:else}
|
{:else}
|
||||||
<img src={cinemaCloseImg} alt="Turn off webcam">
|
<img src={cinemaCloseImg} alt="Turn off webcam" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-monitor nes-btn is-dark" on:click={screenSharingClick} class:hide={!$screenSharingAvailableStore
|
<div class="btn-micro nes-btn is-dark" on:click={microphoneClick} class:disabled={!$requestedMicrophoneState || isSilent}>
|
||||||
|| isSilent} class:enabled={$requestedScreenSharingState}>
|
{#if $requestedMicrophoneState && !isSilent}
|
||||||
{#if $requestedScreenSharingState && !isSilent}
|
<img src={microphoneImg} alt="Turn on microphone" />
|
||||||
<img src={monitorImg} alt="Start screen sharing">
|
|
||||||
{:else}
|
{:else}
|
||||||
<img src={monitorCloseImg} alt="Stop screen sharing">
|
<img src={microphoneCloseImg} alt="Turn off microphone" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from "svelte/transition";
|
||||||
import { chatMessagesStore, chatVisibilityStore } from "../../Stores/ChatStore";
|
import { chatMessagesStore, chatVisibilityStore } from "../../Stores/ChatStore";
|
||||||
import ChatMessageForm from './ChatMessageForm.svelte';
|
import ChatMessageForm from "./ChatMessageForm.svelte";
|
||||||
import ChatElement from './ChatElement.svelte';
|
import ChatElement from "./ChatElement.svelte";
|
||||||
import {afterUpdate, beforeUpdate, onMount} from "svelte";
|
import { afterUpdate, beforeUpdate, onMount } from "svelte";
|
||||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||||
|
|
||||||
let listDom: HTMLElement;
|
let listDom: HTMLElement;
|
||||||
let chatWindowElement: HTMLElement;
|
let chatWindowElement: HTMLElement;
|
||||||
let handleFormBlur: { blur():void };
|
let handleFormBlur: { blur(): void };
|
||||||
let autoscroll: boolean;
|
let autoscroll: boolean;
|
||||||
|
|
||||||
beforeUpdate(() => {
|
beforeUpdate(() => {
|
||||||
autoscroll = listDom && (listDom.offsetHeight + listDom.scrollTop) > (listDom.scrollHeight - 20);
|
autoscroll = listDom && listDom.offsetHeight + listDom.scrollTop > listDom.scrollHeight - 20;
|
||||||
});
|
});
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
listDom.scrollTo(0, listDom.scrollHeight);
|
listDom.scrollTo(0, listDom.scrollHeight);
|
||||||
})
|
});
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
if (autoscroll) listDom.scrollTo(0, listDom.scrollHeight);
|
if (autoscroll) listDom.scrollTo(0, listDom.scrollHeight);
|
||||||
@ -32,78 +32,81 @@
|
|||||||
function closeChat() {
|
function closeChat() {
|
||||||
chatVisibilityStore.set(false);
|
chatVisibilityStore.set(false);
|
||||||
}
|
}
|
||||||
function onKeyDown(e:KeyboardEvent) {
|
function onKeyDown(e: KeyboardEvent) {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === "Escape") {
|
||||||
closeChat();
|
closeChat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:keydown={onKeyDown} on:click={onClick}/>
|
<svelte:window on:keydown={onKeyDown} on:click={onClick} />
|
||||||
|
|
||||||
|
<aside class="chatWindow nes-container is-rounded is-dark" transition:fly={{ x: -1000, duration: 500 }}
|
||||||
<aside class="chatWindow nes-container is-rounded is-dark" transition:fly="{{ x: -1000, duration: 500 }}" bind:this={chatWindowElement}>
|
bind:this={chatWindowElement}>
|
||||||
<p class="close-icon" on:click={closeChat}>×</p>
|
<p class="close-icon" on:click={closeChat}>×</p>
|
||||||
<section class="messagesList" bind:this={listDom}>
|
<section class="messagesList" bind:this={listDom}>
|
||||||
<ul>
|
<ul>
|
||||||
<li><p class="system-text">Here is your chat history: </p></li>
|
<li><p class="system-text">Here is your chat history:</p></li>
|
||||||
{#each $chatMessagesStore as message, i}
|
{#each $chatMessagesStore as message, i}
|
||||||
<li><ChatElement message={message} line={i}></ChatElement></li>
|
<li><ChatElement {message} line={i} /></li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section class="messageForm">
|
<section class="messageForm">
|
||||||
<ChatMessageForm bind:handleForm={handleFormBlur}></ChatMessageForm>
|
<ChatMessageForm bind:handleForm={handleFormBlur} />
|
||||||
</section>
|
</section>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
p.close-icon {
|
p.close-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
right: 12px;
|
right: 12px;
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
line-height: 25px;
|
line-height: 25px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.system-text {
|
p.system-text {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
padding:6px;
|
padding: 6px;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
aside.chatWindow {
|
aside.chatWindow {
|
||||||
z-index:100;
|
z-index: 100;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width:30vw;
|
width: 30vw;
|
||||||
min-width: 350px;
|
min-width: 350px;
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: 0;
|
padding: 10px;
|
||||||
padding: 10px;
|
margin: 0;
|
||||||
|
|
||||||
.messagesList {
|
border-bottom-right-radius: 16px;
|
||||||
margin-top: 35px;
|
border-top-right-radius: 16px;
|
||||||
overflow-y: auto;
|
|
||||||
flex: auto;
|
|
||||||
|
|
||||||
ul {
|
.messagesList {
|
||||||
list-style-type: none;
|
margin-top: 35px;
|
||||||
padding-left: 0;
|
overflow-y: auto;
|
||||||
|
flex: auto;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.messageForm {
|
||||||
|
flex: 0 70px;
|
||||||
|
padding-top: 15px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.messageForm {
|
|
||||||
flex: 0 70px;
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,9 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {ChatMessageTypes} from "../../Stores/ChatStore";
|
import { ChatMessageTypes } from "../../Stores/ChatStore";
|
||||||
import type {ChatMessage} from "../../Stores/ChatStore";
|
import type { ChatMessage } from "../../Stores/ChatStore";
|
||||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||||
import ChatPlayerName from './ChatPlayerName.svelte';
|
import ChatPlayerName from "./ChatPlayerName.svelte";
|
||||||
import type {PlayerInterface} from "../../Phaser/Game/PlayerInterface";
|
import type { PlayerInterface } from "../../Phaser/Game/PlayerInterface";
|
||||||
|
|
||||||
export let message: ChatMessage;
|
export let message: ChatMessage;
|
||||||
export let line: number;
|
export let line: number;
|
||||||
@ -18,30 +18,38 @@
|
|||||||
}
|
}
|
||||||
function renderDate(date: Date) {
|
function renderDate(date: Date) {
|
||||||
return date.toLocaleTimeString(navigator.language, {
|
return date.toLocaleTimeString(navigator.language, {
|
||||||
hour: '2-digit',
|
hour: "2-digit",
|
||||||
minute:'2-digit'
|
minute: "2-digit",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function isLastIteration(index: number) {
|
function isLastIteration(index: number) {
|
||||||
return targets.length -1 === index;
|
return targets.length - 1 === index;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="chatElement">
|
<div class="chatElement">
|
||||||
<div class="messagePart">
|
<div class="messagePart">
|
||||||
{#if message.type === ChatMessageTypes.userIncoming}
|
{#if message.type === ChatMessageTypes.userIncoming}
|
||||||
>> {#each targets as target, index}<ChatPlayerName player={target} line={line}></ChatPlayerName>{#if !isLastIteration(index)}, {/if}{/each} entered <span class="date">({renderDate(message.date)})</span>
|
>> {#each targets as target, index}<ChatPlayerName
|
||||||
|
player={target}
|
||||||
|
{line}
|
||||||
|
/>{#if !isLastIteration(index)}, {/if}{/each} entered
|
||||||
|
<span class="date">({renderDate(message.date)})</span>
|
||||||
{:else if message.type === ChatMessageTypes.userOutcoming}
|
{:else if message.type === ChatMessageTypes.userOutcoming}
|
||||||
<< {#each targets as target, index}<ChatPlayerName player={target} line={line}></ChatPlayerName>{#if !isLastIteration(index)}, {/if}{/each} left <span class="date">({renderDate(message.date)})</span>
|
<< {#each targets as target, index}<ChatPlayerName
|
||||||
|
player={target}
|
||||||
|
{line}
|
||||||
|
/>{#if !isLastIteration(index)}, {/if}{/each} left
|
||||||
|
<span class="date">({renderDate(message.date)})</span>
|
||||||
{:else if message.type === ChatMessageTypes.me}
|
{:else if message.type === ChatMessageTypes.me}
|
||||||
<h4>Me: <span class="date">({renderDate(message.date)})</span></h4>
|
<h4>Me: <span class="date">({renderDate(message.date)})</span></h4>
|
||||||
{#each texts as text}
|
{#each texts as text}
|
||||||
<div><p class="my-text nes-balloon from-left is-dark">{@html urlifyText(text)}</p></div>
|
<div><p class="my-text">{@html urlifyText(text)}</p></div>
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
<h4><ChatPlayerName player={author} line={line}></ChatPlayerName>: <span class="date">({renderDate(message.date)})</span></h4>
|
<h4><ChatPlayerName player={author} {line} />: <span class="date">({renderDate(message.date)})</span></h4>
|
||||||
{#each texts as text}
|
{#each texts as text}
|
||||||
<div><p class="other-text nes-balloon from-right is-dark">{@html urlifyText(text)}</p></div>
|
<div><p class="other-text">{@html urlifyText(text)}</p></div>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
@ -49,29 +57,33 @@
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.chatElement {
|
div.chatElement {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
|
||||||
.messagePart {
|
.messagePart {
|
||||||
flex-grow:1;
|
flex-grow: 1;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
||||||
span.date {
|
span.date {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
color: gray;
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
div > p {
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 6px;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
max-width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
&.other-text {
|
||||||
|
background: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.other-text {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div > p {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
max-width: 100%;
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 75px;
|
|
||||||
padding: 5px;
|
|
||||||
|
|
||||||
&.other-text {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,13 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {chatMessagesStore, chatInputFocusStore} from "../../Stores/ChatStore";
|
import { chatMessagesStore, chatInputFocusStore } from "../../Stores/ChatStore";
|
||||||
|
|
||||||
export const handleForm = {
|
export const handleForm = {
|
||||||
blur() {
|
blur() {
|
||||||
inputElement.blur();
|
inputElement.blur();
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
let inputElement: HTMLElement;
|
let inputElement: HTMLElement;
|
||||||
let newMessageText = '';
|
let newMessageText = "";
|
||||||
|
|
||||||
function onFocus() {
|
function onFocus() {
|
||||||
chatInputFocusStore.set(true);
|
chatInputFocusStore.set(true);
|
||||||
@ -19,14 +19,14 @@
|
|||||||
function saveMessage() {
|
function saveMessage() {
|
||||||
if (!newMessageText) return;
|
if (!newMessageText) return;
|
||||||
chatMessagesStore.addPersonnalMessage(newMessageText);
|
chatMessagesStore.addPersonnalMessage(newMessageText);
|
||||||
newMessageText = '';
|
newMessageText = "";
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form on:submit|preventDefault={saveMessage}>
|
<form on:submit|preventDefault={saveMessage}>
|
||||||
<input class="nes-input is-dark" type="text" bind:value={newMessageText} placeholder="Enter your message..." on:focus={onFocus} on:blur={onBlur} bind:this={inputElement}>
|
<input class="nes-input is-dark" type="text" bind:value={newMessageText} placeholder="Enter your message..." on:focus={onFocus} on:blur={onBlur} bind:this={inputElement}>
|
||||||
<button class="nes-btn" type="submit">
|
<button class="nes-btn" type="submit">
|
||||||
<img src="/static/images/send.png" alt="Send" width="20">
|
<img src="/static/images/send.png" alt="Send" width="20" />
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {PlayerInterface} from "../../Phaser/Game/PlayerInterface";
|
import type { PlayerInterface } from "../../Phaser/Game/PlayerInterface";
|
||||||
import {chatSubMenuVisibilityStore} from "../../Stores/ChatStore";
|
import { chatSubMenuVisibilityStore } from "../../Stores/ChatStore";
|
||||||
import {onDestroy, onMount} from "svelte";
|
import { onDestroy, onMount } from "svelte";
|
||||||
import type {Unsubscriber} from "svelte/store";
|
import type { Unsubscriber } from "svelte/store";
|
||||||
import ChatSubMenu from "./ChatSubMenu.svelte";
|
import ChatSubMenu from "./ChatSubMenu.svelte";
|
||||||
|
|
||||||
export let player: PlayerInterface;
|
export let player: PlayerInterface;
|
||||||
@ -17,35 +17,33 @@
|
|||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
chatSubMenuVisivilytUnsubcribe = chatSubMenuVisibilityStore.subscribe((newValue) => {
|
chatSubMenuVisivilytUnsubcribe = chatSubMenuVisibilityStore.subscribe((newValue) => {
|
||||||
isSubMenuOpen = (newValue === player.name + line);
|
isSubMenuOpen = newValue === player.name + line;
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
chatSubMenuVisivilytUnsubcribe();
|
chatSubMenuVisivilytUnsubcribe();
|
||||||
})
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span class="subMenu">
|
<span class="subMenu">
|
||||||
<span class="chatPlayerName" style="color: {player.color || 'white'}" on:click={openSubMenu}>
|
<span class="chatPlayerName" style="color: {player.color || 'white'}" on:click={openSubMenu}>
|
||||||
{player.name}
|
{player.name}
|
||||||
</span>
|
</span>
|
||||||
{#if isSubMenuOpen}
|
{#if isSubMenuOpen}
|
||||||
<ChatSubMenu player={player}/>
|
<ChatSubMenu {player} />
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
span.subMenu {
|
span.subMenu {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
span.chatPlayerName {
|
span.chatPlayerName {
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
}
|
}
|
||||||
.chatPlayerName:hover {
|
.chatPlayerName:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,10 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {PlayerInterface} from "../../Phaser/Game/PlayerInterface";
|
import type { PlayerInterface } from "../../Phaser/Game/PlayerInterface";
|
||||||
import {requestVisitCardsStore} from "../../Stores/GameStore";
|
import { requestVisitCardsStore } from "../../Stores/GameStore";
|
||||||
|
|
||||||
export let player: PlayerInterface;
|
export let player: PlayerInterface;
|
||||||
|
|
||||||
|
|
||||||
function openVisitCard() {
|
function openVisitCard() {
|
||||||
if (player.visitCardUrl) {
|
if (player.visitCardUrl) {
|
||||||
requestVisitCardsStore.set(player.visitCardUrl);
|
requestVisitCardsStore.set(player.visitCardUrl);
|
||||||
@ -17,17 +16,16 @@
|
|||||||
<li><button class="text-btn" disabled>Add friend</button></li>
|
<li><button class="text-btn" disabled>Add friend</button></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
ul.selectMenu {
|
ul.selectMenu {
|
||||||
background-color: whitesmoke;
|
background-color: whitesmoke;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type { Game } from "../../Phaser/Game/Game";
|
import type { Game } from "../../Phaser/Game/Game";
|
||||||
import {CustomizeScene, CustomizeSceneName} from "../../Phaser/Login/CustomizeScene";
|
import { CustomizeScene, CustomizeSceneName } from "../../Phaser/Login/CustomizeScene";
|
||||||
import {activeRowStore} from "../../Stores/CustomCharacterStore";
|
import { activeRowStore } from "../../Stores/CustomCharacterStore";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
|
|
||||||
@ -30,7 +30,6 @@
|
|||||||
function finish() {
|
function finish() {
|
||||||
customCharacterScene.nextSceneToCamera();
|
customCharacterScene.nextSceneToCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form class="customCharacterScene">
|
<form class="customCharacterScene">
|
||||||
@ -38,80 +37,100 @@
|
|||||||
<h2>Customize your Avatar</h2>
|
<h2>Customize your Avatar</h2>
|
||||||
</section>
|
</section>
|
||||||
<section class="action action-move">
|
<section class="action action-move">
|
||||||
<button class="customCharacterSceneButton customCharacterSceneButtonLeft nes-btn" on:click|preventDefault={ selectLeft }> < </button>
|
<button
|
||||||
<button class="customCharacterSceneButton customCharacterSceneButtonRight nes-btn" on:click|preventDefault={ selectRight }> > </button>
|
class="customCharacterSceneButton customCharacterSceneButtonLeft nes-btn"
|
||||||
|
on:click|preventDefault={selectLeft}
|
||||||
|
>
|
||||||
|
<
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="customCharacterSceneButton customCharacterSceneButtonRight nes-btn"
|
||||||
|
on:click|preventDefault={selectRight}
|
||||||
|
>
|
||||||
|
>
|
||||||
|
</button>
|
||||||
</section>
|
</section>
|
||||||
<section class="action">
|
<section class="action">
|
||||||
{#if $activeRowStore === 0}
|
{#if $activeRowStore === 0}
|
||||||
<button type="submit" class="customCharacterSceneFormBack nes-btn" on:click|preventDefault={ previousScene }>Return</button>
|
<button type="submit" class="customCharacterSceneFormBack nes-btn" on:click|preventDefault={previousScene}
|
||||||
|
>Return</button
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $activeRowStore !== 0}
|
{#if $activeRowStore !== 0}
|
||||||
<button type="submit" class="customCharacterSceneFormBack nes-btn" on:click|preventDefault={ selectUp }>Back <img src="resources/objects/arrow_up_black.png" alt=""/></button>
|
<button type="submit" class="customCharacterSceneFormBack nes-btn" on:click|preventDefault={selectUp}
|
||||||
|
>Back <img src="resources/objects/arrow_up_black.png" alt="" /></button
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $activeRowStore === 5}
|
{#if $activeRowStore === 5}
|
||||||
<button type="submit" class="customCharacterSceneFormSubmit nes-btn is-primary" on:click|preventDefault={ finish }>Finish</button>
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="customCharacterSceneFormSubmit nes-btn is-primary"
|
||||||
|
on:click|preventDefault={finish}>Finish</button
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $activeRowStore !== 5}
|
{#if $activeRowStore !== 5}
|
||||||
<button type="submit" class="customCharacterSceneFormSubmit nes-btn is-primary" on:click|preventDefault={ selectDown }>Next <img src="resources/objects/arrow_down.png" alt=""/></button>
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="customCharacterSceneFormSubmit nes-btn is-primary"
|
||||||
|
on:click|preventDefault={selectDown}>Next <img src="resources/objects/arrow_down.png" alt="" /></button
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
form.customCharacterScene {
|
form.customCharacterScene {
|
||||||
font-family: "Press Start 2P";
|
|
||||||
pointer-events: auto;
|
|
||||||
color: #ebeeee;
|
|
||||||
|
|
||||||
section {
|
|
||||||
margin: 10px;
|
|
||||||
|
|
||||||
&.action {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 55vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-family: "Press Start 2P";
|
font-family: "Press Start 2P";
|
||||||
margin: 1px;
|
pointer-events: auto;
|
||||||
}
|
color: #ebeeee;
|
||||||
|
|
||||||
&.text-center {
|
section {
|
||||||
text-align: center;
|
margin: 10px;
|
||||||
}
|
|
||||||
|
|
||||||
button.customCharacterSceneButton {
|
&.action {
|
||||||
position: absolute;
|
text-align: center;
|
||||||
top: 33vh;
|
margin-top: 55vh;
|
||||||
margin: 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
button.customCharacterSceneFormBack {
|
h2 {
|
||||||
color: #292929;
|
font-family: "Press Start 2P";
|
||||||
}
|
margin: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.customCharacterSceneButton {
|
||||||
|
position: absolute;
|
||||||
|
top: 33vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.customCharacterSceneFormBack {
|
||||||
|
color: #292929;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
|
||||||
|
&.customCharacterSceneButtonLeft {
|
||||||
|
left: 33vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.customCharacterSceneButtonRight {
|
||||||
|
right: 33vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
@media only screen and (max-width: 800px) {
|
||||||
font-family: "Press Start 2P";
|
form.customCharacterScene button.customCharacterSceneButtonLeft {
|
||||||
|
left: 5vw;
|
||||||
&.customCharacterSceneButtonLeft {
|
}
|
||||||
left: 33vw;
|
form.customCharacterScene button.customCharacterSceneButtonRight {
|
||||||
}
|
right: 5vw;
|
||||||
|
}
|
||||||
&.customCharacterSceneButtonRight {
|
|
||||||
right: 33vw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
|
||||||
form.customCharacterScene button.customCharacterSceneButtonLeft{
|
|
||||||
left: 5vw;
|
|
||||||
}
|
|
||||||
form.customCharacterScene button.customCharacterSceneButtonRight{
|
|
||||||
right: 5vw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,76 +1,72 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
|
import type { Unsubscriber } from "svelte/store";
|
||||||
|
import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore";
|
||||||
|
import { onDestroy, onMount } from "svelte";
|
||||||
|
import { EmojiButton } from "@joeattardi/emoji-button";
|
||||||
|
import { isMobile } from "../../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
import type { Unsubscriber } from "svelte/store";
|
let emojiContainer: HTMLElement;
|
||||||
import { emoteStore, emoteMenuStore } from "../../Stores/EmoteStore";
|
let picker: EmojiButton;
|
||||||
import { onDestroy, onMount } from "svelte";
|
|
||||||
import { EmojiButton } from '@joeattardi/emoji-button';
|
|
||||||
import { isMobile } from "../../Enum/EnvironmentVariable";
|
|
||||||
|
|
||||||
let emojiContainer: HTMLElement;
|
let unsubscriber: Unsubscriber | null = null;
|
||||||
let picker: EmojiButton;
|
|
||||||
|
|
||||||
let unsubscriber: Unsubscriber | null = null;
|
onMount(() => {
|
||||||
|
picker = new EmojiButton({
|
||||||
|
rootElement: emojiContainer,
|
||||||
|
styleProperties: {
|
||||||
|
"--font": "Press Start 2P",
|
||||||
|
},
|
||||||
|
emojisPerRow: isMobile() ? 6 : 8,
|
||||||
|
autoFocusSearch: false,
|
||||||
|
style: "twemoji",
|
||||||
|
});
|
||||||
|
//the timeout is here to prevent the menu from flashing
|
||||||
|
setTimeout(() => picker.showPicker(emojiContainer), 100);
|
||||||
|
|
||||||
onMount(() => {
|
picker.on("emoji", (selection) => {
|
||||||
picker = new EmojiButton({
|
emoteStore.set({
|
||||||
rootElement: emojiContainer,
|
unicode: selection.emoji,
|
||||||
styleProperties: {
|
url: selection.url,
|
||||||
'--font': 'Press Start 2P'
|
name: selection.name,
|
||||||
},
|
});
|
||||||
theme: 'dark',
|
});
|
||||||
emojisPerRow: isMobile() ? 6 : 8,
|
|
||||||
autoFocusSearch: false,
|
|
||||||
style: 'twemoji',
|
|
||||||
});
|
|
||||||
//the timeout is here to prevent the menu from flashing
|
|
||||||
setTimeout(() => picker.showPicker(emojiContainer), 100);
|
|
||||||
|
|
||||||
picker.on("emoji", (selection) => {
|
picker.on("hidden", () => {
|
||||||
emoteStore.set({
|
emoteMenuStore.closeEmoteMenu();
|
||||||
unicode: selection.emoji,
|
});
|
||||||
url: selection.url,
|
|
||||||
name: selection.name
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
picker.on("hidden", () => {
|
function onKeyDown(e: KeyboardEvent) {
|
||||||
emoteMenuStore.closeEmoteMenu();
|
if (e.key === "Escape") {
|
||||||
});
|
emoteMenuStore.closeEmoteMenu();
|
||||||
|
}
|
||||||
})
|
|
||||||
|
|
||||||
function onKeyDown(e:KeyboardEvent) {
|
|
||||||
if (e.key === 'Escape') {
|
|
||||||
emoteMenuStore.closeEmoteMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDestroy(() => {
|
|
||||||
if (unsubscriber) {
|
|
||||||
unsubscriber();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
picker.destroyPicker();
|
onDestroy(() => {
|
||||||
})
|
if (unsubscriber) {
|
||||||
|
unsubscriber();
|
||||||
|
}
|
||||||
|
|
||||||
|
picker.destroyPicker();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:keydown={onKeyDown}/>
|
<svelte:window on:keydown={onKeyDown} />
|
||||||
|
|
||||||
<div class="emote-menu-container">
|
<div class="emote-menu-container">
|
||||||
<div class="emote-menu" bind:this={emojiContainer}></div>
|
<div class="emote-menu" bind:this={emojiContainer} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.emote-menu-container {
|
.emote-menu-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emote-menu {
|
.emote-menu {
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type {Game} from "../../Phaser/Game/Game";
|
import type { Game } from "../../Phaser/Game/Game";
|
||||||
import {EnableCameraScene, EnableCameraSceneName} from "../../Phaser/Login/EnableCameraScene";
|
import { EnableCameraScene, EnableCameraSceneName } from "../../Phaser/Login/EnableCameraScene";
|
||||||
import {
|
import {
|
||||||
audioConstraintStore,
|
audioConstraintStore,
|
||||||
cameraListStore,
|
cameraListStore,
|
||||||
localStreamStore,
|
localStreamStore,
|
||||||
microphoneListStore,
|
microphoneListStore,
|
||||||
videoConstraintStore
|
videoConstraintStore,
|
||||||
} from "../../Stores/MediaStore";
|
} from "../../Stores/MediaStore";
|
||||||
import {onDestroy} from "svelte";
|
import { onDestroy } from "svelte";
|
||||||
import HorizontalSoundMeterWidget from "./HorizontalSoundMeterWidget.svelte";
|
import HorizontalSoundMeterWidget from "./HorizontalSoundMeterWidget.svelte";
|
||||||
import cinemaCloseImg from "../images/cinema-close.svg";
|
import cinemaCloseImg from "../images/cinema-close.svg";
|
||||||
import cinemaImg from "../images/cinema.svg";
|
import cinemaImg from "../images/cinema.svg";
|
||||||
import microphoneImg from "../images/microphone.svg";
|
import microphoneImg from "../images/microphone.svg";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
let selectedCamera : string|undefined = undefined;
|
let selectedCamera: string | undefined = undefined;
|
||||||
let selectedMicrophone : string|undefined = undefined;
|
let selectedMicrophone: string | undefined = undefined;
|
||||||
|
|
||||||
const enableCameraScene = game.scene.getScene(EnableCameraSceneName) as EnableCameraScene;
|
const enableCameraScene = game.scene.getScene(EnableCameraSceneName) as EnableCameraScene;
|
||||||
|
|
||||||
@ -29,16 +29,16 @@
|
|||||||
return {
|
return {
|
||||||
update(newStream: MediaStream) {
|
update(newStream: MediaStream) {
|
||||||
if (node.srcObject != newStream) {
|
if (node.srcObject != newStream) {
|
||||||
node.srcObject = newStream
|
node.srcObject = newStream;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let stream: MediaStream | null;
|
let stream: MediaStream | null;
|
||||||
|
|
||||||
const unsubscribe = localStreamStore.subscribe(value => {
|
const unsubscribe = localStreamStore.subscribe((value) => {
|
||||||
if (value.type === 'success') {
|
if (value.type === "success") {
|
||||||
stream = value.stream;
|
stream = value.stream;
|
||||||
|
|
||||||
if (stream !== null) {
|
if (stream !== null) {
|
||||||
@ -62,7 +62,7 @@
|
|||||||
|
|
||||||
function normalizeDeviceName(label: string): string {
|
function normalizeDeviceName(label: string): string {
|
||||||
// remove IDs (that can appear in Chrome, like: "HD Pro Webcam (4df7:4eda)"
|
// remove IDs (that can appear in Chrome, like: "HD Pro Webcam (4df7:4eda)"
|
||||||
return label.replace(/(\([[0-9a-f]{4}:[0-9a-f]{4}\))/g, '').trim();
|
return label.replace(/(\([[0-9a-f]{4}:[0-9a-f]{4}\))/g, "").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectCamera() {
|
function selectCamera() {
|
||||||
@ -72,28 +72,27 @@
|
|||||||
function selectMicrophone() {
|
function selectMicrophone() {
|
||||||
audioConstraintStore.setDeviceId(selectedMicrophone);
|
audioConstraintStore.setDeviceId(selectedMicrophone);
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form class="enableCameraScene" on:submit|preventDefault={submit}>
|
<form class="enableCameraScene" on:submit|preventDefault={submit}>
|
||||||
<section class="text-center">
|
<section class="text-center">
|
||||||
<h2>Turn on your camera and microphone</h2>
|
<h2>Turn on your camera and microphone</h2>
|
||||||
</section>
|
</section>
|
||||||
{#if $localStreamStore.type === 'success' && $localStreamStore.stream}
|
{#if $localStreamStore.type === "success" && $localStreamStore.stream}
|
||||||
<video class="myCamVideoSetup" use:srcObject={$localStreamStore.stream} autoplay muted playsinline></video>
|
<video class="myCamVideoSetup" use:srcObject={$localStreamStore.stream} autoplay muted playsinline />
|
||||||
{:else }
|
{:else}
|
||||||
<div class="webrtcsetup">
|
<div class="webrtcsetup">
|
||||||
<img class="background-img" src={cinemaCloseImg} alt="">
|
<img class="background-img" src={cinemaCloseImg} alt="" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<HorizontalSoundMeterWidget stream={stream}></HorizontalSoundMeterWidget>
|
<HorizontalSoundMeterWidget {stream} />
|
||||||
|
|
||||||
<section class="selectWebcamForm">
|
<section class="selectWebcamForm">
|
||||||
|
{#if $cameraListStore.length > 1}
|
||||||
{#if $cameraListStore.length > 1 }
|
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<img src={cinemaImg} alt="Camera" />
|
<img src={cinemaImg} alt="Camera" />
|
||||||
<div class="nes-select is-dark">
|
<div class="nes-select is-dark">
|
||||||
|
<!-- svelte-ignore a11y-no-onchange -->
|
||||||
<select bind:value={selectedCamera} on:change={selectCamera}>
|
<select bind:value={selectedCamera} on:change={selectCamera}>
|
||||||
{#each $cameraListStore as camera}
|
{#each $cameraListStore as camera}
|
||||||
<option value={camera.deviceId}>
|
<option value={camera.deviceId}>
|
||||||
@ -105,10 +104,11 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $microphoneListStore.length > 1 }
|
{#if $microphoneListStore.length > 1}
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<img src={microphoneImg} alt="Microphone" />
|
<img src={microphoneImg} alt="Microphone" />
|
||||||
<div class="nes-select is-dark">
|
<div class="nes-select is-dark">
|
||||||
|
<!-- svelte-ignore a11y-no-onchange -->
|
||||||
<select bind:value={selectedMicrophone} on:change={selectMicrophone}>
|
<select bind:value={selectedMicrophone} on:change={selectMicrophone}>
|
||||||
{#each $microphoneListStore as microphone}
|
{#each $microphoneListStore as microphone}
|
||||||
<option value={microphone.deviceId}>
|
<option value={microphone.deviceId}>
|
||||||
@ -119,111 +119,109 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
<section class="action">
|
<section class="action">
|
||||||
<button type="submit" class="nes-btn is-primary letsgo" >Let's go!</button>
|
<button type="submit" class="nes-btn is-primary letsgo">Let's go!</button>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.enableCameraScene {
|
.enableCameraScene {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
margin: 20px auto 0;
|
margin: 20px auto 0;
|
||||||
color: #ebeeee;
|
color: #ebeeee;
|
||||||
|
|
||||||
section.selectWebcamForm {
|
section.selectWebcamForm {
|
||||||
margin-top: 3vh;
|
margin-top: 3vh;
|
||||||
margin-bottom: 3vh;
|
margin-bottom: 3vh;
|
||||||
min-height: 10vh;
|
min-height: 10vh;
|
||||||
width: 50vw;
|
width: 50vw;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
|
||||||
select {
|
select {
|
||||||
font-family: "Press Start 2P";
|
font-family: "Press Start 2P";
|
||||||
margin-top: 1vh;
|
margin-top: 1vh;
|
||||||
margin-bottom: 1vh;
|
margin-bottom: 1vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
option {
|
section.action {
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
font-family: "Press Start 2P";
|
font-family: "Press Start 2P";
|
||||||
}
|
margin: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
section.action{
|
section.text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2{
|
|
||||||
font-family: "Press Start 2P";
|
|
||||||
margin: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.text-center{
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.letsgo {
|
|
||||||
font-size: 200%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.control-group {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
max-height: 60px;
|
|
||||||
margin-top: 10px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 30px;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.webrtcsetup{
|
button.letsgo {
|
||||||
margin-top: 2vh;
|
font-size: 200%;
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
height: 28.125vw;
|
|
||||||
width: 50vw;
|
|
||||||
border: white 6px solid;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
img.background-img {
|
|
||||||
width: 40%;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.myCamVideoSetup {
|
|
||||||
margin-top: 2vh;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
max-height: 50vh;
|
|
||||||
width: 50vw;
|
|
||||||
border: white 6px solid;
|
|
||||||
-webkit-transform: scaleX(-1);
|
|
||||||
transform: scaleX(-1);
|
|
||||||
|
|
||||||
display: flex;
|
.control-group {
|
||||||
align-items: center;
|
display: flex;
|
||||||
justify-content: center;
|
flex-direction: row;
|
||||||
}
|
max-height: 60px;
|
||||||
|
margin-top: 10px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 30px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webrtcsetup {
|
||||||
|
margin-top: 2vh;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
height: 28.125vw;
|
||||||
|
width: 50vw;
|
||||||
|
border: white 6px solid;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
img.background-img {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.myCamVideoSetup {
|
||||||
|
margin-top: 2vh;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-height: 50vh;
|
||||||
|
width: 50vw;
|
||||||
|
border: white 6px solid;
|
||||||
|
-webkit-transform: scaleX(-1);
|
||||||
|
transform: scaleX(-1);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
@media only screen and (max-width: 800px) {
|
||||||
.enableCameraScene h2 {
|
.enableCameraScene h2 {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
}
|
}
|
||||||
.enableCameraScene .control-group .nes-select {
|
.enableCameraScene .control-group .nes-select {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
}
|
}
|
||||||
.enableCameraScene button.letsgo {
|
.enableCameraScene button.letsgo {
|
||||||
font-size: 160%;
|
font-size: 160%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { AudioContext } from 'standardized-audio-context';
|
import { AudioContext } from "standardized-audio-context";
|
||||||
import {SoundMeter} from "../../Phaser/Components/SoundMeter";
|
import { SoundMeter } from "../../Phaser/Components/SoundMeter";
|
||||||
import {onDestroy} from "svelte";
|
import { onDestroy } from "svelte";
|
||||||
|
|
||||||
export let stream: MediaStream | null;
|
export let stream: MediaStream | null;
|
||||||
let volume = 0;
|
let volume = 0;
|
||||||
@ -11,6 +11,7 @@
|
|||||||
let timeout: ReturnType<typeof setTimeout>;
|
let timeout: ReturnType<typeof setTimeout>;
|
||||||
const soundMeter = new SoundMeter();
|
const soundMeter = new SoundMeter();
|
||||||
let display = false;
|
let display = false;
|
||||||
|
let error = false;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (stream && stream.getAudioTracks().length > 0) {
|
if (stream && stream.getAudioTracks().length > 0) {
|
||||||
@ -19,17 +20,19 @@
|
|||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
clearInterval(timeout);
|
clearInterval(timeout);
|
||||||
|
error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout = setInterval(() => {
|
timeout = setInterval(() => {
|
||||||
try{
|
try {
|
||||||
volume = parseInt((soundMeter.getVolume() / 100 * NB_BARS).toFixed(0));
|
volume = parseInt(((soundMeter.getVolume() / 100) * NB_BARS).toFixed(0));
|
||||||
//console.log(volume);
|
} catch (err) {
|
||||||
}catch(err){
|
if (!error) {
|
||||||
|
console.error(err);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
display = false;
|
display = false;
|
||||||
}
|
}
|
||||||
@ -40,11 +43,10 @@
|
|||||||
if (timeout) {
|
if (timeout) {
|
||||||
clearInterval(timeout);
|
clearInterval(timeout);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
function color(i: number, volume: number) {
|
function color(i: number, volume: number) {
|
||||||
const red = 255 * i / NB_BARS;
|
const red = (255 * i) / NB_BARS;
|
||||||
const green = 255 * (1 - i / NB_BARS);
|
const green = 255 * (1 - i / NB_BARS);
|
||||||
|
|
||||||
let alpha = 1;
|
let alpha = 1;
|
||||||
@ -52,31 +54,29 @@
|
|||||||
alpha = 0.5;
|
alpha = 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'background-color:rgba('+red+', '+green+', 0, '+alpha+')';
|
return "background-color:rgba(" + red + ", " + green + ", 0, " + alpha + ")";
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div class="horizontal-sound-meter" class:active={display}>
|
<div class="horizontal-sound-meter" class:active={display}>
|
||||||
{#each [...Array(NB_BARS).keys()] as i (i)}
|
{#each [...Array(NB_BARS).keys()] as i (i)}
|
||||||
<div style={color(i, volume)}></div>
|
<div style={color(i, volume)} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.horizontal-sound-meter {
|
.horizontal-sound-meter {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-top: 1vh;
|
margin-top: 1vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.horizontal-sound-meter div {
|
.horizontal-sound-meter div {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from "svelte/transition";
|
||||||
import {helpCameraSettingsVisibleStore} from "../../Stores/HelpCameraSettingsStore";
|
import { helpCameraSettingsVisibleStore } from "../../Stores/HelpCameraSettingsStore";
|
||||||
import firefoxImg from "./images/help-setting-camera-permission-firefox.png";
|
import firefoxImg from "./images/help-setting-camera-permission-firefox.png";
|
||||||
import chromeImg from "./images/help-setting-camera-permission-chrome.png";
|
import chromeImg from "./images/help-setting-camera-permission-chrome.png";
|
||||||
import {getNavigatorType, isAndroid as isAndroidFct, NavigatorType} from "../../WebRtc/DeviceUtils";
|
import { getNavigatorType, isAndroid as isAndroidFct, NavigatorType } from "../../WebRtc/DeviceUtils";
|
||||||
|
|
||||||
let isAndroid = isAndroidFct();
|
let isAndroid = isAndroidFct();
|
||||||
let isFirefox = getNavigatorType() === NavigatorType.firefox;
|
let isFirefox = getNavigatorType() === NavigatorType.firefox;
|
||||||
@ -16,30 +16,37 @@
|
|||||||
function close() {
|
function close() {
|
||||||
helpCameraSettingsVisibleStore.set(false);
|
helpCameraSettingsVisibleStore.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form class="helpCameraSettings nes-container" on:submit|preventDefault={close} transition:fly="{{ y: -900, duration: 500 }}">
|
<form
|
||||||
|
class="helpCameraSettings nes-container"
|
||||||
|
on:submit|preventDefault={close}
|
||||||
|
transition:fly={{ y: -900, duration: 500 }}
|
||||||
|
>
|
||||||
<section>
|
<section>
|
||||||
<h2>Camera / Microphone access needed</h2>
|
<h2>Camera / Microphone access needed</h2>
|
||||||
<p class="err">Permission denied</p>
|
<p class="err">Permission denied</p>
|
||||||
<p>You must allow camera and microphone access in your browser.</p>
|
<p>You must allow camera and microphone access in your browser.</p>
|
||||||
<p>
|
<p>
|
||||||
{#if isFirefox }
|
{#if isFirefox}
|
||||||
<p class="err">Please click the "Remember this decision" checkbox, if you don't want Firefox to keep asking you the authorization.</p>
|
<p class="err">
|
||||||
|
Please click the "Remember this decision" checkbox, if you don't want Firefox to keep asking you the
|
||||||
|
authorization.
|
||||||
|
</p>
|
||||||
<img src={firefoxImg} alt="" />
|
<img src={firefoxImg} alt="" />
|
||||||
{:else if isChrome && !isAndroid }
|
{:else if isChrome && !isAndroid}
|
||||||
<img src={chromeImg} alt="" />
|
<img src={chromeImg} alt="" />
|
||||||
{/if}
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<button class="helpCameraSettingsFormRefresh nes-btn" on:click|preventDefault={refresh}>Refresh</button>
|
<button class="helpCameraSettingsFormRefresh nes-btn" on:click|preventDefault={refresh}>Refresh</button>
|
||||||
<button type="submit" class="helpCameraSettingsFormContinue nes-btn is-primary" on:click|preventDefault={close}>Continue without webcam</button>
|
<button type="submit" class="helpCameraSettingsFormContinue nes-btn is-primary" on:click|preventDefault={close}
|
||||||
|
>Continue without webcam</button
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.helpCameraSettings {
|
.helpCameraSettings {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
@ -53,13 +60,13 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-family: 'Press Start 2P';
|
font-family: "Press Start 2P";
|
||||||
}
|
}
|
||||||
|
|
||||||
section {
|
section {
|
||||||
p {
|
p {
|
||||||
margin: 15px;
|
margin: 15px;
|
||||||
font-family: 'Press Start 2P';
|
font-family: "Press Start 2P";
|
||||||
|
|
||||||
& .err {
|
& .err {
|
||||||
color: #ff0000;
|
color: #ff0000;
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div class="layout-manager-list">
|
<div class="layout-manager-list">
|
||||||
{#each $layoutManagerActionStore as action}
|
{#each $layoutManagerActionStore as action}
|
||||||
<div class="nes-container is-dark {action.type}" on:click={() => onClick(action.callback)}>
|
<div class="nes-container is-dark {action.type}" on:click={() => onClick(action.callback)}>
|
||||||
@ -20,39 +19,48 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.layout-manager-list {
|
div.layout-manager-list {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 40px;
|
bottom: 40px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: clamp(200px, 20vw, 20vw);
|
width: clamp(200px, 20vw, 20vw);
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
animation: moveMessage .5s;
|
animation: moveMessage 0.5s;
|
||||||
animation-iteration-count: infinite;
|
animation-iteration-count: infinite;
|
||||||
animation-timing-function: ease-in-out;
|
animation-timing-function: ease-in-out;
|
||||||
}
|
|
||||||
|
|
||||||
div.nes-container {
|
|
||||||
padding: 8px 4px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&.warning {
|
|
||||||
background-color: #ff9800eb;
|
|
||||||
color: #000;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes moveMessage {
|
div.nes-container {
|
||||||
0% {bottom: 40px;}
|
padding: 8px 4px;
|
||||||
50% {bottom: 30px;}
|
text-align: center;
|
||||||
100% {bottom: 40px;}
|
|
||||||
}
|
font-family: Lato;
|
||||||
|
color: whitesmoke;
|
||||||
|
background-color: rgb(0, 0, 0, 0.5);
|
||||||
|
|
||||||
|
&.warning {
|
||||||
|
background-color: #ff9800eb;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes moveMessage {
|
||||||
|
0% {
|
||||||
|
bottom: 40px;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
bottom: 30px;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
bottom: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type {Game} from "../../Phaser/Game/Game";
|
import type { Game } from "../../Phaser/Game/Game";
|
||||||
import {LoginScene, LoginSceneName} from "../../Phaser/Login/LoginScene";
|
import { LoginScene, LoginSceneName } from "../../Phaser/Login/LoginScene";
|
||||||
import {DISPLAY_TERMS_OF_USE, MAX_USERNAME_LENGTH} from "../../Enum/EnvironmentVariable";
|
import { DISPLAY_TERMS_OF_USE, MAX_USERNAME_LENGTH } from "../../Enum/EnvironmentVariable";
|
||||||
import logoImg from "../images/logo.png";
|
import logoImg from "../images/logo.png";
|
||||||
import {gameManager} from "../../Phaser/Game/GameManager";
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
|
|
||||||
const loginScene = game.scene.getScene(LoginSceneName) as LoginScene;
|
const loginScene = game.scene.getScene(LoginSceneName) as LoginScene;
|
||||||
|
|
||||||
let name = gameManager.getPlayerName() || '';
|
let name = gameManager.getPlayerName() || "";
|
||||||
let startValidating = false;
|
let startValidating = false;
|
||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
startValidating = true;
|
startValidating = true;
|
||||||
|
|
||||||
let finalName = name.trim();
|
let finalName = name.trim();
|
||||||
if (finalName !== '') {
|
if (finalName !== "") {
|
||||||
loginScene.login(finalName);
|
loginScene.login(finalName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -29,17 +29,34 @@
|
|||||||
<section class="text-center">
|
<section class="text-center">
|
||||||
<h2>Enter your name</h2>
|
<h2>Enter your name</h2>
|
||||||
</section>
|
</section>
|
||||||
<input type="text" name="loginSceneName" class="nes-input is-dark" autofocus maxlength={MAX_USERNAME_LENGTH} bind:value={name} on:keypress={() => {startValidating = true}} class:is-error={name.trim() === '' && startValidating} />
|
<!-- svelte-ignore a11y-autofocus -->
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="loginSceneName"
|
||||||
|
class="nes-input is-dark"
|
||||||
|
autofocus
|
||||||
|
maxlength={MAX_USERNAME_LENGTH}
|
||||||
|
bind:value={name}
|
||||||
|
on:keypress={() => {
|
||||||
|
startValidating = true;
|
||||||
|
}}
|
||||||
|
class:is-error={name.trim() === "" && startValidating}
|
||||||
|
/>
|
||||||
<section class="error-section">
|
<section class="error-section">
|
||||||
{#if name.trim() === '' && startValidating }
|
{#if name.trim() === "" && startValidating}
|
||||||
<p class="err">The name is empty</p>
|
<p class="err">The name is empty</p>
|
||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{#if DISPLAY_TERMS_OF_USE}
|
{#if DISPLAY_TERMS_OF_USE}
|
||||||
<section class="terms-and-conditions">
|
<section class="terms-and-conditions">
|
||||||
<p>By continuing, you are agreeing our <a href="https://workadventu.re/terms-of-use" target="_blank">terms of use</a>, <a href="https://workadventu.re/privacy-policy" target="_blank">privacy policy</a> and <a href="https://workadventu.re/cookie-policy" target="_blank">cookie policy</a>.</p>
|
<p>
|
||||||
</section>
|
By continuing, you are agreeing our <a href="https://workadventu.re/terms-of-use" target="_blank"
|
||||||
|
>terms of use</a
|
||||||
|
>, <a href="https://workadventu.re/privacy-policy" target="_blank">privacy policy</a> and
|
||||||
|
<a href="https://workadventu.re/cookie-policy" target="_blank">cookie policy</a>.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
{/if}
|
{/if}
|
||||||
<section class="action">
|
<section class="action">
|
||||||
<button type="submit" class="nes-btn is-primary loginSceneFormSubmit">Continue</button>
|
<button type="submit" class="nes-btn is-primary loginSceneFormSubmit">Continue</button>
|
||||||
@ -47,76 +64,75 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.loginScene {
|
.loginScene {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
margin: 20px auto 0;
|
margin: 20px auto 0;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
color: #ebeeee;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column wrap;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
input {
|
|
||||||
text-align: center;
|
|
||||||
font-family: "Press Start 2P";
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terms-and-conditions {
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.err {
|
|
||||||
color: #ce372b;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
|
||||||
margin: 10px;
|
|
||||||
|
|
||||||
&.error-section {
|
|
||||||
min-height: 2rem;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.action {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-family: "Press Start 2P";
|
|
||||||
margin: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.text-center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: #ebeeee;
|
color: #ebeeee;
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
display: flex;
|
||||||
font-weight: 700;
|
flex-flow: column wrap;
|
||||||
}
|
align-items: center;
|
||||||
|
|
||||||
p {
|
input {
|
||||||
text-align: left;
|
text-align: center;
|
||||||
margin: 10px 10px;
|
font-family: "Press Start 2P";
|
||||||
}
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
img {
|
.terms-and-conditions {
|
||||||
width: 100%;
|
max-width: 400px;
|
||||||
margin: 20px 0;
|
}
|
||||||
}
|
|
||||||
|
p.err {
|
||||||
|
color: #ce372b;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
margin: 10px;
|
||||||
|
|
||||||
|
&.error-section {
|
||||||
|
min-height: 2rem;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.action {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
margin: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #ebeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-align: left;
|
||||||
|
margin: 10px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { gameManager } from "../../Phaser/Game/GameManager";
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
import {onMount} from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
let gameScene = gameManager.getCurrentGameScene();
|
let gameScene = gameManager.getCurrentGameScene();
|
||||||
|
|
||||||
@ -14,29 +14,33 @@
|
|||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (gameScene.mapFile.properties !== undefined) {
|
if (gameScene.mapFile.properties !== undefined) {
|
||||||
const propertyName = gameScene.mapFile.properties.find((property) => property.name === 'mapName')
|
const propertyName = gameScene.mapFile.properties.find((property) => property.name === "mapName");
|
||||||
if ( propertyName !== undefined && typeof propertyName.value === 'string') {
|
if (propertyName !== undefined && typeof propertyName.value === "string") {
|
||||||
mapName = propertyName.value;
|
mapName = propertyName.value;
|
||||||
}
|
}
|
||||||
const propertyDescription = gameScene.mapFile.properties.find((property) => property.name === 'mapDescription')
|
const propertyDescription = gameScene.mapFile.properties.find(
|
||||||
if (propertyDescription !== undefined && typeof propertyDescription.value === 'string') {
|
(property) => property.name === "mapDescription"
|
||||||
|
);
|
||||||
|
if (propertyDescription !== undefined && typeof propertyDescription.value === "string") {
|
||||||
mapDescription = propertyDescription.value;
|
mapDescription = propertyDescription.value;
|
||||||
}
|
}
|
||||||
const propertyCopyright = gameScene.mapFile.properties.find((property) => property.name === 'mapCopyright')
|
const propertyCopyright = gameScene.mapFile.properties.find((property) => property.name === "mapCopyright");
|
||||||
if (propertyCopyright !== undefined && typeof propertyCopyright.value === 'string') {
|
if (propertyCopyright !== undefined && typeof propertyCopyright.value === "string") {
|
||||||
mapCopyright = propertyCopyright.value;
|
mapCopyright = propertyCopyright.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const tileset of gameScene.mapFile.tilesets) {
|
for (const tileset of gameScene.mapFile.tilesets) {
|
||||||
if (tileset.properties !== undefined) {
|
if (tileset.properties !== undefined) {
|
||||||
const propertyTilesetCopyright = tileset.properties.find((property) => property.name === 'tilesetCopyright')
|
const propertyTilesetCopyright = tileset.properties.find(
|
||||||
if (propertyTilesetCopyright !== undefined && typeof propertyTilesetCopyright.value === 'string') {
|
(property) => property.name === "tilesetCopyright"
|
||||||
|
);
|
||||||
|
if (propertyTilesetCopyright !== undefined && typeof propertyTilesetCopyright.value === "string") {
|
||||||
tilesetCopyright = [...tilesetCopyright, propertyTilesetCopyright.value]; //Assignment needed to trigger Svelte's reactivity
|
tilesetCopyright = [...tilesetCopyright, propertyTilesetCopyright.value]; //Assignment needed to trigger Svelte's reactivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="about-room-main">
|
<div class="about-room-main">
|
||||||
@ -44,51 +48,58 @@
|
|||||||
<section class="container-overflow">
|
<section class="container-overflow">
|
||||||
<h3>{mapName}</h3>
|
<h3>{mapName}</h3>
|
||||||
<p class="string-HTML">{mapDescription}</p>
|
<p class="string-HTML">{mapDescription}</p>
|
||||||
<h3 class="nes-pointer hoverable" on:click={() => expandedMapCopyright = !expandedMapCopyright}>Copyrights of the map</h3>
|
<h3 class="nes-pointer hoverable" on:click={() => (expandedMapCopyright = !expandedMapCopyright)}>
|
||||||
<p class="string-HTML" hidden="{!expandedMapCopyright}">{mapCopyright}</p>
|
Copyrights of the map
|
||||||
<h3 class="nes-pointer hoverable" on:click={() => expandedTilesetCopyright = !expandedTilesetCopyright}>Copyrights of the tilesets</h3>
|
</h3>
|
||||||
<section hidden="{!expandedTilesetCopyright}">
|
<p class="string-HTML" hidden={!expandedMapCopyright}>{mapCopyright}</p>
|
||||||
|
<h3 class="nes-pointer hoverable" on:click={() => (expandedTilesetCopyright = !expandedTilesetCopyright)}>
|
||||||
|
Copyrights of the tilesets
|
||||||
|
</h3>
|
||||||
|
<section hidden={!expandedTilesetCopyright}>
|
||||||
{#each tilesetCopyright as copyright}
|
{#each tilesetCopyright as copyright}
|
||||||
<p class="string-HTML">{copyright}</p>
|
<p class="string-HTML">{copyright}</p>
|
||||||
{:else}
|
{:else}
|
||||||
<p>The map creator did not declare a copyright for the tilesets. Warning, This doesn't mean that those tilesets have no license.</p>
|
<p>
|
||||||
|
The map creator did not declare a copyright for the tilesets. Warning, This doesn't mean that those
|
||||||
|
tilesets have no license.
|
||||||
|
</p>
|
||||||
{/each}
|
{/each}
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.string-HTML{
|
.string-HTML {
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
}
|
|
||||||
|
|
||||||
div.about-room-main {
|
|
||||||
height: calc(100% - 56px);
|
|
||||||
|
|
||||||
h2, h3 {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h3.hoverable:hover {
|
|
||||||
background-color: #3c3e40;
|
|
||||||
border-radius: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.container-overflow {
|
|
||||||
height: calc(100% - 220px);
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
|
||||||
div.about-room-main {
|
div.about-room-main {
|
||||||
section.container-overflow {
|
height: calc(100% - 56px);
|
||||||
height: calc(100% - 120px);
|
|
||||||
}
|
h2,
|
||||||
|
h3 {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3.hoverable:hover {
|
||||||
|
background-color: #3c3e40;
|
||||||
|
border-radius: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.container-overflow {
|
||||||
|
height: calc(100% - 220px);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||||
|
div.about-room-main {
|
||||||
|
section.container-overflow {
|
||||||
|
height: calc(100% - 120px);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -26,31 +26,31 @@
|
|||||||
const selectedFile = inputAudio.files ? inputAudio.files[0] : null;
|
const selectedFile = inputAudio.files ? inputAudio.files[0] : null;
|
||||||
if (!selectedFile) {
|
if (!selectedFile) {
|
||||||
errorFile = true;
|
errorFile = true;
|
||||||
throw 'no file selected';
|
throw "no file selected";
|
||||||
}
|
}
|
||||||
|
|
||||||
const fd = new FormData();
|
const fd = new FormData();
|
||||||
fd.append('file', selectedFile);
|
fd.append("file", selectedFile);
|
||||||
const res = await gameScene.connection?.uploadAudio(fd);
|
const res = await gameScene.connection?.uploadAudio(fd);
|
||||||
|
|
||||||
const audioGlobalMessage: PlayGlobalMessageInterface = {
|
const audioGlobalMessage: PlayGlobalMessageInterface = {
|
||||||
content: (res as { path: string }).path,
|
content: (res as { path: string }).path,
|
||||||
type: AUDIO_TYPE,
|
type: AUDIO_TYPE,
|
||||||
broadcastToWorld: broadcast
|
broadcastToWorld: broadcast,
|
||||||
}
|
};
|
||||||
inputAudio.value = '';
|
inputAudio.value = "";
|
||||||
gameScene.connection?.emitGlobalMessage(audioGlobalMessage);
|
gameScene.connection?.emitGlobalMessage(audioGlobalMessage);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
function inputAudioFile(event: Event) {
|
function inputAudioFile(event: Event) {
|
||||||
const eventTarget : EventTargetFiles = (event.target as EventTargetFiles);
|
const eventTarget: EventTargetFiles = event.target as EventTargetFiles;
|
||||||
if(!eventTarget || !eventTarget.files || eventTarget.files.length === 0){
|
if (!eventTarget || !eventTarget.files || eventTarget.files.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const file = eventTarget.files[0];
|
const file = eventTarget.files[0];
|
||||||
if(!file) {
|
if (!file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,52 +61,65 @@
|
|||||||
|
|
||||||
function getFileSize(number: number) {
|
function getFileSize(number: number) {
|
||||||
if (number < 1024) {
|
if (number < 1024) {
|
||||||
return number + 'bytes';
|
return number + "bytes";
|
||||||
} else if (number >= 1024 && number < 1048576) {
|
} else if (number >= 1024 && number < 1048576) {
|
||||||
return (number / 1024).toFixed(1) + 'KB';
|
return (number / 1024).toFixed(1) + "KB";
|
||||||
} else if (number >= 1048576) {
|
} else if (number >= 1048576) {
|
||||||
return (number / 1048576).toFixed(1) + 'MB';
|
return (number / 1048576).toFixed(1) + "MB";
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<section class="section-input-send-audio">
|
<section class="section-input-send-audio">
|
||||||
<img class="nes-pointer" src="{uploadFile}" alt="Upload a file" on:click|preventDefault={ () => {fileInput.click();}}>
|
<img
|
||||||
|
class="nes-pointer"
|
||||||
|
src={uploadFile}
|
||||||
|
alt="Upload a file"
|
||||||
|
on:click|preventDefault={() => {
|
||||||
|
fileInput.click();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
{#if fileName !== undefined}
|
{#if fileName !== undefined}
|
||||||
<p>{fileName} : {fileSize}</p>
|
<p>{fileName} : {fileSize}</p>
|
||||||
{/if}
|
{/if}
|
||||||
{#if errorFile}
|
{#if errorFile}
|
||||||
<p class="err">No file selected. You need to upload a file before sending it.</p>
|
<p class="err">No file selected. You need to upload a file before sending it.</p>
|
||||||
{/if}
|
{/if}
|
||||||
<input type="file" id="input-send-audio" bind:this={fileInput} on:change={(e) => {inputAudioFile(e)}}>
|
<input
|
||||||
|
type="file"
|
||||||
|
id="input-send-audio"
|
||||||
|
bind:this={fileInput}
|
||||||
|
on:change={(e) => {
|
||||||
|
inputAudioFile(e);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
section.section-input-send-audio {
|
section.section-input-send-audio {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
max-height: 80%;
|
max-height: 80%;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
color: whitesmoke;
|
||||||
|
font-size: 1rem;
|
||||||
|
&.err {
|
||||||
|
color: #ce372b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
color: whitesmoke;
|
|
||||||
font-size: 1rem;
|
|
||||||
&.err {
|
|
||||||
color: #ce372b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
input {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
function goToGettingStarted() {
|
function goToGettingStarted() {
|
||||||
const sparkHost = "https://workadventu.re/getting-started";
|
const sparkHost = "https://workadventu.re/getting-started";
|
||||||
window.open(sparkHost, "_blank");
|
window.open(sparkHost, "_blank");
|
||||||
@ -10,7 +9,7 @@
|
|||||||
window.open(sparkHost, "_blank");
|
window.open(sparkHost, "_blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
import {contactPageStore} from "../../Stores/MenuStore";
|
import { contactPageStore } from "../../Stores/MenuStore";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="create-map-main">
|
<div class="create-map-main">
|
||||||
@ -18,8 +17,8 @@
|
|||||||
<section>
|
<section>
|
||||||
<h3>Getting started</h3>
|
<h3>Getting started</h3>
|
||||||
<p>
|
<p>
|
||||||
WorkAdventure allows you to create an online space to communicate spontaneously with others.
|
WorkAdventure allows you to create an online space to communicate spontaneously with others. And it all
|
||||||
And it all starts with creating your own space. Choose from a large selection of prefabricated maps by our team.
|
starts with creating your own space. Choose from a large selection of prefabricated maps by our team.
|
||||||
</p>
|
</p>
|
||||||
<button type="button" class="nes-btn is-primary" on:click={goToGettingStarted}>Getting started</button>
|
<button type="button" class="nes-btn is-primary" on:click={goToGettingStarted}>Getting started</button>
|
||||||
</section>
|
</section>
|
||||||
@ -30,35 +29,37 @@
|
|||||||
<button type="button" class="nes-btn" on:click={goToBuildingMap}>Create your map</button>
|
<button type="button" class="nes-btn" on:click={goToBuildingMap}>Create your map</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<iframe title="contact"
|
<iframe
|
||||||
src="{$contactPageStore}"
|
title="contact"
|
||||||
allow="clipboard-read; clipboard-write self {$contactPageStore}"
|
src={$contactPageStore}
|
||||||
allowfullscreen></iframe>
|
allow="clipboard-read; clipboard-write self {$contactPageStore}"
|
||||||
|
allowfullscreen
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.create-map-main {
|
div.create-map-main {
|
||||||
height: calc(100% - 56px);
|
height: calc(100% - 56px);
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
section {
|
section {
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
section.container-overflow {
|
section.container-overflow {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
border: none;
|
border: none;
|
||||||
height: calc(100% - 56px);
|
height: calc(100% - 56px);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,33 +1,32 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {onDestroy, onMount} from "svelte";
|
import { onDestroy, onMount } from "svelte";
|
||||||
import {iframeListener} from "../../Api/IframeListener";
|
import { iframeListener } from "../../Api/IframeListener";
|
||||||
|
|
||||||
export let url: string;
|
export let url: string;
|
||||||
export let allowApi: boolean;
|
export let allowApi: boolean;
|
||||||
|
|
||||||
let HTMLIframe: HTMLIFrameElement;
|
let HTMLIframe: HTMLIFrameElement;
|
||||||
|
|
||||||
onMount( () => {
|
onMount(() => {
|
||||||
if (allowApi) {
|
if (allowApi) {
|
||||||
iframeListener.registerIframe(HTMLIframe);
|
iframeListener.registerIframe(HTMLIframe);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
onDestroy( () => {
|
onDestroy(() => {
|
||||||
if (allowApi) {
|
if (allowApi) {
|
||||||
iframeListener.unregisterIframe(HTMLIframe);
|
iframeListener.unregisterIframe(HTMLIframe);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<iframe title="customSubMenu" src={url} bind:this={HTMLIframe} />
|
||||||
<iframe title="customSubMenu" src="{url}" bind:this={HTMLIframe}></iframe>
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
iframe {
|
iframe {
|
||||||
border: none;
|
border: none;
|
||||||
height: calc(100% - 56px);
|
height: calc(100% - 56px);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import TextGlobalMessage from './TextGlobalMessage.svelte';
|
import TextGlobalMessage from "./TextGlobalMessage.svelte";
|
||||||
import AudioGlobalMessage from './AudioGlobalMessage.svelte';
|
import AudioGlobalMessage from "./AudioGlobalMessage.svelte";
|
||||||
|
|
||||||
let handleSendText: { sendTextMessage(broadcast: boolean): void };
|
let handleSendText: { sendTextMessage(broadcast: boolean): void };
|
||||||
let handleSendAudio: { sendAudioMessage(broadcast: boolean): Promise<void> };
|
let handleSendAudio: { sendAudioMessage(broadcast: boolean): Promise<void> };
|
||||||
@ -32,23 +32,31 @@
|
|||||||
<div class="global-message-main">
|
<div class="global-message-main">
|
||||||
<div class="global-message-subOptions">
|
<div class="global-message-subOptions">
|
||||||
<section>
|
<section>
|
||||||
<button type="button" class="nes-btn {inputSendTextActive ? 'is-disabled' : ''}" on:click|preventDefault={activateInputText}>Text</button>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="nes-btn {inputSendTextActive ? 'is-disabled' : ''}"
|
||||||
|
on:click|preventDefault={activateInputText}>Text</button
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<button type="button" class="nes-btn {uploadAudioActive ? 'is-disabled' : ''}" on:click|preventDefault={activateUploadAudio}>Audio</button>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="nes-btn {uploadAudioActive ? 'is-disabled' : ''}"
|
||||||
|
on:click|preventDefault={activateUploadAudio}>Audio</button
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="global-message-content">
|
<div class="global-message-content">
|
||||||
{#if inputSendTextActive}
|
{#if inputSendTextActive}
|
||||||
<TextGlobalMessage bind:handleSending={handleSendText}/>
|
<TextGlobalMessage bind:handleSending={handleSendText} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if uploadAudioActive}
|
{#if uploadAudioActive}
|
||||||
<AudioGlobalMessage bind:handleSending={handleSendAudio}/>
|
<AudioGlobalMessage bind:handleSending={handleSendAudio} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="global-message-footer">
|
<div class="global-message-footer">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" class="nes-checkbox is-dark nes-pointer" bind:checked={broadcastToWorld}>
|
<input type="checkbox" class="nes-checkbox is-dark nes-pointer" bind:checked={broadcastToWorld} />
|
||||||
<span>Broadcast to all rooms of the world</span>
|
<span>Broadcast to all rooms of the world</span>
|
||||||
</label>
|
</label>
|
||||||
<section>
|
<section>
|
||||||
@ -57,62 +65,59 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.global-message-main {
|
div.global-message-main {
|
||||||
height: calc(100% - 50px);
|
height: calc(100% - 50px);
|
||||||
display: grid;
|
|
||||||
grid-template-rows: 15% 65% 20%;
|
|
||||||
|
|
||||||
div.global-message-subOptions {
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 50% 50%;
|
grid-template-rows: 15% 65% 20%;
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
section {
|
div.global-message-subOptions {
|
||||||
display: flex;
|
display: grid;
|
||||||
justify-content: center;
|
grid-template-columns: 50% 50%;
|
||||||
align-items: center;
|
margin-bottom: 20px;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div.global-message-footer {
|
section {
|
||||||
margin-bottom: 10px;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
display: grid;
|
align-items: center;
|
||||||
grid-template-rows: 50% 50%;
|
}
|
||||||
|
|
||||||
section {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
div.global-message-footer {
|
||||||
margin: 10px;
|
margin-bottom: 10px;
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
span {
|
display: grid;
|
||||||
font-family: "Press Start 2P";
|
grid-template-rows: 50% 50%;
|
||||||
}
|
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||||
.global-message-content {
|
.global-message-content {
|
||||||
height: calc(100% - 5px);
|
height: calc(100% - 5px);
|
||||||
}
|
}
|
||||||
.global-message-footer {
|
.global-message-footer {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
||||||
label {
|
label {
|
||||||
width: calc(100% - 10px);
|
width: calc(100% - 10px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,18 +1,18 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
function copyLink() {
|
function copyLink() {
|
||||||
const input: HTMLInputElement = document.getElementById('input-share-link') as HTMLInputElement;
|
const input: HTMLInputElement = document.getElementById("input-share-link") as HTMLInputElement;
|
||||||
input.focus();
|
input.focus();
|
||||||
input.select();
|
input.select();
|
||||||
document.execCommand('copy');
|
document.execCommand("copy");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function shareLink() {
|
async function shareLink() {
|
||||||
const shareData = {url: location.toString()};
|
const shareData = { url: location.toString() };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await navigator.share(shareData);
|
await navigator.share(shareData);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error: ' + err);
|
console.error("Error: " + err);
|
||||||
copyLink();
|
copyLink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22,12 +22,12 @@
|
|||||||
<section class="container-overflow">
|
<section class="container-overflow">
|
||||||
<section class="share-url not-mobile">
|
<section class="share-url not-mobile">
|
||||||
<h3>Share the link of the room !</h3>
|
<h3>Share the link of the room !</h3>
|
||||||
<input type="text" readonly id="input-share-link" value={location.toString()}>
|
<input type="text" readonly id="input-share-link" value={location.toString()} />
|
||||||
<button type="button" class="nes-btn is-primary" on:click={copyLink}>Copy</button>
|
<button type="button" class="nes-btn is-primary" on:click={copyLink}>Copy</button>
|
||||||
</section>
|
</section>
|
||||||
<section class="is-mobile">
|
<section class="is-mobile">
|
||||||
<h3>Share the link of the room !</h3>
|
<h3>Share the link of the room !</h3>
|
||||||
<input type="hidden" readonly id="input-share-link" value={location.toString()}>
|
<input type="hidden" readonly id="input-share-link" value={location.toString()} />
|
||||||
<button type="button" class="nes-btn is-primary" on:click={shareLink}>Share</button>
|
<button type="button" class="nes-btn is-primary" on:click={shareLink}>Share</button>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
@ -35,41 +35,41 @@
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.guest-main {
|
div.guest-main {
|
||||||
height: calc(100% - 56px);
|
height: calc(100% - 56px);
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
section {
|
section {
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
}
|
|
||||||
|
|
||||||
section.container-overflow {
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.is-mobile {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 900px), only screen and (max-height: 600px) {
|
|
||||||
div.guest-main {
|
|
||||||
section.share-url.not-mobile {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.is-mobile {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
section.container-overflow {
|
section.container-overflow {
|
||||||
height: calc(100% - 120px);
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.is-mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 900px), only screen and (max-height: 600px) {
|
||||||
|
div.guest-main {
|
||||||
|
section.share-url.not-mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.is-mobile {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.container-overflow {
|
||||||
|
height: calc(100% - 120px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,47 +1,47 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import {fly} from "svelte/transition";
|
import { fly } from "svelte/transition";
|
||||||
import SettingsSubMenu from "./SettingsSubMenu.svelte";
|
import SettingsSubMenu from "./SettingsSubMenu.svelte";
|
||||||
import ProfileSubMenu from "./ProfileSubMenu.svelte";
|
import ProfileSubMenu from "./ProfileSubMenu.svelte";
|
||||||
import WorldsSubMenu from "./WorldsSubMenu.svelte";
|
import WorldsSubMenu from "./WorldsSubMenu.svelte";
|
||||||
import AboutRoomSubMenu from "./AboutRoomSubMenu.svelte";
|
import AboutRoomSubMenu from "./AboutRoomSubMenu.svelte";
|
||||||
import GlobalMessageSubMenu from "./GlobalMessagesSubMenu.svelte";
|
import GlobalMessageSubMenu from "./GlobalMessagesSubMenu.svelte";
|
||||||
import ContactSubMenu from "./ContactSubMenu.svelte";
|
import ContactSubMenu from "./ContactSubMenu.svelte";
|
||||||
import CustomSubMenu from "./CustomSubMenu.svelte"
|
import CustomSubMenu from "./CustomSubMenu.svelte";
|
||||||
import GuestSubMenu from "./GuestSubMenu.svelte";
|
import GuestSubMenu from "./GuestSubMenu.svelte";
|
||||||
import {
|
import {
|
||||||
checkSubMenuToShow,
|
checkSubMenuToShow,
|
||||||
customMenuIframe,
|
customMenuIframe,
|
||||||
menuVisiblilityStore,
|
menuVisiblilityStore,
|
||||||
SubMenusInterface,
|
SubMenusInterface,
|
||||||
subMenusStore
|
subMenusStore,
|
||||||
} from "../../Stores/MenuStore";
|
} from "../../Stores/MenuStore";
|
||||||
import {onDestroy, onMount} from "svelte";
|
import { onDestroy, onMount } from "svelte";
|
||||||
import {get} from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
import type {Unsubscriber} from "svelte/store";
|
import type { Unsubscriber } from "svelte/store";
|
||||||
import {sendMenuClickedEvent} from "../../Api/iframe/Ui/MenuItem";
|
import { sendMenuClickedEvent } from "../../Api/iframe/Ui/MenuItem";
|
||||||
|
|
||||||
let activeSubMenu: string = SubMenusInterface.profile;
|
let activeSubMenu: string = SubMenusInterface.profile;
|
||||||
let activeComponent: typeof ProfileSubMenu | typeof CustomSubMenu = ProfileSubMenu;
|
let activeComponent: typeof ProfileSubMenu | typeof CustomSubMenu = ProfileSubMenu;
|
||||||
let props: { url: string, allowApi: boolean };
|
let props: { url: string; allowApi: boolean };
|
||||||
let unsubscriberSubMenuStore: Unsubscriber;
|
let unsubscriberSubMenuStore: Unsubscriber;
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
unsubscriberSubMenuStore = subMenusStore.subscribe(() => {
|
unsubscriberSubMenuStore = subMenusStore.subscribe(() => {
|
||||||
if(!get(subMenusStore).includes(activeSubMenu)) {
|
if (!get(subMenusStore).includes(activeSubMenu)) {
|
||||||
switchMenu(SubMenusInterface.profile);
|
switchMenu(SubMenusInterface.profile);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
checkSubMenuToShow();
|
checkSubMenuToShow();
|
||||||
|
|
||||||
switchMenu(SubMenusInterface.profile);
|
switchMenu(SubMenusInterface.profile);
|
||||||
})
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
if(unsubscriberSubMenuStore) {
|
if (unsubscriberSubMenuStore) {
|
||||||
unsubscriberSubMenuStore();
|
unsubscriberSubMenuStore();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
function switchMenu(menu: string) {
|
function switchMenu(menu: string) {
|
||||||
if (get(subMenusStore).find((subMenu) => subMenu === menu)) {
|
if (get(subMenusStore).find((subMenu) => subMenu === menu)) {
|
||||||
@ -68,7 +68,7 @@
|
|||||||
case SubMenusInterface.contact:
|
case SubMenusInterface.contact:
|
||||||
activeComponent = ContactSubMenu;
|
activeComponent = ContactSubMenu;
|
||||||
break;
|
break;
|
||||||
default:
|
default: {
|
||||||
const customMenu = customMenuIframe.get(menu);
|
const customMenu = customMenuIframe.get(menu);
|
||||||
if (customMenu !== undefined) {
|
if (customMenu !== undefined) {
|
||||||
props = { url: customMenu.url, allowApi: customMenu.allowApi };
|
props = { url: customMenu.url, allowApi: customMenu.allowApi };
|
||||||
@ -78,109 +78,113 @@
|
|||||||
menuVisiblilityStore.set(false);
|
menuVisiblilityStore.set(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else throw ("There is no menu called " + menu);
|
} else throw "There is no menu called " + menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeMenu() {
|
function closeMenu() {
|
||||||
menuVisiblilityStore.set(false);
|
menuVisiblilityStore.set(false);
|
||||||
}
|
}
|
||||||
function onKeyDown(e:KeyboardEvent) {
|
function onKeyDown(e: KeyboardEvent) {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === "Escape") {
|
||||||
closeMenu();
|
closeMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:keydown={onKeyDown}/>
|
<svelte:window on:keydown={onKeyDown} />
|
||||||
|
|
||||||
|
|
||||||
<div class="menu-container-main">
|
<div class="menu-container-main">
|
||||||
<div class="menu-nav-sidebar nes-container is-rounded" transition:fly="{{ x: -1000, duration: 500 }}">
|
<div class="menu-nav-sidebar nes-container is-rounded" transition:fly={{ x: -1000, duration: 500 }}>
|
||||||
<h2>Menu</h2>
|
<h2>Menu</h2>
|
||||||
<nav>
|
<nav>
|
||||||
{#each $subMenusStore as submenu}
|
{#each $subMenusStore as submenu}
|
||||||
<button type="button" class="nes-btn {activeSubMenu === submenu ? 'is-disabled' : ''}" on:click|preventDefault={() => switchMenu(submenu)}>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="nes-btn {activeSubMenu === submenu ? 'is-disabled' : ''}"
|
||||||
|
on:click|preventDefault={() => switchMenu(submenu)}
|
||||||
|
>
|
||||||
{submenu}
|
{submenu}
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-submenu-container nes-container is-rounded" transition:fly="{{ y: -1000, duration: 500 }}">
|
<div class="menu-submenu-container nes-container is-rounded" transition:fly={{ y: -1000, duration: 500 }}>
|
||||||
<button type="button" class="nes-btn is-error close" on:click={closeMenu}>×</button>
|
<button type="button" class="nes-btn is-error close" on:click={closeMenu}>×</button>
|
||||||
<h2>{activeSubMenu}</h2>
|
<h2>{activeSubMenu}</h2>
|
||||||
<svelte:component this={activeComponent} {...props}/>
|
<svelte:component this={activeComponent} {...props} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.nes-container {
|
.nes-container {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
|
||||||
|
|
||||||
div.menu-container-main {
|
|
||||||
--size-first-columns-grid: 200px;
|
|
||||||
|
|
||||||
font-family: "Press Start 2P";
|
|
||||||
pointer-events: auto;
|
|
||||||
height: 80%;
|
|
||||||
width: 75%;
|
|
||||||
top: 10%;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
z-index: 80;
|
|
||||||
margin: auto;
|
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: var(--size-first-columns-grid) calc(100% - var(--size-first-columns-grid));
|
|
||||||
grid-template-rows: 100%;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div.menu-nav-sidebar {
|
|
||||||
background-color: #333333;
|
|
||||||
color: whitesmoke;
|
|
||||||
|
|
||||||
nav button {
|
|
||||||
width: calc(100% - 10px);
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div.menu-submenu-container {
|
|
||||||
background-color: #333333;
|
|
||||||
color: whitesmoke;
|
|
||||||
|
|
||||||
.nes-btn.is-error.close {
|
|
||||||
position: absolute;
|
|
||||||
top: -20px;
|
|
||||||
right: -20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
|
||||||
div.menu-container-main {
|
div.menu-container-main {
|
||||||
--size-first-columns-grid: 120px;
|
--size-first-columns-grid: 200px;
|
||||||
height: 70%;
|
|
||||||
top: 55px;
|
|
||||||
width: 100%;
|
|
||||||
font-size: 0.5em;
|
|
||||||
|
|
||||||
div.menu-nav-sidebar {
|
font-family: "Press Start 2P";
|
||||||
overflow-y: auto;
|
pointer-events: auto;
|
||||||
}
|
height: 80%;
|
||||||
|
width: 75%;
|
||||||
|
top: 10%;
|
||||||
|
|
||||||
div.menu-submenu-container {
|
position: relative;
|
||||||
.nes-btn.is-error.close {
|
z-index: 80;
|
||||||
position: absolute;
|
margin: auto;
|
||||||
top: -35px;
|
|
||||||
right: 0;
|
display: grid;
|
||||||
|
grid-template-columns: var(--size-first-columns-grid) calc(100% - var(--size-first-columns-grid));
|
||||||
|
grid-template-rows: 100%;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu-nav-sidebar {
|
||||||
|
background-color: #333333;
|
||||||
|
color: whitesmoke;
|
||||||
|
|
||||||
|
nav button {
|
||||||
|
width: calc(100% - 10px);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu-submenu-container {
|
||||||
|
background-color: #333333;
|
||||||
|
color: whitesmoke;
|
||||||
|
|
||||||
|
.nes-btn.is-error.close {
|
||||||
|
position: absolute;
|
||||||
|
top: -20px;
|
||||||
|
right: -20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px) {
|
||||||
|
div.menu-container-main {
|
||||||
|
--size-first-columns-grid: 120px;
|
||||||
|
height: 70%;
|
||||||
|
top: 55px;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.5em;
|
||||||
|
|
||||||
|
div.menu-nav-sidebar {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.menu-submenu-container {
|
||||||
|
.nes-btn.is-error.close {
|
||||||
|
position: absolute;
|
||||||
|
top: -35px;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -1,26 +1,26 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import logoWA from "../images/menu.svg"
|
import logoWA from "../images/menu.svg"
|
||||||
import logoTalk from "../images/chat.svg"
|
import logoTalk from "../images/chat.svg"
|
||||||
import {menuVisiblilityStore} from "../../Stores/MenuStore";
|
import { menuVisiblilityStore } from "../../Stores/MenuStore";
|
||||||
import {chatVisibilityStore} from "../../Stores/ChatStore";
|
import { chatVisibilityStore } from "../../Stores/ChatStore";
|
||||||
import {get} from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
function showMenu(){
|
function showMenu() {
|
||||||
menuVisiblilityStore.set(!get(menuVisiblilityStore))
|
menuVisiblilityStore.set(!get(menuVisiblilityStore));
|
||||||
}
|
}
|
||||||
function showChat(){
|
function showChat() {
|
||||||
chatVisibilityStore.set(true);
|
chatVisibilityStore.set(true);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window/>
|
<svelte:window />
|
||||||
|
|
||||||
<main class="menuIcon">
|
<main class="menuIcon">
|
||||||
<span class=" nes-btn is-dark">
|
<span class="nes-btn is-dark">
|
||||||
<img src={logoWA} alt="open menu" on:click|preventDefault={showMenu}>
|
<img src={logoWA} alt="open menu" on:click|preventDefault={showMenu} />
|
||||||
</span>
|
</span>
|
||||||
<span class=" nes-btn is-dark">
|
<span class="nes-btn is-dark">
|
||||||
<img src={logoTalk} alt="open menu" on:click|preventDefault={showChat}>
|
<img src={logoTalk} alt="open menu" on:click|preventDefault={showChat} />
|
||||||
</span>
|
</span>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
@ -37,6 +37,7 @@
|
|||||||
margin: 3px
|
margin: 3px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuIcon img:hover{
|
.menuIcon img:hover{
|
||||||
transform: scale(1.2);
|
transform: scale(1.2);
|
||||||
}
|
}
|
||||||
|
@ -1,60 +1,59 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import {gameManager} from "../../Phaser/Game/GameManager";
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
import {SelectCompanionScene, SelectCompanionSceneName} from "../../Phaser/Login/SelectCompanionScene";
|
import { SelectCompanionScene, SelectCompanionSceneName } from "../../Phaser/Login/SelectCompanionScene";
|
||||||
import {menuIconVisiblilityStore, menuVisiblilityStore, userIsConnected} from "../../Stores/MenuStore";
|
import { menuIconVisiblilityStore, menuVisiblilityStore, userIsConnected } from "../../Stores/MenuStore";
|
||||||
import {selectCompanionSceneVisibleStore} from "../../Stores/SelectCompanionStore";
|
import { selectCompanionSceneVisibleStore } from "../../Stores/SelectCompanionStore";
|
||||||
import {LoginScene, LoginSceneName} from "../../Phaser/Login/LoginScene";
|
import { LoginScene, LoginSceneName } from "../../Phaser/Login/LoginScene";
|
||||||
import {loginSceneVisibleStore} from "../../Stores/LoginSceneStore";
|
import { loginSceneVisibleStore } from "../../Stores/LoginSceneStore";
|
||||||
import {selectCharacterSceneVisibleStore} from "../../Stores/SelectCharacterStore";
|
import { selectCharacterSceneVisibleStore } from "../../Stores/SelectCharacterStore";
|
||||||
import {SelectCharacterScene, SelectCharacterSceneName} from "../../Phaser/Login/SelectCharacterScene";
|
import { SelectCharacterScene, SelectCharacterSceneName } from "../../Phaser/Login/SelectCharacterScene";
|
||||||
import {connectionManager} from "../../Connexion/ConnectionManager";
|
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||||
import {PROFILE_URL} from "../../Enum/EnvironmentVariable";
|
import { PROFILE_URL } from "../../Enum/EnvironmentVariable";
|
||||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||||
import {EnableCameraScene, EnableCameraSceneName} from "../../Phaser/Login/EnableCameraScene";
|
import { EnableCameraScene, EnableCameraSceneName } from "../../Phaser/Login/EnableCameraScene";
|
||||||
import {enableCameraSceneVisibilityStore} from "../../Stores/MediaStore";
|
import { enableCameraSceneVisibilityStore } from "../../Stores/MediaStore";
|
||||||
import btnProfileSubMenuCamera from "../images/btn-menu-profile-camera.svg";
|
import btnProfileSubMenuCamera from "../images/btn-menu-profile-camera.svg";
|
||||||
import btnProfileSubMenuIdentity from "../images/btn-menu-profile-identity.svg";
|
import btnProfileSubMenuIdentity from "../images/btn-menu-profile-identity.svg";
|
||||||
import btnProfileSubMenuCompanion from "../images/btn-menu-profile-companion.svg";
|
import btnProfileSubMenuCompanion from "../images/btn-menu-profile-companion.svg";
|
||||||
import btnProfileSubMenuWoka from "../images/btn-menu-profile-woka.svg";
|
import btnProfileSubMenuWoka from "../images/btn-menu-profile-woka.svg";
|
||||||
|
|
||||||
|
function disableMenuStores() {
|
||||||
function disableMenuStores(){
|
|
||||||
menuVisiblilityStore.set(false);
|
menuVisiblilityStore.set(false);
|
||||||
menuIconVisiblilityStore.set(false);
|
menuIconVisiblilityStore.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEditCompanionScene(){
|
function openEditCompanionScene() {
|
||||||
disableMenuStores();
|
disableMenuStores();
|
||||||
selectCompanionSceneVisibleStore.set(true);
|
selectCompanionSceneVisibleStore.set(true);
|
||||||
gameManager.leaveGame(SelectCompanionSceneName,new SelectCompanionScene());
|
gameManager.leaveGame(SelectCompanionSceneName, new SelectCompanionScene());
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEditNameScene(){
|
function openEditNameScene() {
|
||||||
disableMenuStores();
|
disableMenuStores();
|
||||||
loginSceneVisibleStore.set(true);
|
loginSceneVisibleStore.set(true);
|
||||||
gameManager.leaveGame(LoginSceneName,new LoginScene());
|
gameManager.leaveGame(LoginSceneName, new LoginScene());
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEditSkinScene(){
|
function openEditSkinScene() {
|
||||||
disableMenuStores();
|
disableMenuStores();
|
||||||
selectCharacterSceneVisibleStore.set(true);
|
selectCharacterSceneVisibleStore.set(true);
|
||||||
gameManager.leaveGame(SelectCharacterSceneName,new SelectCharacterScene());
|
gameManager.leaveGame(SelectCharacterSceneName, new SelectCharacterScene());
|
||||||
}
|
}
|
||||||
|
|
||||||
function logOut(){
|
function logOut() {
|
||||||
disableMenuStores();
|
disableMenuStores();
|
||||||
loginSceneVisibleStore.set(true);
|
loginSceneVisibleStore.set(true);
|
||||||
connectionManager.logout();
|
connectionManager.logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProfileUrl(){
|
function getProfileUrl() {
|
||||||
return PROFILE_URL + `?token=${localUserStore.getAuthToken()}`;
|
return PROFILE_URL + `?token=${localUserStore.getAuthToken()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEnableCameraScene(){
|
function openEnableCameraScene() {
|
||||||
disableMenuStores();
|
disableMenuStores();
|
||||||
enableCameraSceneVisibilityStore.showEnableCameraScene();
|
enableCameraSceneVisibilityStore.showEnableCameraScene();
|
||||||
gameManager.leaveGame(EnableCameraSceneName,new EnableCameraScene());
|
gameManager.leaveGame(EnableCameraSceneName, new EnableCameraScene());
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -63,20 +62,20 @@
|
|||||||
<section>
|
<section>
|
||||||
<!--
|
<!--
|
||||||
<button type="button" class="nes-btn" on:click|preventDefault={openEditNameScene}>
|
<button type="button" class="nes-btn" on:click|preventDefault={openEditNameScene}>
|
||||||
<img src={btnProfileSubMenuIdentity} alt="Edit your name">
|
<img src={btnProfileSubMenuIdentity} alt="Edit your name" />
|
||||||
<span class="btn-hover">Edit your name</span>
|
<span class="btn-hover">Edit your name</span>
|
||||||
</button>
|
</button>
|
||||||
-->
|
-->
|
||||||
<button type="button" class="nes-btn" on:click|preventDefault={openEditSkinScene}>
|
<button type="button" class="nes-btn" on:click|preventDefault={openEditSkinScene}>
|
||||||
<img src={btnProfileSubMenuWoka} alt="Edit your Avatar">
|
<img src={btnProfileSubMenuWoka} alt="Edit your WOKA" />
|
||||||
<span class="btn-hover">Edit your Avatar</span>
|
<span class="btn-hover">Edit your Avatar</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="nes-btn" on:click|preventDefault={openEditCompanionScene}>
|
<button type="button" class="nes-btn" on:click|preventDefault={openEditCompanionScene}>
|
||||||
<img src={btnProfileSubMenuCompanion} alt="Change your companion">
|
<img src={btnProfileSubMenuCompanion} alt="Edit your companion" />
|
||||||
<span class="btn-hover">Change your companion</span>
|
<span class="btn-hover">Change your companion</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="nes-btn" on:click|preventDefault={openEnableCameraScene}>
|
<button type="button" class="nes-btn" on:click|preventDefault={openEnableCameraScene}>
|
||||||
<img src={btnProfileSubMenuCamera} alt="Edit your camera">
|
<img src={btnProfileSubMenuCamera} alt="Edit your camera" />
|
||||||
<span class="btn-hover">Edit your camera</span>
|
<span class="btn-hover">Edit your camera</span>
|
||||||
</button>
|
</button>
|
||||||
</section>
|
</section>
|
||||||
@ -86,7 +85,7 @@
|
|||||||
{#if $userIsConnected}
|
{#if $userIsConnected}
|
||||||
<section>
|
<section>
|
||||||
{#if PROFILE_URL != undefined}
|
{#if PROFILE_URL != undefined}
|
||||||
<iframe title="profile" src="{getProfileUrl()}"></iframe>
|
<iframe title="profile" src={getProfileUrl()} />
|
||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
@ -101,68 +100,68 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.customize-main{
|
div.customize-main {
|
||||||
width: 100%;
|
|
||||||
display: inline-flex;
|
|
||||||
|
|
||||||
div.submenu{
|
|
||||||
height: 100%;
|
|
||||||
width: 50px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
transition: all .5s ease;
|
|
||||||
text-align: left;
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
max-height: 44px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
height: 26px;
|
|
||||||
width: 26px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.btn-hover{
|
|
||||||
display: none;
|
|
||||||
font-family: "Press Start 2P";
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover{
|
|
||||||
width: auto;
|
|
||||||
|
|
||||||
span.btn-hover {
|
|
||||||
display: initial;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div.content {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
section {
|
display: inline-flex;
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
iframe {
|
div.submenu {
|
||||||
width: 100%;
|
height: 100%;
|
||||||
height: 50vh;
|
width: 50px;
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
height: 50px;
|
transition: all 0.5s ease;
|
||||||
width: 250px;
|
text-align: left;
|
||||||
}
|
white-space: nowrap;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
max-height: 44px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 26px;
|
||||||
|
width: 26px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.btn-hover {
|
||||||
|
display: none;
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
span.btn-hover {
|
||||||
|
display: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content {
|
||||||
|
width: 100%;
|
||||||
|
section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 50vh;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 50px;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
@media only screen and (max-width: 800px) {
|
||||||
div.customize-main.content section button {
|
div.customize-main.content section button {
|
||||||
width: 130px;
|
width: 130px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,62 +1,62 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||||
import {videoConstraintStore} from "../../Stores/MediaStore";
|
import { videoConstraintStore } from "../../Stores/MediaStore";
|
||||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||||
import {isMobile} from "../../Enum/EnvironmentVariable";
|
import { isMobile } from "../../Enum/EnvironmentVariable";
|
||||||
import {menuVisiblilityStore} from "../../Stores/MenuStore";
|
import { menuVisiblilityStore } from "../../Stores/MenuStore";
|
||||||
|
|
||||||
let fullscreen : boolean = localUserStore.getFullscreen();
|
let fullscreen: boolean = localUserStore.getFullscreen();
|
||||||
let notification : boolean = localUserStore.getNotification() === 'granted';
|
let notification: boolean = localUserStore.getNotification() === "granted";
|
||||||
let valueGame : number = localUserStore.getGameQualityValue();
|
let valueGame: number = localUserStore.getGameQualityValue();
|
||||||
let valueVideo : number = localUserStore.getVideoQualityValue();
|
let valueVideo: number = localUserStore.getVideoQualityValue();
|
||||||
let previewValueGame = valueGame;
|
let previewValueGame = valueGame;
|
||||||
let previewValueVideo = valueVideo;
|
let previewValueVideo = valueVideo;
|
||||||
|
|
||||||
function saveSetting(){
|
function saveSetting() {
|
||||||
if (valueGame !== previewValueGame) {
|
if (valueGame !== previewValueGame) {
|
||||||
previewValueGame = valueGame;
|
previewValueGame = valueGame;
|
||||||
localUserStore.setGameQualityValue(valueGame);
|
localUserStore.setGameQualityValue(valueGame);
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
|
||||||
|
|
||||||
if (valueVideo !== previewValueVideo) {
|
|
||||||
previewValueVideo = valueVideo;
|
|
||||||
videoConstraintStore.setFrameRate(valueVideo);
|
|
||||||
}
|
|
||||||
|
|
||||||
closeMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeFullscreen() {
|
|
||||||
const body = HtmlUtils.querySelectorOrFail('body');
|
|
||||||
if (body) {
|
|
||||||
if (document.fullscreenElement !== null && !fullscreen) {
|
|
||||||
document.exitFullscreen()
|
|
||||||
} else {
|
|
||||||
body.requestFullscreen();
|
|
||||||
}
|
}
|
||||||
localUserStore.setFullscreen(fullscreen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeNotification() {
|
if (valueVideo !== previewValueVideo) {
|
||||||
if (Notification.permission === 'granted') {
|
previewValueVideo = valueVideo;
|
||||||
localUserStore.setNotification(notification ? 'granted' : 'denied');
|
videoConstraintStore.setFrameRate(valueVideo);
|
||||||
} else {
|
}
|
||||||
Notification.requestPermission().then((response) => {
|
|
||||||
if (response === 'granted') {
|
closeMenu();
|
||||||
localUserStore.setNotification(notification ? 'granted' : 'denied');
|
}
|
||||||
|
|
||||||
|
function changeFullscreen() {
|
||||||
|
const body = HtmlUtils.querySelectorOrFail("body");
|
||||||
|
if (body) {
|
||||||
|
if (document.fullscreenElement !== null && !fullscreen) {
|
||||||
|
document.exitFullscreen();
|
||||||
} else {
|
} else {
|
||||||
localUserStore.setNotification('denied');
|
body.requestFullscreen();
|
||||||
notification = false;
|
|
||||||
}
|
}
|
||||||
})
|
localUserStore.setFullscreen(fullscreen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function closeMenu() {
|
function changeNotification() {
|
||||||
menuVisiblilityStore.set(false);
|
if (Notification.permission === "granted") {
|
||||||
}
|
localUserStore.setNotification(notification ? "granted" : "denied");
|
||||||
|
} else {
|
||||||
|
Notification.requestPermission().then((response) => {
|
||||||
|
if (response === "granted") {
|
||||||
|
localUserStore.setNotification(notification ? "granted" : "denied");
|
||||||
|
} else {
|
||||||
|
localUserStore.setNotification("denied");
|
||||||
|
notification = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeMenu() {
|
||||||
|
menuVisiblilityStore.set(false);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="settings-main" on:submit|preventDefault={saveSetting}>
|
<div class="settings-main" on:submit|preventDefault={saveSetting}>
|
||||||
@ -64,10 +64,12 @@ function closeMenu() {
|
|||||||
<h3>Game quality</h3>
|
<h3>Game quality</h3>
|
||||||
<div class="nes-select is-dark">
|
<div class="nes-select is-dark">
|
||||||
<select bind:value={valueGame}>
|
<select bind:value={valueGame}>
|
||||||
<option value="{120}">{isMobile() ? 'High (120 fps)' : 'High video quality (120 fps)'}</option>
|
<option value={120}>{isMobile() ? "High (120 fps)" : "High video quality (120 fps)"}</option>
|
||||||
<option value="{60}">{isMobile() ? 'Medium (60 fps)' : 'Medium video quality (60 fps, recommended)'}</option>
|
<option value={60}
|
||||||
<option value="{40}">{isMobile() ? 'Minimum (40 fps)' : 'Minimum video quality (40 fps)'}</option>
|
>{isMobile() ? "Medium (60 fps)" : "Medium video quality (60 fps, recommended)"}</option
|
||||||
<option value="{20}">{isMobile() ? 'Small (20 fps)' : 'Small video quality (20 fps)'}</option>
|
>
|
||||||
|
<option value={40}>{isMobile() ? "Minimum (40 fps)" : "Minimum video quality (40 fps)"}</option>
|
||||||
|
<option value={20}>{isMobile() ? "Small (20 fps)" : "Small video quality (20 fps)"}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -75,10 +77,12 @@ function closeMenu() {
|
|||||||
<h3>Video quality</h3>
|
<h3>Video quality</h3>
|
||||||
<div class="nes-select is-dark">
|
<div class="nes-select is-dark">
|
||||||
<select bind:value={valueVideo}>
|
<select bind:value={valueVideo}>
|
||||||
<option value="{30}">{isMobile() ? 'High (30 fps)' : 'High video quality (30 fps)'}</option>
|
<option value={30}>{isMobile() ? "High (30 fps)" : "High video quality (30 fps)"}</option>
|
||||||
<option value="{20}">{isMobile() ? 'Medium (20 fps)' : 'Medium video quality (20 fps, recommended)'}</option>
|
<option value={20}
|
||||||
<option value="{10}">{isMobile() ? 'Minimum (10 fps)' : 'Minimum video quality (10 fps)'}</option>
|
>{isMobile() ? "Medium (20 fps)" : "Medium video quality (20 fps, recommended)"}</option
|
||||||
<option value="{5}">{isMobile() ? 'Small (5 fps)' : 'Small video quality (5 fps)'}</option>
|
>
|
||||||
|
<option value={10}>{isMobile() ? "Minimum (10 fps)" : "Minimum video quality (10 fps)"}</option>
|
||||||
|
<option value={5}>{isMobile() ? "Small (5 fps)" : "Small video quality (5 fps)"}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -88,55 +92,65 @@ function closeMenu() {
|
|||||||
</section>
|
</section>
|
||||||
<section class="settings-section-noSaveOption">
|
<section class="settings-section-noSaveOption">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" class="nes-checkbox is-dark" bind:checked={fullscreen} on:change={changeFullscreen}/>
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="nes-checkbox is-dark"
|
||||||
|
bind:checked={fullscreen}
|
||||||
|
on:change={changeFullscreen}
|
||||||
|
/>
|
||||||
<span>Fullscreen</span>
|
<span>Fullscreen</span>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" class="nes-checkbox is-dark" bind:checked={notification} on:change={changeNotification}>
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="nes-checkbox is-dark"
|
||||||
|
bind:checked={notification}
|
||||||
|
on:change={changeNotification}
|
||||||
|
/>
|
||||||
<span>Notifications</span>
|
<span>Notifications</span>
|
||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.settings-main {
|
|
||||||
height: calc(100% - 40px);
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
section {
|
|
||||||
width: 100%;
|
|
||||||
padding: 20px 20px 0;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
div.nes-select select:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
section.settings-section-save {
|
|
||||||
text-align: center;
|
|
||||||
p {
|
|
||||||
margin: 16px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
section.settings-section-noSaveOption {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
label {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
text-align: center;
|
|
||||||
margin: 0 0 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
|
||||||
div.settings-main {
|
div.settings-main {
|
||||||
section {
|
height: calc(100% - 40px);
|
||||||
padding: 0;
|
overflow-y: auto;
|
||||||
}
|
|
||||||
|
section {
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px 20px 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
div.nes-select select:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
section.settings-section-save {
|
||||||
|
text-align: center;
|
||||||
|
p {
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
section.settings-section-noSaveOption {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
label {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 0 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px), only screen and (max-height: 800px) {
|
||||||
|
div.settings-main {
|
||||||
|
section {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -8,25 +8,25 @@
|
|||||||
|
|
||||||
//toolbar
|
//toolbar
|
||||||
const toolbarOptions = [
|
const toolbarOptions = [
|
||||||
['bold', 'italic', 'underline', 'strike'], // toggled buttons
|
["bold", "italic", "underline", "strike"], // toggled buttons
|
||||||
['blockquote', 'code-block'],
|
["blockquote", "code-block"],
|
||||||
|
|
||||||
[{'header': 1}, {'header': 2}], // custom button values
|
[{ header: 1 }, { header: 2 }], // custom button values
|
||||||
[{'list': 'ordered'}, {'list': 'bullet'}],
|
[{ list: "ordered" }, { list: "bullet" }],
|
||||||
[{'script': 'sub'}, {'script': 'super'}], // superscript/subscript
|
[{ script: "sub" }, { script: "super" }], // superscript/subscript
|
||||||
[{'indent': '-1'}, {'indent': '+1'}], // outdent/indent
|
[{ indent: "-1" }, { indent: "+1" }], // outdent/indent
|
||||||
[{'direction': 'rtl'}], // text direction
|
[{ direction: "rtl" }], // text direction
|
||||||
|
|
||||||
[{'size': ['small', false, 'large', 'huge']}], // custom dropdown
|
[{ size: ["small", false, "large", "huge"] }], // custom dropdown
|
||||||
[{'header': [1, 2, 3, 4, 5, 6, false]}],
|
[{ header: [1, 2, 3, 4, 5, 6, false] }],
|
||||||
|
|
||||||
[{'color': []}, {'background': []}], // dropdown with defaults from theme
|
[{ color: [] }, { background: [] }], // dropdown with defaults from theme
|
||||||
[{'font': []}],
|
[{ font: [] }],
|
||||||
[{'align': []}],
|
[{ align: [] }],
|
||||||
|
|
||||||
['clean'], // remove formatting button
|
["clean"], // remove formatting button
|
||||||
|
|
||||||
['link', 'image', 'video']
|
["link", "image", "video"],
|
||||||
];
|
];
|
||||||
|
|
||||||
const gameScene = gameManager.getCurrentGameScene();
|
const gameScene = gameManager.getCurrentGameScene();
|
||||||
@ -44,24 +44,24 @@
|
|||||||
const textGlobalMessage: PlayGlobalMessageInterface = {
|
const textGlobalMessage: PlayGlobalMessageInterface = {
|
||||||
type: MESSAGE_TYPE,
|
type: MESSAGE_TYPE,
|
||||||
content: text,
|
content: text,
|
||||||
broadcastToWorld: broadcastToWorld
|
broadcastToWorld: broadcastToWorld,
|
||||||
};
|
};
|
||||||
|
|
||||||
quill.deleteText(0, quill.getLength());
|
quill.deleteText(0, quill.getLength());
|
||||||
gameScene.connection?.emitGlobalMessage(textGlobalMessage);
|
gameScene.connection?.emitGlobalMessage(textGlobalMessage);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
//Quill
|
//Quill
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
// Import quill
|
// Import quill
|
||||||
const {default: Quill} = await import("quill"); // eslint-disable-line @typescript-eslint/no-explicit-any
|
const { default: Quill } = await import("quill"); // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
|
||||||
quill = new Quill(QUILL_EDITOR, {
|
quill = new Quill(QUILL_EDITOR, {
|
||||||
placeholder: 'Enter your message here...',
|
placeholder: "Enter your message here...",
|
||||||
theme: 'snow',
|
theme: "snow",
|
||||||
modules: {
|
modules: {
|
||||||
toolbar: toolbarOptions
|
toolbar: toolbarOptions,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
menuInputFocusStore.set(true);
|
menuInputFocusStore.set(true);
|
||||||
@ -69,9 +69,9 @@
|
|||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
menuInputFocusStore.set(false);
|
menuInputFocusStore.set(false);
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="section-input-send-text">
|
<section class="section-input-send-text">
|
||||||
<div class="input-send-text" bind:this={QUILL_EDITOR}></div>
|
<div class="input-send-text" bind:this={QUILL_EDITOR} />
|
||||||
</section>
|
</section>
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import {obtainedMediaConstraintStore} from "../Stores/MediaStore";
|
import { obtainedMediaConstraintStore } from "../Stores/MediaStore";
|
||||||
import {localStreamStore, isSilentStore} from "../Stores/MediaStore";
|
import { localStreamStore, isSilentStore } from "../Stores/MediaStore";
|
||||||
import SoundMeterWidget from "./SoundMeterWidget.svelte";
|
import SoundMeterWidget from "./SoundMeterWidget.svelte";
|
||||||
import {onDestroy} from "svelte";
|
import { onDestroy } from "svelte";
|
||||||
import {srcObject} from "./Video/utils";
|
import { srcObject } from "./Video/utils";
|
||||||
|
|
||||||
let stream : MediaStream|null;
|
let stream: MediaStream | null;
|
||||||
|
|
||||||
const unsubscribe = localStreamStore.subscribe(value => {
|
const unsubscribe = localStreamStore.subscribe((value) => {
|
||||||
if (value.type === 'success') {
|
if (value.type === "success") {
|
||||||
stream = value.stream;
|
stream = value.stream;
|
||||||
} else {
|
} else {
|
||||||
stream = null;
|
stream = null;
|
||||||
@ -17,26 +17,21 @@
|
|||||||
|
|
||||||
onDestroy(unsubscribe);
|
onDestroy(unsubscribe);
|
||||||
|
|
||||||
|
|
||||||
let isSilent: boolean;
|
let isSilent: boolean;
|
||||||
const unsubscribeIsSilent = isSilentStore.subscribe(value => {
|
const unsubscribeIsSilent = isSilentStore.subscribe((value) => {
|
||||||
isSilent = value;
|
isSilent = value;
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(unsubscribeIsSilent);
|
onDestroy(unsubscribeIsSilent);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="video-container nes-container is-rounded is-dark div-myCamVideo"
|
<div class="video-container nes-container is-rounded is-dark div-myCamVideo"
|
||||||
class:hide={!$obtainedMediaConstraintStore.video || isSilent}>
|
class:hide={!$obtainedMediaConstraintStore.video || isSilent}>
|
||||||
{#if $localStreamStore.type === "success" && $localStreamStore.stream}
|
{#if $localStreamStore.type === "success" && $localStreamStore.stream}
|
||||||
<video class="myCamVideo" use:srcObject={stream} autoplay muted playsinline></video>
|
<video class="myCamVideo" use:srcObject={stream} autoplay muted playsinline />
|
||||||
<SoundMeterWidget stream={stream}></SoundMeterWidget>
|
<SoundMeterWidget {stream} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="is-silent" class:hide={isSilent}>
|
<div class="is-silent" class:hide={isSilent}>Silent zone</div>
|
||||||
Silent zone
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {blackListManager} from "../../WebRtc/BlackListManager";
|
import { blackListManager } from "../../WebRtc/BlackListManager";
|
||||||
import {showReportScreenStore, userReportEmpty} from "../../Stores/ShowReportScreenStore";
|
import { showReportScreenStore, userReportEmpty } from "../../Stores/ShowReportScreenStore";
|
||||||
import {onMount} from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
export let userUUID: string | undefined;
|
export let userUUID: string | undefined;
|
||||||
export let userName: string;
|
export let userName: string;
|
||||||
@ -14,7 +14,7 @@
|
|||||||
} else {
|
} else {
|
||||||
userIsBlocked = blackListManager.isBlackListed(userUUID);
|
userIsBlocked = blackListManager.isBlackListed(userUUID);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
function blockUser(): void {
|
function blockUser(): void {
|
||||||
if (userUUID === undefined) {
|
if (userUUID === undefined) {
|
||||||
@ -32,13 +32,12 @@
|
|||||||
<h3>Block</h3>
|
<h3>Block</h3>
|
||||||
<p>Block any communication from and to {userName}. This can be reverted.</p>
|
<p>Block any communication from and to {userName}. This can be reverted.</p>
|
||||||
<button type="button" class="nes-btn is-error" on:click|preventDefault={blockUser}>
|
<button type="button" class="nes-btn is-error" on:click|preventDefault={blockUser}>
|
||||||
{userIsBlocked ? 'Unblock this user' : 'Block this user'}
|
{userIsBlocked ? "Unblock this user" : "Block this user"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.block-container {
|
div.block-container {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,20 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {showReportScreenStore, userReportEmpty} from "../../Stores/ShowReportScreenStore";
|
import { showReportScreenStore, userReportEmpty } from "../../Stores/ShowReportScreenStore";
|
||||||
import BlockSubMenu from "./BlockSubMenu.svelte";
|
import BlockSubMenu from "./BlockSubMenu.svelte";
|
||||||
import ReportSubMenu from "./ReportSubMenu.svelte";
|
import ReportSubMenu from "./ReportSubMenu.svelte";
|
||||||
import {onDestroy, onMount} from "svelte";
|
import { onDestroy, onMount } from "svelte";
|
||||||
import type {Unsubscriber} from "svelte/store";
|
import type { Unsubscriber } from "svelte/store";
|
||||||
import {playersStore} from "../../Stores/PlayersStore";
|
import { playersStore } from "../../Stores/PlayersStore";
|
||||||
import {connectionManager} from "../../Connexion/ConnectionManager";
|
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||||
import {GameConnexionTypes} from "../../Url/UrlManager";
|
import { GameConnexionTypes } from "../../Url/UrlManager";
|
||||||
import {get} from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
let blockActive = true;
|
let blockActive = true;
|
||||||
let reportActive = !blockActive;
|
let reportActive = !blockActive;
|
||||||
let anonymous: boolean = false;
|
let anonymous: boolean = false;
|
||||||
let userUUID: string | undefined = playersStore.getPlayerById(get(showReportScreenStore).userId)?.userUuid;
|
let userUUID: string | undefined = playersStore.getPlayerById(get(showReportScreenStore).userId)?.userUuid;
|
||||||
let userName = "No name";
|
let userName = "No name";
|
||||||
let unsubscriber: Unsubscriber
|
let unsubscriber: Unsubscriber;
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
unsubscriber = showReportScreenStore.subscribe((reportScreenStore) => {
|
unsubscriber = showReportScreenStore.subscribe((reportScreenStore) => {
|
||||||
@ -25,15 +25,15 @@
|
|||||||
console.error("Could not find UUID for user with ID " + reportScreenStore.userId);
|
console.error("Could not find UUID for user with ID " + reportScreenStore.userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
anonymous = connectionManager.getConnexionType === GameConnexionTypes.anonymous;
|
anonymous = connectionManager.getConnexionType === GameConnexionTypes.anonymous;
|
||||||
})
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
if (unsubscriber) {
|
if (unsubscriber) {
|
||||||
unsubscriber();
|
unsubscriber();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
showReportScreenStore.set(userReportEmpty);
|
showReportScreenStore.set(userReportEmpty);
|
||||||
@ -49,14 +49,14 @@
|
|||||||
reportActive = true;
|
reportActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onKeyDown(e:KeyboardEvent) {
|
function onKeyDown(e: KeyboardEvent) {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === "Escape") {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:keydown={onKeyDown}/>
|
<svelte:window on:keydown={onKeyDown} />
|
||||||
|
|
||||||
<div class="report-menu-main nes-container is-rounded">
|
<div class="report-menu-main nes-container is-rounded">
|
||||||
<section class="report-menu-title">
|
<section class="report-menu-title">
|
||||||
@ -67,75 +67,83 @@
|
|||||||
</section>
|
</section>
|
||||||
<section class="report-menu-action {anonymous ? 'hidden' : ''}">
|
<section class="report-menu-action {anonymous ? 'hidden' : ''}">
|
||||||
<section class="justify-center">
|
<section class="justify-center">
|
||||||
<button type="button" class="nes-btn {blockActive ? 'is-disabled' : ''}" on:click|preventDefault={activateBlock}>Block</button>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="nes-btn {blockActive ? 'is-disabled' : ''}"
|
||||||
|
on:click|preventDefault={activateBlock}>Block</button
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
<section class="justify-center">
|
<section class="justify-center">
|
||||||
<button type="button" class="nes-btn {reportActive ? 'is-disabled' : ''}" on:click|preventDefault={activateReport}>Report</button>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="nes-btn {reportActive ? 'is-disabled' : ''}"
|
||||||
|
on:click|preventDefault={activateReport}>Report</button
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section class="report-menu-content">
|
<section class="report-menu-content">
|
||||||
{#if blockActive}
|
{#if blockActive}
|
||||||
<BlockSubMenu userUUID="{userUUID}" userName="{userName}"/>
|
<BlockSubMenu {userUUID} {userName} />
|
||||||
{:else if reportActive}
|
{:else if reportActive}
|
||||||
<ReportSubMenu userUUID="{userUUID}"/>
|
<ReportSubMenu {userUUID} />
|
||||||
{:else }
|
{:else}
|
||||||
<p>ERROR : There is no action selected.</p>
|
<p>ERROR : There is no action selected.</p>
|
||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.nes-container {
|
.nes-container {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
section.justify-center {
|
section.justify-center {
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.report-menu-main {
|
|
||||||
font-family: "Press Start 2P";
|
|
||||||
pointer-events: auto;
|
|
||||||
background-color: #333333;
|
|
||||||
color: whitesmoke;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
height: 70vh;
|
|
||||||
width: 50vw;
|
|
||||||
top: 10vh;
|
|
||||||
margin: auto;
|
|
||||||
|
|
||||||
section.report-menu-title {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: calc(100% - 45px) 40px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
section.report-menu-action {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 50% 50%;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.report-menu-action.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
|
||||||
div.report-menu-main {
|
div.report-menu-main {
|
||||||
top: 21vh;
|
font-family: "Press Start 2P";
|
||||||
height: 60vh;
|
pointer-events: auto;
|
||||||
width: 100vw;
|
background-color: #333333;
|
||||||
font-size: 0.5em;
|
color: whitesmoke;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
height: 70vh;
|
||||||
|
width: 50vw;
|
||||||
|
top: 10vh;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
section.report-menu-title {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: calc(100% - 45px) 40px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section.report-menu-action {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 50% 50%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.report-menu-action.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px) {
|
||||||
|
div.report-menu-main {
|
||||||
|
top: 21vh;
|
||||||
|
height: 60vh;
|
||||||
|
width: 100vw;
|
||||||
|
font-size: 0.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -1,22 +1,22 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {showReportScreenStore, userReportEmpty} from "../../Stores/ShowReportScreenStore";
|
import { showReportScreenStore, userReportEmpty } from "../../Stores/ShowReportScreenStore";
|
||||||
import {gameManager} from "../../Phaser/Game/GameManager";
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
|
|
||||||
export let userUUID: string | undefined;
|
export let userUUID: string | undefined;
|
||||||
let reportMessage: string;
|
let reportMessage: string;
|
||||||
let hiddenError = true;
|
let hiddenError = true;
|
||||||
|
|
||||||
function submitReport() {
|
function submitReport() {
|
||||||
if (reportMessage === '') {
|
if (reportMessage === "") {
|
||||||
hiddenError = true;
|
hiddenError = true;
|
||||||
} else {
|
} else {
|
||||||
hiddenError = false;
|
hiddenError = false;
|
||||||
if( userUUID === undefined) {
|
if (userUUID === undefined) {
|
||||||
console.error('User UUID is not valid.');
|
console.error("User UUID is not valid.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gameManager.getCurrentGameScene().connection?.emitReportPlayerMessage(userUUID, reportMessage);
|
gameManager.getCurrentGameScene().connection?.emitReportPlayerMessage(userUUID, reportMessage);
|
||||||
showReportScreenStore.set(userReportEmpty)
|
showReportScreenStore.set(userReportEmpty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -28,9 +28,9 @@
|
|||||||
<section>
|
<section>
|
||||||
<label>
|
<label>
|
||||||
<span>Your message: </span>
|
<span>Your message: </span>
|
||||||
<textarea type="text" class="nes-textarea" bind:value={reportMessage}></textarea>
|
<textarea type="text" class="nes-textarea" bind:value={reportMessage} />
|
||||||
</label>
|
</label>
|
||||||
<p hidden="{hiddenError}">Report message cannot to be empty.</p>
|
<p hidden={hiddenError}>Report message cannot to be empty.</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<button type="submit" class="nes-btn is-error" on:click={submitReport}>Report this user</button>
|
<button type="submit" class="nes-btn is-error" on:click={submitReport}>Report this user</button>
|
||||||
@ -40,16 +40,16 @@
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.report-container-main {
|
div.report-container-main {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
height: clamp(100px, 15vh, 300px);
|
height: clamp(100px, 15vh, 300px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-height: 630px) {
|
@media only screen and (max-height: 630px) {
|
||||||
div.report-container-main textarea {
|
div.report-container-main textarea {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type {Game} from "../../Phaser/Game/Game";
|
import type { Game } from "../../Phaser/Game/Game";
|
||||||
import {SelectCompanionScene, SelectCompanionSceneName} from "../../Phaser/Login/SelectCompanionScene";
|
import { SelectCompanionScene, SelectCompanionSceneName } from "../../Phaser/Login/SelectCompanionScene";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
|
|
||||||
@ -26,62 +26,70 @@
|
|||||||
<form class="selectCompanionScene">
|
<form class="selectCompanionScene">
|
||||||
<section class="text-center">
|
<section class="text-center">
|
||||||
<h2>Select your companion</h2>
|
<h2>Select your companion</h2>
|
||||||
<button class="selectCharacterButton selectCharacterButtonLeft nes-btn" on:click|preventDefault={selectLeft}> < </button>
|
<button class="selectCharacterButton selectCharacterButtonLeft nes-btn" on:click|preventDefault={selectLeft}>
|
||||||
<button class="selectCharacterButton selectCharacterButtonRight nes-btn" on:click|preventDefault={selectRight}> > </button>
|
<
|
||||||
|
</button>
|
||||||
|
<button class="selectCharacterButton selectCharacterButtonRight nes-btn" on:click|preventDefault={selectRight}>
|
||||||
|
>
|
||||||
|
</button>
|
||||||
</section>
|
</section>
|
||||||
<section class="action">
|
<section class="action">
|
||||||
<button href="/" class="selectCompanionSceneFormBack nes-btn" on:click|preventDefault={noCompanion}>No companion</button>
|
<button href="/" class="selectCompanionSceneFormBack nes-btn" on:click|preventDefault={noCompanion}
|
||||||
<button type="submit" class="selectCompanionSceneFormSubmit nes-btn is-primary" on:click|preventDefault={selectCompanion}>Continue</button>
|
>No companion</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="selectCompanionSceneFormSubmit nes-btn is-primary"
|
||||||
|
on:click|preventDefault={selectCompanion}>Continue</button
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
form.selectCompanionScene {
|
form.selectCompanionScene {
|
||||||
font-family: "Press Start 2P";
|
|
||||||
pointer-events: auto;
|
|
||||||
color: #ebeeee;
|
|
||||||
|
|
||||||
section {
|
|
||||||
margin: 10px;
|
|
||||||
|
|
||||||
&.action {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 55vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-family: "Press Start 2P";
|
font-family: "Press Start 2P";
|
||||||
margin: 1px;
|
pointer-events: auto;
|
||||||
}
|
color: #ebeeee;
|
||||||
|
|
||||||
&.text-center {
|
section {
|
||||||
text-align: center;
|
margin: 10px;
|
||||||
}
|
|
||||||
|
|
||||||
button.selectCharacterButton {
|
&.action {
|
||||||
position: absolute;
|
text-align: center;
|
||||||
top: 33vh;
|
margin-top: 55vh;
|
||||||
margin: 0;
|
}
|
||||||
}
|
|
||||||
|
h2 {
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
margin: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.selectCharacterButton {
|
||||||
|
position: absolute;
|
||||||
|
top: 33vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button.selectCharacterButtonLeft {
|
||||||
|
left: 33vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.selectCharacterButtonRight {
|
||||||
|
right: 33vw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.selectCharacterButtonLeft {
|
@media only screen and (max-width: 800px) {
|
||||||
left: 33vw;
|
form.selectCompanionScene button.selectCharacterButtonLeft {
|
||||||
|
left: 5vw;
|
||||||
|
}
|
||||||
|
form.selectCompanionScene button.selectCharacterButtonRight {
|
||||||
|
right: 5vw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.selectCharacterButtonRight {
|
|
||||||
right: 33vw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
|
||||||
form.selectCompanionScene button.selectCharacterButtonLeft{
|
|
||||||
left: 5vw;
|
|
||||||
}
|
|
||||||
form.selectCompanionScene button.selectCharacterButtonRight{
|
|
||||||
right: 5vw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { AudioContext } from 'standardized-audio-context';
|
import { AudioContext } from "standardized-audio-context";
|
||||||
import {SoundMeter} from "../Phaser/Components/SoundMeter";
|
import { SoundMeter } from "../Phaser/Components/SoundMeter";
|
||||||
import {onDestroy} from "svelte";
|
import { onDestroy } from "svelte";
|
||||||
|
|
||||||
export let stream: MediaStream|null;
|
export let stream: MediaStream | null;
|
||||||
let volume = 0;
|
let volume = 0;
|
||||||
|
|
||||||
let timeout: ReturnType<typeof setTimeout>;
|
let timeout: ReturnType<typeof setTimeout>;
|
||||||
const soundMeter = new SoundMeter();
|
const soundMeter = new SoundMeter();
|
||||||
let display = false;
|
let display = false;
|
||||||
|
let error = false;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (stream && stream.getAudioTracks().length > 0) {
|
if (stream && stream.getAudioTracks().length > 0) {
|
||||||
@ -17,17 +18,19 @@
|
|||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
clearInterval(timeout);
|
clearInterval(timeout);
|
||||||
|
error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout = setInterval(() => {
|
timeout = setInterval(() => {
|
||||||
try{
|
try {
|
||||||
volume = soundMeter.getVolume();
|
volume = soundMeter.getVolume();
|
||||||
//console.log(volume);
|
} catch (err) {
|
||||||
}catch(err){
|
if (!error) {
|
||||||
|
console.error(err);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
display = false;
|
display = false;
|
||||||
}
|
}
|
||||||
@ -38,14 +41,13 @@
|
|||||||
if (timeout) {
|
if (timeout) {
|
||||||
clearInterval(timeout);
|
clearInterval(timeout);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div class="sound-progress" class:active={display}>
|
<div class="sound-progress" class:active={display}>
|
||||||
<span class:active={volume > 5}></span>
|
<span class:active={volume > 5} />
|
||||||
<span class:active={volume > 10}></span>
|
<span class:active={volume > 10} />
|
||||||
<span class:active={volume > 15}></span>
|
<span class:active={volume > 15} />
|
||||||
<span class:active={volume > 40}></span>
|
<span class:active={volume > 40} />
|
||||||
<span class:active={volume > 70}></span>
|
<span class:active={volume > 70} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fly } from "svelte/transition";
|
import { fly } from "svelte/transition";
|
||||||
import {banMessageVisibleStore, banMessageContentStore} from "../../Stores/TypeMessageStore/BanMessageStore";
|
import { banMessageVisibleStore, banMessageContentStore } from "../../Stores/TypeMessageStore/BanMessageStore";
|
||||||
import {onMount} from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
const text = $banMessageContentStore;
|
const text = $banMessageContentStore;
|
||||||
const NAME_BUTTON = 'Ok';
|
const NAME_BUTTON = "Ok";
|
||||||
let nbSeconds = 10;
|
let nbSeconds = 10;
|
||||||
let nameButton = '';
|
let nameButton = "";
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
timeToRead()
|
timeToRead();
|
||||||
})
|
});
|
||||||
|
|
||||||
function timeToRead() {
|
function timeToRead() {
|
||||||
nbSeconds -= 1;
|
nbSeconds -= 1;
|
||||||
nameButton = nbSeconds.toString();
|
nameButton = nbSeconds.toString();
|
||||||
if ( nbSeconds > 0 ) {
|
if (nbSeconds > 0) {
|
||||||
setTimeout( () => {
|
setTimeout(() => {
|
||||||
timeToRead();
|
timeToRead();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else {
|
||||||
@ -29,68 +29,76 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="main-ban-message nes-container is-rounded" transition:fly="{{ y: -1000, duration: 500 }}">
|
<div class="main-ban-message nes-container is-rounded" transition:fly={{ y: -1000, duration: 500 }}>
|
||||||
<h2 class="title-ban-message"><img src="resources/logos/report.svg" alt="***"/> Important message <img src="resources/logos/report.svg" alt="***"/></h2>
|
<h2 class="title-ban-message">
|
||||||
|
<img src="resources/logos/report.svg" alt="***" /> Important message
|
||||||
|
<img src="resources/logos/report.svg" alt="***" />
|
||||||
|
</h2>
|
||||||
<div class="content-ban-message">
|
<div class="content-ban-message">
|
||||||
<p>{text}</p>
|
<p>{text}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-ban-message">
|
<div class="footer-ban-message">
|
||||||
<button type="button" class="nes-btn {nameButton === NAME_BUTTON ? 'is-primary' : 'is-error'}" disabled="{!(nameButton === NAME_BUTTON)}" on:click|preventDefault={closeBanMessage}>{nameButton}</button>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="nes-btn {nameButton === NAME_BUTTON ? 'is-primary' : 'is-error'}"
|
||||||
|
disabled={!(nameButton === NAME_BUTTON)}
|
||||||
|
on:click|preventDefault={closeBanMessage}>{nameButton}</button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- svelte-ignore a11y-media-has-caption -->
|
||||||
<audio id="report-message" autoplay>
|
<audio id="report-message" autoplay>
|
||||||
<source src="/resources/objects/report-message.mp3" type="audio/mp3">
|
<source src="/resources/objects/report-message.mp3" type="audio/mp3" />
|
||||||
</audio>
|
</audio>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.main-ban-message {
|
div.main-ban-message {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 15vh;
|
top: 15vh;
|
||||||
|
|
||||||
height: 70vh;
|
height: 70vh;
|
||||||
width: 60vw;
|
width: 60vw;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
|
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
|
|
||||||
h2.title-ban-message {
|
h2.title-ban-message {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
max-height: 50px;
|
max-height: 50px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content-ban-message {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
max-height: calc(100% - 50px);
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
p {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footer-ban-message {
|
||||||
|
height: 50px;
|
||||||
|
margin-top: 10px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 88px;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div.content-ban-message {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
max-height: calc(100% - 50px);
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
p {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div.footer-ban-message {
|
|
||||||
height: 50px;
|
|
||||||
margin-top: 10px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 88px;
|
|
||||||
height: 44px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -1,59 +1,61 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fly } from "svelte/transition";
|
import { fly } from "svelte/transition";
|
||||||
import {textMessageContentStore, textMessageVisibleStore} from "../../Stores/TypeMessageStore/TextMessageStore";
|
import { textMessageContentStore, textMessageVisibleStore } from "../../Stores/TypeMessageStore/TextMessageStore";
|
||||||
import { QuillDeltaToHtmlConverter } from "quill-delta-to-html";
|
import { QuillDeltaToHtmlConverter } from "quill-delta-to-html";
|
||||||
|
|
||||||
const content = JSON.parse($textMessageContentStore);
|
const content = JSON.parse($textMessageContentStore);
|
||||||
const converter = new QuillDeltaToHtmlConverter(content.ops, {inlineStyles: true});
|
const converter = new QuillDeltaToHtmlConverter(content.ops, { inlineStyles: true });
|
||||||
const NAME_BUTTON = 'Ok';
|
const NAME_BUTTON = "Ok";
|
||||||
|
|
||||||
function closeTextMessage() {
|
function closeTextMessage() {
|
||||||
textMessageVisibleStore.set(false);
|
textMessageVisibleStore.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onKeyDown(e:KeyboardEvent) {
|
function onKeyDown(e: KeyboardEvent) {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === "Escape") {
|
||||||
closeTextMessage();
|
closeTextMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:keydown={onKeyDown}/>
|
<svelte:window on:keydown={onKeyDown} />
|
||||||
|
|
||||||
<div class="main-text-message nes-container is-rounded" transition:fly="{{ x: -1000, duration: 500 }}">
|
<div class="main-text-message nes-container is-rounded" transition:fly={{ x: -1000, duration: 500 }}>
|
||||||
<div class="content-text-message">
|
<div class="content-text-message">
|
||||||
{@html converter.convert()}
|
{@html converter.convert()}
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-text-message">
|
<div class="footer-text-message">
|
||||||
<button type="button" class="nes-btn is-primary" on:click|preventDefault={closeTextMessage}>{NAME_BUTTON}</button>
|
<button type="button" class="nes-btn is-primary" on:click|preventDefault={closeTextMessage}
|
||||||
|
>{NAME_BUTTON}</button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.main-text-message {
|
div.main-text-message {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
max-height: 25vh;
|
max-height: 25vh;
|
||||||
width: 80vw;
|
width: 80vw;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
|
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
|
|
||||||
div.content-text-message {
|
div.content-text-message {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
max-height: calc(100% - 50px);
|
max-height: calc(100% - 50px);
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.footer-text-message {
|
div.footer-text-message {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from "svelte/transition";
|
||||||
import megaphoneImg from "./images/megaphone.svg";
|
import megaphoneImg from "./images/megaphone.svg";
|
||||||
import {soundPlayingStore} from "../../Stores/SoundPlayingStore";
|
import { soundPlayingStore } from "../../Stores/SoundPlayingStore";
|
||||||
import {afterUpdate} from "svelte";
|
import { afterUpdate } from "svelte";
|
||||||
|
|
||||||
export let url: string;
|
export let url: string;
|
||||||
let audio: HTMLAudioElement;
|
let audio: HTMLAudioElement;
|
||||||
@ -16,37 +16,37 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="audio-playing" transition:fly="{{ x: 210, duration: 500 }}">
|
<div class="audio-playing" transition:fly={{ x: 210, duration: 500 }}>
|
||||||
<img src={megaphoneImg} alt="Audio playing" />
|
<img src={megaphoneImg} alt="Audio playing" />
|
||||||
<p>Audio message</p>
|
<p>Audio message</p>
|
||||||
<audio bind:this={audio} src={url} on:ended={soundEnded} >
|
<audio bind:this={audio} src={url} on:ended={soundEnded}>
|
||||||
<track kind="captions">
|
<track kind="captions" />
|
||||||
</audio>
|
</audio>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
/*audio html when audio message playing*/
|
/*audio html when audio message playing*/
|
||||||
.audio-playing {
|
.audio-playing {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
height: 54px;
|
height: 54px;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 40px;
|
top: 40px;
|
||||||
transition: all 0.1s ease-out;
|
transition: all 0.1s ease-out;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
border-radius: 30px 0 0 30px;
|
border-radius: 30px 0 0 30px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: #ffda01;
|
background-color: #ffda01;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
color: white;
|
color: white;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
margin-top: 14px;
|
margin-top: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,48 +1,49 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {errorStore} from "../../Stores/ErrorStore";
|
import { errorStore, hasClosableMessagesInErrorStore } from "../../Stores/ErrorStore";
|
||||||
|
|
||||||
function close(): boolean {
|
|
||||||
errorStore.clearMessages();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
function close(): boolean {
|
||||||
|
errorStore.clearClosableMessages();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="error-div nes-container is-dark is-rounded" open>
|
<div class="error-div nes-container is-dark is-rounded" open>
|
||||||
<p class="nes-text is-error title">Error</p>
|
<p class="nes-text is-error title">Error</p>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
{#each $errorStore as error}
|
{#each $errorStore as error}
|
||||||
<p>{error}</p>
|
<p>{error.message}</p>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
|
||||||
<div class="button-bar">
|
|
||||||
<button class="nes-btn is-error" on:click={close}>Close</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
{#if $hasClosableMessagesInErrorStore}
|
||||||
|
<div class="button-bar">
|
||||||
|
<button class="nes-btn is-error" on:click={close}>Close</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.error-div {
|
div.error-div {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
margin-top: 10vh;
|
margin-top: 10vh;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
max-width: 80vw;
|
max-width: 80vw;
|
||||||
|
|
||||||
.button-bar {
|
.button-bar {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.body {
|
.body {
|
||||||
max-height: 50vh;
|
max-height: 50vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
font-family: "Press Start 2P";
|
font-family: "Press Start 2P";
|
||||||
|
|
||||||
&.title {
|
&.title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {streamableCollectionStore} from "../../Stores/StreamableCollectionStore";
|
import { streamableCollectionStore } from "../../Stores/StreamableCollectionStore";
|
||||||
import {afterUpdate, onDestroy} from "svelte";
|
import { afterUpdate, onDestroy } from "svelte";
|
||||||
import {biggestAvailableAreaStore} from "../../Stores/BiggestAvailableAreaStore";
|
import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStore";
|
||||||
import MediaBox from "./MediaBox.svelte";
|
import MediaBox from "./MediaBox.svelte";
|
||||||
|
|
||||||
let cssClass = 'one-col';
|
let cssClass = "one-col";
|
||||||
|
|
||||||
const unsubscribe = streamableCollectionStore.subscribe((displayableMedias) => {
|
const unsubscribe = streamableCollectionStore.subscribe((displayableMedias) => {
|
||||||
const nbUsers = displayableMedias.size;
|
const nbUsers = displayableMedias.size;
|
||||||
if (nbUsers <= 1) {
|
if (nbUsers <= 1) {
|
||||||
cssClass = 'one-col';
|
cssClass = "one-col";
|
||||||
} else if (nbUsers <= 4) {
|
} else if (nbUsers <= 4) {
|
||||||
cssClass = 'two-col';
|
cssClass = "two-col";
|
||||||
} else if (nbUsers <= 9) {
|
} else if (nbUsers <= 9) {
|
||||||
cssClass = 'three-col';
|
cssClass = "three-col";
|
||||||
} else {
|
} else {
|
||||||
cssClass = 'four-col';
|
cssClass = "four-col";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -25,11 +25,11 @@
|
|||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
biggestAvailableAreaStore.recompute();
|
biggestAvailableAreaStore.recompute();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="chat-mode {cssClass}">
|
<div class="chat-mode {cssClass}">
|
||||||
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
|
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
|
||||||
<MediaBox streamable={peer}></MediaBox>
|
<MediaBox streamable={peer} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type {ScreenSharingLocalMedia} from "../../Stores/ScreenSharingStore";
|
import type { ScreenSharingLocalMedia } from "../../Stores/ScreenSharingStore";
|
||||||
import {videoFocusStore} from "../../Stores/VideoFocusStore";
|
import { videoFocusStore } from "../../Stores/VideoFocusStore";
|
||||||
import {srcObject} from "./utils";
|
import { srcObject } from "./utils";
|
||||||
|
|
||||||
export let peer : ScreenSharingLocalMedia;
|
export let peer: ScreenSharingLocalMedia;
|
||||||
let stream = peer.stream;
|
let stream = peer.stream;
|
||||||
export let cssClass : string|undefined;
|
export let cssClass: string | undefined;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div class="video-container {cssClass ? cssClass : ''}" class:hide={!stream}>
|
<div class="video-container {cssClass ? cssClass : ''}" class:hide={!stream}>
|
||||||
{#if stream}
|
{#if stream}
|
||||||
<video use:srcObject={stream} autoplay muted playsinline on:click={() => videoFocusStore.toggleFocus(peer)}></video>
|
<video use:srcObject={stream} autoplay muted playsinline on:click={() => videoFocusStore.toggleFocus(peer)} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {VideoPeer} from "../../WebRtc/VideoPeer";
|
import { VideoPeer } from "../../WebRtc/VideoPeer";
|
||||||
import VideoMediaBox from "./VideoMediaBox.svelte";
|
import VideoMediaBox from "./VideoMediaBox.svelte";
|
||||||
import ScreenSharingMediaBox from "./ScreenSharingMediaBox.svelte";
|
import ScreenSharingMediaBox from "./ScreenSharingMediaBox.svelte";
|
||||||
import {ScreenSharingPeer} from "../../WebRtc/ScreenSharingPeer";
|
import { ScreenSharingPeer } from "../../WebRtc/ScreenSharingPeer";
|
||||||
import LocalStreamMediaBox from "./LocalStreamMediaBox.svelte";
|
import LocalStreamMediaBox from "./LocalStreamMediaBox.svelte";
|
||||||
import type {Streamable} from "../../Stores/StreamableCollectionStore";
|
import type { Streamable } from "../../Stores/StreamableCollectionStore";
|
||||||
|
|
||||||
export let streamable: Streamable;
|
export let streamable: Streamable;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="media-container">
|
<div class="media-container">
|
||||||
{#if streamable instanceof VideoPeer}
|
{#if streamable instanceof VideoPeer}
|
||||||
<VideoMediaBox peer={streamable}/>
|
<VideoMediaBox peer={streamable} />
|
||||||
{:else if streamable instanceof ScreenSharingPeer}
|
{:else if streamable instanceof ScreenSharingPeer}
|
||||||
<ScreenSharingMediaBox peer={streamable}/>
|
<ScreenSharingMediaBox peer={streamable} />
|
||||||
{:else}
|
{:else}
|
||||||
<LocalStreamMediaBox peer={streamable} cssClass=""/>
|
<LocalStreamMediaBox peer={streamable} cssClass="" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {streamableCollectionStore} from "../../Stores/StreamableCollectionStore";
|
import { streamableCollectionStore } from "../../Stores/StreamableCollectionStore";
|
||||||
import {videoFocusStore} from "../../Stores/VideoFocusStore";
|
import { videoFocusStore } from "../../Stores/VideoFocusStore";
|
||||||
import {afterUpdate} from "svelte";
|
import { afterUpdate } from "svelte";
|
||||||
import {biggestAvailableAreaStore} from "../../Stores/BiggestAvailableAreaStore";
|
import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStore";
|
||||||
import MediaBox from "./MediaBox.svelte";
|
import MediaBox from "./MediaBox.svelte";
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
biggestAvailableAreaStore.recompute();
|
biggestAvailableAreaStore.recompute();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="main-section">
|
<div class="main-section">
|
||||||
{#if $videoFocusStore }
|
{#if $videoFocusStore}
|
||||||
{#key $videoFocusStore.uniqueId}
|
{#key $videoFocusStore.uniqueId}
|
||||||
<MediaBox streamable={$videoFocusStore}></MediaBox>
|
<MediaBox streamable={$videoFocusStore} />
|
||||||
{/key}
|
{/key}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<aside class="sidebar">
|
<aside class="sidebar">
|
||||||
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
|
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
|
||||||
{#if peer !== $videoFocusStore }
|
{#if peer !== $videoFocusStore}
|
||||||
<MediaBox streamable={peer}></MediaBox>
|
<MediaBox streamable={peer} />
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</aside>
|
</aside>
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {ScreenSharingPeer} from "../../WebRtc/ScreenSharingPeer";
|
import type { ScreenSharingPeer } from "../../WebRtc/ScreenSharingPeer";
|
||||||
import {videoFocusStore} from "../../Stores/VideoFocusStore";
|
import { videoFocusStore } from "../../Stores/VideoFocusStore";
|
||||||
import {getColorByString, srcObject} from "./utils";
|
import { getColorByString, srcObject } from "./utils";
|
||||||
|
|
||||||
export let peer: ScreenSharingPeer;
|
export let peer: ScreenSharingPeer;
|
||||||
let streamStore = peer.streamStore;
|
let streamStore = peer.streamStore;
|
||||||
let name = peer.userName;
|
let name = peer.userName;
|
||||||
let statusStore = peer.statusStore;
|
let statusStore = peer.statusStore;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="video-container">
|
<div class="video-container">
|
||||||
{#if $statusStore === 'connecting'}
|
{#if $statusStore === "connecting"}
|
||||||
<div class="connecting-spinner"></div>
|
<div class="connecting-spinner" />
|
||||||
{/if}
|
{/if}
|
||||||
{#if $statusStore === 'error'}
|
{#if $statusStore === "error"}
|
||||||
<div class="rtc-error"></div>
|
<div class="rtc-error" />
|
||||||
{/if}
|
{/if}
|
||||||
{#if $streamStore === null}
|
{#if $streamStore === null}
|
||||||
<i style="background-color: {getColorByString(name)};">{name}</i>
|
<i style="background-color: {getColorByString(name)};">{name}</i>
|
||||||
{:else}
|
{:else}
|
||||||
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)}></video>
|
<!-- svelte-ignore a11y-media-has-caption -->
|
||||||
|
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.video-container {
|
.video-container {
|
||||||
video {
|
video {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {VideoPeer} from "../../WebRtc/VideoPeer";
|
import type { VideoPeer } from "../../WebRtc/VideoPeer";
|
||||||
import SoundMeterWidget from "../SoundMeterWidget.svelte";
|
import SoundMeterWidget from "../SoundMeterWidget.svelte";
|
||||||
import microphoneCloseImg from "../images/microphone-close.svg";
|
import microphoneCloseImg from "../images/microphone-close.svg";
|
||||||
import reportImg from "./images/report.svg";
|
import reportImg from "./images/report.svg";
|
||||||
import blockSignImg from "./images/blockSign.svg";
|
import blockSignImg from "./images/blockSign.svg";
|
||||||
import {videoFocusStore} from "../../Stores/VideoFocusStore";
|
import { videoFocusStore } from "../../Stores/VideoFocusStore";
|
||||||
import {showReportScreenStore} from "../../Stores/ShowReportScreenStore";
|
import { showReportScreenStore } from "../../Stores/ShowReportScreenStore";
|
||||||
import {getColorByString, srcObject} from "./utils";
|
import { getColorByString, srcObject } from "./utils";
|
||||||
|
|
||||||
export let peer: VideoPeer;
|
export let peer: VideoPeer;
|
||||||
let streamStore = peer.streamStore;
|
let streamStore = peer.streamStore;
|
||||||
@ -15,32 +15,31 @@
|
|||||||
let constraintStore = peer.constraintsStore;
|
let constraintStore = peer.constraintsStore;
|
||||||
|
|
||||||
function openReport(peer: VideoPeer): void {
|
function openReport(peer: VideoPeer): void {
|
||||||
showReportScreenStore.set({ userId:peer.userId, userName: peer.userName });
|
showReportScreenStore.set({ userId: peer.userId, userName: peer.userName });
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="video-container nes-container is-rounded is-dark">
|
<div class="video-container nes-container is-rounded is-dark">
|
||||||
{#if $statusStore === 'connecting'}
|
{#if $statusStore === "connecting"}
|
||||||
<div class="connecting-spinner"></div>
|
<div class="connecting-spinner" />
|
||||||
{/if}
|
{/if}
|
||||||
{#if $statusStore === 'error'}
|
{#if $statusStore === "error"}
|
||||||
<div class="rtc-error"></div>
|
<div class="rtc-error" />
|
||||||
{/if}
|
{/if}
|
||||||
{#if !$constraintStore || $constraintStore.video === false}
|
{#if !$constraintStore || $constraintStore.video === false}
|
||||||
<i style="background-color: {getColorByString(name)};">{name}</i>
|
<i style="background-color: {getColorByString(name)};">{name}</i>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $constraintStore && $constraintStore.audio === false}
|
{#if $constraintStore && $constraintStore.audio === false}
|
||||||
<img src={microphoneCloseImg} class="active" alt="Muted">
|
<img src={microphoneCloseImg} class="active" alt="Muted" />
|
||||||
{/if}
|
{/if}
|
||||||
<button class="report nes-button is-dark" on:click={() => openReport(peer)}>
|
<button class="report nes-button is-dark" on:click={() => openReport(peer)}>
|
||||||
<img alt="Report this user" src={reportImg}>
|
<img alt="Report this user" src={reportImg} />
|
||||||
<span>Report/Block</span>
|
<span>Report/Block</span>
|
||||||
</button>
|
</button>
|
||||||
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)}></video>
|
<!-- svelte-ignore a11y-media-has-caption -->
|
||||||
|
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)} />
|
||||||
<img src={blockSignImg} class="block-logo" alt="Block" />
|
<img src={blockSignImg} class="block-logo" alt="Block" />
|
||||||
{#if $constraintStore && $constraintStore.audio !== false}
|
{#if $constraintStore && $constraintStore.audio !== false}
|
||||||
<SoundMeterWidget stream={$streamStore}></SoundMeterWidget>
|
<SoundMeterWidget stream={$streamStore} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {LayoutMode} from "../../WebRtc/LayoutManager";
|
import { LayoutMode } from "../../WebRtc/LayoutManager";
|
||||||
import {layoutModeStore} from "../../Stores/StreamableCollectionStore";
|
import { layoutModeStore } from "../../Stores/StreamableCollectionStore";
|
||||||
import PresentationLayout from "./PresentationLayout.svelte";
|
import PresentationLayout from "./PresentationLayout.svelte";
|
||||||
import ChatLayout from "./ChatLayout.svelte";
|
import ChatLayout from "./ChatLayout.svelte";
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="video-overlay">
|
<div class="video-overlay">
|
||||||
{#if $layoutModeStore === LayoutMode.Presentation }
|
{#if $layoutModeStore === LayoutMode.Presentation}
|
||||||
<PresentationLayout />
|
<PresentationLayout />
|
||||||
{:else }
|
{:else}
|
||||||
<ChatLayout />
|
<ChatLayout />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.video-overlay {
|
.video-overlay {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from "svelte/transition";
|
||||||
import {requestVisitCardsStore} from "../../Stores/GameStore";
|
import { requestVisitCardsStore } from "../../Stores/GameStore";
|
||||||
import {onMount} from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
export let visitCardUrl: string;
|
export let visitCardUrl: string;
|
||||||
let w = '500px';
|
let w = "500px";
|
||||||
let h = '250px';
|
let h = "250px";
|
||||||
let hidden = true;
|
let hidden = true;
|
||||||
let cvIframe: HTMLIFrameElement;
|
let cvIframe: HTMLIFrameElement;
|
||||||
|
|
||||||
@ -13,73 +13,81 @@
|
|||||||
requestVisitCardsStore.set(null);
|
requestVisitCardsStore.set(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleIframeMessage(message:any) {
|
function handleIframeMessage(message: MessageEvent) {
|
||||||
if (message.data.type === 'cvIframeSize') {
|
if (message.data.type === "cvIframeSize") {
|
||||||
w = (message.data.data.w) + 'px';
|
w = message.data.data.w + "px";
|
||||||
h = (message.data.data.h) + 'px';
|
h = message.data.data.h + "px";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
cvIframe.onload = () => hidden = false
|
cvIframe.onload = () => (hidden = false);
|
||||||
cvIframe.onerror = () => hidden = false
|
cvIframe.onerror = () => (hidden = false);
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<section class="visitCard" transition:fly={{ y: -200, duration: 1000 }} style="width: {w}">
|
||||||
|
|
||||||
.loader {
|
|
||||||
border: 16px solid #f3f3f3; /* Light grey */
|
|
||||||
border-top: 16px solid #3498db; /* Blue */
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
margin:auto;
|
|
||||||
animation: spin 2s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% { transform: rotate(0deg); }
|
|
||||||
100% { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.visitCard {
|
|
||||||
pointer-events: all;
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 0);
|
|
||||||
margin-top: 200px;
|
|
||||||
max-width: 80vw;
|
|
||||||
|
|
||||||
iframe {
|
|
||||||
border: 0;
|
|
||||||
max-width: 80vw;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&.hidden {
|
|
||||||
visibility: hidden;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
<section class="visitCard" transition:fly="{{ y: -200, duration: 1000 }}" style="width: {w}">
|
|
||||||
{#if hidden}
|
{#if hidden}
|
||||||
<div class="loader"></div>
|
<div class="loader" />
|
||||||
{/if}
|
{/if}
|
||||||
<iframe title="visitCard" src={visitCardUrl} allow="clipboard-read; clipboard-write self {visitCardUrl}" style="width: {w}; height: {h}" class:hidden={hidden} bind:this={cvIframe}></iframe>
|
<iframe
|
||||||
|
title="visitCard"
|
||||||
|
src={visitCardUrl}
|
||||||
|
allow="clipboard-read; clipboard-write self {visitCardUrl}"
|
||||||
|
style="width: {w}; height: {h}"
|
||||||
|
class:hidden
|
||||||
|
bind:this={cvIframe}
|
||||||
|
/>
|
||||||
{#if !hidden}
|
{#if !hidden}
|
||||||
<div class="buttonContainer">
|
<div class="buttonContainer">
|
||||||
<button class="nes-btn is-popUpElement" on:click={closeCard}>Close</button>
|
<button class="nes-btn is-popUpElement" on:click={closeCard}>Close</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<svelte:window on:message={handleIframeMessage}/>
|
<svelte:window on:message={handleIframeMessage} />
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.loader {
|
||||||
|
border: 16px solid #f3f3f3; /* Light grey */
|
||||||
|
border-top: 16px solid #3498db; /* Blue */
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
margin: auto;
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.visitCard {
|
||||||
|
pointer-events: all;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
margin-top: 200px;
|
||||||
|
max-width: 80vw;
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
border: 0;
|
||||||
|
max-width: 80vw;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -1,37 +1,39 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from "svelte/transition";
|
||||||
import {userIsAdminStore} from "../../Stores/GameStore";
|
import { userIsAdminStore } from "../../Stores/GameStore";
|
||||||
import {ADMIN_URL} from "../../Enum/EnvironmentVariable";
|
import { ADMIN_URL } from "../../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
const upgradeLink = ADMIN_URL+'/pricing';
|
|
||||||
|
|
||||||
|
const upgradeLink = ADMIN_URL + "/pricing";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main class="warningMain" transition:fly="{{ y: -200, duration: 500 }}">
|
<main class="warningMain" transition:fly={{ y: -200, duration: 500 }}>
|
||||||
<h2>Warning!</h2>
|
<h2>Warning!</h2>
|
||||||
{#if $userIsAdminStore}
|
{#if $userIsAdminStore}
|
||||||
<p>This world is close to its limit!. You can upgrade its capacity <a href="{upgradeLink}" target="_blank">here</a></p>
|
<p>
|
||||||
|
This world is close to its limit!. You can upgrade its capacity <a href={upgradeLink} target="_blank"
|
||||||
|
>here</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
<p>This world is close to its limit!</p>
|
<p>This world is close to its limit!</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
main.warningMain {
|
main.warningMain {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
background-color: red;
|
background-color: red;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, 0);
|
transform: translate(-50%, 0);
|
||||||
font-family: Lato;
|
font-family: Lato;
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
h2 {
|
h2 {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import type { Game } from "../../Phaser/Game/Game";
|
import type { Game } from "../../Phaser/Game/Game";
|
||||||
import {SelectCharacterScene, SelectCharacterSceneName} from "../../Phaser/Login/SelectCharacterScene";
|
import { SelectCharacterScene, SelectCharacterSceneName } from "../../Phaser/Login/SelectCharacterScene";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
|
|
||||||
@ -21,72 +21,81 @@
|
|||||||
function customizeScene() {
|
function customizeScene() {
|
||||||
selectCharacterScene.nextSceneToCustomizeScene();
|
selectCharacterScene.nextSceneToCustomizeScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form class="selectCharacterScene">
|
<form class="selectCharacterScene">
|
||||||
<section class="text-center">
|
<section class="text-center">
|
||||||
<h2>Select your Avatar</h2>
|
<h2>Select your Avatar</h2>
|
||||||
<button class="selectCharacterButton selectCharacterButtonLeft nes-btn" on:click|preventDefault={ selectLeft }> < </button>
|
<button class="selectCharacterButton selectCharacterButtonLeft nes-btn" on:click|preventDefault={selectLeft}>
|
||||||
<button class="selectCharacterButton selectCharacterButtonRight nes-btn" on:click|preventDefault={ selectRight }> > </button>
|
<
|
||||||
|
</button>
|
||||||
|
<button class="selectCharacterButton selectCharacterButtonRight nes-btn" on:click|preventDefault={selectRight}>
|
||||||
|
>
|
||||||
|
</button>
|
||||||
</section>
|
</section>
|
||||||
<section class="action">
|
<section class="action">
|
||||||
<button type="submit" class="selectCharacterSceneFormSubmit nes-btn is-primary" on:click|preventDefault={ cameraScene }>Continue</button>
|
<button
|
||||||
<button type="submit" class="selectCharacterSceneFormCustomYourOwnSubmit nes-btn" on:click|preventDefault={ customizeScene }>Customize your Avatar</button>
|
type="submit"
|
||||||
|
class="selectCharacterSceneFormSubmit nes-btn is-primary"
|
||||||
|
on:click|preventDefault={cameraScene}>Continue</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="selectCharacterSceneFormCustomYourOwnSubmit nes-btn"
|
||||||
|
on:click|preventDefault={customizeScene}>Customize your Avatar</button
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
form.selectCharacterScene {
|
form.selectCharacterScene {
|
||||||
font-family: "Press Start 2P";
|
|
||||||
pointer-events: auto;
|
|
||||||
color: #ebeeee;
|
|
||||||
|
|
||||||
section {
|
|
||||||
margin: 10px;
|
|
||||||
|
|
||||||
&.action {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 55vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-family: "Press Start 2P";
|
font-family: "Press Start 2P";
|
||||||
margin: 1px;
|
pointer-events: auto;
|
||||||
}
|
color: #ebeeee;
|
||||||
|
|
||||||
&.text-center {
|
section {
|
||||||
text-align: center;
|
margin: 10px;
|
||||||
}
|
|
||||||
|
|
||||||
button.selectCharacterButton {
|
&.action {
|
||||||
position: absolute;
|
text-align: center;
|
||||||
top: 33vh;
|
margin-top: 55vh;
|
||||||
margin: 0;
|
}
|
||||||
}
|
|
||||||
|
h2 {
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
margin: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.selectCharacterButton {
|
||||||
|
position: absolute;
|
||||||
|
top: 33vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-family: "Press Start 2P";
|
||||||
|
|
||||||
|
&.selectCharacterButtonLeft {
|
||||||
|
left: 33vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selectCharacterButtonRight {
|
||||||
|
right: 33vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
@media only screen and (max-width: 800px) {
|
||||||
font-family: "Press Start 2P";
|
form.selectCharacterScene button.selectCharacterButtonLeft {
|
||||||
|
left: 5vw;
|
||||||
&.selectCharacterButtonLeft {
|
}
|
||||||
left: 33vw;
|
form.selectCharacterScene button.selectCharacterButtonRight {
|
||||||
}
|
right: 5vw;
|
||||||
|
}
|
||||||
&.selectCharacterButtonRight {
|
|
||||||
right: 33vw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
|
||||||
form.selectCharacterScene button.selectCharacterButtonLeft{
|
|
||||||
left: 5vw;
|
|
||||||
}
|
|
||||||
form.selectCharacterScene button.selectCharacterButtonRight{
|
|
||||||
right: 5vw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
37
front/src/Connexion/AxiosUtils.ts
Normal file
37
front/src/Connexion/AxiosUtils.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import * as rax from "retry-axios";
|
||||||
|
import { errorStore } from "../Stores/ErrorStore";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This instance of Axios will retry in case of an issue and display an error message as a HTML overlay.
|
||||||
|
*/
|
||||||
|
export const axiosWithRetry = axios.create();
|
||||||
|
axiosWithRetry.defaults.raxConfig = {
|
||||||
|
instance: axiosWithRetry,
|
||||||
|
retry: Infinity,
|
||||||
|
noResponseRetries: Infinity,
|
||||||
|
|
||||||
|
maxRetryAfter: 60_000,
|
||||||
|
|
||||||
|
// You can detect when a retry is happening, and figure out how many
|
||||||
|
// retry attempts have been made
|
||||||
|
onRetryAttempt: (err) => {
|
||||||
|
const cfg = rax.getConfig(err);
|
||||||
|
console.log(err);
|
||||||
|
console.log(cfg);
|
||||||
|
console.log(`Retry attempt #${cfg?.currentRetryAttempt} on URL '${err.config.url}'`);
|
||||||
|
errorStore.addErrorMessage("Unable to connect to WorkAdventure. Are you connected to internet?", {
|
||||||
|
closable: false,
|
||||||
|
id: "axios_retry",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
axiosWithRetry.interceptors.response.use((res) => {
|
||||||
|
if (res.status < 400) {
|
||||||
|
errorStore.clearMessageById("axios_retry");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
|
||||||
|
const interceptorId = rax.attach(axiosWithRetry);
|
@ -11,6 +11,7 @@ import { loginSceneVisibleIframeStore } from "../Stores/LoginSceneStore";
|
|||||||
import { userIsConnected } from "../Stores/MenuStore";
|
import { userIsConnected } from "../Stores/MenuStore";
|
||||||
import { analyticsClient } from "../Administration/AnalyticsClient";
|
import { analyticsClient } from "../Administration/AnalyticsClient";
|
||||||
import { gameManager } from "../Phaser/Game/GameManager";
|
import { gameManager } from "../Phaser/Game/GameManager";
|
||||||
|
import { axiosWithRetry } from "./AxiosUtils";
|
||||||
|
|
||||||
class ConnectionManager {
|
class ConnectionManager {
|
||||||
private localUser!: LocalUser;
|
private localUser!: LocalUser;
|
||||||
@ -233,7 +234,7 @@ class ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async anonymousLogin(isBenchmark: boolean = false): Promise<void> {
|
public async anonymousLogin(isBenchmark: boolean = false): Promise<void> {
|
||||||
const data = await Axios.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data);
|
const data = await axiosWithRetry.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data);
|
||||||
this.localUser = new LocalUser(data.userUuid, [], data.email);
|
this.localUser = new LocalUser(data.userUuid, [], data.email);
|
||||||
this.authToken = data.authToken;
|
this.authToken = data.authToken;
|
||||||
if (!isBenchmark) {
|
if (!isBenchmark) {
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
|
import * as rax from "retry-axios";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import { CONTACT_URL, PUSHER_URL, DISABLE_ANONYMOUS, OPID_LOGIN_SCREEN_PROVIDER } from "../Enum/EnvironmentVariable";
|
import { CONTACT_URL, PUSHER_URL, DISABLE_ANONYMOUS, OPID_LOGIN_SCREEN_PROVIDER } from "../Enum/EnvironmentVariable";
|
||||||
import type { CharacterTexture } from "./LocalUser";
|
import type { CharacterTexture } from "./LocalUser";
|
||||||
import { localUserStore } from "./LocalUserStore";
|
import { localUserStore } from "./LocalUserStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import { axiosWithRetry } from "./AxiosUtils";
|
||||||
|
|
||||||
export class MapDetail {
|
export class MapDetail {
|
||||||
constructor(public readonly mapUrl: string, public readonly textures: CharacterTexture[] | undefined) {}
|
constructor(public readonly mapUrl: string, public readonly textures: CharacterTexture[] | undefined) {}
|
||||||
@ -90,7 +93,7 @@ export class Room {
|
|||||||
|
|
||||||
private async getMapDetail(): Promise<MapDetail | RoomRedirect> {
|
private async getMapDetail(): Promise<MapDetail | RoomRedirect> {
|
||||||
try {
|
try {
|
||||||
const result = await Axios.get(`${PUSHER_URL}/map`, {
|
const result = await axiosWithRetry.get(`${PUSHER_URL}/map`, {
|
||||||
params: {
|
params: {
|
||||||
playUri: this.roomUrl.toString(),
|
playUri: this.roomUrl.toString(),
|
||||||
authToken: localUserStore.getAuthToken(),
|
authToken: localUserStore.getAuthToken(),
|
||||||
|
@ -255,6 +255,9 @@ export class RoomConnection implements RoomConnection {
|
|||||||
warningContainerStore.activateWarningContainer();
|
warningContainerStore.activateWarningContainer();
|
||||||
} else if (message.hasRefreshroommessage()) {
|
} else if (message.hasRefreshroommessage()) {
|
||||||
//todo: implement a way to notify the user the room was refreshed.
|
//todo: implement a way to notify the user the room was refreshed.
|
||||||
|
} else if (message.hasErrormessage()) {
|
||||||
|
const errorMessage = message.getErrormessage() as ErrorMessage;
|
||||||
|
console.error("An error occurred server side: " + errorMessage.getMessage());
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unknown message received");
|
throw new Error("Unknown message received");
|
||||||
}
|
}
|
||||||
|
@ -271,8 +271,10 @@ export class GameScene extends DirtyScene {
|
|||||||
// 127.0.0.1, localhost and *.localhost are considered secure, even on HTTP.
|
// 127.0.0.1, localhost and *.localhost are considered secure, even on HTTP.
|
||||||
// So if we are in https, we can still try to load a HTTP local resource (can be useful for testing purposes)
|
// So if we are in https, we can still try to load a HTTP local resource (can be useful for testing purposes)
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure
|
// See https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure
|
||||||
const url = new URL(file.src);
|
const base = new URL(window.location.href);
|
||||||
const host = url.host.split(":")[ 0 ];
|
base.pathname = "";
|
||||||
|
const url = new URL(file.src, base.toString());
|
||||||
|
const host = url.host.split(":")[0];
|
||||||
if (
|
if (
|
||||||
window.location.protocol === "https:" &&
|
window.location.protocol === "https:" &&
|
||||||
file.src === this.MapUrlFile &&
|
file.src === this.MapUrlFile &&
|
||||||
@ -324,12 +326,11 @@ export class GameScene extends DirtyScene {
|
|||||||
this.onMapLoad(data);
|
this.onMapLoad(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.load.bitmapFont("main_font", "resources/fonts/arcade.png", "resources/fonts/arcade.xml");
|
|
||||||
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(this.load as any).rexWebFont({
|
(this.load as any).rexWebFont({
|
||||||
custom: {
|
custom: {
|
||||||
families: [ "Press Start 2P" ],
|
families: ["Press Start 2P"],
|
||||||
urls: [ "/resources/fonts/fonts.css" ],
|
urls: ["/resources/fonts/fonts.css"],
|
||||||
testString: "abcdefg",
|
testString: "abcdefg",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -375,7 +376,7 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [ itemType, objectsOfType ] of this.objectsByType) {
|
for (const [itemType, objectsOfType] of this.objectsByType) {
|
||||||
// FIXME: we would ideally need for the loader to WAIT for the import to be performed, which means writing our own loader plugin.
|
// FIXME: we would ideally need for the loader to WAIT for the import to be performed, which means writing our own loader plugin.
|
||||||
|
|
||||||
let itemFactory: ItemFactoryInterface;
|
let itemFactory: ItemFactoryInterface;
|
||||||
@ -406,7 +407,7 @@ export class GameScene extends DirtyScene {
|
|||||||
// TODO: we should pass here a factory to create sprites (maybe?)
|
// TODO: we should pass here a factory to create sprites (maybe?)
|
||||||
|
|
||||||
// Do we have a state for this object?
|
// Do we have a state for this object?
|
||||||
const state = roomJoinedAnswer.items[ object.id ];
|
const state = roomJoinedAnswer.items[object.id];
|
||||||
|
|
||||||
const actionableItem = itemFactory.factory(this, object, state);
|
const actionableItem = itemFactory.factory(this, object, state);
|
||||||
this.actionableItems.set(actionableItem.getId(), actionableItem);
|
this.actionableItems.set(actionableItem.getId(), actionableItem);
|
||||||
@ -636,7 +637,7 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all([ this.connectionAnswerPromise as Promise<unknown>, ...scriptPromises ]).then(() => {
|
Promise.all([this.connectionAnswerPromise as Promise<unknown>, ...scriptPromises]).then(() => {
|
||||||
this.scene.wake();
|
this.scene.wake();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -724,8 +725,8 @@ export class GameScene extends DirtyScene {
|
|||||||
if (item === undefined) {
|
if (item === undefined) {
|
||||||
console.warn(
|
console.warn(
|
||||||
'Received an event about object "' +
|
'Received an event about object "' +
|
||||||
message.itemId +
|
message.itemId +
|
||||||
'" but cannot find this item on the map.'
|
'" but cannot find this item on the map.'
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -933,8 +934,8 @@ export class GameScene extends DirtyScene {
|
|||||||
} else {
|
} else {
|
||||||
console.error(
|
console.error(
|
||||||
"Error while opening a popup. Cannot find an object on the map with name '" +
|
"Error while opening a popup. Cannot find an object on the map with name '" +
|
||||||
openPopupEvent.targetObject +
|
openPopupEvent.targetObject +
|
||||||
"'. The first parameter of WA.openPopup() must be the name of a rectangle object in your map."
|
"'. The first parameter of WA.openPopup() must be the name of a rectangle object in your map."
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1198,7 +1199,7 @@ export class GameScene extends DirtyScene {
|
|||||||
const jsonTilesetDir = eventTileset.url.substr(0, eventTileset.url.lastIndexOf("/"));
|
const jsonTilesetDir = eventTileset.url.substr(0, eventTileset.url.lastIndexOf("/"));
|
||||||
//Initialise the firstgid to 1 because if there is no tileset in the tilemap, the firstgid will be 1
|
//Initialise the firstgid to 1 because if there is no tileset in the tilemap, the firstgid will be 1
|
||||||
let newFirstgid = 1;
|
let newFirstgid = 1;
|
||||||
const lastTileset = this.mapFile.tilesets[ this.mapFile.tilesets.length - 1 ];
|
const lastTileset = this.mapFile.tilesets[this.mapFile.tilesets.length - 1];
|
||||||
if (lastTileset) {
|
if (lastTileset) {
|
||||||
//If there is at least one tileset in the tilemap then calculate the firstgid of the new tileset
|
//If there is at least one tileset in the tilemap then calculate the firstgid of the new tileset
|
||||||
newFirstgid = lastTileset.firstgid + lastTileset.tilecount;
|
newFirstgid = lastTileset.firstgid + lastTileset.tilecount;
|
||||||
@ -1298,14 +1299,14 @@ export class GameScene extends DirtyScene {
|
|||||||
if (phaserLayers === []) {
|
if (phaserLayers === []) {
|
||||||
console.warn(
|
console.warn(
|
||||||
'Could not find layer with name that contains "' +
|
'Could not find layer with name that contains "' +
|
||||||
layerName +
|
layerName +
|
||||||
'" when calling WA.hideLayer / WA.showLayer'
|
'" when calling WA.hideLayer / WA.showLayer'
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < phaserLayers.length; i++) {
|
for (let i = 0; i < phaserLayers.length; i++) {
|
||||||
phaserLayers[ i ].setVisible(visible);
|
phaserLayers[i].setVisible(visible);
|
||||||
phaserLayers[ i ].setCollisionByProperty({ collides: true }, visible);
|
phaserLayers[i].setCollisionByProperty({ collides: true }, visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.markDirty();
|
this.markDirty();
|
||||||
|
@ -3,6 +3,7 @@ import { Scene } from "phaser";
|
|||||||
import { ErrorScene, ErrorSceneName } from "../Reconnecting/ErrorScene";
|
import { ErrorScene, ErrorSceneName } from "../Reconnecting/ErrorScene";
|
||||||
import { WAError } from "../Reconnecting/WAError";
|
import { WAError } from "../Reconnecting/WAError";
|
||||||
import { waScaleManager } from "../Services/WaScaleManager";
|
import { waScaleManager } from "../Services/WaScaleManager";
|
||||||
|
import { ReconnectingTextures } from "../Reconnecting/ReconnectingScene";
|
||||||
|
|
||||||
export const EntrySceneName = "EntryScene";
|
export const EntrySceneName = "EntryScene";
|
||||||
|
|
||||||
@ -17,6 +18,14 @@ export class EntryScene extends Scene {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From the very start, let's preload images used in the ReconnectingScene.
|
||||||
|
preload() {
|
||||||
|
this.load.image(ReconnectingTextures.icon, "static/images/favicons/favicon-32x32.png");
|
||||||
|
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
|
||||||
|
this.load.bitmapFont(ReconnectingTextures.mainFont, "resources/fonts/arcade.png", "resources/fonts/arcade.xml");
|
||||||
|
this.load.spritesheet("cat", "resources/characters/pipoya/Cat 01-1.png", { frameWidth: 32, frameHeight: 32 });
|
||||||
|
}
|
||||||
|
|
||||||
create() {
|
create() {
|
||||||
gameManager
|
gameManager
|
||||||
.init(this.scene)
|
.init(this.scene)
|
||||||
|
@ -4,6 +4,7 @@ import Sprite = Phaser.GameObjects.Sprite;
|
|||||||
import Text = Phaser.GameObjects.Text;
|
import Text = Phaser.GameObjects.Text;
|
||||||
import ScenePlugin = Phaser.Scenes.ScenePlugin;
|
import ScenePlugin = Phaser.Scenes.ScenePlugin;
|
||||||
import { WAError } from "./WAError";
|
import { WAError } from "./WAError";
|
||||||
|
import Axios from "axios";
|
||||||
|
|
||||||
export const ErrorSceneName = "ErrorScene";
|
export const ErrorSceneName = "ErrorScene";
|
||||||
enum Textures {
|
enum Textures {
|
||||||
@ -36,7 +37,11 @@ export class ErrorScene extends Phaser.Scene {
|
|||||||
preload() {
|
preload() {
|
||||||
this.load.image(Textures.icon, "static/images/favicons/favicon-32x32.png");
|
this.load.image(Textures.icon, "static/images/favicons/favicon-32x32.png");
|
||||||
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
|
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
|
||||||
this.load.bitmapFont(Textures.mainFont, "resources/fonts/arcade.png", "resources/fonts/arcade.xml");
|
if (!this.cache.bitmapFont.has("main_font")) {
|
||||||
|
// We put this inside a "if" because despite the cache, Phaser will make a query to the XML file. And if there is no connection (which
|
||||||
|
// is not unlikely given the fact we are in an error scene), this will cause an error.
|
||||||
|
this.load.bitmapFont(Textures.mainFont, "resources/fonts/arcade.png", "resources/fonts/arcade.xml");
|
||||||
|
}
|
||||||
this.load.spritesheet("cat", "resources/characters/pipoya/Cat 01-1.png", { frameWidth: 32, frameHeight: 32 });
|
this.load.spritesheet("cat", "resources/characters/pipoya/Cat 01-1.png", { frameWidth: 32, frameHeight: 32 });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,9 +76,9 @@ export class ErrorScene extends Phaser.Scene {
|
|||||||
/**
|
/**
|
||||||
* Displays the error page, with an error message matching the "error" parameters passed in.
|
* Displays the error page, with an error message matching the "error" parameters passed in.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
public static showError(error: unknown, scene: ScenePlugin): void {
|
||||||
public static showError(error: any, scene: ScenePlugin): void {
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
console.trace();
|
||||||
|
|
||||||
if (typeof error === "string" || error instanceof String) {
|
if (typeof error === "string" || error instanceof String) {
|
||||||
scene.start(ErrorSceneName, {
|
scene.start(ErrorSceneName, {
|
||||||
@ -86,9 +91,10 @@ export class ErrorScene extends Phaser.Scene {
|
|||||||
subTitle: error.subTitle,
|
subTitle: error.subTitle,
|
||||||
message: error.details,
|
message: error.details,
|
||||||
});
|
});
|
||||||
} else if (error.response) {
|
} else if (Axios.isAxiosError(error) && error.response) {
|
||||||
// Axios HTTP error
|
// Axios HTTP error
|
||||||
// client received an error response (5xx, 4xx)
|
// client received an error response (5xx, 4xx)
|
||||||
|
console.error("Axios error. Request:", error.request, " - Response: ", error.response);
|
||||||
scene.start(ErrorSceneName, {
|
scene.start(ErrorSceneName, {
|
||||||
title:
|
title:
|
||||||
"HTTP " +
|
"HTTP " +
|
||||||
@ -98,9 +104,10 @@ export class ErrorScene extends Phaser.Scene {
|
|||||||
subTitle: "An error occurred while accessing URL:",
|
subTitle: "An error occurred while accessing URL:",
|
||||||
message: error.response.config.url,
|
message: error.response.config.url,
|
||||||
});
|
});
|
||||||
} else if (error.request) {
|
} else if (Axios.isAxiosError(error)) {
|
||||||
// Axios HTTP error
|
// Axios HTTP error
|
||||||
// client never received a response, or request never left
|
// client never received a response, or request never left
|
||||||
|
console.error("Axios error. No full HTTP response received. Request to URL:", error.config.url);
|
||||||
scene.start(ErrorSceneName, {
|
scene.start(ErrorSceneName, {
|
||||||
title: "Network error",
|
title: "Network error",
|
||||||
subTitle: error.message,
|
subTitle: error.message,
|
||||||
|
@ -3,7 +3,7 @@ import Image = Phaser.GameObjects.Image;
|
|||||||
import Sprite = Phaser.GameObjects.Sprite;
|
import Sprite = Phaser.GameObjects.Sprite;
|
||||||
|
|
||||||
export const ReconnectingSceneName = "ReconnectingScene";
|
export const ReconnectingSceneName = "ReconnectingScene";
|
||||||
enum ReconnectingTextures {
|
export enum ReconnectingTextures {
|
||||||
icon = "icon",
|
icon = "icon",
|
||||||
mainFont = "main_font",
|
mainFont = "main_font",
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ export class ReconnectingScene extends Phaser.Scene {
|
|||||||
"Connection lost. Reconnecting..."
|
"Connection lost. Reconnecting..."
|
||||||
);
|
);
|
||||||
|
|
||||||
const cat = this.physics.add.sprite(this.game.renderer.width / 2, this.game.renderer.height / 2 - 32, "cat");
|
const cat = this.add.sprite(this.game.renderer.width / 2, this.game.renderer.height / 2 - 32, "cat");
|
||||||
this.anims.create({
|
this.anims.create({
|
||||||
key: "right",
|
key: "right",
|
||||||
frames: this.anims.generateFrameNumbers("cat", { start: 6, end: 8 }),
|
frames: this.anims.generateFrameNumbers("cat", { start: 6, end: 8 }),
|
||||||
|
@ -1,15 +1,27 @@
|
|||||||
import { writable } from "svelte/store";
|
import { derived, writable } from "svelte/store";
|
||||||
|
|
||||||
|
interface ErrorMessage {
|
||||||
|
id: string | undefined;
|
||||||
|
closable: boolean; // Whether it can be closed by a user action or not
|
||||||
|
message: string | number | boolean | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A store that contains a list of error messages to be displayed.
|
* A store that contains a list of error messages to be displayed.
|
||||||
*/
|
*/
|
||||||
function createErrorStore() {
|
function createErrorStore() {
|
||||||
const { subscribe, set, update } = writable<string[]>([]);
|
const { subscribe, set, update } = writable<ErrorMessage[]>([]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
addErrorMessage: (e: string | Error): void => {
|
addErrorMessage: (
|
||||||
update((messages: string[]) => {
|
e: string | Error,
|
||||||
|
options?: {
|
||||||
|
closable?: boolean;
|
||||||
|
id?: string;
|
||||||
|
}
|
||||||
|
): void => {
|
||||||
|
update((messages: ErrorMessage[]) => {
|
||||||
let message: string;
|
let message: string;
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
message = e.message;
|
message = e.message;
|
||||||
@ -17,17 +29,35 @@ function createErrorStore() {
|
|||||||
message = e;
|
message = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!messages.includes(message)) {
|
if (!messages.find((errorMessage) => errorMessage.message === message)) {
|
||||||
messages.push(message);
|
messages.push({
|
||||||
|
message,
|
||||||
|
closable: options?.closable ?? true,
|
||||||
|
id: options?.id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return messages;
|
return messages;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
clearMessages: (): void => {
|
clearMessageById: (id: string): void => {
|
||||||
set([]);
|
update((messages: ErrorMessage[]) => {
|
||||||
|
messages = messages.filter((message) => message.id !== id);
|
||||||
|
return messages;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearClosableMessages: (): void => {
|
||||||
|
update((messages: ErrorMessage[]) => {
|
||||||
|
messages = messages.filter((message) => message.closable);
|
||||||
|
return messages;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const errorStore = createErrorStore();
|
export const errorStore = createErrorStore();
|
||||||
|
|
||||||
|
export const hasClosableMessagesInErrorStore = derived(errorStore, ($errorStore) => {
|
||||||
|
const closableMessage = $errorStore.find((errorMessage) => errorMessage.closable);
|
||||||
|
return !!closableMessage;
|
||||||
|
});
|
||||||
|
@ -32,6 +32,7 @@ module.exports = {
|
|||||||
rewrites: [{ from: /^_\/.*$/, to: "/index.html" }],
|
rewrites: [{ from: /^_\/.*$/, to: "/index.html" }],
|
||||||
disableDotRule: true,
|
disableDotRule: true,
|
||||||
},
|
},
|
||||||
|
liveReload: process.env.LIVE_RELOAD != "0" && process.env.LIVE_RELOAD != "false",
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
@ -2070,6 +2070,11 @@ escape-string-regexp@^4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||||
|
|
||||||
|
eslint-plugin-svelte3@^3.2.1:
|
||||||
|
version "3.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-svelte3/-/eslint-plugin-svelte3-3.2.1.tgz#f0f24150ecea3061c38c69e282bea26dc3e660c6"
|
||||||
|
integrity sha512-YoBR9mLoKCjGghJ/gvpnFZKaMEu/VRcuxpSRS8KuozuEo7CdBH7bmBHa6FmMm0i4kJnOyx+PVsaptz96K6H/4Q==
|
||||||
|
|
||||||
eslint-scope@^5.0.0, eslint-scope@^5.1.1:
|
eslint-scope@^5.0.0, eslint-scope@^5.1.1:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
||||||
@ -2395,14 +2400,6 @@ file-entry-cache@^6.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flat-cache "^3.0.4"
|
flat-cache "^3.0.4"
|
||||||
|
|
||||||
file-loader@^6.2.0:
|
|
||||||
version "6.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d"
|
|
||||||
integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==
|
|
||||||
dependencies:
|
|
||||||
loader-utils "^2.0.0"
|
|
||||||
schema-utils "^3.0.0"
|
|
||||||
|
|
||||||
file-uri-to-path@1.0.0:
|
file-uri-to-path@1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||||
@ -4580,6 +4577,11 @@ prelude-ls@^1.2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||||
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
||||||
|
|
||||||
|
prettier-plugin-svelte@^2.5.0:
|
||||||
|
version "2.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-2.5.0.tgz#7922534729f7febe59b4c56c3f5360539f0d8ab1"
|
||||||
|
integrity sha512-+iHY2uGChOngrgKielJUnqo74gIL/EO5oeWm8MftFWjEi213lq9QYTOwm1pv4lI1nA61tdgf80CF2i5zMcu1kw==
|
||||||
|
|
||||||
prettier@^2.3.1:
|
prettier@^2.3.1:
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.1.tgz#76903c3f8c4449bc9ac597acefa24dc5ad4cbea6"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.1.tgz#76903c3f8c4449bc9ac597acefa24dc5ad4cbea6"
|
||||||
@ -4934,6 +4936,11 @@ ret@~0.1.10:
|
|||||||
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
||||||
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
|
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
|
||||||
|
|
||||||
|
retry-axios@^2.6.0:
|
||||||
|
version "2.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/retry-axios/-/retry-axios-2.6.0.tgz#d4dc5c8a8e73982e26a705e46a33df99a28723e0"
|
||||||
|
integrity sha512-pOLi+Gdll3JekwuFjXO3fTq+L9lzMQGcSq7M5gIjExcl3Gu1hd4XXuf5o3+LuSBsaULQH7DiNbsqPd1chVpQGQ==
|
||||||
|
|
||||||
retry@^0.12.0:
|
retry@^0.12.0:
|
||||||
version "0.12.0"
|
version "0.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
|
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
|
||||||
|
33
maps/tests/Variables/E2ETests/script.js
Normal file
33
maps/tests/Variables/E2ETests/script.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
WA.onInit().then(() => {
|
||||||
|
console.log('Trying to read variable "doorOpened" whose default property is true. This should display "true".');
|
||||||
|
console.log('doorOpened', WA.state.loadVariable('doorOpened'));
|
||||||
|
|
||||||
|
console.log('Trying to set variable "not_exists". This should display an error in the console, followed by a log saying the error was caught.')
|
||||||
|
WA.state.saveVariable('not_exists', 'foo').catch((e) => {
|
||||||
|
console.log('Successfully caught error: ', e);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Trying to set variable "myvar". This should work.');
|
||||||
|
WA.state.saveVariable('myvar', {'foo': 'bar'});
|
||||||
|
|
||||||
|
console.log('Trying to read variable "myvar". This should display a {"foo": "bar"} object.');
|
||||||
|
console.log(WA.state.loadVariable('myvar'));
|
||||||
|
|
||||||
|
console.log('Trying to set variable "myvar" using proxy. This should work.');
|
||||||
|
WA.state.myvar = {'baz': 42};
|
||||||
|
|
||||||
|
console.log('Trying to read variable "myvar" using proxy. This should display a {"baz": 42} object.');
|
||||||
|
console.log(WA.state.myvar);
|
||||||
|
|
||||||
|
console.log('Trying to set variable "config". This should not work because we are not logged as admin.');
|
||||||
|
WA.state.saveVariable('config', {'foo': 'bar'}).catch(e => {
|
||||||
|
console.log('Successfully caught error because variable "config" is not writable: ', e);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Trying to read variable "readableByAdmin" that can only be read by "admin". We are not admin so we should not get the default value.');
|
||||||
|
if (WA.state.readableByAdmin === true) {
|
||||||
|
console.error('Failed test: readableByAdmin can be read.');
|
||||||
|
} else {
|
||||||
|
console.log('Success test: readableByAdmin was not read.');
|
||||||
|
}
|
||||||
|
});
|
47
maps/tests/Variables/E2ETests/shared_variables.html
Normal file
47
maps/tests/Variables/E2ETests/shared_variables.html
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<script>
|
||||||
|
var script = document.createElement('script');
|
||||||
|
// Don't do this at home kids! The "document.referrer" part is actually inserting a XSS security.
|
||||||
|
// We are OK in this precise case because the HTML page is hosted on the "maps" domain that contains only static files.
|
||||||
|
document.head.appendChild(script);
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
console.log('On load');
|
||||||
|
WA.onInit().then(() => {
|
||||||
|
console.log('After WA init');
|
||||||
|
const textField = document.getElementById('textField');
|
||||||
|
textField.value = WA.state.textField;
|
||||||
|
|
||||||
|
textField.addEventListener('change', function (evt) {
|
||||||
|
console.log('saving variable')
|
||||||
|
WA.state.textField = this.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
WA.state.onVariableChange('textField').subscribe((value) => {
|
||||||
|
console.log('variable changed received')
|
||||||
|
textField.value = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('btn').addEventListener('click', () => {
|
||||||
|
console.log(WA.state.loadVariable('textField'));
|
||||||
|
document.getElementById('placeholder').innerText = WA.state.loadVariable('textField');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('setUndefined').addEventListener('click', () => {
|
||||||
|
WA.state.textField = undefined;
|
||||||
|
document.getElementById('textField').value = '';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<input type="text" id="textField" />
|
||||||
|
|
||||||
|
<button id="setUndefined">Delete variable</button>
|
||||||
|
|
||||||
|
<button id="btn">Display textField variable value</button>
|
||||||
|
<div id="placeholder"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
131
maps/tests/Variables/E2ETests/shared_variables.json
Normal file
131
maps/tests/Variables/E2ETests/shared_variables.json
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
{ "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,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"openWebsite",
|
||||||
|
"type":"string",
|
||||||
|
"value":"shared_variables.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"openWebsiteAllowApi",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}],
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":10,
|
||||||
|
"id":2,
|
||||||
|
"name":"start",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":10,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"draworder":"topdown",
|
||||||
|
"id":3,
|
||||||
|
"name":"floorLayer",
|
||||||
|
"objects":[
|
||||||
|
{
|
||||||
|
"height":67,
|
||||||
|
"id":3,
|
||||||
|
"name":"",
|
||||||
|
"rotation":0,
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"fontfamily":"Sans Serif",
|
||||||
|
"pixelsize":11,
|
||||||
|
"text":"Test:\nChange the form\nConnect with another user\n\nResult:\nThe form should open in the same state for the other user\nAlso, a change on one user is directly propagated to the other user",
|
||||||
|
"wrap":true
|
||||||
|
},
|
||||||
|
"type":"",
|
||||||
|
"visible":true,
|
||||||
|
"width":252.4375,
|
||||||
|
"x":2.78125,
|
||||||
|
"y":2.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height":0,
|
||||||
|
"id":5,
|
||||||
|
"name":"textField",
|
||||||
|
"point":true,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"default",
|
||||||
|
"type":"string",
|
||||||
|
"value":"default value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"jsonSchema",
|
||||||
|
"type":"string",
|
||||||
|
"value":"{}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"persist",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"readableBy",
|
||||||
|
"type":"string",
|
||||||
|
"value":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"writableBy",
|
||||||
|
"type":"string",
|
||||||
|
"value":""
|
||||||
|
}],
|
||||||
|
"rotation":0,
|
||||||
|
"type":"variable",
|
||||||
|
"visible":true,
|
||||||
|
"width":0,
|
||||||
|
"x":57.5,
|
||||||
|
"y":111
|
||||||
|
}],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":8,
|
||||||
|
"nextobjectid":10,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"2021.03.23",
|
||||||
|
"tileheight":32,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":11,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"..\/tileset1.png",
|
||||||
|
"imageheight":352,
|
||||||
|
"imagewidth":352,
|
||||||
|
"margin":0,
|
||||||
|
"name":"tileset1",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":121,
|
||||||
|
"tileheight":32,
|
||||||
|
"tilewidth":32
|
||||||
|
}],
|
||||||
|
"tilewidth":32,
|
||||||
|
"type":"map",
|
||||||
|
"version":1.5,
|
||||||
|
"width":10
|
||||||
|
}
|
@ -274,12 +274,12 @@ message ServerToClientMessage {
|
|||||||
SendJitsiJwtMessage sendJitsiJwtMessage = 11;
|
SendJitsiJwtMessage sendJitsiJwtMessage = 11;
|
||||||
SendUserMessage sendUserMessage = 12;
|
SendUserMessage sendUserMessage = 12;
|
||||||
BanUserMessage banUserMessage = 13;
|
BanUserMessage banUserMessage = 13;
|
||||||
AdminRoomMessage adminRoomMessage = 14;
|
//AdminRoomMessage adminRoomMessage = 14;
|
||||||
WorldFullWarningMessage worldFullWarningMessage = 15;
|
WorldFullWarningMessage worldFullWarningMessage = 15;
|
||||||
WorldFullMessage worldFullMessage = 16;
|
WorldFullMessage worldFullMessage = 16;
|
||||||
RefreshRoomMessage refreshRoomMessage = 17;
|
RefreshRoomMessage refreshRoomMessage = 17;
|
||||||
WorldConnexionMessage worldConnexionMessage = 18;
|
WorldConnexionMessage worldConnexionMessage = 18;
|
||||||
EmoteEventMessage emoteEventMessage = 19;
|
//EmoteEventMessage emoteEventMessage = 19;
|
||||||
TokenExpiredMessage tokenExpiredMessage = 20;
|
TokenExpiredMessage tokenExpiredMessage = 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import { jwtTokenManager, tokenInvalidException } from "../Services/JWTTokenMana
|
|||||||
import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi";
|
import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi";
|
||||||
import { SocketManager, socketManager } from "../Services/SocketManager";
|
import { SocketManager, socketManager } from "../Services/SocketManager";
|
||||||
import { emitInBatch } from "../Services/IoSocketHelpers";
|
import { emitInBatch } from "../Services/IoSocketHelpers";
|
||||||
import { ADMIN_SOCKETS_TOKEN, ADMIN_API_URL, DISABLE_ANONYMOUS, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_URL, DISABLE_ANONYMOUS, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable";
|
||||||
import { Zone } from "_Model/Zone";
|
import { Zone } from "_Model/Zone";
|
||||||
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
|
||||||
import { CharacterTexture } from "../Services/AdminApi/CharacterTexture";
|
import { CharacterTexture } from "../Services/AdminApi/CharacterTexture";
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
import { ADMIN_API_URL, ADMIN_SOCKETS_TOKEN, ALLOW_ARTILLERY, SECRET_KEY } from "../Enum/EnvironmentVariable";
|
import { ADMIN_SOCKETS_TOKEN, SECRET_KEY } from "../Enum/EnvironmentVariable";
|
||||||
import { uuid } from "uuidv4";
|
import Jwt from "jsonwebtoken";
|
||||||
import Jwt, { verify } from "jsonwebtoken";
|
|
||||||
import { TokenInterface } from "../Controller/AuthenticateController";
|
|
||||||
import { adminApi, AdminBannedData } from "../Services/AdminApi";
|
|
||||||
|
|
||||||
export interface AuthTokenData {
|
export interface AuthTokenData {
|
||||||
identifier: string; //will be a sub (id) if logged in or an uuid if anonymous
|
identifier: string; //will be a sub (id) if logged in or an uuid if anonymous
|
||||||
|
@ -3,11 +3,28 @@ const BROWSER = process.env.BROWSER || "chrome --use-fake-ui-for-media-stream --
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
"browsers": BROWSER,
|
"browsers": BROWSER,
|
||||||
"hostname": "localhost",
|
"hostname": "localhost",
|
||||||
//"skipJsErrors": true,
|
|
||||||
"src": "tests/",
|
"src": "tests/",
|
||||||
"screenshots": {
|
"screenshots": {
|
||||||
"path": "screenshots/",
|
"path": "screenshots/",
|
||||||
"takeOnFails": true,
|
"takeOnFails": true,
|
||||||
"thumbnails": false,
|
"thumbnails": false,
|
||||||
|
},
|
||||||
|
"assertionTimeout": 20000,
|
||||||
|
"selectorTimeout": 60000,
|
||||||
|
|
||||||
|
|
||||||
|
"videoPath": "screenshots/videos",
|
||||||
|
"videoOptions": {
|
||||||
|
"failedOnly": true,
|
||||||
}
|
}
|
||||||
|
/*"skipJsErrors": true,
|
||||||
|
"clientScripts": [ { "content": `
|
||||||
|
window.addEventListener('error', function (e) {
|
||||||
|
if (e instanceof Error && e.message.includes('_jp')) {
|
||||||
|
console.log('Ignoring sockjs related error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
` } ]*/
|
||||||
}
|
}
|
||||||
|
5
tests/Dockerfile
Normal file
5
tests/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
FROM testcafe/testcafe:1.17.1
|
||||||
|
|
||||||
|
USER root
|
||||||
|
RUN apk add docker-compose
|
||||||
|
USER user
|
734
tests/package-lock.json
generated
734
tests/package-lock.json
generated
@ -4,7 +4,13 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
||||||
|
"@types/dockerode": "^3.3.0",
|
||||||
|
"axios": "^0.24.0"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"dockerode": "^3.3.1",
|
||||||
"testcafe": "^1.17.1"
|
"testcafe": "^1.17.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1804,6 +1810,123 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/darwin-arm64": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-arm64/-/darwin-arm64-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-hYqTiP63mXz7wSQfuqfFwfLOfwwFChUedeCVKkBtl/cliaTM7/ePI9bVzfZ2c+dWu3TqCwLDRWNSJ5pqZl8otA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/darwin-x64": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-x64/-/darwin-x64-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Z4EyG3cIFjdhlY8wI9aLUXuH8nVt7E9SlMVZtWvSPnm2sm37/yC2CwjUzyCQbJbySnef1tQwGG2Sx+uWhd9IAw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/ffmpeg": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/ffmpeg/-/ffmpeg-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-Uq4rmwkdGxIa9A6Bd/VqqYbT7zqh1GrT5/rFwCwKM70b42W5gIjWeVETq6SdcL0zXqDtY081Ws/iJWhr1+xvQg==",
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@ffmpeg-installer/darwin-arm64": "4.1.5",
|
||||||
|
"@ffmpeg-installer/darwin-x64": "4.1.0",
|
||||||
|
"@ffmpeg-installer/linux-arm": "4.1.3",
|
||||||
|
"@ffmpeg-installer/linux-arm64": "4.1.4",
|
||||||
|
"@ffmpeg-installer/linux-ia32": "4.1.0",
|
||||||
|
"@ffmpeg-installer/linux-x64": "4.1.0",
|
||||||
|
"@ffmpeg-installer/win32-ia32": "4.1.0",
|
||||||
|
"@ffmpeg-installer/win32-x64": "4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/linux-arm": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm/-/linux-arm-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-NDf5V6l8AfzZ8WzUGZ5mV8O/xMzRag2ETR6+TlGIsMHp81agx51cqpPItXPib/nAZYmo55Bl2L6/WOMI3A5YRg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/linux-arm64": {
|
||||||
|
"version": "4.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm64/-/linux-arm64-4.1.4.tgz",
|
||||||
|
"integrity": "sha512-dljEqAOD0oIM6O6DxBW9US/FkvqvQwgJ2lGHOwHDDwu/pX8+V0YsDL1xqHbj1DMX/+nP9rxw7G7gcUvGspSoKg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/linux-ia32": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-ia32/-/linux-ia32-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-0LWyFQnPf+Ij9GQGD034hS6A90URNu9HCtQ5cTqo5MxOEc7Rd8gLXrJvn++UmxhU0J5RyRE9KRYstdCVUjkNOQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/linux-x64": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-x64/-/linux-x64-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Y5BWhGLU/WpQjOArNIgXD3z5mxxdV8c41C+U15nsE5yF8tVcdCGet5zPs5Zy3Ta6bU7haGpIzryutqCGQA/W8A==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/win32-ia32": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-ia32/-/win32-ia32-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-FV2D7RlaZv/lrtdhaQ4oETwoFUsUjlUiasiZLDxhEUPdNDWcH1OU9K1xTvqz+OXLdsmYelUDuBS/zkMOTtlUAw==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@ffmpeg-installer/win32-x64": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-x64/-/win32-x64-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Drt5u2vzDnIONf4ZEkKtFlbvwj6rI3kxw1Ck9fpudmtgaZIHD4ucsWB2lCZBXRxJgXR+2IMSti+4rtM4C4rXgg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/@miherlosev/esm": {
|
"node_modules/@miherlosev/esm": {
|
||||||
"version": "3.2.26",
|
"version": "3.2.26",
|
||||||
"resolved": "https://registry.npmjs.org/@miherlosev/esm/-/esm-3.2.26.tgz",
|
"resolved": "https://registry.npmjs.org/@miherlosev/esm/-/esm-3.2.26.tgz",
|
||||||
@ -1848,6 +1971,24 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/docker-modem": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/docker-modem/-/docker-modem-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-qC7prjoEYR2QEe6SmCVfB1x3rfcQtUr1n4x89+3e0wSTMQ/KYCyf+/RAA9n2tllkkNc6//JMUZePdFRiGIWfaQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/ssh2": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/dockerode": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-3Mc0b2gnypJB8Gwmr+8UVPkwjpf4kg1gVxw8lAI4Y/EzpK50LixU1wBSPN9D+xqiw2Ubb02JO8oM0xpwzvi2mg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/docker-modem": "*",
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/error-stack-parser": {
|
"node_modules/@types/error-stack-parser": {
|
||||||
"version": "1.3.18",
|
"version": "1.3.18",
|
||||||
"resolved": "https://registry.npmjs.org/@types/error-stack-parser/-/error-stack-parser-1.3.18.tgz",
|
"resolved": "https://registry.npmjs.org/@types/error-stack-parser/-/error-stack-parser-1.3.18.tgz",
|
||||||
@ -1885,8 +2026,24 @@
|
|||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "12.20.37",
|
"version": "12.20.37",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.37.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.37.tgz",
|
||||||
"integrity": "sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA==",
|
"integrity": "sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA=="
|
||||||
"dev": true
|
},
|
||||||
|
"node_modules/@types/ssh2": {
|
||||||
|
"version": "0.5.49",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-0.5.49.tgz",
|
||||||
|
"integrity": "sha512-ffxhQhJqgTzrw8NxHTgkaDtAmAj2qxCyoves7ztpRgqvzbHcZTpTcm+ATWuuCbPQzxnnF4F3SGGTLGEWTZpwqA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/ssh2-streams": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/ssh2-streams": {
|
||||||
|
"version": "0.1.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ssh2-streams/-/ssh2-streams-0.1.9.tgz",
|
||||||
|
"integrity": "sha512-I2J9jKqfmvXLR5GomDiCoHrEJ58hAOmFrekfFqmCFd+A6gaEStvWnPykoWUwld1PNg4G5ag1LwdA+Lz1doRJqg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn-hammerhead": {
|
"node_modules/acorn-hammerhead": {
|
||||||
"version": "0.5.0",
|
"version": "0.5.0",
|
||||||
@ -2012,6 +2169,15 @@
|
|||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/asn1": {
|
||||||
|
"version": "0.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
|
||||||
|
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"safer-buffer": "~2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/assertion-error": {
|
"node_modules/assertion-error": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
|
||||||
@ -2048,6 +2214,14 @@
|
|||||||
"node": ">= 4.5.0"
|
"node": ">= 4.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "0.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||||
|
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.14.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/babel-plugin-dynamic-import-node": {
|
"node_modules/babel-plugin-dynamic-import-node": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
|
||||||
@ -2153,12 +2327,46 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/bcrypt-pbkdf": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tweetnacl": "^0.14.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/bin-v8-flags-filter": {
|
"node_modules/bin-v8-flags-filter": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/bin-v8-flags-filter/-/bin-v8-flags-filter-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/bin-v8-flags-filter/-/bin-v8-flags-filter-1.2.0.tgz",
|
||||||
"integrity": "sha512-g8aeYkY7GhyyKRvQMBsJQZjhm2iCX3dKYvfrMpwVR8IxmUGrkpCBFoKbB9Rh0o3sTLCjU/1tFpZ4C7j3f+D+3g==",
|
"integrity": "sha512-g8aeYkY7GhyyKRvQMBsJQZjhm2iCX3dKYvfrMpwVR8IxmUGrkpCBFoKbB9Rh0o3sTLCjU/1tFpZ4C7j3f+D+3g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/bl": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"buffer": "^5.5.0",
|
||||||
|
"inherits": "^2.0.4",
|
||||||
|
"readable-stream": "^3.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bl/node_modules/readable-stream": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/bluebird": {
|
"node_modules/bluebird": {
|
||||||
"version": "3.7.2",
|
"version": "3.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||||
@ -2225,6 +2433,30 @@
|
|||||||
"url": "https://opencollective.com/browserslist"
|
"url": "https://opencollective.com/browserslist"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.1.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/buffer-from": {
|
"node_modules/buffer-from": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
@ -2319,6 +2551,12 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chownr": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/chrome-remote-interface": {
|
"node_modules/chrome-remote-interface": {
|
||||||
"version": "0.30.1",
|
"version": "0.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.30.1.tgz",
|
"resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.30.1.tgz",
|
||||||
@ -2449,6 +2687,20 @@
|
|||||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/cpu-features": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-/2yieBqvMcRj8McNzkycjW2v3OIUOibBfd2dLEJ0nWts8NobAxwiyw9phVNS6oDL8x8tz9F7uNVFEVpJncQpeA==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"nan": "^2.14.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
@ -2649,6 +2901,60 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/docker-modem": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-Tgkn2a+yiNP9FoZgMa/D9Wk+D2Db///0KOyKSYZRJa8w4+DzKyzQMkczKSdR/adQ0x46BOpeNkoyEOKjPhCzjw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"readable-stream": "^3.5.0",
|
||||||
|
"split-ca": "^1.0.1",
|
||||||
|
"ssh2": "^1.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/docker-modem/node_modules/readable-stream": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dockerode": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-AS2mr8Lp122aa5n6d99HkuTNdRV1wkkhHwBdcnY6V0+28D3DSYwhxAk85/mM9XwD3RMliTxyr63iuvn5ZblFYQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"docker-modem": "^3.0.0",
|
||||||
|
"tar-fs": "~2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dockerode/node_modules/tar-fs": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"chownr": "^1.1.1",
|
||||||
|
"mkdirp-classic": "^0.5.2",
|
||||||
|
"pump": "^3.0.0",
|
||||||
|
"tar-stream": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.3.906",
|
"version": "1.3.906",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.906.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.906.tgz",
|
||||||
@ -2852,6 +3158,31 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
|
||||||
|
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fs-constants": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/fs.realpath": {
|
"node_modules/fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
@ -3100,6 +3431,26 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ieee754": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.1.9",
|
"version": "5.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz",
|
||||||
@ -3549,6 +3900,12 @@
|
|||||||
"mkdirp": "bin/cmd.js"
|
"mkdirp": "bin/cmd.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mkdirp-classic": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||||
|
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/moment": {
|
"node_modules/moment": {
|
||||||
"version": "2.29.1",
|
"version": "2.29.1",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||||
@ -3582,6 +3939,13 @@
|
|||||||
"npm": ">=1.4.0"
|
"npm": ">=1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nan": {
|
||||||
|
"version": "2.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
|
||||||
|
"integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "1.3.4",
|
"version": "1.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-1.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-1.3.4.tgz",
|
||||||
@ -4281,6 +4645,30 @@
|
|||||||
"integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
|
"integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/split-ca": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/ssh2": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-iUmRkhH9KGeszQwDW7YyyqjsMTf4z+0o48Cp4xOwlY5LjtbIAvyd3fwnsoUZW/hXmTCRA3yt7S/Jb9uVjErVlA==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"asn1": "^0.2.4",
|
||||||
|
"bcrypt-pbkdf": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.16.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"cpu-features": "0.0.2",
|
||||||
|
"nan": "^2.15.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/stackframe": {
|
"node_modules/stackframe": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-0.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-0.3.1.tgz",
|
||||||
@ -4355,6 +4743,36 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tar-stream": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"bl": "^4.0.3",
|
||||||
|
"end-of-stream": "^1.4.1",
|
||||||
|
"fs-constants": "^1.0.0",
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"readable-stream": "^3.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar-stream/node_modules/readable-stream": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/testcafe": {
|
"node_modules/testcafe": {
|
||||||
"version": "1.17.1",
|
"version": "1.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/testcafe/-/testcafe-1.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/testcafe/-/testcafe-1.17.1.tgz",
|
||||||
@ -4889,6 +5307,12 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tweetnacl": {
|
||||||
|
"version": "0.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||||
|
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/type-detect": {
|
"node_modules/type-detect": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||||
@ -6330,6 +6754,69 @@
|
|||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@ffmpeg-installer/darwin-arm64": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-arm64/-/darwin-arm64-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-hYqTiP63mXz7wSQfuqfFwfLOfwwFChUedeCVKkBtl/cliaTM7/ePI9bVzfZ2c+dWu3TqCwLDRWNSJ5pqZl8otA==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@ffmpeg-installer/darwin-x64": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-x64/-/darwin-x64-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Z4EyG3cIFjdhlY8wI9aLUXuH8nVt7E9SlMVZtWvSPnm2sm37/yC2CwjUzyCQbJbySnef1tQwGG2Sx+uWhd9IAw==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@ffmpeg-installer/ffmpeg": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/ffmpeg/-/ffmpeg-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-Uq4rmwkdGxIa9A6Bd/VqqYbT7zqh1GrT5/rFwCwKM70b42W5gIjWeVETq6SdcL0zXqDtY081Ws/iJWhr1+xvQg==",
|
||||||
|
"requires": {
|
||||||
|
"@ffmpeg-installer/darwin-arm64": "4.1.5",
|
||||||
|
"@ffmpeg-installer/darwin-x64": "4.1.0",
|
||||||
|
"@ffmpeg-installer/linux-arm": "4.1.3",
|
||||||
|
"@ffmpeg-installer/linux-arm64": "4.1.4",
|
||||||
|
"@ffmpeg-installer/linux-ia32": "4.1.0",
|
||||||
|
"@ffmpeg-installer/linux-x64": "4.1.0",
|
||||||
|
"@ffmpeg-installer/win32-ia32": "4.1.0",
|
||||||
|
"@ffmpeg-installer/win32-x64": "4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ffmpeg-installer/linux-arm": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm/-/linux-arm-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-NDf5V6l8AfzZ8WzUGZ5mV8O/xMzRag2ETR6+TlGIsMHp81agx51cqpPItXPib/nAZYmo55Bl2L6/WOMI3A5YRg==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@ffmpeg-installer/linux-arm64": {
|
||||||
|
"version": "4.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm64/-/linux-arm64-4.1.4.tgz",
|
||||||
|
"integrity": "sha512-dljEqAOD0oIM6O6DxBW9US/FkvqvQwgJ2lGHOwHDDwu/pX8+V0YsDL1xqHbj1DMX/+nP9rxw7G7gcUvGspSoKg==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@ffmpeg-installer/linux-ia32": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-ia32/-/linux-ia32-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-0LWyFQnPf+Ij9GQGD034hS6A90URNu9HCtQ5cTqo5MxOEc7Rd8gLXrJvn++UmxhU0J5RyRE9KRYstdCVUjkNOQ==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@ffmpeg-installer/linux-x64": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-x64/-/linux-x64-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Y5BWhGLU/WpQjOArNIgXD3z5mxxdV8c41C+U15nsE5yF8tVcdCGet5zPs5Zy3Ta6bU7haGpIzryutqCGQA/W8A==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@ffmpeg-installer/win32-ia32": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-ia32/-/win32-ia32-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-FV2D7RlaZv/lrtdhaQ4oETwoFUsUjlUiasiZLDxhEUPdNDWcH1OU9K1xTvqz+OXLdsmYelUDuBS/zkMOTtlUAw==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@ffmpeg-installer/win32-x64": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-x64/-/win32-x64-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Drt5u2vzDnIONf4ZEkKtFlbvwj6rI3kxw1Ck9fpudmtgaZIHD4ucsWB2lCZBXRxJgXR+2IMSti+4rtM4C4rXgg==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"@miherlosev/esm": {
|
"@miherlosev/esm": {
|
||||||
"version": "3.2.26",
|
"version": "3.2.26",
|
||||||
"resolved": "https://registry.npmjs.org/@miherlosev/esm/-/esm-3.2.26.tgz",
|
"resolved": "https://registry.npmjs.org/@miherlosev/esm/-/esm-3.2.26.tgz",
|
||||||
@ -6362,6 +6849,24 @@
|
|||||||
"fastq": "^1.6.0"
|
"fastq": "^1.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/docker-modem": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/docker-modem/-/docker-modem-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-qC7prjoEYR2QEe6SmCVfB1x3rfcQtUr1n4x89+3e0wSTMQ/KYCyf+/RAA9n2tllkkNc6//JMUZePdFRiGIWfaQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/ssh2": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/dockerode": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-3Mc0b2gnypJB8Gwmr+8UVPkwjpf4kg1gVxw8lAI4Y/EzpK50LixU1wBSPN9D+xqiw2Ubb02JO8oM0xpwzvi2mg==",
|
||||||
|
"requires": {
|
||||||
|
"@types/docker-modem": "*",
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/error-stack-parser": {
|
"@types/error-stack-parser": {
|
||||||
"version": "1.3.18",
|
"version": "1.3.18",
|
||||||
"resolved": "https://registry.npmjs.org/@types/error-stack-parser/-/error-stack-parser-1.3.18.tgz",
|
"resolved": "https://registry.npmjs.org/@types/error-stack-parser/-/error-stack-parser-1.3.18.tgz",
|
||||||
@ -6399,8 +6904,24 @@
|
|||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "12.20.37",
|
"version": "12.20.37",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.37.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.37.tgz",
|
||||||
"integrity": "sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA==",
|
"integrity": "sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA=="
|
||||||
"dev": true
|
},
|
||||||
|
"@types/ssh2": {
|
||||||
|
"version": "0.5.49",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-0.5.49.tgz",
|
||||||
|
"integrity": "sha512-ffxhQhJqgTzrw8NxHTgkaDtAmAj2qxCyoves7ztpRgqvzbHcZTpTcm+ATWuuCbPQzxnnF4F3SGGTLGEWTZpwqA==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/ssh2-streams": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/ssh2-streams": {
|
||||||
|
"version": "0.1.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ssh2-streams/-/ssh2-streams-0.1.9.tgz",
|
||||||
|
"integrity": "sha512-I2J9jKqfmvXLR5GomDiCoHrEJ58hAOmFrekfFqmCFd+A6gaEStvWnPykoWUwld1PNg4G5ag1LwdA+Lz1doRJqg==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"acorn-hammerhead": {
|
"acorn-hammerhead": {
|
||||||
"version": "0.5.0",
|
"version": "0.5.0",
|
||||||
@ -6498,6 +7019,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"asn1": {
|
||||||
|
"version": "0.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
|
||||||
|
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"safer-buffer": "~2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"assertion-error": {
|
"assertion-error": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
|
||||||
@ -6522,6 +7052,14 @@
|
|||||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"axios": {
|
||||||
|
"version": "0.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||||
|
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||||
|
"requires": {
|
||||||
|
"follow-redirects": "^1.14.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"babel-plugin-dynamic-import-node": {
|
"babel-plugin-dynamic-import-node": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
|
||||||
@ -6600,12 +7138,45 @@
|
|||||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"bcrypt-pbkdf": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"tweetnacl": "^0.14.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"bin-v8-flags-filter": {
|
"bin-v8-flags-filter": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/bin-v8-flags-filter/-/bin-v8-flags-filter-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/bin-v8-flags-filter/-/bin-v8-flags-filter-1.2.0.tgz",
|
||||||
"integrity": "sha512-g8aeYkY7GhyyKRvQMBsJQZjhm2iCX3dKYvfrMpwVR8IxmUGrkpCBFoKbB9Rh0o3sTLCjU/1tFpZ4C7j3f+D+3g==",
|
"integrity": "sha512-g8aeYkY7GhyyKRvQMBsJQZjhm2iCX3dKYvfrMpwVR8IxmUGrkpCBFoKbB9Rh0o3sTLCjU/1tFpZ4C7j3f+D+3g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"bl": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"buffer": "^5.5.0",
|
||||||
|
"inherits": "^2.0.4",
|
||||||
|
"readable-stream": "^3.4.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"bluebird": {
|
"bluebird": {
|
||||||
"version": "3.7.2",
|
"version": "3.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||||
@ -6659,6 +7230,16 @@
|
|||||||
"picocolors": "^1.0.0"
|
"picocolors": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"buffer": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.1.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
"buffer-from": {
|
"buffer-from": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
@ -6734,6 +7315,12 @@
|
|||||||
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
|
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"chownr": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"chrome-remote-interface": {
|
"chrome-remote-interface": {
|
||||||
"version": "0.30.1",
|
"version": "0.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.30.1.tgz",
|
"resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.30.1.tgz",
|
||||||
@ -6842,6 +7429,16 @@
|
|||||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"cpu-features": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-/2yieBqvMcRj8McNzkycjW2v3OIUOibBfd2dLEJ0nWts8NobAxwiyw9phVNS6oDL8x8tz9F7uNVFEVpJncQpeA==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"nan": "^2.14.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"cross-spawn": {
|
"cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
@ -7000,6 +7597,55 @@
|
|||||||
"path-type": "^4.0.0"
|
"path-type": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"docker-modem": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-Tgkn2a+yiNP9FoZgMa/D9Wk+D2Db///0KOyKSYZRJa8w4+DzKyzQMkczKSdR/adQ0x46BOpeNkoyEOKjPhCzjw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"readable-stream": "^3.5.0",
|
||||||
|
"split-ca": "^1.0.1",
|
||||||
|
"ssh2": "^1.4.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dockerode": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-AS2mr8Lp122aa5n6d99HkuTNdRV1wkkhHwBdcnY6V0+28D3DSYwhxAk85/mM9XwD3RMliTxyr63iuvn5ZblFYQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"docker-modem": "^3.0.0",
|
||||||
|
"tar-fs": "~2.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tar-fs": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chownr": "^1.1.1",
|
||||||
|
"mkdirp-classic": "^0.5.2",
|
||||||
|
"pump": "^3.0.0",
|
||||||
|
"tar-stream": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.3.906",
|
"version": "1.3.906",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.906.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.906.tgz",
|
||||||
@ -7165,6 +7811,17 @@
|
|||||||
"locate-path": "^3.0.0"
|
"locate-path": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"follow-redirects": {
|
||||||
|
"version": "1.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
|
||||||
|
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA=="
|
||||||
|
},
|
||||||
|
"fs-constants": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"fs.realpath": {
|
"fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
@ -7357,6 +8014,12 @@
|
|||||||
"safer-buffer": ">= 2.1.2 < 3"
|
"safer-buffer": ">= 2.1.2 < 3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ieee754": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ignore": {
|
"ignore": {
|
||||||
"version": "5.1.9",
|
"version": "5.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz",
|
||||||
@ -7699,6 +8362,12 @@
|
|||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mkdirp-classic": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||||
|
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.29.1",
|
"version": "2.29.1",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||||
@ -7723,6 +8392,13 @@
|
|||||||
"integrity": "sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ==",
|
"integrity": "sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"nan": {
|
||||||
|
"version": "2.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
|
||||||
|
"integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "1.3.4",
|
"version": "1.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-1.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-1.3.4.tgz",
|
||||||
@ -8257,6 +8933,24 @@
|
|||||||
"integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
|
"integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"split-ca": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"ssh2": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-iUmRkhH9KGeszQwDW7YyyqjsMTf4z+0o48Cp4xOwlY5LjtbIAvyd3fwnsoUZW/hXmTCRA3yt7S/Jb9uVjErVlA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"asn1": "^0.2.4",
|
||||||
|
"bcrypt-pbkdf": "^1.0.2",
|
||||||
|
"cpu-features": "0.0.2",
|
||||||
|
"nan": "^2.15.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"stackframe": {
|
"stackframe": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-0.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-0.3.1.tgz",
|
||||||
@ -8316,6 +9010,32 @@
|
|||||||
"has-flag": "^3.0.0"
|
"has-flag": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tar-stream": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"bl": "^4.0.3",
|
||||||
|
"end-of-stream": "^1.4.1",
|
||||||
|
"fs-constants": "^1.0.0",
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"readable-stream": "^3.1.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"testcafe": {
|
"testcafe": {
|
||||||
"version": "1.17.1",
|
"version": "1.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/testcafe/-/testcafe-1.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/testcafe/-/testcafe-1.17.1.tgz",
|
||||||
@ -8772,6 +9492,12 @@
|
|||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tweetnacl": {
|
||||||
|
"version": "0.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||||
|
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"type-detect": {
|
"type-detect": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
{
|
{
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"dockerode": "^3.3.1",
|
||||||
"testcafe": "^1.17.1"
|
"testcafe": "^1.17.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "testcafe"
|
"test": "testcafe"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
||||||
|
"@types/dockerode": "^3.3.0",
|
||||||
|
"axios": "^0.24.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,38 @@
|
|||||||
import {assertLogMessage} from "./utils/log";
|
import {assertLogMessage} from "./utils/log";
|
||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs');
|
||||||
|
const Docker = require('dockerode');
|
||||||
import { Selector } from 'testcafe';
|
import { Selector } from 'testcafe';
|
||||||
import {userAlice} from "./utils/roles";
|
import {login} from "./utils/roles";
|
||||||
|
import {findContainer, rebootBack, rebootPusher, resetRedis, startContainer, stopContainer} from "./utils/containers";
|
||||||
|
|
||||||
// Note: we are also testing that we can connect if the URL contains a random query string
|
fixture `Reconnection`
|
||||||
fixture `Variables`
|
.page `http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/mousewheel.json`;
|
||||||
.page `http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/Cache/variables_tmp.json?somerandomparam=1`;
|
|
||||||
|
|
||||||
|
test("Test that connection can succeed even if WorkAdventure starts while pusher is down", async (t: TestController) => {
|
||||||
|
// Let's stop the pusher
|
||||||
|
const container = await findContainer('pusher');
|
||||||
|
await stopContainer(container);
|
||||||
|
|
||||||
|
const errorMessage = Selector('.error-div');
|
||||||
|
|
||||||
|
await t
|
||||||
|
.navigateTo('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/mousewheel.json')
|
||||||
|
.expect(errorMessage.innerText).contains('Unable to connect to WorkAdventure')
|
||||||
|
|
||||||
|
await startContainer(container);
|
||||||
|
|
||||||
|
await login(t, 'http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/mousewheel.json');
|
||||||
|
|
||||||
|
t.ctx.passed = true;
|
||||||
|
}).after(async t => {
|
||||||
|
if (!t.ctx.passed) {
|
||||||
|
console.log("Test failed. Browser logs:")
|
||||||
|
console.log(await t.getBrowserConsoleMessages());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
test("Test that variables cache in the back don't prevent setting a variable in case the map changes", async (t: TestController) => {
|
test("Test that variables cache in the back don't prevent setting a variable in case the map changes", async (t: TestController) => {
|
||||||
// Let's start by visiting a map that DOES not have the variable.
|
// Let's start by visiting a map that DOES not have the variable.
|
||||||
fs.copyFileSync('../maps/tests/Variables/Cache/variables_cache_1.json', '../maps/tests/Variables/Cache/variables_tmp.json');
|
fs.copyFileSync('../maps/tests/Variables/Cache/variables_cache_1.json', '../maps/tests/Variables/Cache/variables_tmp.json');
|
||||||
@ -18,11 +43,9 @@ test("Test that variables cache in the back don't prevent setting a variable in
|
|||||||
// Let's REPLACE the map by a map that has a new variable
|
// Let's REPLACE the map by a map that has a new variable
|
||||||
// At this point, the back server contains a cache of the old map (with no variables)
|
// At this point, the back server contains a cache of the old map (with no variables)
|
||||||
fs.copyFileSync('../maps/tests/Variables/Cache/variables_cache_2.json', '../maps/tests/Variables/Cache/variables_tmp.json');
|
fs.copyFileSync('../maps/tests/Variables/Cache/variables_cache_2.json', '../maps/tests/Variables/Cache/variables_tmp.json');
|
||||||
await t.openWindow('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/Cache/variables_tmp.json');
|
await t.openWindow('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/Cache/variables_tmp.json')
|
||||||
|
.resizeWindow(960, 800)
|
||||||
await t.resizeWindow(960, 800);
|
.useRole(userAlice);
|
||||||
|
|
||||||
await t.useRole(userAlice);
|
|
||||||
//.takeScreenshot('after_switch.png');
|
//.takeScreenshot('after_switch.png');
|
||||||
|
|
||||||
// Let's check we successfully manage to save the variable value.
|
// Let's check we successfully manage to save the variable value.
|
||||||
@ -35,3 +58,4 @@ test("Test that variables cache in the back don't prevent setting a variable in
|
|||||||
console.log(await t.getBrowserConsoleMessages());
|
console.log(await t.getBrowserConsoleMessages());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
*/
|
85
tests/tests/utils/containers.ts
Normal file
85
tests/tests/utils/containers.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
//import Docker from "dockerode";
|
||||||
|
//import * as Dockerode from "dockerode";
|
||||||
|
import Dockerode = require( 'dockerode')
|
||||||
|
const util = require('util');
|
||||||
|
const exec = util.promisify(require('child_process').exec);
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
const path = require("path");
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute Docker compose, passing the correct host directory (in case this is run from the TestCafe container)
|
||||||
|
*/
|
||||||
|
export function dockerCompose(command: string): void {
|
||||||
|
let param = '';
|
||||||
|
const projectDir = process.env.PROJECT_DIR;
|
||||||
|
|
||||||
|
if (!projectDir && fs.existsSync('/project')) {
|
||||||
|
// We are probably in the docker-image AND we did not pass PROJECT_DIR env variable
|
||||||
|
throw new Error('Incorrect docker-compose command used to fire testcafe tests. You need to add a PROJECT_DIR environment variable. Please refer to the CONTRIBUTING.md guide');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectDir) {
|
||||||
|
const dirName = path.basename(projectDir);
|
||||||
|
param = '--project-name '+dirName+' --project-directory '+projectDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stdout = execSync('docker-compose '+param+' '+command, {
|
||||||
|
cwd: __dirname + '/../../../'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a container ID based on the container name.
|
||||||
|
*/
|
||||||
|
export async function findContainer(name: string): Promise<Dockerode.ContainerInfo> {
|
||||||
|
const docker = new Dockerode();
|
||||||
|
|
||||||
|
const containers = await docker.listContainers();
|
||||||
|
|
||||||
|
const foundContainer = containers.find((container) => container.State === 'running' && container.Names.find((containerName) => containerName.includes(name)));
|
||||||
|
|
||||||
|
if (foundContainer === undefined) {
|
||||||
|
throw new Error('Could not find a running container whose name contains "'+name+'"');
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function stopContainer(container: Dockerode.ContainerInfo): Promise<void> {
|
||||||
|
const docker = new Dockerode();
|
||||||
|
|
||||||
|
await docker.getContainer(container.Id).stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function startContainer(container: Dockerode.ContainerInfo): Promise<void> {
|
||||||
|
const docker = new Dockerode();
|
||||||
|
|
||||||
|
await docker.getContainer(container.Id).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function rebootBack(): Promise<void> {
|
||||||
|
dockerCompose('up --force-recreate -d back');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rebootTraefik(): void {
|
||||||
|
dockerCompose('up --force-recreate -d reverse-proxy');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function rebootPusher(): Promise<void> {
|
||||||
|
dockerCompose('up --force-recreate -d pusher');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function resetRedis(): Promise<void> {
|
||||||
|
dockerCompose('stop redis');
|
||||||
|
dockerCompose('rm -f redis');
|
||||||
|
dockerCompose('up --force-recreate -d redis');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopRedis(): void {
|
||||||
|
dockerCompose('stop redis');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function startRedis(): void {
|
||||||
|
dockerCompose('start redis');
|
||||||
|
}
|
31
tests/tests/utils/debug.ts
Normal file
31
tests/tests/utils/debug.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN;
|
||||||
|
|
||||||
|
export async function getPusherDump(): Promise<any> {
|
||||||
|
let url = 'http://pusher.workadventure.localhost/dump?token='+ADMIN_API_TOKEN;
|
||||||
|
if (fs.existsSync('/project')) {
|
||||||
|
// We are inside a container. Let's use a direct route
|
||||||
|
url = 'http://pusher:8080/dump?token='+ADMIN_API_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await axios({
|
||||||
|
url,
|
||||||
|
method: 'get',
|
||||||
|
})).data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getBackDump(): Promise<any> {
|
||||||
|
let url = 'http://api.workadventure.localhost/dump?token='+ADMIN_API_TOKEN;
|
||||||
|
if (fs.existsSync('/project')) {
|
||||||
|
// We are inside a container. Let's use a direct route
|
||||||
|
url = 'http://back:8080/dump?token='+ADMIN_API_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await axios({
|
||||||
|
url,
|
||||||
|
method: 'get',
|
||||||
|
})).data;
|
||||||
|
}
|
||||||
|
|
@ -1,20 +1,15 @@
|
|||||||
import { Role } from 'testcafe';
|
import { Role } from 'testcafe';
|
||||||
|
|
||||||
export const userAlice = Role('http://play.workadventure.localhost/', async t => {
|
export function login(t: TestController, url: string, userName: string = "Alice", characterNumber: number = 2) {
|
||||||
await t
|
t = t
|
||||||
.typeText('input[name="loginSceneName"]', 'Alice')
|
.navigateTo(url)
|
||||||
.click('button.loginSceneFormSubmit')
|
.typeText('input[name="loginSceneName"]', userName)
|
||||||
.click('button.selectCharacterButtonRight')
|
.click('button.loginSceneFormSubmit');
|
||||||
.click('button.selectCharacterButtonRight')
|
|
||||||
.click('button.selectCharacterSceneFormSubmit')
|
|
||||||
.click('button.letsgo');
|
|
||||||
});
|
|
||||||
|
|
||||||
export const userBob = Role('http://play.workadventure.localhost/', async t => {
|
for (let i = 0; i < characterNumber; i++) {
|
||||||
await t
|
t = t.click('button.selectCharacterButtonRight');
|
||||||
.typeText('input[name="loginSceneName"]', 'Bob')
|
}
|
||||||
.click('button.loginSceneFormSubmit')
|
|
||||||
.click('button.selectCharacterButtonRight')
|
return t.click('button.selectCharacterSceneFormSubmit')
|
||||||
.click('button.selectCharacterSceneFormSubmit')
|
|
||||||
.click('button.letsgo');
|
.click('button.letsgo');
|
||||||
});
|
}
|
||||||
|
202
tests/tests/variables.ts
Normal file
202
tests/tests/variables.ts
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
import {assertLogMessage} from "./utils/log";
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const Docker = require('dockerode');
|
||||||
|
import { Selector } from 'testcafe';
|
||||||
|
import {login} from "./utils/roles";
|
||||||
|
import {
|
||||||
|
findContainer,
|
||||||
|
rebootBack,
|
||||||
|
rebootPusher,
|
||||||
|
resetRedis,
|
||||||
|
rebootTraefik,
|
||||||
|
startContainer,
|
||||||
|
stopContainer, stopRedis, startRedis
|
||||||
|
} from "./utils/containers";
|
||||||
|
import {getBackDump, getPusherDump} from "./utils/debug";
|
||||||
|
|
||||||
|
// Note: we are also testing that passing a random query parameter does not cause any issue.
|
||||||
|
fixture `Variables`
|
||||||
|
.page `http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json?somerandomparam=1`;
|
||||||
|
|
||||||
|
test("Test that variables storage works", async (t: TestController) => {
|
||||||
|
|
||||||
|
const variableInput = Selector('#textField');
|
||||||
|
|
||||||
|
await resetRedis();
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
rebootBack(),
|
||||||
|
rebootPusher(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
//const mainWindow = await t.getCurrentWindow();
|
||||||
|
|
||||||
|
await login(t, 'http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json?somerandomparam=1');
|
||||||
|
|
||||||
|
await t //.useRole(userAliceOnPage('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json?somerandomparam=1'))
|
||||||
|
.switchToIframe("#cowebsite-buffer iframe")
|
||||||
|
.expect(variableInput.value).eql('default value')
|
||||||
|
.selectText(variableInput)
|
||||||
|
.pressKey('delete')
|
||||||
|
.typeText(variableInput, 'new value')
|
||||||
|
.pressKey('tab')
|
||||||
|
.switchToMainWindow()
|
||||||
|
//.switchToWindow(mainWindow)
|
||||||
|
.wait(500)
|
||||||
|
// reload
|
||||||
|
.navigateTo('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json')
|
||||||
|
.switchToIframe("#cowebsite-buffer iframe")
|
||||||
|
.expect(variableInput.value).eql('new value')
|
||||||
|
//.debug()
|
||||||
|
.switchToMainWindow()
|
||||||
|
//.wait(5000)
|
||||||
|
//.switchToWindow(mainWindow)
|
||||||
|
/*
|
||||||
|
.wait(5000)
|
||||||
|
//.debug()
|
||||||
|
.switchToIframe("#cowebsite-buffer iframe")
|
||||||
|
.expect(variableInput.value).eql('new value')
|
||||||
|
.switchToMainWindow();*/
|
||||||
|
|
||||||
|
// Now, let's kill the reverse proxy to cut the connexion
|
||||||
|
//console.log('Rebooting traefik');
|
||||||
|
rebootTraefik();
|
||||||
|
//console.log('Rebooting done');
|
||||||
|
|
||||||
|
// Maybe we should:
|
||||||
|
// 1: stop Traefik
|
||||||
|
// 2: detect reconnecting screen
|
||||||
|
// 3: start Traefik again
|
||||||
|
|
||||||
|
|
||||||
|
await t
|
||||||
|
.switchToIframe("#cowebsite-buffer iframe")
|
||||||
|
.expect(variableInput.value).eql('new value')
|
||||||
|
|
||||||
|
stopRedis();
|
||||||
|
|
||||||
|
// Redis is stopped, let's try to modify a variable.
|
||||||
|
await t.selectText(variableInput)
|
||||||
|
.pressKey('delete')
|
||||||
|
.typeText(variableInput, 'value set while Redis stopped')
|
||||||
|
.pressKey('tab')
|
||||||
|
.switchToMainWindow()
|
||||||
|
|
||||||
|
startRedis();
|
||||||
|
|
||||||
|
// Navigate to some other map so that the pusher connection is freed.
|
||||||
|
await t.navigateTo('http://maps.workadventure.localhost/tests/')
|
||||||
|
.wait(3000);
|
||||||
|
|
||||||
|
|
||||||
|
const backDump = await getBackDump();
|
||||||
|
//console.log('backDump', backDump);
|
||||||
|
for (const room of backDump) {
|
||||||
|
if (room.roomUrl === 'http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json') {
|
||||||
|
throw new Error('Room still found in back');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pusherDump = await getPusherDump();
|
||||||
|
//console.log('pusherDump', pusherDump);
|
||||||
|
await t.expect(pusherDump['http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json']).eql(undefined);
|
||||||
|
|
||||||
|
await t.navigateTo('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json')
|
||||||
|
.switchToIframe("#cowebsite-buffer iframe")
|
||||||
|
// Redis will reconnect automatically and will store the variable on reconnect!
|
||||||
|
// So we should see the new value.
|
||||||
|
.expect(variableInput.value).eql('value set while Redis stopped')
|
||||||
|
.switchToMainWindow()
|
||||||
|
|
||||||
|
|
||||||
|
// Now, let's try to kill / reboot the back
|
||||||
|
await rebootBack();
|
||||||
|
|
||||||
|
await t.navigateTo('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json')
|
||||||
|
.switchToIframe("#cowebsite-buffer iframe")
|
||||||
|
.expect(variableInput.value).eql('value set while Redis stopped')
|
||||||
|
.selectText(variableInput)
|
||||||
|
.pressKey('delete')
|
||||||
|
.typeText(variableInput, 'value set after back restart')
|
||||||
|
.pressKey('tab')
|
||||||
|
.switchToMainWindow()
|
||||||
|
|
||||||
|
.navigateTo('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json')
|
||||||
|
.switchToIframe("#cowebsite-buffer iframe")
|
||||||
|
// Redis will reconnect automatically and will store the variable on reconnect!
|
||||||
|
// So we should see the new value.
|
||||||
|
.expect(variableInput.value).eql('value set after back restart')
|
||||||
|
.switchToMainWindow()
|
||||||
|
|
||||||
|
// Now, let's try to kill / reboot the back
|
||||||
|
await rebootPusher();
|
||||||
|
|
||||||
|
await t.navigateTo('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json')
|
||||||
|
.switchToIframe("#cowebsite-buffer iframe")
|
||||||
|
.expect(variableInput.value).eql('value set after back restart')
|
||||||
|
.selectText(variableInput)
|
||||||
|
.pressKey('delete')
|
||||||
|
.typeText(variableInput, 'value set after pusher restart')
|
||||||
|
.pressKey('tab')
|
||||||
|
.switchToMainWindow()
|
||||||
|
|
||||||
|
.navigateTo('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/shared_variables.json')
|
||||||
|
.switchToIframe("#cowebsite-buffer iframe")
|
||||||
|
// Redis will reconnect automatically and will store the variable on reconnect!
|
||||||
|
// So we should see the new value.
|
||||||
|
.expect(variableInput.value).eql('value set after pusher restart')
|
||||||
|
.switchToMainWindow()
|
||||||
|
|
||||||
|
|
||||||
|
t.ctx.passed = true;
|
||||||
|
}).after(async t => {
|
||||||
|
if (!t.ctx.passed) {
|
||||||
|
console.log("Test 'Test that variables storage works' failed. Browser logs:")
|
||||||
|
try {
|
||||||
|
console.log(await t.getBrowserConsoleMessages());
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error while fetching browser logs (maybe linked to a closed iframe?)', e);
|
||||||
|
try {
|
||||||
|
console.log('Logs from main window:');
|
||||||
|
console.log(await t.switchToMainWindow().getBrowserConsoleMessages());
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Unable to retrieve logs', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test("Test that variables cache in the back don't prevent setting a variable in case the map changes", async (t: TestController) => {
|
||||||
|
// Let's start by visiting a map that DOES not have the variable.
|
||||||
|
fs.copyFileSync('../maps/tests/Variables/Cache/variables_cache_1.json', '../maps/tests/Variables/Cache/variables_tmp.json');
|
||||||
|
|
||||||
|
//const aliceOnPageTmp = userAliceOnPage('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/Cache/variables_tmp.json');
|
||||||
|
|
||||||
|
await login(t, 'http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/Cache/variables_tmp.json', 'Alice', 2);
|
||||||
|
|
||||||
|
//.takeScreenshot('before_switch.png');
|
||||||
|
|
||||||
|
// Let's REPLACE the map by a map that has a new variable
|
||||||
|
// At this point, the back server contains a cache of the old map (with no variables)
|
||||||
|
fs.copyFileSync('../maps/tests/Variables/Cache/variables_cache_2.json', '../maps/tests/Variables/Cache/variables_tmp.json');
|
||||||
|
await t.openWindow('http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/Cache/variables_tmp.json')
|
||||||
|
.resizeWindow(960, 800)
|
||||||
|
|
||||||
|
await login(t, 'http://play.workadventure.localhost/_/global/maps.workadventure.localhost/tests/Variables/Cache/variables_tmp.json', 'Bob', 3);
|
||||||
|
|
||||||
|
//.takeScreenshot('after_switch.png');
|
||||||
|
|
||||||
|
// Let's check we successfully manage to save the variable value.
|
||||||
|
await assertLogMessage(t, 'SUCCESS!');
|
||||||
|
|
||||||
|
t.ctx.passed = true;
|
||||||
|
}).after(async t => {
|
||||||
|
if (!t.ctx.passed) {
|
||||||
|
console.log("Test 'Test that variables cache in the back don't prevent setting a variable in case the map changes' failed. Browser logs:")
|
||||||
|
console.log(await t.getBrowserConsoleMessages());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user