All files / components Header.tsx

84.21% Statements 32/38
55.55% Branches 30/54
83.33% Functions 10/12
93.75% Lines 30/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232              1x 10x 10x 10x 10x     10x 4x 1x     4x 4x       10x 4x 4x 4x 3x 3x 3x 3x 3x       10x               10x 10x 10x 2x           8x               10x                                                             50x                                                                                   1x                                                                                 1x                               10x                                                                                
import React, { useState, useEffect } from 'react';
import { Link } from 'gatsby';
import { StaticImage } from 'gatsby-plugin-image';
import { useTheme } from '../context/ThemeContext';
import Search from './Search';
import ThemeToggle from './ThemeToggle';
 
const Header: React.FC = () => {
  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
  const [isScrolled, setIsScrolled] = useState(false);
  const [activeItem, setActiveItem] = useState('');
  const { theme } = useTheme();
  
  // Handle scroll effect
  useEffect(() => {
    const handleScroll = () => {
      setIsScrolled(window.scrollY > 10);
    };
    
    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);
 
  // Detect current page for navigation highlighting
  useEffect(() => {
    Eif (typeof window !== 'undefined') {
      const path = window.location.pathname;
      if (path.includes('/docs')) setActiveItem('docs');
      else Iif (path.includes('/guides')) setActiveItem('guides');
      else Iif (path.includes('/examples')) setActiveItem('examples');
      else Iif (path.includes('/playground')) setActiveItem('playground');
      else Iif (path.includes('/api-reference')) setActiveItem('api');
      else setActiveItem('');
    }
  }, []);
 
  const navItems = [
    { label: 'Documentation', path: '/docs', id: 'docs' },
    { label: 'Guides', path: '/guides', id: 'guides' },
    { label: 'Examples', path: '/examples', id: 'examples' },
    { label: 'Playground', path: '/playground', id: 'playground' },
    { label: 'API', path: '/api-reference', id: 'api' }
  ];
 
  const getHeaderClasses = () => {
    const baseClasses = 'fixed w-full z-50 transition-all duration-300';
    if (isScrolled) {
      return `${baseClasses} ${
        theme === 'dark' 
          ? 'bg-slate-900/90 backdrop-blur-md shadow-lg shadow-black/10' 
          : 'bg-white/90 backdrop-blur-md shadow-lg shadow-black/5'
      }`;
    } else {
      return `${baseClasses} ${
        theme === 'dark'
          ? 'bg-transparent'
          : 'bg-transparent'
      }`;
    }
  };
 
  return (
    <header className={getHeaderClasses()}>
      <div className="container mx-auto px-4 py-3 flex justify-between items-center">
        <Link 
          to="/" 
          className="flex items-center space-x-3 transition-all duration-300 hover:scale-105"
          aria-label="Neo Rust SDK Home"
        >
          <div className="w-10 h-10 relative rounded-full bg-gradient-to-br from-green-400 to-teal-500 p-0.5 flex items-center justify-center">
            <StaticImage 
              src="../images/neo-logo.svg" 
              alt="Neo Logo" 
              width={32} 
              height={32}
              placeholder="blurred"
              className="rounded-full filter hover:brightness-110 transition"
            />
          </div>
          <span className={`text-2xl font-bold ${
            theme === 'dark' 
              ? 'text-white' 
              : 'text-gray-900'
          }`}>
            <span className={theme === 'dark' ? 'text-white' : 'text-gray-900'}>Neo</span>
            <span className={theme === 'dark' ? 'text-green-400' : 'text-green-600'}>Rust</span>
          </span>
        </Link>
        
        <nav className="hidden md:flex items-center space-x-1">
          <div className="flex items-center">
            {navItems.map((item) => (
              <Link 
                key={item.id}
                to={item.path} 
                className={`px-4 py-2 rounded-lg transition-all duration-300 ${
                  activeItem === item.id
                    ? theme === 'dark'
                      ? 'text-green-400 bg-green-900/20'
                      : 'text-green-600 bg-green-100'
                    : theme === 'dark'
                      ? 'text-gray-300 hover:text-white hover:bg-white/5'
                      : 'text-gray-700 hover:text-gray-900 hover:bg-gray-100'
                }`}
              >
                {item.label}
              </Link>
            ))}
          </div>
          <div className="ml-2 flex items-center space-x-3">
            <Search />
            <ThemeToggle />
            <a 
              href="https://github.com/R3E-Network/NeoRust" 
              target="_blank" 
              rel="noopener noreferrer" 
              className={`p-2 rounded-lg transition-all duration-300 hover:bg-white/5 ${
                theme === 'dark' ? 'text-gray-300 hover:text-white' : 'text-gray-600 hover:text-gray-900'
              }`}
              aria-label="GitHub Repository"
            >
              <svg className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
                <path fillRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clipRule="evenodd"></path>
              </svg>
            </a>
          </div>
        </nav>
        
        <div className="flex items-center space-x-4 md:hidden">
          <ThemeToggle />
          <button 
            className={`p-2 rounded-lg transition-all duration-300 hover:bg-white/5 ${
              theme === 'dark' ? 'text-gray-300 hover:text-white' : 'text-gray-700 hover:text-gray-900'
            }`}
            onClick={() => setIsMobileMenuOpen(true)}
            aria-label="Open menu"
            aria-expanded={isMobileMenuOpen}
          >
            <svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16"></path>
            </svg>
          </button>
        </div>
      </div>
 
      {/* Mobile menu */}
      {isMobileMenuOpen && (
        <div className={`fixed inset-0 z-50 animate-fade-in ${theme === 'dark' ? 'bg-slate-900' : 'bg-white'}`}>
          <div className="container mx-auto px-4 py-4">
            <div className="flex justify-between items-center mb-8">
              <Link 
                to="/" 
                className="flex items-center space-x-3"
                onClick={() => setIsMobileMenuOpen(false)}
              >
                <div className="w-10 h-10 relative rounded-full bg-gradient-to-br from-green-400 to-teal-500 p-0.5 flex items-center justify-center">
                  <StaticImage 
                    src="../images/neo-logo.svg" 
                    alt="Neo Logo" 
                    width={32} 
                    height={32}
                    placeholder="blurred"
                    className="rounded-full"
                  />
                </div>
                <span className={`text-2xl font-bold ${
                  theme === 'dark' 
                    ? 'text-white' 
                    : 'text-gray-900'
                }`}>
                  <span className={theme === 'dark' ? 'text-white' : 'text-gray-900'}>Neo</span>
                  <span className={theme === 'dark' ? 'text-green-400' : 'text-green-600'}>Rust</span>
                </span>
              </Link>
              <button 
                onClick={() => setIsMobileMenuOpen(false)}
                className={`p-2 rounded-lg transition-all duration-300 hover:bg-white/5 ${
                  theme === 'dark' ? 'text-gray-300 hover:text-white' : 'text-gray-700 hover:text-gray-900'
                }`}
                aria-label="Close menu"
              >
                <svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path>
                </svg>
              </button>
            </div>
            <div className="px-4 py-2 mb-8">
              <Search placeholder="Search..." />
            </div>
            <nav className="flex flex-col space-y-3 text-xl">
              {navItems.map((item, index) => (
                <Link 
                  key={item.id}
                  to={item.path} 
                  className={`px-4 py-3 rounded-lg transition-all duration-300 animate-fade-in-up ${
                    activeItem === item.id
                      ? theme === 'dark'
                        ? 'text-green-400 bg-green-900/20'
                        : 'text-green-600 bg-green-100'
                      : theme === 'dark'
                        ? 'text-gray-300 hover:text-white hover:bg-white/5'
                        : 'text-gray-700 hover:text-gray-900 hover:bg-gray-100'
                  }`}
                  onClick={() => setIsMobileMenuOpen(false)}
                  style={{ animationDelay: `${index * 50 + 100}ms` }}
                >
                  {item.label}
                </Link>
              ))}
              <a 
                href="https://github.com/R3E-Network/NeoRust" 
                target="_blank" 
                rel="noopener noreferrer" 
                className={`mt-6 flex items-center space-x-3 px-4 py-3 rounded-lg transition-all duration-300 animate-fade-in-up hover:bg-white/5 ${
                  theme === 'dark' ? 'text-gray-300 hover:text-white' : 'text-gray-600 hover:text-gray-900'
                }`}
                style={{ animationDelay: '350ms' }}
              >
                <svg className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
                  <path fillRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clipRule="evenodd"></path>
                </svg>
                <span>GitHub Repository</span>
              </a>
            </nav>
          </div>
        </div>
      )}
    </header>
  );
};
 
export default Header;