feat: add 'Use with LLM' dropdown to doc pages#597
feat: add 'Use with LLM' dropdown to doc pages#597data-cowwboy wants to merge 4 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR introduces a new "Use with LLM" dropdown component that provides four AI-related actions (ChatGPT, Claude, copy page, view markdown) within documentation pages. The component includes state management for dropdown visibility and copy feedback, with fallback handling for fetch errors. Integration into the doc item layout adds the dropdown alongside synthetic titles when available. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Adds a dropdown button on every doc page with options to open the page in ChatGPT or Claude, copy the raw markdown source to clipboard, and view the page as plain markdown via GitHub raw URL.
- Fix button colors for dark mode (light blue bg, dark text) - Use correct logo SVG for the AI assistant option - Update LLM prompt to "Read from <url> so I can ask questions about it" - Fetch raw markdown from GitHub for copy/view actions
dd8d29a to
102c4bc
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/components/AiActionsDropdown/index.tsx (1)
76-77: Consider handling the case wheneditUrlis not available.When
rawUrlis falsy (noeditUrlprovided), clicking "Copy page" closes the dropdown without any feedback. Consider either:
- Using the fallback (copy article text) when
rawUrlis unavailable, or- Disabling the copy button when
editUrlis not provided♻️ Option 1: Always attempt fallback when rawUrl unavailable
const copyPage = async () => { - if (rawUrl) { - try { - const res = await fetch(rawUrl) - const md = await res.text() + try { + if (rawUrl) { + const res = await fetch(rawUrl) + if (!res.ok) throw new Error(`HTTP ${res.status}`) + const md = await res.text() await navigator.clipboard.writeText(md) - setCopied(true) - setTimeout(() => setCopied(false), 2000) - } catch { - // Fallback: copy article text if fetch fails + } else { const article = document.querySelector('article') - if (article) { - await navigator.clipboard.writeText(article.innerText) - setCopied(true) - setTimeout(() => setCopied(false), 2000) - } + if (article) await navigator.clipboard.writeText(article.innerText) } + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } catch { + // Fallback: copy article text if fetch fails + const article = document.querySelector('article') + if (article) { + await navigator.clipboard.writeText(article.innerText) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } } setOpen(false) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/AiActionsDropdown/index.tsx` around lines 76 - 77, The copyPage handler currently assumes rawUrl/editUrl exists and silently closes the dropdown when missing; update the copyPage function to first check rawUrl (and/or editUrl) and if absent fall back to copying the article text (call the existing copyArticleText or copyToClipboard helper) and provide user feedback instead of just closing, and also update the AiActionsDropdown button rendering to disable the "Copy page" button when neither rawUrl nor article text is available so the action cannot be triggered; reference the copyPage function, rawUrl/editUrl variables, and the copyArticleText/copyToClipboard helper to locate where to add the fallback and disable logic.skills/cow-swap-order-creator.md (1)
531-531:signHashis deprecated in newer eth_account versions.The
acct.signHash(msg_hash)method is deprecated ineth_account>= 0.6.0. Consider noting this in the tooling section or usingacct.unsafe_sign_hash()for the newer API (which makes the security implications explicit).The tooling notes at lines 603-605 partially address version differences but could be more explicit about
signHashdeprecation.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/cow-swap-order-creator.md` at line 531, The current use of acct.signHash(msg_hash) is deprecated in eth_account >= 0.6.0; update the implementation to call acct.unsafe_sign_hash(msg_hash) when targeting newer eth_account releases (and ensure callers are aware of the security implications), or add a clear tooling note explaining the version-specific API change and advising use of acct.unsafe_sign_hash versus acct.signHash for older versions; update the documentation/tooling section that references version differences (the note around the existing tooling lines) to explicitly mention the deprecation of signHash and recommend unsafe_sign_hash when appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/AiActionsDropdown/index.tsx`:
- Around line 76-95: In copyPage, the fetch response is read without checking
HTTP status so error pages may be copied; after awaiting fetch(rawUrl) check
res.ok and if false throw or fall through to the existing catch/fallback logic
(or explicitly use the fallback path) instead of calling res.text() for non-OK
responses; update references to res and rawUrl within copyPage to ensure only
successful responses are copied to clipboard and retain the existing article
fallback behavior.
- Around line 64-74: Update the openInChatGPT function to remove the
undocumented hints=search parameter and use a supported/fallback query pattern
(e.g., use only ?q=... like `https://chatgpt.com/?q=${q}` or
`https://chat.openai.com/?q=${q}`), and add a simple fallback strategy in
openInChatGPT that tries the primary URL and, if it fails to load or is
unreliable, opens the alternative URL; keep openInClaude unchanged. Locate the
openInChatGPT function and replace the URL construction accordingly and add a
lightweight fallback attempt/alternative open to ensure resiliency.
---
Nitpick comments:
In `@skills/cow-swap-order-creator.md`:
- Line 531: The current use of acct.signHash(msg_hash) is deprecated in
eth_account >= 0.6.0; update the implementation to call
acct.unsafe_sign_hash(msg_hash) when targeting newer eth_account releases (and
ensure callers are aware of the security implications), or add a clear tooling
note explaining the version-specific API change and advising use of
acct.unsafe_sign_hash versus acct.signHash for older versions; update the
documentation/tooling section that references version differences (the note
around the existing tooling lines) to explicitly mention the deprecation of
signHash and recommend unsafe_sign_hash when appropriate.
In `@src/components/AiActionsDropdown/index.tsx`:
- Around line 76-77: The copyPage handler currently assumes rawUrl/editUrl
exists and silently closes the dropdown when missing; update the copyPage
function to first check rawUrl (and/or editUrl) and if absent fall back to
copying the article text (call the existing copyArticleText or copyToClipboard
helper) and provide user feedback instead of just closing, and also update the
AiActionsDropdown button rendering to disable the "Copy page" button when
neither rawUrl nor article text is available so the action cannot be triggered;
reference the copyPage function, rawUrl/editUrl variables, and the
copyArticleText/copyToClipboard helper to locate where to add the fallback and
disable logic.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
skills/cow-swap-order-creator.mdsrc/components/AiActionsDropdown/index.tsxsrc/components/AiActionsDropdown/styles.module.csssrc/theme/DocItem/Layout/index.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/components/AiActionsDropdown/styles.module.css (1)
106-108: Hardcoded green color for copied state.The
#16a34a(green) for the copied state could use a CSS variable for consistency with the design system, though hardcoding success colors is common practice..copied .itemLabel { - color: `#16a34a`; + color: var(--ifm-color-success, `#16a34a`); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/AiActionsDropdown/styles.module.css` around lines 106 - 108, Replace the hardcoded green in the .copied .itemLabel rule with the design-system CSS variable (e.g., use var(--color-success) or the project's standard success token such as var(--success-500)); update the .copied .itemLabel declaration in src/components/AiActionsDropdown/styles.module.css to reference that variable so the copied state color follows the global theme instead of `#16a34a`.src/components/AiActionsDropdown/index.tsx (2)
55-55: Consider memoizingpageUrlto avoid recalculation on every render.While this is a minor concern,
window.location.hrefis read on every render. UsinguseMemowould be cleaner, though the performance impact is negligible.- const pageUrl = typeof window !== 'undefined' ? window.location.href : '' + const pageUrl = React.useMemo( + () => (typeof window !== 'undefined' ? window.location.href : ''), + [] + )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/AiActionsDropdown/index.tsx` at line 55, Memoize the computed pageUrl to avoid reading window.location.href each render: inside the AiActionsDropdown component replace the direct const pageUrl = typeof window !== 'undefined' ? window.location.href : '' with a useMemo that returns the same value (guarding typeof window) and import/use React's useMemo; keep the fallback '' behavior so server-side renders remain safe and ensure the memo has an empty dependency array so it only computes once.
76-95: No user feedback whenrawUrlis unavailable and copy is silently skipped.If
rawUrlis falsy (noeditUrlprovided), clicking "Copy page" closes the dropdown without any feedback. Consider either hiding the button whenrawUrlis unavailable, or providing fallback behavior.🔧 Suggested fix - fallback to article text when no rawUrl
const copyPage = async () => { - if (rawUrl) { - try { - const res = await fetch(rawUrl) - const md = await res.text() - await navigator.clipboard.writeText(md) - setCopied(true) - setTimeout(() => setCopied(false), 2000) - } catch { - // Fallback: copy article text if fetch fails - const article = document.querySelector('article') - if (article) { - await navigator.clipboard.writeText(article.innerText) - setCopied(true) - setTimeout(() => setCopied(false), 2000) - } + try { + if (rawUrl) { + const res = await fetch(rawUrl) + if (!res.ok) throw new Error(`HTTP ${res.status}`) + const md = await res.text() + await navigator.clipboard.writeText(md) + } else { + throw new Error('No raw URL') } + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } catch { + // Fallback: copy article text if fetch fails or no rawUrl + const article = document.querySelector('article') + if (article) { + await navigator.clipboard.writeText(article.innerText) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } } setOpen(false) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/AiActionsDropdown/index.tsx` around lines 76 - 95, The copyPage handler currently does nothing when rawUrl is falsy which closes the dropdown with no feedback; update copyPage (or the rendering of the "Copy page" button) to handle that case by falling back to copying the article text when rawUrl is unavailable: inside copyPage, if rawUrl is falsy query document.querySelector('article'), copy its innerText via navigator.clipboard.writeText, call setCopied(true) and reset with setTimeout as done for the fetch path, and still call setOpen(false) at the end; alternatively (if you prefer hiding/disable), conditionally hide/disable the button in the component render based on rawUrl and provide an aria-label/tooltip to explain why it’s disabled (use the same setCopied/setOpen behavior for consistent UX).src/theme/DocItem/Layout/index.tsx (1)
11-11: Consider extracting inline style to CSS module for consistency.The inline style works but could be co-located with the component's styles for maintainability. This is a minor style consistency suggestion.
// In styles.module.css: // .dropdownWrapper { display: flex; justify-content: flex-end; margin-bottom: -8px; } // Then: // <div className={styles.dropdownWrapper}>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/theme/DocItem/Layout/index.tsx` at line 11, Extract the inline style on the div in the Layout component (the element with style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: -8 }}) into a CSS module: add a class like .dropdownWrapper { display: flex; justify-content: flex-end; margin-bottom: -8px; } in a co-located styles.module.css, import it (e.g. import styles from './styles.module.css') into src/theme/DocItem/Layout/index.tsx and replace the inline style with className={styles.dropdownWrapper}; ensure the unit px is included for margin-bottom and update any existing imports to avoid naming conflicts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/AiActionsDropdown/index.tsx`:
- Line 106: The dropdown trigger button in AiActionsDropdown currently toggles
open via setOpen(!open) but lacks accessibility attributes; update the button
(the element using className={styles.trigger} and the open/state setter setOpen)
to include aria-expanded={open} (ensure it's a boolean) and aria-haspopup="menu"
(or appropriate popup type) so assistive tech knows the expanded state and role
of the control.
---
Nitpick comments:
In `@src/components/AiActionsDropdown/index.tsx`:
- Line 55: Memoize the computed pageUrl to avoid reading window.location.href
each render: inside the AiActionsDropdown component replace the direct const
pageUrl = typeof window !== 'undefined' ? window.location.href : '' with a
useMemo that returns the same value (guarding typeof window) and import/use
React's useMemo; keep the fallback '' behavior so server-side renders remain
safe and ensure the memo has an empty dependency array so it only computes once.
- Around line 76-95: The copyPage handler currently does nothing when rawUrl is
falsy which closes the dropdown with no feedback; update copyPage (or the
rendering of the "Copy page" button) to handle that case by falling back to
copying the article text when rawUrl is unavailable: inside copyPage, if rawUrl
is falsy query document.querySelector('article'), copy its innerText via
navigator.clipboard.writeText, call setCopied(true) and reset with setTimeout as
done for the fetch path, and still call setOpen(false) at the end; alternatively
(if you prefer hiding/disable), conditionally hide/disable the button in the
component render based on rawUrl and provide an aria-label/tooltip to explain
why it’s disabled (use the same setCopied/setOpen behavior for consistent UX).
In `@src/components/AiActionsDropdown/styles.module.css`:
- Around line 106-108: Replace the hardcoded green in the .copied .itemLabel
rule with the design-system CSS variable (e.g., use var(--color-success) or the
project's standard success token such as var(--success-500)); update the .copied
.itemLabel declaration in src/components/AiActionsDropdown/styles.module.css to
reference that variable so the copied state color follows the global theme
instead of `#16a34a`.
In `@src/theme/DocItem/Layout/index.tsx`:
- Line 11: Extract the inline style on the div in the Layout component (the
element with style={{ display: 'flex', justifyContent: 'flex-end', marginBottom:
-8 }}) into a CSS module: add a class like .dropdownWrapper { display: flex;
justify-content: flex-end; margin-bottom: -8px; } in a co-located
styles.module.css, import it (e.g. import styles from './styles.module.css')
into src/theme/DocItem/Layout/index.tsx and replace the inline style with
className={styles.dropdownWrapper}; ensure the unit px is included for
margin-bottom and update any existing imports to avoid naming conflicts.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/components/AiActionsDropdown/index.tsxsrc/components/AiActionsDropdown/styles.module.csssrc/theme/DocItem/Layout/index.tsx
- Check res.ok before copying fetched markdown to prevent copying error page HTML on 404s - Remove undocumented hints=search param from ChatGPT URL
|
@fairlighteth done.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/components/AiActionsDropdown/styles.module.css (1)
100-103: Increase helper text contrast for light mode.The description text on Line 100-103 is still relatively faint. Bumping one emphasis step improves readability and better matches docs body contrast.
💡 Proposed fix
.itemDesc { font-size: 0.75rem; - color: var(--ifm-color-emphasis-700); + color: var(--ifm-color-emphasis-800); line-height: 1.3; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/AiActionsDropdown/styles.module.css` around lines 100 - 103, Update the .itemDesc rule to use a higher-contrast emphasis token for light mode by changing its color from var(--ifm-color-emphasis-700) to var(--ifm-color-emphasis-600); if your project uses a light-mode scope (e.g., .theme-light or :root when not dark), apply the var(--ifm-color-emphasis-600) specifically under that scope so only light mode increases helper text contrast while leaving dark mode unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/AiActionsDropdown/styles.module.css`:
- Around line 20-23: Remove the CSS Modules :global() wrapper from the
dark-theme selector so stylelint stops flagging the pseudo-class; change the
selector from ":global(html[data-theme='dark']) .trigger" to
"html[data-theme='dark'] .trigger" in styles.module.css so the .trigger rule
remains scoped by CSS Modules but avoids the unknown pseudo-class error.
In `@src/theme/DocItem/Content/index.tsx`:
- Around line 31-34: The inline style using marginBottom: -16 on the wrapper div
(rendered when !syntheticTitle) is a fragile layout hack; remove the negative
margin and replace it with a predictable spacing rule—either add a className to
the div and define a margin or padding in CSS/SCSS, or use a container spacing
layout (e.g., gap, padding, or a dedicated utility class) so AiActionsDropdown
(with prop metadata.editUrl) aligns without overlapping surrounding content;
update the JSX around syntheticTitle and AiActionsDropdown to use that
class/utility and adjust the surrounding component spacing accordingly.
---
Nitpick comments:
In `@src/components/AiActionsDropdown/styles.module.css`:
- Around line 100-103: Update the .itemDesc rule to use a higher-contrast
emphasis token for light mode by changing its color from
var(--ifm-color-emphasis-700) to var(--ifm-color-emphasis-600); if your project
uses a light-mode scope (e.g., .theme-light or :root when not dark), apply the
var(--ifm-color-emphasis-600) specifically under that scope so only light mode
increases helper text contrast while leaving dark mode unchanged.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/components/AiActionsDropdown/index.tsxsrc/components/AiActionsDropdown/styles.module.csssrc/theme/DocItem/Content/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/AiActionsDropdown/index.tsx
| :global(html[data-theme='dark']) .trigger { | ||
| background: #CAE9FF; | ||
| color: #052B65; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find stylelint configuration files
echo "=== Searching for stylelint config files ==="
fd -HI "stylelint.config.*"
fd -HI ".stylelintrc*"
echo ""
# Search for relevant rules and patterns in the codebase
echo "=== Searching for selector-pseudo-class-no-unknown and CSS Modules references ==="
rg -n "selector-pseudo-class-no-unknown|ignorePseudoClasses|postcss-css-modules|stylelint-config-css-modules" -S
echo ""
echo "=== Searching for :global usage in CSS ==="
rg ":global\(" -S --type cssRepository: cowprotocol/docs
Length of output: 344
🏁 Script executed:
#!/bin/bash
# Read the stylelint config
echo "=== Content of .stylelintrc.json ==="
cat -n .stylelintrc.json
echo ""
# Check package.json for stylelint plugins and CSS Modules support
echo "=== Searching package.json for stylelint-related dependencies ==="
rg "stylelint|postcss|css-modules" package.json -A 2 -B 2Repository: cowprotocol/docs
Length of output: 1379
🏁 Script executed:
#!/bin/bash
# Verify the file is indeed a CSS Module
ls -la src/components/AiActionsDropdown/styles.module.css
echo ""
# Search for CI configuration files that might run stylelint
echo "=== Searching for CI/lint config files ==="
fd -HI "\.github|\.gitlab-ci|\.circleci|\.travis|lint" --type f | head -20
echo ""
# Check if there's any package.json and what scripts it has
echo "=== Checking for lint scripts in package.json ==="
rg "\"lint\"|\"stylelint\"" package.json -A 1 -B 1Repository: cowprotocol/docs
Length of output: 272
🏁 Script executed:
#!/bin/bash
cat -n src/components/AiActionsDropdown/styles.module.cssRepository: cowprotocol/docs
Length of output: 2575
🏁 Script executed:
#!/bin/bash
# Check for GitHub Actions workflows
find .github -type f -name "*.yml" -o -name "*.yaml" 2>/dev/null | head -10
# If .github doesn't exist, search more broadly
if [ ! -d .github ]; then
echo "No .github directory found"
fd -HI "\.yml|\.yaml" --type f | grep -i "workflow\|ci\|lint\|action" | head -10
fiRepository: cowprotocol/docs
Length of output: 207
🏁 Script executed:
#!/bin/bash
# Search GitHub workflows for stylelint or lint commands
echo "=== Searching workflow files for stylelint/lint ==="
rg "stylelint|lint|build" .github/workflows/ -i
echo ""
# Also check if there's a package.json with build/lint scripts
echo "=== Checking package.json for all scripts ==="
rg "\"scripts\"" -A 20 package.jsonRepository: cowprotocol/docs
Length of output: 981
Remove the :global() wrapper to resolve the stylelint selector pseudo-class issue.
The selector uses :global(html[data-theme='dark']) which triggers selector-pseudo-class-no-unknown because the current stylelint config extends stylelint-config-standard-scss without CSS Modules support. Since html is a global element and doesn't require wrapping, the selector can be simplified to html[data-theme='dark'] with no functional change. The .trigger class will remain properly scoped by CSS Modules.
Suggested fix
-:global(html[data-theme='dark']) .trigger {
+html[data-theme='dark'] .trigger {
background: `#CAE9FF`;
color: `#052B65`;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| :global(html[data-theme='dark']) .trigger { | |
| background: #CAE9FF; | |
| color: #052B65; | |
| } | |
| html[data-theme='dark'] .trigger { | |
| background: `#CAE9FF`; | |
| color: `#052B65`; | |
| } |
🧰 Tools
🪛 Stylelint (17.3.0)
[error] 20-20: Unexpected unknown pseudo-class selector ":global" (selector-pseudo-class-no-unknown)
(selector-pseudo-class-no-unknown)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/AiActionsDropdown/styles.module.css` around lines 20 - 23,
Remove the CSS Modules :global() wrapper from the dark-theme selector so
stylelint stops flagging the pseudo-class; change the selector from
":global(html[data-theme='dark']) .trigger" to "html[data-theme='dark']
.trigger" in styles.module.css so the .trigger rule remains scoped by CSS
Modules but avoids the unknown pseudo-class error.
| {!syntheticTitle && ( | ||
| <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: -16 }}> | ||
| <AiActionsDropdown editUrl={metadata.editUrl} /> | ||
| </div> |
There was a problem hiding this comment.
Avoid negative margin layout hack on Line 32.
marginBottom: -16 can cause content overlap/spacing drift across pages. Use normal spacing (or a class-based layout rule) for predictable rendering.
💡 Proposed fix
- {!syntheticTitle && (
- <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: -16 }}>
+ {!syntheticTitle && (
+ <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 8 }}>
<AiActionsDropdown editUrl={metadata.editUrl} />
</div>
)}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {!syntheticTitle && ( | |
| <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: -16 }}> | |
| <AiActionsDropdown editUrl={metadata.editUrl} /> | |
| </div> | |
| {!syntheticTitle && ( | |
| <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 8 }}> | |
| <AiActionsDropdown editUrl={metadata.editUrl} /> | |
| </div> | |
| )} |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/theme/DocItem/Content/index.tsx` around lines 31 - 34, The inline style
using marginBottom: -16 on the wrapper div (rendered when !syntheticTitle) is a
fragile layout hack; remove the negative margin and replace it with a
predictable spacing rule—either add a className to the div and define a margin
or padding in CSS/SCSS, or use a container spacing layout (e.g., gap, padding,
or a dedicated utility class) so AiActionsDropdown (with prop metadata.editUrl)
aligns without overlapping surrounding content; update the JSX around
syntheticTitle and AiActionsDropdown to use that class/utility and adjust the
surrounding component spacing accordingly.




Summary
Implementation
src/components/AiActionsDropdown/DocItem/Layoutto inject the dropdown on all doc pageseditUrlconfig to derive raw GitHub URLsTest plan
yarn startand verify dropdown appears on doc pagesSummary by CodeRabbit