Implemented thumbhash into MediaComponent and reduced content-shift in editor

This commit is contained in:
Mawoka
2023-09-23 11:15:40 +02:00
parent dd0f953713
commit c7f6f4dc7c
3 changed files with 21 additions and 11 deletions
@@ -7,14 +7,17 @@ SPDX-License-Identifier: MPL-2.0
<script lang="ts"> <script lang="ts">
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
import { thumbHashToDataURL } from 'thumbhash';
export let src: string; export let src: string;
export let css_classes = 'max-h-64 h-auto w-auto'; export let css_classes = 'max-h-64 h-auto w-auto';
export let added_thumbhash_classes = 'h-full';
export let muted = true; export let muted = true;
export let allow_fullscreen = true; export let allow_fullscreen = true;
let type: 'img' | 'video' | undefined = undefined; let type: 'img' | 'video' | undefined = undefined;
let img_data; let img_data;
let thumbhash_data: string;
function base64ToBytes(base64: string): Uint8Array { function base64ToBytes(base64: string): Uint8Array {
const binString = atob(base64); const binString = atob(base64);
@@ -31,11 +34,13 @@ SPDX-License-Identifier: MPL-2.0
type = 'video'; type = 'video';
} else { } else {
type = 'img'; type = 'img';
thumbhash_data = thumbHashToDataURL(base64ToBytes(res.headers.get('x-thumbhash')));
const data = await fetch(`/api/v1/storage/download/${src}`); const data = await fetch(`/api/v1/storage/download/${src}`);
img_data = { img_data = {
data: URL.createObjectURL(await data.blob()), data: URL.createObjectURL(await data.blob()),
alt_text: new TextDecoder().decode(base64ToBytes(res.headers.get('X-Alt-Text'))) alt_text: new TextDecoder().decode(base64ToBytes(res.headers.get('X-Alt-Text')))
}; };
thumbhash_data = undefined;
} }
}; };
const update_url = () => { const update_url = () => {
@@ -58,10 +63,11 @@ SPDX-License-Identifier: MPL-2.0
</script> </script>
{#await media} {#await media}
<p>Placeholder</p> <img src={thumbhash_data} class={`${css_classes} ${added_thumbhash_classes}`} />
{:then data} {:then data}
{#if type === 'img'} {#if type === 'img'}
<img <img
in:fade={{ duration: 300 }}
src={img_data.data} src={img_data.data}
alt={img_data.alt_text ?? 'Not available'} alt={img_data.alt_text ?? 'Not available'}
class={css_classes} class={css_classes}
+8 -9
View File
@@ -13,6 +13,7 @@ SPDX-License-Identifier: MPL-2.0
import Spinner from '../Spinner.svelte'; import Spinner from '../Spinner.svelte';
// import { createTippy } from 'svelte-tippy'; // import { createTippy } from 'svelte-tippy';
import { getLocalization } from '$lib/i18n'; import { getLocalization } from '$lib/i18n';
import MediaComponent from '$lib/editor/MediaComponent.svelte';
// import MediaComponent from "$lib/editor/MediaComponent.svelte"; // import MediaComponent from "$lib/editor/MediaComponent.svelte";
const { t } = getLocalization(); const { t } = getLocalization();
@@ -79,7 +80,7 @@ SPDX-License-Identifier: MPL-2.0
*/ */
</script> </script>
<div class="w-full max-h-full pb-20 px-20 h-full"> <div class="w-full max-h-full pb-10 px-10 h-full">
<div class="rounded-lg bg-white w-full h-full border-gray-500 dark:bg-gray-700 shadow-2xl"> <div class="rounded-lg bg-white w-full h-full border-gray-500 dark:bg-gray-700 shadow-2xl">
<div class="h-12 bg-gray-300 rounded-t-lg dark:bg-gray-500"> <div class="h-12 bg-gray-300 rounded-t-lg dark:bg-gray-500">
<div class="flex align-middle p-4 gap-3"> <div class="flex align-middle p-4 gap-3">
@@ -123,9 +124,9 @@ SPDX-License-Identifier: MPL-2.0
{/await} {/await}
{/key} {/key}
</div> </div>
{#if data.questions[selected_question].image != undefined && data.questions[selected_question].image !== ''} {#if data.questions[selected_question].image}
<div class="flex justify-center pt-10 w-full max-h-72"> <div class="flex justify-center pt-10 w-full h-72">
<div class="max-h-72 h-auto relative"> <div class="h-72 relative">
<button <button
class="rounded-full absolute -top-2 -right-2 opacity-70 hover:opacity-100 transition" class="rounded-full absolute -top-2 -right-2 opacity-70 hover:opacity-100 transition"
type="button" type="button"
@@ -148,9 +149,7 @@ SPDX-License-Identifier: MPL-2.0
/> />
</svg> </svg>
</button> </button>
{#await import('$lib/editor/MediaComponent.svelte') then c} <MediaComponent bind:src={image_url} />
<svelte:component this={c.default} bind:src={image_url} />
{/await}
</div> </div>
</div> </div>
{:else} {:else}
@@ -192,10 +191,10 @@ SPDX-License-Identifier: MPL-2.0
/> />
</div> </div>
</div> </div>
<div class="flex justify-center pt-10"> <div class="flex justify-center py-5">
<p>{type_to_name[String(data.questions[selected_question].type)]}</p> <p>{type_to_name[String(data.questions[selected_question].type)]}</p>
</div> </div>
<div class="flex justify-center py-10 w-full"> <div class="flex justify-center w-full">
{#if type === QuizQuestionType.ABCD || type === QuizQuestionType.CHECK} {#if type === QuizQuestionType.ABCD || type === QuizQuestionType.CHECK}
{#await import('$lib/editor/ABCDEditorPart.svelte')} {#await import('$lib/editor/ABCDEditorPart.svelte')}
<Spinner my_20={false} /> <Spinner my_20={false} />
+6 -1
View File
@@ -17,6 +17,7 @@ SPDX-License-Identifier: MPL-2.0
import { fly } from 'svelte/transition'; import { fly } from 'svelte/transition';
import StartGamePopup from '$lib/dashboard/start_game.svelte'; import StartGamePopup from '$lib/dashboard/start_game.svelte';
import Analytics from './Analytics.svelte'; import Analytics from './Analytics.svelte';
import MediaComponent from '$lib/editor/MediaComponent.svelte';
// import GrayButton from "$lib/components/buttons/gray.svelte"; // import GrayButton from "$lib/components/buttons/gray.svelte";
@@ -177,11 +178,15 @@ SPDX-License-Identifier: MPL-2.0
> >
<div class="hidden lg:flex w-auto h-full items-center relative"> <div class="hidden lg:flex w-auto h-full items-center relative">
{#if quiz.cover_image} {#if quiz.cover_image}
<img <!-- <img
src="/api/v1/storage/download/{quiz.cover_image}" src="/api/v1/storage/download/{quiz.cover_image}"
alt="user provided" alt="user provided"
loading="lazy" loading="lazy"
class="shrink-0 max-w-full max-h-full absolute rounded" class="shrink-0 max-w-full max-h-full absolute rounded"
/>-->
<MediaComponent
src={quiz.cover_image}
css_classes="shrink-0 max-w-full max-h-full absolute rounded"
/> />
{/if} {/if}
</div> </div>