Page Not Found
We couldn't find the page you were looking for :(
diff --git a/package.json b/package.json index 8e76182dcc1e38..5822b2b1c1fc3e 100644 --- a/package.json +++ b/package.json @@ -91,8 +91,9 @@ "next-themes": "^0.3.0", "nextjs-toploader": "^1.6.6", "p-limit": "^6.2.0", - "platformicons": "^9.0.6", + "platformicons": "^9.0.7", "prism-sentry": "^1.0.2", + "query-string": "^9.3.1", "react": "^19.2.4", "react-dom": "^19.2.4", "react-feather": "^2.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0cc772d42a60e9..ce48deb47cd085 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -176,11 +176,14 @@ importers: specifier: ^6.2.0 version: 6.2.0 platformicons: - specifier: ^9.0.6 + specifier: ^9.0.7 version: 9.0.7(react@19.2.4) prism-sentry: specifier: ^1.0.2 version: 1.0.2 + query-string: + specifier: ^9.3.1 + version: 9.3.1 react: specifier: ^19.2.4 version: 19.2.4 @@ -4225,6 +4228,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -4924,6 +4932,10 @@ packages: decode-named-character-reference@1.3.0: resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + decode-uri-component@0.4.1: + resolution: {integrity: sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==} + engines: {node: '>=14.16'} + dedent@1.7.1: resolution: {integrity: sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==} peerDependencies: @@ -5483,6 +5495,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + filter-obj@5.1.0: + resolution: {integrity: sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==} + engines: {node: '>=14.16'} + find-root@1.1.0: resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} @@ -7121,6 +7137,10 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + query-string@9.3.1: + resolution: {integrity: sha512-5fBfMOcDi5SA9qj5jZhWAcTtDfKF5WFdd2uD9nVNlbxVv1baq65aALy6qofpNEGELHvisjjasxQp7BlM9gvMzw==} + engines: {node: '>=18'} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -7642,6 +7662,10 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + split-on-first@3.0.0: + resolution: {integrity: sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==} + engines: {node: '>=12'} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -13228,9 +13252,9 @@ snapshots: dependencies: acorn: 8.15.0 - acorn-import-phases@1.0.4(acorn@8.15.0): + acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 acorn-jsx@5.3.2(acorn@8.15.0): dependencies: @@ -13246,6 +13270,8 @@ snapshots: acorn@8.15.0: {} + acorn@8.16.0: {} + agent-base@6.0.2: dependencies: debug: 4.4.3 @@ -14029,6 +14055,8 @@ snapshots: dependencies: character-entities: 2.0.2 + decode-uri-component@0.4.1: {} + dedent@1.7.1(babel-plugin-macros@3.1.0): optionalDependencies: babel-plugin-macros: 3.1.0 @@ -14851,6 +14879,8 @@ snapshots: dependencies: to-regex-range: 5.0.1 + filter-obj@5.1.0: {} + find-root@1.1.0: {} find-up@4.1.0: @@ -17178,6 +17208,12 @@ snapshots: pure-rand@6.1.0: {} + query-string@9.3.1: + dependencies: + decode-uri-component: 0.4.1 + filter-obj: 5.1.0 + split-on-first: 3.0.0 + querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -18049,6 +18085,8 @@ snapshots: space-separated-tokens@2.0.2: {} + split-on-first@3.0.0: {} + sprintf-js@1.0.3: {} stable-hash@0.0.5: {} @@ -18284,7 +18322,7 @@ snapshots: terser@5.46.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -18876,8 +18914,8 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) + acorn: 8.16.0 + acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.19.0 diff --git a/src/components/TopNavClient.tsx b/src/components/TopNavClient.tsx new file mode 100644 index 00000000000000..fdad7c5b945a48 --- /dev/null +++ b/src/components/TopNavClient.tsx @@ -0,0 +1,711 @@ +'use client'; +import {useEffect, useRef, useState} from 'react'; +import ReactDOM from 'react-dom'; +import Link from 'next/link'; +import {usePathname, useRouter} from 'next/navigation'; + +import {Platform} from 'sentry-docs/types'; + +import platformSelectorStyles from './platformSelector/style.module.scss'; + +import {mainSectionsWithDropdowns, productSections} from './navigationData'; +import {PlatformSelector} from './platformSelector'; + +const mainSections = mainSectionsWithDropdowns; + +// Add a helper hook for portal dropdown positioning +function useDropdownPosition(triggerRef, open) { + const [position, setPosition] = useState({top: 0, left: 0, width: 0}); + useEffect(() => { + function updatePosition() { + if (triggerRef.current && open) { + const rect = triggerRef.current.getBoundingClientRect(); + setPosition({ + top: rect.bottom + window.scrollY, + left: rect.left + window.scrollX, + width: rect.width, + }); + } + } + updatePosition(); + if (open) { + window.addEventListener('resize', updatePosition); + window.addEventListener('scroll', updatePosition, true); + } + return () => { + window.removeEventListener('resize', updatePosition); + window.removeEventListener('scroll', updatePosition, true); + }; + }, [triggerRef, open]); + return position; +} + +export default function TopNavClient({platforms}: {platforms: Platform[]}) { + const [platformDropdownOpen, setPlatformDropdownOpen] = useState(false); + const [platformDropdownByClick, setPlatformDropdownByClick] = useState(false); + const platformBtnRef = useRef-
+ {mainSections.map(section => (
+
-
+ {section.label === 'Product' ? (
+ { + clearTimeout(closeTimers.current.products); + setProductsDropdownOpen(true); + setConceptsDropdownOpen(false); + setMoreDropdownOpen(false); + setPlatformDropdownOpen(false); + }} + onMouseLeave={() => { + closeTimers.current.products = setTimeout(() => { + setProductsDropdownOpen(false); + }, 150); + }} + > + ++ ) : section.label === 'Concepts' ? ( +{ + clearTimeout(closeTimers.current.concepts); + setConceptsDropdownOpen(true); + setProductsDropdownOpen(false); + setMoreDropdownOpen(false); + setPlatformDropdownOpen(false); + }} + onMouseLeave={() => { + closeTimers.current.concepts = setTimeout(() => { + setConceptsDropdownOpen(false); + }, 150); + }} + > + ++ ) : section.label === 'More' ? ( +{ + clearTimeout(closeTimers.current.more); + setMoreDropdownOpen(true); + setProductsDropdownOpen(false); + setConceptsDropdownOpen(false); + setPlatformDropdownOpen(false); + }} + onMouseLeave={() => { + closeTimers.current.more = setTimeout(() => { + setMoreDropdownOpen(false); + }, 150); + }} + > + ++ ) : section.label === 'SDKs' ? ( + + {section.label} + + ) : ( + + {section.label} + + )} +
+ ))}
+
-
- {breadcrumbs.map(b => {
+ {items.map(b => {
+ const isPlatformsLink = b.to === '/platforms/';
return (
-
-
{b.title} + {isPlatformsLink ? ( + + {b.title} + + ) : ( + {b.title} + )}
);
})}
diff --git a/src/components/breadcrumbs/utils.ts b/src/components/breadcrumbs/utils.ts
new file mode 100644
index 00000000000000..2ea0fb9c1d295e
--- /dev/null
+++ b/src/components/breadcrumbs/utils.ts
@@ -0,0 +1,22 @@
+import {DocNode} from 'sentry-docs/docTree';
+
+import {BreadcrumbItem} from './index';
+
+// Helper function to build breadcrumbs from DocNode (for use in server components)
+export function buildBreadcrumbs(leafNode: DocNode | undefined): BreadcrumbItem[] {
+ const breadcrumbs: BreadcrumbItem[] = [];
+
+ for (let node: DocNode | undefined = leafNode; node; node = node.parent) {
+ if (node && !node.missing) {
+ const to = node.path === '/' ? node.path : `/${node.path}/`;
+ const title = node.frontmatter.sidebar_title ?? node.frontmatter.title;
+
+ breadcrumbs.unshift({
+ to,
+ title,
+ });
+ }
+ }
+
+ return breadcrumbs;
+}
diff --git a/src/components/card.tsx b/src/components/card.tsx
index b17746da26ed1f..a266aa63aba00a 100644
--- a/src/components/card.tsx
+++ b/src/components/card.tsx
@@ -19,7 +19,7 @@ export function Card({
}) {
return (
-