diff --git a/src/components/sidebar/collapsibleSidebarLink.tsx b/src/components/sidebar/collapsibleSidebarLink.tsx
index e660102a6f2cf..73c51680888ab 100644
--- a/src/components/sidebar/collapsibleSidebarLink.tsx
+++ b/src/components/sidebar/collapsibleSidebarLink.tsx
@@ -16,6 +16,12 @@ interface SidebarLinkProps {
*/
title: string;
to: string;
+
+ /**
+ * Shows a beta badge next to the title
+ */
+ beta?: boolean;
+
/**
* Children represent the additional links nested under this sidebar link
*/
@@ -26,6 +32,11 @@ interface SidebarLinkProps {
* Indicates that the links are currently hidden. Overridden by isActive
*/
collapsed?: boolean | null;
+
+ /**
+ * Shows a new badge next to the title
+ */
+ isNew?: boolean;
}
/**
@@ -39,6 +50,8 @@ export function CollapsibleSidebarLink({
path,
collapsed = null,
className = '',
+ beta = false,
+ isNew = false,
}: SidebarLinkProps) {
const isActive = path?.indexOf(to) === 0;
const enableSubtree = isActive || collapsed === false;
@@ -54,6 +67,8 @@ export function CollapsibleSidebarLink({
isActive={to === getUnversionedPath(path)}
collapsible={hasSubtree}
title={title}
+ beta={beta}
+ isNew={isNew}
onClick={() => {
// Allow toggling the sidebar subtree only if the item is selected
if (path === to) {
diff --git a/src/components/sidebar/dynamicNav.tsx b/src/components/sidebar/dynamicNav.tsx
index bf144120f871b..8f0a2841d5a7f 100644
--- a/src/components/sidebar/dynamicNav.tsx
+++ b/src/components/sidebar/dynamicNav.tsx
@@ -11,6 +11,8 @@ type Node = {
[key: string]: any;
context: {
[key: string]: any;
+ beta?: boolean;
+ new?: boolean;
sidebar_hidden?: boolean;
sidebar_order?: number;
sidebar_title?: string;
@@ -63,7 +65,7 @@ export const renderChildren = (
showDepth: number = 0,
depth: number = 0
): React.ReactNode[] => {
- return sortPages(
+ const sortedChildren = sortPages(
children.filter(
({name, node}) =>
node &&
@@ -73,23 +75,32 @@ export const renderChildren = (
!node.context.sidebar_hidden
),
({node}) => node!
- ).map(({node, children: nodeChildren}) => {
+ );
+
+ const result: React.ReactNode[] = [];
+
+ sortedChildren.forEach(({node, children: nodeChildren}) => {
// will not be null because of the filter above
if (!node) {
- return null;
+ return;
}
- return (
+
+ result.push(
= showDepth}
path={path}
+ beta={node.context.beta}
+ isNew={node.context.new}
>
{renderChildren(nodeChildren, exclude, path, showDepth, depth + 1)}
);
});
+
+ return result;
};
type ChildrenProps = {
diff --git a/src/components/sidebar/platformSidebar.tsx b/src/components/sidebar/platformSidebar.tsx
index 8e6213a6d91e0..ebbe1694ec378 100644
--- a/src/components/sidebar/platformSidebar.tsx
+++ b/src/components/sidebar/platformSidebar.tsx
@@ -22,6 +22,8 @@ export function PlatformSidebar({
sidebar_order: n.frontmatter.sidebar_order,
sidebar_title: n.frontmatter.sidebar_title,
sidebar_hidden: n.frontmatter.sidebar_hidden,
+ beta: n.frontmatter.beta,
+ new: n.frontmatter.new,
},
path: '/' + n.path + '/',
};
diff --git a/src/components/sidebar/sidebarLink.tsx b/src/components/sidebar/sidebarLink.tsx
index 10b50564545b0..e5de1be487543 100644
--- a/src/components/sidebar/sidebarLink.tsx
+++ b/src/components/sidebar/sidebarLink.tsx
@@ -13,11 +13,15 @@ export function SidebarLink({
collapsible,
onClick,
topLevel = false,
+ beta = false,
+ isNew = false,
}: {
href: string;
title: string;
+ beta?: boolean;
collapsible?: boolean;
isActive?: boolean;
+ isNew?: boolean;
onClick?: () => void;
topLevel?: boolean;
}) {
@@ -33,12 +37,16 @@ export function SidebarLink({
}`}
data-sidebar-link
>
-
{title}
+
+ {title}
+ {beta && BETA}
+ {isNew && NEW}
+
{collapsible && }
);
}
export function SidebarSeparator() {
- return
;
+ return
;
}
diff --git a/src/components/sidebar/style.module.scss b/src/components/sidebar/style.module.scss
index 3a6850e7d3d31..91c1894602782 100644
--- a/src/components/sidebar/style.module.scss
+++ b/src/components/sidebar/style.module.scss
@@ -91,10 +91,6 @@
}
}
- .sidebar-separator {
- border-top: 1px solid var(--border-color);
- }
-
.toc {
font-size: 0.875rem;
flex: 1;
@@ -159,3 +155,57 @@
background-color: var(--brandDecoration);
}
}
+
+.sidebar-link-content {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ flex: 1;
+ min-width: 0;
+}
+
+.beta-badge {
+ display: inline-flex;
+ align-items: center;
+ padding: 0.0625rem 0.375rem;
+ font-size: 0.625rem;
+ font-weight: 500;
+ letter-spacing: 0.02em;
+ color: #fafaf9; /* off-white */
+ background-color: transparent;
+ border: 1px solid #f59e0b; /* amber-500 warning color */
+ border-radius: 0.25rem;
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+:global(.dark) .beta-badge {
+ color: #fafaf9; /* off-white */
+ border-color: #fbbf24; /* amber-400 for dark mode */
+}
+
+.new-badge {
+ display: inline-flex;
+ align-items: center;
+ padding: 0.0625rem 0.375rem;
+ font-size: 0.625rem;
+ font-weight: 500;
+ letter-spacing: 0.02em;
+ color: #fafaf9; /* off-white */
+ background-color: transparent;
+ border: 1px solid #10b981; /* emerald-500 success green */
+ border-radius: 0.25rem;
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+:global(.dark) .new-badge {
+ color: #fafaf9; /* off-white */
+ border-color: #34d399; /* emerald-400 for dark mode */
+}
+
+.sidebar-separator {
+ margin: 1rem 0;
+ border: none;
+ border-top: 1px solid var(--border-color);
+}
diff --git a/src/types/frontmatter.ts b/src/types/frontmatter.ts
index 197a4e2c5a8b3..c7a71bbb5041d 100644
--- a/src/types/frontmatter.ts
+++ b/src/types/frontmatter.ts
@@ -13,24 +13,36 @@ export interface FrontMatter {
* Document title - used in as well as things like search titles.
*/
title: string;
+ /**
+ * Set this to true to show a "beta" badge next to the title in the sidebar
+ */
+ beta?: boolean;
/**
* A description to use in the header, as well as in auto generated page grids.
*/
customCanonicalTag?: string;
+
/** Add this if you want to add a canonical tag (without this it will default to the page url). Should be a relative path without the domain (e.g. `/platforms/react/options/`) */
description?: string;
+
/**
* 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.
*/
fullWidth?: boolean;
+
/**
* A list of keywords for indexing with search.
*/
keywords?: string[];
+ /**
+ * Set this to true to show a "new" badge next to the title in the sidebar
+ */
+ new?: boolean;
/**
* The next page in the bottom pagination navigation.
@@ -69,6 +81,11 @@ export interface FrontMatter {
*/
previousPage?: PaginationNavNode;
+ /**
+ * Set this to true to show a separator/divider below this item in the sidebar
+ */
+ section_end_divider?: boolean;
+
/**
* The next page in the sidebar navigation.
*/