mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-25 16:59:45 +00:00
Bookmark folder icon customization (#647)
* Add bookmark customization support * WIP * Fix bugs * Fix color update * Handle rename and delete of customization * nit * Add custom color picker * Computed final color * i18n * Remove cancel button as dialog already has it * Add playwright test
This commit is contained in:
@@ -86,6 +86,12 @@
|
||||
</template>
|
||||
</SidebarTabTemplate>
|
||||
<ContextMenu ref="menu" :model="menuItems" />
|
||||
<FolderCustomizationDialog
|
||||
v-model="showCustomizationDialog"
|
||||
@confirm="updateCustomization"
|
||||
:initialIcon="initialIcon"
|
||||
:initialColor="initialColor"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -105,6 +111,7 @@ import ContextMenu from 'primevue/contextmenu'
|
||||
import EditableText from '@/components/common/EditableText.vue'
|
||||
import NodePreview from '@/components/node/NodePreview.vue'
|
||||
import SearchBox from '@/components/common/SearchBox.vue'
|
||||
import FolderCustomizationDialog from '@/components/common/CustomizationDialog.vue'
|
||||
import SidebarTabTemplate from '@/components/sidebar/tabs/SidebarTabTemplate.vue'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { app } from '@/scripts/app'
|
||||
@@ -171,6 +178,11 @@ const getTreeNodeIcon = (node: TreeNode) => {
|
||||
|
||||
// If the node is a bookmark folder, show a bookmark icon
|
||||
if (node.data && node.data.isDummyFolder) {
|
||||
const customization =
|
||||
nodeBookmarkStore.bookmarksCustomization[node.data.nodePath]
|
||||
if (customization?.icon) {
|
||||
return 'pi ' + customization.icon
|
||||
}
|
||||
return 'pi pi-bookmark-fill'
|
||||
}
|
||||
|
||||
@@ -280,13 +292,22 @@ const menuItems = computed<MenuItem[]>(() => [
|
||||
command: () => {
|
||||
renameEditingNode.value = menuTargetNode.value
|
||||
}
|
||||
},
|
||||
{
|
||||
label: t('customize'),
|
||||
icon: 'pi pi-palette',
|
||||
command: () => {
|
||||
initialIcon.value =
|
||||
nodeBookmarkStore.bookmarksCustomization[
|
||||
menuTargetNode.value.data.nodePath
|
||||
]?.icon || nodeBookmarkStore.defaultBookmarkIcon
|
||||
initialColor.value =
|
||||
nodeBookmarkStore.bookmarksCustomization[
|
||||
menuTargetNode.value.data.nodePath
|
||||
]?.color || nodeBookmarkStore.defaultBookmarkColor
|
||||
showCustomizationDialog.value = true
|
||||
}
|
||||
}
|
||||
// TODO: Add customize color and icon feature.
|
||||
// {
|
||||
// label: t('customize'),
|
||||
// icon: 'pi pi-palette',
|
||||
// command: () => console.log('customize')
|
||||
// }
|
||||
])
|
||||
|
||||
const handleContextMenu = (node: TreeNode, e: MouseEvent) => {
|
||||
@@ -320,6 +341,18 @@ const addNewBookmarkFolder = (parent?: ComfyNodeDefImpl) => {
|
||||
renameEditingNode.value = findNodeByKey(renderedRoot.value, newFolderKey)
|
||||
})
|
||||
}
|
||||
|
||||
const showCustomizationDialog = ref(false)
|
||||
const initialIcon = ref(nodeBookmarkStore.defaultBookmarkIcon)
|
||||
const initialColor = ref(nodeBookmarkStore.defaultBookmarkColor)
|
||||
const updateCustomization = (icon: string, color: string) => {
|
||||
if (menuTargetNode.value?.data) {
|
||||
nodeBookmarkStore.updateBookmarkCustomization(
|
||||
menuTargetNode.value.data.nodePath,
|
||||
{ icon, color }
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -26,7 +26,8 @@ import type { CanvasDragAndDropData } from '@/types/litegraphTypes'
|
||||
import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'
|
||||
import Badge from 'primevue/badge'
|
||||
import type { TreeNode } from 'primevue/treenode'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import type { BookmarkCustomization } from '@/types/apiTypes'
|
||||
|
||||
const props = defineProps<{
|
||||
node: TreeNode
|
||||
@@ -39,6 +40,10 @@ const emit = defineEmits<{
|
||||
|
||||
const nodeBookmarkStore = useNodeBookmarkStore()
|
||||
|
||||
const customization = computed<BookmarkCustomization | undefined>(() => {
|
||||
return nodeBookmarkStore.bookmarksCustomization[props.node.data.nodePath]
|
||||
})
|
||||
|
||||
const addNodeToBookmarkFolder = (node: ComfyNodeDefImpl) => {
|
||||
if (!props.node.data) {
|
||||
console.error('Bookmark folder does not have data!')
|
||||
@@ -56,15 +61,20 @@ const addNodeToBookmarkFolder = (node: ComfyNodeDefImpl) => {
|
||||
const container = ref<HTMLElement | null>(null)
|
||||
const canDrop = ref(false)
|
||||
|
||||
const treeNodeElement = ref<HTMLElement | null>(null)
|
||||
const iconElement = ref<HTMLElement | null>(null)
|
||||
|
||||
let dropTargetCleanup = () => {}
|
||||
let stopWatchCustomization: (() => void) | null = null
|
||||
|
||||
onMounted(() => {
|
||||
if (!props.isBookmarkFolder) return
|
||||
|
||||
const treeNodeElement = container.value?.closest(
|
||||
treeNodeElement.value = container.value?.closest(
|
||||
'.p-tree-node-content'
|
||||
) as HTMLElement
|
||||
dropTargetCleanup = dropTargetForElements({
|
||||
element: treeNodeElement,
|
||||
element: treeNodeElement.value,
|
||||
onDrop: (event) => {
|
||||
const dndData = event.source.data as CanvasDragAndDropData
|
||||
if (dndData.type === 'add-node') {
|
||||
@@ -83,8 +93,34 @@ onMounted(() => {
|
||||
canDrop.value = false
|
||||
}
|
||||
})
|
||||
|
||||
iconElement.value = treeNodeElement.value.querySelector(
|
||||
':scope > .p-tree-node-icon'
|
||||
) as HTMLElement
|
||||
|
||||
updateIconColor()
|
||||
|
||||
// Start watching after the component is mounted
|
||||
stopWatchCustomization = watch(customization, updateIconColor, { deep: true })
|
||||
})
|
||||
|
||||
const updateIconColor = () => {
|
||||
if (iconElement.value && customization.value) {
|
||||
iconElement.value.style.color = customization.value.color
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
dropTargetCleanup()
|
||||
if (stopWatchCustomization) {
|
||||
stopWatchCustomization()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.node-tree-folder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user