final polish phase 1
This commit is contained in:
112
frontend/src/components/dashboard/WorkflowPipelineWidget.tsx
Normal file
112
frontend/src/components/dashboard/WorkflowPipelineWidget.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* WorkflowPipelineWidget - Visual flow showing content creation pipeline
|
||||
* Sites → Keywords → Clusters → Ideas → Tasks → Drafts → Published
|
||||
* Balanced single-row layout with filled arrow connectors
|
||||
*/
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ProgressBar } from '../ui/progress';
|
||||
import {
|
||||
GridIcon,
|
||||
ListIcon,
|
||||
GroupIcon,
|
||||
BoltIcon,
|
||||
CheckCircleIcon,
|
||||
FileTextIcon,
|
||||
PaperPlaneIcon,
|
||||
ChevronRightIcon,
|
||||
} from '../../icons';
|
||||
|
||||
export interface PipelineData {
|
||||
sites: number;
|
||||
keywords: number;
|
||||
clusters: number;
|
||||
ideas: number;
|
||||
tasks: number;
|
||||
drafts: number;
|
||||
published: number;
|
||||
completionPercentage: number;
|
||||
}
|
||||
|
||||
interface WorkflowPipelineWidgetProps {
|
||||
data: PipelineData;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const stages = [
|
||||
{ key: 'sites', label: 'Sites', icon: GridIcon, href: '/sites', color: 'text-blue-600 dark:text-blue-400' },
|
||||
{ key: 'keywords', label: 'Keywords', icon: ListIcon, href: '/planner/keywords', color: 'text-blue-600 dark:text-blue-400' },
|
||||
{ key: 'clusters', label: 'Clusters', icon: GroupIcon, href: '/planner/clusters', color: 'text-purple-600 dark:text-purple-400' },
|
||||
{ key: 'ideas', label: 'Ideas', icon: BoltIcon, href: '/planner/ideas', color: 'text-orange-600 dark:text-orange-400' },
|
||||
{ key: 'tasks', label: 'Tasks', icon: CheckCircleIcon, href: '/writer/tasks', color: 'text-indigo-600 dark:text-indigo-400' },
|
||||
{ key: 'drafts', label: 'Drafts', icon: FileTextIcon, href: '/writer/content', color: 'text-green-600 dark:text-green-400' },
|
||||
{ key: 'published', label: 'Published', icon: PaperPlaneIcon, href: '/writer/published', color: 'text-emerald-600 dark:text-emerald-400' },
|
||||
] as const;
|
||||
|
||||
// Small filled arrow triangle component
|
||||
function ArrowTip() {
|
||||
return (
|
||||
<div className="flex items-center justify-center w-4 h-4 mx-1">
|
||||
<svg viewBox="0 0 8 12" className="w-2.5 h-3.5 fill-brand-500 dark:fill-brand-400">
|
||||
<path d="M0 0 L8 6 L0 12 Z" />
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function WorkflowPipelineWidget({ data, loading }: WorkflowPipelineWidgetProps) {
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-800 p-5">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between mb-5">
|
||||
<h3 className="text-base font-semibold text-gray-800 dark:text-gray-200 uppercase tracking-wide">
|
||||
Workflow Pipeline
|
||||
</h3>
|
||||
<span className="text-3xl font-bold text-brand-600 dark:text-brand-400">
|
||||
{data.completionPercentage}%
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Pipeline Flow - Single Balanced Row */}
|
||||
<div className="flex items-center justify-between mb-5">
|
||||
{stages.map((stage, index) => {
|
||||
const Icon = stage.icon;
|
||||
const count = data[stage.key as keyof PipelineData];
|
||||
|
||||
return (
|
||||
<div key={stage.key} className="flex items-center">
|
||||
<Link
|
||||
to={stage.href}
|
||||
className="flex flex-col items-center group min-w-[60px]"
|
||||
>
|
||||
<div className="p-2.5 rounded-lg bg-gray-50 dark:bg-gray-800 group-hover:bg-brand-50 dark:group-hover:bg-brand-900/20 transition-colors border border-transparent group-hover:border-brand-200 dark:group-hover:border-brand-800">
|
||||
<Icon className={`w-6 h-6 ${stage.color}`} />
|
||||
</div>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300 mt-1.5 font-medium">
|
||||
{stage.label}
|
||||
</span>
|
||||
<span className={`text-lg font-bold ${stage.color}`}>
|
||||
{loading ? '—' : typeof count === 'number' ? count.toLocaleString() : count}
|
||||
</span>
|
||||
</Link>
|
||||
{index < stages.length - 1 && <ArrowTip />}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Progress Bar */}
|
||||
<div className="mt-4">
|
||||
<ProgressBar
|
||||
value={data.completionPercentage}
|
||||
size="md"
|
||||
color="primary"
|
||||
className="h-2.5"
|
||||
/>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 mt-2 text-center">
|
||||
{data.completionPercentage}% of keywords converted to published content
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user