| @use "config" as *; |
| @use "functions" as *; |
| @use "layout/breakpoints" as *; |
| @use "mixins/box-shadow" as *; |
| @use "mixins/mask-icon" as *; |
| @use "mixins/tokens" as *; |
| @use "mixins/transition" as *; |
| |
| // stylelint-disable custom-property-no-missing-var-function |
| // scss-docs-start navbar-breakpoints |
| $navbar-breakpoints: $breakpoints !default; |
| // scss-docs-end navbar-breakpoints |
| |
| $navbar-tokens: () !default; |
| $navbar-dark-tokens: () !default; |
| $navbar-nav-tokens: () !default; |
| |
| // scss-docs-start navbar-tokens |
| // stylelint-disable-next-line scss/dollar-variable-default |
| $navbar-tokens: defaults( |
| ( |
| --navbar-padding-x: 0, |
| --navbar-padding-y: .5rem, |
| --navbar-min-height: 3.5rem, |
| --navbar-color: var(--fg-2), |
| --navbar-hover-color: var(--fg-1), |
| --navbar-disabled-color: var(--fg-3), |
| --navbar-active-color: var(--fg-body), |
| --navbar-brand-padding-y: .375rem, // Match nav link padding-y |
| --navbar-brand-margin-end: 1rem, |
| --navbar-brand-font-size: var(--font-size-md), |
| --navbar-brand-font-weight: var(--font-weight-medium), |
| --navbar-brand-color: var(--fg-body), |
| --navbar-brand-hover-color: var(--fg-body), |
| --navbar-nav-link-padding-x: .75rem, |
| --navbar-toggler-width: 2rem, |
| --navbar-toggler-padding-y: .25rem, |
| --navbar-toggler-padding-x: .75rem, |
| --navbar-toggler-font-size: var(--font-size-lg), |
| --navbar-toggler-border-color: color-mix(in oklch, var(--fg-body) 15%, transparent), |
| --navbar-toggler-border-radius: var(--radius-5), |
| --navbar-toggler-transition: box-shadow .15s ease-in-out, |
| --navbar-toggler-icon-size: 1.25rem, |
| --navbar-toggler-icon: #{escape-svg(url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path stroke='black' stroke-linecap='round' stroke-width='1' d='M1 3.5h14M1 8h14M1 12.5h14'/></svg>"))}, |
| ), |
| $navbar-tokens |
| ); |
| // scss-docs-end navbar-tokens |
| |
| // scss-docs-start navbar-dark-tokens |
| // stylelint-disable-next-line scss/dollar-variable-default |
| $navbar-dark-tokens: defaults( |
| ( |
| --navbar-color: color-mix(in oklch, var(--white) .55, transparent), |
| --navbar-hover-color: color-mix(in oklch, var(--white) .75, transparent), |
| --navbar-disabled-color: color-mix(in oklch, var(--white) .25, transparent), |
| --navbar-active-color: var(--white), |
| --navbar-brand-color: var(--white), |
| --navbar-brand-hover-color: var(--white), |
| --navbar-toggler-border-color: color-mix(in oklch, var(--white) .1, transparent), |
| ), |
| $navbar-dark-tokens |
| ); |
| // scss-docs-end navbar-dark-tokens |
| |
| // scss-docs-start navbar-nav-tokens |
| // stylelint-disable-next-line scss/dollar-variable-default |
| $navbar-nav-tokens: defaults( |
| ( |
| --nav-gap: .25rem, |
| --nav-link-gap: .5rem, |
| --nav-link-padding-x: .5rem, |
| --nav-link-padding-y: .375rem, |
| --nav-link-color: var(--navbar-color), |
| --nav-link-border-width: var(--border-width), |
| //--nav-link-border-color: var(--border-color), |
| --nav-link-hover-color: var(--navbar-hover-color), |
| --nav-link-hover-bg: transparent, |
| --nav-link-active-color: var(--navbar-active-color), |
| --nav-link-active-bg: transparent, |
| --nav-link-disabled-color: var(--navbar-disabled-color), |
| ), |
| $navbar-nav-tokens |
| ); |
| // scss-docs-end navbar-nav-tokens |
| // stylelint-enable custom-property-no-missing-var-function |
| |
| @layer components { |
| // Base navbar |
| .navbar { |
| @include tokens($navbar-tokens); |
| |
| position: relative; |
| display: flex; |
| flex-wrap: wrap; |
| align-items: center; |
| justify-content: space-between; |
| min-height: var(--navbar-min-height); |
| padding: var(--navbar-padding-y) var(--navbar-padding-x); |
| @include set-container(); |
| color: var(--navbar-color, var(--fg-body)); |
| background-color: var(--navbar-bg, var(--bg-body)); |
| // @include gradient-bg(var(--navbar-bg, var(--bg-body))); |
| |
| // Container properties for nested containers |
| %container-flex-properties { |
| display: flex; |
| flex-wrap: inherit; |
| align-items: center; |
| justify-content: space-between; |
| } |
| |
| > .container, |
| > .container-fluid { |
| @extend %container-flex-properties; |
| } |
| |
| @each $breakpoint, $container-max-width in $container-max-widths { |
| > .#{breakpoint-prefix($breakpoint, $container-max-widths)}container { |
| @extend %container-flex-properties; |
| } |
| } |
| } |
| |
| // Navbar brand |
| // |
| // Used for brand, project, or site names. |
| .navbar-brand { |
| padding-top: var(--navbar-brand-padding-y); |
| padding-bottom: var(--navbar-brand-padding-y); |
| margin-inline-end: var(--navbar-brand-margin-end); |
| font-size: var(--navbar-brand-font-size); |
| font-weight: var(--navbar-brand-font-weight); |
| color: var(--theme-fg, var(--navbar-brand-color)); |
| text-decoration: none; |
| white-space: nowrap; |
| |
| &:hover, |
| &:focus { |
| color: var(--theme-fg-emphasis, var(--navbar-brand-hover-color)); |
| } |
| } |
| |
| // Navigation within navbars. Sets all nav-link CSS variables needed for |
| // proper styling. |
| // |
| // Relies on `.nav` base class. |
| .navbar-nav { |
| @include tokens($navbar-nav-tokens); |
| |
| display: flex; |
| flex-direction: column; |
| gap: var(--nav-gap); |
| padding-inline-start: 0; |
| margin-bottom: 0; |
| list-style-type: ""; |
| |
| .nav-link { |
| &.active, |
| &.show { |
| color: var(--theme-fg, var(--navbar-active-color)); |
| border: var(--nav-link-border-width) solid var(--nav-link-border-color, transparent); |
| } |
| } |
| } |
| |
| // Navbar text |
| // |
| // For adding text or inline elements to the navbar |
| .navbar-text { |
| padding-top: var(--navbar-brand-padding-y); |
| padding-bottom: var(--navbar-brand-padding-y); |
| color: var(--navbar-color); |
| |
| a, |
| a:hover, |
| a:focus { |
| color: var(--theme-fg, var(--navbar-active-color)); |
| } |
| } |
| |
| // Button for toggling the navbar when in its collapsed state |
| .navbar-toggler { |
| --btn-bg: transparent; |
| --btn-hover-bg: var(--bg-2); |
| @include transition(var(--navbar-toggler-transition)); |
| } |
| |
| // Hamburger icon, rendered via CSS mask so it inherits the navbar color |
| .navbar-toggler-icon { |
| display: inline-block; |
| width: var(--navbar-toggler-icon-size); |
| height: var(--navbar-toggler-icon-size); |
| background-color: currentcolor; |
| @include mask-icon(var(--navbar-toggler-icon)); |
| } |
| |
| // scss-docs-start navbar-expand-loop |
| // Generate series of responsive `.navbar-expand` classes for configuring |
| // where your navbar collapses and expands. Uses container queries so the |
| // navbar responds to its own width, not the viewport width. |
| |
| // Mixin for expanded state styles (applied to descendants) |
| @mixin navbar-expanded { |
| // Style the inner container since we can't style .navbar itself with container queries |
| > .container, |
| > .container-fluid, |
| %navbar-expand-container { |
| flex-wrap: nowrap; |
| justify-content: flex-start; |
| } |
| |
| .navbar-nav { |
| --nav-link-padding-x: var(--navbar-nav-link-padding-x); |
| flex-direction: row; |
| } |
| |
| .navbar-toggler { |
| display: none !important; // stylelint-disable-line declaration-no-important |
| } |
| |
| [class*="drawer"] { |
| // stylelint-disable declaration-no-important |
| // Reset native <dialog> UA styles and below-breakpoint drawer styles. |
| // Must use !important to override both UA <dialog> defaults and the |
| // responsive drawer styles from media-breakpoint-down(). |
| position: static !important; |
| inset: auto !important; |
| z-index: auto; |
| display: flex !important; |
| flex-grow: 1; |
| width: auto !important; |
| max-width: none !important; |
| height: auto !important; |
| max-height: none !important; |
| padding: 0; |
| margin: 0; |
| overflow: visible !important; |
| visibility: visible !important; |
| background-color: transparent !important; |
| border: 0 !important; |
| transform: none !important; |
| @include box-shadow(none); |
| @include transition(none); |
| // stylelint-enable declaration-no-important |
| |
| .drawer-header { |
| display: none !important; // stylelint-disable-line declaration-no-important |
| } |
| |
| .drawer-body { |
| display: flex; |
| flex-grow: 1; |
| flex-direction: row; |
| align-items: center; |
| padding: 0; |
| overflow-y: visible; |
| } |
| } |
| } |
| |
| // Always expanded (no responsive behavior) |
| .navbar-expand { |
| @include navbar-expanded(); |
| |
| // Also set on navbar itself for non-responsive case |
| flex-wrap: nowrap; |
| justify-content: flex-start; |
| } |
| |
| // Responsive navbar expand classes using container queries |
| @include loop-breakpoints-down($navbar-breakpoints) using ($breakpoint, $next, $prefix) { |
| @if $next { |
| .#{$prefix}navbar-expand { |
| @include container-breakpoint-up($next) { |
| @include navbar-expanded(); |
| } |
| } |
| } |
| } |
| // scss-docs-end navbar-expand-loop |
| |
| // Prevent drawer flash on breakpoint crossing. |
| // When the navbar crosses from expanded (inline) to collapsed (drawer), |
| // the drawer transitions from visibility:visible to visibility:hidden. |
| // Without this override, the slide transition plays — briefly showing the |
| // panel sliding away. Disabling transitions when not [open] ensures only |
| // intentional show/hide actions animate. |
| // stylelint-disable-next-line no-duplicate-selectors |
| .navbar { |
| [class*="drawer"]:not([open], .hiding) { |
| @include transition(none !important); |
| } |
| } |
| |
| .navbar-translucent { |
| position: relative; |
| background-color: transparent; |
| |
| &::before { |
| position: absolute; |
| inset: 0; |
| z-index: -1; |
| content: ""; |
| background-color: color-mix(in oklch, var(--navbar-bg, var(--bg-body)) 80%, transparent); |
| background-image: none; |
| backdrop-filter: blur(5px) saturate(180%); |
| } |
| } |
| |
| .navbar[data-bs-theme="dark"] { |
| @include tokens($navbar-dark-tokens); |
| } |
| } |