Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 4,209 Bytes
10b8070 a1a6daf 10b8070 a1a6daf 10b8070 a1a6daf 10b8070 a1a6daf 10b8070 a1a6daf 10b8070 a1a6daf 10b8070 a1a6daf 10b8070 9fc7651 10b8070 9fc7651 10b8070 05aaf48 a1a6daf 05aaf48 9fc7651 05aaf48 10b8070 |
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 |
<script lang="ts">
import { base } from "$app/paths";
import type { ToolLogoColor, ToolLogoIcon } from "$lib/types/Tool";
import { debounce } from "$lib/utils/debounce";
import { onMount } from "svelte";
import ToolLogo from "./ToolLogo.svelte";
import CarbonClose from "~icons/carbon/close";
interface ToolSuggestion {
_id: string;
displayName: string;
createdByName: string;
color: ToolLogoColor;
icon: ToolLogoIcon;
}
interface Props {
toolIds?: string[];
}
let { toolIds = $bindable([]) }: Props = $props();
let selectedValues: ToolSuggestion[] = $state([]);
onMount(async () => {
selectedValues = await Promise.all(
toolIds.map(async (id) => await fetch(`${base}/api/tools/${id}`).then((res) => res.json()))
);
await fetchSuggestions("");
});
let inputValue = $state("");
let maxValues = 3;
let suggestions: ToolSuggestion[] = $state([]);
async function fetchSuggestions(query: string) {
suggestions = (await fetch(`${base}/api/tools/search?q=${query}`).then((res) =>
res.json()
)) satisfies ToolSuggestion[];
}
const debouncedFetch = debounce((query: string) => fetchSuggestions(query), 300);
function addValue(value: ToolSuggestion) {
if (selectedValues.length < maxValues && !selectedValues.includes(value)) {
selectedValues = [...selectedValues, value];
toolIds = [...toolIds, value._id];
inputValue = "";
suggestions = [];
}
}
function removeValue(id: ToolSuggestion["_id"]) {
selectedValues = selectedValues.filter((v) => v._id !== id);
toolIds = selectedValues.map((value) => value._id);
}
</script>
{#if selectedValues.length > 0}
<div class="flex flex-wrap items-center justify-center gap-2">
{#each selectedValues as value}
<div
class="flex items-center justify-center space-x-2 rounded border border-gray-300 bg-gray-200 px-2 py-1"
>
{#key value.color + value.icon}
<ToolLogo color={value.color} icon={value.icon} size="sm" />
{/key}
<div class="flex flex-col items-center justify-center py-1">
<a
href={`${base}/tools/${value._id}`}
target="_blank"
class="line-clamp-1 truncate font-semibold text-blue-600 hover:underline"
>{value.displayName}</a
>
{#if value.createdByName}
<p class="text-center text-xs text-gray-500">
Created by
<a class="underline" href="{base}/tools?user={value.createdByName}" target="_blank"
>{value.createdByName}</a
>
</p>
{:else}
<p class="text-center text-xs text-gray-500">Official HuggingChat tool</p>
{/if}
</div>
<button
onclick={(e) => {
e.preventDefault();
e.stopPropagation();
removeValue(value._id);
}}
class="text-lg text-gray-600"
>
<CarbonClose />
</button>
</div>
{/each}
</div>
{/if}
{#if selectedValues.length < maxValues}
<div class="group relative block">
<input
type="text"
bind:value={inputValue}
oninput={(ev) => {
inputValue = ev.currentTarget.value;
debouncedFetch(inputValue);
}}
disabled={selectedValues.length >= maxValues}
class="w-full rounded border border-gray-200 bg-gray-100 px-3 py-2"
class:opacity-50={selectedValues.length >= maxValues}
class:bg-gray-100={selectedValues.length >= maxValues}
placeholder="Type to search tools..."
tabindex="0"
/>
{#if suggestions.length > 0}
<div
class="invisible absolute z-10 mt-1 w-full rounded border border-gray-300 bg-white shadow-lg group-focus-within:visible"
tabindex="-1"
>
{#if inputValue === ""}
<p class="px-3 py-2 text-left text-xs text-gray-500">
Start typing to search for tools...
</p>
{:else}
{#each suggestions as suggestion}
<button
onclick={(e) => {
e.preventDefault();
e.stopPropagation();
addValue(suggestion);
}}
class="w-full cursor-pointer px-3 py-2 text-left hover:bg-blue-500 hover:text-white"
tabindex="0"
>
{suggestion.displayName}
{#if suggestion.createdByName}
<span class="text-xs text-gray-500"> by {suggestion.createdByName}</span>
{/if}
</button>
{/each}
{/if}
</div>
{/if}
</div>
{/if}
|