CloudBridge/components/AppHeader.vue
2025-09-04 18:01:27 +08:00

142 lines
4.8 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<header class="bg-white shadow-sm border-b border-gray-200">
<div class="container-custom">
<div class="flex items-center justify-between h-16">
<!-- Logo -->
<NuxtLink to="/" class="flex items-center space-x-2">
<div class="w-8 h-8 bg-aws-orange rounded-lg flex items-center justify-center">
<span class="text-white font-bold text-lg">C</span>
</div>
<span class="text-xl font-bold text-gray-900">CloudBridge</span>
</NuxtLink>
<!-- Desktop Navigation -->
<nav class="hidden md:flex items-center space-x-8">
<NuxtLink
v-for="item in navItems"
:key="item.key"
:to="item.to"
class="text-gray-700 hover:text-aws-orange font-medium transition-colors duration-200"
>
{{ item.label }}
</NuxtLink>
</nav>
<!-- Right side actions -->
<div class="flex items-center space-x-4">
<!-- Language Switcher -->
<div class="relative">
<select
v-model="currentLocale"
@change="switchLanguage"
class="appearance-none bg-white border border-gray-300 rounded-md px-3 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-aws-orange focus:border-transparent"
>
<option v-for="locale in locales" :key="locale.code" :value="locale.code">
{{ locale.name }}
</option>
</select>
</div>
<!-- Social Links -->
<div class="flex items-center space-x-3">
<a
href="https://t.me/pinnovatecloud"
target="_blank"
rel="noopener noreferrer"
class="text-gray-600 hover:text-aws-orange transition-colors duration-200"
:title="$t('contact.telegram')"
>
<MessageCircle class="w-5 h-5" />
</a>
<a
href="https://wa.me/19174029875"
target="_blank"
rel="noopener noreferrer"
class="text-gray-600 hover:text-aws-orange transition-colors duration-200"
:title="$t('contact.whatsapp')"
>
<Phone class="w-5 h-5" />
</a>
<span class="text-sm text-gray-500">+1 9174029875</span>
</div>
<!-- Mobile menu button -->
<button
@click="mobileMenuOpen = !mobileMenuOpen"
class="md:hidden p-2 rounded-md text-gray-600 hover:text-aws-orange hover:bg-gray-100"
>
<Menu v-if="!mobileMenuOpen" class="w-6 h-6" />
<X v-else class="w-6 h-6" />
</button>
</div>
</div>
<!-- Mobile Navigation -->
<div v-if="mobileMenuOpen" class="md:hidden border-t border-gray-200 py-4">
<nav class="flex flex-col space-y-4">
<NuxtLink
v-for="item in navItems"
:key="item.key"
:to="item.to"
@click="mobileMenuOpen = false"
class="text-gray-700 hover:text-aws-orange font-medium py-2"
>
{{ item.label }}
</NuxtLink>
</nav>
</div>
</div>
</header>
</template>
<script setup>
import { MessageCircle, Phone, Menu, X } from 'lucide-vue-next'
const { t, locale, locales, setLocale } = useI18n()
const localePath = useLocalePath()
const switchLocalePath = useSwitchLocalePath()
const router = useRouter()
const mobileMenuOpen = ref(false)
const currentLocale = ref(locale.value)
const navItems = computed(() => [
{ key: 'home', label: t('nav.home'), to: localePath('/') },
{ key: 'services', label: t('nav.services'), to: localePath('/services') },
{ key: 'pricing', label: t('nav.pricing'), to: localePath('/pricing') },
{ key: 'blog', label: t('nav.blog'), to: localePath('/blog') },
{ key: 'contact', label: t('nav.contact'), to: localePath('/contact') }
])
const route = useRoute()
const switchLanguage = async () => {
const target = currentLocale.value
let path = switchLocalePath(target)
// 强力回退:若未返回路径,则拼接目标语言前缀到当前非语言前缀路径
if (!path) {
const withoutPrefix = route.fullPath.replace(/^\/(en|zh|zh-hant)(?=\/|$)/, '') || '/'
path = target === 'en' ? withoutPrefix : `/${target}${withoutPrefix}`
}
// 规范化默认语言en不应包含 /en 前缀strategy: prefix_except_default
if (path && /^\/en(\/|$)/.test(path)) {
path = path.replace(/^\/en(\/|$)/, '/').replace(/\/$/, '') || '/'
}
await router.push(path)
mobileMenuOpen.value = false
}
// Keep select value in sync when locale changes externally (e.g., via links)
watch(locale, (val) => {
currentLocale.value = val
})
// Close mobile menu when route changes
watch(() => useRoute().path, () => {
mobileMenuOpen.value = false
})
</script>