File size: 7,624 Bytes
d6da254
83d9f5e
332141a
83deba1
d6da254
 
 
 
 
 
 
f05d33c
d6da254
0dfbd23
 
549506b
d6da254
f05d33c
 
d6da254
 
332141a
f05d33c
 
 
 
 
 
83deba1
 
332141a
 
d6da254
0d4cbee
 
 
 
 
 
 
 
7a5d25a
 
 
 
 
332141a
549506b
332141a
549506b
d6da254
 
 
644d65a
f05d33c
 
644d65a
d6da254
644d65a
 
 
 
 
 
c43830b
 
644d65a
c43830b
 
549506b
644d65a
0d4cbee
644d65a
 
 
d6da254
 
644d65a
 
 
 
727ce74
 
 
 
644d65a
d6da254
644d65a
8fce765
 
727ce74
644d65a
727ce74
644d65a
 
 
 
727ce74
644d65a
727ce74
644d65a
 
d6da254
644d65a
0d4cbee
dec161b
 
 
0d4cbee
644d65a
0d4cbee
74e73b3
644d65a
 
 
0d4cbee
 
 
 
 
 
 
 
644d65a
 
 
 
 
 
 
 
 
727ce74
 
1003d95
727ce74
07ab6eb
727ce74
1003d95
727ce74
07ab6eb
727ce74
1003d95
727ce74
07ab6eb
727ce74
 
 
644d65a
 
09efb88
644d65a
727ce74
644d65a
 
 
 
 
d6da254
644d65a
d6da254
644d65a
7a5d25a
063f28a
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<script lang="ts">
  import { clickoutside } from '@svelte-put/clickoutside';
  import { goto, invalidate } from "$app/navigation";
  import { page } from "$app/stores"; 
  import { get } from "svelte/store";
  import Icon from "@iconify/svelte";

  import { modelStore } from "$lib/stores/use-model";
  import UserIsLogged from '$lib/components/UserIsLogged.svelte';
  import Comments from '$lib/components/models/drawer/comments/Comments.svelte';

  let { open, model } = get(modelStore);

  $: author = model?.id.split('/')[0];
  $: repo = model?.id.split('/')[1];

  modelStore.subscribe((value) => {
    open = value?.open;
    model = value?.model;
  });

  const handleClose = async () => {
    modelStore.update((value) => {
      return {
        ...value,
        open: false,
      };
    });

    $page.url.searchParams.delete('model');
    await goto(`?${$page.url.searchParams.toString()}`);
    await invalidate(url => url.pathname.includes("/api/models"));
  };
  
  const handleClickNext = () => {
    const element = document.getElementById('gallery_examples');
    element?.scrollBy({
      left: 300,
      behavior: 'smooth'
    });
  }
  const handlePressEscape = (event: KeyboardEvent) => {
    if (event.key === 'Escape') {
      handleClose();
    }
  };
  const handleClickAuthor = async () => {
    $page.url.searchParams.set('search', author as string);
    handleClose();
  }
</script>

<div
  class="w-full fixed top-0 left-0 h-full bg-black bg-opacity-50 z-0 backdrop-blur transition-all duration-100"
  class:opacity-0={!open}
  class:pointer-events-none={!open}
  class:!z-40={open}
