File size: 3,418 Bytes
1c0590e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1bc7bbb
1c0590e
 
 
 
 
 
 
 
 
 
 
 
 
eb29a95
 
 
 
 
 
 
1c0590e
 
 
 
 
 
 
 
 
eb29a95
 
 
 
 
 
 
1c0590e
 
 
 
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
<script lang="ts">
  import { clickoutside } from '@svelte-put/clickoutside';
	import type { ModelCard } from "$lib/type";
	import Icon from "@iconify/svelte";
	import Item from "./Item.svelte";

  export let defaultModels: ModelCard[] = [];
  export let onChange: (model: ModelCard | null) => void;
  export let value: ModelCard | null = null;

  let models: ModelCard[] = [];
  let search: string = "";
  let open: boolean = false;

  const handleSearch = (event: any) => {
    search = event.target.value;
    if (search.length >= 3) {
      open = true;
      onSearch();
    } else {
      models = []
    }
  }

  const onSearch = async () => {
    const request = await fetch(`/api/models?search=${search}`);
    const response = await request.json();

    if (response?.cards && response?.cards.length > 0) {
      models = response.cards;
    } else {
      models = [];
    }
  }

  const handleClickOutside = (event: any) => {
    if (event.target === event.currentTarget) {
      open = false;
    }
  }

</script>

<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
  class="w-full bg-neutral-900 rounded-xl border border-neutral-800 p-4 text-neutral-500 focus-within:border-neutral-700 transition-all duration-200 relative"
  use:clickoutside on:clickoutside={() => open = false}
  on:click={handleClickOutside}
>
  {#if value}
    <div class="flex items-center justify-between gap-4">
      <div class="flex items-center justify-start gap-3">
        <img src={value.image} alt={value.title} class="w-6 h-6 rounded-lg object-cover" />
        <p class="text-neutral-200 text-base font-medium">{value.title}</p>
      </div>
      <button on:click={() => onChange(null)}>
        <Icon icon="maki:cross" class="w-4 h-4 text-neutral-500 transition-all duration-200 cursor-pointer" />
      </button>
    </div>
    {:else}
    <div class="flex items-center justify-start gap-2 group">
      <Icon icon="lucide:search" class="w-5 h-5 text-neutral-500 group-focus-within:text-neutral-100 transition-all duration-200" />
      <input
        value={search}
        type="text"
        class="w-full bg-transparent text-neutral-200 placeholder:text-neutral-500 outline-none"
        placeholder="Filter by model name "
        on:focus={() => open = true}
        on:input={handleSearch}
      />
    </div>
  {/if}
  <div
    class="w-full absolute bottom-0 left-0 p-2 bg-neutral-900 rounded-xl translate-y-[calc(100%+12px)] border border-neutral-800 transition-all duration-200 z-10"
    class:opacity-0="{!open}"
    class:pointer-events-none="{!open}"
  > 
    {#if search?.length >= 3}
      {#if models?.length > 0}
        {#each models as model}
          <Item
            model={model}
            onClick={() => {
              open = false;
              onChange(model)
            }}
          />
        {/each}
      {:else}
        <div class="flex items-center justify-center flex-col gap-2 p-3">
          <Icon icon="bxs:sad" class="w-12 h-12 text-neutral-500 transition-all duration-200" />
          <p class="text-neutral-500 text-base">No models found</p>
        </div>
      {/if}
    {:else}
      {#each defaultModels as model}
        <Item
          model={model}
          onClick={() => {
            open = false;
            onChange(model)
          }}
        />
      {/each}
    {/if}
  </div>
</div>