Files
supabase/apps/studio/components/interfaces/Compute/ComputeInstanceSnippetTabs.tsx
T
Joshen Lim 09a1f431bc Mass update for all lucide icon imports to use the component with Icon suffix (#51659)
## Context

This is largely just a mechanical change here:
Opting to use lucide icons with the `Icon` suffix across all icon
imports within `studio`
- so that it’s clearer which components are icons + reduces the
possibility of name collision with our own components
- e.g <User /> vs <UserIcon />

Also added a eslint rule for this:
<img width="1069" height="167" alt="image"
src="https://github.com/user-attachments/assets/7f36f443-5ca2-4bf6-8d22-86e774513bfc"
/>

And updated `AGENTS.md` as such:
```
Icons come from `lucide-react`, always imported with the `Icon` suffix (`import { CheckIcon, Trash2Icon } from 'lucide-react'`) — never the bare names (`Check`) or `Check as CheckIcon` aliases (lint-enforced).
```
2026-10-14 12:56:55 +02:00

116 lines
3.5 KiB
TypeScript

import { useParams } from 'common'
import { FileCodeIcon, SparklesIcon, TerminalIcon, type LucideIcon } from 'lucide-react'
import { useState } from 'react'
import { cn } from 'ui'
import {
buildComputeInstanceSnippets,
type ComputeInstanceSnippetInput,
} from './computeInstanceSnippets'
import CopyButton from '@/components/ui/CopyButton'
import { useProjectSettingsV2Query } from '@/data/config/project-settings-v2-query'
export type ComputeInstanceSnippetTab = 'ai' | 'config' | 'cli' | 'curl' | 'js' | 'python'
export const COMPUTE_INSTANCE_CALL_TABS = [
'curl',
'js',
'python',
] as const satisfies readonly ComputeInstanceSnippetTab[]
const TAB_LABEL: Record<ComputeInstanceSnippetTab, string> = {
ai: 'AI Prompt',
config: 'config.toml',
cli: 'CLI',
curl: 'cURL',
js: 'JavaScript',
python: 'Python',
}
const TAB_ICON: Record<ComputeInstanceSnippetTab, LucideIcon> = {
ai: SparklesIcon,
config: FileCodeIcon,
cli: TerminalIcon,
curl: TerminalIcon,
js: FileCodeIcon,
python: FileCodeIcon,
}
interface ComputeInstanceSnippetTabsProps {
input: Omit<ComputeInstanceSnippetInput, 'endpoint' | 'protocol'>
tabs?: readonly [ComputeInstanceSnippetTab, ...ComputeInstanceSnippetTab[]]
className?: string
}
export const ComputeInstanceSnippetTabs = ({
input,
tabs = ['cli'],
className,
}: ComputeInstanceSnippetTabsProps) => {
const { ref } = useParams()
const [active, setActive] = useState<ComputeInstanceSnippetTab>(tabs[0])
const { data: settings } = useProjectSettingsV2Query({ projectRef: ref }, { enabled: !!ref })
const snippets = buildComputeInstanceSnippets({
...input,
endpoint: settings?.app_config?.endpoint,
protocol: settings?.app_config?.protocol,
})
const snippetByTab: Record<ComputeInstanceSnippetTab, string> = {
ai: snippets.aiPrompt,
config: snippets.configToml,
cli: snippets.cli,
curl: snippets.curl,
js: snippets.javascript,
python: snippets.python,
}
const activeTab = tabs.includes(active) ? active : tabs[0]
const value = snippetByTab[activeTab]
return (
<div className={cn('flex flex-col gap-y-2', className)}>
<div className="flex items-center gap-x-4 border-b border-default">
{tabs.map((tab) => {
const Icon = TAB_ICON[tab]
return (
<button
key={tab}
type="button"
tabIndex={0}
onClick={() => setActive(tab)}
className={cn(
'-mb-px flex items-center gap-1.5 border-b px-0.5 py-1.5 text-sm transition-colors',
tab === activeTab
? 'border-foreground text-foreground'
: 'border-transparent text-foreground-lighter hover:text-foreground-light'
)}
>
<Icon size={14} strokeWidth={1.5} />
{TAB_LABEL[tab]}
</button>
)
})}
</div>
<div className="relative rounded-md border border-default bg-surface-100">
<CopyButton
text={value}
iconOnly
variant="text"
aria-label="Copy snippet"
className="absolute right-2 top-2 text-foreground-lighter hover:text-foreground"
/>
{activeTab === 'ai' ? (
<p className="overflow-x-auto whitespace-pre-wrap p-3 pr-10 text-sm leading-relaxed text-foreground-light">
{value}
</p>
) : (
<pre className="overflow-x-auto p-3 pr-10 font-mono text-xs leading-relaxed text-foreground-light">
{value}
</pre>
)}
</div>
</div>
)
}