OpenMAIC-React / src /components /chat /inline-action-tag.tsx
muthuk1's picture
Convert OpenMAIC from Next.js to React (Vite)
f56a29b verified
import { cn } from '@/lib/utils';
import {
Flashlight,
MousePointer2,
Type,
Shapes,
Eraser,
PanelLeftOpen,
PanelLeftClose,
MessageSquare,
Zap,
Loader2,
BarChart3,
Sigma,
Table2,
PenLine,
Trash2,
Play,
Minus,
Code2,
FileCode,
} from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
interface InlineActionTagProps {
actionName: string;
state: string;
}
// ── Style tokens ──────────────────────────────────────────────
const WB_STYLE =
'bg-violet-50 dark:bg-violet-500/15 border-violet-300/40 dark:border-violet-500/30 text-violet-600 dark:text-violet-300';
const WB_ACCENT = 'bg-violet-500 dark:bg-violet-400';
const SPOTLIGHT_STYLE =
'bg-yellow-50 dark:bg-yellow-500/15 border-yellow-300/40 dark:border-yellow-500/30 text-yellow-700 dark:text-yellow-300';
const LASER_STYLE =
'bg-red-50 dark:bg-red-500/15 border-red-300/40 dark:border-red-500/30 text-red-600 dark:text-red-300';
const DISCUSS_STYLE =
'bg-amber-50 dark:bg-amber-500/15 border-amber-300/40 dark:border-amber-500/30 text-amber-700 dark:text-amber-300';
const DEFAULT_STYLE =
'bg-gray-50 dark:bg-gray-500/15 border-gray-300/40 dark:border-gray-500/30 text-gray-600 dark:text-gray-300';
// ── Action config ─────────────────────────────────────────────
interface ActionCfg {
label: string;
Icon: LucideIcon;
style: string;
/** Whiteboard family β€” gets the pen-line accent indicator */
wb?: boolean;
}
const ACTION_CONFIG: Record<string, ActionCfg> = {
// Slide effects
spotlight: { label: 'Spotlight', Icon: Flashlight, style: SPOTLIGHT_STYLE },
laser: { label: 'Laser', Icon: MousePointer2, style: LASER_STYLE },
play_video: { label: 'Play', Icon: Play, style: SPOTLIGHT_STYLE },
// Whiteboard lifecycle
wb_open: { label: 'Open', Icon: PanelLeftOpen, style: WB_STYLE, wb: true },
wb_close: { label: 'Close', Icon: PanelLeftClose, style: WB_STYLE, wb: true },
wb_clear: { label: 'Clear', Icon: Eraser, style: WB_STYLE, wb: true },
wb_delete: { label: 'Delete', Icon: Trash2, style: WB_STYLE, wb: true },
// Whiteboard drawing
wb_draw_text: { label: 'Text', Icon: Type, style: WB_STYLE, wb: true },
wb_draw_shape: { label: 'Shape', Icon: Shapes, style: WB_STYLE, wb: true },
wb_draw_chart: { label: 'Chart', Icon: BarChart3, style: WB_STYLE, wb: true },
wb_draw_latex: { label: 'Formula', Icon: Sigma, style: WB_STYLE, wb: true },
wb_draw_table: { label: 'Table', Icon: Table2, style: WB_STYLE, wb: true },
wb_draw_line: { label: 'Line', Icon: Minus, style: WB_STYLE, wb: true },
wb_draw_code: { label: 'Code', Icon: Code2, style: WB_STYLE, wb: true },
wb_edit_code: { label: 'Edit Code', Icon: FileCode, style: WB_STYLE, wb: true },
// Social
discussion: { label: 'Discuss', Icon: MessageSquare, style: DISCUSS_STYLE },
};
// ── Component ─────────────────────────────────────────────────
export function InlineActionTag({ actionName, state }: InlineActionTagProps) {
const config = ACTION_CONFIG[actionName];
const Icon = config?.Icon || Zap;
const label = config?.label || actionName;
const style = config?.style || DEFAULT_STYLE;
const isWb = config?.wb ?? false;
const isRunning = state === 'running' || state === 'input-available';
return (
<span
className={cn(
'inline-flex items-center mx-1 rounded-full border align-middle leading-none whitespace-nowrap',
'text-[9px] font-bold tracking-wide',
// Slightly tighter padding when wb accent is present (accent provides left visual weight)
isWb ? 'pl-0.5 pr-1.5 py-px' : 'px-1.5 py-px',
style,
isRunning && 'animate-pulse',
)}
>
{/* Whiteboard accent: tiny PenLine chip on the left */}
{isWb && (
<span
className={cn(
'inline-flex items-center justify-center rounded-full mr-0.5 shrink-0',
'w-3 h-3',
WB_ACCENT,
)}
>
<PenLine className="w-[7px] h-[7px] text-white dark:text-violet-950" strokeWidth={2.5} />
</span>
)}
{/* Action icon */}
{isRunning ? (
<Loader2 className="w-2.5 h-2.5 animate-spin shrink-0" />
) : (
<Icon className="w-2.5 h-2.5 shrink-0" />
)}
<span className="ml-0.5">{label}</span>
</span>
);
}