From 9c951df4b2651b01b8864d887283c3076cf878d9 Mon Sep 17 00:00:00 2001 From: Sergiy Dybskiy Date: Wed, 29 Jul 2026 10:45:04 -0400 Subject: [PATCH 01/21] Reapply "feat(homepage): Bifurcated homepage refresh" (#18870) This reverts commit fea20ccd0ac5bdb5a3d32f8cdcf48071ebd20b63. --- src/components/header.tsx | 36 +- src/components/home.tsx | 699 +++++++++++--------------------------- 2 files changed, 213 insertions(+), 522 deletions(-) diff --git a/src/components/header.tsx b/src/components/header.tsx index c51b32230da37e..9394770c0ba4f5 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -183,40 +183,16 @@ export function Header({ {/* define a header-height variable for consumption by other components */} ); } +function Arrow() { + return ( + + + + + ); +} + +function QuickLink({href, title, desc}: {desc: string; href: string; title: string}) { + return ( + +
{title}
+
{desc}
+ + ); +} + function FooterLink({ children, external, From 9168fc59483971c9e39b03d112b7d6b6f6447e9d Mon Sep 17 00:00:00 2001 From: Sergiy Dybskiy Date: Wed, 29 Jul 2026 08:40:17 -0400 Subject: [PATCH 02/21] feat(homepage): Add AI setup pill, full SDK list, and copy fixes Follow-ups to the bifurcated homepage refresh (#18786): - Replace the popular-SDK strip with the same filterable list /platforms/ uses, so every SDK, guide, and searchable integration is reachable from the homepage. - Rework the AI setup card around a click-to-copy pill for 'npx @sentry/ai install' (the installer from /ai/agent-plugin/), with Claude, Codex, and Cursor glyphs. Both cards now end in a single pill row so they match in height. - Move search and Ask AI out of the hero to a 'Not finding what you're looking for?' block below the quick links, and rewrite the hero tagline. - Point 'Set up manually' at /platforms/#platform-specific-docs instead of a same-page hash, which barely moved on tall viewports. - Drop the duplicate sidebar separator on SDK pages. SidebarNavigation and Sidebar each rendered one, left over from when product links sat between them. - Stop auto-opening the platform selector on /platforms/. Radix Select focuses the combobox and locks body scroll while open, so the page could not be scrolled. - Move the homepage styles into home.module.scss with theme tokens instead of an inline style block, reuse the /platforms/ search input and the agent callout's pill styling, and de-duplicate CopyIcon. - Track the homepage copy button under a new homepage_card metric source rather than mislabelling it as a callout. --- .../agentSetupCallout/checkIcon.tsx | 18 ++ src/components/agentSetupCallout/copyIcon.tsx | 19 ++ src/components/agentSetupCallout/index.tsx | 19 +- src/components/arrowRightIcon.tsx | 19 ++ src/components/copyPromptButton/index.tsx | 19 +- src/components/home.module.scss | 213 +++++++++++++++++ src/components/home.tsx | 224 ++++-------------- src/components/homeAiSetupCard.tsx | 92 +++++++ src/components/platformFilter/client.tsx | 5 +- src/components/platformSelector/index.tsx | 8 +- src/components/sidebar/sidebarNavigation.tsx | 17 +- src/icons/codex.tsx | 20 ++ src/icons/cursor.tsx | 16 ++ src/metrics.ts | 2 +- 14 files changed, 457 insertions(+), 234 deletions(-) create mode 100644 src/components/agentSetupCallout/checkIcon.tsx create mode 100644 src/components/agentSetupCallout/copyIcon.tsx create mode 100644 src/components/arrowRightIcon.tsx create mode 100644 src/components/home.module.scss create mode 100644 src/components/homeAiSetupCard.tsx create mode 100644 src/icons/codex.tsx create mode 100644 src/icons/cursor.tsx diff --git a/src/components/agentSetupCallout/checkIcon.tsx b/src/components/agentSetupCallout/checkIcon.tsx new file mode 100644 index 00000000000000..889b112b786371 --- /dev/null +++ b/src/components/agentSetupCallout/checkIcon.tsx @@ -0,0 +1,18 @@ +/** Confirmation glyph swapped in after a successful copy. */ +export function CheckIcon() { + return ( + + + + ); +} diff --git a/src/components/agentSetupCallout/copyIcon.tsx b/src/components/agentSetupCallout/copyIcon.tsx new file mode 100644 index 00000000000000..394e0c5bacd553 --- /dev/null +++ b/src/components/agentSetupCallout/copyIcon.tsx @@ -0,0 +1,19 @@ +/** Clipboard glyph shared by every "Copy Prompt" affordance. */ +export function CopyIcon() { + return ( + + + + + ); +} diff --git a/src/components/agentSetupCallout/index.tsx b/src/components/agentSetupCallout/index.tsx index 0b0129ef80e50c..145b5bc4f9f47b 100644 --- a/src/components/agentSetupCallout/index.tsx +++ b/src/components/agentSetupCallout/index.tsx @@ -8,6 +8,7 @@ import {usePlausibleEvent} from 'sentry-docs/hooks/usePlausibleEvent'; import {DocMetrics} from 'sentry-docs/metrics'; import {CodeBlock} from '../codeBlock'; +import {CopyIcon} from './copyIcon'; import {buildPrompt} from './shared'; import styles from './style.module.scss'; @@ -108,21 +109,3 @@ export function AgentSetupCallout({skill, platformName}: Props) { ); } - -function CopyIcon() { - return ( - - - - - ); -} diff --git a/src/components/arrowRightIcon.tsx b/src/components/arrowRightIcon.tsx new file mode 100644 index 00000000000000..c60dd0077cce2b --- /dev/null +++ b/src/components/arrowRightIcon.tsx @@ -0,0 +1,19 @@ +/** Inline "→" used by the homepage CTA links. */ +export function ArrowRightIcon() { + return ( + + + + + ); +} diff --git a/src/components/copyPromptButton/index.tsx b/src/components/copyPromptButton/index.tsx index 97543dc6cd6ea6..e3cd3f633edb0c 100644 --- a/src/components/copyPromptButton/index.tsx +++ b/src/components/copyPromptButton/index.tsx @@ -8,6 +8,7 @@ import {useCallback, useMemo, useState} from 'react'; import {usePlausibleEvent} from 'sentry-docs/hooks/usePlausibleEvent'; import {DocMetrics} from 'sentry-docs/metrics'; +import {CopyIcon} from '../agentSetupCallout/copyIcon'; import {buildPrompt} from '../agentSetupCallout/shared'; import styles from './style.module.scss'; @@ -117,21 +118,3 @@ export function CopyPromptButton({skill, platformName}: Props) { ); } - -function CopyIcon() { - return ( - - - - - ); -} diff --git a/src/components/home.module.scss b/src/components/home.module.scss new file mode 100644 index 00000000000000..4dccff2da07045 --- /dev/null +++ b/src/components/home.module.scss @@ -0,0 +1,213 @@ +// Styles for the homepage and its client sub-components (homeAiSetupCard, +// homeSdkPicker). Previously an inline ` ); } -function Arrow() { - return ( - - - - - ); -} - function QuickLink({href, title, desc}: {desc: string; href: string; title: string}) { return ( - +
{title}
{desc}
diff --git a/src/components/homeAiSetupCard.tsx b/src/components/homeAiSetupCard.tsx new file mode 100644 index 00000000000000..a1eabec1a62839 --- /dev/null +++ b/src/components/homeAiSetupCard.tsx @@ -0,0 +1,92 @@ +'use client'; + +import * as Sentry from '@sentry/nextjs'; +import Link from 'next/link'; +import {useCallback, useState} from 'react'; +import {usePlausibleEvent} from 'sentry-docs/hooks/usePlausibleEvent'; +import Claude from 'sentry-docs/icons/claude'; +import Codex from 'sentry-docs/icons/codex'; +import Cursor from 'sentry-docs/icons/cursor'; +import {DocMetrics} from 'sentry-docs/metrics'; + +import {CheckIcon} from './agentSetupCallout/checkIcon'; +import {CopyIcon} from './agentSetupCallout/copyIcon'; +import styles from './home.module.scss'; + +/** The installer from /ai/agent-plugin/ — keep the two in sync. */ +const INSTALL_COMMAND = 'npx @sentry/ai install'; + +/** + * Homepage counterpart to the "Set up manually" card: instead of prose, it hands + * the visitor the one command that wires the Sentry plugin into their agent. + */ +export function HomeAiSetupCard() { + const [copied, setCopied] = useState(false); + const {emit} = usePlausibleEvent(); + + const copyCommand = useCallback(async () => { + emit('Copy AI Prompt', { + props: {page: window.location.pathname, title: 'Homepage Setup Card'}, + }); + + try { + await navigator.clipboard.writeText(INSTALL_COMMAND); + setCopied(true); + DocMetrics.copyAIPrompt( + window.location.pathname, + undefined, + true, + 'homepage_card' + ); + setTimeout(() => setCopied(false), 1500); + } catch (error) { + Sentry.logger.warn('clipboard.writeText failed', { + error: (error as Error)?.message, + errorName: (error as Error)?.name, + }); + DocMetrics.copyAIPrompt( + window.location.pathname, + undefined, + false, + 'homepage_card' + ); + setCopied(false); + } + }, [emit]); + + return ( +
+
+ + + + +
+

Set up AI-utomatically

+

+ One command teaches Claude Code, Cursor, Codex, and Grok how to install and + configure Sentry for you. See the{' '} + + plugin docs + + . +

+ +
+ ); +} diff --git a/src/components/platformFilter/client.tsx b/src/components/platformFilter/client.tsx index 1661fb206745b0..f1a0c1e25e9efd 100644 --- a/src/components/platformFilter/client.tsx +++ b/src/components/platformFilter/client.tsx @@ -56,7 +56,10 @@ export function PlatformFilterClient({platforms}: {platforms: Platform[]}) {
-

Platform-specific docs

+ {/* id is the anchor the homepage's "Set up manually" card links to */} +

+ Platform-specific docs +

If you use it, we probably support it.

diff --git a/src/components/platformSelector/index.tsx b/src/components/platformSelector/index.tsx index e151f71d04c315..f76fa86704d5b2 100644 --- a/src/components/platformSelector/index.tsx +++ b/src/components/platformSelector/index.tsx @@ -84,10 +84,10 @@ export function PlatformSelector({ const currentPlatformKey = currentPlatform?.key; const pathname = usePathname(); - // Auto-open selector when on /platforms/ index page (no SDK selected) - const isOnPlatformsIndex = pathname === '/platforms/' || pathname === '/platforms'; - - const [open, setOpen] = useState(alwaysOpen || isOnPlatformsIndex); + // Deliberately NOT auto-opened on the /platforms/ index: the Radix Select + // focuses the combobox and locks body scroll while open, so opening it on + // mount stops the page from scrolling. The full SDK list is in the page body. + const [open, setOpen] = useState(alwaysOpen); const [searchValue, setSearchValue] = useState(''); const matches = useMemo(() => { diff --git a/src/components/sidebar/sidebarNavigation.tsx b/src/components/sidebar/sidebarNavigation.tsx index 6db0452bff65fa..36b10128739fed 100644 --- a/src/components/sidebar/sidebarNavigation.tsx +++ b/src/components/sidebar/sidebarNavigation.tsx @@ -4,7 +4,6 @@ import {getDocsRootNode, nodeForPath} from 'sentry-docs/docTree'; 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'; @@ -44,17 +43,17 @@ export async function SidebarNavigation({path}: {path: string[]}) { if (path[0] === 'platforms') { const platformName = path[1]; const guideName = path[3]; + // No trailing separator — Sidebar already renders one between the + // navigation and SidebarMoreLinks, and the product links that used to sit + // in between now live in the top-level header. return ( {platformName && ( - - - - + )} ); diff --git a/src/icons/codex.tsx b/src/icons/codex.tsx new file mode 100644 index 00000000000000..4f65d712278ce4 --- /dev/null +++ b/src/icons/codex.tsx @@ -0,0 +1,20 @@ +function Codex({width = 16, height = 16, ...props}: React.SVGAttributes) { + return ( + + Codex + + + ); +} +export default Codex; diff --git a/src/icons/cursor.tsx b/src/icons/cursor.tsx new file mode 100644 index 00000000000000..1c63049ed4ad92 --- /dev/null +++ b/src/icons/cursor.tsx @@ -0,0 +1,16 @@ +function Cursor({width = 16, height = 16, ...props}: React.SVGAttributes) { + return ( + + Cursor + + + ); +} +export default Cursor; diff --git a/src/metrics.ts b/src/metrics.ts index bf7eacd6da4ce5..cd77fc9a9bcd93 100644 --- a/src/metrics.ts +++ b/src/metrics.ts @@ -172,7 +172,7 @@ export const DocMetrics = { pathname: string, skill: string | undefined, success: boolean, - source: 'callout' | 'inline_link' = 'callout' + source: 'callout' | 'inline_link' | 'homepage_card' = 'callout' ) => { Sentry.metrics.count('docs.copy_ai_prompt', 1, { attributes: { From a0a4fc01a3f511301de28a8b8bc2094592b2b1d2 Mon Sep 17 00:00:00 2001 From: "getsantry[bot]" <66042841+getsantry[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2026 12:41:46 +0000 Subject: [PATCH 03/21] [getsentry/action-github-commit] Auto commit --- src/components/homeAiSetupCard.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/homeAiSetupCard.tsx b/src/components/homeAiSetupCard.tsx index a1eabec1a62839..f331b33b5604ef 100644 --- a/src/components/homeAiSetupCard.tsx +++ b/src/components/homeAiSetupCard.tsx @@ -32,12 +32,7 @@ export function HomeAiSetupCard() { try { await navigator.clipboard.writeText(INSTALL_COMMAND); setCopied(true); - DocMetrics.copyAIPrompt( - window.location.pathname, - undefined, - true, - 'homepage_card' - ); + DocMetrics.copyAIPrompt(window.location.pathname, undefined, true, 'homepage_card'); setTimeout(() => setCopied(false), 1500); } catch (error) { Sentry.logger.warn('clipboard.writeText failed', { From 8699111c39ecef5c2f05bcf6de5fe649610fc493 Mon Sep 17 00:00:00 2001 From: Sergiy Dybskiy Date: Wed, 29 Jul 2026 08:46:29 -0400 Subject: [PATCH 04/21] ref(homepage): Use react-feather icons instead of hand-rolled SVGs The copy, check, and arrow glyphs were inline SVGs. react-feather is already a dependency and is what the other copy buttons use (codeBlock, codeHighlights, copyableCard, apiExamples), so use Copy, Check, and ArrowRight from it. Removes three icon components, including two hand-rolled CopyIcon copies that predated this branch. --- .../agentSetupCallout/checkIcon.tsx | 18 ------------------ src/components/agentSetupCallout/copyIcon.tsx | 19 ------------------- src/components/agentSetupCallout/index.tsx | 4 ++-- src/components/arrowRightIcon.tsx | 19 ------------------- src/components/copyPromptButton/index.tsx | 4 ++-- src/components/home.tsx | 4 ++-- src/components/homeAiSetupCard.tsx | 5 ++--- 7 files changed, 8 insertions(+), 65 deletions(-) delete mode 100644 src/components/agentSetupCallout/checkIcon.tsx delete mode 100644 src/components/agentSetupCallout/copyIcon.tsx delete mode 100644 src/components/arrowRightIcon.tsx diff --git a/src/components/agentSetupCallout/checkIcon.tsx b/src/components/agentSetupCallout/checkIcon.tsx deleted file mode 100644 index 889b112b786371..00000000000000 --- a/src/components/agentSetupCallout/checkIcon.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/** Confirmation glyph swapped in after a successful copy. */ -export function CheckIcon() { - return ( - - - - ); -} diff --git a/src/components/agentSetupCallout/copyIcon.tsx b/src/components/agentSetupCallout/copyIcon.tsx deleted file mode 100644 index 394e0c5bacd553..00000000000000 --- a/src/components/agentSetupCallout/copyIcon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/** Clipboard glyph shared by every "Copy Prompt" affordance. */ -export function CopyIcon() { - return ( - - - - - ); -} diff --git a/src/components/agentSetupCallout/index.tsx b/src/components/agentSetupCallout/index.tsx index 145b5bc4f9f47b..703f8853d050ee 100644 --- a/src/components/agentSetupCallout/index.tsx +++ b/src/components/agentSetupCallout/index.tsx @@ -4,11 +4,11 @@ import {ChevronDownIcon, ChevronRightIcon} from '@radix-ui/react-icons'; import * as Sentry from '@sentry/nextjs'; import Link from 'next/link'; import {useCallback, useState} from 'react'; +import {Copy} from 'react-feather'; import {usePlausibleEvent} from 'sentry-docs/hooks/usePlausibleEvent'; import {DocMetrics} from 'sentry-docs/metrics'; import {CodeBlock} from '../codeBlock'; -import {CopyIcon} from './copyIcon'; import {buildPrompt} from './shared'; import styles from './style.module.scss'; @@ -67,7 +67,7 @@ export function AgentSetupCallout({skill, platformName}: Props) { {prompt}
diff --git a/src/components/arrowRightIcon.tsx b/src/components/arrowRightIcon.tsx deleted file mode 100644 index c60dd0077cce2b..00000000000000 --- a/src/components/arrowRightIcon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/** Inline "→" used by the homepage CTA links. */ -export function ArrowRightIcon() { - return ( - - - - - ); -} diff --git a/src/components/copyPromptButton/index.tsx b/src/components/copyPromptButton/index.tsx index e3cd3f633edb0c..21455df35cc220 100644 --- a/src/components/copyPromptButton/index.tsx +++ b/src/components/copyPromptButton/index.tsx @@ -5,10 +5,10 @@ import {Theme} from '@radix-ui/themes'; import * as Sentry from '@sentry/nextjs'; import {useTheme} from 'next-themes'; import {useCallback, useMemo, useState} from 'react'; +import {Copy} from 'react-feather'; import {usePlausibleEvent} from 'sentry-docs/hooks/usePlausibleEvent'; import {DocMetrics} from 'sentry-docs/metrics'; -import {CopyIcon} from '../agentSetupCallout/copyIcon'; import {buildPrompt} from '../agentSetupCallout/shared'; import styles from './style.module.scss'; @@ -99,7 +99,7 @@ export function CopyPromptButton({skill, platformName}: Props) { type="button" aria-label="Copy setup prompt for AI agents" > - + {copied ? 'Copied!' : 'Copy Prompt'} diff --git a/src/components/home.tsx b/src/components/home.tsx index 4649e69489eeac..c096381c0a72ef 100644 --- a/src/components/home.tsx +++ b/src/components/home.tsx @@ -1,8 +1,8 @@ import Link from 'next/link'; +import {ArrowRight} from 'react-feather'; import {Banner} from 'sentry-docs/components/banner'; import {extractPlatforms, getDocsRootNode} from 'sentry-docs/docTree'; -import {ArrowRightIcon} from './arrowRightIcon'; import AskAiSearchParams from './askAiSearchParams'; import {Header} from './header'; import styles from './home.module.scss'; @@ -84,7 +84,7 @@ export async function Home() {

Choose your platform - +
diff --git a/src/components/homeAiSetupCard.tsx b/src/components/homeAiSetupCard.tsx index f331b33b5604ef..ba27fc480e11e0 100644 --- a/src/components/homeAiSetupCard.tsx +++ b/src/components/homeAiSetupCard.tsx @@ -3,14 +3,13 @@ import * as Sentry from '@sentry/nextjs'; import Link from 'next/link'; import {useCallback, useState} from 'react'; +import {Check, Copy} from 'react-feather'; import {usePlausibleEvent} from 'sentry-docs/hooks/usePlausibleEvent'; import Claude from 'sentry-docs/icons/claude'; import Codex from 'sentry-docs/icons/codex'; import Cursor from 'sentry-docs/icons/cursor'; import {DocMetrics} from 'sentry-docs/metrics'; -import {CheckIcon} from './agentSetupCallout/checkIcon'; -import {CopyIcon} from './agentSetupCallout/copyIcon'; import styles from './home.module.scss'; /** The installer from /ai/agent-plugin/ — keep the two in sync. */ @@ -79,7 +78,7 @@ export function HomeAiSetupCard() { {INSTALL_COMMAND} - {copied ? : } + {copied ? : } From 0d666bcf8a76e7af0170f75d085fb752b0e8fc17 Mon Sep 17 00:00:00 2001 From: Sergiy Dybskiy Date: Wed, 29 Jul 2026 08:50:44 -0400 Subject: [PATCH 05/21] fix(homepage): Show header search on load and trim comments The header search initialised homeSearchVisible to true, which was correct when the search sat in the hero. Now that it is below the fold, the header affordance was suppressed until the IntersectionObserver ran. --- src/components/header.tsx | 3 ++- src/components/home.module.scss | 18 ++---------------- src/components/home.tsx | 7 +------ src/components/homeAiSetupCard.tsx | 6 +----- src/components/platformFilter/client.tsx | 1 - src/components/platformSelector/index.tsx | 4 +--- src/components/sidebar/sidebarNavigation.tsx | 4 +--- 7 files changed, 8 insertions(+), 35 deletions(-) diff --git a/src/components/header.tsx b/src/components/header.tsx index 9394770c0ba4f5..5252a525569604 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -49,7 +49,8 @@ export function Header({ platforms = [], }: Props) { const isHomePage = pathname === '/'; - const [homeSearchVisible, setHomeSearchVisible] = useState(true); + // Homepage search is below the fold, so the header search starts visible. + const [homeSearchVisible, setHomeSearchVisible] = useState(false); const [homeMobileNavOpen, setHomeMobileNavOpen] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false); const [mobileSearchOpen, setMobileSearchOpen] = useState(false); diff --git a/src/components/home.module.scss b/src/components/home.module.scss index 4dccff2da07045..eca916ca96b48e 100644 --- a/src/components/home.module.scss +++ b/src/components/home.module.scss @@ -1,6 +1,3 @@ -// Styles for the homepage and its client sub-components (homeAiSetupCard, -// homeSdkPicker). Previously an inline `