mirror of
https://github.com/supabase/supabase.git
synced 2026-10-09 03:15:06 +03:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? This PR reworks the `/guides/ai-tools` docs section to be agent-first. The overview now leads with the fastest path to a working setup (the plugin install command), a "What's supported?" card grid showing which coding agents and IDEs work via Plugin and/or MCP (with each product's own tagline, not a generated sentence), and a concepts glossary — instead of a plain four-item list. The sidebar "AI Tools" widget, shown on every guides page, now links to this hub ("Connect your AI agent") instead of opening a ChatGPT/Claude chat frontend. Closes DOCS-1201. ## What is the current behavior? - The `/guides/ai-tools` overview is a plain four-item bullet list with no getting-started path, compatibility info, or concepts explanation. - The sidebar "AI Tools" widget offers "Copy as Markdown", "Ask ChatGPT", and "Ask Claude" — the latter two send you to a chat frontend instead of agent setup. ## What is the new behavior? - `ai-tools.mdx`: intro → plugin install callout → "What's supported?" card grid (`<ContentListings id="ai-tools-supported-agents" />`, icon + tagline + Plugin/MCP badge per agent) → "Key concepts" glossary → "Building AI into your app?" (also converted to `ContentListings`). - New `data/content-listings/ai-tools.data.ts` builds the card grid from the existing `PLUGIN_CLIENTS`/`MCP_CLIENT_DATA` client lists (no new hand-maintained data) — fixing two latent bugs found along the way: GitHub Copilot was keyed differently between the two sources (would have produced duplicate cards), and Windsurf has no upstream docs URL (would have been silently dropped). - New opt-in `badgePosition` field on `ContentListingItem` so the badge renders under the title for the agent grid, without changing the one other existing badge usage (self-hosting's "Official" tag, still inline). - `plugins.mdx`/`mcp.mdx`/`ai-skills.mdx` each get a one-line "Quick start" lead-in so they stand alone via the `.md` content-negotiation route. - `GuidesSidebar.tsx` + `telemetry-constants.ts`: Added "Connect your AI agent" → `/guides/ai-tools`, and the `ask_ai_clicked` event with `agent_setup_clicked`. - Accessibility fix (from review): the "Not supported" indicator now exposes an `sr-only` label instead of being fully `aria-hidden`. ## Additional context - Worktree: `~/GitHub/supabase/supabase-worktrees/nikrichers/docs-1201-make-guidesai-tools-agent-first-and-replace-chat-frontend` - **Open question — Windsurf card**: `windsurf.com` now redirects to a Devin Desktop page (Cognition acquired Windsurf in 2025), but Supabase's own `MCP_CLIENT_DATA` still targets Windsurf's distinct config path (`~/.codeium/windsurf/mcp_config.json`), so the card is still labeled "Windsurf" with its pre-acquisition tagline ("The first agentic IDE. Tomorrow's editor, today."). Needs a follow-up decision on whether to relabel/merge/drop this card once Devin Desktop's MCP support (if any) is confirmed. - Follow-up (not in this PR): deeper IA rework of the ai-tools section belongs to the broader agent-first audit; `content/guides/resources/glossary.mdx` has no MCP/Agent Skills/Plugin/Prompts entries yet — this PR's "Key concepts" is currently the only definition of these terms site-wide. - Verification: | Check | Result | | --- | --- | | Lint (`lint:mdx`, `eslint`), `typecheck`, `test:local lib/content-listings.test.ts` | Pass — 13/13 tests, 0 errors | | `build:guides-markdown` | Pass — card grid flattens cleanly to markdown | | Playwright: broken icon requests, light + dark theme, PR preview | Pass — 0 in either theme | | `/guides/self-hosting` "Official" badge (existing `ContentListings` usage) | Pass — unaffected by the new `badgePosition` opt-in | ### Before & After #### [`/guides/ai-tools`](https://supabase.com/docs/guides/ai-tools) Also shows the sidebar change (right rail): "Ask ChatGPT" / "Ask Claude" → "Connect your AI agent". | [Before](https://supabase.com/docs/guides/ai-tools) | [After](https://docs-git-nikrichers-docs-1201-make-guidesai-too-7c7493-supabase.vercel.app/docs/guides/ai-tools) | | --- | --- | |  |  | Sub-pages each just add a one-line "Quick start" callout under the intro (no other layout change): [plugins](https://supabase.com/docs/guides/ai-tools/plugins) ([preview](https://docs-git-nikrichers-docs-1201-make-guidesai-too-7c7493-supabase.vercel.app/docs/guides/ai-tools/plugins)) · [mcp](https://supabase.com/docs/guides/ai-tools/mcp) ([preview](https://docs-git-nikrichers-docs-1201-make-guidesai-too-7c7493-supabase.vercel.app/docs/guides/ai-tools/mcp)) · [ai-skills](https://supabase.com/docs/guides/ai-tools/ai-skills) ([preview](https://docs-git-nikrichers-docs-1201-make-guidesai-too-7c7493-supabase.vercel.app/docs/guides/ai-tools/ai-skills)). ### Test plan - [x] `/guides/ai-tools` renders callout → card grid → concepts → Building AI into your app, in order - [x] Card grid: one card per agent (no duplicate Copilot), Windsurf present, icons clean in both themes, taglines shown, badges below title - [x] Sidebar shows "Connect your AI agent"; self-hosting's "Official" badge unaffected - [x] `.md` route still serves clean markdown; no lingering `ask_ai_clicked`, ChatGPT/Claude icon, or `SupportedAgentsTable` references --------- Co-authored-by: Nik Richers <nik@validmind.ai>
165 lines
5.0 KiB
TypeScript
165 lines
5.0 KiB
TypeScript
'use client'
|
|
|
|
import { Feedback } from '~/components/Feedback'
|
|
import { useSendTelemetryEvent } from '~/lib/telemetry'
|
|
import { isFeatureEnabled } from 'common'
|
|
import { Chatgpt, Claude } from 'icons'
|
|
import { Check, Copy, Sparkles } from 'lucide-react'
|
|
import Link from 'next/link'
|
|
import { usePathname } from 'next/navigation'
|
|
import { useState } from 'react'
|
|
import { cn } from 'ui'
|
|
import { ExpandableVideo } from 'ui-patterns/ExpandableVideo'
|
|
import { Toc, TOCItems, TOCScrollArea } from 'ui-patterns/Toc'
|
|
|
|
import { useTocAnchors } from '../features/docs/GuidesMdx.state'
|
|
|
|
interface TOCHeader {
|
|
id?: string
|
|
text: string
|
|
link: string
|
|
level: number
|
|
}
|
|
|
|
function AiTools({ className }: { className?: string }) {
|
|
const [copied, setCopied] = useState(false)
|
|
const path = usePathname()
|
|
const sendTelemetryEvent = useSendTelemetryEvent()
|
|
|
|
function handleAgentSetupClick() {
|
|
sendTelemetryEvent({ action: 'agent_setup_clicked' })
|
|
}
|
|
|
|
async function copyMarkdown() {
|
|
const mdUrl = `/docs/${path}.md`
|
|
|
|
try {
|
|
const res = await fetch(mdUrl)
|
|
let text: string
|
|
|
|
if (res.ok) {
|
|
text = await res.text()
|
|
} else {
|
|
// Default to HTML content within the article when no .md file is available.
|
|
text = document.getElementById('sb-docs-guide-main-article')?.innerHTML ?? ''
|
|
}
|
|
|
|
await navigator.clipboard.writeText(text)
|
|
setCopied(true)
|
|
setTimeout(() => setCopied(false), 2000)
|
|
} catch (error) {
|
|
console.error('Failed to copy markdown', error)
|
|
}
|
|
|
|
sendTelemetryEvent({
|
|
action: 'copy_as_markdown_clicked',
|
|
})
|
|
}
|
|
|
|
return (
|
|
<section className={cn(className)} aria-labelledby="ai-tools-title">
|
|
<h3
|
|
id="ai-tools-title"
|
|
className="block font-mono uppercase text-xs text-foreground-light mb-3"
|
|
>
|
|
AI Tools
|
|
</h3>
|
|
<div className="flex flex-col gap-2">
|
|
<Link
|
|
href="/guides/ai-tools"
|
|
onClick={handleAgentSetupClick}
|
|
className="flex items-center gap-1.5 text-xs text-foreground-lighter hover:text-foreground transition-colors"
|
|
>
|
|
<Sparkles size={14} strokeWidth={1.5} />
|
|
Connect your AI agent
|
|
</Link>
|
|
<button
|
|
tabIndex={0}
|
|
onClick={copyMarkdown}
|
|
className="flex items-center gap-1.5 text-xs text-foreground-lighter hover:text-foreground text-left transition-colors"
|
|
>
|
|
{copied ? (
|
|
<Check size={14} strokeWidth={1.5} className="text-brand" />
|
|
) : (
|
|
<Copy size={14} strokeWidth={1.5} />
|
|
)}
|
|
{copied ? 'Copied!' : 'Copy as Markdown'}
|
|
</button>
|
|
<a
|
|
href={`https://chatgpt.com/?hint=search&q=Read from https://supabase.com/docs${path} so I can ask questions about its contents`}
|
|
target="_blank"
|
|
onClick={() =>
|
|
sendTelemetryEvent({ action: 'ask_ai_clicked', properties: { agent: 'chatgpt' } })
|
|
}
|
|
rel="noreferrer noopener"
|
|
className="flex items-center gap-1.5 text-xs text-foreground-lighter hover:text-foreground transition-colors"
|
|
>
|
|
<Chatgpt size={14} />
|
|
Ask ChatGPT
|
|
</a>
|
|
<a
|
|
href={`https://claude.ai/new?q=Read from https://supabase.com/docs${path} so I can ask questions about its contents`}
|
|
target="_blank"
|
|
onClick={() =>
|
|
sendTelemetryEvent({ action: 'ask_ai_clicked', properties: { agent: 'claude' } })
|
|
}
|
|
rel="noreferrer noopener"
|
|
className="flex items-center gap-1.5 text-xs text-foreground-lighter hover:text-foreground transition-colors"
|
|
>
|
|
<Claude size={14} />
|
|
Ask Claude
|
|
</a>
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|
|
|
|
const GuidesSidebar = ({
|
|
className,
|
|
video,
|
|
hideToc,
|
|
}: {
|
|
className?: string
|
|
video?: string
|
|
hideToc?: boolean
|
|
}) => {
|
|
const pathname = usePathname()
|
|
const { toc } = useTocAnchors()
|
|
const showFeedback = isFeatureEnabled('feedback:docs')
|
|
const tocVideoPreview = `https://img.youtube.com/vi/${video}/0.jpg`
|
|
|
|
return (
|
|
<div className={cn('thin-scrollbar overflow-y-auto h-fit', 'px-px', className)}>
|
|
<div className="w-full relative border-l flex flex-col gap-6 lg:gap-8 px-2 h-fit">
|
|
{video && (
|
|
<div className="relative pl-5">
|
|
<ExpandableVideo imgUrl={tocVideoPreview} videoId={video} />
|
|
</div>
|
|
)}
|
|
{showFeedback && (
|
|
<div className="pl-5">
|
|
<Feedback key={pathname} />
|
|
</div>
|
|
)}
|
|
<div className="pl-5">
|
|
<AiTools key={pathname} />
|
|
</div>
|
|
{!hideToc && toc.length !== 0 && (
|
|
<Toc className="-ml-[calc(0.25rem+6px)]">
|
|
<h3 className="inline-flex items-center gap-1.5 font-mono text-xs uppercase text-foreground pl-[calc(1.5rem+6px)]">
|
|
On this page
|
|
</h3>
|
|
<TOCScrollArea>
|
|
<TOCItems items={toc} />
|
|
</TOCScrollArea>
|
|
</Toc>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default GuidesSidebar
|
|
export { GuidesSidebar }
|
|
export type { TOCHeader }
|