5 changed files with 212 additions and 7 deletions
@ -0,0 +1,8 @@ |
|||
{ |
|||
"recommendations": [ |
|||
"bradlc.vscode-tailwindcss", |
|||
"ms-vscode.vscode-typescript-next", |
|||
"esbenp.prettier-vscode", |
|||
"ms-vscode.vscode-eslint" |
|||
] |
|||
} |
@ -0,0 +1,26 @@ |
|||
{ |
|||
"tailwindCSS.includeLanguages": { |
|||
"typescript": "html", |
|||
"typescriptreact": "html", |
|||
"javascript": "html", |
|||
"javascriptreact": "html" |
|||
}, |
|||
"tailwindCSS.experimental.classRegex": [ |
|||
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], |
|||
["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"], |
|||
["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] |
|||
], |
|||
"tailwindCSS.validate": true, |
|||
"tailwindCSS.lint.cssConflict": "warning", |
|||
"tailwindCSS.lint.invalidApply": "error", |
|||
"tailwindCSS.lint.invalidConfigPath": "error", |
|||
"tailwindCSS.lint.invalidScreen": "error", |
|||
"tailwindCSS.lint.invalidTailwindDirective": "error", |
|||
"tailwindCSS.lint.invalidVariant": "error", |
|||
"tailwindCSS.lint.recommendedVariantOrder": "warning", |
|||
"editor.quickSuggestions": { |
|||
"strings": true |
|||
}, |
|||
"css.validate": false, |
|||
"scss.validate": false |
|||
} |
@ -0,0 +1,165 @@ |
|||
'use client'; |
|||
import { useState, useEffect } from 'react'; |
|||
import Link from 'next/link'; |
|||
import { usePathname } from 'next/navigation'; |
|||
import {getSiteInfo} from "@/api/layout"; |
|||
import {CmsWebsite} from "@/api/cms/cmsWebsite/model"; |
|||
|
|||
|
|||
const Header = () => { |
|||
const [config, setConfig] = useState<CmsWebsite>({}) |
|||
const [isMenuOpen, setIsMenuOpen] = useState(false); |
|||
const pathname = usePathname(); |
|||
|
|||
const navigation = [ |
|||
{ name: '首页', href: '/' }, |
|||
{ name: '产品', href: '/products' }, |
|||
{ name: '解决方案', href: '/solutions' }, |
|||
{ name: '案例', href: '/cases' }, |
|||
{ name: '关于', href: '/about' }, |
|||
{ name: '联系', href: '/contact' }, |
|||
]; |
|||
|
|||
const isActive = (href: string) => { |
|||
if (href === '/') { |
|||
return pathname === '/'; |
|||
} |
|||
return pathname.startsWith(href); |
|||
}; |
|||
|
|||
const reload = () => { |
|||
getSiteInfo().then(data => { |
|||
console.log(data,'data') |
|||
if(data){ |
|||
setConfig(data); |
|||
} |
|||
}) |
|||
} |
|||
|
|||
useEffect(() => { |
|||
reload(); |
|||
}, []); |
|||
|
|||
return ( |
|||
<header className="bg-white shadow-sm border-b border-gray-100 sticky top-0 z-50"> |
|||
<div className="container mx-auto px-4"> |
|||
<div className="flex items-center justify-between h-16"> |
|||
{/* Logo */} |
|||
<div className="flex-shrink-0"> |
|||
<Link href="/" className="text-xl font-bold text-gray-800"> |
|||
= {config?.websiteName} = |
|||
</Link> |
|||
</div> |
|||
|
|||
{/* Desktop Navigation */} |
|||
<nav className="hidden md:block"> |
|||
<div className="flex items-center space-x-8"> |
|||
{navigation.map((item) => ( |
|||
<Link |
|||
key={item.name} |
|||
href={item.href} |
|||
className={`text-sm font-medium transition-colors duration-300 ${ |
|||
isActive(item.href) |
|||
? 'text-blue-600' |
|||
: 'text-gray-700 hover:text-blue-600' |
|||
}`}
|
|||
> |
|||
{item.name} |
|||
</Link> |
|||
))} |
|||
</div> |
|||
</nav> |
|||
|
|||
{/* Language Switch & CTA */} |
|||
<div className="hidden md:flex items-center space-x-4"> |
|||
<div className="flex items-center space-x-2 text-sm text-gray-600"> |
|||
<span className="cursor-pointer hover:text-blue-600">中文</span> |
|||
<span>|</span> |
|||
<span className="cursor-pointer hover:text-blue-600">EN</span> |
|||
</div> |
|||
<Link href="/contact" className="btn btn-primary text-sm"> |
|||
免费咨询 |
|||
</Link> |
|||
</div> |
|||
|
|||
{/* Mobile menu button */} |
|||
<div className="md:hidden"> |
|||
<button |
|||
onClick={() => setIsMenuOpen(!isMenuOpen)} |
|||
className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500" |
|||
aria-expanded="false" |
|||
> |
|||
<span className="sr-only">打开主菜单</span> |
|||
{!isMenuOpen ? ( |
|||
<svg |
|||
className="block h-6 w-6" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
fill="none" |
|||
viewBox="0 0 24 24" |
|||
stroke="currentColor" |
|||
aria-hidden="true" |
|||
> |
|||
<path |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth={2} |
|||
d="M4 6h16M4 12h16M4 18h16" |
|||
/> |
|||
</svg> |
|||
) : ( |
|||
<svg |
|||
className="block h-6 w-6" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
fill="none" |
|||
viewBox="0 0 24 24" |
|||
stroke="currentColor" |
|||
aria-hidden="true" |
|||
> |
|||
<path |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
strokeWidth={2} |
|||
d="M6 18L18 6M6 6l12 12" |
|||
/> |
|||
</svg> |
|||
)} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
{/* Mobile Navigation */} |
|||
{isMenuOpen && ( |
|||
<div className="md:hidden"> |
|||
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3 bg-white border-t border-gray-200"> |
|||
{navigation.map((item) => ( |
|||
<Link |
|||
key={item.name} |
|||
href={item.href} |
|||
className={`block px-3 py-2 rounded-md text-base font-medium transition-colors duration-300 ${ |
|||
isActive(item.href) |
|||
? 'text-blue-600 bg-blue-50' |
|||
: 'text-gray-700 hover:text-blue-600 hover:bg-gray-50' |
|||
}`}
|
|||
onClick={() => setIsMenuOpen(false)} |
|||
> |
|||
{item.name} |
|||
</Link> |
|||
))} |
|||
<div className="px-3 py-2"> |
|||
<Link |
|||
href="/contact" |
|||
className="btn btn-primary w-full" |
|||
onClick={() => setIsMenuOpen(false)} |
|||
> |
|||
免费咨询 |
|||
</Link> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
)} |
|||
</div> |
|||
</header> |
|||
); |
|||
}; |
|||
|
|||
export default Header; |
@ -0,0 +1,12 @@ |
|||
/** @type {import('tailwindcss').Config} */ |
|||
module.exports = { |
|||
content: [ |
|||
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}', |
|||
'./src/components/**/*.{js,ts,jsx,tsx,mdx}', |
|||
'./src/app/**/*.{js,ts,jsx,tsx,mdx}', |
|||
], |
|||
theme: { |
|||
extend: {}, |
|||
}, |
|||
plugins: [], |
|||
} |
Loading…
Reference in new issue