| class CustomNavbar extends HTMLElement { |
| connectedCallback() { |
| this.attachShadow({ mode: 'open' }); |
| this.shadowRoot.innerHTML = ` |
| <style> |
| .nav-link { |
| position: relative; |
| } |
| .nav-link::after { |
| content: ''; |
| position: absolute; |
| bottom: -2px; |
| left: 0; |
| width: 0; |
| height: 2px; |
| background-color: #7c3aed; |
| transition: width 0.3s ease; |
| } |
| .nav-link:hover::after { |
| width: 100%; |
| } |
| </style> |
| <nav class="bg-gray-800 border-b border-gray-700"> |
| <div class="container mx-auto px-4"> |
| <div class="flex justify-between items-center py-4"> |
| <a href="/" class="flex items-center space-x-2"> |
| <span class="text-2xl font-bold bg-gradient-to-r from-primary-500 to-secondary-500 bg-clip-text text-transparent">ShadowStack</span> |
| </a> |
| |
| <div class="hidden md:flex items-center space-x-8"> |
| <a href="/" class="nav-link text-gray-300 hover:text-white">Home</a> |
| <a href="/services" class="nav-link text-gray-300 hover:text-white">Services</a> |
| <a href="/projects" class="nav-link text-gray-300 hover:text-white">Projects</a> |
| <a href="/about" class="nav-link text-gray-300 hover:text-white">About</a> |
| <a href="/contact" class="nav-link text-gray-300 hover:text-white">Contact</a> |
| |
| <button id="themeToggle" class="p-2 rounded-full hover:bg-gray-700"> |
| <i data-feather="moon" class="text-gray-300"></i> |
| </button> |
| </div> |
| |
| <button class="md:hidden p-2 rounded-full hover:bg-gray-700" id="mobileMenuButton"> |
| <i data-feather="menu" class="text-gray-300"></i> |
| </button> |
| </div> |
| |
| <!-- Mobile menu --> |
| <div class="md:hidden hidden py-4 border-t border-gray-700" id="mobileMenu"> |
| <div class="flex flex-col space-y-4"> |
| <a href="/" class="text-gray-300 hover:text-white">Home</a> |
| <a href="/services" class="text-gray-300 hover:text-white">Services</a> |
| <a href="/projects" class="text-gray-300 hover:text-white">Projects</a> |
| <a href="/about" class="text-gray-300 hover:text-white">About</a> |
| <a href="/contact" class="text-gray-300 hover:text-white">Contact</a> |
| |
| <div class="flex justify-between items-center pt-4 border-t border-gray-700"> |
| <span>Dark Mode</span> |
| <button id="mobileThemeToggle" class="p-2 rounded-full hover:bg-gray-700"> |
| <i data-feather="moon" class="text-gray-300"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
| </nav> |
| `; |
| |
| |
| setTimeout(() => { |
| const themeToggle = this.shadowRoot.getElementById('themeToggle'); |
| const mobileThemeToggle = this.shadowRoot.getElementById('mobileThemeToggle'); |
| const mobileMenuButton = this.shadowRoot.getElementById('mobileMenuButton'); |
| const mobileMenu = this.shadowRoot.getElementById('mobileMenu'); |
| |
| if (themeToggle) { |
| themeToggle.addEventListener('click', this.toggleTheme); |
| } |
| |
| if (mobileThemeToggle) { |
| mobileThemeToggle.addEventListener('click', this.toggleTheme); |
| } |
| |
| if (mobileMenuButton) { |
| mobileMenuButton.addEventListener('click', () => { |
| mobileMenu.classList.toggle('hidden'); |
| feather.replace(); |
| }); |
| } |
| }, 0); |
| } |
| |
| toggleTheme() { |
| const html = document.documentElement; |
| html.classList.toggle('dark'); |
| |
| |
| const isDark = html.classList.contains('dark'); |
| localStorage.setItem('darkMode', isDark); |
| |
| |
| const icons = this.shadowRoot.querySelectorAll('[data-feather]'); |
| icons.forEach(icon => { |
| if (icon.dataset.feather === 'moon' && !isDark) { |
| icon.dataset.feather = 'sun'; |
| } else if (icon.dataset.feather === 'sun' && isDark) { |
| icon.dataset.feather = 'moon'; |
| } |
| }); |
| feather.replace(); |
| } |
| } |
|
|
| customElements.define('custom-navbar', CustomNavbar); |