mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-07 22:20:03 +00:00
feat: New Template Library (#7062)
## Summary Implement the new design for template library ## Changes - What - New sort option: `Popular` and `Recommended` - New category: `Popular`, leverage the `Popular` sorting - Support add category stick to top of the side bar - Support template customized visible in different platform by `includeOnDistributions` field ### How to make `Popular` and `Recommended` work Add usage-based ordering to workflow templates with position bias correction, manual ranking (searchRank), and freshness boost. New sort modes: - "Recommended" (default): usage × 0.5 + searchRank × 0.3 + freshness × 0.2 - "Popular": usage × 0.9 + freshness × 0.1 ## Screenshots (if applicable) New default ordering: <img width="1812" height="1852" alt="Selection_2485" src="https://github.com/user-attachments/assets/8f4ed6e9-9cf4-43a8-8796-022dcf4c277e" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7062-feat-usage-based-template-ordering-2bb6d73d365081f1ac65f8ad55fe8ce6) by [Unito](https://www.unito.io) Popular category: <img width="281" height="283" alt="image" src="https://github.com/user-attachments/assets/fd54fcb8-6caa-4982-a6b6-1f70ca4b31e3" /> --------- Co-authored-by: Yourz <crazilou@vip.qq.com> Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
@@ -6,7 +6,7 @@ import { i18n, st } from '@/i18n'
|
||||
import { isCloud } from '@/platform/distribution/types'
|
||||
import { api } from '@/scripts/api'
|
||||
import type { NavGroupData, NavItemData } from '@/types/navTypes'
|
||||
import { getCategoryIcon } from '@/utils/categoryIcons'
|
||||
import { generateCategoryId, getCategoryIcon } from '@/utils/categoryUtil'
|
||||
import { normalizeI18nKey } from '@/utils/formatUtil'
|
||||
|
||||
import type {
|
||||
@@ -276,9 +276,18 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
return enhancedTemplates.value
|
||||
}
|
||||
|
||||
if (categoryId === 'basics') {
|
||||
if (categoryId.startsWith('basics-')) {
|
||||
// Filter for templates from categories marked as essential
|
||||
return enhancedTemplates.value.filter((t) => t.isEssential)
|
||||
return enhancedTemplates.value.filter(
|
||||
(t) =>
|
||||
t.isEssential &&
|
||||
t.category?.toLowerCase().replace(/\s+/g, '-') ===
|
||||
categoryId.replace('basics-', '')
|
||||
)
|
||||
}
|
||||
|
||||
if (categoryId === 'popular') {
|
||||
return enhancedTemplates.value
|
||||
}
|
||||
|
||||
if (categoryId === 'partner-nodes') {
|
||||
@@ -333,20 +342,34 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
icon: getCategoryIcon('all')
|
||||
})
|
||||
|
||||
// 2. Basics (isEssential categories) - always second if it exists
|
||||
const essentialCat = coreTemplates.value.find(
|
||||
// 1.5. Popular categories
|
||||
|
||||
items.push({
|
||||
id: 'popular',
|
||||
label: st('templateWorkflows.category.Popular', 'Popular'),
|
||||
icon: 'icon-[lucide--flame]'
|
||||
})
|
||||
|
||||
// 2. Basics (isEssential categories) - always beneath All Templates if they exist
|
||||
const essentialCats = coreTemplates.value.filter(
|
||||
(cat) => cat.isEssential && cat.templates.length > 0
|
||||
)
|
||||
|
||||
if (essentialCat) {
|
||||
const categoryTitle = essentialCat.title ?? 'Getting Started'
|
||||
items.push({
|
||||
id: 'basics',
|
||||
label: st(
|
||||
`templateWorkflows.category.${normalizeI18nKey(categoryTitle)}`,
|
||||
categoryTitle
|
||||
),
|
||||
icon: 'icon-[lucide--graduation-cap]'
|
||||
if (essentialCats.length > 0) {
|
||||
essentialCats.forEach((essentialCat) => {
|
||||
const categoryIcon = essentialCat.icon
|
||||
const categoryTitle = essentialCat.title ?? 'Getting Started'
|
||||
const categoryId = generateCategoryId('basics', essentialCat.title)
|
||||
items.push({
|
||||
id: categoryId,
|
||||
label: st(
|
||||
`templateWorkflows.category.${normalizeI18nKey(categoryTitle)}`,
|
||||
categoryTitle
|
||||
),
|
||||
icon:
|
||||
categoryIcon ||
|
||||
getCategoryIcon(essentialCat.type || 'getting-started')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -375,7 +398,7 @@ export const useWorkflowTemplatesStore = defineStore(
|
||||
const group = categoryGroups.get(categoryGroup)!
|
||||
|
||||
// Generate unique ID for this category
|
||||
const categoryId = `${categoryGroup.toLowerCase().replace(/\s+/g, '-')}-${category.title.toLowerCase().replace(/\s+/g, '-')}`
|
||||
const categoryId = generateCategoryId(categoryGroup, category.title)
|
||||
|
||||
// Store the filter mapping
|
||||
categoryFilters.value.set(categoryId, {
|
||||
|
||||
@@ -32,6 +32,29 @@ export interface TemplateInfo {
|
||||
* Templates with this field will be hidden on local installations temporarily.
|
||||
*/
|
||||
requiresCustomNodes?: string[]
|
||||
/**
|
||||
* Manual ranking boost/demotion for "Recommended" sort. Scale 1-10, default 5.
|
||||
* Higher values promote the template, lower values demote it.
|
||||
*/
|
||||
searchRank?: number
|
||||
/**
|
||||
* Usage score based on real world usage statistics.
|
||||
* Used for popular templates sort and for "Recommended" sort boost.
|
||||
*/
|
||||
usage?: number
|
||||
/**
|
||||
* Manage template's visibility across different distributions by specifying which distributions it should be included on.
|
||||
* If not specified, the template will be included on all distributions.
|
||||
*/
|
||||
includeOnDistributions?: TemplateIncludeOnDistributionEnum[]
|
||||
}
|
||||
|
||||
export enum TemplateIncludeOnDistributionEnum {
|
||||
Cloud = 'cloud',
|
||||
Local = 'local',
|
||||
Desktop = 'desktop',
|
||||
Mac = 'mac',
|
||||
Windows = 'windows'
|
||||
}
|
||||
|
||||
export interface WorkflowTemplates {
|
||||
|
||||
Reference in New Issue
Block a user