Spaces:
Running
Running
| <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 { env } from "$env/dynamic/public"; | |
| 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>; | |
| 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()}`); | |
| }; | |
| </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={env.PUBLIC_FILE_UPLOAD_DIR}/{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?.title} class="w-14 h-14 rounded-lg object-cover" /> | |
| <div> | |
| <p class="text-neutral-200 text-base font-medium">{gallery?.model?.title}</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> | |
| <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> | |
| </div> | |
| {/if} | |
| </div> | |
| {/if} | |
| </div> |