Co-website management move to Svelte
This commit is contained in:
parent
0bf1acfefb
commit
4f068c72be
@ -6,13 +6,14 @@ export const isOpenCoWebsiteEvent = new tg.IsInterface()
|
|||||||
allowApi: tg.isOptional(tg.isBoolean),
|
allowApi: tg.isOptional(tg.isBoolean),
|
||||||
allowPolicy: tg.isOptional(tg.isString),
|
allowPolicy: tg.isOptional(tg.isString),
|
||||||
position: tg.isOptional(tg.isNumber),
|
position: tg.isOptional(tg.isNumber),
|
||||||
|
closable: tg.isOptional(tg.isBoolean),
|
||||||
|
lazy: tg.isOptional(tg.isBoolean),
|
||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
export const isCoWebsite = new tg.IsInterface()
|
export const isCoWebsite = new tg.IsInterface()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
id: tg.isString,
|
id: tg.isString,
|
||||||
position: tg.isNumber,
|
|
||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { IframeApiContribution, sendToWorkadventure, queryWorkadventure } from "./IframeApiContribution";
|
import { IframeApiContribution, sendToWorkadventure, queryWorkadventure } from "./IframeApiContribution";
|
||||||
|
|
||||||
export class CoWebsite {
|
export class CoWebsite {
|
||||||
constructor(private readonly id: string, public readonly position: number) {}
|
constructor(private readonly id: string) {}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
return queryWorkadventure({
|
return queryWorkadventure({
|
||||||
@ -41,7 +41,14 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async openCoWebSite(url: string, allowApi?: boolean, allowPolicy?: string, position?: number): Promise<CoWebsite> {
|
async openCoWebSite(
|
||||||
|
url: string,
|
||||||
|
allowApi?: boolean,
|
||||||
|
allowPolicy?: string,
|
||||||
|
position?: number,
|
||||||
|
closable?: boolean,
|
||||||
|
lazy?: boolean
|
||||||
|
): Promise<CoWebsite> {
|
||||||
const result = await queryWorkadventure({
|
const result = await queryWorkadventure({
|
||||||
type: "openCoWebsite",
|
type: "openCoWebsite",
|
||||||
data: {
|
data: {
|
||||||
@ -49,9 +56,11 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
|
|||||||
allowApi,
|
allowApi,
|
||||||
allowPolicy,
|
allowPolicy,
|
||||||
position,
|
position,
|
||||||
|
closable,
|
||||||
|
lazy,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return new CoWebsite(result.id, result.position);
|
return new CoWebsite(result.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCoWebSites(): Promise<CoWebsite[]> {
|
async getCoWebSites(): Promise<CoWebsite[]> {
|
||||||
@ -59,7 +68,7 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
|
|||||||
type: "getCoWebsites",
|
type: "getCoWebsites",
|
||||||
data: undefined,
|
data: undefined,
|
||||||
});
|
});
|
||||||
return result.map((cowebsiteEvent) => new CoWebsite(cowebsiteEvent.id, cowebsiteEvent.position));
|
return result.map((cowebsiteEvent) => new CoWebsite(cowebsiteEvent.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -166,7 +166,7 @@
|
|||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 200;
|
z-index: 550;
|
||||||
|
|
||||||
background-color: rgb(0, 0, 0, 0.5);
|
background-color: rgb(0, 0, 0, 0.5);
|
||||||
display: grid;
|
display: grid;
|
||||||
|
32
front/src/Components/EmbedScreens/CamerasContainer.svelte
Normal file
32
front/src/Components/EmbedScreens/CamerasContainer.svelte
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<script lang="typescript">
|
||||||
|
import type { EmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||||
|
import { streamableCollectionStore } from "../../Stores/StreamableCollectionStore";
|
||||||
|
import MediaBox from "../Video/MediaBox.svelte";
|
||||||
|
|
||||||
|
export let highlightedEmbedScreen: EmbedScreen | null;
|
||||||
|
export let full = false;
|
||||||
|
$: clickable = !full;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<aside class="cameras-container" class:full>
|
||||||
|
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
|
||||||
|
{#if !highlightedEmbedScreen || highlightedEmbedScreen.type !== "streamable" || (highlightedEmbedScreen.type === "streamable" && highlightedEmbedScreen.embed !== peer)}
|
||||||
|
<MediaBox streamable={peer} isClickable={clickable} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.cameras-container {
|
||||||
|
flex: 0 0 25%;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
&:first-child {
|
||||||
|
margin-top: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.full {
|
||||||
|
flex: 0 0 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
100
front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte
Normal file
100
front/src/Components/EmbedScreens/CoWebsiteThumbnailSlot.svelte
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<script lang="typescript">
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
|
import { ICON_URL } from "../../Enum/EnvironmentVariable";
|
||||||
|
import { mainCoWebsite } from "../../Stores/CoWebsiteStore";
|
||||||
|
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||||
|
import type { CoWebsite } from "../../WebRtc/CoWebsiteManager";
|
||||||
|
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||||
|
|
||||||
|
export let index: number;
|
||||||
|
export let coWebsite: CoWebsite;
|
||||||
|
export let vertical: boolean;
|
||||||
|
|
||||||
|
let icon: HTMLImageElement;
|
||||||
|
let state = coWebsite.state;
|
||||||
|
|
||||||
|
const coWebsiteUrl = coWebsite.iframe.src;
|
||||||
|
const urlObject = new URL(coWebsiteUrl);
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
icon.src = `${ICON_URL}/icon?url=${urlObject.hostname}&size=64..96..256&fallback_icon_color=14304c`;
|
||||||
|
icon.alt = urlObject.hostname;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function toggleHighlightEmbedScreen() {
|
||||||
|
if (vertical) {
|
||||||
|
coWebsiteManager.goToMain(coWebsite);
|
||||||
|
} else if ($mainCoWebsite) {
|
||||||
|
highlightedEmbedScreen.toggleHighlight({
|
||||||
|
type: "cowebsite",
|
||||||
|
embed: coWebsite,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($state === "asleep") {
|
||||||
|
await coWebsiteManager.loadCoWebsite(coWebsite);
|
||||||
|
}
|
||||||
|
|
||||||
|
coWebsiteManager.resizeAllIframes();
|
||||||
|
}
|
||||||
|
|
||||||
|
function noDrag() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id={"cowebsite-thumbnail-" + index}
|
||||||
|
class="cowebsite-thumbnail nes-container is-rounded nes-pointer"
|
||||||
|
class:asleep={$state === "asleep"}
|
||||||
|
class:loading={$state === "loading"}
|
||||||
|
class:ready={$state === "ready"}
|
||||||
|
class:vertical
|
||||||
|
on:click={toggleHighlightEmbedScreen}
|
||||||
|
>
|
||||||
|
<img class="cowebsite-icon noselect nes-pointer" bind:this={icon} on:dragstart|preventDefault={noDrag} alt="" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.cowebsite-thumbnail {
|
||||||
|
padding: 0;
|
||||||
|
background-color: rgba(#000000, 0.6);
|
||||||
|
margin: 1%;
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
|
||||||
|
.cowebsite-icon {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.vertical {
|
||||||
|
margin: 7px;
|
||||||
|
.cowebsite-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.asleep {
|
||||||
|
filter: grayscale(100%);
|
||||||
|
--webkit-filter: grayscale(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.loading {
|
||||||
|
animation: 2500ms ease-in-out 0s infinite alternate backgroundLoading;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes backgroundLoading {
|
||||||
|
0% {
|
||||||
|
background-color: rgba(#000000, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
background-color: #25598e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
34
front/src/Components/EmbedScreens/CoWebsitesContainer.svelte
Normal file
34
front/src/Components/EmbedScreens/CoWebsitesContainer.svelte
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<script lang="typescript">
|
||||||
|
import { coWebsiteThumbails } from "../../Stores/CoWebsiteStore";
|
||||||
|
import CoWebsiteThumbnail from "./CoWebsiteThumbnailSlot.svelte";
|
||||||
|
|
||||||
|
export let vertical = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $coWebsiteThumbails.length > 0}
|
||||||
|
<div id="cowebsite-thumbnail-container" class:vertical>
|
||||||
|
{#each [...$coWebsiteThumbails.values()] as coWebsite, index (coWebsite.iframe.id)}
|
||||||
|
<CoWebsiteThumbnail {index} {coWebsite} {vertical} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
#cowebsite-thumbnail-container {
|
||||||
|
pointer-events: all;
|
||||||
|
height: 12%;
|
||||||
|
display: flex;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
|
||||||
|
&.vertical {
|
||||||
|
height: auto !important;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,22 @@
|
|||||||
|
<script lang="typescript">
|
||||||
|
import PresentationLayout from "./Layouts/PresentationLayout.svelte";
|
||||||
|
import MozaicLayout from "./Layouts/MozaicLayout.svelte";
|
||||||
|
import { LayoutMode } from "../../WebRtc/LayoutManager";
|
||||||
|
import { embedScreenLayout } from "../../Stores/EmbedScreensStore";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="embedScreensContainer">
|
||||||
|
{#if $embedScreenLayout === LayoutMode.Presentation}
|
||||||
|
<PresentationLayout />
|
||||||
|
{:else}
|
||||||
|
<MozaicLayout />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
#embedScreensContainer {
|
||||||
|
display: flex;
|
||||||
|
padding-top: 2%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,61 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import { highlightedEmbedScreen } from "../../../Stores/EmbedScreensStore";
|
||||||
|
import { streamableCollectionStore } from "../../../Stores/StreamableCollectionStore";
|
||||||
|
import MediaBox from "../../Video/MediaBox.svelte";
|
||||||
|
|
||||||
|
let layoutDom: HTMLDivElement;
|
||||||
|
|
||||||
|
const resizeObserver = new ResizeObserver(() => {});
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
resizeObserver.observe(layoutDom);
|
||||||
|
highlightedEmbedScreen.removeHighlight();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="mozaic-layout" bind:this={layoutDom}>
|
||||||
|
<div
|
||||||
|
class="media-container"
|
||||||
|
class:full-width={$streamableCollectionStore.size === 1 || $streamableCollectionStore.size === 2}
|
||||||
|
class:quarter={$streamableCollectionStore.size === 3 || $streamableCollectionStore.size === 4}
|
||||||
|
>
|
||||||
|
{#each [...$streamableCollectionStore.values()] as peer (peer.uniqueId)}
|
||||||
|
<MediaBox
|
||||||
|
streamable={peer}
|
||||||
|
mozaicFullWidth={$streamableCollectionStore.size === 1 || $streamableCollectionStore.size === 2}
|
||||||
|
mozaicQuarter={$streamableCollectionStore.size === 3 || $streamableCollectionStore.size === 4}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
#mozaic-layout {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
|
.media-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 33.3% 33.3% 33.3%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
|
&.full-width {
|
||||||
|
grid-template-columns: 100%;
|
||||||
|
grid-template-rows: 50% 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.quarter {
|
||||||
|
grid-template-columns: 50% 50%;
|
||||||
|
grid-template-rows: 50% 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,169 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { highlightedEmbedScreen } from "../../../Stores/EmbedScreensStore";
|
||||||
|
import CamerasContainer from "../CamerasContainer.svelte";
|
||||||
|
import CoWebsitesContainer from "../CoWebsitesContainer.svelte";
|
||||||
|
import MediaBox from "../../Video/MediaBox.svelte";
|
||||||
|
import { coWebsiteManager } from "../../../WebRtc/CoWebsiteManager";
|
||||||
|
import { afterUpdate, onMount } from "svelte";
|
||||||
|
import { isMediaBreakpointDown, isMediaBreakpointUp } from "../../../Utils/BreakpointsUtils";
|
||||||
|
import { peerStore } from "../../../Stores/PeerStore";
|
||||||
|
|
||||||
|
function closeCoWebsite() {
|
||||||
|
if ($highlightedEmbedScreen?.type === "cowebsite") {
|
||||||
|
if ($highlightedEmbedScreen.embed.closable) {
|
||||||
|
coWebsiteManager.closeCoWebsite($highlightedEmbedScreen.embed).catch(() => {
|
||||||
|
console.error("Error during co-website highlighted closing");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
coWebsiteManager.unloadCoWebsite($highlightedEmbedScreen.embed).catch(() => {
|
||||||
|
console.error("Error during co-website highlighted unloading");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function minimiseCoWebsite() {
|
||||||
|
if ($highlightedEmbedScreen?.type === "cowebsite") {
|
||||||
|
highlightedEmbedScreen.removeHighlight();
|
||||||
|
coWebsiteManager.resizeAllIframes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandCoWebsite() {
|
||||||
|
if ($highlightedEmbedScreen?.type === "cowebsite") {
|
||||||
|
coWebsiteManager.goToMain($highlightedEmbedScreen.embed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
afterUpdate(() => {
|
||||||
|
if ($highlightedEmbedScreen) {
|
||||||
|
coWebsiteManager.resizeAllIframes();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let layoutDom: HTMLDivElement;
|
||||||
|
|
||||||
|
let displayCoWebsiteContainer = isMediaBreakpointDown("lg");
|
||||||
|
let displayFullMedias = isMediaBreakpointUp("sm");
|
||||||
|
|
||||||
|
const resizeObserver = new ResizeObserver(() => {
|
||||||
|
displayCoWebsiteContainer = isMediaBreakpointDown("lg");
|
||||||
|
displayFullMedias = isMediaBreakpointUp("sm");
|
||||||
|
|
||||||
|
if (!displayCoWebsiteContainer && $highlightedEmbedScreen && $highlightedEmbedScreen.type === "cowebsite") {
|
||||||
|
highlightedEmbedScreen.removeHighlight();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayFullMedias) {
|
||||||
|
highlightedEmbedScreen.removeHighlight();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
resizeObserver.observe(layoutDom);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="presentation-layout" bind:this={layoutDom} class:full-medias={displayFullMedias}>
|
||||||
|
{#if displayFullMedias}
|
||||||
|
<div id="full-medias">
|
||||||
|
<CamerasContainer full={true} highlightedEmbedScreen={$highlightedEmbedScreen} />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div id="embed-left-block" class:full={$peerStore.size === 0}>
|
||||||
|
<div id="main-embed-screen">
|
||||||
|
{#if $highlightedEmbedScreen}
|
||||||
|
{#if $highlightedEmbedScreen.type === "streamable"}
|
||||||
|
{#key $highlightedEmbedScreen.embed.uniqueId}
|
||||||
|
<MediaBox
|
||||||
|
isHightlighted={true}
|
||||||
|
isClickable={true}
|
||||||
|
streamable={$highlightedEmbedScreen.embed}
|
||||||
|
/>
|
||||||
|
{/key}
|
||||||
|
{:else if $highlightedEmbedScreen.type === "cowebsite"}
|
||||||
|
{#key $highlightedEmbedScreen.embed.iframe.id}
|
||||||
|
<div
|
||||||
|
id={"cowebsite-slot-" + $highlightedEmbedScreen.embed.iframe.id}
|
||||||
|
class="highlighted-cowebsite nes-container is-rounded"
|
||||||
|
>
|
||||||
|
<div class="actions">
|
||||||
|
<button type="button" class="nes-btn is-primary expand" on:click={expandCoWebsite}
|
||||||
|
>></button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="nes-btn is-secondary minimise"
|
||||||
|
on:click={minimiseCoWebsite}>=</button
|
||||||
|
>
|
||||||
|
<button type="button" class="nes-btn is-error close" on:click={closeCoWebsite}
|
||||||
|
>×</button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/key}
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if displayCoWebsiteContainer}
|
||||||
|
<CoWebsitesContainer />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if $peerStore.size > 0}
|
||||||
|
<CamerasContainer highlightedEmbedScreen={$highlightedEmbedScreen} />
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
#presentation-layout {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&.full-medias {
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#embed-left-block {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 0 0 75%;
|
||||||
|
height: 100%;
|
||||||
|
width: 75%;
|
||||||
|
|
||||||
|
&.full {
|
||||||
|
flex: 0 0 98% !important;
|
||||||
|
width: 98% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-embed-screen {
|
||||||
|
height: 82%;
|
||||||
|
margin-bottom: 3%;
|
||||||
|
|
||||||
|
.highlighted-cowebsite {
|
||||||
|
height: 100% !important;
|
||||||
|
width: 96%;
|
||||||
|
background-color: rgba(#000000, 0.6);
|
||||||
|
margin: 0 !important;
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
z-index: 200;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: end;
|
||||||
|
gap: 2%;
|
||||||
|
|
||||||
|
button {
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -87,7 +87,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 101;
|
z-index: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emote-menu {
|
.emote-menu {
|
||||||
|
@ -121,7 +121,7 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
z-index: 150;
|
z-index: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.interact-menu {
|
div.interact-menu {
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
margin-top: 4%;
|
margin-top: 4%;
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
max-width: 80vw;
|
max-width: 80vw;
|
||||||
z-index: 250;
|
z-index: 600;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { audioManagerVisibilityStore } from "../Stores/AudioManagerStore";
|
import { audioManagerVisibilityStore } from "../Stores/AudioManagerStore";
|
||||||
import { hasEmbedScreen } from "../Stores/EmbedScreensStore";
|
import { embedScreenLayout, hasEmbedScreen } from "../Stores/EmbedScreensStore";
|
||||||
import { emoteMenuStore } from "../Stores/EmoteStore";
|
import { emoteMenuStore } from "../Stores/EmoteStore";
|
||||||
import { myCameraVisibilityStore } from "../Stores/MyCameraStoreVisibility";
|
import { myCameraVisibilityStore } from "../Stores/MyCameraStoreVisibility";
|
||||||
import { requestVisitCardsStore } from "../Stores/GameStore";
|
import { requestVisitCardsStore } from "../Stores/GameStore";
|
||||||
@ -30,11 +30,12 @@
|
|||||||
import BanMessageContainer from "./TypeMessage/BanMessageContainer.svelte";
|
import BanMessageContainer from "./TypeMessage/BanMessageContainer.svelte";
|
||||||
import { textMessageStore } from "../Stores/TypeMessageStore/TextMessageStore";
|
import { textMessageStore } from "../Stores/TypeMessageStore/TextMessageStore";
|
||||||
import TextMessageContainer from "./TypeMessage/TextMessageContainer.svelte";
|
import TextMessageContainer from "./TypeMessage/TextMessageContainer.svelte";
|
||||||
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
|
import { soundPlayingStore } from "../Stores/SoundPlayingStore";
|
||||||
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
import AudioPlaying from "./UI/AudioPlaying.svelte";
|
||||||
import { showLimitRoomModalStore, showShareLinkMapModalStore } from "../Stores/ModalStore";
|
import { showLimitRoomModalStore, showShareLinkMapModalStore } from "../Stores/ModalStore";
|
||||||
import LimitRoomModal from "./Modal/LimitRoomModal.svelte";
|
import LimitRoomModal from "./Modal/LimitRoomModal.svelte";
|
||||||
import ShareLinkMapModal from "./Modal/ShareLinkMapModal.svelte";
|
import ShareLinkMapModal from "./Modal/ShareLinkMapModal.svelte";
|
||||||
|
import { LayoutMode } from "../WebRtc/LayoutManager";
|
||||||
|
|
||||||
let mainLayout: HTMLDivElement;
|
let mainLayout: HTMLDivElement;
|
||||||
|
|
||||||
@ -55,7 +56,7 @@ import ShareLinkMapModal from "./Modal/ShareLinkMapModal.svelte";
|
|||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if displayCoWebsiteContainer}
|
{#if $embedScreenLayout === LayoutMode.VideoChat || displayCoWebsiteContainer}
|
||||||
<CoWebsitesContainer vertical={true} />
|
<CoWebsitesContainer vertical={true} />
|
||||||
{/if}
|
{/if}
|
||||||
</aside>
|
</aside>
|
||||||
@ -75,14 +76,14 @@ import ShareLinkMapModal from "./Modal/ShareLinkMapModal.svelte";
|
|||||||
<AudioPlaying url={$soundPlayingStore} />
|
<AudioPlaying url={$soundPlayingStore} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $showReportScreenStore !== userReportEmpty}
|
|
||||||
<ReportMenu />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if $warningContainerStore}
|
{#if $warningContainerStore}
|
||||||
<WarningContainer />
|
<WarningContainer />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if $showReportScreenStore !== userReportEmpty}
|
||||||
|
<ReportMenu />
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if $helpCameraSettingsVisibleStore}
|
{#if $helpCameraSettingsVisibleStore}
|
||||||
<HelpCameraSettingsPopup />
|
<HelpCameraSettingsPopup />
|
||||||
{/if}
|
{/if}
|
||||||
@ -133,7 +134,7 @@ import ShareLinkMapModal from "./Modal/ShareLinkMapModal.svelte";
|
|||||||
|
|
||||||
#main-layout {
|
#main-layout {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 7% 93%;
|
grid-template-columns: 120px calc(100% - 120px);
|
||||||
grid-template-rows: 80% 20%;
|
grid-template-rows: 80% 20%;
|
||||||
|
|
||||||
&-left-aside {
|
&-left-aside {
|
||||||
|
@ -74,6 +74,7 @@
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../../style/breakpoints.scss";
|
@import "../../../style/breakpoints.scss";
|
||||||
|
|
||||||
.menuIcon {
|
.menuIcon {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -89,9 +90,11 @@
|
|||||||
margin: 5%;
|
margin: 5%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuIcon img:hover {
|
.menuIcon img:hover {
|
||||||
transform: scale(1.2);
|
transform: scale(1.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
.menuIcon {
|
.menuIcon {
|
||||||
margin-top: 10%;
|
margin-top: 10%;
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
max-width: 80vw;
|
max-width: 80vw;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
z-index: 500;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-family: "Press Start 2P";
|
font-family: "Press Start 2P";
|
||||||
|
@ -75,6 +75,7 @@
|
|||||||
max-width: 80vw;
|
max-width: 80vw;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
z-index: 450;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-family: "Press Start 2P";
|
font-family: "Press Start 2P";
|
||||||
|
@ -108,7 +108,7 @@
|
|||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
z-index: 300;
|
z-index: 650;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 70vh;
|
height: 70vh;
|
||||||
width: 50vw;
|
width: 50vw;
|
||||||
|
@ -11,3 +11,9 @@
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.main-ban-message-container {
|
||||||
|
z-index: 800;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div.main-text-message-container {
|
.main-text-message-container {
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
|
z-index: 800;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
background-color: black;
|
background-color: black;
|
||||||
border-radius: 30px 0 0 30px;
|
border-radius: 30px 0 0 30px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
z-index: 750;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
@ -8,16 +8,23 @@
|
|||||||
|
|
||||||
export let streamable: Streamable;
|
export let streamable: Streamable;
|
||||||
export let isHightlighted = false;
|
export let isHightlighted = false;
|
||||||
export let clickable = false;
|
export let isClickable = false;
|
||||||
|
export let mozaicFullWidth = false;
|
||||||
|
export let mozaicQuarter = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="media-container nes-container is-rounded {isHightlighted ? 'hightlighted' : ''}" class:clickable>
|
<div
|
||||||
|
class="media-container nes-container is-rounded {isHightlighted ? 'hightlighted' : ''}"
|
||||||
|
class:clickable={isClickable}
|
||||||
|
class:mozaic-full-width={mozaicFullWidth}
|
||||||
|
class:mozaic-quarter={mozaicQuarter}
|
||||||
|
>
|
||||||
{#if streamable instanceof VideoPeer}
|
{#if streamable instanceof VideoPeer}
|
||||||
<VideoMediaBox peer={streamable} {clickable} />
|
<VideoMediaBox peer={streamable} clickable={isClickable} />
|
||||||
{:else if streamable instanceof ScreenSharingPeer}
|
{:else if streamable instanceof ScreenSharingPeer}
|
||||||
<ScreenSharingMediaBox peer={streamable} {clickable} />
|
<ScreenSharingMediaBox peer={streamable} clickable={isClickable} />
|
||||||
{:else}
|
{:else}
|
||||||
<LocalStreamMediaBox peer={streamable} {clickable} cssClass="" />
|
<LocalStreamMediaBox peer={streamable} clickable={isClickable} cssClass="" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -57,6 +64,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.mozaic-full-width {
|
||||||
|
width: 95%;
|
||||||
|
max-width: 95%;
|
||||||
|
margin-left: 3%;
|
||||||
|
margin-right: 3%;
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mozaic-quarter {
|
||||||
|
width: 95%;
|
||||||
|
max-width: 95%;
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.clickable {
|
&.clickable {
|
||||||
cursor: url("../../../style/images/cursor_pointer.png"), pointer;
|
cursor: url("../../../style/images/cursor_pointer.png"), pointer;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
height: 120px;
|
height: 120px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
animation: spin 2s linear infinite;
|
animation: spin 2s linear infinite;
|
||||||
z-index: 102;
|
z-index: 350;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
font-family: Lato;
|
font-family: Lato;
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
z-index: 270;
|
z-index: 700;
|
||||||
h2 {
|
h2 {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
@ -9,21 +9,21 @@ import { get } from "svelte/store";
|
|||||||
import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
|
import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
|
||||||
import type { ITiledMapLayer } from "../Map/ITiledMap";
|
import type { ITiledMapLayer } from "../Map/ITiledMap";
|
||||||
import { GameMapProperties } from "./GameMapProperties";
|
import { GameMapProperties } from "./GameMapProperties";
|
||||||
|
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
|
||||||
|
|
||||||
enum OpenCoWebsiteState {
|
enum OpenCoWebsiteState {
|
||||||
LOADING,
|
ASLEEP,
|
||||||
OPENED,
|
OPENED,
|
||||||
MUST_BE_CLOSE,
|
MUST_BE_CLOSE,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OpenCoWebsite {
|
interface OpenCoWebsite {
|
||||||
coWebsite: CoWebsite | undefined;
|
coWebsite: CoWebsite;
|
||||||
state: OpenCoWebsiteState;
|
state: OpenCoWebsiteState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GameMapPropertiesListener {
|
export class GameMapPropertiesListener {
|
||||||
private coWebsitesOpenByLayer = new Map<ITiledMapLayer, OpenCoWebsite>();
|
private coWebsitesOpenByLayer = new Map<ITiledMapLayer, OpenCoWebsite>();
|
||||||
private coWebsitesActionTriggerByLayer = new Map<ITiledMapLayer, string>();
|
|
||||||
|
|
||||||
constructor(private scene: GameScene, private gameMap: GameMap) {}
|
constructor(private scene: GameScene, private gameMap: GameMap) {}
|
||||||
|
|
||||||
@ -64,10 +64,8 @@ export class GameMapPropertiesListener {
|
|||||||
let openWebsiteProperty: string | undefined;
|
let openWebsiteProperty: string | undefined;
|
||||||
let allowApiProperty: boolean | undefined;
|
let allowApiProperty: boolean | undefined;
|
||||||
let websitePolicyProperty: string | undefined;
|
let websitePolicyProperty: string | undefined;
|
||||||
let websiteWidthProperty: number | undefined;
|
|
||||||
let websitePositionProperty: number | undefined;
|
let websitePositionProperty: number | undefined;
|
||||||
let websiteTriggerProperty: string | undefined;
|
let websiteTriggerProperty: string | undefined;
|
||||||
let websiteTriggerMessageProperty: string | undefined;
|
|
||||||
|
|
||||||
layer.properties.forEach((property) => {
|
layer.properties.forEach((property) => {
|
||||||
switch (property.name) {
|
switch (property.name) {
|
||||||
@ -80,18 +78,12 @@ export class GameMapPropertiesListener {
|
|||||||
case GameMapProperties.OPEN_WEBSITE_POLICY:
|
case GameMapProperties.OPEN_WEBSITE_POLICY:
|
||||||
websitePolicyProperty = property.value as string | undefined;
|
websitePolicyProperty = property.value as string | undefined;
|
||||||
break;
|
break;
|
||||||
case GameMapProperties.OPEN_WEBSITE_WIDTH:
|
|
||||||
websiteWidthProperty = property.value as number | undefined;
|
|
||||||
break;
|
|
||||||
case GameMapProperties.OPEN_WEBSITE_POSITION:
|
case GameMapProperties.OPEN_WEBSITE_POSITION:
|
||||||
websitePositionProperty = property.value as number | undefined;
|
websitePositionProperty = property.value as number | undefined;
|
||||||
break;
|
break;
|
||||||
case GameMapProperties.OPEN_WEBSITE_TRIGGER:
|
case GameMapProperties.OPEN_WEBSITE_TRIGGER:
|
||||||
websiteTriggerProperty = property.value as string | undefined;
|
websiteTriggerProperty = property.value as string | undefined;
|
||||||
break;
|
break;
|
||||||
case GameMapProperties.OPEN_WEBSITE_TRIGGER_MESSAGE:
|
|
||||||
websiteTriggerMessageProperty = property.value as string | undefined;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -105,27 +97,30 @@ export class GameMapPropertiesListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const coWebsite = coWebsiteManager.addCoWebsite(
|
||||||
|
openWebsiteProperty,
|
||||||
|
this.scene.MapUrlFile,
|
||||||
|
allowApiProperty,
|
||||||
|
websitePolicyProperty,
|
||||||
|
websitePositionProperty,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
this.coWebsitesOpenByLayer.set(layer, {
|
this.coWebsitesOpenByLayer.set(layer, {
|
||||||
coWebsite: undefined,
|
coWebsite: coWebsite,
|
||||||
state: OpenCoWebsiteState.LOADING,
|
state: OpenCoWebsiteState.ASLEEP,
|
||||||
});
|
});
|
||||||
|
|
||||||
const openWebsiteFunction = () => {
|
const openWebsiteFunction = () => {
|
||||||
coWebsiteManager
|
coWebsiteManager
|
||||||
.loadCoWebsite(
|
.loadCoWebsite(coWebsite)
|
||||||
openWebsiteProperty as string,
|
|
||||||
this.scene.MapUrlFile,
|
|
||||||
allowApiProperty,
|
|
||||||
websitePolicyProperty,
|
|
||||||
websiteWidthProperty,
|
|
||||||
websitePositionProperty
|
|
||||||
)
|
|
||||||
.then((coWebsite) => {
|
.then((coWebsite) => {
|
||||||
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
|
const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer);
|
||||||
if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) {
|
if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) {
|
||||||
coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => console.error(e));
|
coWebsiteManager.closeCoWebsite(coWebsite).catch(() => {
|
||||||
|
console.error("Error during a co-website closing");
|
||||||
|
});
|
||||||
this.coWebsitesOpenByLayer.delete(layer);
|
this.coWebsitesOpenByLayer.delete(layer);
|
||||||
this.coWebsitesActionTriggerByLayer.delete(layer);
|
|
||||||
} else {
|
} else {
|
||||||
this.coWebsitesOpenByLayer.set(layer, {
|
this.coWebsitesOpenByLayer.set(layer, {
|
||||||
coWebsite,
|
coWebsite,
|
||||||
@ -133,27 +128,17 @@ export class GameMapPropertiesListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => console.error(e));
|
.catch(() => {
|
||||||
|
console.error("Error during loading a co-website: " + coWebsite.url);
|
||||||
|
});
|
||||||
|
|
||||||
layoutManagerActionStore.removeAction(actionUuid);
|
layoutManagerActionStore.removeAction(actionUuid);
|
||||||
};
|
};
|
||||||
|
|
||||||
const forceTrigger = localUserStore.getForceCowebsiteTrigger();
|
if (
|
||||||
if (forceTrigger || websiteTriggerProperty === ON_ACTION_TRIGGER_BUTTON) {
|
!localUserStore.getForceCowebsiteTrigger() &&
|
||||||
if (!websiteTriggerMessageProperty) {
|
websiteTriggerProperty !== ON_ACTION_TRIGGER_BUTTON
|
||||||
websiteTriggerMessageProperty = "Press SPACE or touch here to open web site";
|
) {
|
||||||
}
|
|
||||||
|
|
||||||
this.coWebsitesActionTriggerByLayer.set(layer, actionUuid);
|
|
||||||
|
|
||||||
layoutManagerActionStore.addAction({
|
|
||||||
uuid: actionUuid,
|
|
||||||
type: "message",
|
|
||||||
message: websiteTriggerMessageProperty,
|
|
||||||
callback: () => openWebsiteFunction(),
|
|
||||||
userInputManager: this.scene.userInputManager,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
openWebsiteFunction();
|
openWebsiteFunction();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -194,7 +179,7 @@ export class GameMapPropertiesListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coWebsiteOpen.state === OpenCoWebsiteState.LOADING) {
|
if (coWebsiteOpen.state === OpenCoWebsiteState.ASLEEP) {
|
||||||
coWebsiteOpen.state = OpenCoWebsiteState.MUST_BE_CLOSE;
|
coWebsiteOpen.state = OpenCoWebsiteState.MUST_BE_CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,26 +188,6 @@ export class GameMapPropertiesListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.coWebsitesOpenByLayer.delete(layer);
|
this.coWebsitesOpenByLayer.delete(layer);
|
||||||
|
|
||||||
if (!websiteTriggerProperty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const actionStore = get(layoutManagerActionStore);
|
|
||||||
const actionTriggerUuid = this.coWebsitesActionTriggerByLayer.get(layer);
|
|
||||||
|
|
||||||
if (!actionTriggerUuid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const action =
|
|
||||||
actionStore && actionStore.length > 0
|
|
||||||
? actionStore.find((action) => action.uuid === actionTriggerUuid)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
if (action) {
|
|
||||||
layoutManagerActionStore.removeAction(actionTriggerUuid);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2145,8 +2145,8 @@ ${escapedMessage}
|
|||||||
public stopJitsi(): void {
|
public stopJitsi(): void {
|
||||||
const coWebsite = coWebsiteManager.searchJitsi();
|
const coWebsite = coWebsiteManager.searchJitsi();
|
||||||
if (coWebsite) {
|
if (coWebsite) {
|
||||||
coWebsiteManager.closeCoWebsite(coWebsite).catch(() => {
|
coWebsiteManager.closeCoWebsite(coWebsite).catch((e) => {
|
||||||
console.error("Error during Jitsi co-website closing");
|
console.error("Error during Jitsi co-website closing", e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
66
front/src/Stores/CoWebsiteStore.ts
Normal file
66
front/src/Stores/CoWebsiteStore.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { derived, get, writable } from "svelte/store";
|
||||||
|
import type { CoWebsite } from "../WebRtc/CoWebsiteManager";
|
||||||
|
import { highlightedEmbedScreen } from "./EmbedScreensStore";
|
||||||
|
|
||||||
|
function createCoWebsiteStore() {
|
||||||
|
const { subscribe, set, update } = writable(Array<CoWebsite>());
|
||||||
|
|
||||||
|
set(Array<CoWebsite>());
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
add: (coWebsite: CoWebsite, position?: number) => {
|
||||||
|
coWebsite.state.subscribe((value) => {
|
||||||
|
update((currentArray) => currentArray);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (position || position === 0) {
|
||||||
|
update((currentArray) => {
|
||||||
|
if (position === 0) {
|
||||||
|
return [coWebsite, ...currentArray];
|
||||||
|
} else if (currentArray.length > position) {
|
||||||
|
const test = [...currentArray.splice(position, 0, coWebsite)];
|
||||||
|
return [...currentArray.splice(position, 0, coWebsite)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...currentArray, coWebsite];
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
update((currentArray) => [...currentArray, coWebsite]);
|
||||||
|
},
|
||||||
|
remove: (coWebsite: CoWebsite) => {
|
||||||
|
update((currentArray) => [
|
||||||
|
...currentArray.filter((currentCoWebsite) => currentCoWebsite.iframe.id !== coWebsite.iframe.id),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
empty: () => {
|
||||||
|
set(Array<CoWebsite>());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const coWebsites = createCoWebsiteStore();
|
||||||
|
|
||||||
|
export const coWebsitesNotAsleep = derived([coWebsites], ([$coWebsites]) =>
|
||||||
|
$coWebsites.filter((coWebsite) => get(coWebsite.state) !== "asleep")
|
||||||
|
);
|
||||||
|
|
||||||
|
export const mainCoWebsite = derived([coWebsites], ([$coWebsites]) =>
|
||||||
|
$coWebsites.find((coWebsite) => get(coWebsite.state) !== "asleep")
|
||||||
|
);
|
||||||
|
|
||||||
|
export const coWebsiteThumbails = derived(
|
||||||
|
[coWebsites, highlightedEmbedScreen, mainCoWebsite],
|
||||||
|
([$coWebsites, highlightedEmbedScreen, $mainCoWebsite]) =>
|
||||||
|
$coWebsites.filter((coWebsite, index) => {
|
||||||
|
return (
|
||||||
|
(!$mainCoWebsite || $mainCoWebsite.iframe.id !== coWebsite.iframe.id) &&
|
||||||
|
(!highlightedEmbedScreen ||
|
||||||
|
highlightedEmbedScreen.type !== "cowebsite" ||
|
||||||
|
(highlightedEmbedScreen.type === "cowebsite" &&
|
||||||
|
highlightedEmbedScreen.embed.iframe.id !== coWebsite.iframe.id))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
51
front/src/Stores/EmbedScreensStore.ts
Normal file
51
front/src/Stores/EmbedScreensStore.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { derived, get, writable } from "svelte/store";
|
||||||
|
import type { CoWebsite } from "../WebRtc/CoWebsiteManager";
|
||||||
|
import { LayoutMode } from "../WebRtc/LayoutManager";
|
||||||
|
import { coWebsites } from "./CoWebsiteStore";
|
||||||
|
import { Streamable, streamableCollectionStore } from "./StreamableCollectionStore";
|
||||||
|
|
||||||
|
export type EmbedScreen =
|
||||||
|
| {
|
||||||
|
type: "streamable";
|
||||||
|
embed: Streamable;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "cowebsite";
|
||||||
|
embed: CoWebsite;
|
||||||
|
};
|
||||||
|
|
||||||
|
function createHighlightedEmbedScreenStore() {
|
||||||
|
const { subscribe, set, update } = writable<EmbedScreen | null>(null);
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
highlight: (embedScreen: EmbedScreen) => {
|
||||||
|
set(embedScreen);
|
||||||
|
},
|
||||||
|
removeHighlight: () => {
|
||||||
|
set(null);
|
||||||
|
},
|
||||||
|
toggleHighlight: (embedScreen: EmbedScreen) => {
|
||||||
|
update((currentEmbedScreen) =>
|
||||||
|
!currentEmbedScreen ||
|
||||||
|
embedScreen.type !== currentEmbedScreen.type ||
|
||||||
|
(embedScreen.type === "cowebsite" &&
|
||||||
|
currentEmbedScreen.type === "cowebsite" &&
|
||||||
|
embedScreen.embed.iframe.id !== currentEmbedScreen.embed.iframe.id) ||
|
||||||
|
(embedScreen.type === "streamable" &&
|
||||||
|
currentEmbedScreen.type === "streamable" &&
|
||||||
|
embedScreen.embed.uniqueId !== currentEmbedScreen.embed.uniqueId)
|
||||||
|
? embedScreen
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const highlightedEmbedScreen = createHighlightedEmbedScreenStore();
|
||||||
|
export const embedScreenLayout = writable<LayoutMode>(LayoutMode.Presentation);
|
||||||
|
|
||||||
|
export const hasEmbedScreen = derived(
|
||||||
|
[streamableCollectionStore],
|
||||||
|
($values) => get(streamableCollectionStore).size + get(coWebsites).length > 0
|
||||||
|
);
|
File diff suppressed because it is too large
Load Diff
@ -132,64 +132,64 @@ class JitsiFactory {
|
|||||||
return slugify(instance.replace("/", "-") + "-" + roomName);
|
return slugify(instance.replace("/", "-") + "-" + roomName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public start(
|
public async start(
|
||||||
roomName: string,
|
roomName: string,
|
||||||
playerName: string,
|
playerName: string,
|
||||||
jwt?: string,
|
jwt?: string,
|
||||||
config?: object,
|
config?: object,
|
||||||
interfaceConfig?: object,
|
interfaceConfig?: object,
|
||||||
jitsiUrl?: string,
|
jitsiUrl?: string
|
||||||
jitsiWidth?: number
|
) {
|
||||||
): Promise<CoWebsite> {
|
const coWebsite = coWebsiteManager.searchJitsi();
|
||||||
return coWebsiteManager.addCoWebsite(
|
|
||||||
async (cowebsiteDiv) => {
|
|
||||||
// Jitsi meet external API maintains some data in local storage
|
|
||||||
// which is sent via the appData URL parameter when joining a
|
|
||||||
// conference. Problem is that this data grows indefinitely. Thus
|
|
||||||
// after some time the URLs get so huge that loading the iframe
|
|
||||||
// becomes slow and eventually breaks completely. Thus lets just
|
|
||||||
// clear jitsi local storage before starting a new conference.
|
|
||||||
window.localStorage.removeItem("jitsiLocalStorage");
|
|
||||||
|
|
||||||
const domain = jitsiUrl || JITSI_URL;
|
if (coWebsite) {
|
||||||
if (domain === undefined) {
|
await coWebsiteManager.closeCoWebsite(coWebsite);
|
||||||
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
|
}
|
||||||
}
|
|
||||||
await this.loadJitsiScript(domain);
|
|
||||||
|
|
||||||
const options: JitsiOptions = {
|
// Jitsi meet external API maintains some data in local storage
|
||||||
roomName: roomName,
|
// which is sent via the appData URL parameter when joining a
|
||||||
jwt: jwt,
|
// conference. Problem is that this data grows indefinitely. Thus
|
||||||
width: "100%",
|
// after some time the URLs get so huge that loading the iframe
|
||||||
height: "100%",
|
// becomes slow and eventually breaks completely. Thus lets just
|
||||||
parentNode: cowebsiteDiv,
|
// clear jitsi local storage before starting a new conference.
|
||||||
configOverwrite: mergeConfig(config),
|
window.localStorage.removeItem("jitsiLocalStorage");
|
||||||
interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig },
|
|
||||||
};
|
|
||||||
if (!options.jwt) {
|
|
||||||
delete options.jwt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
const domain = jitsiUrl || JITSI_URL;
|
||||||
const doResolve = (): void => {
|
if (domain === undefined) {
|
||||||
const iframe = cowebsiteDiv.querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
|
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
|
||||||
if (iframe === null) {
|
}
|
||||||
throw new Error("Could not find Jitsi Iframe");
|
await this.loadJitsiScript(domain);
|
||||||
}
|
|
||||||
resolve(iframe);
|
|
||||||
};
|
|
||||||
options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations.
|
|
||||||
setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
|
|
||||||
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
|
|
||||||
this.jitsiApi.executeCommand("displayName", playerName);
|
|
||||||
|
|
||||||
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
|
const options: JitsiOptions = {
|
||||||
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
|
roomName: roomName,
|
||||||
});
|
jwt: jwt,
|
||||||
},
|
width: "100%",
|
||||||
jitsiWidth,
|
height: "100%",
|
||||||
0
|
parentNode: coWebsiteManager.getCoWebsiteBuffer(),
|
||||||
);
|
configOverwrite: mergeConfig(config),
|
||||||
|
interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!options.jwt) {
|
||||||
|
delete options.jwt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const doResolve = (): void => {
|
||||||
|
const iframe = coWebsiteManager.getCoWebsiteBuffer().querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
|
||||||
|
if (iframe) {
|
||||||
|
coWebsiteManager.addCoWebsiteFromIframe(iframe, false, undefined, 0, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
coWebsiteManager.resizeAllIframes();
|
||||||
|
};
|
||||||
|
|
||||||
|
options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations.
|
||||||
|
setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
|
||||||
|
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
|
||||||
|
this.jitsiApi.executeCommand("displayName", playerName);
|
||||||
|
|
||||||
|
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
|
||||||
|
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public stop() {
|
public stop() {
|
||||||
@ -197,12 +197,6 @@ class JitsiFactory {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const jitsiCoWebsite = coWebsiteManager.searchJitsi();
|
|
||||||
|
|
||||||
if (jitsiCoWebsite) {
|
|
||||||
coWebsiteManager.closeJitsi().catch((e) => console.error(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback);
|
this.jitsiApi.removeListener("audioMuteStatusChanged", this.audioCallback);
|
||||||
this.jitsiApi.removeListener("videoMuteStatusChanged", this.videoCallback);
|
this.jitsiApi.removeListener("videoMuteStatusChanged", this.videoCallback);
|
||||||
this.jitsiApi?.dispose();
|
this.jitsiApi?.dispose();
|
||||||
|
@ -1,220 +1,3 @@
|
|||||||
/* A potentially shared website could appear in an iframe in the cowebsite space. */
|
@import "cowebsite/global";
|
||||||
|
@import "cowebsite/short-screens";
|
||||||
#cowebsite {
|
@import "cowebsite/wide-screens";
|
||||||
position: fixed;
|
|
||||||
z-index: 200;
|
|
||||||
transition: transform 0.5s;
|
|
||||||
background-color: whitesmoke;
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
&.loading {
|
|
||||||
background-color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
iframe {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-width: 100vw;
|
|
||||||
max-height: 100vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aside {
|
|
||||||
background: gray;
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
#cowebsite-aside-holder {
|
|
||||||
background: gray;
|
|
||||||
height: 20px;
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 80%;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#cowebsite-aside-buttons {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-bottom: auto;
|
|
||||||
flex: 1;
|
|
||||||
justify-content: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-right-btn{
|
|
||||||
transform: scale(0.5);
|
|
||||||
cursor: url('./images/cursor_pointer.png'), pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#cowebsite-sub-icons {
|
|
||||||
display: flex;
|
|
||||||
margin-top: auto;
|
|
||||||
visibility: hidden;
|
|
||||||
justify-content: end;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-container {
|
|
||||||
position: absolute;
|
|
||||||
display: none;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&-main {
|
|
||||||
padding: 2% 5%;
|
|
||||||
height: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-sub {
|
|
||||||
position: absolute !important;
|
|
||||||
display: inline-flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
bottom: 23%;
|
|
||||||
height: 20% !important;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-slot-0 {
|
|
||||||
z-index: 70 !important;
|
|
||||||
background-color: whitesmoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
@for $i from 1 through 4 {
|
|
||||||
&-slot-#{$i} {
|
|
||||||
transition: transform 0.5s;
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
display: none;
|
|
||||||
background-color: #333333;
|
|
||||||
|
|
||||||
@if $i == 1 {
|
|
||||||
width: 100%;
|
|
||||||
} @else {
|
|
||||||
width: 33%;
|
|
||||||
margin: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overlay {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
z-index: 50;
|
|
||||||
position: absolute;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.actions-move {
|
|
||||||
display: none;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
gap: 10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba($color: #333333, $alpha: 0.6);
|
|
||||||
|
|
||||||
.actions-move {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
pointer-events: all !important;
|
|
||||||
margin: 3% 2%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: end;
|
|
||||||
position: relative;
|
|
||||||
z-index: 50;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
margin: 8px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-buffer {
|
|
||||||
iframe {
|
|
||||||
z-index: 45 !important;
|
|
||||||
pointer-events: none !important;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 0;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
pointer-events: all !important;
|
|
||||||
z-index: 205 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-main {
|
|
||||||
pointer-events: all !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thumbnail {
|
|
||||||
transform: scale(0.5, 0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.pixel {
|
|
||||||
visibility: hidden;
|
|
||||||
height: 1px;
|
|
||||||
width: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-aspect-ratio: 1/1) {
|
|
||||||
#cowebsite {
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 50%;
|
|
||||||
height: 100vh;
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
&.loading {
|
|
||||||
transform: translateX(90%);
|
|
||||||
}
|
|
||||||
&.hidden {
|
|
||||||
transform: translateX(100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
aside {
|
|
||||||
width: 30px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-aside-holder {
|
|
||||||
cursor: ew-resize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
119
front/style/cowebsite/_global.scss
Normal file
119
front/style/cowebsite/_global.scss
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#cowebsite {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 820;
|
||||||
|
transition: transform 0.5s;
|
||||||
|
background-color: rgba(10, 9, 9, 0.8);
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
main {
|
||||||
|
iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
max-width: 100vw;
|
||||||
|
max-height: 100vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aside {
|
||||||
|
background: gray;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
#cowebsite-aside-holder {
|
||||||
|
background: gray;
|
||||||
|
height: 20px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 80%;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#cowebsite-aside-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: auto;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-right-btn {
|
||||||
|
transform: scale(0.5);
|
||||||
|
cursor: url("./images/cursor_pointer.png"), pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cowebsite-other-actions {
|
||||||
|
display: flex;
|
||||||
|
margin-top: auto;
|
||||||
|
visibility: hidden;
|
||||||
|
justify-content: end;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-loader {
|
||||||
|
width: 20%;
|
||||||
|
|
||||||
|
#smoke {
|
||||||
|
@for $i from 1 through 3 {
|
||||||
|
#trail-#{$i} {
|
||||||
|
@for $y from 1 through 3 {
|
||||||
|
#trail-#{$i}-state-#{$y} {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-slot-main {
|
||||||
|
z-index: 70 !important;
|
||||||
|
background-color: rgba(10, 9, 9, 0);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-buffer {
|
||||||
|
iframe {
|
||||||
|
z-index: 45 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 0;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
&.pixel {
|
||||||
|
height: 1px !important;
|
||||||
|
width: 1px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
pointer-events: all !important;
|
||||||
|
z-index: 821 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlighted {
|
||||||
|
pointer-events: all !important;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail {
|
||||||
|
transform: scale(0.5, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pixel {
|
||||||
|
visibility: hidden;
|
||||||
|
height: 1px;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
}
|
84
front/style/cowebsite/_short-screens.scss
Normal file
84
front/style/cowebsite/_short-screens.scss
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
#main-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cowebsite {
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 50%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
|
||||||
|
visibility: collapse;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
|
||||||
|
&.loading {
|
||||||
|
visibility: visible;
|
||||||
|
transform: translateY(0%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.opened {
|
||||||
|
visibility: visible;
|
||||||
|
transform: translateY(0%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.closing {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-loader {
|
||||||
|
height: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
aside {
|
||||||
|
height: 50px;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
#cowebsite-aside-holder {
|
||||||
|
height: 100%;
|
||||||
|
cursor: ns-resize;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#cowebsite-aside-buttons {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-bottom: 0;
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cowebsite-fullscreen {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cowebsite-other-actions {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 0;
|
||||||
|
height: 100%;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-right-btn {
|
||||||
|
img {
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
front/style/cowebsite/_wide-screens.scss
Normal file
41
front/style/cowebsite/_wide-screens.scss
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
@include media-breakpoint-down(lg) {
|
||||||
|
#cowebsite {
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 50%;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
visibility: collapse;
|
||||||
|
transform: translateX(100%);
|
||||||
|
|
||||||
|
&.loading {
|
||||||
|
visibility: visible;
|
||||||
|
transform: translateX(0%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.opened {
|
||||||
|
visibility: visible;
|
||||||
|
transform: translateX(0%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.closing {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
aside {
|
||||||
|
width: 30px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-aside-holder {
|
||||||
|
cursor: ew-resize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user