Co-website management move to Svelte
This commit is contained in:
parent
0bf1acfefb
commit
4f068c72be
33 changed files with 1409 additions and 759 deletions
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>
|
Loading…
Add table
Add a link
Reference in a new issue