Skip to content
Merged
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
15 changes: 15 additions & 0 deletions src/components/sidebar/collapsibleSidebarLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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;
}

/**
Expand All @@ -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;
Expand All @@ -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) {
Expand Down
19 changes: 15 additions & 4 deletions src/components/sidebar/dynamicNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 &&
Expand All @@ -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(
<CollapsibleSidebarLink
to={node.path}
key={node.path}
title={node.context.sidebar_title || node.context.title!}
collapsed={depth >= showDepth}
path={path}
beta={node.context.beta}
isNew={node.context.new}
>
{renderChildren(nodeChildren, exclude, path, showDepth, depth + 1)}
</CollapsibleSidebarLink>
);
});

return result;
};

type ChildrenProps = {
Expand Down
2 changes: 2 additions & 0 deletions src/components/sidebar/platformSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 + '/',
};
Expand Down
12 changes: 10 additions & 2 deletions src/components/sidebar/sidebarLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}) {
Expand All @@ -33,12 +37,16 @@ export function SidebarLink({
}`}
data-sidebar-link
>
<div>{title}</div>
<div className={styles['sidebar-link-content']}>
<span>{title}</span>
{beta && <span className={styles['beta-badge']}>BETA</span>}
{isNew && <span className={styles['new-badge']}>NEW</span>}
</div>
{collapsible && <NavChevron direction={isActive ? 'down' : 'right'} />}
</LinkComponent>
);
}

export function SidebarSeparator() {
return <hr className={`${styles['sidebar-separator']} mt-3 mb-3`} />;
return <hr className={styles['sidebar-separator']} />;
}
58 changes: 54 additions & 4 deletions src/components/sidebar/style.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,6 @@
}
}

.sidebar-separator {
border-top: 1px solid var(--border-color);
}

.toc {
font-size: 0.875rem;
flex: 1;
Expand Down Expand Up @@ -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);
}
17 changes: 17 additions & 0 deletions src/types/frontmatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,36 @@ export interface FrontMatter {
* Document title - used in <title> 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 <meta> 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.
Expand Down Expand Up @@ -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.
*/
Expand Down
Loading