mirror of
https://github.com/supabase/supabase.git
synced 2026-09-09 19:42:46 +08:00
## What kind of change does this PR introduce? UI polish for the Connect sheet: clearer mode selection, wider sheet layout, and step/content chrome across Direct, Server, MCP, and shadcn flows. ## What is the current behavior? - Connect modes use a weak selected state and an awkward grid layout. - The sheet can jump width below the `lg` breakpoint when switching modes. - Direct connection chrome is noisy (reset in a footer, Title Case / mono pooler labels, mismatched copy-button sizes). - Several steps use admonitions or extra tips that repeat footer guidance. - Case-sensitive import of `InlineLink` breaks Linux/Vercel builds. ## What is the new behavior? ### Mode selector and sheet - Stronger selected/hover treatment; comfortable single row that wraps via `@container`. - Empty odd slots use a sunk placeholder cell. - Sheet uses `size="lg"` with `max-w-4xl` and `w-full min-w-0` so width stays stable when switching modes. ### Steps chrome - “Follow these steps” header with a copy-prompt action for coding agents. - Optional steps labelled `(optional)`. - Shared `CodeBlock` for install snippets; MCP feature groups preselect all except Storage. - Server / shadcn tips folded into footers; IPv4 add-on admonition is responsive with an inline Learn more link and a single Enable action. ### Direct connection - Connection string and connection parameters stay one step (same credentials, two formats). - Reset database password lives in the string card title row beside Shared/Dedicated pooler. - Card titles use sans + sentence case (`Shared pooler`, `Connection parameters`); `.env` stays mono. - Icon-only copy buttons match CodeBlock square sizing; row actions sit slightly closer to the right edge (`pr-2`). - Shared pooler toggle copy clarified. | Before | After | | --- | --- | | <img width="390" height="763" alt="API Keys Settings Chisel Toolshed Supabase" src="https://github.com/user-attachments/assets/adca3cc5-94f8-47e5-a4a2-2831790f430a" /> | <img width="390" height="763" alt="API Keys Settings Chisel Toolshed Supabase" src="https://github.com/user-attachments/assets/f03afe58-e654-435e-a821-835f6243ca95" /> | | <img width="1718" height="1323" alt="API Keys Settings Chisel Toolshed Supabase" src="https://github.com/user-attachments/assets/79f08620-7e1e-4246-a70f-801606c0f499" /> | <img width="1718" height="1323" alt="API Keys Settings Chisel Toolshed Supabase" src="https://github.com/user-attachments/assets/fb45e851-955e-46c2-90f1-afecb93d6ac4" /> | | <img width="1718" height="1323" alt="API Keys Settings Chisel Toolshed Supabase" src="https://github.com/user-attachments/assets/eda36d21-bba7-46ab-ad48-134acf93b471" /> | <img width="1718" height="1323" alt="API Keys Settings Chisel Toolshed Supabase" src="https://github.com/user-attachments/assets/b7b728c6-fc92-46a7-8e3f-2f182c56ece7" /> | ### Test plan - [ ] Open **Connect** and confirm mode cells select/hover clearly; narrow the sheet and confirm wrap + stable width. - [ ] Direct: switch Direct / Transaction / Session; confirm pooler title, reset in title row, parameters table, and percent-encode note. - [ ] Toggle IPv4 shared pooler on Transaction; confirm string updates and admonition/Learn more behaviour when on IPv4-only paths. - [ ] Server: `.env` Copy all / row copy sizing; install command copy. - [ ] MCP / shadcn / Framework: steps still resolve and copy prompt still builds a useful agent prompt. - [ ] Spot-check light/dark and a Linux/Vercel build (InlineLink import casing).
81 lines
1.9 KiB
TypeScript
81 lines
1.9 KiB
TypeScript
import { Check, Copy } from 'lucide-react'
|
|
import { ComponentProps, forwardRef, useEffect, useState } from 'react'
|
|
import { Button, cn, copyToClipboard } from 'ui'
|
|
|
|
type CopyButtonBaseProps = {
|
|
iconOnly?: boolean
|
|
copyLabel?: string
|
|
copiedLabel?: string
|
|
}
|
|
|
|
type CopyButtonWithText = CopyButtonBaseProps & {
|
|
text: string
|
|
asyncText?: never
|
|
}
|
|
|
|
type CopyButtonWithAsyncText = CopyButtonBaseProps & {
|
|
text?: never
|
|
asyncText: () => Promise<string> | string
|
|
}
|
|
|
|
export type CopyButtonProps = (CopyButtonWithText | CopyButtonWithAsyncText) &
|
|
ComponentProps<typeof Button>
|
|
|
|
const CopyButton = forwardRef<HTMLButtonElement, CopyButtonProps>(
|
|
(
|
|
{
|
|
text,
|
|
asyncText,
|
|
iconOnly = false,
|
|
children,
|
|
onClick,
|
|
copyLabel = 'Copy',
|
|
copiedLabel = 'Copied',
|
|
variant = 'primary',
|
|
icon,
|
|
className,
|
|
...props
|
|
},
|
|
ref
|
|
) => {
|
|
const [showCopied, setShowCopied] = useState(false)
|
|
|
|
useEffect(() => {
|
|
if (!showCopied) return
|
|
const timer = setTimeout(() => setShowCopied(false), 2000)
|
|
return () => clearTimeout(timer)
|
|
}, [showCopied])
|
|
|
|
return (
|
|
<Button
|
|
ref={ref}
|
|
onClick={(e) => {
|
|
const textToCopy = asyncText ? asyncText() : text
|
|
setShowCopied(true)
|
|
copyToClipboard(textToCopy)
|
|
onClick?.(e)
|
|
}}
|
|
{...props}
|
|
variant={variant}
|
|
className={cn({ 'px-1.5': iconOnly }, className)}
|
|
icon={
|
|
showCopied ? (
|
|
<Check
|
|
strokeWidth={2}
|
|
className={cn(variant === 'primary' ? 'text-inherit' : 'text-brand')}
|
|
/>
|
|
) : (
|
|
(icon ?? <Copy />)
|
|
)
|
|
}
|
|
>
|
|
{!iconOnly && <>{children ?? (showCopied ? copiedLabel : copyLabel)}</>}
|
|
</Button>
|
|
)
|
|
}
|
|
)
|
|
|
|
CopyButton.displayName = 'CopyButton'
|
|
|
|
export default CopyButton
|