Spaces:
Runtime error
Runtime error
| import React, { useState, useEffect } from 'react'; | |
| import { Link, useLocation, Outlet } from 'react-router-dom'; | |
| import { Menu, X, ChevronRight, Twitter, Linkedin, Facebook, Youtube } from 'lucide-react'; | |
| const PublicLayout = ({ children }) => { | |
| const location = useLocation(); | |
| const [isScrolled, setIsScrolled] = useState(false); | |
| const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); | |
| useEffect(() => { | |
| const handleScroll = () => { | |
| setIsScrolled(window.scrollY > 20); | |
| }; | |
| window.addEventListener('scroll', handleScroll); | |
| return () => window.removeEventListener('scroll', handleScroll); | |
| }, []); | |
| const isActive = (path) => location.pathname === path; | |
| const navLinks = [ | |
| { path: '/', label: 'Home' }, | |
| { path: '/pricing', label: 'Pricing' }, | |
| { path: '/about', label: 'About' }, | |
| { path: '/contact', label: 'Contact' }, | |
| { path: '/blog', label: 'Blog' }, | |
| ]; | |
| return ( | |
| <div className="min-h-screen flex flex-col bg-secondary-50 dark:bg-secondary-950 transition-colors duration-300"> | |
| {/* Navigation */} | |
| <nav | |
| className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${isScrolled ? 'glass py-3' : 'bg-transparent py-5' | |
| }`} | |
| > | |
| <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div className="flex items-center justify-between"> | |
| {/* Logo */} | |
| <Link to="/" className="flex items-center gap-2 group"> | |
| <div className="w-10 h-10 rounded-xl bg-gradient-to-br from-primary-500 to-accent-500 flex items-center justify-center text-white font-bold text-xl shadow-lg group-hover:scale-105 transition-transform"> | |
| CA | |
| </div> | |
| <span className="font-bold text-xl text-secondary-900 dark:text-white tracking-tight"> | |
| Customer<span className="text-primary-600">Agent</span> | |
| </span> | |
| </Link> | |
| {/* Desktop Navigation */} | |
| <div className="hidden md:flex items-center gap-8"> | |
| {navLinks.map((link) => ( | |
| <Link | |
| key={link.path} | |
| to={link.path} | |
| className={`text-sm font-medium transition-colors hover:text-primary-600 ${isActive(link.path) | |
| ? 'text-primary-600' | |
| : 'text-secondary-600 dark:text-secondary-300' | |
| }`} | |
| > | |
| {link.label} | |
| </Link> | |
| ))} | |
| <div className="flex items-center gap-4"> | |
| <Link | |
| to="/login" | |
| className="text-sm font-medium text-secondary-600 dark:text-secondary-300 hover:text-primary-600 transition-colors" | |
| > | |
| Log In | |
| </Link> | |
| <Link | |
| to="/register" | |
| className="px-5 py-2.5 rounded-lg bg-primary-600 text-white text-sm font-semibold shadow-lg shadow-primary-500/30 hover:bg-primary-700 hover:-translate-y-0.5 transition-all" | |
| > | |
| Start Free Trial | |
| </Link> | |
| </div> | |
| </div> | |
| {/* Mobile Menu Button */} | |
| <button | |
| className="md:hidden p-2 text-secondary-600 dark:text-secondary-300" | |
| onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)} | |
| > | |
| {isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />} | |
| </button> | |
| </div> | |
| </div> | |
| {/* Mobile Menu */} | |
| {isMobileMenuOpen && ( | |
| <div className="md:hidden absolute top-full left-0 right-0 bg-white dark:bg-secondary-900 border-b border-secondary-200 dark:border-secondary-800 shadow-xl animate-fade-in"> | |
| <div className="px-4 py-6 space-y-4"> | |
| {navLinks.map((link) => ( | |
| <Link | |
| key={link.path} | |
| to={link.path} | |
| className={`block text-base font-medium ${isActive(link.path) | |
| ? 'text-primary-600' | |
| : 'text-secondary-600 dark:text-secondary-300' | |
| }`} | |
| onClick={() => setIsMobileMenuOpen(false)} | |
| > | |
| {link.label} | |
| </Link> | |
| ))} | |
| <div className="pt-4 border-t border-secondary-200 dark:border-secondary-800 flex flex-col gap-4"> | |
| <Link | |
| to="/login" | |
| className="text-center text-secondary-600 dark:text-secondary-300 font-medium" | |
| onClick={() => setIsMobileMenuOpen(false)} | |
| > | |
| Log In | |
| </Link> | |
| <Link | |
| to="/register" | |
| className="block text-center px-5 py-3 rounded-lg bg-primary-600 text-white font-semibold" | |
| onClick={() => setIsMobileMenuOpen(false)} | |
| > | |
| Start Free Trial | |
| </Link> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| </nav> | |
| {/* Main Content */} | |
| <main className="flex-grow pt-20"> | |
| <Outlet /> | |
| </main> | |
| {/* Footer */} | |
| <footer className="bg-white dark:bg-secondary-900 border-t border-secondary-200 dark:border-secondary-800 pt-16 pb-8"> | |
| <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-12 mb-12"> | |
| <div className="space-y-4"> | |
| <div className="flex items-center gap-2"> | |
| <div className="w-8 h-8 rounded-lg bg-gradient-to-br from-primary-500 to-accent-500 flex items-center justify-center text-white font-bold text-lg"> | |
| CA | |
| </div> | |
| <span className="font-bold text-lg text-secondary-900 dark:text-white"> | |
| CustomerAgent | |
| </span> | |
| </div> | |
| <p className="text-secondary-500 dark:text-secondary-400 text-sm leading-relaxed"> | |
| AI-powered customer support platform that helps businesses deliver exceptional experiences at scale. | |
| </p> | |
| <div className="flex gap-4"> | |
| {[Twitter, Linkedin, Facebook, Youtube].map((Icon, i) => ( | |
| <a key={i} href="#" className="text-secondary-400 hover:text-primary-500 transition-colors"> | |
| <Icon size={20} /> | |
| </a> | |
| ))} | |
| </div> | |
| </div> | |
| <div> | |
| <h4 className="font-semibold text-secondary-900 dark:text-white mb-6">Product</h4> | |
| <ul className="space-y-3"> | |
| {['Features', 'Pricing', 'Integrations', 'Enterprise', 'Changelog'].map((item) => ( | |
| <li key={item}> | |
| <Link to={`/${item.toLowerCase()}`} className="text-secondary-500 dark:text-secondary-400 hover:text-primary-600 text-sm transition-colors"> | |
| {item} | |
| </Link> | |
| </li> | |
| ))} | |
| </ul> | |
| </div> | |
| <div> | |
| <h4 className="font-semibold text-secondary-900 dark:text-white mb-6">Resources</h4> | |
| <ul className="space-y-3"> | |
| {[ | |
| { name: 'Documentation', path: '/docs' }, | |
| { name: 'API Reference', path: '/api' }, | |
| { name: 'Blog', path: '/blog' }, | |
| { name: 'Community', path: '/community' }, | |
| { name: 'Help Center', path: '/help-center' } | |
| ].map((item) => ( | |
| <li key={item.name}> | |
| <Link to={item.path} className="text-secondary-500 dark:text-secondary-400 hover:text-primary-600 text-sm transition-colors"> | |
| {item.name} | |
| </Link> | |
| </li> | |
| ))} | |
| </ul> | |
| </div> | |
| <div> | |
| <h4 className="font-semibold text-secondary-900 dark:text-white mb-6">Legal</h4> | |
| <ul className="space-y-3"> | |
| {[ | |
| { name: 'Privacy Policy', path: '/privacy' }, | |
| { name: 'Terms of Service', path: '/terms' }, | |
| { name: 'Cookie Policy', path: '/cookie-policy' }, | |
| { name: 'GDPR', path: '/gdpr' }, | |
| { name: 'Security', path: '/security' } | |
| ].map((item) => ( | |
| <li key={item.name}> | |
| <Link to={item.path} className="text-secondary-500 dark:text-secondary-400 hover:text-primary-600 text-sm transition-colors"> | |
| {item.name} | |
| </Link> | |
| </li> | |
| ))} | |
| </ul> | |
| </div> | |
| </div> | |
| <div className="pt-8 border-t border-secondary-200 dark:border-secondary-800 flex flex-col md:flex-row justify-between items-center gap-4"> | |
| <p className="text-secondary-400 text-sm"> | |
| © {new Date().getFullYear()} CustomerAgent. All rights reserved. | |
| </p> | |
| <div className="flex items-center gap-6"> | |
| <span className="flex items-center gap-2 text-sm text-secondary-500"> | |
| <span className="w-2 h-2 rounded-full bg-green-500"></span> | |
| All systems operational | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| </footer> | |
| </div> | |
| ); | |
| }; | |
| export default PublicLayout; | |