From cfc14ec8b2a4f29a1c0ab5a8fb1f4907fc6ca800 Mon Sep 17 00:00:00 2001 From: Cody De Arkland Date: Sun, 9 Nov 2025 21:51:44 -0800 Subject: [PATCH 1/3] feat: Add navigation section separator component - Add section_end_divider frontmatter field - Add SidebarSeparator component to render horizontal dividers - Add separator styles (.sidebar-separator) - Update dynamicNav to render separators after items with section_end_divider - Update platformSidebar to map section_end_divider from frontmatter This allows documentation pages to add visual separators in the sidebar by setting section_end_divider: true in their frontmatter, helping to visually group related navigation sections. --- src/components/sidebar/dynamicNav.tsx | 23 +++++++++++++++++----- src/components/sidebar/platformSidebar.tsx | 1 + src/components/sidebar/sidebarLink.tsx | 4 +++- src/components/sidebar/style.module.scss | 10 +++++++++- src/types/frontmatter.ts | 6 ++++++ 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/components/sidebar/dynamicNav.tsx b/src/components/sidebar/dynamicNav.tsx index bf144120f871b0..a0212878985b2a 100644 --- a/src/components/sidebar/dynamicNav.tsx +++ b/src/components/sidebar/dynamicNav.tsx @@ -5,12 +5,13 @@ import {sortPages} from 'sentry-docs/utils'; import {getUnversionedPath, VERSION_INDICATOR} from 'sentry-docs/versioning'; import {CollapsibleSidebarLink} from './collapsibleSidebarLink'; -import {SidebarLink} from './sidebarLink'; +import {SidebarLink, SidebarSeparator} from './sidebarLink'; type Node = { [key: string]: any; context: { [key: string]: any; + section_end_divider?: boolean; sidebar_hidden?: boolean; sidebar_order?: number; sidebar_title?: string; @@ -63,7 +64,7 @@ export const renderChildren = ( showDepth: number = 0, depth: number = 0 ): React.ReactNode[] => { - return sortPages( + const sortedChildren = sortPages( children.filter( ({name, node}) => node && @@ -73,12 +74,17 @@ export const renderChildren = ( !node.context.sidebar_hidden ), ({node}) => node! - ).map(({node, children: nodeChildren}) => { + ); + + const result: React.ReactNode[] = []; + + sortedChildren.forEach(({node, children: nodeChildren}, index) => { // will not be null because of the filter above if (!node) { - return null; + return; } - return ( + + result.push( ); + + // Add separator after this item if section_end_divider is true + if (node.context.section_end_divider && depth === 0) { + result.push(); + } }); + + return result; }; type ChildrenProps = { diff --git a/src/components/sidebar/platformSidebar.tsx b/src/components/sidebar/platformSidebar.tsx index 8e6213a6d91e0f..fcf1e0ae52787d 100644 --- a/src/components/sidebar/platformSidebar.tsx +++ b/src/components/sidebar/platformSidebar.tsx @@ -22,6 +22,7 @@ export function PlatformSidebar({ sidebar_order: n.frontmatter.sidebar_order, sidebar_title: n.frontmatter.sidebar_title, sidebar_hidden: n.frontmatter.sidebar_hidden, + section_end_divider: n.frontmatter.section_end_divider, }, path: '/' + n.path + '/', }; diff --git a/src/components/sidebar/sidebarLink.tsx b/src/components/sidebar/sidebarLink.tsx index 10b50564545b0a..a7032b95663df0 100644 --- a/src/components/sidebar/sidebarLink.tsx +++ b/src/components/sidebar/sidebarLink.tsx @@ -33,7 +33,9 @@ export function SidebarLink({ }`} data-sidebar-link > -
{title}
+
+ {title} +
{collapsible && } ); diff --git a/src/components/sidebar/style.module.scss b/src/components/sidebar/style.module.scss index 3a6850e7d3d315..783c84ac6d3b12 100644 --- a/src/components/sidebar/style.module.scss +++ b/src/components/sidebar/style.module.scss @@ -92,7 +92,7 @@ } .sidebar-separator { - border-top: 1px solid var(--border-color); + border-top: 2px solid var(--gray-6); } .toc { @@ -159,3 +159,11 @@ background-color: var(--brandDecoration); } } + +.sidebar-link-content { + display: flex; + align-items: center; + gap: 0.5rem; + flex: 1; + min-width: 0; +} diff --git a/src/types/frontmatter.ts b/src/types/frontmatter.ts index 197a4e2c5a8b3f..e9407b5d957be9 100644 --- a/src/types/frontmatter.ts +++ b/src/types/frontmatter.ts @@ -23,6 +23,7 @@ export interface FrontMatter { * Set this to true to mark this page as a draft, and hide it from various other components (such as the PageGrid). */ draft?: boolean; + /** * Set this to true to take all the available width for the page content. */ @@ -87,6 +88,11 @@ export interface FrontMatter { */ sidebar_title?: string; + /** + * Set this to true to show a separator/divider below this item in the sidebar + */ + section_end_divider?: boolean; + /** * filesystem path to the source file, generated during build time */ From 832ce36ec151cfd3c88e1703025212a604872def Mon Sep 17 00:00:00 2001 From: Cody De Arkland Date: Sun, 9 Nov 2025 23:18:20 -0800 Subject: [PATCH 2/3] fix: remove unused index parameter in dynamicNav forEach --- src/components/sidebar/dynamicNav.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/sidebar/dynamicNav.tsx b/src/components/sidebar/dynamicNav.tsx index a0212878985b2a..11862b7b829d3b 100644 --- a/src/components/sidebar/dynamicNav.tsx +++ b/src/components/sidebar/dynamicNav.tsx @@ -78,7 +78,7 @@ export const renderChildren = ( const result: React.ReactNode[] = []; - sortedChildren.forEach(({node, children: nodeChildren}, index) => { + sortedChildren.forEach(({node, children: nodeChildren}) => { // will not be null because of the filter above if (!node) { return; From 236f2d62abad9192921e5bc2bdb40dbfd060431e Mon Sep 17 00:00:00 2001 From: Cody De Arkland Date: Mon, 10 Nov 2025 08:52:10 -0800 Subject: [PATCH 3/3] fix: remove duplicate section_end_divider field in FrontMatter type --- src/types/frontmatter.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/types/frontmatter.ts b/src/types/frontmatter.ts index 9d8e55a6e4fb3e..c7a71bbb5041d4 100644 --- a/src/types/frontmatter.ts +++ b/src/types/frontmatter.ts @@ -104,11 +104,6 @@ export interface FrontMatter { */ sidebar_title?: string; - /** - * Set this to true to show a separator/divider below this item in the sidebar - */ - section_end_divider?: boolean; - /** * filesystem path to the source file, generated during build time */