<script lang="ts"> import { clickoutside } from '@svelte-put/clickoutside'; import { goto } from "$app/navigation"; import { page } from "$app/stores"; import { get } from "svelte/store"; import Icon from "@iconify/svelte"; import { galleryStore } from "$lib/stores/use-gallery"; import Reactions from '../reactions/Reactions.svelte'; import Button from '$lib/components/Button.svelte'; export let form: Record<string, string> | undefined = undefined; let { open, gallery, previous, next } = get(galleryStore); let loading = false; galleryStore.subscribe((value) => { open = value?.open; gallery = value?.gallery; previous = value?.previous; next = value?.next; }); const handleClose = () => { galleryStore.update((value) => { return { ...value, open: false, }; }); $page.url.searchParams.delete('model'); goto(`?${$page.url.searchParams.toString()}`); }; const handlePagination = async (id?: string) => { if (!id) return; loading = true; const request = await fetch(`/api/community/${id}?${new URLSearchParams(form)}`); const { gallery, next, previous } = await request.json(); galleryStore.set({ gallery, open: true, next, previous }); loading = false; $page.url.searchParams.set('gallery', id); goto(`?${$page.url.searchParams.toString()}`); }; // to url search params const handleClickModel = (id?: string) => { if (!id) return; $page.url.searchParams.set('model', id); $page.url.searchParams.delete('gallery'); goto(`/?${$page.url.searchParams.toString()}`); }; const handlePressEscape = (event: KeyboardEvent) => { if (event.key === 'Escape') { handleClose(); } }; </script> <div class="w-full fixed top-0 left-0 h-full bg-black bg-opacity-50 z-40 backdrop-blur transition-all duration-100 p-6 lg:p-10 flex items-center justify-center" class:opacity-0={!open} class:pointer-events-none={!open} > {#if open} <div class="mx-auto w-full max-w-6xl bg-neutral-900 transition-all duration-200 lg:grid lg:grid-cols-2 rounded-xl overflow-hidden" use:clickoutside on:clickoutside={handleClose} > {#if gallery?.id} <img src="/api/images/{gallery?.image}" alt={gallery?.prompt} class="w-full object-cover h-[200px] lg:h-auto" /> <div class="flex flex-col justify-between w-full overflow-auto flex-1"> <div class="w-full p-6"> <header class="w-full flex items-start justify-between px-2 pt-2"> <div class="flex items-center justify-start gap-4"> <img src={gallery?.user?.picture} class="w-12 h-12 rounded-full object-cover" alt={gallery?.user?.name} /> <div> <p class="text-neutral-100 font-bold text-lg"> {gallery?.user?.name} </p> <p class="text-neutral-400 text-sm"> @{gallery?.user?.preferred_username} </p> </div> </div> <button on:click={handleClose}> <Icon icon="carbon:close" class="w-6 h-6 text-white" /> </button> </header> <div class="mt-8 grid grid-cols-1 gap-5 overflow-auto"> <div class="w-full px-2"> <Reactions reactions={gallery?.reactions} gallery_id={gallery.id} /> </div> <div> <button class="flex items-center justify-start gap-4 cursor-pointer w-full text-left transition-all duration-200 hover:bg-neutral-950/50 p-3 group relative rounded-lg" on:click={() => handleClickModel(gallery?.model?.id)} > <img src={gallery?.model?.image} alt={gallery?.model?.id} class="w-14 h-14 rounded-lg object-cover" /> <div> <p class="text-neutral-200 text-base font-medium">{gallery?.model?.id}</p> <p class="text-neutral-400 text-sm">{gallery?.model?.id}</p> </div> <div class="rounded-full absolute top-1/2 -translate-y-1/2 text-neutral-100 w-8 h-8 right-4 bg-pink-500 flex items-center justify-center transition-all duration-200 group-hover:opacity-100 opacity-0"> <Icon icon="tabler:arrow-up" class="w-5 h-5 transform rotate-45 font-bold" /> </div> </button> </div> <div class="px-2"> <p class="text-neutral-400 font-semibold text-xs uppercase"> Prompt </p> <p class="text-neutral-200 text-base font-medium mt-2">"{gallery?.prompt}"</p> </div> <div class="px-2"> <p class="text-neutral-400 font-semibold text-xs uppercase"> Dimension </p> <p class="text-neutral-200 text-base font-medium mt-2">1024x1024</p> </div> </div> </div> {#if form} <footer class="border-t border-neutral-800 px-8 py-6 flex items-center justify-between"> <Button size="lg" theme="dark" disabled={!previous} loading={loading} onClick={() => handlePagination(previous)} > Previous </Button> <Button size="lg" theme="light" loading={loading} disabled={!next} onClick={() => handlePagination(next)} > Next </Button> </footer> {/if} </div> {/if} </div> {/if} </div> <svelte:window on:keydown|preventDefault={handlePressEscape} />