refactor: Icons
This commit is contained in:
parent
5207527e9d
commit
22507fed74
|
|
@ -1,9 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Paperclip, Image, FileText, File, Volume2 } from '@lucide/svelte';
|
import { Paperclip } from '@lucide/svelte';
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||||
import * as Tooltip from '$lib/components/ui/tooltip';
|
import * as Tooltip from '$lib/components/ui/tooltip';
|
||||||
import { TOOLTIP_DELAY_DURATION } from '$lib/constants/tooltip-config';
|
import { TOOLTIP_DELAY_DURATION } from '$lib/constants/tooltip-config';
|
||||||
|
import { FILE_TYPE_ICONS } from '$lib/constants/modality-icons';
|
||||||
import { FileTypeCategory } from '$lib/enums';
|
import { FileTypeCategory } from '$lib/enums';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -63,7 +64,7 @@
|
||||||
disabled={!hasVisionModality}
|
disabled={!hasVisionModality}
|
||||||
onclick={() => handleFileUpload(FileTypeCategory.IMAGE)}
|
onclick={() => handleFileUpload(FileTypeCategory.IMAGE)}
|
||||||
>
|
>
|
||||||
<Image class="h-4 w-4" />
|
<FILE_TYPE_ICONS.image class="h-4 w-4" />
|
||||||
|
|
||||||
<span>Images</span>
|
<span>Images</span>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
|
|
@ -83,7 +84,7 @@
|
||||||
disabled={!hasAudioModality}
|
disabled={!hasAudioModality}
|
||||||
onclick={() => handleFileUpload(FileTypeCategory.AUDIO)}
|
onclick={() => handleFileUpload(FileTypeCategory.AUDIO)}
|
||||||
>
|
>
|
||||||
<Volume2 class="h-4 w-4" />
|
<FILE_TYPE_ICONS.audio class="h-4 w-4" />
|
||||||
|
|
||||||
<span>Audio Files</span>
|
<span>Audio Files</span>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
|
|
@ -100,7 +101,7 @@
|
||||||
class="flex cursor-pointer items-center gap-2"
|
class="flex cursor-pointer items-center gap-2"
|
||||||
onclick={() => handleFileUpload(FileTypeCategory.TEXT)}
|
onclick={() => handleFileUpload(FileTypeCategory.TEXT)}
|
||||||
>
|
>
|
||||||
<FileText class="h-4 w-4" />
|
<FILE_TYPE_ICONS.text class="h-4 w-4" />
|
||||||
|
|
||||||
<span>Text Files</span>
|
<span>Text Files</span>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
|
|
@ -111,7 +112,7 @@
|
||||||
class="flex cursor-pointer items-center gap-2"
|
class="flex cursor-pointer items-center gap-2"
|
||||||
onclick={() => handleFileUpload(FileTypeCategory.PDF)}
|
onclick={() => handleFileUpload(FileTypeCategory.PDF)}
|
||||||
>
|
>
|
||||||
<File class="h-4 w-4" />
|
<FILE_TYPE_ICONS.pdf class="h-4 w-4" />
|
||||||
|
|
||||||
<span>PDF Files</span>
|
<span>PDF Files</span>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@
|
||||||
modelsLoading,
|
modelsLoading,
|
||||||
modelsUpdating,
|
modelsUpdating,
|
||||||
selectModel,
|
selectModel,
|
||||||
selectedModelId
|
selectedModelId,
|
||||||
|
modelsStore
|
||||||
} from '$lib/stores/models.svelte';
|
} from '$lib/stores/models.svelte';
|
||||||
import { isRouterMode, propsStore } from '$lib/stores/props.svelte';
|
import { isRouterMode, propsStore } from '$lib/stores/props.svelte';
|
||||||
import { DialogModelInformation } from '$lib/components/app';
|
import { DialogModelInformation } from '$lib/components/app';
|
||||||
|
import { MODALITY_ICONS } from '$lib/constants/modality-icons';
|
||||||
import type { ModelOption } from '$lib/types/models';
|
import type { ModelOption } from '$lib/types/models';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -379,19 +381,49 @@
|
||||||
<div class="my-1 h-px bg-border"></div>
|
<div class="my-1 h-px bg-border"></div>
|
||||||
{/if}
|
{/if}
|
||||||
{#each options as option (option.id)}
|
{#each options as option (option.id)}
|
||||||
|
{@const isLoaded = modelsStore.isModelLoaded(option.model)}
|
||||||
|
{@const hasVision = option.capabilities.includes('vision')}
|
||||||
|
{@const hasAudio = option.capabilities.includes('audio')}
|
||||||
|
{@const isSelected = currentModel === option.model || activeId === option.id}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class={cn(
|
class={cn(
|
||||||
'flex w-full cursor-pointer items-center px-3 py-2 text-left text-sm transition hover:bg-muted focus:bg-muted focus:outline-none',
|
'flex w-full cursor-pointer items-center gap-2 px-3 py-2 text-left text-sm transition hover:bg-muted focus:bg-muted focus:outline-none',
|
||||||
currentModel === option.model || activeId === option.id
|
isSelected
|
||||||
? 'bg-accent text-accent-foreground'
|
? 'bg-accent text-accent-foreground'
|
||||||
: 'text-popover-foreground hover:bg-accent hover:text-accent-foreground'
|
: 'hover:bg-accent hover:text-accent-foreground',
|
||||||
|
isLoaded ? 'text-popover-foreground' : 'text-muted-foreground'
|
||||||
)}
|
)}
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected={currentModel === option.model || activeId === option.id}
|
aria-selected={isSelected}
|
||||||
onclick={() => handleSelect(option.id)}
|
onclick={() => handleSelect(option.id)}
|
||||||
>
|
>
|
||||||
<span class="truncate">{option.model}</span>
|
<!-- Status dot -->
|
||||||
|
<span
|
||||||
|
class={cn(
|
||||||
|
'h-2 w-2 shrink-0 rounded-full',
|
||||||
|
isLoaded ? 'bg-green-500' : 'bg-muted-foreground/50'
|
||||||
|
)}
|
||||||
|
></span>
|
||||||
|
|
||||||
|
<!-- Model name -->
|
||||||
|
<span class="min-w-0 flex-1 truncate">{option.model}</span>
|
||||||
|
|
||||||
|
<!-- Modality icons -->
|
||||||
|
<div class="flex shrink-0 items-center gap-1">
|
||||||
|
<MODALITY_ICONS.vision
|
||||||
|
class={cn(
|
||||||
|
'h-3.5 w-3.5',
|
||||||
|
hasVision ? 'text-foreground' : 'text-muted-foreground/40'
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<MODALITY_ICONS.audio
|
||||||
|
class={cn(
|
||||||
|
'h-3.5 w-3.5',
|
||||||
|
hasAudio ? 'text-foreground' : 'text-muted-foreground/40'
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* Icon mappings for file types and model modalities
|
||||||
|
* Centralized configuration to ensure consistent icon usage across the app
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
File as FileIcon,
|
||||||
|
FileText as FileTextIcon,
|
||||||
|
Image as ImageIcon,
|
||||||
|
Volume2 as AudioIcon
|
||||||
|
} from '@lucide/svelte';
|
||||||
|
import { FileTypeCategory } from '$lib/enums';
|
||||||
|
|
||||||
|
export const FILE_TYPE_ICONS = {
|
||||||
|
[FileTypeCategory.IMAGE]: ImageIcon,
|
||||||
|
[FileTypeCategory.AUDIO]: AudioIcon,
|
||||||
|
[FileTypeCategory.TEXT]: FileTextIcon,
|
||||||
|
[FileTypeCategory.PDF]: FileIcon
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const DEFAULT_FILE_ICON = FileIcon;
|
||||||
|
|
||||||
|
export type ModelModality = 'vision' | 'audio';
|
||||||
|
|
||||||
|
export const MODALITY_ICONS = {
|
||||||
|
vision: ImageIcon,
|
||||||
|
audio: AudioIcon
|
||||||
|
} as const;
|
||||||
Loading…
Reference in New Issue