>
  {#if open}
    <div
      class="ml-auto w-full max-w-3xl bg-neutral-950 h-full border-l border-neutral-800 transition-all duration-200 flex flex-col justify-between"
      use:clickoutside on:clickoutside={handleClose}
      >
      <div class="p-8 overflow-auto">
        <header class="flex w-full justify-between items-start mb-6 pr-6 gap-3">
          <div class="flex items-center justify-start gap-3 lg:gap-6 w-full">
            <img src={model?.image} class="lg:w-16 lg:h-16 w-12 h-12 rounded-xl bg-neutral-800 object-cover" alt={model?.id} />
            <div class="w-full truncate">
              <p class="text-neutral-300 font-semibold text-lg lg:text-2xl mb-1 truncate w-full">
                <button class="underline text-white" on:click={handleClickAuthor}>{author}</button>/{repo}
              </p>
              <a href="https://huggingface.co/{model?.id}" target="_blank" class="text-neutral-400 underline hover:text-neutral-300 flex items-center justify-start gap-1">
                <Icon icon="iconamoon:link-external-fill" class="w-4 h-4" /> 
                View on HuggingFace
              </a>
            </div>
          </div>
          <button on:click={handleClose}>
            <Icon icon="carbon:close" class="w-6 h-6 text-white cursor-pointer" />
          </button>
        </header>
        <main class="grid grid-cols-1 gap-6">
          <div class="justify-start items-center gap-4 flex">
            <div class="bg-red-500 bg-opacity-20 border border-red-500 md:px-4 md:py-2 px-3 py-1.5 rounded-full text-neutral-100 flex items-center justify-center gap-1 md:gap-2 font-medium text-sm md:text-base">
              <Icon icon="solar:heart-bold" class="lg:w-5 lg:h-5 w-4 h-4 text-red-500" />
              {model?.likes ?? 0}
            </div>
            <a
              href="https://huggingface.co/{model?.id}/tree/main"
              target="_blank"
              class="bg-blue-500 bg-opacity-20 border border-blue-500 hover:bg-opacity-60 transition-all duration-200 md:px-4 md:py-2 px-3 py-1.5 rounded-full text-neutral-100 flex items-center justify-center gap-1 md:gap-2 font-medium text-sm md:text-base"
            >
              <Icon icon="solar:download-square-bold" class="lg:w-5 lg:h-5 w-4 h-4 text-blue-500" />
              View files
            </a>
            <a
              href="/generate?model={model?.id}"
              class="bg-pink-500 bg-opacity-20 hover:bg-opacity-60 transition-all duration-200 border border-pink-500 md:px-4 md:py-2 px-3 py-1.5 rounded-full text-neutral-100 flex items-center justify-center gap-1 md:gap-2 font-medium text-sm md:text-base"
            >
              <Icon icon="fluent:glance-horizontal-sparkles-16-filled" class="lg:w-5 lg:h-5 w-4 h-4 text-pink-500" />
              Generate
            </a>
          </div>
          {#if model?.gallery && model?.gallery?.length > 0}
            <div class="-mr-8 relative">
              <p class="text-neutral-400 uppercase text-xs font-bold">
                Generations made by the community
              </p>
              <div id="gallery_examples" class="w-full h-[300px] mt-2 flex flex-nowrap overflow-auto gap-5 relative">
                {#each model?.gallery as example}
                  <div class="w-[300px] min-w-[300px] h-full relative">
                    <img src="/api/images/{example.image}"  class="w-full h-full bg-center bg-cover rounded-lg object-cover object-center bg-neutral-800" alt={example.prompt} />
                  </div>
                {/each}
              </div>
              <div class="w-[100px] h-full absolute right-0 top-0 bg-gradient-to-r from-transparent to-neutral-950 flex items-center justify-end pr-4">
                <button
                  class="w-8 h-8 rounded-full bg-neutral-100/20 flex items-center justify-center text-neutral-100 hover:bg-neutral-100/40 transition-all duration-200"
                  on:click={handleClickNext}
                >
                  <Icon icon="tabler:arrow-narrow-right" class="w-5 h-5" />
                </button>
              </div>
            </div>
          {:else}
            <div class="bg-neutral-900 rounded-lg p-8 text-center">
              <p class="text-neutral-400 font-base">No generation examples available for this model</p>
              <a href="/generate?model={model?.id}" class="text-neutral-100 underline">
                Generate the first one
              </a>
            </div>
          {/if}
          {#if model?.infos}
            <div class="bg-neutral-900/70 rounded-lg border border-neutral-800/20">
              <div class="border-b border-neutral-800/80 px-4 py-3">
                <p class="text-neutral-400 uppercase text-[10px]">license</p>
                <p class="text-neutral-100 font-medium text-base mt-0.5">{model?.infos?.license ?? 'N/A'}</p>
              </div>
              <div class="border-b border-neutral-800/80 px-4 py-3">
                <p class="text-neutral-400 uppercase text-[10px]">tags</p>
                <p class="text-neutral-100 font-medium text-base mt-0.5">{model?.infos?.tags?.join(', ')}</p>
              </div>
              <div class="px-4 py-3">
                <p class="text-neutral-400 uppercase text-[10px]">base_model</p>
                <p class="text-neutral-100 font-medium text-base mt-0.5">{model?.infos?.base_model ?? 'N/A'}</p>
              </div>
            </div>
          {/if}
        </main>
      </div>
      <footer class="p-8 border-t border-neutral-900 bg-neutral-900/30 flex flex-col justify-between relative">
        <p class="font-semibold text-neutral-100 text-base lg:text-lg mb-6">
          Commentaire{(model?.comments?.length ?? 0) > 1 ? 's' : ''} ({model?.comments?.length ?? 0})
        </p>
        {#if model?.id}
          <UserIsLogged>
            <Comments comments={model?.comments} model={model} />
          </UserIsLogged>
        {/if}
      </footer>
    </div>
  {/if}
</div>
<svelte:window on:keydown={handlePressEscape} />