Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions site/data/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
- title: JavaScript
- title: Accessibility
# - title: Community
- title: Examples
href: examples/

- title: Guides
section: Guides
Expand Down
65 changes: 49 additions & 16 deletions site/src/components/DocsSidebar.astro
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,66 @@ import { getSlug } from '@libs/utils'
import NewBadge from '@components/NewBadge.astro'

const sidebar = getData('sidebar')

// Derive active section from the current slug
const { slug } = Astro.params
const currentDir = (slug as string)?.split('/')[0] ?? ''
const activeSection = sidebar.find((g) => getSlug(g.title) === currentDir)?.section

// Only show groups that belong to the active section; fall back to all groups
const visibleGroups = activeSection ? sidebar.filter((g) => g.section === activeSection) : sidebar

// Skip group headings when there's only one group in the section
const skipGroupHeading = visibleGroups.filter((g) => g.pages).length === 1
---

<nav class="nav vstack bd-links w-100 pb-3 md:pb-2 lg:pe-2" id="bd-docs-nav" aria-label="Docs navigation">
{
sidebar.map((group) => {
visibleGroups.map((group) => {
const groupSlug = getSlug(group.title)

if (group.pages) {
return (
<div class="vstack bd-links-group py-2">
<strong class="bd-links-heading d-flex w-100 align-items-center fw-semibold">
{group.icon && (
<svg
class="bi me-2"
style={
group.icon_color &&
`color: light-dark(var(--bs-${group.icon_color}-500), var(--bs-${group.icon_color}-400));`
}
aria-hidden="true"
>
<use href={`#${group.icon}`} />
</svg>
)}
{group.title}
</strong>
{!skipGroupHeading && (
<strong class="bd-links-heading d-flex w-100 align-items-center fw-semibold">
{group.icon && (
<svg
class="bi me-2"
style={
group.icon_color &&
`color: light-dark(var(--bs-${group.icon_color}-500), var(--bs-${group.icon_color}-400));`
}
aria-hidden="true"
>
<use href={`#${group.icon}`} />
</svg>
)}
{group.title}
</strong>
)}
<ul class="nav flex-column bd-links-nav">
{group.pages?.map((item: SidebarItem) => {
// Handle href-only items (e.g. Examples, Migration)
if (item.href && !item.title) {
return null
}

if (item.href && item.title) {
const active = Astro.params.slug === item.href.replace(/\/$/, '')
return (
<li>
<a
href={`/docs/${getConfig().docs_version}/${item.href}`}
class:list={['nav-link bd-links-link border-0', { active }]}
aria-current={active ? 'page' : undefined}
>
{item.title}
</a>
</li>
)
}

// Handle sub-groups
if (item.group && item.pages) {
return (
Expand Down
56 changes: 56 additions & 0 deletions site/src/components/DocsSubNavbar.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
import { getData } from '@libs/data'
import { getSlug } from '@libs/utils'
import { getVersionedDocsPath } from '@libs/path'

interface Props {
currentSlug: string
}

const { currentSlug } = Astro.props
const sidebar = getData('sidebar')

// Build ordered, deduplicated list of sections with their first-group info
const seen = new Set<string>()
const sections: { section: string; href: string }[] = []

for (const group of sidebar) {
if (!group.section || seen.has(group.section)) continue
seen.add(group.section)

// Find the first linkable page in this group
const firstItem = group.pages?.find((p) => p.title && !p.href)
const href = firstItem?.title
? getVersionedDocsPath(`${getSlug(group.title)}/${getSlug(firstItem.title)}/`)
: getVersionedDocsPath(`${getSlug(group.title)}/`)

sections.push({ section: group.section, href })
}

// Detect active section from the current slug (e.g. "getting-started/install" -> "getting-started")
const currentDir = currentSlug?.split('/')[0] ?? ''
const activeSection =
sidebar.find((g) => getSlug(g.title) === currentDir)?.section ?? null
---

<nav class="navbar navbar-expand bd-subnavbar border-bottom" aria-label="Docs sections">
<div class="2xl:container bd-gutter">
<ul
class="nav navbar-nav"
data-bs-toggle="nav-overflow"
data-bs-collapse-below="md"
data-bs-more-text={activeSection ?? 'More'}
data-bs-menu-placement="bottom-start"
>
{
sections.map(({ section, href }) => (
<li class="nav-item">
<a class:list={['nav-link', { active: section === activeSection }]} href={href}>
{section}
</a>
</li>
))
}
</ul>
</div>
</nav>
6 changes: 6 additions & 0 deletions site/src/layouts/BaseLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Header from '@components/header/Header.astro'
import Scripts from '@components/Scripts.astro'
import Footer from '@components/footer/Footer.astro'
import { stripMarkdown } from '@libs/utils'
import DocsSubNavbar from '@components/DocsSubNavbar.astro'

// The following props can be directly passed to the base layout component from any page or layout extending it,
// e.g. <BaseLayout layout="docs" robots="noindex" />.
Expand Down Expand Up @@ -42,6 +43,10 @@ const thumbnail = frontmatter?.thumbnail ? `img/${frontmatter.thumbnail}` : 'bra

const bodyProps = overrides?.body ?? {}
const mainProps = overrides?.main ?? {}

const docsCurrentSlug = layout === 'docs'
? Astro.url.pathname.replace(/^\/docs\/[^/]+\//, '').replace(/\/$/, '')
: ''
---

<!doctype html>
Expand All @@ -52,6 +57,7 @@ const mainProps = overrides?.main ?? {}
<body {...bodyProps}>
<div class="navbar-translucent sticky-top bd-sticky-navbar">
<Header layout={layout} title={title} addedIn={frontmatter?.added} />
{layout === 'docs' && <DocsSubNavbar currentSlug={docsCurrentSlug} />}
</div>

{
Expand Down
19 changes: 19 additions & 0 deletions site/src/scss/_subnavbar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@use "../../../scss/config" as *;
@use "../../../scss/layout/breakpoints" as *;

@layer custom {
.bd-subnavbar {
background-color: var(--bs-body-bg);

.nav {
flex-wrap: nowrap;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}

.nav-link {
white-space: nowrap;
padding-block: .5rem;
}
}
}
1 change: 1 addition & 0 deletions site/src/scss/docs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
// Load docs components
// @use "variables";
@use "navbar";
@use "subnavbar";
@use "masthead";
@use "ads";
@use "content";
Expand Down
Loading