1
0
Fork 0
mirror of https://github.com/MatomoCamp/workadventure-map.git synced 2024-09-19 16:03:45 +02:00

Merge pull request #4 from GRL78/customize_iframe

Possibility to configure the map
This commit is contained in:
GRL78 2021-08-11 15:18:09 +02:00 committed by GitHub
commit 963a0a99e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 4858 additions and 4694 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
/node_modules/
/dist/
/yarn.lock

View file

@ -25,4 +25,4 @@ terms of use, available online in the following link:
The terms described in the above link have precedence over the terms described
in the present document. In case of disagreement, the Freepik Terms of Use
will prevail.
will prevail.

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

1173
map.json

File diff suppressed because one or more lines are too long

3599
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -4,9 +4,24 @@
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@workadventure/iframe-api-typings": "^1.2.1",
"@tsconfig/svelte": "^1.0.10",
"@types/mini-css-extract-plugin": "^1.4.3",
"@types/webpack-dev-server": "^3.11.4",
"@workadventure/iframe-api-typings": "^1.4.12",
"cross-env": "^7.0.3",
"css-loader": "^5.2.4",
"eslint": "^7.24.0",
"fork-ts-checker-webpack-plugin": "^6.2.9",
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^1.6.0",
"node-polyfill-webpack-plugin": "^1.1.2",
"npm-run-all": "^4.1.5",
"sass": "^1.32.12",
"sass-loader": "^11.1.0",
"svelte": "^3.38.2",
"svelte-check": "^2.1.0",
"svelte-loader": "^3.1.1",
"svelte-preprocess": "^4.7.3",
"ts-loader": "^8.1.0",
"ts-node": "^9.1.1",
"typescript": "^4.2.4",
@ -16,10 +31,17 @@
"webpack-merge": "^5.7.3"
},
"scripts": {
"start": "webpack serve --open",
"build": "webpack --config webpack.prod.js",
"start": "run-p serve svelte-check-watch",
"serve": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" webpack serve --open",
"build": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack.json\" NODE_ENV=production webpack",
"test": "ts-node node_modules/jasmine/bin/jasmine --config=jasmine.json",
"lint": "node_modules/.bin/eslint src/ . --ext .ts",
"fix": "node_modules/.bin/eslint --fix src/ . --ext .ts"
"fix": "node_modules/.bin/eslint --fix src/ . --ext .ts",
"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\""
},
"dependencies": {
"@fontsource/press-start-2p": "^4.5.0",
"nes.css": "^2.3.0"
}
}

59
src/Components/App.svelte Normal file
View file

