mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
fix(web): show full model names in selectors when truncated
Selector dropdowns previously reserved 50% of the row for the right-hand metadata, squeezing long model names beyond visibility, and triggers truncated their labels without a tooltip. Restructure the model option into a two-row layout (name + capabilities/context badge above, model_id below), and add native title tooltips on every truncated label across the shared SearchableSelectPopover and the model/TTS/search/memory/ browser-context selectors so the full name is always reachable.
This commit is contained in:
@@ -15,7 +15,10 @@
|
||||
:aria-label="ariaLabel || placeholder"
|
||||
class="w-full justify-between font-normal"
|
||||
>
|
||||
<span class="truncate">
|
||||
<span
|
||||
class="truncate"
|
||||
:title="displayLabel || placeholder"
|
||||
>
|
||||
{{ displayLabel || placeholder }}
|
||||
</span>
|
||||
<Search
|
||||
@@ -80,33 +83,39 @@
|
||||
>
|
||||
<Check
|
||||
v-if="selected === option.value"
|
||||
class="size-3.5"
|
||||
class="size-3.5 shrink-0"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="size-3.5"
|
||||
class="size-3.5 shrink-0"
|
||||
/>
|
||||
<slot
|
||||
name="option-icon"
|
||||
:option="option"
|
||||
/>
|
||||
<slot
|
||||
name="option-label"
|
||||
:option="option"
|
||||
>
|
||||
<span class="truncate">{{ option.label }}</span>
|
||||
</slot>
|
||||
<slot
|
||||
name="option-suffix"
|
||||
:option="option"
|
||||
>
|
||||
<span
|
||||
v-if="option.description"
|
||||
class="ml-auto text-xs text-muted-foreground"
|
||||
<span class="flex min-w-0 flex-1 items-center gap-2">
|
||||
<slot
|
||||
name="option-label"
|
||||
:option="option"
|
||||
>
|
||||
{{ option.description }}
|
||||
</span>
|
||||
</slot>
|
||||
<span
|
||||
class="truncate flex-1 text-left"
|
||||
:title="option.label"
|
||||
>{{ option.label }}</span>
|
||||
</slot>
|
||||
<slot
|
||||
name="option-suffix"
|
||||
:option="option"
|
||||
>
|
||||
<span
|
||||
v-if="option.description"
|
||||
class="ml-auto text-xs text-muted-foreground truncate max-w-[50%] text-right"
|
||||
:title="option.description"
|
||||
>
|
||||
{{ option.description }}
|
||||
</span>
|
||||
</slot>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
:aria-label="placeholder || 'Select browser context'"
|
||||
class="w-full justify-between font-normal"
|
||||
>
|
||||
<span class="flex items-center gap-2 truncate">
|
||||
<span class="flex min-w-0 items-center gap-2 truncate">
|
||||
<AppWindow
|
||||
v-if="selected"
|
||||
class="size-3.5 text-muted-foreground"
|
||||
class="size-3.5 shrink-0 text-muted-foreground"
|
||||
/>
|
||||
<span class="truncate">{{ displayLabel || placeholder }}</span>
|
||||
<span
|
||||
class="truncate"
|
||||
:title="displayLabel || placeholder"
|
||||
>{{ displayLabel || placeholder }}</span>
|
||||
</span>
|
||||
<Search
|
||||
class="ml-2 size-3.5 shrink-0 text-muted-foreground"
|
||||
@@ -33,14 +36,15 @@
|
||||
<template #option-icon="{ option }">
|
||||
<AppWindow
|
||||
v-if="option.value"
|
||||
class="size-3.5 text-muted-foreground"
|
||||
class="size-3.5 shrink-0 text-muted-foreground"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #option-label="{ option }">
|
||||
<span
|
||||
class="truncate"
|
||||
class="truncate flex-1 text-left"
|
||||
:class="{ 'text-muted-foreground': !option.value }"
|
||||
:title="option.label"
|
||||
>
|
||||
{{ option.label }}
|
||||
</span>
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
:aria-label="placeholder || 'Select memory provider'"
|
||||
class="w-full justify-between font-normal"
|
||||
>
|
||||
<span class="flex items-center gap-2 truncate">
|
||||
<span class="flex min-w-0 items-center gap-2 truncate">
|
||||
<Brain
|
||||
v-if="selected"
|
||||
class="size-3.5 text-primary"
|
||||
class="size-3.5 shrink-0 text-primary"
|
||||
/>
|
||||
<span class="truncate">{{ displayLabel || placeholder }}</span>
|
||||
<span
|
||||
class="truncate"
|
||||
:title="displayLabel || placeholder"
|
||||
>{{ displayLabel || placeholder }}</span>
|
||||
</span>
|
||||
<Search
|
||||
class="ml-2 size-3.5 shrink-0 text-muted-foreground"
|
||||
@@ -33,14 +36,15 @@
|
||||
<template #option-icon="{ option }">
|
||||
<Brain
|
||||
v-if="option.value"
|
||||
class="size-3.5 text-primary"
|
||||
class="size-3.5 shrink-0 text-primary"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #option-label="{ option }">
|
||||
<span
|
||||
class="truncate"
|
||||
class="truncate flex-1 text-left"
|
||||
:class="{ 'text-muted-foreground': !option.value }"
|
||||
:title="option.label"
|
||||
>
|
||||
{{ option.label }}
|
||||
</span>
|
||||
|
||||
@@ -35,34 +35,41 @@
|
||||
</div>
|
||||
|
||||
<button
|
||||
|
||||
v-for="option in group.items"
|
||||
:key="option.value"
|
||||
type="button"
|
||||
role="option"
|
||||
:aria-selected="modelValue === option.value"
|
||||
class="relative flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-xs outline-none hover:bg-accent hover:text-accent-foreground [&_+button]:mt-1"
|
||||
class="relative flex w-full cursor-pointer items-start gap-2 rounded-md px-2 py-1.5 text-xs outline-none hover:bg-accent hover:text-accent-foreground [&_+button]:mt-1"
|
||||
:class="{ 'bg-accent': modelValue === option.value }"
|
||||
@click="$emit('update:modelValue', option.value)"
|
||||
>
|
||||
<Check
|
||||
v-if="modelValue === option.value"
|
||||
class="size-3.5 shrink-0"
|
||||
class="size-3.5 shrink-0 mt-0.5"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="size-3.5 shrink-0"
|
||||
/>
|
||||
<span class="truncate ">{{ option.label }}</span>
|
||||
<span class="ml-auto min-w-[50%] flex items-center gap-1.5 text-right">
|
||||
<ModelCapabilities
|
||||
v-if="option.compatibilities?.length"
|
||||
:compatibilities="option.compatibilities"
|
||||
/>
|
||||
<ContextWindowBadge :context-window="option.contextWindow" />
|
||||
<span class="flex min-w-0 flex-1 flex-col gap-0.5">
|
||||
<span class="flex min-w-0 items-center gap-2">
|
||||
<span
|
||||
class="truncate flex-1 text-left"
|
||||
:title="option.label"
|
||||
>{{ option.label }}</span>
|
||||
<span class="flex items-center gap-1.5 shrink-0">
|
||||
<ModelCapabilities
|
||||
v-if="option.compatibilities?.length"
|
||||
:compatibilities="option.compatibilities"
|
||||
/>
|
||||
<ContextWindowBadge :context-window="option.contextWindow" />
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
v-if="option.description"
|
||||
class="text-xs text-muted-foreground truncate "
|
||||
v-if="option.description && option.description !== option.label"
|
||||
class="text-xs text-muted-foreground truncate text-left"
|
||||
:title="option.description"
|
||||
>
|
||||
{{ option.description }}
|
||||
</span>
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
:aria-label="placeholder || 'Select model'"
|
||||
class="w-full justify-between font-normal"
|
||||
>
|
||||
<span class="truncate">
|
||||
<span
|
||||
class="truncate"
|
||||
:title="displayLabel || placeholder"
|
||||
>
|
||||
{{ displayLabel || placeholder }}
|
||||
</span>
|
||||
<Search
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
:aria-label="placeholder || 'Select search provider'"
|
||||
class="w-full justify-between font-normal"
|
||||
>
|
||||
<span class="flex items-center gap-2 truncate">
|
||||
<span class="flex min-w-0 items-center gap-2 truncate">
|
||||
<SearchProviderLogo
|
||||
v-if="selectedProvider"
|
||||
:provider="selectedProvider.provider || ''"
|
||||
size="xs"
|
||||
/>
|
||||
<span class="truncate">{{ displayLabel || placeholder }}</span>
|
||||
<span
|
||||
class="truncate"
|
||||
:title="displayLabel || placeholder"
|
||||
>{{ displayLabel || placeholder }}</span>
|
||||
</span>
|
||||
<Search
|
||||
class="ml-2 size-3.5 shrink-0 text-muted-foreground"
|
||||
@@ -41,8 +44,9 @@
|
||||
|
||||
<template #option-label="{ option }">
|
||||
<span
|
||||
class="truncate"
|
||||
class="truncate flex-1 text-left"
|
||||
:class="{ 'text-muted-foreground': !option.value }"
|
||||
:title="option.label"
|
||||
>
|
||||
{{ option.label }}
|
||||
</span>
|
||||
|
||||
@@ -16,12 +16,15 @@
|
||||
:aria-label="placeholder || 'Select TTS model'"
|
||||
class="w-full justify-between font-normal"
|
||||
>
|
||||
<span class="flex items-center gap-2 truncate">
|
||||
<span class="flex min-w-0 items-center gap-2 truncate">
|
||||
<Volume2
|
||||
v-if="selected"
|
||||
class="size-3.5 text-muted-foreground"
|
||||
class="size-3.5 shrink-0 text-muted-foreground"
|
||||
/>
|
||||
<span class="truncate">{{ displayLabel || placeholder }}</span>
|
||||
<span
|
||||
class="truncate"
|
||||
:title="displayLabel || placeholder"
|
||||
>{{ displayLabel || placeholder }}</span>
|
||||
</span>
|
||||
<Search
|
||||
class="ml-2 size-3.5 shrink-0 text-muted-foreground"
|
||||
@@ -32,14 +35,15 @@
|
||||
<template #option-icon="{ option }">
|
||||
<Volume2
|
||||
v-if="option.value"
|
||||
class="size-3.5 text-muted-foreground"
|
||||
class="size-3.5 shrink-0 text-muted-foreground"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #option-label="{ option }">
|
||||
<span
|
||||
class="truncate"
|
||||
class="truncate flex-1 text-left"
|
||||
:class="{ 'text-muted-foreground': !option.value }"
|
||||
:title="option.label"
|
||||
>
|
||||
{{ option.label }}
|
||||
</span>
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
variant="ghost"
|
||||
:disabled="!currentBotId || activeChatReadOnly"
|
||||
class="gap-0.5 text-muted-foreground max-w-40"
|
||||
:title="selectedModelLabel"
|
||||
>
|
||||
<span class="truncate text-[11px]">{{ selectedModelLabel }}</span>
|
||||
<ChevronDown class="size-3 shrink-0 opacity-50" />
|
||||
|
||||
Reference in New Issue
Block a user