Files
ComfyUI_frontend/src/components/searchbox/v2/NodeSearchCategorySidebar.vue
Christian Byrne ef4e4a69d5 fix: enable enforce-consistent-class-order tailwind lint rule (#9428)
## Summary

Enable `better-tailwindcss/enforce-consistent-class-order` lint rule and
auto-fix all 1027 violations across 263 files. Stacked on #9427.

## Changes

- **What**: Sort Tailwind classes into consistent order via `eslint
--fix`
- Enable `enforce-consistent-class-order` as `'error'` in eslint config
- Purely cosmetic reordering — no behavioral or visual changes

## Review Focus

Mechanical auto-fix PR — all changes are class reordering only. This is
the largest diff but lowest risk since it changes no class names, only
their order.

**Stack:** #9417#9427 → **this PR**

Fixes #9300 (partial — 3 of 3 rules)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9428-fix-enable-enforce-consistent-class-order-tailwind-lint-rule-31a6d73d3650811c9065f5178ba3e724)
by [Unito](https://www.unito.io)
2026-03-05 17:24:34 -08:00

142 lines
4.0 KiB
Vue

<template>
<div class="flex min-h-0 flex-col overflow-y-auto py-2.5">
<!-- Preset categories -->
<div class="flex flex-col px-1">
<button
v-for="preset in topCategories"
:key="preset.id"
type="button"
:data-testid="`category-${preset.id}`"
:aria-current="selectedCategory === preset.id || undefined"
:class="categoryBtnClass(preset.id)"
@click="selectCategory(preset.id)"
>
{{ preset.label }}
</button>
</div>
<!-- Source categories -->
<div class="my-2 flex flex-col border-y border-border-subtle px-1 py-2">
<button
v-for="preset in sourceCategories"
:key="preset.id"
type="button"
:data-testid="`category-${preset.id}`"
:aria-current="selectedCategory === preset.id || undefined"
:class="categoryBtnClass(preset.id)"
@click="selectCategory(preset.id)"
>
{{ preset.label }}
</button>
</div>
<!-- Category tree -->
<div class="flex flex-col px-1">
<NodeSearchCategoryTreeNode
v-for="category in categoryTree"
:key="category.key"
:node="category"
:selected-category="selectedCategory"
:selected-collapsed="selectedCollapsed"
@select="selectCategory"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import NodeSearchCategoryTreeNode, {
CATEGORY_SELECTED_CLASS,
CATEGORY_UNSELECTED_CLASS
} from '@/components/searchbox/v2/NodeSearchCategoryTreeNode.vue'
import type { CategoryNode } from '@/components/searchbox/v2/NodeSearchCategoryTreeNode.vue'
import { nodeOrganizationService } from '@/services/nodeOrganizationService'
import { useNodeDefStore } from '@/stores/nodeDefStore'
import { NodeSourceType } from '@/types/nodeSource'
import type { TreeNode } from '@/types/treeExplorerTypes'
import { cn } from '@/utils/tailwindUtil'
const selectedCategory = defineModel<string>('selectedCategory', {
required: true
})
const { t } = useI18n()
const nodeDefStore = useNodeDefStore()
const topCategories = computed(() => [
{ id: 'most-relevant', label: t('g.mostRelevant') },
{ id: 'recents', label: t('g.recents') },
{ id: 'favorites', label: t('g.favorites') }
])
const hasEssentialNodes = computed(() =>
nodeDefStore.visibleNodeDefs.some(
(n) => n.nodeSource.type === NodeSourceType.Essentials
)
)
const sourceCategories = computed(() => {
const categories = []
if (hasEssentialNodes.value) {
categories.push({ id: 'essentials', label: t('g.essentials') })
}
categories.push(
{
id: 'blueprints',
label: t('sideToolbar.nodeLibraryTab.filterOptions.blueprints')
},
{ id: 'partner', label: t('g.partner') },
{ id: 'comfy', label: t('g.comfy') },
{ id: 'extensions', label: t('g.extensions') }
)
return categories
})
const categoryTree = computed<CategoryNode[]>(() => {
const tree = nodeOrganizationService.organizeNodes(
nodeDefStore.visibleNodeDefs,
{ groupBy: 'category' }
)
const stripRootPrefix = (key: string) => key.replace(/^root\//, '')
function mapNode(node: TreeNode): CategoryNode {
const children = node.children
?.filter((child): child is TreeNode => !child.leaf)
.map(mapNode)
return {
key: stripRootPrefix(node.key as string),
label: node.label,
...(children?.length ? { children } : {})
}
}
return (tree.children ?? [])
.filter((node): node is TreeNode => !node.leaf)
.map(mapNode)
})
function categoryBtnClass(id: string) {
return cn(
'cursor-pointer rounded-sm border-none bg-transparent px-3 py-2.5 text-left text-sm transition-colors',
selectedCategory.value === id
? CATEGORY_SELECTED_CLASS
: CATEGORY_UNSELECTED_CLASS
)
}
const selectedCollapsed = ref(false)
function selectCategory(categoryId: string) {
if (selectedCategory.value === categoryId) {
selectedCollapsed.value = !selectedCollapsed.value
} else {
selectedCollapsed.value = false
selectedCategory.value = categoryId
}
}
</script>