mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
## Summary Adds the layout shell for the marketing site: SEO head, analytics, nav, and footer. ## Changes (incremental from #10140) - BaseLayout.astro: SEO meta (OG/Twitter), GTM (GTM-NP9JM6K7), Vercel Analytics, ClientRouter, i18n - SiteNav.vue: Fixed nav with logo, Enterprise/Gallery/About/Careers links, COMFY CLOUD + COMFY HUB CTAs, mobile hamburger with ARIA - SiteFooter.vue: Product/Resources/Company/Legal columns, social icons ## Stack (via Graphite) - #10140 [1/3] Scaffold ← merge first - **[2/3] Layout Shell** ← this PR - #10142 [3/3] Homepage Sections ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10141-feat-add-layout-shell-BaseLayout-SiteNav-SiteFooter-2-3-3266d73d365081aeb2d7e598943a8e17) by [Unito](https://www.unito.io)
150 lines
4.2 KiB
Vue
150 lines
4.2 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, onUnmounted, ref } from 'vue'
|
|
|
|
const mobileMenuOpen = ref(false)
|
|
const currentPath = ref('')
|
|
|
|
const navLinks = [
|
|
{ label: 'ENTERPRISE', href: '/enterprise' },
|
|
{ label: 'GALLERY', href: '/gallery' },
|
|
{ label: 'ABOUT', href: '/about' },
|
|
{ label: 'CAREERS', href: '/careers' }
|
|
]
|
|
|
|
const ctaLinks = [
|
|
{
|
|
label: 'COMFY CLOUD',
|
|
href: 'https://app.comfy.org',
|
|
primary: true
|
|
},
|
|
{
|
|
label: 'COMFY HUB',
|
|
href: 'https://hub.comfy.org',
|
|
primary: false
|
|
}
|
|
]
|
|
|
|
function onKeydown(e: KeyboardEvent) {
|
|
if (e.key === 'Escape' && mobileMenuOpen.value) {
|
|
mobileMenuOpen.value = false
|
|
}
|
|
}
|
|
|
|
function onAfterSwap() {
|
|
mobileMenuOpen.value = false
|
|
currentPath.value = window.location.pathname
|
|
}
|
|
|
|
onMounted(() => {
|
|
document.addEventListener('keydown', onKeydown)
|
|
document.addEventListener('astro:after-swap', onAfterSwap)
|
|
currentPath.value = window.location.pathname
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
document.removeEventListener('keydown', onKeydown)
|
|
document.removeEventListener('astro:after-swap', onAfterSwap)
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<nav
|
|
class="fixed top-0 left-0 right-0 z-50 bg-black/80 backdrop-blur-md"
|
|
aria-label="Main navigation"
|
|
>
|
|
<div class="mx-auto flex max-w-7xl items-center justify-between px-6 py-4">
|
|
<!-- Logo -->
|
|
<a href="/" class="text-2xl font-bold italic text-brand-yellow">
|
|
Comfy
|
|
</a>
|
|
|
|
<!-- Desktop nav links -->
|
|
<div class="hidden items-center gap-8 md:flex">
|
|
<a
|
|
v-for="link in navLinks"
|
|
:key="link.href"
|
|
:href="link.href"
|
|
:aria-current="currentPath === link.href ? 'page' : undefined"
|
|
class="text-sm font-medium tracking-wide text-white transition-colors hover:text-brand-yellow"
|
|
>
|
|
{{ link.label }}
|
|
</a>
|
|
|
|
<div class="flex items-center gap-3">
|
|
<a
|
|
v-for="cta in ctaLinks"
|
|
:key="cta.href"
|
|
:href="cta.href"
|
|
:class="
|
|
cta.primary
|
|
? 'bg-brand-yellow text-black hover:opacity-90 transition-opacity'
|
|
: 'border border-brand-yellow text-brand-yellow hover:bg-brand-yellow hover:text-black transition-colors'
|
|
"
|
|
class="rounded-full px-5 py-2 text-sm font-semibold"
|
|
>
|
|
{{ cta.label }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile hamburger -->
|
|
<button
|
|
class="flex flex-col gap-1.5 md:hidden"
|
|
aria-label="Toggle menu"
|
|
aria-controls="site-mobile-menu"
|
|
:aria-expanded="mobileMenuOpen"
|
|
@click="mobileMenuOpen = !mobileMenuOpen"
|
|
>
|
|
<span
|
|
class="block h-0.5 w-6 bg-white transition-transform"
|
|
:class="mobileMenuOpen && 'translate-y-2 rotate-45'"
|
|
/>
|
|
<span
|
|
class="block h-0.5 w-6 bg-white transition-opacity"
|
|
:class="mobileMenuOpen && 'opacity-0'"
|
|
/>
|
|
<span
|
|
class="block h-0.5 w-6 bg-white transition-transform"
|
|
:class="mobileMenuOpen && '-translate-y-2 -rotate-45'"
|
|
/>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Mobile menu -->
|
|
<div
|
|
v-show="mobileMenuOpen"
|
|
id="site-mobile-menu"
|
|
class="border-t border-white/10 bg-black px-6 pb-6 md:hidden"
|
|
>
|
|
<div class="flex flex-col gap-4 pt-4">
|
|
<a
|
|
v-for="link in navLinks"
|
|
:key="link.href"
|
|
:href="link.href"
|
|
:aria-current="currentPath === link.href ? 'page' : undefined"
|
|
class="text-sm font-medium tracking-wide text-white transition-colors hover:text-brand-yellow"
|
|
@click="mobileMenuOpen = false"
|
|
>
|
|
{{ link.label }}
|
|
</a>
|
|
|
|
<div class="flex flex-col gap-3 pt-2">
|
|
<a
|
|
v-for="cta in ctaLinks"
|
|
:key="cta.href"
|
|
:href="cta.href"
|
|
:class="
|
|
cta.primary
|
|
? 'bg-brand-yellow text-black hover:opacity-90 transition-opacity'
|
|
: 'border border-brand-yellow text-brand-yellow hover:bg-brand-yellow hover:text-black transition-colors'
|
|
"
|
|
class="rounded-full px-5 py-2 text-center text-sm font-semibold"
|
|
>
|
|
{{ cta.label }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</template>
|