@ -0,0 +1,59 @@
<script lang="ts">
import ChooseSpace from "./ChooseSpace.svelte";
import Miniature from "./Miniature.svelte";
import type { SvelteComponent } from "svelte";
import type { WorkAdventureApi } from "@workadventure/iframe-api-typings";
import { ConferenceStore } from "../Stores/ConferenceStore";
import { MeetingRoomStore } from "../Stores/MeetingRoomStore";
import { OpenCoWebsiteStore } from "../Stores/OpenCoWebsiteStore";
import { ExitStore } from "../Stores/ExitStore";
import { StartStore } from "../Stores/StartStore";
export let WA: WorkAdventureApi;
let selected: { id: number, label: string, component: typeof SvelteComponent };
function saveMetadata() {
WA.state.conference = $ConferenceStore;
WA.state.meetingRooms = $MeetingRoomStore;
WA.state.receptionWebsite = $OpenCoWebsiteStore;
WA.state.exits = $ExitStore;
WA.state.starts = $StartStore;
}
function cancel() {
WA.nav.closeCoWebSite();
}
</script>
<div class="main-app">
<h1>Configure the room</h1>
<Miniature/>
<ChooseSpace bind:selected={selected} />
{#if selected}
<svelte:component this="{selected.component}" />
{/if}
</div>
<div class="main-app-btn">
<button class="nes-btn" type="button" on:click={cancel}>Cancel</button>
<button class="nes-btn is-primary" type="button" on:click={saveMetadata}>Save</button>
</div>
<style lang="scss">
div.main-app {
h1 {
margin-top: 10px;
margin-bottom: 25px;
text-align: center;
}
}
div.main-app-btn {
margin-top: 10px;
text-align: right;
font-size: 25px;
}
</style>

View file

@ -0,0 +1,26 @@
<script lang="ts">
import ReceptionSpace from "./SpacesComponents/ReceptionSpace.svelte"
import AmphiSpace from "./SpacesComponents/AmphiSpace.svelte"
import MeetingRoomSpace from "./SpacesComponents/MeetingRoomSpace.svelte"
import ExitStartSpace from "./SpacesComponents/ExitStartSpace.svelte"
const spaces = [
{ id: 1, label: "Amphi", component: AmphiSpace },
{ id: 2, label: "Reception", component: ReceptionSpace },
{ id: 3, label: "Meeting Room", component: MeetingRoomSpace },
{ id: 4, label: "Exit/Start", component: ExitStartSpace }
]
export let selected = spaces[0];
</script>
<div class="select nes-select">
<select bind:value={selected}>
{#each spaces as space}
<option value="{space}">
{space.label}
</option>
{/each}
</select>
</div>

View file

@ -0,0 +1,9 @@
/**
* Declare and export the exitConfig interface
*/
export interface ExitConfig {
nameSpace : string,
active: boolean,
url : string,
}

View file

@ -0,0 +1,12 @@
/**
* Declare and export the jitsiConfig interface
*/
export interface JitsiConfig {
nameSpace : string,
roomName: string,
url : string,
audioMute : boolean,
videoMute : boolean,
adminTags : string[],
}

View file

@ -0,0 +1,12 @@
/**
* Declare and export the openCoWebSiteConfig interface
*/
export interface OpenCoWebSiteConfig {
nameSpace : string,
url : string,
active : number,
onaction : boolean,
messageTrigger : string,
fullscreen : boolean,
}

View file

@ -0,0 +1,11 @@
/**
* Declare and export the youtubeConfig interface
*/
export interface YoutubeConfig {
nameSpace : string,
channelID : string,
fullscreen : boolean,
autoplay: boolean,
pictureInPicture : boolean
}

View file

@ -0,0 +1,87 @@
<script lang="ts">
import { MeetingRoomStore } from "../Stores/MeetingRoomStore";
</script>
<div class="img-miniature">
{#if $MeetingRoomStore.nbRooms === 5}
<img src="../../image/mini-config-5-rooms.png" alt="Miniature Configuration with 5 rooms"/>
{/if}
{#if $MeetingRoomStore.nbRooms === 4}
<img src="../../image/mini-config-4-rooms.png" alt="Miniature Configuration with 4 rooms"/>
{/if}
{#if $MeetingRoomStore.nbRooms === 3}
<img src="../../image/mini-config-3-rooms.png" alt="Miniature Configuration with 3 rooms"/>
{/if}
{#if $MeetingRoomStore.nbRooms === 2}
<img src="../../image/mini-config-2-rooms.png" alt="Miniature Configuration with 2 rooms"/>
{/if}
<section class="show-space-Amphi">Amphi</section>
<section class="show-space-MeetingRoom">Meeting Rooms</section>
<section class="show-space-Reception">Reception</section>
</div>
<style lang="scss">
div.img-miniature {
position: relative;
width: 630px;
height: 500px;
text-align: center;
margin-bottom: 25px;
margin-right: auto;
margin-left: auto;
img {
width: 100%;
height: 100%;
}
section {
position: absolute;
border: #006bb3 2px solid;
font-size: 25px;
display: flex;
justify-content: center;
align-items: center;
&.show-space-Amphi {
width: 370px;
height: 325px;
top: 175px;
left: 0;
&:hover {
background: linear-gradient(45deg, rgb(255, 255, 255, .5) 1%, rgb(0, 107, 179, .5) 1%, rgb(0, 107, 179, .5) 49%, rgb(255, 255, 255, .5) 49%, rgb(255, 255, 255, .5) 51%, rgb(0, 107, 179, .5) 51%, rgb(0, 107, 179, .5) 99%, rgb(255, 255, 255, .5) 99%);
background-size: 6px 6px;
}
}
&.show-space-Reception {
width: 152px;
height: 203px;
top: 297px;
left: 478px;
&:hover {
background: linear-gradient(45deg, rgb(255, 255, 255, .5) 1%, rgb(0, 107, 179, .5) 1%, rgb(0, 107, 179, .5) 49%, rgb(255, 255, 255, .5) 49%, rgb(255, 255, 255, .5) 51%, rgb(0, 107, 179, .5) 51%, rgb(0, 107, 179, .5) 99%, rgb(255, 255, 255, .5) 99%);
background-size: 6px 6px;
}
}
&.show-space-MeetingRoom {
width: 630px;
height: 150px;
top: 0;
left: 0;
&:hover {
background: linear-gradient(45deg, rgb(255, 255, 255, .5) 1%, rgb(0, 107, 179, .5) 1%, rgb(0, 107, 179, .5) 49%, rgb(255, 255, 255, .5) 49%, rgb(255, 255, 255, .5) 51%, rgb(0, 107, 179, .5) 51%, rgb(0, 107, 179, .5) 99%, rgb(255, 255, 255, .5) 99%);
background-size: 6px 6px;
}
}
}
}
</style>

View file

@ -0,0 +1,29 @@
<script lang="ts">
import { ExitStore } from "../../Stores/ExitStore";
import { get } from "svelte/store";
export let exitNameSpace: string;
let exitConfig = get(ExitStore).find(e => e.nameSpace == exitNameSpace);
let exitActive = exitConfig ? exitConfig.active : false;
let exitUrl = exitConfig ? exitConfig.url : '';
function changeExit() {
ExitStore.addExit({nameSpace: exitNameSpace, active: exitActive, url: exitUrl});
}
</script>
<div class="nes-container with-title">
<p class="title">{exitNameSpace}</p>
<section on:change={changeExit}>
<label>
<input type="checkbox" class="nes-checkbox" bind:checked={exitActive}>
<span>Enable</span>
</label>
<label class={!exitActive ? "disabled" : ""}>
URL of the next map :
<input type="text" class="nes-input" bind:value={exitUrl} disabled="{!exitActive}">
</label>
</section>
</div>

View file

@ -0,0 +1,48 @@
<script lang="ts">
import type { JitsiConfig } from "../Configs/JitsiConfig";
export let jitsi: JitsiConfig;
let showMore: boolean = false;
</script>
<div class="nes-container with-title">
<p class="title">Jitsi</p>
<h2>{ jitsi.roomName }</h2>
<section>
<label>
Name of the jitsi room :
<input type="text" class="nes-input" bind:value={jitsi.roomName}>
</label>
</section>
<section>
<label>
<input type="checkbox" class="nes-checkbox" bind:checked={jitsi.audioMute}>
<span>Start with audio mute</span>
</label>
<label>
<input type="checkbox" class="nes-checkbox" bind:checked={jitsi.videoMute}>
<span>Start with video mute</span>
</label>
</section>
<section>
<p>You need to have the '{jitsi.adminTags}' tag to be moderator of this jitsi.</p>
</section>
<label class="right">
<input type="checkbox" class="nes-checkbox" bind:checked={showMore}>
<span> More options</span>
</label>
{#if showMore}
<section>
<label>
Url of the jitsi server :
<input type="text" class="nes-input" bind:value={jitsi.url}>
</label>
<p>(If empty the jitsi room will use the default jitsi server of your workadventure version)</p>
</section>
{/if}
</div>

View file

@ -0,0 +1,42 @@
<script lang="ts">
import type { OpenCoWebSiteConfig } from "../Configs/OpenCoWebSiteConfig";
export let openCoWebSite: OpenCoWebSiteConfig
</script>
<div class="nes-container with-title">
<p class="title">OpenCoWebSite</p>
<section class="centered">
<p>Do you want an OpenCoWebSite in your reception ?</p>
<label>
<input type="radio" class="nes-radio" bind:group={openCoWebSite.active} value={1}>
<span>Yes</span>
</label>
<label>
<input type="radio" class="nes-radio" bind:group={openCoWebSite.active} value={0}>
<span>No</span>
</label>
</section>
<section>
<label class={!openCoWebSite.active ? "disabled" : ""}>
URL :
<input type="text" class="nes-input" bind:value={openCoWebSite.url} disabled={!openCoWebSite.active}>
</label>
<label class={!openCoWebSite.active ? "disabled" : ""}>
<input type="checkbox" class="nes-checkbox" bind:checked={openCoWebSite.fullscreen} disabled={!openCoWebSite.active}>
<span>Fullscreen</span>
</label>
</section>
<section>
<label class={!openCoWebSite.active ? "disabled" : ""}>
<input type="checkbox" class="nes-checkbox" bind:checked={openCoWebSite.onaction} disabled={!openCoWebSite.active}>
<span>Trigger by action</span>
</label>
<label class={!openCoWebSite.active || !openCoWebSite.onaction ? "disabled" : ""}>
Message trigger :
<input type="text" class="nes-input" bind:value={openCoWebSite.messageTrigger} disabled={!openCoWebSite.active || !openCoWebSite.onaction}>
</label>
</section>
</div>

View file

@ -0,0 +1,26 @@
<script lang="ts">
import { ExitStore } from "../../Stores/ExitStore";
import { StartStore } from "../../Stores/StartStore";
let starts: string[] = [];
function changeStart(): void {
StartStore.set(starts);
}
</script>
<div class="nes-container with-title">
<p class="title">Start</p>
<p>Choose the entry point of your map. Use #[entry_point] at the end of the url of the map to enter by this entry point.</p>
<p>Default entry will always be 'south'. (even if disable as entry point.)</p>
<form on:change={() => changeStart()}>
{#each $ExitStore as exit}
{#if exit.active }
<label class="chooseStart">
<input type="checkbox" class="nes-checkbox" bind:group={starts} value="{exit.nameSpace}">
<span>{exit.nameSpace}</span>
</label>
{/if}
{/each}
</form>
</div>

View file

@ -0,0 +1,30 @@
<script lang="ts">
import type { YoutubeConfig } from "../Configs/YoutubeConfig";
export let youtube: YoutubeConfig;
</script>
<div class="nes-container with-title">
<p class="title">Youtube</p>
<section>
<label>
URL Live Stream:
<input type="text" class="nes-input" bind:value={youtube.channelID}>
</label>
</section>
<section>
<label>
<input type="checkbox" class="nes-checkbox" bind:checked={youtube.fullscreen}>
<span>Fullscreen</span>
</label>
<label>
<input type="checkbox" class="nes-checkbox" bind:checked={youtube.autoplay}>
<span>Autoplay</span>
</label>
<label>
<input type="checkbox" class="nes-checkbox" bind:checked={youtube.pictureInPicture}>
<span>Picture-in-picture</span>
</label>
</section>
</div>

View file

@ -0,0 +1,22 @@
<script lang="ts">
import JitsiComponent from "../PropertiesComponents/JitsiComponent.svelte";
import YoutubeComponent from "../PropertiesComponents/YoutubeComponent.svelte";
import { ConferenceStore } from "../../Stores/ConferenceStore";
</script>
<div class="spaceComponent">
<h2>Properties of the amphi</h2>
<label>
<input type="radio" class="nes-radio" bind:group={$ConferenceStore.typeConference} value={1}>
<span>Little conference (50 peoples or less)</span>
</label>
<label>
<input type="radio" class="nes-radio" bind:group={$ConferenceStore.typeConference} value={2}>
<span>Big conference (more than 50 peoples)</span>
</label>
</div>
<JitsiComponent jitsi={$ConferenceStore.jitsi} />
{#if $ConferenceStore.typeConference === 2}
<YoutubeComponent youtube={$ConferenceStore.youtube} />
{/if}

View file

@ -0,0 +1,19 @@
<script lang="ts">
import StartComponent from "../PropertiesComponents/StartComponent.svelte";
import ExitComponent from "../PropertiesComponents/ExitComponent.svelte";
import { MeetingRoomStore } from "../../Stores/MeetingRoomStore";
</script>
<div class="spaceComponent">
<h2>Properties of the exits and start</h2>
</div>
{#if $MeetingRoomStore.nbRooms === 2}
<ExitComponent exitNameSpace="north"/>
{/if}
<ExitComponent exitNameSpace="east"/>
<ExitComponent exitNameSpace="south"/>
<ExitComponent exitNameSpace="west"/>
<StartComponent/>

View file

@ -0,0 +1,48 @@
<script lang="ts">
import JitsiComponent from "../PropertiesComponents/JitsiComponent.svelte"
import { MeetingRoomStore } from "../../Stores/MeetingRoomStore";
import { get } from "svelte/store";
const meetingRooms = [
{ id: 1, label : "5 little rooms", nbRooms: 5},
{ id: 2, label: "1 big room and 3 little ones", nbRooms: 4 },
{ id: 3, label: "2 big rooms and 1 little", nbRooms: 3 },
{ id: 4, label: "2 big rooms and north exit", nbRooms: 2 }
]
let selectedMeetingRoom = meetingRooms.find(c => c.nbRooms === get(MeetingRoomStore).nbRooms);
function onChangeNBRooms() {
if (selectedMeetingRoom === undefined) {
throw Error("You MUST select a meeting rooms configuration !");
}
MeetingRoomStore.setNbRooms(selectedMeetingRoom.nbRooms);
}
</script>
<div class="spaceComponent">
<h2>Properties of the meeting rooms</h2>
</div>
<div on:change={onChangeNBRooms} class="nes-select">
<select bind:value={selectedMeetingRoom}>
{#each meetingRooms as meetingRoom}
<option value="{meetingRoom}">
{meetingRoom.label}
</option>
{/each}
</select>
</div>
<p class="text">The list of the meeting rooms is displayed form left to right. (The room on top of the list is the leftest room in the map.)</p>
{#each Array($MeetingRoomStore.nbRooms) as _, i}
<JitsiComponent jitsi={$MeetingRoomStore.jitsis[i]} />
{/each}
<style lang="scss">
p.text {
margin: 15px;
}
</style>

View file

@ -0,0 +1,10 @@
<script lang="ts">
import OpenCoWebSiteComponent from "../PropertiesComponents/OpenCoWebSiteComponent.svelte";
import { OpenCoWebsiteStore } from "../../Stores/OpenCoWebsiteStore";
</script>
<div class="spaceComponent">
<h2>Properties of the reception</h2>
</div>
<OpenCoWebSiteComponent openCoWebSite={$OpenCoWebsiteStore}/>

View file

@ -0,0 +1,36 @@
import { writable } from "svelte/store";
import type { JitsiConfig } from "../Components/Configs/JitsiConfig";
import type { YoutubeConfig } from "../Components/Configs/YoutubeConfig";
/**
* A store that contains the type of conference wanted and the configuration of the jitsi and the youtube
* TypeConference :
* - 1 : Little conference, only jitsi
* - 2 : Big conference, jitsi on stage and youtube for audience
*/
export interface TypeConference {
typeConference : number,
jitsi : JitsiConfig,
youtube : YoutubeConfig;
}
export const ConferenceStore = writable<TypeConference>(
{
typeConference: 1,
jitsi : {
nameSpace: 'jitsiAmphi/jitsiStage',
roomName : "Amphi",
url : '',
audioMute : false,
videoMute : false,
adminTags : ["expert"],
},
youtube : {
nameSpace : 'jitsiAmphi/jitsiYoutube',
channelID : '',
fullscreen : false,
autoplay : true,
pictureInPicture: false,
}
});

56
src/Stores/ExitStore.ts Normal file
View file

@ -0,0 +1,56 @@
import { writable } from "svelte/store";
import type { ExitConfig } from "../Components/Configs/ExitConfig";
/**
* A store that contains an array of the exit on the map
*/
function createExitStore() {
const { subscribe, update } = writable<ExitConfig[]>(
[
{
nameSpace: 'north',
active: false,
url: '',
},
{
nameSpace: 'east',
active: false,
url: '',
},
{
nameSpace: 'south',
active: true,
url: '',
},
{
nameSpace: 'west',
active: false,
url: '',
}
]);
return {
subscribe,
addExit: (newExit: ExitConfig): void => {
update((configs: ExitConfig[]) => {
let found = false;
for (let config of configs) {
if (config.nameSpace === newExit.nameSpace) {
config.url = newExit.url;
config.active = newExit.active;
found = true;
break;
}
}
if (!found) {
configs.push(newExit);
}
return configs;
})
}
}
}
export const ExitStore = createExitStore();

View file

@ -0,0 +1,81 @@
import { writable } from "svelte/store";
import type { JitsiConfig } from "../Components/Configs/JitsiConfig";
/**
* A store that contains the number of meeting rooms wanted and the configuration of every jitsi of the meeting room.
*/
export interface MeetingRooms {
nbRooms : number,
jitsis : JitsiConfig[],
}
const defaultMeetingRooms = {
nbRooms : 5,
jitsis : [
{
nameSpace : "meetingRoom/meetingroom-1/bottom",
roomName : "meetingroom-1",
url : '',
audioMute : false,
videoMute : false,
adminTags : ["expert"],
},
{
nameSpace : "meetingRoom/meetingroom-2/bottom",
roomName : "meetingroom-2",
url : '',
audioMute : false,
videoMute : false,
adminTags : ["expert"],
},
{
nameSpace : "meetingRoom/meetingroom-3/bottom",
roomName : "meetingroom-3",
url : '',
audioMute : false,
videoMute : false,
adminTags : ["expert"],
},
{
nameSpace : "meetingRoom/meetingroom-4/bottom",
roomName : "meetingroom-4",
url : '',
audioMute : false,
videoMute : false,
adminTags : ["expert"],
},
{
nameSpace : "meetingRoom/meetingroom-5/bottom",
roomName : "meetingroom-5",
url : '',
audioMute : false,
videoMute : false,
adminTags : ["expert"],
},
]
};
function createMeetingRoomStore() {
const {subscribe, update, set} = writable<MeetingRooms>(defaultMeetingRooms);
return {
subscribe,
set: (value: MeetingRooms|undefined): void => {
if (value === undefined) {
set(defaultMeetingRooms);
} else {
set(value);
}
},
setNbRooms: (nb : number): void => {
update((meetingRoom : MeetingRooms) => {
meetingRoom.nbRooms = nb;
return meetingRoom;
})
},
}
}
export const MeetingRoomStore = createMeetingRoomStore();

View file

@ -0,0 +1,16 @@
import { writable } from "svelte/store";
import type { OpenCoWebSiteConfig } from "../Components/Configs/OpenCoWebSiteConfig";
/**
* A store that contains an array of the configuration of the OpenCoWebSite of the map
*/
export const OpenCoWebsiteStore = writable<OpenCoWebSiteConfig>(
{
nameSpace: "reception",
url: '',
active: 0,
onaction : false,
messageTrigger: '',
fullscreen : false,
});

7
src/Stores/StartStore.ts Normal file
View file

@ -0,0 +1,7 @@
import { writable } from "svelte/store";
/**
* A store that contains the name of the start layer on the map
*/
export const StartStore = writable<string[]>();

View file

@ -0,0 +1,18 @@
import type {Readable} from "svelte/store";
/**
* A function that maps a WorkAdventure variable to a Svelte store
*
* The store is initialized with the value of the variable.
*/
export function mapVariableToStore(variableName: string, store: Readable<unknown>&{set(this: void, value: unknown): void;}) {
store.set(WA.state.loadVariable(variableName));
store.subscribe((value) => {
WA.state.saveVariable(variableName, value);
});
WA.state.onVariableChange(variableName).subscribe((value: unknown) => {
store.set(value);
});
}

18
src/iframe.html Normal file
View file

@ -0,0 +1,18 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>WorkAdventure</title>
<script src="https://play.workadventu.re/iframe_api.js"></script>
<link rel="stylesheet" href="./node_modules/nes.css/css/nes.min.css">
</head>
<body>
</body>
</html>

19
src/iframe.ts Normal file
View file

@ -0,0 +1,19 @@
/// <reference path="../node_modules/@workadventure/iframe-api-typings/iframe_api.d.ts" />
import App from "./Components/App.svelte";
import "../style/style.scss";
import {mapVariableToStore} from "./Stores/VariableMapper";
import {MeetingRoomStore} from "./Stores/MeetingRoomStore";
WA.onInit().then(() => {
//mapVariableToStore('meetingRooms', MeetingRoomStore);
});
const app = new App({
target: document.body,
props: {
WA: WA,
}
});
export default app;

View file

@ -2,6 +2,275 @@
// You can write your WorkAdventure script here, if any.
// The "WA" global object is available from anywhere.
import type { TypeConference } from "./Stores/ConferenceStore";
import {get} from "svelte/store";
import type {MeetingRooms} from "./Stores/MeetingRoomStore";
import {OpenCoWebsiteStore} from "./Stores/OpenCoWebsiteStore";
import {ExitStore} from "./Stores/ExitStore";
import {StartStore} from "./Stores/StartStore";
import type {JitsiConfig} from "./Components/Configs/JitsiConfig";
import type {OpenCoWebSiteConfig} from "./Components/Configs/OpenCoWebSiteConfig";
import type {ExitConfig} from "./Components/Configs/ExitConfig";
import type {YoutubeConfig} from "./Components/Configs/YoutubeConfig";
console.log('Script started successfully');
WA.openCoWebSite('https://workadventu.re');
WA.ui.registerMenuCommand('Configure the room', () => {
WA.nav.openCoWebSite("../iframe.html", true);
});
/*Start by hiding the following layer :
- Open/North
- Open/East
- Open/West
- Close/South
- meetingroom-6
- meetingroom-7
*/
WA.room.hideLayer('Open/North');
WA.room.hideLayer('Open/East');
WA.room.hideLayer('Open/West');
WA.room.hideLayer('Close/South');
WA.room.hideLayer('meetingroom-6');
WA.room.hideLayer('meetingroom-7');
WA.onInit().then(() => {
applyMetadata();
});
function applyMetadata() {
deleteJitsi();
applyConference();
applyMeetingRooms();
applyOpenCoWebSite();
applyExit();
applyStart();
}
function applyConference() {
const conference = WA.state.conference as TypeConference|undefined;
if (conference === undefined) {
return;
}
if (conference.typeConference === 1) {
applyJitsiConfig(conference.jitsi);
applyJitsiConfig(conference.jitsi, "jitsiAmphi/jitsiBetween");
applyJitsiConfig(conference.jitsi, "jitsiAmphi/jitsiYoutube");
} else if (conference.typeConference === 2) {
applyJitsiConfig(conference.jitsi);
applyYoutubeConfig(conference.youtube);
}
}
WA.state.onVariableChange("conference").subscribe(applyConference);
function applyMeetingRooms() {
const meetingRooms = WA.state.meetingRooms as MeetingRooms|undefined;
if (meetingRooms === undefined) {
return;
}
if (meetingRooms.nbRooms === 2) {
for (let i = 0; i < meetingRooms.nbRooms; i++) {
applyJitsiConfig(meetingRooms.jitsis[i], "meetingRoom/meetingroom-" + (i + 6) + "/bottom");
WA.room.showLayer("meetingroom-" + (i + 6));
}
WA.room.hideLayer("meetingroom-1");
WA.room.hideLayer("meetingroom-2");
WA.room.hideLayer("meetingroom-3");
WA.room.hideLayer("meetingroom-4");
WA.room.hideLayer("meetingroom-5");
}
if (meetingRooms.nbRooms === 3) {
applyJitsiConfig(meetingRooms.jitsis[0], "meetingRoom/meetingroom-6/bottom");
applyJitsiConfig(meetingRooms.jitsis[1]);
applyJitsiConfig(meetingRooms.jitsis[2], "meetingRoom/meetingroom-7/bottom");
WA.room.showLayer("meetingroom-3");
WA.room.showLayer("meetingroom-6");
WA.room.showLayer("meetingroom-7");
WA.room.hideLayer("meetingroom-1");
WA.room.hideLayer("meetingroom-2");
WA.room.hideLayer("meetingroom-4");
WA.room.hideLayer("meetingroom-5");
}
if (meetingRooms.nbRooms === 4) {
applyJitsiConfig(meetingRooms.jitsis[0], "meetingRoom/meetingRoom/meetingroom-6/bottom");
WA.room.showLayer("meetingroom-6");
WA.room.hideLayer("meetingroom-1");
WA.room.hideLayer("meetingroom-2");
WA.room.hideLayer("meetingroom-7");
for (let i = 1; i < meetingRooms.nbRooms; i++) {
applyJitsiConfig(meetingRooms.jitsis[i]);
WA.room.showLayer("meetingroom-" + (i + 2));
}
}
if (meetingRooms.nbRooms === 5) {
for (let jitsi of meetingRooms.jitsis) {
applyJitsiConfig(jitsi);
}
WA.room.hideLayer("meetingroom-6");
WA.room.hideLayer("meetingroom-7");
WA.room.showLayer("meetingroom-1");
WA.room.showLayer("meetingroom-2");
WA.room.showLayer("meetingroom-3");
WA.room.showLayer("meetingroom-4");
WA.room.showLayer("meetingroom-5");
}
}
WA.state.onVariableChange("meetingRooms").subscribe(applyMeetingRooms);
function applyJitsiConfig(jitsiConfig: JitsiConfig, name?: string) {
WA.room.setProperty(name ? name : jitsiConfig.nameSpace, "jitsiRoom", jitsiConfig.roomName);
if (jitsiConfig.url !== '') {
WA.room.setProperty(name ? name : jitsiConfig.nameSpace, "jitsiUrl", jitsiConfig.url);
}
let jitsiConfigFormat = `{ \"startWithAudioMuted\": ${jitsiConfig.audioMute}, \"startWithVideoMuted\": ${jitsiConfig.videoMute} } `;
WA.room.setProperty(name ? name : jitsiConfig.nameSpace, "jitsiConfig", jitsiConfigFormat);
}
function applyYoutubeConfig(youtubeConfig: YoutubeConfig) {
WA.room.setProperty(youtubeConfig.nameSpace, "OpenCoWebSite", "https://www.youtube.com/embed/live_stream?channel=" + youtubeConfig.channelID);
let youtubeConfigFormat = `${youtubeConfig.fullscreen ? 'fullscreen' : ''}; ${youtubeConfig.autoplay ? 'autoplay' : ''}; ${youtubeConfig.pictureInPicture ? 'picture-in-picture' : ''}`;
WA.room.setProperty(youtubeConfig.nameSpace, "OpenCoWebSitePolicy", youtubeConfigFormat);
}
function applyOpenCoWebSite() {
const receptionWebsite = WA.state.receptionWebsite as OpenCoWebSiteConfig|undefined;
if (receptionWebsite === undefined) {
return;
}
if (receptionWebsite.active) {
WA.room.setProperty(receptionWebsite.nameSpace, 'OpenCoWebSite', receptionWebsite.url);
let OpenCoWebSiteConfigFormat = `${receptionWebsite.fullscreen ? 'fullscreen' : undefined}`;
WA.room.setProperty(receptionWebsite.nameSpace, 'OpenCoWebSitePolicy', OpenCoWebSiteConfigFormat);
if (receptionWebsite.onaction) {
WA.room.setProperty(receptionWebsite.nameSpace, 'OpenCoWebSiteTrigger', 'onaction');
WA.room.setProperty(receptionWebsite.nameSpace, 'OpenCoWebSiteTriggerMessage', receptionWebsite.messageTrigger);
}
} else {
WA.room.setProperty(receptionWebsite.nameSpace, "OpenCoWebSite", undefined);
}
}
WA.state.onVariableChange("receptionWebsite").subscribe(applyOpenCoWebSite);
function applyExit() {
const exits = WA.state.exits as ExitConfig[]|undefined;
if (exits === undefined) {
return;
}
for (let exit of exits) {
if (exit.nameSpace === "north") {
if (exit.active) {
WA.room.showLayer("Open/North");
WA.room.hideLayer("Close/North");
WA.room.setProperty("Exit/Open/North/bottom", "exitUrl", exit.url);
} else {
WA.room.hideLayer("Open/North");
WA.room.showLayer("Close/North");
WA.room.setProperty("Exit/Open/North/bottom", "exitUrl", undefined);
}
}
if (exit.nameSpace === "south") {
if (exit.active) {
WA.room.showLayer("Open/South");
WA.room.hideLayer("Close/South");
WA.room.setProperty("Exit/Open/South/bottom", "exitUrl", exit.url);
} else {
WA.room.hideLayer("Open/South");
WA.room.showLayer("Close/South");
WA.room.setProperty("Exit/Open/South/bottom", "exitUrl", undefined);
}
}
if (exit.nameSpace === "east") {
if (exit.active) {
WA.room.showLayer("Open/East");
WA.room.hideLayer("Close/East");
WA.room.setProperty("Exit/Open/East/bottom", "exitUrl", exit.url);
} else {
WA.room.hideLayer("Open/East");
WA.room.showLayer("Close/East");
WA.room.setProperty("Exit/Open/East/bottom", "exitUrl", undefined);
}
}
if (exit.nameSpace === "west") {
if (exit.active) {
WA.room.showLayer("Open/West");
WA.room.hideLayer("Close/West");
WA.room.setProperty("Exit/Open/West/bottom", "exitUrl", exit.url);
} else {
WA.room.hideLayer("Open/West");
WA.room.showLayer("Close/West");
WA.room.setProperty("Exit/Open/West/bottom", "exitUrl", undefined);
}
}
}
}
WA.state.onVariableChange("exits").subscribe(applyExit);
function applyStart() {
const starts = WA.state.starts as string[]|undefined;
if (starts === undefined) {
return;
}
for (let start of starts) {
if (start == "north") {
WA.room.setTiles([
{x: 22, y: 1, tile: start, layer: 'start'},
{x: 22, y: 2, tile: start, layer: 'start'},
{x: 23, y: 1, tile: start, layer: 'start'},
{x: 23, y: 2, tile: start, layer: 'start'}
]);
} else if (start == "east") {
WA.room.setTiles([
{x: 43, y: 16, tile: start, layer: 'start'},
{x: 43, y: 17, tile: start, layer: 'start'},
{x: 44, y: 16, tile: start, layer: 'start'},
{x: 44, y: 17, tile: start, layer: 'start'}
]);
} else if (start == "south") {
WA.room.setTiles([
{x: 30, y: 34, tile: start, layer: 'start'},
{x: 30, y: 35, tile: start, layer: 'start'},
{x: 31, y: 34, tile: start, layer: 'start'},
{x: 31, y: 35, tile: start, layer: 'start'}
]);
} else if (start == "west") {
WA.room.setTiles([
{x: 1, y: 11, tile: start, layer: 'start'},
{x: 1, y: 12, tile: start, layer: 'start'},
{x: 2, y: 11, tile: start, layer: 'start'},
{x: 2, y: 12, tile: start, layer: 'start'}
]);
}
}
}
WA.state.onVariableChange("starts").subscribe(applyStart);
function deleteJitsi() {
WA.room.setProperty("jitsiAmphi/jitsiStage", "jitsiRoom", undefined);
WA.room.setProperty("jitsiAmphi/jitsiBetween", "jitsiRoom", undefined);
WA.room.setProperty("jitsiAmphi/jitsiYoutube", "jitsiRoom", undefined);
WA.room.setProperty("meetingRoom/meetingroom-1/bottom", "jitsiRoom", undefined);
WA.room.setProperty("meetingRoom/meetingroom-2/bottom", "jitsiRoom", undefined);
WA.room.setProperty("meetingRoom/meetingroom-3/bottom", "jitsiRoom", undefined);
WA.room.setProperty("meetingRoom/meetingroom-4/bottom", "jitsiRoom", undefined);
WA.room.setProperty("meetingRoom/meetingroom-5/bottom", "jitsiRoom", undefined);
WA.room.setProperty("meetingRoom/meetingroom-6/bottom", "jitsiRoom", undefined);
WA.room.setProperty("meetingRoom/meetingroom-7/bottom", "jitsiRoom", undefined);
}
export {}

57
style/style.scss Normal file
View file

@ -0,0 +1,57 @@
@import "~@fontsource/press-start-2p/index.css";
*{
font-family: "Press Start 2P";
}
div.main-app div {
max-width: 98%;
}
div.nes-select {
max-width: 700px;
width: 90%;
margin-right: auto;
margin-left: auto;
}
.spaceComponent {
text-align: center;
h2 {
margin: 20px;
}
}
div.nes-container.with-title {
margin-top: 25px;
margin-right: auto;
margin-left: auto;
padding-top: 15px;
p.title {
margin-bottom: 0;
}
h2 {
margin: 0;
text-align: center;
}
section {
margin-top: 20px;
label.disabled {
color: gray;
input {
background-color: lightgray;
color: gray;
}
}
&.centered {
text-align: center;
}
}
}

View file

@ -0,0 +1,7 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"esModuleInterop": true
}
}

View file

@ -1,14 +1,18 @@
{
"extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"moduleResolution": "node",
"module": "CommonJS",
"target": "ES2015",
"module": "ESNext",
"target": "ES2017",
"declaration": false,
"downlevelIteration": true,
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"importsNotUsedAsValues": "error",
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */

View file

@ -1,61 +0,0 @@
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index.ts',
devtool: 'inline-source-map',
devServer: {
contentBase: '.',
//host: '0.0.0.0',
host: 'localhost',
//sockPort: 80,
disableHostCheck: true,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
}
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ],
},
output: {
filename: 'script.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
/*externals:[
require('webpack-require-http')
],*/
plugins: [
/*new webpack.ProvidePlugin({
WA: ['@workadventure/iframe-api-typings', 'window.WA']
}),*/
/*new webpack.EnvironmentPlugin({
'API_URL': null,
'PUSHER_URL': undefined,
'UPLOADER_URL': null,
'ADMIN_URL': null,
'DEBUG_MODE': null,
'STUN_SERVER': null,
'TURN_SERVER': null,
'TURN_USER': null,
'TURN_PASSWORD': null,
'JITSI_URL': null,
'JITSI_PRIVATE_MODE': null,
'START_ROOM_URL': null
})*/
],
};

176
webpack.config.ts Normal file
View file

@ -0,0 +1,176 @@
import type {Configuration} from "webpack";
import type WebpackDevServer from "webpack-dev-server";
import path from 'path';
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import sveltePreprocess from 'svelte-preprocess';
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
import NodePolyfillPlugin from 'node-polyfill-webpack-plugin';
const mode = process.env.NODE_ENV ?? 'development';
const isProduction = mode === 'production';
const isDevelopment = !isProduction;
module.exports = {
entry: {
'main': './src/index.ts',
'iframe': './src/iframe.ts'
},
mode: mode,
//devtool: isDevelopment ? 'inline-source-map' : 'source-map',
//devtool: isDevelopment ? 'eval' : 'source-map',
devServer: {
port: 3000,
contentBase: '.',
host: 'localhost',
disableHostCheck: true,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
}
},
module: {
rules: [
{
test: /\.tsx?$/,
//use: 'ts-loader',
exclude: /node_modules/,
loader: 'ts-loader',
options: {
//transpileOnly: true,
},
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
MiniCssExtractPlugin.loader, {
loader: 'css-loader',
options: {
//url: false,
sourceMap: true
}
}, 'sass-loader'],
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
//url: false,
sourceMap: true
}
}
]
},
{
test: /\.svelte$/,
exclude: /node_modules/,
use: {
loader: 'svelte-loader',
options: {
compilerOptions: {
// Dev mode must be enabled for HMR to work!
dev: isDevelopment
},
emitCss: isProduction,
hotReload: isDevelopment,
hotOptions: {
// List of options and defaults: https://www.npmjs.com/package/svelte-loader-hot#usage
noPreserveState: false,
optimistic: true,
},
preprocess: sveltePreprocess({
scss: true,
sass: true,
}),
onwarn: function (warning: { code: string }, handleWarning: (warning: { code: string }) => void) {
// See https://github.com/sveltejs/svelte/issues/4946#issuecomment-662168782
/*if (warning.code === 'a11y-no-onchange') { return }
if (warning.code === 'a11y-autofocus') { return }
if (warning.code === 'a11y-media-has-caption') { return }*/
// process as usual
handleWarning(warning);
}
}
}
},
// Required to prevent errors from Svelte on Webpack 5+, omit on Webpack 4
// See: https://github.com/sveltejs/svelte-loader#usage
{
test: /node_modules\/svelte\/.*\.mjs$/,
resolve: {
fullySpecified: false
}
},
{
test: /\.(eot|svg|png|gif|jpg)$/,
exclude: /node_modules/,
type: 'asset'
},
{
test: /\.(woff(2)?|ttf)$/,
type: 'asset',
generator: {
filename: 'fonts/[name][ext]'
}
}
],
},
resolve: {
alias: {
svelte: path.resolve('node_modules', 'svelte')
},
extensions: [ '.tsx', '.ts', '.js', '.svelte' ],
mainFields: ['svelte', 'browser', 'module', 'main', 'iframe']
},
output: {
filename: (pathData) => {
// Add a content hash only for the main bundle.
// We want the iframe_api.js file to keep its name as it will be referenced from outside iframes.
//return pathData.chunk?.name === 'main' ? 'js/[name].js': '[name].[contenthash].js';
return pathData.chunk?.name === 'main' ? 'js/[name].js': 'js/[name].[contenthash].js';
},
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
//new ForkTsCheckerWebpackPlugin({
//eslint: {
// files: './src/**/*.ts'
//}
//}),
new MiniCssExtractPlugin({filename: '[name].[contenthash].css'}),
new HtmlWebpackPlugin(
{
template: './src/iframe.html',
filename: 'iframe.html',
minify: {
collapseWhitespace: true,
keepClosingSlash: true,
removeComments: false,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
},
chunks: ['iframe']
}
),
new webpack.ProvidePlugin({
Phaser: 'phaser'
}),
new NodePolyfillPlugin()
],
} as Configuration & WebpackDevServer.Configuration;

View file

@ -1,7 +0,0 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.config.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map'
});

3416
yarn.lock

File diff suppressed because it is too large Load diff