File size: 6,172 Bytes
0b5f169 003aab5 4b8b411 65131f6 4b8b411 d47c403 60216ec e63e7c7 7b1d26a 003aab5 1754cbb d37b3c2 65131f6 d37b3c2 de14ada da50250 003aab5 d37b3c2 d4fcb0f 65131f6 0bcf467 d37b3c2 60216ec 65131f6 c6262f2 90c9ef4 65131f6 de14ada 65131f6 d37b3c2 60216ec d37b3c2 de14ada 0b5f169 65131f6 d37b3c2 dee0245 d37b3c2 f250f57 77100da 0b5f169 7965df6 de14ada 0b5f169 dee0245 0b5f169 65131f6 d47c403 65131f6 18f47bc 65131f6 d47c403 0b5f169 d47c403 a7b12ab dee0245 a7b12ab d47c403 0b5f169 dee0245 0b5f169 65131f6 60216ec 65131f6 1754cbb 65131f6 18f47bc 65131f6 ad1d85c 60216ec ad1d85c 1754cbb 7b1d26a a7b12ab dee0245 a7b12ab 7b1d26a 1754cbb 7b1d26a 0b5f169 |
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 165 166 167 168 169 170 171 172 173 174 175 |
<script lang="ts">
import type { Conversation, ModelEntryWithTokenizer } from "./types";
import { createEventDispatcher, tick } from "svelte";
import { FEATUED_MODELS_IDS } from "./inferencePlaygroundUtils";
import IconSearch from "../Icons/IconSearch.svelte";
import IconStar from "../Icons/IconStar.svelte";
export let models: ModelEntryWithTokenizer[];
export let conversation: Conversation;
let backdropEl: HTMLDivElement;
let highlightIdx = 0;
let ignoreCursorHighlight = false;
let containerEl: HTMLDivElement;
const dispatch = createEventDispatcher<{ modelSelected: string; close: void }>();
let featuredModels = models.filter(m => FEATUED_MODELS_IDS.includes(m.id));
let otherModels = models.filter(m => !FEATUED_MODELS_IDS.includes(m.id));
if (featuredModels.findIndex(model => model.id === conversation.model.id) !== -1) {
highlightIdx = featuredModels.findIndex(model => model.id === conversation.model.id);
} else {
highlightIdx = featuredModels.length + otherModels.findIndex(model => model.id === conversation.model.id);
}
function handleKeydown(event: KeyboardEvent) {
const { key } = event;
let scrollLogicalPosition: ScrollLogicalPosition = "end";
if (key === "Escape") {
event.preventDefault();
dispatch("close");
} else if (key === "Enter") {
event.preventDefault();
const highlightedEl = document.querySelector(".highlighted");
if (highlightedEl) {
(highlightedEl as HTMLButtonElement).click();
}
} else if (key === "ArrowUp") {
event.preventDefault();
highlightIdx--;
scrollLogicalPosition = "start";
ignoreCursorHighlight = true;
} else if (key === "ArrowDown") {
event.preventDefault();
highlightIdx++;
ignoreCursorHighlight = true;
}
const n = featuredModels.length + otherModels.length;
highlightIdx = ((highlightIdx % n) + n) % n;
scrollToResult(scrollLogicalPosition);
}
async function scrollToResult(block: ScrollLogicalPosition) {
await tick();
const highlightedEl = document.querySelector(".highlighted");
if (containerEl && highlightedEl) {
const { bottom: containerBottom, top: containerTop } = containerEl.getBoundingClientRect();
const { bottom: highlightedBottom, top: highlightedTop } = highlightedEl.getBoundingClientRect();
if (highlightedBottom > containerBottom || containerTop > highlightedTop) {
highlightedEl.scrollIntoView({ block });
}
}
}
function highlightRow(idx: number) {
if (!ignoreCursorHighlight) {
highlightIdx = idx;
}
}
function handleBackdropClick(event: MouseEvent) {
if (window?.getSelection()?.toString()) {
return;
}
if (event.target === backdropEl) {
dispatch("close");
}
}
function filterModels(query: string) {
featuredModels = models.filter(m =>
query
? FEATUED_MODELS_IDS.includes(m.id) && m.id.toLocaleLowerCase().includes(query.toLocaleLowerCase().trim())
: FEATUED_MODELS_IDS.includes(m.id)
);
otherModels = models.filter(m =>
query
? !FEATUED_MODELS_IDS.includes(m.id) && m.id.toLocaleLowerCase().includes(query.toLocaleLowerCase().trim())
: !FEATUED_MODELS_IDS.includes(m.id)
);
}
</script>
<svelte:window on:keydown={handleKeydown} on:mousemove={() => (ignoreCursorHighlight = false)} />
<!-- svelte-ignore a11y-no-static-element-interactions a11y-click-events-have-key-events -->
<div
class="fixed inset-0 z-10 flex h-screen items-start justify-center bg-black/85 pt-32"
bind:this={backdropEl}
on:click|stopPropagation={handleBackdropClick}
>
<div class="flex w-full max-w-[600px] items-start justify-center overflow-hidden whitespace-nowrap p-10">
<div
class="flex h-full w-full flex-col overflow-hidden rounded-lg border bg-white text-gray-900 shadow-md dark:border-gray-800 dark:bg-gray-900 dark:text-gray-300"
bind:this={containerEl}
>
<div class="flex items-center border-b px-3 dark:border-gray-800">
<IconSearch classNames="mr-2 text-sm" />
<input
autofocus
class="flex h-10 w-full rounded-md bg-transparent py-3 text-sm placeholder-gray-400 outline-none"
placeholder="Search models ..."
on:input={e => filterModels(e.currentTarget.value)}
/>
</div>
<div class="max-h-[300px] overflow-y-auto overflow-x-hidden">
<div>
<div class="px-2 py-1.5 text-xs font-medium text-gray-500">Trending</div>
<div>
{#each featuredModels as model, idx}
{@const [nameSpace, modelName] = model.id.split("/")}
<button
class="flex w-full cursor-pointer items-center px-2 py-1.5 text-sm {highlightIdx === idx
? 'highlighted bg-gray-100 dark:bg-gray-800'
: ''}"
on:mouseenter={() => highlightRow(idx)}
on:click={() => {
dispatch("modelSelected", model.id);
dispatch("close");
}}
>
<IconStar classNames="lucide lucide-star mr-2 h-4 w-4 text-yellow-400" />
<span class="inline-flex items-center"
><span class="text-gray-500 dark:text-gray-400">{nameSpace}</span><span
class="mx-1 text-gray-300 dark:text-gray-700">/</span
><span class="text-black dark:text-white">{modelName}</span></span
>
</button>
{/each}
</div>
</div>
<div>
<div class="px-2 py-1.5 text-xs font-medium text-gray-500">Other Models</div>
<div>
{#each otherModels as model, _idx}
{@const [nameSpace, modelName] = model.id.split("/")}
{@const idx = featuredModels.length + _idx}
<button
class="flex w-full cursor-pointer items-center px-2 py-1.5 text-sm {highlightIdx === idx
? 'highlighted bg-gray-100 dark:bg-gray-800'
: ''}"
on:mouseenter={() => highlightRow(idx)}
on:click={() => {
dispatch("modelSelected", model.id);
dispatch("close");
}}
>
<span class="inline-flex items-center"
><span class="text-gray-500 dark:text-gray-400">{nameSpace}</span><span
class="mx-1 text-gray-300 dark:text-gray-700">/</span
><span class="text-black dark:text-white">{modelName}</span></span
>
</button>
{/each}
</div>
</div>
</div>
</div>
</div>
</div>
|