diff --git a/src/components/platformSelector/index.tsx b/src/components/platformSelector/index.tsx
index 85a97fcbf270d1..8463900d678afd 100644
--- a/src/components/platformSelector/index.tsx
+++ b/src/components/platformSelector/index.tsx
@@ -20,7 +20,7 @@ import {uniqByReference} from 'sentry-docs/utils';
import styles from './style.module.scss';
-import {SidebarLink} from '../sidebarLink';
+import {SidebarLink, SidebarSeparator} from '../sidebar/sidebarLink';
export function PlatformSelector({
platforms,
@@ -240,19 +240,14 @@ export function PlatformSelector({
{showStoredPlatform && (
-
-
-
- {/* display chevron icon by adding a child element */}
-
-
-
-
+
+
+
)}
diff --git a/src/components/sidebarLink.tsx b/src/components/sidebar/collapsibleSidebarLink.tsx
similarity index 52%
rename from src/components/sidebarLink.tsx
rename to src/components/sidebar/collapsibleSidebarLink.tsx
index db38cf81ae8cd6..345c6e94c95859 100644
--- a/src/components/sidebarLink.tsx
+++ b/src/components/sidebar/collapsibleSidebarLink.tsx
@@ -1,11 +1,10 @@
'use client';
import {Children, useState} from 'react';
-import styled from '@emotion/styled';
import {getUnversionedPath} from 'sentry-docs/versioning';
-import {SmartLink} from './smartLink';
+import {SidebarLink} from './sidebarLink';
interface SidebarLinkProps {
/**
@@ -29,7 +28,11 @@ interface SidebarLinkProps {
collapsed?: boolean | null;
}
-export function SidebarLink({
+/**
+ * This client component is used to render a collapsible sidebar link.
+ * It is only used by the DynamicNav component.
+ */
+export function CollapsibleSidebarLink({
to,
title,
children,
@@ -45,55 +48,20 @@ export function SidebarLink({
return (
- {
// Allow toggling the sidebar subtree only if the item is selected
if (path === to) {
setShowSubtree(v => enableSubtree && !v);
}
}}
- >
- {title || children}
- {hasSubtree && }
-
- {title && children && {showSubtree && children} }
+ />
+ {showSubtree && }
);
}
-
-const SidebarNavItem = styled(SmartLink)`
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 4px;
-`;
-
-const rotation = {
- down: 0,
- right: 270,
-} as const;
-
-interface ChevronProps extends React.SVGAttributes {
- direction: keyof typeof rotation;
-}
-
-const Chevron = styled(({direction: _, ...props}: ChevronProps) => (
-
-
-
-))`
- transition: transform 200ms;
- transform: rotate(${p => rotation[p.direction]}deg);
-`;
diff --git a/src/components/sidebar/defaultSidebar.tsx b/src/components/sidebar/defaultSidebar.tsx
deleted file mode 100644
index 215c604a4af474..00000000000000
--- a/src/components/sidebar/defaultSidebar.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import {Fragment} from 'react';
-import {Link} from 'react-feather';
-
-import styles from './style.module.scss';
-
-import {NavChevron} from './navChevron';
-import {DefaultSidebarProps, SidebarNode} from './types';
-
-export function DefaultSidebar({node, path}: DefaultSidebarProps) {
- const activeClassName = (n: SidebarNode, baseClassName = '') => {
- const className = n.path === path.join('/') ? 'active' : '';
- return `${baseClassName} ${className}`;
- };
-
- const renderChildren = (children: SidebarNode[]) =>
- children && (
-
- {children
- .filter(n => n.frontmatter.sidebar_title || n.frontmatter.title)
- .map(n => (
-
-
- {n.frontmatter.sidebar_title || n.frontmatter.title}
- {n.children.length > 0 && }
-
- {renderChildren(n.children)}
-
- ))}
-
- );
-
- return (
-
-
-
-
-
- {node.frontmatter.sidebar_title || node.frontmatter.title}
-
-
- {renderChildren(node.children)}
-
-
-
- );
-}
diff --git a/src/components/sidebar/developDocsSidebar.tsx b/src/components/sidebar/developDocsSidebar.tsx
index d96194e4088b8d..e62dc34dcdc228 100644
--- a/src/components/sidebar/developDocsSidebar.tsx
+++ b/src/components/sidebar/developDocsSidebar.tsx
@@ -2,9 +2,8 @@ import {DocNode, nodeForPath} from 'sentry-docs/docTree';
import styles from './style.module.scss';
-import {SidebarLink} from '../sidebarLink';
-
import {DynamicNav, toTree} from './dynamicNav';
+import {SidebarLink, SidebarSeparator} from './sidebarLink';
import {NavNode} from './types';
import {docNodeToNavNode, getNavNodes} from './utils';
@@ -23,7 +22,6 @@ const devDocsMenuItems: {root: string; title: string}[] = [
];
export function DevelopDocsSidebar({
- path,
rootNode,
sidebarToggleId,
}: {
@@ -55,18 +53,13 @@ export function DevelopDocsSidebar({
/>
))}
-
+
diff --git a/src/components/sidebar/dynamicNav.tsx b/src/components/sidebar/dynamicNav.tsx
index 10e2ee66435f8f..bf144120f871b0 100644
--- a/src/components/sidebar/dynamicNav.tsx
+++ b/src/components/sidebar/dynamicNav.tsx
@@ -4,12 +4,8 @@ import {serverContext} from 'sentry-docs/serverContext';
import {sortPages} from 'sentry-docs/utils';
import {getUnversionedPath, VERSION_INDICATOR} from 'sentry-docs/versioning';
-import styles from './style.module.scss';
-
-import {SidebarLink} from '../sidebarLink';
-import {SmartLink} from '../smartLink';
-
-import {NavChevron} from './navChevron';
+import {CollapsibleSidebarLink} from './collapsibleSidebarLink';
+import {SidebarLink} from './sidebarLink';
type Node = {
[key: string]: any;
@@ -83,7 +79,7 @@ export const renderChildren = (
return null;
}
return (
-
{renderChildren(nodeChildren, exclude, path, showDepth, depth + 1)}
-
+
);
});
};
@@ -142,6 +138,9 @@ export function DynamicNav({
if (!title && entity.node) {
title = entity.node.context.sidebar_title || entity.node.context.title || '';
}
+ if (!title) {
+ return null;
+ }
const parentNode = entity.children?.find((n: EntityTree) => n.name === '');
if (!parentNode) {
@@ -153,15 +152,14 @@ export function DynamicNav({
const linkPath = `/${path.join('/')}/`;
const header = (
-
- {title}
- {collapsible && }
-
+ />
);
return (
diff --git a/src/components/sidebar/index.tsx b/src/components/sidebar/index.tsx
index 08188f92f2ec58..dcb5b3a0089767 100644
--- a/src/components/sidebar/index.tsx
+++ b/src/components/sidebar/index.tsx
@@ -15,7 +15,7 @@ import {PlatformSelector} from '../platformSelector';
import {VersionSelector} from '../versionSelector';
import {DevelopDocsSidebar} from './developDocsSidebar';
-import {SidebarLinks} from './sidebarLinks';
+import {SidebarNavigation} from './sidebarNavigation';
import {SidebarProps} from './types';
const activeLinkSelector = `.${styles.sidebar} .toc-item .active`;
@@ -100,7 +100,7 @@ export async function Sidebar({path, versions}: SidebarProps) {
-
+
diff --git a/src/components/sidebar/productSidebar.tsx b/src/components/sidebar/productSidebar.tsx
index a43d48f1142a16..0425a4a0440c1a 100644
--- a/src/components/sidebar/productSidebar.tsx
+++ b/src/components/sidebar/productSidebar.tsx
@@ -1,8 +1,7 @@
import {nodeForPath} from 'sentry-docs/docTree';
-import {SidebarLink} from '../sidebarLink';
-
import {DynamicNav, toTree} from './dynamicNav';
+import {SidebarLink, SidebarSeparator} from './sidebarLink';
import {NavNode, ProductSidebarProps} from './types';
import {docNodeToNavNode, getNavNodes} from './utils';
@@ -34,26 +33,20 @@ export function ProductSidebar({rootNode, items}: ProductSidebarProps) {
);
})}
-
+
diff --git a/src/components/sidebar/sidebarLink.tsx b/src/components/sidebar/sidebarLink.tsx
new file mode 100644
index 00000000000000..10b50564545b0a
--- /dev/null
+++ b/src/components/sidebar/sidebarLink.tsx
@@ -0,0 +1,44 @@
+import Link from 'next/link';
+
+import styles from './style.module.scss';
+
+import {ExternalLink} from '../externalLink';
+
+import {NavChevron} from './navChevron';
+
+export function SidebarLink({
+ title,
+ href,
+ isActive,
+ collapsible,
+ onClick,
+ topLevel = false,
+}: {
+ href: string;
+ title: string;
+ collapsible?: boolean;
+ isActive?: boolean;
+ onClick?: () => void;
+ topLevel?: boolean;
+}) {
+ const isRemote = href.includes('://');
+ const LinkComponent = isRemote ? ExternalLink : Link;
+
+ return (
+
+ {title}
+ {collapsible && }
+
+ );
+}
+
+export function SidebarSeparator() {
+ return ;
+}
diff --git a/src/components/sidebar/sidebarLinks.tsx b/src/components/sidebar/sidebarNavigation.tsx
similarity index 85%
rename from src/components/sidebar/sidebarLinks.tsx
rename to src/components/sidebar/sidebarNavigation.tsx
index a22e65a1f75f4f..fb2502e3de077b 100644
--- a/src/components/sidebar/sidebarLinks.tsx
+++ b/src/components/sidebar/sidebarNavigation.tsx
@@ -2,10 +2,10 @@ import {Fragment} from 'react';
import {getDocsRootNode, nodeForPath} from 'sentry-docs/docTree';
-import {DefaultSidebar} from './defaultSidebar';
import {DynamicNav, toTree} from './dynamicNav';
import {PlatformSidebar} from './platformSidebar';
import {ProductSidebar} from './productSidebar';
+import {SidebarSeparator} from './sidebarLink';
import {NavNode} from './types';
import {docNodeToNavNode, getNavNodes} from './utils';
@@ -46,14 +46,16 @@ const productSidebarItems = [
},
];
-export async function SidebarLinks({path}: {path: string[]}) {
+export async function SidebarNavigation({path}: {path: string[]}) {
const rootNode = await getDocsRootNode();
+ // product docs and platform-redirect page
if (
productSidebarItems.some(el => el.root === path[0]) ||
path[0] === 'platform-redirect'
) {
return ;
}
+
// /platforms/:platformName/guides/:guideName
if (path[0] === 'platforms') {
const platformName = path[1];
@@ -67,13 +69,15 @@ export async function SidebarLinks({path}: {path: string[]}) {
guideName={guideName}
rootNode={rootNode}
/>
-
+
)}
);
}
+
+ // contributing pages
if (path[0] === 'contributing') {
const contribNode = nodeForPath(rootNode, 'contributing');
if (contribNode) {
@@ -89,6 +93,7 @@ export async function SidebarLinks({path}: {path: string[]}) {
);
}
}
- // render the default sidebar if no special case is met
- return ;
+
+ // This should never happen, all cases need to be handled above
+ throw new Error(`Unknown path: ${path.join('/')} - cannot render sidebar`);
}
diff --git a/src/components/sidebar/style.module.scss b/src/components/sidebar/style.module.scss
index c55c50e0a8eaa0..2c0b5c169833b5 100644
--- a/src/components/sidebar/style.module.scss
+++ b/src/components/sidebar/style.module.scss
@@ -62,9 +62,7 @@
}
}
- ul + hr {
- margin-top: 1rem;
- margin-bottom: 1rem;
+ .sidebar-separator {
border-top: 1px solid var(--border-color);
}
@@ -114,25 +112,21 @@
}
}
-.sidebar-title {
+.sidebar-link-top-level {
font-weight: 500;
- margin-bottom: 2px;
+ font-size: 0.8rem;
+ text-transform: uppercase;
+ letter-spacing: 0.2px;
+ color: inherit;
+}
+
+.sidebar-link {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.25rem;
&.active {
background-color: var(--brandDecoration);
-
- strong {
- color: #fff;
- }
- }
-
- strong {
- display: block;
- margin-bottom: 0;
- font-size: 0.8rem;
- text-transform: uppercase;
- letter-spacing: 0.2px;
- color: inherit;
- font-weight: inherit;
}
}