enzostvs's picture
enzostvs HF staff
placeholder models
1bc7bbb
raw
history blame
3.42 kB
<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>