final polish phase 1

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-27 21:27:37 +00:00
parent 627938aa95
commit 5f9a4b8dca
25 changed files with 3286 additions and 1397 deletions

View 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>
);
}