final polish phase 1
This commit is contained in:
255
frontend/src/components/dashboard/QuickActionsWidget.tsx
Normal file
255
frontend/src/components/dashboard/QuickActionsWidget.tsx
Normal file
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* QuickActionsWidget - Workflow guide with explainer text
|
||||
* Full-width layout with steps in 3 columns (1-3, 4-6, 7-8)
|
||||
*/
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import Button from '../ui/button/Button';
|
||||
import {
|
||||
ListIcon,
|
||||
GroupIcon,
|
||||
BoltIcon,
|
||||
FileTextIcon,
|
||||
FileIcon,
|
||||
CheckCircleIcon,
|
||||
PaperPlaneIcon,
|
||||
HelpCircleIcon,
|
||||
} from '../../icons';
|
||||
|
||||
interface QuickActionsWidgetProps {
|
||||
onAddKeywords?: () => void;
|
||||
}
|
||||
|
||||
const workflowSteps = [
|
||||
{
|
||||
num: 1,
|
||||
icon: ListIcon,
|
||||
title: 'Add Keywords',
|
||||
description: 'Import your target keywords manually or from CSV',
|
||||
href: '/planner/keyword-opportunities',
|
||||
actionLabel: 'Add',
|
||||
color: 'text-blue-600 dark:text-blue-400',
|
||||
},
|
||||
{
|
||||
num: 2,
|
||||
icon: GroupIcon,
|
||||
title: 'Auto Cluster',
|
||||
description: 'AI groups related keywords into content clusters',
|
||||
href: '/planner/clusters',
|
||||
actionLabel: 'Cluster',
|
||||
color: 'text-purple-600 dark:text-purple-400',
|
||||
},
|
||||
{
|
||||
num: 3,
|
||||
icon: BoltIcon,
|
||||
title: 'Generate Ideas',
|
||||
description: 'Create content ideas from your keyword clusters',
|
||||
href: '/planner/ideas',
|
||||
actionLabel: 'Ideas',
|
||||
color: 'text-orange-600 dark:text-orange-400',
|
||||
},
|
||||
{
|
||||
num: 4,
|
||||
icon: CheckCircleIcon,
|
||||
title: 'Create Tasks',
|
||||
description: 'Convert approved ideas into content tasks',
|
||||
href: '/writer/tasks',
|
||||
actionLabel: 'Tasks',
|
||||
color: 'text-indigo-600 dark:text-indigo-400',
|
||||
},
|
||||
{
|
||||
num: 5,
|
||||
icon: FileTextIcon,
|
||||
title: 'Generate Content',
|
||||
description: 'AI writes SEO-optimized articles from tasks',
|
||||
href: '/writer/content',
|
||||
actionLabel: 'Write',
|
||||
color: 'text-green-600 dark:text-green-400',
|
||||
},
|
||||
{
|
||||
num: 6,
|
||||
icon: FileIcon,
|
||||
title: 'Generate Images',
|
||||
description: 'Create featured images and media for articles',
|
||||
href: '/writer/images',
|
||||
actionLabel: 'Images',
|
||||
color: 'text-pink-600 dark:text-pink-400',
|
||||
},
|
||||
{
|
||||
num: 7,
|
||||
icon: CheckCircleIcon,
|
||||
title: 'Review & Approve',
|
||||
description: 'Quality check and approve generated content',
|
||||
href: '/writer/review',
|
||||
actionLabel: 'Review',
|
||||
color: 'text-amber-600 dark:text-amber-400',
|
||||
},
|
||||
{
|
||||
num: 8,
|
||||
icon: PaperPlaneIcon,
|
||||
title: 'Publish to WP',
|
||||
description: 'Push approved content to your WordPress site',
|
||||
href: '/writer/published',
|
||||
actionLabel: 'Publish',
|
||||
color: 'text-emerald-600 dark:text-emerald-400',
|
||||
},
|
||||
];
|
||||
|
||||
export default function QuickActionsWidget({ onAddKeywords }: QuickActionsWidgetProps) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
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-4">
|
||||
<h3 className="text-base font-semibold text-gray-800 dark:text-gray-200 uppercase tracking-wide">
|
||||
Workflow Guide
|
||||
</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
tone="neutral"
|
||||
size="sm"
|
||||
startIcon={<HelpCircleIcon className="w-4 h-4" />}
|
||||
onClick={() => navigate('/help')}
|
||||
>
|
||||
Full Help Guide
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 3-Column Grid: Steps 1-3, 4-6, 7-8 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
{/* Column 1: Steps 1-3 */}
|
||||
<div className="space-y-2.5">
|
||||
{workflowSteps.slice(0, 3).map((step) => {
|
||||
const Icon = step.icon;
|
||||
return (
|
||||
<div
|
||||
key={step.num}
|
||||
className="flex items-center gap-3 p-2 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors group"
|
||||
>
|
||||
{/* Step Number */}
|
||||
<span className="w-6 h-6 flex items-center justify-center rounded-full bg-brand-100 dark:bg-brand-900/30 text-sm font-semibold text-brand-600 dark:text-brand-400 flex-shrink-0">
|
||||
{step.num}
|
||||
</span>
|
||||
|
||||
{/* Icon */}
|
||||
<div className={`flex-shrink-0 ${step.color}`}>
|
||||
<Icon className="w-5 h-5" />
|
||||
</div>
|
||||
|
||||
{/* Text Content */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
{step.title}
|
||||
</p>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400 line-clamp-1">
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Action Button */}
|
||||
<Button
|
||||
size="xs"
|
||||
variant="outline"
|
||||
tone="brand"
|
||||
onClick={() => navigate(step.href)}
|
||||
className="flex-shrink-0 opacity-70 group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
{step.actionLabel}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Column 2: Steps 4-6 */}
|
||||
<div className="space-y-2.5">
|
||||
{workflowSteps.slice(3, 6).map((step) => {
|
||||
const Icon = step.icon;
|
||||
return (
|
||||
<div
|
||||
key={step.num}
|
||||
className="flex items-center gap-3 p-2 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors group"
|
||||
>
|
||||
{/* Step Number */}
|
||||
<span className="w-6 h-6 flex items-center justify-center rounded-full bg-brand-100 dark:bg-brand-900/30 text-sm font-semibold text-brand-600 dark:text-brand-400 flex-shrink-0">
|
||||
{step.num}
|
||||
</span>
|
||||
|
||||
{/* Icon */}
|
||||
<div className={`flex-shrink-0 ${step.color}`}>
|
||||
<Icon className="w-5 h-5" />
|
||||
</div>
|
||||
|
||||
{/* Text Content */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
{step.title}
|
||||
</p>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400 line-clamp-1">
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Action Button */}
|
||||
<Button
|
||||
size="xs"
|
||||
variant="outline"
|
||||
tone="brand"
|
||||
onClick={() => navigate(step.href)}
|
||||
className="flex-shrink-0 opacity-70 group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
{step.actionLabel}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Column 3: Steps 7-8 */}
|
||||
<div className="space-y-2.5">
|
||||
{workflowSteps.slice(6, 8).map((step) => {
|
||||
const Icon = step.icon;
|
||||
return (
|
||||
<div
|
||||
key={step.num}
|
||||
className="flex items-center gap-3 p-2 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors group"
|
||||
>
|
||||
{/* Step Number */}
|
||||
<span className="w-6 h-6 flex items-center justify-center rounded-full bg-brand-100 dark:bg-brand-900/30 text-sm font-semibold text-brand-600 dark:text-brand-400 flex-shrink-0">
|
||||
{step.num}
|
||||
</span>
|
||||
|
||||
{/* Icon */}
|
||||
<div className={`flex-shrink-0 ${step.color}`}>
|
||||
<Icon className="w-5 h-5" />
|
||||
</div>
|
||||
|
||||
{/* Text Content */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
{step.title}
|
||||
</p>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400 line-clamp-1">
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Action Button */}
|
||||
<Button
|
||||
size="xs"
|
||||
variant="outline"
|
||||
tone="brand"
|
||||
onClick={() => navigate(step.href)}
|
||||
className="flex-shrink-0 opacity-70 group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
{step.actionLabel}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user