mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 15:10:06 +00:00
feat: enhance navigation and template filtering with icon support and new category mappings
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
</template>
|
||||
<template #header-title>
|
||||
<span class="text-neutral text-base">{{
|
||||
$t('templateWorkflows.categories', 'Categories')
|
||||
$t('sideToolbar.templates', 'Templates')
|
||||
}}</span>
|
||||
</template>
|
||||
</LeftSidePanel>
|
||||
@@ -146,11 +146,6 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #rightPanel>
|
||||
<RightSidePanel>
|
||||
<!-- Template details could go here -->
|
||||
</RightSidePanel>
|
||||
</template>
|
||||
</BaseWidgetLayout>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
role="button"
|
||||
@click="onClick"
|
||||
>
|
||||
<i-lucide:folder v-if="hasFolderIcon" class="text-xs text-neutral" />
|
||||
<component :is="iconComponent" class="text-xs text-neutral" />
|
||||
<span class="flex items-center">
|
||||
<slot></slot>
|
||||
</span>
|
||||
@@ -17,13 +17,70 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const {
|
||||
hasFolderIcon = true,
|
||||
active,
|
||||
onClick
|
||||
} = defineProps<{
|
||||
hasFolderIcon?: boolean
|
||||
import { computed } from 'vue'
|
||||
// Import only the icons used in getCategoryIcon
|
||||
import ILucideList from '~icons/lucide/list'
|
||||
import ILucideGraduationCap from '~icons/lucide/graduation-cap'
|
||||
import ILucideImage from '~icons/lucide/image'
|
||||
import ILucideFilm from '~icons/lucide/film'
|
||||
import ILucideBox from '~icons/lucide/box'
|
||||
import ILucideVolume2 from '~icons/lucide/volume-2'
|
||||
import ILucideHandCoins from '~icons/lucide/hand-coins'
|
||||
import ILucideMessageSquareText from '~icons/lucide/message-square-text'
|
||||
import ILucideZap from '~icons/lucide/zap'
|
||||
import ILucideCommand from '~icons/lucide/command'
|
||||
import ILucideDumbbell from '~icons/lucide/dumbbell'
|
||||
import ILucidePuzzle from '~icons/lucide/puzzle'
|
||||
import ILucideWrench from '~icons/lucide/wrench'
|
||||
import ILucideMaximize2 from '~icons/lucide/maximize-2'
|
||||
import ILucideSlidersHorizontal from '~icons/lucide/sliders-horizontal'
|
||||
import ILucideLayoutGrid from '~icons/lucide/layout-grid'
|
||||
import ILucideFolder from '~icons/lucide/folder'
|
||||
|
||||
const { icon, active, onClick } = defineProps<{
|
||||
icon?: string
|
||||
active?: boolean
|
||||
onClick: () => void
|
||||
}>()
|
||||
|
||||
// Icon map matching getCategoryIcon function exactly
|
||||
const iconMap = {
|
||||
// Main categories
|
||||
'list': ILucideList,
|
||||
'graduation-cap': ILucideGraduationCap,
|
||||
|
||||
// Generation types
|
||||
'image': ILucideImage,
|
||||
'film': ILucideFilm,
|
||||
'box': ILucideBox,
|
||||
'volume-2': ILucideVolume2,
|
||||
|
||||
// API and models
|
||||
'hand-coins': ILucideHandCoins,
|
||||
|
||||
// LLMs and AI
|
||||
'message-square-text': ILucideMessageSquareText,
|
||||
|
||||
// Performance and hardware
|
||||
'zap': ILucideZap,
|
||||
'command': ILucideCommand,
|
||||
|
||||
// Training
|
||||
'dumbbell': ILucideDumbbell,
|
||||
|
||||
// Extensions and tools
|
||||
'puzzle': ILucidePuzzle,
|
||||
'wrench': ILucideWrench,
|
||||
|
||||
// Fallbacks for common patterns
|
||||
'maximize-2': ILucideMaximize2,
|
||||
'sliders-horizontal': ILucideSlidersHorizontal,
|
||||
'layout-grid': ILucideLayoutGrid,
|
||||
'folder': ILucideFolder
|
||||
}
|
||||
|
||||
const iconComponent = computed(() => {
|
||||
if (!icon) return ILucideFolder
|
||||
return iconMap[icon as keyof typeof iconMap] || ILucideFolder
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<NavItem
|
||||
v-for="subItem in item.items"
|
||||
:key="subItem.id"
|
||||
:icon="subItem.icon"
|
||||
:active="activeItem === subItem.id"
|
||||
@click="activeItem = subItem.id"
|
||||
>
|
||||
@@ -22,6 +23,7 @@
|
||||
</div>
|
||||
<div v-else class="flex flex-col gap-2">
|
||||
<NavItem
|
||||
:icon="item.icon"
|
||||
:active="activeItem === item.id"
|
||||
@click="activeItem = item.id"
|
||||
>
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
TemplateInfo,
|
||||
WorkflowTemplates
|
||||
} from '@/types/workflowTemplateTypes'
|
||||
import { getCategoryIcon } from '@/utils/categoryIcons'
|
||||
import { normalizeI18nKey } from '@/utils/formatUtil'
|
||||
|
||||
// Enhanced template interface for easier filtering
|
||||
@@ -302,6 +303,15 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
(t) => t.sourceModule !== 'default'
|
||||
)
|
||||
|
||||
case 'lora-training':
|
||||
return enhancedTemplates.value.filter(
|
||||
(t) =>
|
||||
t.tags?.includes('LoRA') ||
|
||||
t.tags?.includes('Training') ||
|
||||
t.name?.toLowerCase().includes('lora') ||
|
||||
t.title?.toLowerCase().includes('lora')
|
||||
)
|
||||
|
||||
case 'performance-small':
|
||||
return enhancedTemplates.value.filter((t) => t.isPerformance)
|
||||
|
||||
@@ -347,11 +357,19 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
const macCompatibleCounts = enhancedTemplates.value.filter(
|
||||
(t) => t.isMacCompatible
|
||||
).length
|
||||
const loraTrainingCounts = enhancedTemplates.value.filter(
|
||||
(t) =>
|
||||
t.tags?.includes('LoRA') ||
|
||||
t.tags?.includes('Training') ||
|
||||
t.name?.toLowerCase().includes('lora') ||
|
||||
t.title?.toLowerCase().includes('lora')
|
||||
).length
|
||||
|
||||
// All Templates - as a simple selector
|
||||
items.push({
|
||||
id: 'all',
|
||||
label: st('templateWorkflows.category.All', 'All Templates')
|
||||
label: st('templateWorkflows.category.All', 'All Templates'),
|
||||
icon: getCategoryIcon('all')
|
||||
})
|
||||
|
||||
// Getting Started - as a simple selector
|
||||
@@ -361,7 +379,8 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
label: st(
|
||||
'templateWorkflows.category.GettingStarted',
|
||||
'Getting Started'
|
||||
)
|
||||
),
|
||||
icon: getCategoryIcon('getting-started')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -377,28 +396,32 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
if (imageCounts > 0) {
|
||||
generationTypeItems.push({
|
||||
id: 'generation-image',
|
||||
label: st('templateWorkflows.category.Image', 'Image')
|
||||
label: st('templateWorkflows.category.Image', 'Image'),
|
||||
icon: getCategoryIcon('generation-image')
|
||||
})
|
||||
}
|
||||
|
||||
if (videoCounts > 0) {
|
||||
generationTypeItems.push({
|
||||
id: 'generation-video',
|
||||
label: st('templateWorkflows.category.Video', 'Video')
|
||||
label: st('templateWorkflows.category.Video', 'Video'),
|
||||
icon: getCategoryIcon('generation-video')
|
||||
})
|
||||
}
|
||||
|
||||
if (threeDCounts > 0) {
|
||||
generationTypeItems.push({
|
||||
id: 'generation-3d',
|
||||
label: st('templateWorkflows.category.3DModels', '3D Models')
|
||||
label: st('templateWorkflows.category.3DModels', '3D Models'),
|
||||
icon: getCategoryIcon('generation-3d')
|
||||
})
|
||||
}
|
||||
|
||||
if (audioCounts > 0) {
|
||||
generationTypeItems.push({
|
||||
id: 'generation-audio',
|
||||
label: st('templateWorkflows.category.Audio', 'Audio')
|
||||
label: st('templateWorkflows.category.Audio', 'Audio'),
|
||||
icon: getCategoryIcon('generation-audio')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -414,11 +437,15 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
// Closed Models (API nodes) - as a group
|
||||
if (apiCounts > 0) {
|
||||
items.push({
|
||||
title: st('templateWorkflows.category.ClosedModels', 'Closed Models'),
|
||||
title: st(
|
||||
'templateWorkflows.category.ClosedSourceModels',
|
||||
'Closed Source Models'
|
||||
),
|
||||
items: [
|
||||
{
|
||||
id: 'api-nodes',
|
||||
label: st('templateWorkflows.category.APINodes', 'API nodes')
|
||||
label: st('templateWorkflows.category.APINodes', 'API nodes'),
|
||||
icon: getCategoryIcon('api-nodes')
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -428,7 +455,28 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
if (extensionCounts > 0) {
|
||||
items.push({
|
||||
id: 'extensions',
|
||||
label: st('templateWorkflows.category.Extensions', 'Extensions')
|
||||
label: st('templateWorkflows.category.Extensions', 'Extensions'),
|
||||
icon: getCategoryIcon('extensions')
|
||||
})
|
||||
}
|
||||
|
||||
// Model Training - as a group
|
||||
if (loraTrainingCounts > 0) {
|
||||
items.push({
|
||||
title: st(
|
||||
'templateWorkflows.category.ModelTraining',
|
||||
'Model Training'
|
||||
),
|
||||
items: [
|
||||
{
|
||||
id: 'lora-training',
|
||||
label: st(
|
||||
'templateWorkflows.category.LoRATraining',
|
||||
'LoRA Training'
|
||||
),
|
||||
icon: getCategoryIcon('lora-training')
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
@@ -437,7 +485,8 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
const performanceItems: NavItemData[] = [
|
||||
{
|
||||
id: 'performance-small',
|
||||
label: st('templateWorkflows.category.SmallModels', 'Small Models')
|
||||
label: st('templateWorkflows.category.SmallModels', 'Small Models'),
|
||||
icon: getCategoryIcon('small-models')
|
||||
}
|
||||
]
|
||||
|
||||
@@ -448,7 +497,8 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
label: st(
|
||||
'templateWorkflows.category.RunsOnMac',
|
||||
'Runs on Mac (Silicon)'
|
||||
)
|
||||
),
|
||||
icon: getCategoryIcon('runs-on-mac')
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
export interface NavItemData {
|
||||
id: string
|
||||
label: string
|
||||
icon?: string
|
||||
}
|
||||
|
||||
export interface NavGroupData {
|
||||
title: string
|
||||
items: NavItemData[]
|
||||
icon?: string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user