diff --git a/src/pydata_sphinx_theme/assets/styles/abstracts/_links.scss b/src/pydata_sphinx_theme/assets/styles/abstracts/_links.scss index f3fe96be1..b47dd77ab 100644 --- a/src/pydata_sphinx_theme/assets/styles/abstracts/_links.scss +++ b/src/pydata_sphinx_theme/assets/styles/abstracts/_links.scss @@ -182,3 +182,59 @@ $link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; outline: 2px solid var(--pst-color-accent); } } + +/* +Mixin for links in the header (and the More dropdown toggle). + +The mixin assumes it will be applied to some element X with a markup structure +like: X > .nav-link, or X > .dropdown-toggle. + +It also assumes X.current is how the app annotates which item in the header nav +corresponds to the section in the docs that the user is currently reading. +*/ +@mixin header-link { + > .nav-link, + > .dropdown-toggle { + border-radius: 2px; + color: var(--pst-color-text-muted); + + &:hover { + background-color: var(--pst-color-header-link-hover-bg); + color: var(--pst-color-header-link-hover); + text-decoration: none; // override the link-style-hover mixin + } + + &:focus { + box-shadow: none; // override Bootstrap + outline: 3px solid var(--pst-color-accent); + outline-offset: 2px; + + &:not(:hover) { + background-color: var(--pst-color-accent-bg); + } + } + } + + &.current { + > .nav-link, + > .dropdown-toggle { + color: var(--pst-color-primary); + &:hover { + color: var(--pst-color-header-link-hover); + } + + // These styles underline the current navbar item + position: relative; + &::after { + content: ""; + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + border-bottom: 3px solid var(--pst-color-primary); + } + } + } +} diff --git a/src/pydata_sphinx_theme/assets/styles/sections/_header.scss b/src/pydata_sphinx_theme/assets/styles/sections/_header.scss index 0e491274f..8c01d69fe 100644 --- a/src/pydata_sphinx_theme/assets/styles/sections/_header.scss +++ b/src/pydata_sphinx_theme/assets/styles/sections/_header.scss @@ -80,26 +80,29 @@ @include media-breakpoint-up($breakpoint-sidebar-primary) { // Center align on wide screens so the dropdown button is centered properly - align-items: center; + align-items: baseline; } - li a.nav-link { - @include link-style-text; + li.pst-header-nav-item { + margin-inline: 4px; // breathing room so hover, focus styles do not overlap + &:first-child { + margin-inline-start: 0; + } + &:last-child { + margin-inline-end: 0; + } + @include header-link; } - // Current page is always underlined in the navbar - > .current > .nav-link { - @include link-navbar-current; + li a.nav-link.dropdown-item { + @include link-style-text; } // Dropdowns for the extra links .dropdown { button { display: unset; - color: var(--pst-color-text-muted); border: none; - @include link-style-hover; - @include focus-indicator; } .dropdown-menu { diff --git a/src/pydata_sphinx_theme/assets/styles/variables/_color.scss b/src/pydata_sphinx_theme/assets/styles/variables/_color.scss index e658ae062..8eab79a66 100644 --- a/src/pydata_sphinx_theme/assets/styles/variables/_color.scss +++ b/src/pydata_sphinx_theme/assets/styles/variables/_color.scss @@ -228,6 +228,12 @@ $pst-semantic-colors: ( "light": #{map-deep-get($color-palette, "gray", "800")}, "dark": $foundation-light-gray, ), + "header-link-hover": ( + "light": $foundation-white, + "bg-light": #{map-deep-get($color-palette, "violet", "500")}, + "dark": #{map-deep-get($color-palette, "violet", "500")}, + "bg-dark": #{map-deep-get($color-palette, "gray", "800")}, + ), ); /******************************************************************************* diff --git a/src/pydata_sphinx_theme/toctree.py b/src/pydata_sphinx_theme/toctree.py index 94a0d9b48..629b62e72 100644 --- a/src/pydata_sphinx_theme/toctree.py +++ b/src/pydata_sphinx_theme/toctree.py @@ -91,7 +91,7 @@ def generate_header_nav_before_dropdown(n_links_before_dropdown): page = toc.attributes["parent"] if page == "self" else page # If this is the active ancestor page, add a class so we highlight it - current = " current active" if page == active_header_page else "" + current = "current active" if page == active_header_page else "" # sanitize page title for use in the html output if needed if title is None: @@ -108,14 +108,14 @@ def generate_header_nav_before_dropdown(n_links_before_dropdown): # If it's an absolute one then we use the external class and # the complete url. is_absolute = bool(urlparse(page).netloc) - link_status = "external" if is_absolute else "internal" + link_status = "nav-external" if is_absolute else "nav-internal" link_href = page if is_absolute else context["pathto"](page) # create the html output links_html.append( f""" - @@ -126,7 +126,7 @@ def generate_header_nav_before_dropdown(n_links_before_dropdown): for external_link in context["theme_external_links"]: links_html.append( f""" -