mirror of
https://github.com/supabase/supabase.git
synced 2026-10-17 07:09:07 +03:00
## 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). ```
89 lines
2.2 KiB
TypeScript
89 lines
2.2 KiB
TypeScript
import { ArrowRightIcon, Loader2Icon, SquareIcon, XIcon, type LucideIcon } from 'lucide-react'
|
|
import { cn } from 'ui'
|
|
|
|
export interface ReplicationState {
|
|
isComingUp: boolean
|
|
isReplicating: boolean
|
|
isFailed: boolean
|
|
}
|
|
|
|
export interface EdgeVisual {
|
|
Icon: LucideIcon
|
|
// CSS color shared by the icon and the connecting line so they always match.
|
|
color: string
|
|
opacity: number
|
|
dashArray: string
|
|
strokeWidth: number
|
|
shouldAnimate: boolean
|
|
shouldSpin?: boolean
|
|
isFilled?: boolean
|
|
}
|
|
|
|
// Picks the icon + line appearance for a replication state. Both the icon and the line are derived
|
|
// here from the same state so they always stay in sync. We deliberately don't surface lag: the line
|
|
// just communicates whether data is moving, stopped, starting, or broken.
|
|
export const getEdgeVisual = ({
|
|
isComingUp,
|
|
isReplicating,
|
|
isFailed,
|
|
}: ReplicationState): EdgeVisual => {
|
|
if (isFailed) {
|
|
return {
|
|
Icon: XIcon,
|
|
color: 'hsl(var(--destructive-default))',
|
|
opacity: 1,
|
|
dashArray: '5 5',
|
|
shouldAnimate: false,
|
|
strokeWidth: 4,
|
|
}
|
|
}
|
|
if (isComingUp) {
|
|
return {
|
|
Icon: Loader2Icon,
|
|
color: 'var(--foreground-light)',
|
|
opacity: 1,
|
|
dashArray: '5',
|
|
strokeWidth: 2,
|
|
shouldAnimate: true,
|
|
shouldSpin: true,
|
|
}
|
|
}
|
|
if (isReplicating) {
|
|
return {
|
|
Icon: ArrowRightIcon,
|
|
color: 'var(--primary-bright)',
|
|
opacity: 1,
|
|
dashArray: '5',
|
|
strokeWidth: 2,
|
|
shouldAnimate: true,
|
|
}
|
|
}
|
|
return {
|
|
Icon: SquareIcon,
|
|
color: 'var(--foreground-lighter)',
|
|
opacity: 0.5,
|
|
dashArray: '5 5',
|
|
strokeWidth: 2,
|
|
shouldAnimate: false,
|
|
isFilled: true,
|
|
}
|
|
}
|
|
|
|
/** The round icon chip rendered mid-edge, bordered in the edge's color. */
|
|
export const EdgeVisualChip = ({ visual }: { visual: EdgeVisual }) => {
|
|
const { Icon, color, shouldSpin, isFilled } = visual
|
|
|
|
return (
|
|
<div
|
|
className="w-6 h-6 rounded-full flex items-center justify-center border bg-surface-100"
|
|
style={{ borderColor: color }}
|
|
>
|
|
<Icon
|
|
size={14}
|
|
className={cn(shouldSpin && 'motion-safe:animate-spin')}
|
|
style={{ color, fill: isFilled ? color : undefined }}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|