Files
supabase/apps/studio/components/ui/HelpPanel/HelpOptionsList.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

148 lines
4.5 KiB
TypeScript

import { ActivityIcon, BookOpenIcon, ChevronRightIcon, MailIcon, WrenchIcon } from 'lucide-react'
import { useRouter } from 'next/router'
import type { ReactNode } from 'react'
import SVG from 'react-inlinesvg'
import { AiIconAnimation } from 'ui'
import type { HelpOptionId } from './HelpPanel.constants'
import { HELP_OPTION_IDS } from './HelpPanel.constants'
import type { SupportFormUrlKeys } from '@/components/interfaces/Support/SupportForm.utils'
import { createSupportFormUrl } from '@/components/interfaces/Support/SupportForm.utils'
import { ResourceItem } from '@/components/ui/Resource/ResourceItem'
import { ResourceList } from '@/components/ui/Resource/ResourceList'
import { takeBreadcrumbSnapshot } from '@/lib/breadcrumbs'
import { DOCS_URL } from '@/lib/constants'
const DISCORD_URL = 'https://discord.supabase.com'
const STATUS_URL = 'https://status.supabase.com'
type HelpOptionsListProps = {
excludeIds?: HelpOptionId[]
isPlatform: boolean
projectRef: string | undefined
supportLinkQueryParams: Partial<SupportFormUrlKeys> | undefined
onAssistantClick?: () => void
onSupportClick?: () => boolean | void
}
type HelpOption = {
media: ReactNode
title: string
description: string
href?: string
onClick?: () => void
}
export const HelpOptionsList = ({
excludeIds = [],
isPlatform,
projectRef,
supportLinkQueryParams,
onAssistantClick,
onSupportClick,
}: HelpOptionsListProps) => {
const router = useRouter()
const basePath = router.basePath ?? ''
const ids = HELP_OPTION_IDS.filter((id) => !excludeIds.includes(id))
const include = (id: HelpOptionId): boolean => {
if (id === 'assistant') return !!projectRef
if (id === 'status' || id === 'support') return isPlatform
return true
}
const filteredIds = ids.filter(include)
const handleSupportClick = () => {
const shouldNavigate = onSupportClick?.()
if (shouldNavigate === false) {
return
}
takeBreadcrumbSnapshot()
router.push(createSupportFormUrl(supportLinkQueryParams ?? {}))
}
const renderOption = (title: string, description: string) => (
<div className="flex flex-col gap-0.5">
<p className="text-sm text-foreground">{title}</p>
<p className="text-xs text-foreground-lighter">{description}</p>
</div>
)
const options: Record<HelpOptionId, HelpOption> = {
assistant: {
media: <AiIconAnimation allowHoverEffect size={14} />,
title: 'Supabase Assistant',
description: 'Get guided help with your project directly in Studio.',
onClick: onAssistantClick,
},
docs: {
media: <BookOpenIcon strokeWidth={1.5} size={14} />,
title: 'Docs',
description: 'Browse guides, references, and product documentation.',
href: `${DOCS_URL}/`,
},
troubleshooting: {
media: <WrenchIcon strokeWidth={1.5} size={14} />,
title: 'Troubleshooting',
description: 'Find fixes for common platform issues and errors.',
href: `${DOCS_URL}/guides/troubleshooting?products=platform`,
},
discord: {
media: <SVG src={`${basePath}/img/discord-icon.svg`} className="h-4 w-4" />,
title: 'Ask on Discord',
description: 'Get help from the community on code-related questions.',
href: DISCORD_URL,
},
status: {
media: <ActivityIcon strokeWidth={1.5} size={14} />,
title: 'Supabase status',
description: 'Check incidents, maintenance, and uptime updates.',
href: STATUS_URL,
},
support: {
media: <MailIcon strokeWidth={1.5} size={14} />,
title: 'Contact support',
description: 'Reach support for account and platform issues.',
onClick: handleSupportClick,
},
}
return (
<ResourceList className="rounded-none border-0 bg-transparent shadow-none">
{filteredIds.map((id) => {
const option = options[id]
if (option.href) {
return (
<ResourceItem
key={id}
className="!border-b"
media={option.media}
meta={<ChevronRightIcon strokeWidth={1.5} size={16} />}
href={option.href}
target="_blank"
rel="noreferrer noopener"
>
{renderOption(option.title, option.description)}
</ResourceItem>
)
}
return (
<ResourceItem
key={id}
className="!border-b"
media={option.media}
onClick={option.onClick}
>
{renderOption(option.title, option.description)}
</ResourceItem>
)
})}
</ResourceList>
)
}