mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-22 21:38:52 +00:00
Compare commits
4 Commits
glary/fix-
...
feat/model
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1610bcaacb | ||
|
|
5b6508e103 | ||
|
|
563e759041 | ||
|
|
984b6914d3 |
136
apps/website/src/components/models/ModelCreationsSection.vue
Normal file
136
apps/website/src/components/models/ModelCreationsSection.vue
Normal file
@@ -0,0 +1,136 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
import type { Locale } from '../../i18n/translations'
|
||||
import type { GalleryItem } from '../gallery/GallerySection.vue'
|
||||
|
||||
import { t } from '../../i18n/translations'
|
||||
import BrandButton from '../common/BrandButton.vue'
|
||||
import GalleryCard from '../gallery/GalleryCard.vue'
|
||||
import GalleryDetailModal from '../gallery/GalleryDetailModal.vue'
|
||||
|
||||
const { locale = 'en' } = defineProps<{ locale?: Locale }>()
|
||||
|
||||
const modelName = 'Grok'
|
||||
const ctaHref = 'https://comfy.org/workflows/model/grok'
|
||||
|
||||
const items: GalleryItem[] = [
|
||||
{
|
||||
video: 'https://media.comfy.org/videos/compressed_512/eye.webm',
|
||||
title: 'Until Our Eye Interlink harajuku',
|
||||
userAlias: 'ShaneF Motion Design',
|
||||
teamAlias: 'ThinkDiffusion',
|
||||
tool: 'Grok Imagine',
|
||||
href: 'https://www.thinkdiffusion.com/studio#success-stories-anta'
|
||||
},
|
||||
{
|
||||
image: 'https://media.comfy.org/website/gallery/gallery.webp',
|
||||
title: 'Amber Astronaut',
|
||||
userAlias: 'Yogo',
|
||||
teamAlias: '',
|
||||
tool: 'Grok Imagine',
|
||||
href: 'https://de.linkedin.com/in/milan-kastenmueller-18778a174'
|
||||
},
|
||||
{
|
||||
video: 'https://media.comfy.org/videos/compressed_512/cigarette.webm',
|
||||
title: 'Autopoiesis',
|
||||
userAlias: 'Yogo',
|
||||
teamAlias: 'Visual Frisson',
|
||||
tool: 'Grok Imagine',
|
||||
href: 'https://www.instagram.com/visualfrisson/?hl=en'
|
||||
},
|
||||
{
|
||||
video: 'https://media.comfy.org/videos/compressed_512/kyrie.webm',
|
||||
title: 'Origins',
|
||||
userAlias: 'ShaneF Motion Design',
|
||||
teamAlias: 'ThinkDiffusion',
|
||||
tool: 'Grok Imagine',
|
||||
href: 'https://vimeo.com/1021360563'
|
||||
},
|
||||
{
|
||||
image: 'https://media.comfy.org/website/gallery/desert.webp',
|
||||
title: 'Desert Landing',
|
||||
userAlias: 'Yogo',
|
||||
teamAlias: '',
|
||||
tool: 'Grok Imagine',
|
||||
href: 'https://de.linkedin.com/in/milan-kastenmueller-18778a174'
|
||||
}
|
||||
]
|
||||
|
||||
const modalOpen = ref(false)
|
||||
const modalIndex = ref(0)
|
||||
|
||||
function openDetail(index: number) {
|
||||
modalIndex.value = index
|
||||
modalOpen.value = true
|
||||
}
|
||||
|
||||
const title = t('models.list.creations.title', locale).replace(
|
||||
'{name}',
|
||||
modelName
|
||||
)
|
||||
const ctaLabel = t('models.list.creations.cta', locale)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
data-testid="model-creations"
|
||||
class="flex flex-col items-center px-4 pt-12 pb-20 lg:px-20"
|
||||
>
|
||||
<h2
|
||||
class="text-primary-comfy-canvas max-w-4xl text-center text-3xl font-light tracking-tight lg:text-5xl"
|
||||
>
|
||||
{{ title }}
|
||||
</h2>
|
||||
<BrandButton
|
||||
:href="ctaHref"
|
||||
variant="solid"
|
||||
size="lg"
|
||||
class="mt-16 px-8 py-4 uppercase"
|
||||
>
|
||||
{{ ctaLabel }}
|
||||
</BrandButton>
|
||||
|
||||
<div class="mt-20 hidden w-full flex-col gap-2 lg:flex">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<GalleryCard
|
||||
v-for="(item, i) in items.slice(0, 2)"
|
||||
:key="i"
|
||||
:item
|
||||
:locale
|
||||
@click="openDetail(i)"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="items.length > 2" class="grid grid-cols-3 gap-2">
|
||||
<GalleryCard
|
||||
v-for="(item, i) in items.slice(2, 5)"
|
||||
:key="i + 2"
|
||||
:item
|
||||
:locale
|
||||
@click="openDetail(i + 2)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="rounded-5xl bg-transparency-white-t4 mt-12 flex w-full flex-col gap-6 p-2 lg:hidden"
|
||||
>
|
||||
<GalleryCard
|
||||
v-for="(item, i) in items"
|
||||
:key="i"
|
||||
:item
|
||||
:locale
|
||||
mobile
|
||||
@click="openDetail(i)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<GalleryDetailModal
|
||||
v-if="modalOpen"
|
||||
:items
|
||||
:initial-index="modalIndex"
|
||||
:locale
|
||||
@close="modalOpen = false"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
50
apps/website/src/components/models/ModelsHeroSection.vue
Normal file
50
apps/website/src/components/models/ModelsHeroSection.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
import type { Locale } from '../../i18n/translations'
|
||||
|
||||
import { t } from '../../i18n/translations'
|
||||
import BrandButton from '../common/BrandButton.vue'
|
||||
|
||||
const {
|
||||
locale = 'en',
|
||||
modelName,
|
||||
ctaHref,
|
||||
mediaSrc,
|
||||
mediaAlt = ''
|
||||
} = defineProps<{
|
||||
locale?: Locale
|
||||
modelName: string
|
||||
ctaHref: string
|
||||
mediaSrc: string
|
||||
mediaAlt?: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="flex flex-col items-center px-6 pt-36 pb-16 text-center">
|
||||
<h1
|
||||
class="text-primary-comfy-canvas max-w-4xl text-4xl font-light tracking-tight lg:text-6xl"
|
||||
>
|
||||
{{ modelName }} in <span class="text-primary-comfy-yellow">ComfyUI</span>
|
||||
</h1>
|
||||
<p
|
||||
class="text-primary-comfy-canvas mt-6 max-w-2xl text-sm text-pretty lg:text-base"
|
||||
>
|
||||
{{ t('hero.subtitle', locale) }}
|
||||
</p>
|
||||
<BrandButton
|
||||
:href="ctaHref"
|
||||
variant="solid"
|
||||
size="lg"
|
||||
class="mt-10 px-8 py-4 uppercase"
|
||||
>
|
||||
{{ t('models.list.heroCta', locale).replace('{name}', modelName) }}
|
||||
</BrandButton>
|
||||
<div class="mt-16 w-full max-w-5xl">
|
||||
<img
|
||||
:src="mediaSrc"
|
||||
:alt="mediaAlt"
|
||||
class="rounded-4.5xl size-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
114
apps/website/src/components/models/ModelsShowcaseSection.vue
Normal file
114
apps/website/src/components/models/ModelsShowcaseSection.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<script setup lang="ts">
|
||||
import type { Locale, TranslationKey } from '../../i18n/translations'
|
||||
|
||||
import { externalLinks, getRoutes } from '../../config/routes'
|
||||
import { t } from '../../i18n/translations'
|
||||
import BrandButton from '../common/BrandButton.vue'
|
||||
import ShowcaseCard from './ShowcaseCard.vue'
|
||||
|
||||
export type ModelCard = {
|
||||
titleKey: TranslationKey
|
||||
slug: string
|
||||
imageSrc: string
|
||||
badgeIcon?: string
|
||||
badgeText?: string
|
||||
layoutClass: string
|
||||
objectPosition?: string
|
||||
}
|
||||
|
||||
const { locale = 'en' } = defineProps<{ locale?: Locale }>()
|
||||
|
||||
const routes = getRoutes(locale)
|
||||
|
||||
const modelCards: ModelCard[] = [
|
||||
{
|
||||
titleKey: 'models.showcase.card.grokImagine',
|
||||
slug: 'grok-image',
|
||||
imageSrc: 'https://media.comfy.org/website/cloud/ai-models/grok-video.webm',
|
||||
badgeIcon: '/icons/ai-models/grok.svg',
|
||||
layoutClass: 'lg:col-span-6'
|
||||
},
|
||||
{
|
||||
titleKey: 'models.showcase.card.nanoBananaPro',
|
||||
slug: 'nano-banana',
|
||||
imageSrc:
|
||||
'https://media.comfy.org/website/cloud/ai-models/nano-banana-pro.webp',
|
||||
badgeIcon: '/icons/ai-models/gemini.svg',
|
||||
layoutClass: 'lg:col-span-6',
|
||||
objectPosition: 'center 20%'
|
||||
},
|
||||
{
|
||||
titleKey: 'models.showcase.card.ltx23',
|
||||
slug: 'ltxv-api',
|
||||
imageSrc: 'https://media.comfy.org/website/gallery/desert.webp',
|
||||
badgeText: 'ltx',
|
||||
layoutClass: 'lg:col-span-4'
|
||||
},
|
||||
{
|
||||
titleKey: 'models.showcase.card.qwenAdvancedEdit',
|
||||
slug: 'qwen-image-fp8-e4m3fn',
|
||||
imageSrc:
|
||||
'https://media.comfy.org/website/cloud/ai-models/qwen-image-edit.webp',
|
||||
badgeIcon: '/icons/ai-models/qwen.svg',
|
||||
layoutClass: 'lg:col-span-4'
|
||||
},
|
||||
{
|
||||
titleKey: 'models.showcase.card.wan22TextToVideo',
|
||||
slug: 'wan-api',
|
||||
imageSrc: 'https://media.comfy.org/website/cloud/ai-models/wan-22.webm',
|
||||
badgeIcon: '/icons/ai-models/wan.svg',
|
||||
layoutClass: 'lg:col-span-4'
|
||||
}
|
||||
]
|
||||
|
||||
function modelHref(slug: string): string {
|
||||
return `${routes.models}/${slug}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="px-4 py-24 lg:px-20 lg:py-40">
|
||||
<div class="mx-auto flex w-full max-w-7xl flex-col items-center">
|
||||
<p
|
||||
class="text-primary-comfy-yellow text-center text-sm font-bold tracking-widest uppercase"
|
||||
>
|
||||
{{ t('models.showcase.label', locale) }}
|
||||
</p>
|
||||
|
||||
<h2
|
||||
class="text-primary-comfy-canvas text-3.5xl/tight mt-8 max-w-4xl text-center font-light whitespace-pre-line lg:text-5xl"
|
||||
>
|
||||
{{ t('models.showcase.heading', locale) }}
|
||||
</h2>
|
||||
|
||||
<p
|
||||
class="text-primary-comfy-canvas mt-8 max-w-xl text-center text-sm font-light lg:text-base/snug"
|
||||
>
|
||||
{{ t('models.showcase.subtitle', locale) }}
|
||||
</p>
|
||||
|
||||
<div class="mt-24 w-full">
|
||||
<div class="bg-transparency-white-t4 rounded-4xl p-2 lg:p-1.5">
|
||||
<div class="grid grid-cols-1 gap-2 lg:grid-cols-12">
|
||||
<ShowcaseCard
|
||||
v-for="card in modelCards"
|
||||
:key="card.titleKey"
|
||||
:card="card"
|
||||
:href="modelHref(card.slug)"
|
||||
:locale="locale"
|
||||
:class="card.layoutClass"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BrandButton
|
||||
:href="externalLinks.workflows"
|
||||
variant="outline"
|
||||
class="mt-8 w-full max-w-md text-center lg:w-auto"
|
||||
>
|
||||
{{ t('models.showcase.cta', locale) }}
|
||||
</BrandButton>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
96
apps/website/src/components/models/ShowcaseCard.vue
Normal file
96
apps/website/src/components/models/ShowcaseCard.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@comfyorg/tailwind-utils'
|
||||
|
||||
import type { Locale } from '../../i18n/translations'
|
||||
import type { ModelCard } from './ModelsShowcaseSection.vue'
|
||||
|
||||
import { t } from '../../i18n/translations'
|
||||
|
||||
const {
|
||||
card,
|
||||
href,
|
||||
locale = 'en'
|
||||
} = defineProps<{
|
||||
card: ModelCard
|
||||
href: string
|
||||
locale?: Locale
|
||||
}>()
|
||||
|
||||
const badgeBase =
|
||||
'bg-white/20 text-white backdrop-blur-sm transition-colors duration-300 ease-in-out group-hover:bg-primary-comfy-yellow group-hover:text-primary-comfy-ink'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a
|
||||
:href="href"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="group relative h-80 cursor-pointer overflow-hidden rounded-4xl bg-black/40"
|
||||
>
|
||||
<video
|
||||
v-if="card.imageSrc.endsWith('.webm')"
|
||||
:src="card.imageSrc"
|
||||
:aria-label="t(card.titleKey, locale)"
|
||||
:style="
|
||||
card.objectPosition
|
||||
? { objectPosition: card.objectPosition }
|
||||
: undefined
|
||||
"
|
||||
class="size-full object-cover transition-transform duration-600 ease-in-out group-hover:scale-105"
|
||||
autoplay
|
||||
loop
|
||||
muted
|
||||
playsinline
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
:src="card.imageSrc"
|
||||
:alt="t(card.titleKey, locale)"
|
||||
:style="
|
||||
card.objectPosition
|
||||
? { objectPosition: card.objectPosition }
|
||||
: undefined
|
||||
"
|
||||
class="size-full object-cover transition-transform duration-600 ease-in-out group-hover:scale-105"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="absolute inset-0 bg-linear-to-t from-black/50 via-black/5 to-black/35"
|
||||
/>
|
||||
|
||||
<div
|
||||
:class="
|
||||
cn(
|
||||
'absolute top-5 right-5 flex h-12 min-w-12 items-center justify-center px-3 lg:top-6 lg:right-6',
|
||||
badgeBase,
|
||||
'rounded-2xl'
|
||||
)
|
||||
"
|
||||
>
|
||||
<span
|
||||
v-if="card.badgeIcon"
|
||||
class="inline-block size-6 bg-current"
|
||||
:style="{
|
||||
maskImage: `url(${card.badgeIcon})`,
|
||||
maskSize: 'contain',
|
||||
maskRepeat: 'no-repeat',
|
||||
maskPosition: 'center'
|
||||
}"
|
||||
/>
|
||||
<span
|
||||
v-else-if="card.badgeText"
|
||||
class="text-xs font-bold tracking-wider lowercase"
|
||||
>
|
||||
{{ card.badgeText }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p
|
||||
class="text-primary-warm-white absolute inset-x-6 bottom-6 text-2xl/tight font-light whitespace-pre-line drop-shadow-[0_2px_8px_rgba(0,0,0,0.9)] lg:top-6 lg:right-auto lg:bottom-auto lg:text-3xl"
|
||||
>
|
||||
{{ t(card.titleKey, locale) }}
|
||||
</p>
|
||||
</a>
|
||||
</template>
|
||||
@@ -4194,6 +4194,76 @@ const translations = {
|
||||
'zh-CN': '支持的模型'
|
||||
},
|
||||
|
||||
// Models list page (/models)
|
||||
'models.list.label': { en: 'MODELS', 'zh-CN': '模型' },
|
||||
'models.list.heroCta': {
|
||||
en: 'Try {name} Now',
|
||||
'zh-CN': '立即试用 {name}'
|
||||
},
|
||||
'models.list.creations.title': {
|
||||
en: '{name} Image and Video Creations',
|
||||
'zh-CN': '{name} 图像与视频创作'
|
||||
},
|
||||
'models.list.creations.cta': {
|
||||
en: 'Explore Workflows',
|
||||
'zh-CN': '探索工作流'
|
||||
},
|
||||
'models.list.heroTitle.before': {
|
||||
en: 'Run the world’s leading AI models in',
|
||||
'zh-CN': '在以下平台运行世界领先的 AI 模型'
|
||||
},
|
||||
'models.list.heroSubtitle': {
|
||||
en: 'From open-source diffusion checkpoints to partner APIs — every major model, with community workflow templates ready to run.',
|
||||
'zh-CN':
|
||||
'从开源扩散模型到合作伙伴 API,涵盖每一个主流模型,并附带可直接运行的社区工作流模板。'
|
||||
},
|
||||
'models.list.card.workflows': {
|
||||
en: '{count} workflows',
|
||||
'zh-CN': '{count} 个工作流'
|
||||
},
|
||||
'models.list.contact.label': {
|
||||
en: 'COMFY HUB',
|
||||
'zh-CN': 'COMFY HUB'
|
||||
},
|
||||
'models.showcase.label': { en: 'AI MODELS', 'zh-CN': 'AI 模型' },
|
||||
'models.showcase.heading': {
|
||||
en: 'Run the world’s\nleading AI models',
|
||||
'zh-CN': '运行全球领先的\nAI 模型'
|
||||
},
|
||||
'models.showcase.subtitle': {
|
||||
en: 'New models are added as they launch.',
|
||||
'zh-CN': '新模型发布后会第一时间上线。'
|
||||
},
|
||||
'models.showcase.cta': {
|
||||
en: 'EXPLORE WORKFLOWS',
|
||||
'zh-CN': '探索工作流'
|
||||
},
|
||||
'models.showcase.card.grokImagine': {
|
||||
en: 'Grok Imagine',
|
||||
'zh-CN': 'Grok Imagine'
|
||||
},
|
||||
'models.showcase.card.nanoBananaPro': {
|
||||
en: 'Nano Banana Pro',
|
||||
'zh-CN': 'Nano Banana Pro'
|
||||
},
|
||||
'models.showcase.card.ltx23': {
|
||||
en: 'LTX 2.3',
|
||||
'zh-CN': 'LTX 2.3'
|
||||
},
|
||||
'models.showcase.card.qwenAdvancedEdit': {
|
||||
en: 'Advanced image\nediting with Qwen',
|
||||
'zh-CN': '使用 Qwen 进行\n高级图像编辑'
|
||||
},
|
||||
'models.showcase.card.wan22TextToVideo': {
|
||||
en: 'Wan 2.2\ntext to video',
|
||||
'zh-CN': 'Wan 2.2\n文字转视频'
|
||||
},
|
||||
'models.list.contact.heading': {
|
||||
en: 'Pick a model and explore what the community has built. <a href="https://comfy.org/workflows" target="_blank" rel="noopener noreferrer" class="text-primary-comfy-yellow underline">Browse Comfy Hub</a> for the newest workflows.',
|
||||
'zh-CN':
|
||||
'选择一个模型,浏览社区的创作成果。<a href="https://comfy.org/workflows" target="_blank" rel="noopener noreferrer" class="text-primary-comfy-yellow underline">访问 Comfy Hub</a> 查看最新工作流。'
|
||||
},
|
||||
|
||||
// Payment status pages
|
||||
'payment.success.label': {
|
||||
en: 'PAYMENT',
|
||||
|
||||
22
apps/website/src/pages/models.astro
Normal file
22
apps/website/src/pages/models.astro
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro'
|
||||
import ModelsHeroSection from '../components/models/ModelsHeroSection.vue'
|
||||
import ModelCreationsSection from '../components/models/ModelCreationsSection.vue'
|
||||
import ModelsShowcaseSection from '../components/models/ModelsShowcaseSection.vue'
|
||||
import ProductShowcaseSection from '../components/home/ProductShowcaseSection.vue'
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="Models — Comfy"
|
||||
description="Run the world's leading AI models in ComfyUI. Browse every supported model with community workflow templates ready to run."
|
||||
>
|
||||
<ModelsHeroSection
|
||||
modelName="Grok Imagine"
|
||||
ctaHref="/p/supported-models/grok-image"
|
||||
mediaSrc="https://media.comfy.org/website/gallery/gallery.webp"
|
||||
mediaAlt="Grok Imagine output created with ComfyUI"
|
||||
/>
|
||||
<ModelCreationsSection client:load />
|
||||
<ModelsShowcaseSection />
|
||||
<ProductShowcaseSection client:load />
|
||||
</BaseLayout>
|
||||
23
apps/website/src/pages/zh-CN/models.astro
Normal file
23
apps/website/src/pages/zh-CN/models.astro
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro'
|
||||
import ModelsHeroSection from '../../components/models/ModelsHeroSection.vue'
|
||||
import ModelCreationsSection from '../../components/models/ModelCreationsSection.vue'
|
||||
import ModelsShowcaseSection from '../../components/models/ModelsShowcaseSection.vue'
|
||||
import ProductShowcaseSection from '../../components/home/ProductShowcaseSection.vue'
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="模型 — Comfy"
|
||||
description="在 ComfyUI 中运行世界领先的 AI 模型。浏览所有支持的模型及社区工作流模板。"
|
||||
>
|
||||
<ModelsHeroSection
|
||||
locale="zh-CN"
|
||||
modelName="Grok Imagine"
|
||||
ctaHref="/zh-CN/p/supported-models/grok-image"
|
||||
mediaSrc="https://media.comfy.org/website/gallery/gallery.webp"
|
||||
mediaAlt="Grok Imagine output created with ComfyUI"
|
||||
/>
|
||||
<ModelCreationsSection client:load locale="zh-CN" />
|
||||
<ModelsShowcaseSection locale="zh-CN" />
|
||||
<ProductShowcaseSection client:load locale="zh-CN" />
|
||||
</BaseLayout>
|
||||
Reference in New Issue
Block a user