Fix desync in dragged elements with client side state object
This commit is contained in:
parent
a4e4f1157b
commit
4d24b90afa
4 changed files with 66 additions and 12 deletions
src
lib
routes/(games)/pakubiiti
44
src/lib/client/AlbumClientState.svelte.ts
Normal file
44
src/lib/client/AlbumClientState.svelte.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { getContext, onDestroy, setContext } from 'svelte';
|
||||
import type { AlbumData, AlbumDataField } from '$lib/types';
|
||||
|
||||
export class AlbumClientState {
|
||||
albums = $state<AlbumData>({
|
||||
names: [],
|
||||
artists: [],
|
||||
images: []
|
||||
});
|
||||
|
||||
constructor() {
|
||||
onDestroy(() => {
|
||||
this.albums = {
|
||||
names: [],
|
||||
artists: [],
|
||||
images: []
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
update(items: AlbumDataField[], type: string) {
|
||||
if (type === 'names') {
|
||||
this.albums.names = items;
|
||||
}
|
||||
|
||||
if (type === 'artists') {
|
||||
this.albums.artists = items;
|
||||
}
|
||||
|
||||
if (type === 'images') {
|
||||
this.albums.images = items;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ALBUM_KEY = Symbol('ALBUM');
|
||||
|
||||
export function setAlbumClientState() {
|
||||
return setContext(ALBUM_KEY, new AlbumClientState());
|
||||
}
|
||||
|
||||
export function getAlbumClientState() {
|
||||
return getContext<ReturnType<typeof setAlbumClientState>>(ALBUM_KEY);
|
||||
}
|
|
@ -11,16 +11,20 @@
|
|||
type Item
|
||||
} from 'svelte-dnd-action';
|
||||
import * as Card from '$lib/components/ui/card/index.js';
|
||||
import { getAlbumClientState } from '$lib/client/AlbumClientState.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let { items = $bindable(), image = false, type = 'default' } = $props();
|
||||
let { items, image = false, type = 'default' } = $props();
|
||||
|
||||
const flipDurationMs = 300;
|
||||
const clientState = getAlbumClientState();
|
||||
|
||||
function handleDndConsider(e: CustomEvent<DndEvent<Item>>) {
|
||||
items = e.detail.items;
|
||||
}
|
||||
function handleDndFinalize(e: CustomEvent<DndEvent<Item>>) {
|
||||
items = e.detail.items;
|
||||
clientState.update(e.detail.items as AlbumDataField[], type);
|
||||
}
|
||||
function transformDraggedElement(draggedEl: HTMLElement | undefined) {
|
||||
if (!draggedEl) {
|
||||
|
@ -44,6 +48,10 @@
|
|||
: 'border-blue-400'
|
||||
}`
|
||||
);
|
||||
|
||||
onMount(() => {
|
||||
clientState.update(items as AlbumDataField[], type);
|
||||
});
|
||||
</script>
|
||||
|
||||
{#snippet card(item: AlbumDataField, i: number)}
|
||||
|
|
9
src/routes/(games)/pakubiiti/+layout.svelte
Normal file
9
src/routes/(games)/pakubiiti/+layout.svelte
Normal file
|
@ -0,0 +1,9 @@
|
|||
<script lang="ts">
|
||||
import { setAlbumClientState } from '$lib/client/AlbumClientState.svelte';
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
setAlbumClientState();
|
||||
</script>
|
||||
|
||||
{@render children()}
|
|
@ -10,20 +10,13 @@
|
|||
import type { AlbumData } from '$lib/types';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { expoIn, expoOut } from 'svelte/easing';
|
||||
import { getAlbumClientState } from '$lib/client/AlbumClientState.svelte';
|
||||
|
||||
let { data }: { data: PageData; form: FormData } = $props();
|
||||
|
||||
let loading = $state(false);
|
||||
let oldAlbums: AlbumData | undefined = $state();
|
||||
|
||||
// Used when user answers wrong and no new data comes in
|
||||
$effect(() => {
|
||||
if (data.streamed?.albums) {
|
||||
data.streamed.albums.then((data) => {
|
||||
oldAlbums = data as AlbumData;
|
||||
});
|
||||
}
|
||||
});
|
||||
const clientState = getAlbumClientState();
|
||||
</script>
|
||||
|
||||
{#snippet footer(loading: boolean)}
|
||||
|
@ -93,7 +86,7 @@
|
|||
</AlertDialog.Content>
|
||||
</AlertDialog.Root>
|
||||
|
||||
<header class="font-title mb-12 flex flex-col items-center">
|
||||
<header class="mb-12 flex flex-col items-center font-title">
|
||||
<h1 class="mb-1 scroll-m-20 text-5xl font-extrabold tracking-tight lg:text-6xl">Paku biiti</h1>
|
||||
<p class="text-xl font-semibold text-muted-foreground">
|
||||
Lohista kokku õiged albumi <span class="text-red-600 dark:text-red-400">nimed</span>,
|
||||
|
@ -126,7 +119,7 @@
|
|||
{/await}
|
||||
{:else}
|
||||
<div class="grid w-full gap-4" out:fade={{ duration: 150, easing: expoOut }}>
|
||||
{@render playArea(oldAlbums)}
|
||||
{@render playArea(clientState.albums)}
|
||||
</div>
|
||||
{@render footer(false)}
|
||||
{/if}
|
||||
|
|
Loading…
Add table
Reference in a new issue