385 lines
14 KiB
Plaintext
385 lines
14 KiB
Plaintext
---
|
|
import Footer from '../components/sections/Footer.astro';
|
|
import 'font-awesome/css/font-awesome.min.css';
|
|
|
|
const { title = "浙江贝凡网络科技", activeNav = "home" } = Astro.props;
|
|
|
|
interface NavChild {
|
|
id: string;
|
|
label: string;
|
|
href: string;
|
|
icon: string;
|
|
}
|
|
|
|
interface NavItem {
|
|
id: string;
|
|
label: string;
|
|
href: string;
|
|
icon: string;
|
|
children?: NavChild[];
|
|
}
|
|
|
|
const navItems: NavItem[] = [
|
|
{ id: 'home', label: '公司介绍', href: '/', icon: 'fa-building' },
|
|
{
|
|
id: 'products', label: '产品中心', href: '/qazk', icon: 'fa-cubes',
|
|
children: [
|
|
{ id: 'qazk', label: '工贸企业', href: '/qazk', icon: 'fa-cogs' },
|
|
{ id: 'property', label: '物业楼宇', href: '/property', icon: 'fa-building-o' },
|
|
{ id: 'elderly', label: '智慧养老', href: '/elderly', icon: 'fa-heartbeat' },
|
|
{ id: 'kitchen', label: '明厨亮灶', href: '/kitchen', icon: 'fa-cutlery' },
|
|
{ id: 'education', label: '智慧学校', href: '/education', icon: 'fa-graduation-cap' },
|
|
{ id: 'construction', label: '智慧工地', href: '/construction', icon: 'fa-industry' },
|
|
{ id: 'chemical', label: '危险化学品', href: '/chemical', icon: 'fa-flask' },
|
|
{ id: 'fireworks', label: '烟花爆竹', href: '/fireworks', icon: 'fa-asterisk' },
|
|
{ id: 'mining', label: '非煤矿山', href: '/mining', icon: 'fa-cubes' },
|
|
]
|
|
},
|
|
{ id: 'customization', label: '本地化定制', href: '/customization', icon: 'fa-wrench' },
|
|
{ id: 'partnership', label: '生态合作', href: '/partnership', icon: 'fa-handshake-o' },
|
|
];
|
|
|
|
function isActive(item: NavItem): boolean {
|
|
if (item.id === activeNav) return true;
|
|
if (item.children) return item.children.some(child => child.id === activeNav);
|
|
return false;
|
|
}
|
|
|
|
function getNavLinkClass(item: NavItem) {
|
|
const baseClass = 'flex items-center gap-2 px-4 py-2.5 rounded-full font-medium transition-all duration-300';
|
|
if (isActive(item)) {
|
|
return `${baseClass} bg-primary text-white shadow-md`;
|
|
}
|
|
return `${baseClass} text-gray-600 hover:text-primary hover:bg-primary/10`;
|
|
}
|
|
|
|
function getMobileNavLinkClass(item: NavItem) {
|
|
const baseClass = 'flex flex-col items-center justify-center py-2 px-2 min-w-[4.5rem] rounded-xl transition-all duration-300';
|
|
if (isActive(item)) {
|
|
return `${baseClass} bg-primary text-white`;
|
|
}
|
|
return `${baseClass} text-gray-600 hover:bg-primary/10`;
|
|
}
|
|
---
|
|
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{title}</title>
|
|
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
|
</head>
|
|
<body class="font-inter text-dark bg-slate-50">
|
|
<header id="navbar" class="fixed w-full top-0 z-50 transition-all duration-300 bg-white/95 backdrop-blur-md shadow-lg border-b border-gray-100">
|
|
<div class="max-w-7xl mx-auto px-4 lg:px-0 py-3 flex items-center justify-between hidden lg:flex">
|
|
<a href="/" class="flex items-center space-x-3">
|
|
<img src="/img/logo.png" alt="浙江贝凡 Logo" class="h-8 w-auto">
|
|
</a>
|
|
<nav class="hidden lg:flex items-center gap-3">
|
|
{
|
|
navItems.map(item => item.children ? (
|
|
<div class="relative" data-dropdown>
|
|
<button type="button" class={`${getNavLinkClass(item)} cursor-pointer`}
|
|
aria-haspopup="true" aria-expanded="false" data-dropdown-trigger>
|
|
<i class={`fa ${item.icon}`}></i>
|
|
<span>{item.label}</span>
|
|
<i class="fa fa-angle-down text-xs ml-0.5 transition-transform duration-200" data-dropdown-chevron></i>
|
|
</button>
|
|
<div class="absolute top-full left-1/2 -translate-x-1/2 pt-2 opacity-0 invisible transition-all duration-200 z-50"
|
|
data-dropdown-panel role="menu">
|
|
<div class="bg-white rounded-2xl shadow-xl border border-gray-100 p-3 w-[600px]">
|
|
<div class="grid grid-cols-3 gap-2">
|
|
{item.children.map(child => (
|
|
<a href={child.href} role="menuitem"
|
|
class={`group flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all ${
|
|
child.id === activeNav
|
|
? 'bg-primary text-white'
|
|
: 'text-gray-700 hover:bg-primary/10 hover:text-primary'
|
|
}`}>
|
|
<span class={`w-9 h-9 rounded-lg flex items-center justify-center shrink-0 ${
|
|
child.id === activeNav
|
|
? 'bg-white/20 text-white'
|
|
: 'bg-primary/10 text-primary group-hover:bg-primary group-hover:text-white'
|
|
}`}>
|
|
<i class={`fa ${child.icon} text-base`}></i>
|
|
</span>
|
|
<span class="text-sm font-semibold whitespace-nowrap">{child.label}</span>
|
|
</a>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<a href={item.href} class={getNavLinkClass(item)}>
|
|
<i class={`fa ${item.icon}`}></i>
|
|
<span>{item.label}</span>
|
|
</a>
|
|
))
|
|
}
|
|
</nav>
|
|
<a href="/#contact-info" class="hidden lg:flex items-center gap-2 bg-primary hover:bg-blue-600 text-white px-5 py-2.5 rounded-full font-bold transition-all duration-300 shadow-lg hover:shadow-xl">
|
|
<i class="fa fa-phone"></i>
|
|
<span>立即咨询</span>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Mobile Header - First Row -->
|
|
<div id="mobile-header-row" class="lg:hidden flex items-center justify-between px-4 py-3 bg-white border-b border-gray-100">
|
|
<a href="/" class="flex items-center space-x-2">
|
|
<img src="/img/logo.png" alt="浙江贝凡 Logo" class="h-6 w-auto">
|
|
</a>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Mobile Navigation Row - Separate from header -->
|
|
<div id="mobile-nav-container" class="lg:hidden fixed left-0 right-0 z-40 bg-gray-50 border-b border-gray-200 transition-all duration-300" style="top: 60px;">
|
|
<div class="flex items-center justify-between px-2 py-2">
|
|
<div class="flex items-center gap-1 overflow-x-auto no-scrollbar">
|
|
{
|
|
navItems.map(item => item.children ? (
|
|
<button type="button"
|
|
class={getMobileNavLinkClass(item)}
|
|
aria-haspopup="true" aria-expanded="false"
|
|
data-mobile-dropdown-trigger>
|
|
<i class={`fa ${item.icon} text-lg mb-1`}></i>
|
|
<span class="text-xs font-medium whitespace-nowrap">{item.label}</span>
|
|
</button>
|
|
) : (
|
|
<a href={item.href} class={getMobileNavLinkClass(item)}>
|
|
<i class={`fa ${item.icon} text-lg mb-1`}></i>
|
|
<span class="text-xs font-medium whitespace-nowrap">{item.label}</span>
|
|
</a>
|
|
))
|
|
}
|
|
</div>
|
|
<a href="/#contact-info" class="flex items-center justify-center py-2 px-3 bg-primary text-white rounded-xl min-w-[3rem] ml-1">
|
|
<i class="fa fa-phone text-lg"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile Product Panel -->
|
|
<div id="mobile-product-panel"
|
|
class="lg:hidden fixed left-0 right-0 z-30 bg-white shadow-xl border-b border-gray-200 transform -translate-y-full opacity-0 pointer-events-none transition-all duration-300"
|
|
style="top: 108px;" role="menu">
|
|
<div class="max-w-md mx-auto px-3 py-3 grid grid-cols-3 gap-2">
|
|
{navItems.find(item => item.children)?.children?.map(child => (
|
|
<a href={child.href} role="menuitem"
|
|
class={`flex flex-col items-center gap-1.5 py-2.5 px-1 rounded-xl transition-colors ${
|
|
child.id === activeNav
|
|
? 'bg-primary text-white'
|
|
: 'bg-primary/5 text-gray-700 hover:bg-primary/10'
|
|
}`}>
|
|
<i class={`fa ${child.icon} text-lg ${child.id === activeNav ? 'text-white' : 'text-primary'}`}></i>
|
|
<span class={`text-[11px] font-semibold leading-tight text-center whitespace-nowrap ${child.id === activeNav ? 'text-white' : 'text-gray-700'}`}>{child.label}</span>
|
|
</a>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile Product Backdrop -->
|
|
<div id="mobile-product-backdrop"
|
|
class="lg:hidden fixed inset-0 z-20 bg-black/20 opacity-0 pointer-events-none transition-opacity duration-300"></div>
|
|
|
|
<!-- Spacer for mobile to prevent content overlap (header 3.5rem + nav 2.5rem) -->
|
|
<div class="lg:hidden h-[6rem] transition-all duration-300"></div>
|
|
|
|
<slot />
|
|
<Footer />
|
|
|
|
<button id="back-to-top" class="fixed bottom-8 right-8 w-12 h-12 bg-primary rounded-full flex items-center justify-center text-white shadow-lg opacity-0 invisible transition-all duration-300 hover:bg-primary/90 z-50">
|
|
<i class="fa fa-arrow-up"></i>
|
|
</button>
|
|
|
|
<script is:inline src="/js/script.js"></script>
|
|
<script>
|
|
// Mobile navigation scroll behavior
|
|
(function() {
|
|
var navContainer = document.getElementById('mobile-nav-container');
|
|
var headerRow = document.getElementById('mobile-header-row');
|
|
var spacer = document.querySelector('.lg\\:hidden.h-\\[6rem\\]');
|
|
var lastScrollTop = 0;
|
|
var scrollThreshold = 50;
|
|
|
|
// Set correct top position based on actual header height
|
|
function updateNavPosition() {
|
|
if (headerRow && navContainer && window.innerWidth < 1024) {
|
|
var headerHeight = headerRow.getBoundingClientRect().height;
|
|
navContainer.style.top = headerHeight + 'px';
|
|
}
|
|
}
|
|
|
|
// Update on load and resize
|
|
updateNavPosition();
|
|
window.addEventListener('resize', updateNavPosition);
|
|
window.addEventListener('load', updateNavPosition);
|
|
|
|
window.addEventListener('scroll', function() {
|
|
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
|
|
// Only apply on mobile
|
|
if (window.innerWidth >= 1024) return;
|
|
|
|
if (scrollTop > lastScrollTop && scrollTop > scrollThreshold) {
|
|
// Scrolling down - hide second row
|
|
if (navContainer) {
|
|
navContainer.style.transform = 'translateY(-100%)';
|
|
navContainer.style.opacity = '0';
|
|
}
|
|
// Reduce spacer height
|
|
if (spacer) {
|
|
(spacer as HTMLElement).style.height = '3.5rem';
|
|
}
|
|
} else {
|
|
// Scrolling up - show second row
|
|
if (navContainer) {
|
|
navContainer.style.transform = 'translateY(0)';
|
|
navContainer.style.opacity = '1';
|
|
}
|
|
// Restore spacer height
|
|
if (spacer) {
|
|
(spacer as HTMLElement).style.height = '6rem';
|
|
}
|
|
}
|
|
|
|
lastScrollTop = scrollTop;
|
|
}, { passive: true });
|
|
})();
|
|
|
|
// Desktop dropdown hover + keyboard navigation
|
|
(function() {
|
|
var dropdown = document.querySelector('[data-dropdown]');
|
|
if (!dropdown) return;
|
|
|
|
var trigger = dropdown.querySelector('[data-dropdown-trigger]') as HTMLElement;
|
|
var panel = dropdown.querySelector('[data-dropdown-panel]') as HTMLElement;
|
|
var chevron = dropdown.querySelector('[data-dropdown-chevron]') as HTMLElement;
|
|
var menuItems = panel.querySelectorAll('[role="menuitem"]') as NodeListOf<HTMLElement>;
|
|
|
|
function openPanel() {
|
|
trigger.setAttribute('aria-expanded', 'true');
|
|
panel.classList.remove('opacity-0', 'invisible');
|
|
panel.classList.add('opacity-100', 'visible');
|
|
if (chevron) chevron.style.transform = 'rotate(180deg)';
|
|
}
|
|
|
|
function closePanel() {
|
|
trigger.setAttribute('aria-expanded', 'false');
|
|
panel.classList.add('opacity-0', 'invisible');
|
|
panel.classList.remove('opacity-100', 'visible');
|
|
if (chevron) chevron.style.transform = '';
|
|
}
|
|
|
|
// Click to toggle
|
|
trigger.addEventListener('click', function(e: Event) {
|
|
e.preventDefault();
|
|
if (trigger.getAttribute('aria-expanded') === 'true') {
|
|
closePanel();
|
|
} else {
|
|
openPanel();
|
|
}
|
|
});
|
|
|
|
// Keyboard
|
|
trigger.addEventListener('keydown', function(e: KeyboardEvent) {
|
|
if (e.key === 'ArrowDown') {
|
|
e.preventDefault();
|
|
openPanel();
|
|
menuItems[0]?.focus();
|
|
}
|
|
if (e.key === 'Escape') {
|
|
closePanel();
|
|
trigger.focus();
|
|
}
|
|
});
|
|
|
|
panel.addEventListener('keydown', function(e: KeyboardEvent) {
|
|
var items = Array.from(menuItems);
|
|
var idx = items.indexOf(document.activeElement as HTMLElement);
|
|
if (e.key === 'ArrowDown') {
|
|
e.preventDefault();
|
|
items[(idx + 1) % items.length].focus();
|
|
} else if (e.key === 'ArrowUp') {
|
|
e.preventDefault();
|
|
items[(idx - 1 + items.length) % items.length].focus();
|
|
} else if (e.key === 'Escape') {
|
|
closePanel();
|
|
trigger.focus();
|
|
}
|
|
});
|
|
|
|
document.addEventListener('click', function(e) {
|
|
if (!(dropdown as HTMLElement).contains(e.target as Node)) {
|
|
closePanel();
|
|
}
|
|
});
|
|
})();
|
|
|
|
// Mobile product dropdown
|
|
(function() {
|
|
var trigger = document.querySelector('[data-mobile-dropdown-trigger]') as HTMLElement;
|
|
var panel = document.getElementById('mobile-product-panel');
|
|
var backdrop = document.getElementById('mobile-product-backdrop');
|
|
if (!trigger || !panel) return;
|
|
|
|
var isOpen = false;
|
|
|
|
function updatePanelPosition() {
|
|
var navContainer = document.getElementById('mobile-nav-container');
|
|
if (navContainer && panel) {
|
|
var rect = navContainer.getBoundingClientRect();
|
|
panel.style.top = (rect.bottom) + 'px';
|
|
}
|
|
}
|
|
|
|
function openPanel() {
|
|
isOpen = true;
|
|
updatePanelPosition();
|
|
trigger.setAttribute('aria-expanded', 'true');
|
|
panel!.classList.remove('-translate-y-full', 'opacity-0', 'pointer-events-none');
|
|
panel!.classList.add('translate-y-0', 'opacity-100', 'pointer-events-auto');
|
|
if (backdrop) {
|
|
backdrop.classList.remove('opacity-0', 'pointer-events-none');
|
|
backdrop.classList.add('opacity-100', 'pointer-events-auto');
|
|
}
|
|
}
|
|
|
|
function closePanel() {
|
|
isOpen = false;
|
|
trigger.setAttribute('aria-expanded', 'false');
|
|
panel!.classList.add('-translate-y-full', 'opacity-0', 'pointer-events-none');
|
|
panel!.classList.remove('translate-y-0', 'opacity-100', 'pointer-events-auto');
|
|
if (backdrop) {
|
|
backdrop.classList.add('opacity-0', 'pointer-events-none');
|
|
backdrop.classList.remove('opacity-100', 'pointer-events-auto');
|
|
}
|
|
}
|
|
|
|
trigger.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
isOpen ? closePanel() : openPanel();
|
|
});
|
|
|
|
if (backdrop) {
|
|
backdrop.addEventListener('click', closePanel);
|
|
}
|
|
|
|
window.addEventListener('scroll', function() {
|
|
if (isOpen && window.innerWidth < 1024) closePanel();
|
|
}, { passive: true });
|
|
})();
|
|
</script>
|
|
|
|
<style>
|
|
.no-scrollbar {
|
|
-ms-overflow-style: none;
|
|
scrollbar-width: none;
|
|
}
|
|
.no-scrollbar::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
</style>
|
|
</body>
|
|
</html>
|