fix: workflow template style review

This commit is contained in:
Jin Yi
2025-09-26 15:20:51 +09:00
parent a5100ba37a
commit f44356b152
4 changed files with 85 additions and 81 deletions

View File

@@ -1,5 +1,5 @@
<template>
<div :class="containerClasses" :style="containerStyle">
<div :class="containerClasses">
<slot name="top"></slot>
<slot name="bottom"></slot>
</div>
@@ -8,36 +8,26 @@
<script setup lang="ts">
import { computed } from 'vue'
const {
ratio = 'square',
maxWidth,
minWidth
} = defineProps<{
maxWidth?: number
minWidth?: number
ratio?: 'square' | 'portrait' | 'tallPortrait' | 'none'
const { ratio = 'square', type } = defineProps<{
ratio?: 'smallSquare' | 'square' | 'portrait' | 'tallPortrait'
type?: string
}>()
const containerClasses = computed(() => {
const baseClasses =
'flex flex-col hover:bg-white dark-theme:hover:bg-zinc-800 rounded-lg hover:shadow-sm hover:border hover:border-zinc-200 dark-theme:hover:border-zinc-700 overflow-hidden hover:p-2'
'cursor-pointer flex flex-col bg-white dark-theme:bg-zinc-800 rounded-lg shadow-sm border border-zinc-200 dark-theme:border-zinc-700 overflow-hidden'
if (type === 'workflow-template-card') {
return `cursor-pointer p-2 flex flex-col hover:bg-white dark-theme:hover:bg-zinc-800 rounded-lg transition-background duration-200 ease-in-out`
}
const ratioClasses = {
smallSquare: 'aspect-240/311',
square: 'aspect-256/308',
portrait: 'aspect-256/325',
tallPortrait: 'aspect-256/353',
none: ''
tallPortrait: 'aspect-256/353'
}
return `${baseClasses} ${ratioClasses[ratio]}`
})
const containerStyle = computed(() =>
maxWidth || minWidth
? {
maxWidth: maxWidth ? `${maxWidth}px` : undefined,
minWidth: minWidth ? `${minWidth}px` : undefined
}
: {}
)
</script>

View File

@@ -2,26 +2,40 @@
<div :class="topStyle">
<slot class="absolute top-0 left-0 w-full h-full"></slot>
<div class="absolute top-2 left-2 flex gap-2">
<div
v-if="slots['top-left']"
class="absolute top-2 left-2 flex gap-2 flex-wrap justify-start"
>
<slot name="top-left"></slot>
</div>
<div class="absolute top-2 right-2 flex gap-2">
<div
v-if="slots['top-right']"
class="absolute top-2 right-2 flex gap-2 flex-wrap justify-end"
>
<slot name="top-right"></slot>
</div>
<div class="absolute bottom-2 left-2 flex gap-2">
<div
v-if="slots['bottom-left']"
class="absolute bottom-2 left-2 flex gap-2 flex-wrap justify-start"
>
<slot name="bottom-left"></slot>
</div>
<div class="absolute bottom-2 right-2 flex gap-2 flex-wrap">
<div
v-if="slots['bottom-right']"
class="absolute bottom-2 right-2 flex gap-2 flex-wrap justify-end"
>
<slot name="bottom-right"></slot>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { computed, useSlots } from 'vue'
const slots = useSlots()
const { ratio = 'square' } = defineProps<{
ratio?: 'square' | 'landscape'

View File

@@ -134,16 +134,15 @@
<!-- Template Cards Grid -->
<div
:key="templateListKey"
class="grid grid-cols-[repeat(auto-fill,minmax(16rem,1fr))] gap-x-4 gap-y-6 px-4 py-4"
:style="gridStyle"
data-testid="template-workflows-content"
>
<!-- Loading Skeletons (show while loading initial data) -->
<CardContainer
v-for="n in isLoading ? 12 : 0"
:key="`initial-skeleton-${n}`"
ratio="square"
:max-width="300"
:min-width="200"
ratio="smallSquare"
type="workflow-template-card"
>
<template #top>
<CardTop ratio="landscape">
@@ -174,20 +173,20 @@
:key="template.name"
ref="cardRefs"
v-memo="[template.name, hoveredTemplate === template.name]"
ratio="none"
:max-width="300"
:min-width="200"
class="cursor-pointer transition-all duration-300 hover:scale-[1.02]"
ratio="smallSquare"
type="workflow-template-card"
:data-testid="`template-workflow-${template.name}`"
@mouseenter="hoveredTemplate = template.name"
@mouseleave="hoveredTemplate = null"
@click="onLoadWorkflow(template)"
>
<template #top>
<CardTop ratio="landscape">
<CardTop ratio="square">
<template #default>
<!-- Template Thumbnail -->
<div class="w-full h-full relative">
<div
class="w-full h-full relative rounded-lg overflow-hidden"
>
<template v-if="template.mediaType === 'audio'">
<AudioThumbnail :src="getBaseThumbnailSrc(template)" />
</template>
@@ -266,49 +265,47 @@
</CardTop>
</template>
<template #bottom>
<CardBottom :full-height="false">
<div class="flex flex-col px-4 flex-1">
<div class="flex-1">
<h3
class="line-clamp-2 text-lg font-normal mb-1"
:title="
getTemplateTitle(
template,
getEffectiveSourceModule(template)
)
"
>
{{
getTemplateTitle(
template,
getEffectiveSourceModule(template)
)
}}
</h3>
<div class="flex justify-between gap-2">
<CardBottom>
<div class="flex flex-col gap-2 pt-3">
<h3
class="line-clamp-1 text-sm m-0"
:title="
getTemplateTitle(
template,
getEffectiveSourceModule(template)
)
"
>
{{
getTemplateTitle(
template,
getEffectiveSourceModule(template)
)
}}
</h3>
<div class="flex justify-between gap-2">
<div class="flex-1">
<p
class="line-clamp-2 text-sm text-muted mb-3"
class="line-clamp-2 text-sm text-muted m-0"
:title="getTemplateDescription(template)"
>
{{ getTemplateDescription(template) }}
</p>
<div
v-if="template.tutorialUrl"
class="flex flex-col-reverse justify-center"
</div>
<div
v-if="template.tutorialUrl"
class="flex flex-col-reverse justify-center"
>
<IconButton
v-if="hoveredTemplate === template.name"
v-tooltip.bottom="$t('g.seeTutorial')"
v-bind="$attrs"
type="primary"
size="sm"
@click.stop="openTutorial(template)"
>
<button
v-tooltip.bottom="$t('g.seeTutorial')"
:class="[
'inline-flex items-center justify-center rounded-lg bg-[#FDFBFA] w-8 h-8 cursor-pointer transition-opacity duration-200',
hoveredTemplate === template.name
? 'opacity-100'
: 'opacity-0 pointer-events-none'
]"
@click.stop="openTutorial(template)"
>
<i class="icon-[comfy--dark-info] w-4 h-4" />
</button>
</div>
<i class="icon-[lucide--info] size-4" />
</IconButton>
</div>
</div>
</div>
@@ -320,12 +317,11 @@
<CardContainer
v-for="n in isLoadingMore ? 6 : 0"
:key="`skeleton-${n}`"
ratio="square"
:max-width="300"
:min-width="200"
ratio="smallSquare"
type="workflow-template-card"
>
<template #top>
<CardTop ratio="landscape">
<CardTop ratio="square">
<template #default>
<div
class="w-full h-full bg-neutral-200 dark-theme:bg-neutral-700 animate-pulse"
@@ -382,6 +378,7 @@ import ProgressSpinner from 'primevue/progressspinner'
import { computed, onBeforeUnmount, provide, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import IconButton from '@/components/button/IconButton.vue'
import IconTextButton from '@/components/button/IconTextButton.vue'
import CardBottom from '@/components/card/CardBottom.vue'
import CardContainer from '@/components/card/CardContainer.vue'
@@ -404,6 +401,7 @@ import { useWorkflowTemplatesStore } from '@/platform/workflow/templates/reposit
import type { TemplateInfo } from '@/platform/workflow/templates/types/template'
import type { NavGroupData, NavItemData } from '@/types/navTypes'
import { OnCloseKey } from '@/types/widgetTypes'
import { createGridStyle } from '@/utils/gridUtil'
const { t } = useI18n()
@@ -476,6 +474,8 @@ const navItems = computed<(NavItemData | NavGroupData)[]>(() => {
return workflowTemplatesStore.navGroupedTemplates
})
const gridStyle = computed(() => createGridStyle())
// Get enhanced templates for better filtering
const allTemplates = computed(() => {
return workflowTemplatesStore.enhancedTemplates

View File

@@ -1,7 +1,5 @@
<template>
<div
class="flex flex-col h-full w-full bg-white dark-theme:bg-zinc-800 overflow-y-scroll"
>
<div class="flex flex-col h-full w-full bg-white dark-theme:bg-zinc-800">
<PanelHeader>
<template #icon>
<slot name="header-icon"></slot>
@@ -9,7 +7,9 @@
<slot name="header-title"></slot>
</PanelHeader>
<nav class="flex-1 px-3 py-4 flex flex-col gap-1">
<nav
class="flex-1 px-3 py-4 flex flex-col gap-1 overflow-y-auto scrollbar-hide"
>
<template v-for="(item, index) in navItems" :key="index">
<div v-if="'items' in item" class="flex flex-col gap-2">
<NavTitle