refac
This commit is contained in:
1 parent
d3676b4f71
commit
b58b0ea7ca
2 files changed
+138
-19
No files matched your search
@@ -1,25 +1,81 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import TagList from './Tags/TagList.svelte';
|
import TagList from './Tags/TagList.svelte';
|
||||||
import { getContext, createEventDispatcher } from 'svelte';
|
import { getContext, createEventDispatcher, tick } from 'svelte';
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
export let tags = [];
|
type Tag = { name: string };
|
||||||
export let suggestionTags = [];
|
|
||||||
|
export let tags: Tag[] = [];
|
||||||
|
export let suggestionTags: (Tag | string | null | undefined)[] = [];
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
|
|
||||||
let inputValue = '';
|
let inputValue = '';
|
||||||
|
let inputElement: HTMLInputElement | null = null;
|
||||||
|
let popupElement: HTMLDivElement | null = null;
|
||||||
|
let suggestionsOpen = false;
|
||||||
|
|
||||||
const addTag = () => {
|
$: tagNames = new Set((tags ?? []).map((tag) => tag.name.toLowerCase()));
|
||||||
const value = inputValue.trim();
|
$: filteredSuggestionTags = (suggestionTags ?? [])
|
||||||
|
.map((tag) => (typeof tag === 'string' ? tag : (tag?.name ?? '')).trim())
|
||||||
|
.filter(
|
||||||
|
(name) =>
|
||||||
|
name &&
|
||||||
|
!tagNames.has(name.toLowerCase()) &&
|
||||||
|
name.toLowerCase().includes(inputValue.trim().toLowerCase())
|
||||||
|
)
|
||||||
|
.slice(0, 8);
|
||||||
|
$: if (suggestionsOpen && filteredSuggestionTags.length > 0) {
|
||||||
|
tick().then(positionPopup);
|
||||||
|
}
|
||||||
|
|
||||||
|
const portal = (node: HTMLElement) => {
|
||||||
|
document.body.appendChild(node);
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
node.remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const positionPopup = () => {
|
||||||
|
if (!inputElement || !popupElement) return;
|
||||||
|
const rect = inputElement.getBoundingClientRect();
|
||||||
|
popupElement.style.top = `${rect.bottom + 4}px`;
|
||||||
|
popupElement.style.left = `${Math.max(8, Math.min(rect.left, window.innerWidth - 200))}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const addTag = (tagName = inputValue) => {
|
||||||
|
const value = tagName.trim();
|
||||||
if (value !== '') {
|
if (value !== '') {
|
||||||
dispatch('add', value);
|
if (!tagNames.has(value.toLowerCase())) {
|
||||||
|
dispatch('add', value);
|
||||||
|
}
|
||||||
inputValue = '';
|
inputValue = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suggestionsOpen = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePointerDown = (event: PointerEvent) => {
|
||||||
|
if (!suggestionsOpen) return;
|
||||||
|
|
||||||
|
const target = event.target as Node;
|
||||||
|
if (inputElement?.contains(target) || popupElement?.contains(target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestionsOpen = false;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:window
|
||||||
|
on:pointerdown={handlePointerDown}
|
||||||
|
on:scroll|capture={positionPopup}
|
||||||
|
on:resize={positionPopup}
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-1 w-full">
|
<div class="flex flex-wrap items-center gap-1 w-full">
|
||||||
<TagList
|
<TagList
|
||||||
{tags}
|
{tags}
|
||||||
@@ -30,18 +86,68 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{#if !disabled}
|
{#if !disabled}
|
||||||
<input
|
<div class="flex-1 min-w-24">
|
||||||
bind:value={inputValue}
|
<input
|
||||||
class="flex-1 min-w-24 {tags.length > 0
|
bind:this={inputElement}
|
||||||
? 'px-0.5'
|
bind:value={inputValue}
|
||||||
: ''} text-xs bg-transparent outline-hidden placeholder:text-gray-400 dark:placeholder:text-gray-500"
|
class="w-full {tags.length > 0
|
||||||
placeholder={$i18n.t('Add a tag...')}
|
? 'px-0.5'
|
||||||
on:keydown={(event) => {
|
: ''} text-xs bg-transparent outline-hidden placeholder:text-gray-400 dark:placeholder:text-gray-500"
|
||||||
if (event.key === 'Enter' || event.key === ' ') {
|
placeholder={$i18n.t('Add a tag...')}
|
||||||
event.preventDefault();
|
role="combobox"
|
||||||
addTag();
|
aria-autocomplete="list"
|
||||||
}
|
aria-expanded={suggestionsOpen && filteredSuggestionTags.length > 0}
|
||||||
}}
|
autocomplete="off"
|
||||||
/>
|
on:focus={() => {
|
||||||
|
suggestionsOpen = true;
|
||||||
|
positionPopup();
|
||||||
|
}}
|
||||||
|
on:input={() => {
|
||||||
|
suggestionsOpen = true;
|
||||||
|
positionPopup();
|
||||||
|
}}
|
||||||
|
on:keydown={(event) => {
|
||||||
|
if (event.key === 'Enter' || event.key === ' ') {
|
||||||
|
event.preventDefault();
|
||||||
|
addTag();
|
||||||
|
} else if (event.key === 'Escape') {
|
||||||
|
suggestionsOpen = false;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
on:blur={() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!popupElement?.contains(document.activeElement)) {
|
||||||
|
suggestionsOpen = false;
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{#if suggestionsOpen && filteredSuggestionTags.length > 0}
|
||||||
|
<div
|
||||||
|
use:portal
|
||||||
|
bind:this={popupElement}
|
||||||
|
class="fixed w-48 max-h-48 overflow-y-auto rounded-lg border border-gray-200 bg-white p-0.5 shadow-lg dark:border-gray-800 dark:bg-gray-850"
|
||||||
|
role="listbox"
|
||||||
|
style="z-index: 9999; top: 0; left: 0;"
|
||||||
|
>
|
||||||
|
{#each filteredSuggestionTags as tag (tag)}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex w-full items-center rounded-md px-2 py-1 text-left text-xs text-gray-700 transition-colors hover:bg-gray-50 dark:text-gray-200 dark:hover:bg-gray-800"
|
||||||
|
role="option"
|
||||||
|
on:mousedown={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
}}
|
||||||
|
on:click={() => {
|
||||||
|
addTag(tag);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span class="truncate">{tag}</span>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
import { getSkills } from '$lib/apis/skills';
|
import { getSkills } from '$lib/apis/skills';
|
||||||
import { getFunctions } from '$lib/apis/functions';
|
import { getFunctions } from '$lib/apis/functions';
|
||||||
import { getModelsDefaults } from '$lib/apis/configs';
|
import { getModelsDefaults } from '$lib/apis/configs';
|
||||||
|
import { getBaseModelTags, getModelTags } from '$lib/apis/models';
|
||||||
|
|
||||||
import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
|
import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
|
||||||
import Tags from '$lib/components/common/Tags.svelte';
|
import Tags from '$lib/components/common/Tags.svelte';
|
||||||
@@ -106,6 +107,14 @@
|
|||||||
let accessGrants = [];
|
let accessGrants = [];
|
||||||
let terminalId = '';
|
let terminalId = '';
|
||||||
let tts = { voice: '' };
|
let tts = { voice: '' };
|
||||||
|
export let suggestionTags: { name: string }[] = [];
|
||||||
|
|
||||||
|
const loadSuggestionTags = async () => {
|
||||||
|
const res: string[] = await (preset ? getModelTags : getBaseModelTags)(
|
||||||
|
localStorage.token
|
||||||
|
).catch(() => []);
|
||||||
|
suggestionTags = res.map((tag) => ({ name: tag }));
|
||||||
|
};
|
||||||
|
|
||||||
const submitHandler = async () => {
|
const submitHandler = async () => {
|
||||||
loading = true;
|
loading = true;
|
||||||
@@ -255,6 +264,9 @@
|
|||||||
if (!$functions) {
|
if (!$functions) {
|
||||||
await functions.set(await getFunctions(localStorage.token));
|
await functions.set(await getFunctions(localStorage.token));
|
||||||
}
|
}
|
||||||
|
if (suggestionTags.length === 0) {
|
||||||
|
await loadSuggestionTags();
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch admin-configured default model metadata so the editor
|
// Fetch admin-configured default model metadata so the editor
|
||||||
// reflects the actual defaults rather than hardcoded values
|
// reflects the actual defaults rather than hardcoded values
|
||||||
@@ -651,6 +663,7 @@
|
|||||||
<div class="">
|
<div class="">
|
||||||
<Tags
|
<Tags
|
||||||
tags={info?.meta?.tags ?? []}
|
tags={info?.meta?.tags ?? []}
|
||||||
|
{suggestionTags}
|
||||||
on:delete={(e) => {
|
on:delete={(e) => {
|
||||||
const tagName = e.detail;
|
const tagName = e.detail;
|
||||||
info.meta.tags = info.meta.tags.filter((tag) => tag.name !== tagName);
|
info.meta.tags = info.meta.tags.filter((tag) => tag.name !== tagName);
|
||||||
|
|||||||
Reference in new issue
Block a user