diff options
Diffstat (limited to 'src/components/NavBar.svelte')
| -rw-r--r-- | src/components/NavBar.svelte | 306 |
1 files changed, 273 insertions, 33 deletions
diff --git a/src/components/NavBar.svelte b/src/components/NavBar.svelte index 44118ba..2b64c88 100644 --- a/src/components/NavBar.svelte +++ b/src/components/NavBar.svelte @@ -1,34 +1,274 @@ -<nav class="navbar navbar-expand-md navbar-dark bg-dark"> - <div class="container"> - <a href="/" class="navbar-brand abs"> - <img height="100" src="/logo.png" alt="Misty Mountains Therapy"/> - </a> - <button class="navbar-toggler ms-auto" type="button" data-bs-toggle="collapse" data-bs-target="#toggle"> - <span class="navbar-toggler-icon"></span> - </button> - <div class="navbar-collapse collapse" id="toggle"> - <ul class="navbar-nav "> - <li class="nav-item active"> - <a class="nav-link" href="/">Home</a> - </li> - <li class="nav-item active"> - <a class="nav-link" href="/team">Our Team</a> - </li> - <li class="nav-item active"> - <a class="nav-link" href="/services">Services</a> - </li> - <li class="nav-item active"> - <a class="nav-link" href="/approach">Approach</a> - </li> - <li class="nav-item active"> - <a class="nav-link" href="https://joni-hunt.clientsecure.me/" target="_blank">Portal</a> - </li> - </ul> - <ul class="navbar-nav ms-auto"> - <li class="nav-item"> - <a class="btn btn-primary" href="/contact">Contact Us</a> - </li> - </ul> - </div> - </div> +<script> + import { resolveRoute } from '$app/paths'; + import { page } from '$app/stores'; + + let menuOpen = false; + const menuId = 'primary-navigation'; + let menuEl; + let toggleEl; + + const navLinks = [ + { href: '/', label: 'Home' }, + { href: '/team', label: 'Team' }, + { href: '/services', label: 'Services' }, + { href: '/approach', label: 'Approach' } + ]; + + function isActive(path, currentPath) { + if (path === '/') return currentPath === '/'; + return currentPath.startsWith(path); + } + + function onWindowPointerDown(event) { + if (!menuOpen) return; + const target = event.target; + if (menuEl?.contains(target) || toggleEl?.contains(target)) return; + closeMenu(); + } + + function toggleMenu() { + menuOpen = !menuOpen; + } + + function closeMenu() { + menuOpen = false; + } + + function onNavKeydown(event) { + if (event.key === 'Escape') { + menuOpen = false; + } + } +</script> + +<svelte:window on:keydown={onNavKeydown} on:pointerdown={onWindowPointerDown} /> + +{#if menuOpen} + <div class="site-nav__backdrop" aria-hidden="true" on:click={closeMenu}></div> +{/if} + +<nav class="site-nav" aria-label="Primary"> + <div class="container site-nav__inner"> + <a class="site-nav__brand" href={resolveRoute('/')} on:click={closeMenu}> + <img class="site-nav__logo" height="64" src="/logo.png" alt="Misty Mountains Therapy" /> + <span class="visually-hidden">Misty Mountains Therapy</span> + </a> + + <button + bind:this={toggleEl} + class="site-nav__toggle" + type="button" + aria-expanded={menuOpen} + aria-controls={menuId} + on:click={toggleMenu} + > + <span class="visually-hidden">{menuOpen ? 'Close menu' : 'Open menu'}</span> + <i class={'bi ' + (menuOpen ? 'bi-x-lg' : 'bi-list')} aria-hidden="true"></i> + </button> + + <div bind:this={menuEl} id={menuId} class="site-nav__menu" class:site-nav__menuOpen={menuOpen}> + <ul class="site-nav__links"> + {#each navLinks as link (link.href)} + <li> + <a + class="site-nav__link" + class:site-nav__link--active={isActive(link.href, $page.url.pathname)} + href={resolveRoute(link.href)} + aria-current={isActive(link.href, $page.url.pathname) ? 'page' : undefined} + on:click={closeMenu} + > + {link.label} + </a> + </li> + {/each} + <li> + <a + class="site-nav__link" + href="https://joni-hunt.clientsecure.me/" + target="_blank" + rel="noopener noreferrer" + on:click={closeMenu} + > + Portal + <i class="bi bi-box-arrow-up-right" aria-hidden="true"></i> + </a> + </li> + </ul> + + <div class="site-nav__cta"> + <a class="button button--primary" href={resolveRoute('/contact')} on:click={closeMenu}>Contact Us</a> + </div> + </div> + </div> </nav> + +<style> + .site-nav { + position: sticky; + top: 0; + z-index: 70; + background: rgba(247, 247, 243, 0.86); + backdrop-filter: blur(10px); + border-bottom: 1px solid var(--color-border); + } + + .site-nav__inner { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-4); + padding-block: var(--space-3); + } + + .site-nav__brand { + display: inline-flex; + align-items: center; + gap: var(--space-3); + text-decoration: none; + } + + .site-nav__logo { + display: block; + width: auto; + height: 64px; + } + + .site-nav__toggle { + margin-left: auto; + border: 1px solid var(--color-border); + border-radius: var(--radius-pill); + background: transparent; + padding: 0.75rem 0.9rem; + cursor: pointer; + line-height: 1; + } + + .site-nav__toggle:hover { + border-color: var(--color-accent); + } + + .site-nav__toggle i { + font-size: 1.25rem; + } + + .site-nav__backdrop { + position: fixed; + inset: 0; + background: rgba(16, 20, 19, 0.32); + backdrop-filter: blur(2px); + z-index: 40; + } + + .site-nav__menu { + z-index: 60; + position: absolute; + top: calc(100% + var(--space-2)); + left: 0; + right: 0; + width: 100%; + display: flex; + flex-direction: column; + gap: var(--space-4); + padding: var(--space-3); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + background: rgba(247, 247, 243, 0.95); + box-shadow: var(--shadow-sm); + + transform: translateX(0.75rem); + opacity: 0; + max-height: 0; + overflow: hidden; + pointer-events: none; + transition: + transform 180ms ease, + opacity 180ms ease, + max-height 240ms ease; + } + + .site-nav__menuOpen { + transform: translateX(0); + opacity: 1; + max-height: 70vh; + pointer-events: auto; + } + + .site-nav__links { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: var(--space-2); + } + + .site-nav__link { + position: relative; + display: inline-flex; + align-items: center; + gap: 0.5rem; + text-decoration: none; + padding: 0.75rem 0.9rem; + border-radius: var(--radius-pill); + font-weight: 600; + transition: background 150ms ease, color 150ms ease; + } + + .site-nav__link:hover { + background: color-mix(in srgb, var(--color-accent) 12%, transparent); + } + + .site-nav__link--active { + background: color-mix(in srgb, var(--color-accent) 15%, transparent); + color: var(--color-accent-strong); + } + + .site-nav__link--active:hover { + background: color-mix(in srgb, var(--color-accent) 20%, transparent); + } + + .site-nav__cta { + display: flex; + } + + @media (min-width: 768px) { + .site-nav__toggle { + display: none; + } + + .site-nav__backdrop { + display: none; + } + + .site-nav__menu { + z-index: auto; + position: static; + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-end; + gap: var(--space-4); + margin-top: 0; + padding: 0; + border: 0; + border-radius: 0; + background: transparent; + box-shadow: none; + width: auto; + margin-left: auto; + + transform: none; + opacity: 1; + max-height: none; + overflow: visible; + pointer-events: auto; + transition: none; + } + + .site-nav__links { + flex-direction: row; + align-items: center; + } + } +</style> |
