File size: 5,667 Bytes
f05d33c
 
 
 
 
 
 
 
 
 
 
 
644d65a
f05d33c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
644d65a
f05d33c
 
 
 
 
 
 
 
 
 
 
644d65a
 
 
 
 
 
 
 
f05d33c
 
 
 
 
 
 
644d65a
 
 
 
 
 
 
 
0d4cbee
 
644d65a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0d4cbee
 
 
644d65a
 
0d4cbee
644d65a
 
 
 
 
 
 
 
 
 
 
 
0d4cbee
644d65a
 
f05d33c
644d65a
 
0d4cbee
644d65a
 
f05d33c
644d65a
f05d33c
 
 
644d65a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f05d33c
644d65a
 
 
f05d33c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<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>