feat: upgrade EmptyState component with illustration and learn more support
Add illustration and learnMoreLink props to EmptyState (backward compatible). Create EmptyStateIllustrations.tsx with 7 brand-themed SVG illustrations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,23 +1,51 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface EmptyStateProps {
|
||||
icon?: ReactNode
|
||||
illustration?: ReactNode
|
||||
title: string
|
||||
description?: string
|
||||
action?: ReactNode
|
||||
learnMoreLink?: string
|
||||
learnMoreText?: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function EmptyState({ icon, title, description, action, className }: EmptyStateProps) {
|
||||
export function EmptyState({
|
||||
icon,
|
||||
illustration,
|
||||
title,
|
||||
description,
|
||||
action,
|
||||
learnMoreLink,
|
||||
learnMoreText = 'Learn more',
|
||||
className,
|
||||
}: EmptyStateProps) {
|
||||
return (
|
||||
<div className={cn('flex flex-col items-center justify-center py-12 text-center', className)}>
|
||||
{icon && <div className="mb-4 text-muted-foreground">{icon}</div>}
|
||||
{illustration && (
|
||||
<div className="mb-6 opacity-60">
|
||||
{illustration}
|
||||
</div>
|
||||
)}
|
||||
{!illustration && icon && (
|
||||
<div className="mb-4 text-muted-foreground">{icon}</div>
|
||||
)}
|
||||
<h3 className="text-lg font-semibold text-foreground">{title}</h3>
|
||||
{description && (
|
||||
<p className="mt-1 max-w-sm text-sm text-muted-foreground">{description}</p>
|
||||
<p className="mt-2 max-w-sm text-sm text-muted-foreground">{description}</p>
|
||||
)}
|
||||
{action && <div className="mt-4">{action}</div>}
|
||||
{learnMoreLink && (
|
||||
<Link
|
||||
to={learnMoreLink}
|
||||
className="mt-3 text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
{learnMoreText} →
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
130
frontend/src/components/common/EmptyStateIllustrations.tsx
Normal file
130
frontend/src/components/common/EmptyStateIllustrations.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* SVG illustrations for EmptyState components.
|
||||
* Each uses the brand cyan palette (#06b6d4 / #22d3ee) at low opacity.
|
||||
* ViewBox: 80x60, simple line art style.
|
||||
*/
|
||||
|
||||
export function FlowIllustration() {
|
||||
return (
|
||||
<svg width="80" height="60" viewBox="0 0 80 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
{/* Root node */}
|
||||
<circle cx="40" cy="10" r="6" fill="rgba(6,182,212,0.15)" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
{/* Branches */}
|
||||
<line x1="40" y1="16" x2="20" y2="34" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
<line x1="40" y1="16" x2="60" y2="34" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
{/* Left child */}
|
||||
<circle cx="20" cy="38" r="5" fill="rgba(6,182,212,0.15)" stroke="#22d3ee" strokeWidth="1.5" />
|
||||
{/* Right child */}
|
||||
<circle cx="60" cy="38" r="5" fill="rgba(6,182,212,0.15)" stroke="#22d3ee" strokeWidth="1.5" />
|
||||
{/* Leaf branches */}
|
||||
<line x1="20" y1="43" x2="12" y2="52" stroke="#22d3ee" strokeWidth="1" />
|
||||
<line x1="20" y1="43" x2="28" y2="52" stroke="#22d3ee" strokeWidth="1" />
|
||||
<circle cx="12" cy="54" r="3" fill="rgba(34,211,238,0.15)" stroke="#22d3ee" strokeWidth="1" />
|
||||
<circle cx="28" cy="54" r="3" fill="rgba(34,211,238,0.15)" stroke="#22d3ee" strokeWidth="1" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function AnalyticsIllustration() {
|
||||
return (
|
||||
<svg width="80" height="60" viewBox="0 0 80 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
{/* Bars */}
|
||||
<rect x="12" y="38" width="10" height="16" rx="2" fill="rgba(6,182,212,0.15)" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
<rect x="26" y="28" width="10" height="26" rx="2" fill="rgba(6,182,212,0.15)" stroke="#22d3ee" strokeWidth="1.5" />
|
||||
<rect x="40" y="20" width="10" height="34" rx="2" fill="rgba(6,182,212,0.15)" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
<rect x="54" y="10" width="10" height="44" rx="2" fill="rgba(6,182,212,0.15)" stroke="#22d3ee" strokeWidth="1.5" />
|
||||
{/* Baseline */}
|
||||
<line x1="8" y1="56" x2="72" y2="56" stroke="#06b6d4" strokeWidth="1" opacity="0.5" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function SessionIllustration() {
|
||||
return (
|
||||
<svg width="80" height="60" viewBox="0 0 80 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
{/* Card 1 */}
|
||||
<rect x="12" y="8" width="56" height="12" rx="3" fill="rgba(6,182,212,0.15)" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
<circle cx="22" cy="14" r="2" fill="#06b6d4" />
|
||||
<line x1="28" y1="14" x2="56" y2="14" stroke="#06b6d4" strokeWidth="1" opacity="0.5" />
|
||||
{/* Card 2 */}
|
||||
<rect x="12" y="24" width="56" height="12" rx="3" fill="rgba(6,182,212,0.15)" stroke="#22d3ee" strokeWidth="1.5" />
|
||||
<circle cx="22" cy="30" r="2" fill="#22d3ee" />
|
||||
<line x1="28" y1="30" x2="52" y2="30" stroke="#22d3ee" strokeWidth="1" opacity="0.5" />
|
||||
{/* Card 3 */}
|
||||
<rect x="12" y="40" width="56" height="12" rx="3" fill="rgba(6,182,212,0.15)" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
<circle cx="22" cy="46" r="2" fill="#06b6d4" />
|
||||
<line x1="28" y1="46" x2="48" y2="46" stroke="#06b6d4" strokeWidth="1" opacity="0.5" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function IntegrationIllustration() {
|
||||
return (
|
||||
<svg width="80" height="60" viewBox="0 0 80 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
{/* Left box */}
|
||||
<rect x="6" y="18" width="22" height="24" rx="4" fill="rgba(6,182,212,0.15)" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
<line x1="12" y1="26" x2="22" y2="26" stroke="#06b6d4" strokeWidth="1" opacity="0.6" />
|
||||
<line x1="12" y1="30" x2="20" y2="30" stroke="#06b6d4" strokeWidth="1" opacity="0.4" />
|
||||
{/* Right box */}
|
||||
<rect x="52" y="18" width="22" height="24" rx="4" fill="rgba(6,182,212,0.15)" stroke="#22d3ee" strokeWidth="1.5" />
|
||||
<line x1="58" y1="26" x2="68" y2="26" stroke="#22d3ee" strokeWidth="1" opacity="0.6" />
|
||||
<line x1="58" y1="30" x2="66" y2="30" stroke="#22d3ee" strokeWidth="1" opacity="0.4" />
|
||||
{/* Dashed arrows */}
|
||||
<line x1="30" y1="26" x2="50" y2="26" stroke="#06b6d4" strokeWidth="1.5" strokeDasharray="3 2" />
|
||||
<line x1="50" y1="34" x2="30" y2="34" stroke="#22d3ee" strokeWidth="1.5" strokeDasharray="3 2" />
|
||||
{/* Arrow tips */}
|
||||
<path d="M48 23 L52 26 L48 29" stroke="#06b6d4" strokeWidth="1.5" fill="none" />
|
||||
<path d="M32 31 L28 34 L32 37" stroke="#22d3ee" strokeWidth="1.5" fill="none" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function StepLibraryIllustration() {
|
||||
return (
|
||||
<svg width="80" height="60" viewBox="0 0 80 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
{/* List items */}
|
||||
<circle cx="18" cy="14" r="3" fill="rgba(6,182,212,0.15)" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
<line x1="26" y1="14" x2="62" y2="14" stroke="#06b6d4" strokeWidth="1.5" opacity="0.5" />
|
||||
<circle cx="18" cy="27" r="3" fill="rgba(6,182,212,0.15)" stroke="#22d3ee" strokeWidth="1.5" />
|
||||
<line x1="26" y1="27" x2="58" y2="27" stroke="#22d3ee" strokeWidth="1.5" opacity="0.5" />
|
||||
<circle cx="18" cy="40" r="3" fill="rgba(6,182,212,0.15)" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
<line x1="26" y1="40" x2="54" y2="40" stroke="#06b6d4" strokeWidth="1.5" opacity="0.5" />
|
||||
<circle cx="18" cy="53" r="3" fill="rgba(34,211,238,0.15)" stroke="#22d3ee" strokeWidth="1.5" />
|
||||
<line x1="26" y1="53" x2="50" y2="53" stroke="#22d3ee" strokeWidth="1.5" opacity="0.5" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function ScriptIllustration() {
|
||||
return (
|
||||
<svg width="80" height="60" viewBox="0 0 80 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
{/* Terminal window */}
|
||||
<rect x="8" y="4" width="64" height="52" rx="4" fill="rgba(6,182,212,0.15)" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
{/* Title bar */}
|
||||
<line x1="8" y1="14" x2="72" y2="14" stroke="#06b6d4" strokeWidth="1" opacity="0.3" />
|
||||
<circle cx="16" cy="9" r="2" fill="#06b6d4" opacity="0.4" />
|
||||
<circle cx="23" cy="9" r="2" fill="#22d3ee" opacity="0.4" />
|
||||
{/* Code lines */}
|
||||
<line x1="16" y1="22" x2="40" y2="22" stroke="#06b6d4" strokeWidth="1.5" opacity="0.6" />
|
||||
<line x1="20" y1="30" x2="52" y2="30" stroke="#22d3ee" strokeWidth="1.5" opacity="0.5" />
|
||||
<line x1="20" y1="38" x2="46" y2="38" stroke="#06b6d4" strokeWidth="1.5" opacity="0.4" />
|
||||
<line x1="16" y1="46" x2="36" y2="46" stroke="#22d3ee" strokeWidth="1.5" opacity="0.5" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function ShareIllustration() {
|
||||
return (
|
||||
<svg width="80" height="60" viewBox="0 0 80 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
{/* Center node */}
|
||||
<circle cx="28" cy="30" r="8" fill="rgba(6,182,212,0.15)" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
{/* Top-right node */}
|
||||
<circle cx="58" cy="14" r="6" fill="rgba(6,182,212,0.15)" stroke="#22d3ee" strokeWidth="1.5" />
|
||||
{/* Bottom-right node */}
|
||||
<circle cx="58" cy="46" r="6" fill="rgba(6,182,212,0.15)" stroke="#22d3ee" strokeWidth="1.5" />
|
||||
{/* Connecting lines */}
|
||||
<line x1="35" y1="25" x2="52" y2="17" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
<line x1="35" y1="35" x2="52" y2="43" stroke="#06b6d4" strokeWidth="1.5" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user