component Navbar { outputs { toggle(payload: { open: boolean }) open(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) close(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) select(payload: { item: string | number | boolean | null | object; value: string | number | boolean; level: string }) action(payload: { item: string | number | boolean | null | object; value: string | number | boolean }) } props { size: string = "default" color: string = "primary" label: string = "Primary navigation" topbarLabel: string = "Utility navigation" brand: Record = {} items: unknown[] = [] actions: unknown[] = [] active: string = "" sticky: boolean = false openOnHover: boolean = false maxWidth: string = "full" mobileLabel: string = "Toggle navigation" translationPrefix: string = "" class: string = "" } state mobileOpen: boolean = false functions { shared function translationKey(item, field) { if (!item) return "" const explicit = item[field + "Key"] if (explicit) return explicit if (!translationPrefix) return "" const source = item.value || item.href || item.label || item.title || "" const slug = String(source).replace(/^\/+|\/+$/g, "").replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() return slug ? translationPrefix + "." + slug + (field === "description" ? ".description" : "") : "" } client function toggleNavigation() { mobileOpen = !mobileOpen output.toggle({ open: mobileOpen }) output[mobileOpen ? "open" : "close"]({ source: "mobile" }) } client function selectItem(item, level) { mobileOpen = false output.select({ item: item, value: item.value || "", level: level }) } client function selectAction(item) { mobileOpen = false output.action({ item: item, value: item.value || "" }) } shared function isItemActive(item) { if (!item) return false if (item.value && item.value === active) return true if (!item.children || !item.children.length) return false return item.children.some(function (child) { return isItemActive(child) }) } client function toggleDropdown(event, item) { output[event.currentTarget.open ? "open" : "close"]({ source: "menu", item: item }) } } view {
{#if brand.logo || brand.icon || brand.label || brand.description} {#if brand.logo} {/if} {#if brand.icon} {/if} {#if brand.label || brand.description} {#if brand.label}{brand.label}{/if} {#if brand.description}{brand.description}{/if} {/if} {/if}
{#each actions as item} {#if item.icon}{/if} {item.label} {/each}
} style { /* Full application navigation */ .wrn-navbar { position: relative; z-index: 40; width: 100%; color: var(--wrn-color-text); background: color-mix(in srgb, var(--wrn-color-surface) 96%, transparent); border-bottom: 1px solid var(--wrn-color-border); } .wrn-navbar--sticky { position: sticky; top: 0; backdrop-filter: blur(16px); } .wrn-navbar__topbar:empty, .wrn-navbar__topbar:not(:has(*)) { display: none; } .wrn-navbar__topbar:not(:empty) { display: flex; min-height: 2.25rem; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.35rem clamp(1rem, 4vw, 3rem); color: var(--wrn-color-muted); background: var(--wrn-color-surface-2); border-bottom: 1px solid var(--wrn-color-border); font-size: 0.75rem; font-weight: 400; } .wrn-navbar__main { display: flex; min-height: 4.25rem; width: min(100%, 90rem); margin-inline: auto; padding: 0.75rem clamp(1rem, 4vw, 3rem); align-items: center; gap: 1.5rem; } .wrn-navbar--width-full .wrn-navbar__main { width: 100%; max-width: none; } .wrn-navbar--width-compact .wrn-navbar__main { width: min(86%, 80rem); } .wrn-navbar__brand, .wrn-navbar__menu-link, .wrn-navbar__dropdown summary, .wrn-navbar__action, .wrn-navbar__panel a { color: inherit; text-decoration: none; } .wrn-navbar__brand { display: inline-flex; min-width: 0; align-items: center; gap: 0.75rem; flex: 0 0 auto; } .wrn-navbar__brand-logo { display: block; width: auto; max-width: 11rem; height: 2.5rem; object-fit: contain; } .wrn-navbar__brand-icon { width: 2.5rem; height: 2.5rem; color: var(--wrn-component-color, var(--wrn-color-primary)); } .wrn-navbar__brand-copy { display: grid; min-width: 0; line-height: 1.2; } .wrn-navbar__brand-copy strong { font-size: 0.9rem; font-weight: 600; } .wrn-navbar__brand-copy small { margin-top: 0.2rem; color: var(--wrn-color-muted); font-size: 0.6875rem; font-weight: 400; } .wrn-navbar__collapse, .wrn-navbar__menus, .wrn-navbar__actions { display: flex; align-items: center; } .wrn-navbar__collapse { min-width: 0; flex: 1; gap: 1rem; } .wrn-navbar__menus { justify-content: center; flex: 1; gap: 0.25rem; } .wrn-navbar__actions { justify-content: flex-end; gap: 0.5rem; } .wrn-navbar__menu-link, .wrn-navbar__dropdown > summary, .wrn-navbar__action { display: inline-flex; min-height: 2.75rem; padding: 0.65rem 0.8rem; align-items: center; gap: 0.45rem; border-radius: 0.65rem; cursor: pointer; font-size: 0.8125rem; font-weight: 500; white-space: nowrap; } .wrn-navbar__menu-link:hover, .wrn-navbar__dropdown > summary:hover { color: var(--wrn-color-text); background: var(--wrn-color-surface-2); } .wrn-navbar__menu-link[aria-current="page"], .wrn-navbar__dropdown > summary[aria-current="page"] { color: var(--wrn-component-color, var(--wrn-color-primary)); font-weight: 600; background: color-mix( in srgb, var(--wrn-component-color, var(--wrn-color-primary)) 12%, transparent ); box-shadow: inset 0 -2px 0 var(--wrn-component-color, var(--wrn-color-primary)); } .wrn-navbar__menu-link[aria-current="page"]:hover, .wrn-navbar__dropdown > summary[aria-current="page"]:hover { color: var(--wrn-component-color, var(--wrn-color-primary)); background: color-mix( in srgb, var(--wrn-component-color, var(--wrn-color-primary)) 16%, transparent ); } .wrn-navbar__dropdown { position: relative; } .wrn-navbar__dropdown > summary { list-style: none; } .wrn-navbar__dropdown > summary::-webkit-details-marker { display: none; } .wrn-navbar__chevron { width: 0.45rem; height: 0.45rem; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg) translateY(-0.15rem); transition: transform var(--wrn-motion-fast, 150ms) ease; } .wrn-navbar__dropdown[open] .wrn-navbar__chevron { transform: rotate(225deg) translate(-0.1rem, -0.1rem); } .wrn-navbar__panel { position: absolute; top: calc(100% + 0.55rem); left: 50%; display: grid; width: max-content; min-width: 15rem; max-width: min(90vw, 64rem); padding: 0.65rem; gap: 0.45rem; border: 1px solid var(--wrn-color-border); border-radius: 0.9rem; color: var(--wrn-color-text); background: var(--wrn-color-surface); box-shadow: 0 18px 48px rgb(15 23 42 / 0.16); opacity: 1; transform: translateX(-50%) translateY(0) scale(1); transform-origin: top center; transition: opacity 180ms ease, transform 180ms cubic-bezier(0.22, 1, 0.36, 1), display 180ms allow-discrete; } .wrn-navbar__panel::before { position: absolute; right: 0; bottom: 100%; left: 0; height: 0.65rem; content: ""; } .wrn-navbar__dropdown:not([open]) > .wrn-navbar__panel { display: none; opacity: 0; transform: translateX(-50%) translateY(-0.5rem) scale(0.98); } @starting-style { .wrn-navbar__dropdown[open] > .wrn-navbar__panel { opacity: 0; transform: translateX(-50%) translateY(-0.5rem) scale(0.98); } } .wrn-navbar__dropdown--mega { position: static; } .wrn-navbar__dropdown--mega .wrn-navbar__panel { right: auto; left: 50%; width: min(calc(100vw - 2rem), 64rem); } .wrn-navbar__panel--columns-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .wrn-navbar__panel--columns-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } .wrn-navbar__panel--columns-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } .wrn-navbar__panel-intro { grid-column: 1 / -1; margin: 0; padding: 0.5rem 0.65rem; color: var(--wrn-color-muted); font-size: 0.8125rem; font-weight: 400; } .wrn-navbar__group { display: grid; align-content: start; gap: 0.25rem; } .wrn-navbar__group-title { padding: 0.55rem 0.65rem 0.25rem; font-size: 0.7rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; } .wrn-navbar__group > small { padding: 0 0.65rem 0.4rem; color: var(--wrn-color-muted); font-size: 0.7rem; font-weight: 400; } .wrn-navbar__panel a { display: flex; min-height: 2.75rem; padding: 0.65rem; align-items: flex-start; gap: 0.65rem; border-radius: 0.6rem; font-size: 0.8rem; font-weight: 450; } .wrn-navbar__panel a:hover { background: var(--wrn-color-surface-2); } .wrn-navbar__panel a span:last-child { display: grid; gap: 0.15rem; } .wrn-navbar__panel a strong { font-weight: 500; } .wrn-navbar__panel a small { color: var(--wrn-color-muted); font-size: 0.7rem; font-weight: 400; } .wrn-navbar__action { border: 1px solid transparent; } .wrn-navbar__action--primary { color: var(--wrn-color-on-primary, #fff); background: var(--wrn-component-color, var(--wrn-color-primary)); font-weight: 600; } .wrn-navbar__action--outline { border-color: var(--wrn-color-border); } .wrn-navbar__toggle { display: none; width: 2.75rem; height: 2.75rem; margin-left: auto; padding: 0.65rem; border: 1px solid var(--wrn-color-border); border-radius: 0.65rem; color: inherit; background: var(--wrn-color-surface); } .wrn-navbar__toggle span { display: block; height: 2px; margin: 0.25rem 0; background: currentColor; } @media (max-width: 900px) { .wrn-navbar__main { min-height: 3.5rem; padding-block: 0.4rem; } .wrn-navbar--width-compact .wrn-navbar__main { width: 100%; } .wrn-navbar__toggle { display: block; } .wrn-navbar__collapse { position: absolute; top: 100%; right: 0; left: 0; display: none; padding: 0.75rem 1rem 1rem; align-items: stretch; flex-direction: column; background: var(--wrn-color-surface); border-bottom: 1px solid var(--wrn-color-border); box-shadow: 0 16px 32px rgb(15 23 42 / 0.12); height: calc(100dvh - 3.5rem); max-height: calc(100dvh - 3.5rem); overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; } .wrn-navbar__collapse.is-open { display: flex; } .wrn-navbar:has(.wrn-navbar__collapse.is-open)::after { position: fixed; z-index: -1; inset: 0; background: rgb(15 23 42 / 0.42); content: ""; } .wrn-navbar__menus, .wrn-navbar__actions { width: 100%; align-items: stretch; flex-direction: column; } .wrn-navbar__menu-link, .wrn-navbar__dropdown > summary, .wrn-navbar__action { width: 100%; } .wrn-navbar__panel, .wrn-navbar__dropdown--mega .wrn-navbar__panel { position: static; width: 100%; max-width: none; margin-top: 0.25rem; box-shadow: none; transform: none; overflow: hidden; animation: wrn-navbar-mobile-panel 180ms ease both; } .wrn-navbar__dropdown:not([open]) > .wrn-navbar__panel, .wrn-navbar__dropdown[open] > .wrn-navbar__panel { transform: none; } .wrn-navbar__panel[class*="wrn-navbar__panel--columns-"] { grid-template-columns: 1fr; } .wrn-navbar__panel::before { display: none; } } @media (max-width: 600px) { .wrn-navbar__brand-copy small { display: none; } } @keyframes wrn-navbar-mobile-panel { from { opacity: 0; transform: translateY(-0.35rem); } to { opacity: 1; transform: translateY(0); } } /* Shared component foundation. */ .wrn-component { --wrn-component-color: var(--wrn-color-primary); --wrn-component-scale: 1; margin: 0; color: var(--wrn-color-text); font-family: var(--wrn-font-sans, inherit); } .wrn-component--color-primary { --wrn-component-color: var(--wrn-color-primary); } .wrn-component--color-secondary { --wrn-component-color: var(--wrn-color-secondary); } .wrn-component--color-success { --wrn-component-color: var(--wrn-color-success); } .wrn-component--color-warning { --wrn-component-color: var(--wrn-color-warning); } .wrn-component--color-danger { --wrn-component-color: var(--wrn-color-danger); } .wrn-component--color-info { --wrn-component-color: var(--wrn-color-info); } .wrn-component--size-xs { --wrn-component-scale: 0.78; } .wrn-component--size-sm { --wrn-component-scale: 0.88; } .wrn-component--size-default, .wrn-component--size-md { --wrn-component-scale: 1; } .wrn-component--size-lg { --wrn-component-scale: 1.14; } .wrn-component--size-xl { --wrn-component-scale: 1.28; } .wrn-component:not(.wrn-btn) { font-size: calc(1em * var(--wrn-component-scale)); } .wrn-component :is(a, button, input, select, textarea):focus-visible { outline-color: var(--wrn-component-color); } .wrn-component p { margin: 0; color: var(--wrn-color-muted); line-height: 1.6; } } }