mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-06-07 08:14:42 +00:00
## Summary Adds a new Learning page to the website with a hero, featured workflow showcase, tutorials section, and CTA, wired into site nav and footer Resources. ## Changes - **What**: - New `/learning` page (Astro) with `HeroSection`, `FeaturedWorkflowSection`, `TutorialsSection`, and `CallToActionSection` - Localized for `zh-CN` at `/zh-CN/learning` - Featured workflow CTA links out to `comfy.org/workflows/<slug>` - Added `nav.learning` translation; added Learning entry to `SiteNav` and `SiteFooter` Resources - New shared `PillButton`, `MaskRevealButton`, `Badge`, and `VideoPlayer` work used by the page; `TutorialDetailDialog` for tutorial deep-dives - Featured demo video updated; poster image added - `routes.ts`: added `learning` route entry - `EventsSection` temporarily hidden pending content ## Review Focus - Copy on `learning.featured.description` (newly written, both `en` and `zh-CN`) - Tutorial data shape in `data/learningTutorials*.ts` - Internal-vs-external link styling: Learning shows the active-page yellow when viewing `/learning` (expected — internal route, no external arrow) ## Screenshots (if applicable) _Add deployment preview screenshots here._ --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Alexander Brown <drjkl@comfy.org>
97 lines
2.8 KiB
Vue
97 lines
2.8 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, onUnmounted, useTemplateRef, watch } from 'vue'
|
|
|
|
import type { LearningTutorial } from '../../data/learningTutorials'
|
|
import type { Locale } from '../../i18n/translations'
|
|
|
|
import { lockScroll, unlockScroll } from '../../composables/scrollLock'
|
|
import { t } from '../../i18n/translations'
|
|
|
|
const { tutorial, locale = 'en' } = defineProps<{
|
|
tutorial: LearningTutorial
|
|
locale?: Locale
|
|
}>()
|
|
|
|
const emit = defineEmits<{ close: [] }>()
|
|
|
|
const dialogRef = useTemplateRef<HTMLDialogElement>('dialogRef')
|
|
const videoRef = useTemplateRef<HTMLVideoElement>('videoRef')
|
|
|
|
const playFromStart = () => {
|
|
const video = videoRef.value
|
|
if (!video) return
|
|
video.currentTime = 0
|
|
void video.play().catch(() => {})
|
|
}
|
|
|
|
watch(
|
|
() => tutorial.id,
|
|
() => {
|
|
playFromStart()
|
|
}
|
|
)
|
|
|
|
function handleBackdropClick(e: MouseEvent) {
|
|
if (e.target === e.currentTarget) emit('close')
|
|
}
|
|
|
|
function handleKeydown(e: KeyboardEvent) {
|
|
if (e.key === 'Escape') emit('close')
|
|
}
|
|
|
|
onMounted(() => {
|
|
lockScroll()
|
|
dialogRef.value?.showModal()
|
|
playFromStart()
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
unlockScroll()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<Teleport to="body">
|
|
<dialog
|
|
ref="dialogRef"
|
|
:aria-label="tutorial.title[locale]"
|
|
class="fixed inset-0 z-50 flex size-full max-h-none max-w-none flex-col items-center justify-center border-0 bg-transparent px-4 py-8 backdrop-blur-xl backdrop:bg-transparent lg:px-20 lg:py-8"
|
|
@click="handleBackdropClick"
|
|
@keydown="handleKeydown"
|
|
@close="emit('close')"
|
|
>
|
|
<button
|
|
:aria-label="t('gallery.detail.close', locale)"
|
|
class="border-primary-comfy-yellow bg-primary-comfy-ink hover:bg-primary-comfy-yellow group absolute top-8 right-10 z-10 flex size-10 cursor-pointer items-center justify-center rounded-2xl border-2 transition-colors lg:right-26"
|
|
@click="emit('close')"
|
|
>
|
|
<span
|
|
class="bg-primary-comfy-yellow group-hover:bg-primary-comfy-ink size-5 transition-colors"
|
|
style="mask: url('/icons/close.svg') center / contain no-repeat"
|
|
/>
|
|
</button>
|
|
|
|
<div
|
|
class="border-primary-comfy-yellow bg-primary-comfy-ink rounded-5xl flex w-full max-w-7xl items-center justify-center overflow-hidden border-2 p-3 lg:p-4"
|
|
>
|
|
<video
|
|
ref="videoRef"
|
|
:src="tutorial.videoSrc"
|
|
:poster="tutorial.poster"
|
|
class="aspect-video w-full rounded-3xl object-contain lg:rounded-4xl"
|
|
controls
|
|
autoplay
|
|
playsinline
|
|
></video>
|
|
</div>
|
|
|
|
<h2
|
|
class="text-primary-comfy-canvas mt-6 text-center text-lg font-medium lg:text-xl"
|
|
>
|
|
{{ t('learning.tutorials.titlePrefix', locale) }}
|
|
{{ tutorial.title[locale] }}
|
|
</h2>
|
|
</dialog>
|
|
</Teleport>
|
|
</template>
|