stlyes fixes
This commit is contained in:
@@ -51,7 +51,7 @@ const ActivityLog: React.FC<ActivityLogProps> = ({ runId }) => {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-gray-900 dark:bg-gray-950 text-green-400 p-4 rounded-lg font-mono text-xs overflow-auto max-h-96 border border-gray-700">
|
<div className="bg-gray-900 dark:bg-gray-950 text-success-400 p-4 rounded-lg font-mono text-xs overflow-auto max-h-96 border border-gray-700">
|
||||||
<pre className="whitespace-pre-wrap">{logs || 'No logs available'}</pre>
|
<pre className="whitespace-pre-wrap">{logs || 'No logs available'}</pre>
|
||||||
</div>
|
</div>
|
||||||
</ComponentCard>
|
</ComponentCard>
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-red-50 dark:bg-red-900/20 border-2 border-red-500 rounded-lg p-4 mb-6">
|
<div className="bg-error-50 dark:bg-error-900/20 border-2 border-error-500 rounded-lg p-4 mb-6">
|
||||||
<p className="text-red-700 dark:text-red-300 text-sm">{error}</p>
|
<p className="text-error-700 dark:text-error-300 text-sm">{error}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -71,13 +71,13 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
const percentage = processingState.percentage;
|
const percentage = processingState.percentage;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-blue-50 dark:bg-blue-900/20 border-2 border-blue-500 rounded-lg p-6 mb-6">
|
<div className="bg-brand-50 dark:bg-brand-900/20 border-2 border-brand-500 rounded-lg p-6 mb-6">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="animate-pulse">
|
<div className="animate-pulse">
|
||||||
<svg
|
<svg
|
||||||
className="w-8 h-8 text-blue-600 dark:text-blue-400"
|
className="w-8 h-8 text-brand-600 dark:text-brand-400"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -96,14 +96,14 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||||
Stage {currentStage}: {processingState.stage_name}
|
Stage {currentStage}: {processingState.stage_name}
|
||||||
<span className="ml-2 px-2 py-0.5 bg-blue-100 dark:bg-blue-900 text-blue-700 dark:text-blue-300 rounded text-xs">
|
<span className="ml-2 px-2 py-0.5 bg-brand-100 dark:bg-brand-900 text-brand-700 dark:text-brand-300 rounded text-xs">
|
||||||
{processingState.stage_type}
|
{processingState.stage_type}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<div className="text-4xl font-bold text-blue-600 dark:text-blue-400">
|
<div className="text-4xl font-bold text-brand-600 dark:text-brand-400">
|
||||||
{percentage}%
|
{percentage}%
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-gray-600 dark:text-gray-400">
|
<div className="text-sm text-gray-600 dark:text-gray-400">
|
||||||
@@ -116,7 +116,7 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-3">
|
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-3">
|
||||||
<div
|
<div
|
||||||
className="bg-blue-600 dark:bg-blue-500 h-3 rounded-full transition-all duration-500"
|
className="bg-brand-600 dark:bg-brand-500 h-3 rounded-full transition-all duration-500"
|
||||||
style={{ width: `${Math.min(percentage, 100)}%` }}
|
style={{ width: `${Math.min(percentage, 100)}%` }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -133,7 +133,7 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
{processingState.currently_processing.length > 0 ? (
|
{processingState.currently_processing.length > 0 ? (
|
||||||
processingState.currently_processing.map((item, idx) => (
|
processingState.currently_processing.map((item, idx) => (
|
||||||
<div key={idx} className="flex items-start gap-2 text-sm">
|
<div key={idx} className="flex items-start gap-2 text-sm">
|
||||||
<span className="text-blue-600 dark:text-blue-400 mt-1">•</span>
|
<span className="text-brand-600 dark:text-brand-400 mt-1">•</span>
|
||||||
<span className="text-gray-800 dark:text-gray-200 font-medium line-clamp-2">
|
<span className="text-gray-800 dark:text-gray-200 font-medium line-clamp-2">
|
||||||
{item.title}
|
{item.title}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -240,12 +240,12 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-red-50 dark:bg-red-900/20 border-2 border-red-500 rounded-lg p-4 mb-6">
|
<div className="bg-error-50 dark:bg-error-900/20 border-2 border-error-500 rounded-lg p-4 mb-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<p className="text-red-700 dark:text-red-300 text-sm">{error}</p>
|
<p className="text-error-700 dark:text-error-300 text-sm">{error}</p>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="text-red-500 hover:text-red-700 dark:hover:text-red-300"
|
className="text-error-500 hover:text-error-700 dark:hover:text-error-300"
|
||||||
>
|
>
|
||||||
<XMarkIcon className="w-5 h-5" />
|
<XMarkIcon className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
@@ -321,21 +321,21 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
|
|
||||||
// Choose stage accent color (simple map matching AutomationPage STAGE_CONFIG)
|
// Choose stage accent color (simple map matching AutomationPage STAGE_CONFIG)
|
||||||
const stageColors = [
|
const stageColors = [
|
||||||
'from-blue-500 to-blue-600',
|
'from-brand-500 to-brand-600',
|
||||||
'from-purple-500 to-purple-600',
|
'from-purple-500 to-purple-600',
|
||||||
'from-indigo-500 to-indigo-600',
|
'from-purple-500 to-purple-600',
|
||||||
'from-green-500 to-green-600',
|
'from-success-500 to-success-600',
|
||||||
'from-amber-500 to-amber-600',
|
'from-warning-500 to-warning-600',
|
||||||
'from-pink-500 to-pink-600',
|
'from-purple-500 to-purple-600',
|
||||||
'from-teal-500 to-teal-600',
|
'from-success-500 to-success-600',
|
||||||
];
|
];
|
||||||
const stageColorClass = stageColors[(currentRun.current_stage || 1) - 1] || 'from-blue-500 to-blue-600';
|
const stageColorClass = stageColors[(currentRun.current_stage || 1) - 1] || 'from-brand-500 to-brand-600';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`border-2 rounded-lg p-6 mb-6 ${
|
<div className={`border-2 rounded-lg p-6 mb-6 ${
|
||||||
isPaused
|
isPaused
|
||||||
? 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-500'
|
? 'bg-warning-50 dark:bg-warning-900/20 border-warning-500'
|
||||||
: 'bg-blue-50 dark:bg-blue-900/20 border-blue-500'
|
: 'bg-brand-50 dark:bg-brand-900/20 border-brand-500'
|
||||||
}`}>
|
}`}>
|
||||||
{/* Header Row with Main Info and Close */}
|
{/* Header Row with Main Info and Close */}
|
||||||
<div className="flex items-start justify-between mb-4">
|
<div className="flex items-start justify-between mb-4">
|
||||||
@@ -344,9 +344,9 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
<div className={isPaused ? '' : 'animate-pulse'}>
|
<div className={isPaused ? '' : 'animate-pulse'}>
|
||||||
{isPaused ? (
|
{isPaused ? (
|
||||||
<PauseIcon className="w-8 h-8 text-yellow-600 dark:text-yellow-400" />
|
<PauseIcon className="w-8 h-8 text-warning-600 dark:text-warning-400" />
|
||||||
) : (
|
) : (
|
||||||
<BoltIcon className="w-8 h-8 text-blue-600 dark:text-blue-400" />
|
<BoltIcon className="w-8 h-8 text-brand-600 dark:text-brand-400" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
@@ -361,8 +361,8 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
Stage {currentRun.current_stage}: {displayState.stage_name}
|
Stage {currentRun.current_stage}: {displayState.stage_name}
|
||||||
<span className={`ml-2 px-2 py-0.5 rounded text-xs ${
|
<span className={`ml-2 px-2 py-0.5 rounded text-xs ${
|
||||||
isPaused
|
isPaused
|
||||||
? 'bg-yellow-100 dark:bg-yellow-900 text-yellow-700 dark:text-yellow-300'
|
? 'bg-warning-100 dark:bg-warning-900 text-warning-700 dark:text-warning-300'
|
||||||
: 'bg-blue-100 dark:bg-blue-900 text-blue-700 dark:text-blue-300'
|
: 'bg-brand-100 dark:bg-brand-900 text-brand-700 dark:text-brand-300'
|
||||||
}`}>
|
}`}>
|
||||||
{displayState.stage_type}
|
{displayState.stage_type}
|
||||||
</span>
|
</span>
|
||||||
@@ -396,7 +396,7 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
<>
|
<>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<div className="text-3xl font-bold text-blue-600 dark:text-blue-400">
|
<div className="text-3xl font-bold text-brand-600 dark:text-brand-400">
|
||||||
{percentage}%
|
{percentage}%
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-gray-600 dark:text-gray-400">
|
<div className="text-sm text-gray-600 dark:text-gray-400">
|
||||||
@@ -408,8 +408,8 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
<div
|
<div
|
||||||
className={`h-3 rounded-full transition-all duration-500 ${
|
className={`h-3 rounded-full transition-all duration-500 ${
|
||||||
isPaused
|
isPaused
|
||||||
? 'bg-yellow-600 dark:bg-yellow-500'
|
? 'bg-warning-600 dark:bg-warning-500'
|
||||||
: 'bg-blue-600 dark:bg-blue-500'
|
: 'bg-brand-600 dark:bg-brand-500'
|
||||||
}`}
|
}`}
|
||||||
style={{ width: `${Math.min(percentage, 100)}%` }}
|
style={{ width: `${Math.min(percentage, 100)}%` }}
|
||||||
/>
|
/>
|
||||||
@@ -427,7 +427,7 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
{((displayState.currently_processing && displayState.currently_processing.length > 0) ? displayState.currently_processing : fetchedCurrently).length > 0 ? (
|
{((displayState.currently_processing && displayState.currently_processing.length > 0) ? displayState.currently_processing : fetchedCurrently).length > 0 ? (
|
||||||
((displayState.currently_processing && displayState.currently_processing.length > 0) ? displayState.currently_processing : fetchedCurrently).map((item, idx) => (
|
((displayState.currently_processing && displayState.currently_processing.length > 0) ? displayState.currently_processing : fetchedCurrently).map((item, idx) => (
|
||||||
<div key={idx} className="flex items-start gap-2 text-sm">
|
<div key={idx} className="flex items-start gap-2 text-sm">
|
||||||
<span className={isPaused ? 'text-yellow-600 dark:text-yellow-400 mt-1' : 'text-blue-600 dark:text-blue-400 mt-1'}>•</span>
|
<span className={isPaused ? 'text-warning-600 dark:text-warning-400 mt-1' : 'text-brand-600 dark:text-brand-400 mt-1'}>•</span>
|
||||||
<span className="text-gray-800 dark:text-gray-200 font-medium line-clamp-2">
|
<span className="text-gray-800 dark:text-gray-200 font-medium line-clamp-2">
|
||||||
{item.title}
|
{item.title}
|
||||||
</span>
|
</span>
|
||||||
@@ -536,10 +536,10 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
<div className="bg-white dark:bg-gray-800 rounded-lg p-3 border border-gray-200 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg p-3 border border-gray-200 dark:border-gray-700">
|
||||||
<div className="flex items-center justify-between mb-0">
|
<div className="flex items-center justify-between mb-0">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<BoltIcon className="w-4 h-4 text-amber-500" />
|
<BoltIcon className="w-4 h-4 text-warning-500" />
|
||||||
<div className="text-xs text-gray-500 dark:text-gray-400 uppercase font-semibold">Credits Used</div>
|
<div className="text-xs text-gray-500 dark:text-gray-400 uppercase font-semibold">Credits Used</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm font-bold text-amber-600 dark:text-amber-400">{currentRun.total_credits_used}</div>
|
<div className="text-sm font-bold text-warning-600 dark:text-warning-400">{currentRun.total_credits_used}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -555,7 +555,7 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
<div className="bg-white dark:bg-gray-800 rounded-lg p-3 border border-gray-200 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg p-3 border border-gray-200 dark:border-gray-700">
|
||||||
<div className="flex items-center justify-between mb-0">
|
<div className="flex items-center justify-between mb-0">
|
||||||
<div className="text-xs text-gray-500 dark:text-gray-400 uppercase font-semibold">Status</div>
|
<div className="text-xs text-gray-500 dark:text-gray-400 uppercase font-semibold">Status</div>
|
||||||
<div className={`text-sm font-semibold ${isPaused ? 'text-yellow-600 dark:text-yellow-400' : 'text-blue-600 dark:text-blue-400'}`}>
|
<div className={`text-sm font-semibold ${isPaused ? 'text-warning-600 dark:text-warning-400' : 'text-brand-600 dark:text-brand-400'}`}>
|
||||||
{isPaused ? 'Paused' : 'Running'}
|
{isPaused ? 'Paused' : 'Running'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -567,7 +567,7 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowDebugTable(!showDebugTable)}
|
onClick={() => setShowDebugTable(!showDebugTable)}
|
||||||
className="text-xs text-slate-600 hover:underline"
|
className="text-xs text-gray-600 hover:underline"
|
||||||
>
|
>
|
||||||
{showDebugTable ? 'Hide' : 'Show'} debug table
|
{showDebugTable ? 'Hide' : 'Show'} debug table
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -193,16 +193,16 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className={`rounded-xl p-5 mb-6 border-2 transition-all ${
|
<div className={`rounded-xl p-5 mb-6 border-2 transition-all ${
|
||||||
isPaused
|
isPaused
|
||||||
? 'bg-gradient-to-r from-amber-50 to-amber-100 dark:from-amber-900/20 dark:to-amber-800/20 border-amber-400'
|
? 'bg-gradient-to-r from-warning-50 to-warning-100 dark:from-warning-900/20 dark:to-warning-800/20 border-warning-400'
|
||||||
: 'bg-gradient-to-r from-blue-50 to-blue-100 dark:from-blue-900/20 dark:to-blue-800/20 border-blue-400'
|
: 'bg-gradient-to-r from-brand-50 to-brand-100 dark:from-brand-900/20 dark:to-brand-800/20 border-brand-400'
|
||||||
}`}>
|
}`}>
|
||||||
{/* Header Row */}
|
{/* Header Row */}
|
||||||
<div className="flex items-start justify-between mb-4">
|
<div className="flex items-start justify-between mb-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className={`size-10 rounded-lg flex items-center justify-center shadow-md ${
|
<div className={`size-10 rounded-lg flex items-center justify-center shadow-md ${
|
||||||
isPaused
|
isPaused
|
||||||
? 'bg-gradient-to-br from-amber-500 to-amber-600'
|
? 'bg-gradient-to-br from-warning-500 to-warning-600'
|
||||||
: 'bg-gradient-to-br from-blue-500 to-blue-600'
|
: 'bg-gradient-to-br from-brand-500 to-brand-600'
|
||||||
}`}>
|
}`}>
|
||||||
{isPaused ? (
|
{isPaused ? (
|
||||||
<PauseIcon className="w-5 h-5 text-white" />
|
<PauseIcon className="w-5 h-5 text-white" />
|
||||||
@@ -217,7 +217,7 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
<div className="text-sm text-gray-600 dark:text-gray-400">
|
<div className="text-sm text-gray-600 dark:text-gray-400">
|
||||||
Stage {currentRun.current_stage}: {stageName}
|
Stage {currentRun.current_stage}: {stageName}
|
||||||
<span className={`ml-2 px-1.5 py-0.5 rounded text-xs ${
|
<span className={`ml-2 px-1.5 py-0.5 rounded text-xs ${
|
||||||
isPaused ? 'bg-amber-200 text-amber-800' : 'bg-blue-200 text-blue-800'
|
isPaused ? 'bg-warning-200 text-warning-800' : 'bg-brand-200 text-brand-800'
|
||||||
}`}>
|
}`}>
|
||||||
{stageOverview?.type || 'AI'}
|
{stageOverview?.type || 'AI'}
|
||||||
</span>
|
</span>
|
||||||
@@ -241,7 +241,7 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
{/* Progress Text */}
|
{/* Progress Text */}
|
||||||
<div className="flex items-baseline justify-between mb-2">
|
<div className="flex items-baseline justify-between mb-2">
|
||||||
<div className="flex items-baseline gap-3">
|
<div className="flex items-baseline gap-3">
|
||||||
<span className={`text-4xl font-bold ${isPaused ? 'text-amber-600' : 'text-blue-600'}`}>
|
<span className={`text-4xl font-bold ${isPaused ? 'text-warning-600' : 'text-brand-600'}`}>
|
||||||
{displayPercent}%
|
{displayPercent}%
|
||||||
</span>
|
</span>
|
||||||
<span className="text-sm text-gray-500">
|
<span className="text-sm text-gray-500">
|
||||||
@@ -258,8 +258,8 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
<div
|
<div
|
||||||
className={`h-3 rounded-full transition-all duration-300 ${
|
className={`h-3 rounded-full transition-all duration-300 ${
|
||||||
isPaused
|
isPaused
|
||||||
? 'bg-gradient-to-r from-amber-400 to-amber-600'
|
? 'bg-gradient-to-r from-warning-400 to-warning-600'
|
||||||
: 'bg-gradient-to-r from-blue-400 to-blue-600'
|
: 'bg-gradient-to-r from-brand-400 to-brand-600'
|
||||||
} ${!isPaused && displayPercent < 100 ? 'animate-pulse' : ''}`}
|
} ${!isPaused && displayPercent < 100 ? 'animate-pulse' : ''}`}
|
||||||
style={{ width: `${Math.min(displayPercent, 100)}%` }}
|
style={{ width: `${Math.min(displayPercent, 100)}%` }}
|
||||||
/>
|
/>
|
||||||
@@ -292,7 +292,7 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
<button
|
<button
|
||||||
onClick={handleCancel}
|
onClick={handleCancel}
|
||||||
disabled={isCancelling}
|
disabled={isCancelling}
|
||||||
className="text-sm text-gray-500 hover:text-red-600 transition-colors"
|
className="text-sm text-gray-500 hover:text-error-600 transition-colors"
|
||||||
>
|
>
|
||||||
<XMarkIcon className="w-4 h-4 inline mr-1" />
|
<XMarkIcon className="w-4 h-4 inline mr-1" />
|
||||||
{isCancelling ? 'Cancelling...' : 'Cancel'}
|
{isCancelling ? 'Cancelling...' : 'Cancel'}
|
||||||
@@ -312,10 +312,10 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
|
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg px-3 py-2 border border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
<div className="bg-white dark:bg-gray-800 rounded-lg px-3 py-2 border border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex items-center gap-1.5">
|
||||||
<BoltIcon className="w-4 h-4 text-amber-500" />
|
<BoltIcon className="w-4 h-4 text-warning-500" />
|
||||||
<span className="text-xs text-gray-500 uppercase">Credits</span>
|
<span className="text-xs text-gray-500 uppercase">Credits</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-sm font-bold text-amber-600">{currentRun.total_credits_used}</span>
|
<span className="text-sm font-bold text-warning-600">{currentRun.total_credits_used}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg px-3 py-2 border border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
<div className="bg-white dark:bg-gray-800 rounded-lg px-3 py-2 border border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
||||||
@@ -325,7 +325,7 @@ const CurrentProcessingCard: React.FC<CurrentProcessingCardProps> = ({
|
|||||||
|
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg px-3 py-2 border border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
<div className="bg-white dark:bg-gray-800 rounded-lg px-3 py-2 border border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
||||||
<span className="text-xs text-gray-500 uppercase">Status</span>
|
<span className="text-xs text-gray-500 uppercase">Status</span>
|
||||||
<span className={`text-sm font-bold ${isPaused ? 'text-amber-600' : 'text-green-600'}`}>
|
<span className={`text-sm font-bold ${isPaused ? 'text-warning-600' : 'text-success-600'}`}>
|
||||||
{isPaused ? 'Paused' : 'Running'}
|
{isPaused ? 'Paused' : 'Running'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import { BoltIcon, CheckCircleIcon, PauseIcon } from '../../icons';
|
|||||||
|
|
||||||
// Stage colors matching AutomationPage STAGE_CONFIG
|
// Stage colors matching AutomationPage STAGE_CONFIG
|
||||||
const STAGE_COLORS = [
|
const STAGE_COLORS = [
|
||||||
'from-blue-500 to-blue-600', // Stage 1: Keywords → Clusters
|
'from-brand-500 to-brand-600', // Stage 1: Keywords → Clusters
|
||||||
'from-purple-500 to-purple-600', // Stage 2: Clusters → Ideas
|
'from-purple-500 to-purple-600', // Stage 2: Clusters → Ideas
|
||||||
'from-indigo-500 to-indigo-600', // Stage 3: Ideas → Tasks
|
'from-purple-500 to-purple-600', // Stage 3: Ideas → Tasks
|
||||||
'from-green-500 to-green-600', // Stage 4: Tasks → Content
|
'from-success-500 to-success-600', // Stage 4: Tasks → Content
|
||||||
'from-amber-500 to-amber-600', // Stage 5: Content → Image Prompts
|
'from-warning-500 to-warning-600', // Stage 5: Content → Image Prompts
|
||||||
'from-pink-500 to-pink-600', // Stage 6: Image Prompts → Images
|
'from-purple-500 to-purple-600', // Stage 6: Image Prompts → Images
|
||||||
'from-teal-500 to-teal-600', // Stage 7: Manual Review Gate
|
'from-success-500 to-success-600', // Stage 7: Manual Review Gate
|
||||||
];
|
];
|
||||||
|
|
||||||
const STAGE_NAMES = [
|
const STAGE_NAMES = [
|
||||||
@@ -141,7 +141,7 @@ const GlobalProgressBar: React.FC<GlobalProgressBarProps> = ({
|
|||||||
<div className={`
|
<div className={`
|
||||||
rounded-xl p-4 mb-6 border-2 transition-all
|
rounded-xl p-4 mb-6 border-2 transition-all
|
||||||
${isPaused
|
${isPaused
|
||||||
? 'bg-gradient-to-r from-amber-50 to-amber-100 dark:from-amber-900/20 dark:to-amber-800/20 border-amber-300 dark:border-amber-700'
|
? 'bg-gradient-to-r from-warning-50 to-warning-100 dark:from-warning-900/20 dark:to-warning-800/20 border-warning-300 dark:border-warning-700'
|
||||||
: 'bg-gradient-to-r from-brand-50 to-brand-100 dark:from-brand-900/20 dark:to-brand-800/20 border-brand-300 dark:border-brand-700'
|
: 'bg-gradient-to-r from-brand-50 to-brand-100 dark:from-brand-900/20 dark:to-brand-800/20 border-brand-300 dark:border-brand-700'
|
||||||
}
|
}
|
||||||
`}>
|
`}>
|
||||||
@@ -151,7 +151,7 @@ const GlobalProgressBar: React.FC<GlobalProgressBarProps> = ({
|
|||||||
<div className={`
|
<div className={`
|
||||||
size-10 rounded-lg flex items-center justify-center shadow-md
|
size-10 rounded-lg flex items-center justify-center shadow-md
|
||||||
${isPaused
|
${isPaused
|
||||||
? 'bg-gradient-to-br from-amber-500 to-amber-600'
|
? 'bg-gradient-to-br from-warning-500 to-warning-600'
|
||||||
: 'bg-gradient-to-br from-brand-500 to-brand-600'
|
: 'bg-gradient-to-br from-brand-500 to-brand-600'
|
||||||
}
|
}
|
||||||
`}>
|
`}>
|
||||||
@@ -164,7 +164,7 @@ const GlobalProgressBar: React.FC<GlobalProgressBarProps> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className={`font-bold ${isPaused ? 'text-amber-800 dark:text-amber-200' : 'text-brand-800 dark:text-brand-200'}`}>
|
<div className={`font-bold ${isPaused ? 'text-warning-800 dark:text-warning-200' : 'text-brand-800 dark:text-brand-200'}`}>
|
||||||
{isPaused ? 'Pipeline Paused' : 'Full Pipeline Progress'}
|
{isPaused ? 'Pipeline Paused' : 'Full Pipeline Progress'}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-gray-600 dark:text-gray-400">
|
<div className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
@@ -172,7 +172,7 @@ const GlobalProgressBar: React.FC<GlobalProgressBarProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`text-3xl font-bold ${isPaused ? 'text-amber-600 dark:text-amber-400' : 'text-brand-600 dark:text-brand-400'}`}>
|
<div className={`text-3xl font-bold ${isPaused ? 'text-warning-600 dark:text-warning-400' : 'text-brand-600 dark:text-brand-400'}`}>
|
||||||
{percentage}%
|
{percentage}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -216,8 +216,8 @@ const GlobalProgressBar: React.FC<GlobalProgressBarProps> = ({
|
|||||||
<span
|
<span
|
||||||
key={stageNum}
|
key={stageNum}
|
||||||
className={`
|
className={`
|
||||||
${status === 'completed' ? 'text-green-600 dark:text-green-400 font-medium' : ''}
|
${status === 'completed' ? 'text-success-600 dark:text-success-400 font-medium' : ''}
|
||||||
${status === 'active' ? `${isPaused ? 'text-amber-600 dark:text-amber-400' : 'text-brand-600 dark:text-brand-400'} font-bold` : ''}
|
${status === 'active' ? `${isPaused ? 'text-warning-600 dark:text-warning-400' : 'text-brand-600 dark:text-brand-400'} font-bold` : ''}
|
||||||
${status === 'pending' ? 'text-gray-400 dark:text-gray-500' : ''}
|
${status === 'pending' ? 'text-gray-400 dark:text-gray-500' : ''}
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ const RunHistory: React.FC<RunHistoryProps> = ({ siteId }) => {
|
|||||||
|
|
||||||
const getStatusBadge = (status: string) => {
|
const getStatusBadge = (status: string) => {
|
||||||
const colors: Record<string, string> = {
|
const colors: Record<string, string> = {
|
||||||
completed: 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400',
|
completed: 'bg-success-100 text-success-800 dark:bg-success-900/30 dark:text-success-400',
|
||||||
running: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400',
|
running: 'bg-brand-100 text-brand-800 dark:bg-brand-900/30 dark:text-brand-400',
|
||||||
paused: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400',
|
paused: 'bg-warning-100 text-warning-800 dark:bg-warning-900/30 dark:text-warning-400',
|
||||||
failed: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400',
|
failed: 'bg-error-100 text-error-800 dark:bg-error-900/30 dark:text-error-400',
|
||||||
};
|
};
|
||||||
return colors[status] || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300';
|
return colors[status] || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300';
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ const StageCard: React.FC<StageCardProps> = ({
|
|||||||
const isComplete = stageNumber < currentStage || (result !== null && stageNumber <= 7);
|
const isComplete = stageNumber < currentStage || (result !== null && stageNumber <= 7);
|
||||||
|
|
||||||
const getStatusColor = () => {
|
const getStatusColor = () => {
|
||||||
if (isActive) return 'border-blue-500 bg-blue-50 dark:bg-blue-900/20 dark:border-blue-400';
|
if (isActive) return 'border-brand-500 bg-brand-50 dark:bg-brand-900/20 dark:border-brand-400';
|
||||||
if (isComplete) return 'border-green-500 bg-green-50 dark:bg-green-900/20 dark:border-green-400';
|
if (isComplete) return 'border-success-500 bg-success-50 dark:bg-success-900/20 dark:border-success-400';
|
||||||
if (pipelineData && pipelineData.pending > 0) return 'border-purple-400 bg-purple-50 dark:bg-purple-900/20 dark:border-purple-400';
|
if (pipelineData && pipelineData.pending > 0) return 'border-purple-400 bg-purple-50 dark:bg-purple-900/20 dark:border-purple-400';
|
||||||
return 'border-gray-300 bg-gray-50 dark:bg-gray-800 dark:border-gray-600';
|
return 'border-gray-300 bg-gray-50 dark:bg-gray-800 dark:border-gray-600';
|
||||||
};
|
};
|
||||||
@@ -78,8 +78,8 @@ const StageCard: React.FC<StageCardProps> = ({
|
|||||||
|
|
||||||
{/* Show processing indicator when active */}
|
{/* Show processing indicator when active */}
|
||||||
{isActive && !result && (
|
{isActive && !result && (
|
||||||
<div className="mt-2 pt-2 border-t border-blue-200 dark:border-blue-600">
|
<div className="mt-2 pt-2 border-t border-brand-200 dark:border-brand-600">
|
||||||
<div className="text-xs text-blue-600 dark:text-blue-400 animate-pulse">Processing...</div>
|
<div className="text-xs text-brand-600 dark:text-brand-400 animate-pulse">Processing...</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -93,8 +93,8 @@ export default function ProtectedRoute({ children }: ProtectedRouteProps) {
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
{showError && (
|
{showError && (
|
||||||
<div className="mt-4 p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
|
<div className="mt-4 p-4 bg-warning-50 dark:bg-warning-900/20 border border-warning-200 dark:border-warning-800 rounded-lg">
|
||||||
<p className="text-sm text-yellow-800 dark:text-yellow-200 mb-3">
|
<p className="text-sm text-warning-800 dark:text-warning-200 mb-3">
|
||||||
{errorMessage}
|
{errorMessage}
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
@@ -103,7 +103,7 @@ export default function ProtectedRoute({ children }: ProtectedRouteProps) {
|
|||||||
setShowError(false);
|
setShowError(false);
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}}
|
}}
|
||||||
className="px-4 py-2 text-sm bg-yellow-600 text-white rounded hover:bg-yellow-700"
|
className="px-4 py-2 text-sm bg-warning-600 text-white rounded hover:bg-warning-700"
|
||||||
>
|
>
|
||||||
Retry or Reload Page
|
Retry or Reload Page
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -169,22 +169,22 @@ export default function SignInForm() {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Logout Reason Display */}
|
{/* Logout Reason Display */}
|
||||||
{logoutReason && (
|
{logoutReason && (
|
||||||
<div className="p-4 bg-yellow-50 border border-yellow-200 rounded-lg dark:bg-yellow-900/20 dark:border-yellow-800">
|
<div className="p-4 bg-warning-50 border border-warning-200 rounded-lg dark:bg-warning-900/20 dark:border-warning-800">
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-center gap-2 mb-2">
|
<div className="flex items-center gap-2 mb-2">
|
||||||
<svg className="w-5 h-5 text-yellow-600 dark:text-yellow-400" fill="currentColor" viewBox="0 0 20 20">
|
<svg className="w-5 h-5 text-warning-600 dark:text-warning-400" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
<h4 className="font-semibold text-yellow-800 dark:text-yellow-300">
|
<h4 className="font-semibold text-warning-800 dark:text-warning-300">
|
||||||
Session Ended
|
Session Ended
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-yellow-700 dark:text-yellow-400 mb-2">
|
<p className="text-sm text-warning-700 dark:text-warning-400 mb-2">
|
||||||
{logoutReason.message}
|
{logoutReason.message}
|
||||||
</p>
|
</p>
|
||||||
{logoutReason.path && logoutReason.path !== '/signin' && (
|
{logoutReason.path && logoutReason.path !== '/signin' && (
|
||||||
<p className="text-xs text-yellow-600 dark:text-yellow-500">
|
<p className="text-xs text-warning-600 dark:text-warning-500">
|
||||||
Original page: <span className="font-mono">{logoutReason.path}</span>
|
Original page: <span className="font-mono">{logoutReason.path}</span>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -192,7 +192,7 @@ export default function SignInForm() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowLogoutDetails(!showLogoutDetails)}
|
onClick={() => setShowLogoutDetails(!showLogoutDetails)}
|
||||||
className="ml-2 p-1 text-yellow-600 hover:text-yellow-800 dark:text-yellow-400 dark:hover:text-yellow-300"
|
className="ml-2 p-1 text-warning-600 hover:text-warning-800 dark:text-warning-400 dark:hover:text-warning-300"
|
||||||
title="Toggle technical details"
|
title="Toggle technical details"
|
||||||
>
|
>
|
||||||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||||
@@ -203,18 +203,18 @@ export default function SignInForm() {
|
|||||||
|
|
||||||
{/* Expandable Technical Details */}
|
{/* Expandable Technical Details */}
|
||||||
{showLogoutDetails && (
|
{showLogoutDetails && (
|
||||||
<div className="mt-3 pt-3 border-t border-yellow-300 dark:border-yellow-700">
|
<div className="mt-3 pt-3 border-t border-warning-300 dark:border-warning-700">
|
||||||
<p className="text-xs font-semibold text-yellow-800 dark:text-yellow-300 mb-2">
|
<p className="text-xs font-semibold text-warning-800 dark:text-warning-300 mb-2">
|
||||||
Technical Details:
|
Technical Details:
|
||||||
</p>
|
</p>
|
||||||
<div className="space-y-1 text-xs font-mono text-yellow-700 dark:text-yellow-400">
|
<div className="space-y-1 text-xs font-mono text-warning-700 dark:text-warning-400">
|
||||||
<div><span className="font-bold">Code:</span> {logoutReason.code}</div>
|
<div><span className="font-bold">Code:</span> {logoutReason.code}</div>
|
||||||
<div><span className="font-bold">Source:</span> {logoutReason.source}</div>
|
<div><span className="font-bold">Source:</span> {logoutReason.source}</div>
|
||||||
<div><span className="font-bold">Time:</span> {new Date(logoutReason.timestamp).toLocaleString()}</div>
|
<div><span className="font-bold">Time:</span> {new Date(logoutReason.timestamp).toLocaleString()}</div>
|
||||||
{logoutReason.context && Object.keys(logoutReason.context).length > 0 && (
|
{logoutReason.context && Object.keys(logoutReason.context).length > 0 && (
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<span className="font-bold">Context:</span>
|
<span className="font-bold">Context:</span>
|
||||||
<pre className="mt-1 p-2 bg-yellow-100 dark:bg-yellow-900/30 rounded text-xs overflow-x-auto">
|
<pre className="mt-1 p-2 bg-warning-100 dark:bg-warning-900/30 rounded text-xs overflow-x-auto">
|
||||||
{JSON.stringify(logoutReason.context, null, 2)}
|
{JSON.stringify(logoutReason.context, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
@@ -227,22 +227,22 @@ export default function SignInForm() {
|
|||||||
|
|
||||||
{/* Session Conflict Alert */}
|
{/* Session Conflict Alert */}
|
||||||
{sessionConflict && (
|
{sessionConflict && (
|
||||||
<div className="p-4 bg-orange-50 border border-orange-200 rounded-lg dark:bg-orange-900/20 dark:border-orange-800">
|
<div className="p-4 bg-warning-50 border border-warning-200 rounded-lg dark:bg-warning-900/20 dark:border-warning-800">
|
||||||
<div className="flex items-center gap-2 mb-3">
|
<div className="flex items-center gap-2 mb-3">
|
||||||
<svg className="w-5 h-5 text-orange-600 dark:text-orange-400" fill="currentColor" viewBox="0 0 20 20">
|
<svg className="w-5 h-5 text-warning-600 dark:text-warning-400" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
<h4 className="font-semibold text-orange-800 dark:text-orange-300">
|
<h4 className="font-semibold text-warning-800 dark:text-warning-300">
|
||||||
Active Session Detected
|
Active Session Detected
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-orange-700 dark:text-orange-400 mb-2">
|
<p className="text-sm text-warning-700 dark:text-warning-400 mb-2">
|
||||||
You have an active session for:
|
You have an active session for:
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm font-semibold text-orange-800 dark:text-orange-300 mb-3">
|
<p className="text-sm font-semibold text-warning-800 dark:text-warning-300 mb-3">
|
||||||
{sessionConflict.existingUser.email}
|
{sessionConflict.existingUser.email}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm text-orange-700 dark:text-orange-400 mb-4">
|
<p className="text-sm text-warning-700 dark:text-warning-400 mb-4">
|
||||||
You're trying to login as: <strong>{sessionConflict.requestedUser.email}</strong>
|
You're trying to login as: <strong>{sessionConflict.requestedUser.email}</strong>
|
||||||
</p>
|
</p>
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
@@ -250,14 +250,14 @@ export default function SignInForm() {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={handleForceLogout}
|
onClick={handleForceLogout}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="flex-1 px-4 py-2 text-sm font-medium text-white bg-orange-600 rounded-lg hover:bg-orange-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
className="flex-1 px-4 py-2 text-sm font-medium text-white bg-warning-600 rounded-lg hover:bg-warning-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||||
>
|
>
|
||||||
{loading ? 'Logging out...' : 'Logout Previous & Continue'}
|
{loading ? 'Logging out...' : 'Logout Previous & Continue'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setSessionConflict(null)}
|
onClick={() => setSessionConflict(null)}
|
||||||
className="flex-1 px-4 py-2 text-sm font-medium text-orange-700 bg-orange-100 rounded-lg hover:bg-orange-200 dark:bg-orange-900/40 dark:text-orange-300 dark:hover:bg-orange-900/60 transition-colors"
|
className="flex-1 px-4 py-2 text-sm font-medium text-warning-700 bg-warning-100 rounded-lg hover:bg-warning-200 dark:bg-warning-900/40 dark:text-warning-300 dark:hover:bg-warning-900/60 transition-colors"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
@@ -266,7 +266,7 @@ export default function SignInForm() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="p-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded-lg dark:bg-red-900/20 dark:text-red-400 dark:border-red-800">
|
<div className="p-3 text-sm text-error-600 bg-error-50 border border-error-200 rounded-lg dark:bg-error-900/20 dark:text-error-400 dark:border-error-800">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ export default function SignUpForm({ planDetails: planDetailsProp, planLoading:
|
|||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
{error && (
|
{error && (
|
||||||
<div className="p-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded-lg dark:bg-red-900/20 dark:text-red-400 dark:border-red-800">
|
<div className="p-3 text-sm text-error-600 bg-error-50 border border-error-200 rounded-lg dark:bg-error-900/20 dark:text-error-400 dark:border-error-800">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ export default function SignUpFormEnhanced({ planDetails: planDetailsProp, planL
|
|||||||
${step === currentStep
|
${step === currentStep
|
||||||
? 'bg-brand-500 text-white'
|
? 'bg-brand-500 text-white'
|
||||||
: step < currentStep
|
: step < currentStep
|
||||||
? 'bg-green-500 text-white'
|
? 'bg-success-500 text-white'
|
||||||
: 'bg-gray-200 text-gray-600 dark:bg-gray-700 dark:text-gray-400'
|
: 'bg-gray-200 text-gray-600 dark:bg-gray-700 dark:text-gray-400'
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
@@ -245,7 +245,7 @@ export default function SignUpFormEnhanced({ planDetails: planDetailsProp, planL
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{step < 3 && (
|
{step < 3 && (
|
||||||
<div className={`flex-1 h-0.5 mx-4 ${step < currentStep ? 'bg-green-500' : 'bg-gray-200 dark:bg-gray-700'}`} />
|
<div className={`flex-1 h-0.5 mx-4 ${step < currentStep ? 'bg-success-500' : 'bg-gray-200 dark:bg-gray-700'}`} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -282,7 +282,7 @@ export default function SignUpFormEnhanced({ planDetails: planDetailsProp, planL
|
|||||||
{renderStepIndicator()}
|
{renderStepIndicator()}
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mb-4 p-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded-lg dark:bg-red-900/20 dark:text-red-400 dark:border-red-800">
|
<div className="mb-4 p-3 text-sm text-error-600 bg-error-50 border border-error-200 rounded-lg dark:bg-error-900/20 dark:text-error-400 dark:border-error-800">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ export default function SignUpFormSimplified({ planDetails: planDetailsProp, pla
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mb-4 p-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded-lg dark:bg-red-900/20 dark:text-red-400 dark:border-red-800">
|
<div className="mb-4 p-3 text-sm text-error-600 bg-error-50 border border-error-200 rounded-lg dark:bg-error-900/20 dark:text-error-400 dark:border-error-800">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -357,7 +357,7 @@ export default function SignUpFormSimplified({ planDetails: planDetailsProp, pla
|
|||||||
<span className="text-sm text-gray-600 dark:text-gray-400">Loading payment options...</span>
|
<span className="text-sm text-gray-600 dark:text-gray-400">Loading payment options...</span>
|
||||||
</div>
|
</div>
|
||||||
) : paymentMethods.length === 0 ? (
|
) : paymentMethods.length === 0 ? (
|
||||||
<div className="p-4 bg-amber-50 border border-amber-200 rounded-lg text-amber-800 dark:bg-amber-900/20 dark:border-amber-800 dark:text-amber-200">
|
<div className="p-4 bg-warning-50 border border-warning-200 rounded-lg text-warning-800 dark:bg-warning-900/20 dark:border-warning-800 dark:text-warning-200">
|
||||||
<p className="text-sm">No payment methods available. Please contact support.</p>
|
<p className="text-sm">No payment methods available. Please contact support.</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ export default function SignUpFormUnified({
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-6 flex items-center justify-center">
|
<div className="h-6 flex items-center justify-center">
|
||||||
<span className={`inline-flex items-center gap-1.5 text-xs text-green-600 dark:text-green-400 font-semibold bg-green-50 dark:bg-green-900/20 px-2 py-1 rounded-full transition-opacity duration-200 ${
|
<span className={`inline-flex items-center gap-1.5 text-xs text-success-600 dark:text-success-400 font-semibold bg-success-50 dark:bg-success-900/20 px-2 py-1 rounded-full transition-opacity duration-200 ${
|
||||||
billingPeriod === 'annually' ? 'opacity-100' : 'opacity-0'
|
billingPeriod === 'annually' ? 'opacity-100' : 'opacity-0'
|
||||||
}`}>
|
}`}>
|
||||||
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -374,7 +374,7 @@ export default function SignUpFormUnified({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mb-4 p-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded-lg dark:bg-red-900/20 dark:text-red-400 dark:border-red-800">
|
<div className="mb-4 p-3 text-sm text-error-600 bg-error-50 border border-error-200 rounded-lg dark:bg-error-900/20 dark:text-error-400 dark:border-error-800">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -453,7 +453,7 @@ export default function SignUpFormUnified({
|
|||||||
<Loader2 className="w-4 h-4 animate-spin text-brand-500" />
|
<Loader2 className="w-4 h-4 animate-spin text-brand-500" />
|
||||||
</div>
|
</div>
|
||||||
) : paymentMethods.length === 0 ? (
|
) : paymentMethods.length === 0 ? (
|
||||||
<div className="p-3 bg-amber-50 border border-amber-200 rounded-lg text-amber-800 dark:bg-amber-900/20 dark:border-amber-800 dark:text-amber-200">
|
<div className="p-3 bg-warning-50 border border-warning-200 rounded-lg text-warning-800 dark:bg-warning-900/20 dark:border-warning-800 dark:text-warning-200">
|
||||||
<p className="text-xs">No payment methods available</p>
|
<p className="text-xs">No payment methods available</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -565,7 +565,7 @@ export default function SignUpFormUnified({
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-7 flex items-center justify-center">
|
<div className="h-7 flex items-center justify-center">
|
||||||
<p className={`inline-flex items-center gap-1.5 text-green-600 dark:text-green-400 text-sm font-semibold bg-green-50 dark:bg-green-900/20 px-3 py-1.5 rounded-full transition-opacity duration-200 ${
|
<p className={`inline-flex items-center gap-1.5 text-success-600 dark:text-success-400 text-sm font-semibold bg-success-50 dark:bg-success-900/20 px-3 py-1.5 rounded-full transition-opacity duration-200 ${
|
||||||
billingPeriod === 'annually' ? 'opacity-100' : 'opacity-0'
|
billingPeriod === 'annually' ? 'opacity-100' : 'opacity-0'
|
||||||
}`}>
|
}`}>
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -599,7 +599,7 @@ export default function SignUpFormUnified({
|
|||||||
>
|
>
|
||||||
{isPopular && !isSelected && (
|
{isPopular && !isSelected && (
|
||||||
<div className="absolute -top-3 left-1/2 -translate-x-1/2">
|
<div className="absolute -top-3 left-1/2 -translate-x-1/2">
|
||||||
<span className="bg-gradient-to-r from-green-500 to-emerald-500 text-white text-xs font-bold px-3 py-1 rounded-full shadow-lg">
|
<span className="bg-gradient-to-r from-success-500 to-success-500 text-white text-xs font-bold px-3 py-1 rounded-full shadow-lg">
|
||||||
⭐ POPULAR
|
⭐ POPULAR
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -638,7 +638,7 @@ export default function SignUpFormUnified({
|
|||||||
<div className="flex-1 grid grid-cols-2 gap-x-6 gap-y-2.5">
|
<div className="flex-1 grid grid-cols-2 gap-x-6 gap-y-2.5">
|
||||||
{features.map((feature, idx) => (
|
{features.map((feature, idx) => (
|
||||||
<div key={idx} className="flex items-center gap-2">
|
<div key={idx} className="flex items-center gap-2">
|
||||||
<CheckCircle className="w-4 h-4 text-green-500 dark:text-green-400 flex-shrink-0" />
|
<CheckCircle className="w-4 h-4 text-success-500 dark:text-success-400 flex-shrink-0" />
|
||||||
<span className="text-sm text-gray-700 dark:text-gray-300 leading-tight">{feature}</span>
|
<span className="text-sm text-gray-700 dark:text-gray-300 leading-tight">{feature}</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export default function BillingBalancePanel() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && !balance && (
|
{error && !balance && (
|
||||||
<div className="p-4 rounded-lg border border-amber-200 bg-amber-50 text-amber-800 dark:border-amber-800 dark:bg-amber-900/20 dark:text-amber-200">
|
<div className="p-4 rounded-lg border border-warning-200 bg-warning-50 text-warning-800 dark:border-warning-800 dark:bg-warning-900/20 dark:text-warning-200">
|
||||||
Usage unavailable. {error}
|
Usage unavailable. {error}
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<Button variant="outline" size="sm" onClick={loadBalance}>
|
<Button variant="outline" size="sm" onClick={loadBalance}>
|
||||||
@@ -88,7 +88,7 @@ export default function BillingBalancePanel() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{error && balance && (
|
{error && balance && (
|
||||||
<div className="text-sm text-amber-600 dark:text-amber-400">
|
<div className="text-sm text-warning-600 dark:text-warning-400">
|
||||||
Latest balance may be stale: {error}
|
Latest balance may be stale: {error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export default function BillingFormStep({
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
{error && (
|
{error && (
|
||||||
<div className="p-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded-lg dark:bg-red-900/20 dark:text-red-400 dark:border-red-800">
|
<div className="p-3 text-sm text-error-600 bg-error-50 border border-error-200 rounded-lg dark:bg-error-900/20 dark:text-error-400 dark:border-error-800">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export default function BillingRecentTransactions({ limit = 10, variant = 'card'
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<div className={`font-bold ${transaction.amount > 0 ? 'text-green-600' : 'text-red-600'}`}>
|
<div className={`font-bold ${transaction.amount > 0 ? 'text-success-600' : 'text-error-600'}`}>
|
||||||
{transaction.amount > 0 ? '+' : ''}{transaction.amount}
|
{transaction.amount > 0 ? '+' : ''}{transaction.amount}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export default function BillingUsagePanel({ showOnlyActivity = false }: BillingU
|
|||||||
<td className="py-3 px-4">
|
<td className="py-3 px-4">
|
||||||
<Badge variant="soft" tone={txn.amount >= 0 ? 'success' : 'danger'}>{txn.transaction_type}</Badge>
|
<Badge variant="soft" tone={txn.amount >= 0 ? 'success' : 'danger'}>{txn.transaction_type}</Badge>
|
||||||
</td>
|
</td>
|
||||||
<td className={`py-3 px-4 text-sm font-medium ${txn.amount >= 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}`}>
|
<td className={`py-3 px-4 text-sm font-medium ${txn.amount >= 0 ? 'text-success-600 dark:text-success-400' : 'text-error-600 dark:text-error-400'}`}>
|
||||||
{txn.amount >= 0 ? '+' : ''}{txn.amount}
|
{txn.amount >= 0 ? '+' : ''}{txn.amount}
|
||||||
</td>
|
</td>
|
||||||
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">{txn.description}</td>
|
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">{txn.description}</td>
|
||||||
@@ -178,7 +178,7 @@ export default function BillingUsagePanel({ showOnlyActivity = false }: BillingU
|
|||||||
{usageLimits.credits_remaining?.toLocaleString?.() || 0}
|
{usageLimits.credits_remaining?.toLocaleString?.() || 0}
|
||||||
</div>
|
</div>
|
||||||
{usageLimits.approaching_limit && (
|
{usageLimits.approaching_limit && (
|
||||||
<div className="text-sm text-amber-600 dark:text-amber-400 mt-1">Approaching limit</div>
|
<div className="text-sm text-warning-600 dark:text-warning-400 mt-1">Approaching limit</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 rounded-lg border border-gray-200 dark:border-gray-700">
|
<div className="p-4 rounded-lg border border-gray-200 dark:border-gray-700">
|
||||||
@@ -236,7 +236,7 @@ export default function BillingUsagePanel({ showOnlyActivity = false }: BillingU
|
|||||||
<td className="py-3 px-4">
|
<td className="py-3 px-4">
|
||||||
<Badge variant="light" color={txn.amount >= 0 ? 'success' : 'error'}>{txn.transaction_type}</Badge>
|
<Badge variant="light" color={txn.amount >= 0 ? 'success' : 'error'}>{txn.transaction_type}</Badge>
|
||||||
</td>
|
</td>
|
||||||
<td className={`py-3 px-4 text-sm font-medium ${txn.amount >= 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}`}>
|
<td className={`py-3 px-4 text-sm font-medium ${txn.amount >= 0 ? 'text-success-600 dark:text-success-400' : 'text-error-600 dark:text-error-400'}`}>
|
||||||
{txn.amount >= 0 ? '+' : ''}{txn.amount}
|
{txn.amount >= 0 ? '+' : ''}{txn.amount}
|
||||||
</td>
|
</td>
|
||||||
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">{txn.description}</td>
|
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">{txn.description}</td>
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export default function CreditCostBreakdownPanel() {
|
|||||||
if (error || !summary) {
|
if (error || !summary) {
|
||||||
return (
|
return (
|
||||||
<Card className="p-6 text-center">
|
<Card className="p-6 text-center">
|
||||||
<AlertCircle className="w-12 h-12 text-red-500 mx-auto mb-4" />
|
<AlertCircle className="w-12 h-12 text-error-500 mx-auto mb-4" />
|
||||||
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
||||||
Failed to Load Cost Data
|
Failed to Load Cost Data
|
||||||
</h3>
|
</h3>
|
||||||
@@ -110,7 +110,7 @@ export default function CreditCostBreakdownPanel() {
|
|||||||
{ bg: 'bg-info-50 dark:bg-info-900/20', text: 'text-info-600 dark:text-info-400', border: 'border-info-500 dark:border-info-400' },
|
{ bg: 'bg-info-50 dark:bg-info-900/20', text: 'text-info-600 dark:text-info-400', border: 'border-info-500 dark:border-info-400' },
|
||||||
{ bg: 'bg-purple-50 dark:bg-purple-900/20', text: 'text-purple-600 dark:text-purple-400', border: 'border-purple-500 dark:border-purple-400' },
|
{ bg: 'bg-purple-50 dark:bg-purple-900/20', text: 'text-purple-600 dark:text-purple-400', border: 'border-purple-500 dark:border-purple-400' },
|
||||||
{ bg: 'bg-warning-50 dark:bg-warning-900/20', text: 'text-warning-600 dark:text-warning-400', border: 'border-warning-500 dark:border-warning-400' },
|
{ bg: 'bg-warning-50 dark:bg-warning-900/20', text: 'text-warning-600 dark:text-warning-400', border: 'border-warning-500 dark:border-warning-400' },
|
||||||
{ bg: 'bg-teal-50 dark:bg-teal-900/20', text: 'text-teal-600 dark:text-teal-400', border: 'border-teal-500 dark:border-teal-400' },
|
{ bg: 'bg-purple-50 dark:bg-purple-900/20', text: 'text-purple-600 dark:text-purple-400', border: 'border-purple-500 dark:border-purple-400' },
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ export default function PaymentConfirmationModal({
|
|||||||
<div className="p-6 sm:p-8">
|
<div className="p-6 sm:p-8">
|
||||||
{success ? (
|
{success ? (
|
||||||
<div className="text-center py-8">
|
<div className="text-center py-8">
|
||||||
<CheckCircle className="w-16 h-16 text-green-500 mx-auto mb-4" />
|
<CheckCircle className="w-16 h-16 text-success-500 mx-auto mb-4" />
|
||||||
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-2">
|
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-2">
|
||||||
Payment Submitted!
|
Payment Submitted!
|
||||||
</h3>
|
</h3>
|
||||||
@@ -193,7 +193,7 @@ export default function PaymentConfirmationModal({
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mb-4 p-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded-lg dark:bg-red-900/20 dark:text-red-400 dark:border-red-800">
|
<div className="mb-4 p-3 text-sm text-error-600 bg-error-50 border border-error-200 rounded-lg dark:bg-error-900/20 dark:text-error-400 dark:border-error-800">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -288,7 +288,7 @@ export default function PaymentConfirmationModal({
|
|||||||
) : (
|
) : (
|
||||||
<div className="mt-2 flex items-center justify-between p-3 bg-gray-50 border border-gray-200 rounded-lg dark:bg-gray-800 dark:border-gray-700">
|
<div className="mt-2 flex items-center justify-between p-3 bg-gray-50 border border-gray-200 rounded-lg dark:bg-gray-800 dark:border-gray-700">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<CheckCircle className="w-5 h-5 text-green-500" />
|
<CheckCircle className="w-5 h-5 text-success-500" />
|
||||||
<span className="text-sm text-gray-700 dark:text-gray-300">
|
<span className="text-sm text-gray-700 dark:text-gray-300">
|
||||||
{uploadedFileName}
|
{uploadedFileName}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -53,11 +53,11 @@ export default function PaymentHistory() {
|
|||||||
const getStatusIcon = (status: string) => {
|
const getStatusIcon = (status: string) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'succeeded':
|
case 'succeeded':
|
||||||
return <CheckCircle className="w-5 h-5 text-green-500" />;
|
return <CheckCircle className="w-5 h-5 text-success-500" />;
|
||||||
case 'failed':
|
case 'failed':
|
||||||
return <XCircle className="w-5 h-5 text-red-500" />;
|
return <XCircle className="w-5 h-5 text-error-500" />;
|
||||||
case 'pending_approval':
|
case 'pending_approval':
|
||||||
return <Clock className="w-5 h-5 text-yellow-500" />;
|
return <Clock className="w-5 h-5 text-warning-500" />;
|
||||||
default:
|
default:
|
||||||
return <Clock className="w-5 h-5 text-gray-500" />;
|
return <Clock className="w-5 h-5 text-gray-500" />;
|
||||||
}
|
}
|
||||||
@@ -65,9 +65,9 @@ export default function PaymentHistory() {
|
|||||||
|
|
||||||
const getStatusBadge = (status: string) => {
|
const getStatusBadge = (status: string) => {
|
||||||
const badges = {
|
const badges = {
|
||||||
succeeded: 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400',
|
succeeded: 'bg-success-100 text-success-800 dark:bg-success-900/20 dark:text-success-400',
|
||||||
failed: 'bg-red-100 text-red-800 dark:bg-red-900/20 dark:text-red-400',
|
failed: 'bg-error-100 text-error-800 dark:bg-error-900/20 dark:text-error-400',
|
||||||
pending_approval: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400',
|
pending_approval: 'bg-warning-100 text-warning-800 dark:bg-warning-900/20 dark:text-warning-400',
|
||||||
refunded: 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-400',
|
refunded: 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-400',
|
||||||
};
|
};
|
||||||
return badges[status as keyof typeof badges] || badges.pending_approval;
|
return badges[status as keyof typeof badges] || badges.pending_approval;
|
||||||
@@ -104,7 +104,7 @@ export default function PaymentHistory() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className="p-4 bg-red-50 border border-red-200 rounded-lg text-red-600 dark:bg-red-900/20 dark:border-red-800">
|
<div className="p-4 bg-error-50 border border-error-200 rounded-lg text-error-600 dark:bg-error-900/20 dark:border-error-800">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export default function PaymentMethodSelect({
|
|||||||
|
|
||||||
if (fetchError) {
|
if (fetchError) {
|
||||||
return (
|
return (
|
||||||
<div className="p-4 rounded-lg border border-red-200 bg-red-50 text-red-800 dark:border-red-800 dark:bg-red-900/20 dark:text-red-200">
|
<div className="p-4 rounded-lg border border-error-200 bg-error-50 text-error-800 dark:border-error-800 dark:bg-error-900/20 dark:text-error-200">
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<AlertCircle className="w-5 h-5 flex-shrink-0 mt-0.5" />
|
<AlertCircle className="w-5 h-5 flex-shrink-0 mt-0.5" />
|
||||||
<div>
|
<div>
|
||||||
@@ -104,7 +104,7 @@ export default function PaymentMethodSelect({
|
|||||||
|
|
||||||
if (methods.length === 0) {
|
if (methods.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="p-4 rounded-lg border border-amber-200 bg-amber-50 text-amber-800 dark:border-amber-800 dark:bg-amber-900/20 dark:text-amber-200">
|
<div className="p-4 rounded-lg border border-warning-200 bg-warning-50 text-warning-800 dark:border-warning-800 dark:bg-warning-900/20 dark:text-warning-200">
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<AlertCircle className="w-5 h-5 flex-shrink-0 mt-0.5" />
|
<AlertCircle className="w-5 h-5 flex-shrink-0 mt-0.5" />
|
||||||
<div>
|
<div>
|
||||||
@@ -123,7 +123,7 @@ export default function PaymentMethodSelect({
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{error && (
|
{error && (
|
||||||
<div className="p-3 text-sm text-red-600 bg-red-50 border border-red-200 rounded-lg dark:bg-red-900/20 dark:text-red-400 dark:border-red-800">
|
<div className="p-3 text-sm text-error-600 bg-error-50 border border-error-200 rounded-lg dark:bg-error-900/20 dark:text-error-400 dark:border-error-800">
|
||||||
{error}
|
{error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -198,8 +198,8 @@ export default function PaymentMethodSelect({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-4 p-4 rounded-lg bg-blue-50 border border-blue-200 dark:bg-blue-900/20 dark:border-blue-800">
|
<div className="mt-4 p-4 rounded-lg bg-brand-50 border border-brand-200 dark:bg-brand-900/20 dark:border-brand-800">
|
||||||
<p className="text-sm text-blue-800 dark:text-blue-200">
|
<p className="text-sm text-brand-800 dark:text-brand-200">
|
||||||
<span className="font-medium">Note:</span> For manual payment methods (bank transfer, local wallets),
|
<span className="font-medium">Note:</span> For manual payment methods (bank transfer, local wallets),
|
||||||
you'll need to complete the payment and then submit proof of payment for admin approval.
|
you'll need to complete the payment and then submit proof of payment for admin approval.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -115,15 +115,15 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
|
|||||||
// If no invoice found, show simplified banner
|
// If no invoice found, show simplified banner
|
||||||
if (!invoice) {
|
if (!invoice) {
|
||||||
return (
|
return (
|
||||||
<div className={`relative border-l-4 border-amber-500 bg-amber-50 dark:bg-amber-900/20 ${className}`}>
|
<div className={`relative border-l-4 border-warning-500 bg-warning-50 dark:bg-warning-900/20 ${className}`}>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<div className="flex items-start gap-4">
|
<div className="flex items-start gap-4">
|
||||||
<AlertCircle className="w-6 h-6 text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5" />
|
<AlertCircle className="w-6 h-6 text-warning-600 dark:text-warning-400 flex-shrink-0 mt-0.5" />
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<h3 className="font-semibold text-amber-900 dark:text-amber-100">
|
<h3 className="font-semibold text-warning-900 dark:text-warning-100">
|
||||||
Payment Required
|
Payment Required
|
||||||
</h3>
|
</h3>
|
||||||
<p className="mt-1 text-sm text-amber-800 dark:text-amber-200">
|
<p className="mt-1 text-sm text-warning-800 dark:text-warning-200">
|
||||||
Your account is pending payment. Please complete your payment to activate your subscription.
|
Your account is pending payment. Please complete your payment to activate your subscription.
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-3 flex gap-2">
|
<div className="mt-3 flex gap-2">
|
||||||
@@ -141,9 +141,9 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={handleDismiss}
|
onClick={handleDismiss}
|
||||||
className="p-1 hover:bg-amber-100 dark:hover:bg-amber-800/40 rounded transition-colors"
|
className="p-1 hover:bg-warning-100 dark:hover:bg-warning-800/40 rounded transition-colors"
|
||||||
>
|
>
|
||||||
<X className="w-5 h-5 text-amber-600 dark:text-amber-400" />
|
<X className="w-5 h-5 text-warning-600 dark:text-warning-400" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -167,59 +167,59 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={`relative border-l-4 ${isOverdue ? 'border-red-500 bg-red-50 dark:bg-red-900/20' : 'border-amber-500 bg-amber-50 dark:bg-amber-900/20'} ${className}`}>
|
<div className={`relative border-l-4 ${isOverdue ? 'border-error-500 bg-error-50 dark:bg-error-900/20' : 'border-warning-500 bg-warning-50 dark:bg-warning-900/20'} ${className}`}>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<div className="flex items-start gap-4">
|
<div className="flex items-start gap-4">
|
||||||
<AlertCircle
|
<AlertCircle
|
||||||
className={`w-6 h-6 flex-shrink-0 mt-0.5 ${isOverdue ? 'text-red-600 dark:text-red-400' : 'text-amber-600 dark:text-amber-400'}`}
|
className={`w-6 h-6 flex-shrink-0 mt-0.5 ${isOverdue ? 'text-error-600 dark:text-error-400' : 'text-warning-600 dark:text-warning-400'}`}
|
||||||
/>
|
/>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<h3 className={`font-semibold ${isOverdue ? 'text-red-900 dark:text-red-100' : 'text-amber-900 dark:text-amber-100'}`}>
|
<h3 className={`font-semibold ${isOverdue ? 'text-error-900 dark:text-error-100' : 'text-warning-900 dark:text-warning-100'}`}>
|
||||||
{isOverdue ? 'Payment Overdue' : 'Payment Required'}
|
{isOverdue ? 'Payment Overdue' : 'Payment Required'}
|
||||||
</h3>
|
</h3>
|
||||||
{isDueSoon && !isOverdue && (
|
{isDueSoon && !isOverdue && (
|
||||||
<span className="px-2 py-0.5 text-xs font-medium rounded bg-amber-200 text-amber-900 dark:bg-amber-700 dark:text-amber-100">
|
<span className="px-2 py-0.5 text-xs font-medium rounded bg-warning-200 text-warning-900 dark:bg-warning-700 dark:text-warning-100">
|
||||||
Due Soon
|
Due Soon
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className={`mt-1 text-sm ${isOverdue ? 'text-red-800 dark:text-red-200' : 'text-amber-800 dark:text-amber-200'}`}>
|
<p className={`mt-1 text-sm ${isOverdue ? 'text-error-800 dark:text-error-200' : 'text-warning-800 dark:text-warning-200'}`}>
|
||||||
Your subscription is pending payment confirmation. Complete your payment to activate your account and unlock all features.
|
Your subscription is pending payment confirmation. Complete your payment to activate your account and unlock all features.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Invoice Details */}
|
{/* Invoice Details */}
|
||||||
<div className="mt-3 grid grid-cols-2 md:grid-cols-4 gap-3 text-sm">
|
<div className="mt-3 grid grid-cols-2 md:grid-cols-4 gap-3 text-sm">
|
||||||
<div>
|
<div>
|
||||||
<span className={`block font-medium ${isOverdue ? 'text-red-700 dark:text-red-300' : 'text-amber-700 dark:text-amber-300'}`}>
|
<span className={`block font-medium ${isOverdue ? 'text-error-700 dark:text-error-300' : 'text-warning-700 dark:text-warning-300'}`}>
|
||||||
Invoice
|
Invoice
|
||||||
</span>
|
</span>
|
||||||
<span className={`${isOverdue ? 'text-red-900 dark:text-red-100' : 'text-amber-900 dark:text-amber-100'}`}>
|
<span className={`${isOverdue ? 'text-error-900 dark:text-error-100' : 'text-warning-900 dark:text-warning-100'}`}>
|
||||||
#{invoice.invoice_number}
|
#{invoice.invoice_number}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span className={`block font-medium ${isOverdue ? 'text-red-700 dark:text-red-300' : 'text-amber-700 dark:text-amber-300'}`}>
|
<span className={`block font-medium ${isOverdue ? 'text-error-700 dark:text-error-300' : 'text-warning-700 dark:text-warning-300'}`}>
|
||||||
Amount
|
Amount
|
||||||
</span>
|
</span>
|
||||||
<span className={`${isOverdue ? 'text-red-900 dark:text-red-100' : 'text-amber-900 dark:text-amber-100'}`}>
|
<span className={`${isOverdue ? 'text-error-900 dark:text-error-100' : 'text-warning-900 dark:text-warning-100'}`}>
|
||||||
{invoice.currency} {invoice.total_amount}
|
{invoice.currency} {invoice.total_amount}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span className={`block font-medium ${isOverdue ? 'text-red-700 dark:text-red-300' : 'text-amber-700 dark:text-amber-300'}`}>
|
<span className={`block font-medium ${isOverdue ? 'text-error-700 dark:text-error-300' : 'text-warning-700 dark:text-warning-300'}`}>
|
||||||
Status
|
Status
|
||||||
</span>
|
</span>
|
||||||
<span className={`${isOverdue ? 'text-red-900 dark:text-red-100' : 'text-amber-900 dark:text-amber-100'} capitalize`}>
|
<span className={`${isOverdue ? 'text-error-900 dark:text-error-100' : 'text-warning-900 dark:text-warning-100'} capitalize`}>
|
||||||
{invoice.status}
|
{invoice.status}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span className={`block font-medium ${isOverdue ? 'text-red-700 dark:text-red-300' : 'text-amber-700 dark:text-amber-300'}`}>
|
<span className={`block font-medium ${isOverdue ? 'text-error-700 dark:text-error-300' : 'text-warning-700 dark:text-warning-300'}`}>
|
||||||
{isOverdue ? 'Was Due' : 'Due Date'}
|
{isOverdue ? 'Was Due' : 'Due Date'}
|
||||||
</span>
|
</span>
|
||||||
<span className={`${isOverdue ? 'text-red-900 dark:text-red-100' : 'text-amber-900 dark:text-amber-100'}`}>
|
<span className={`${isOverdue ? 'text-error-900 dark:text-error-100' : 'text-warning-900 dark:text-warning-100'}`}>
|
||||||
{formatDate(invoice.due_date)}
|
{formatDate(invoice.due_date)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -248,8 +248,8 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
|
|||||||
onClick={handleDismiss}
|
onClick={handleDismiss}
|
||||||
className={`p-1 rounded transition-colors ${
|
className={`p-1 rounded transition-colors ${
|
||||||
isOverdue
|
isOverdue
|
||||||
? 'hover:bg-red-100 dark:hover:bg-red-800/40 text-red-600 dark:text-red-400'
|
? 'hover:bg-error-100 dark:hover:bg-error-800/40 text-error-600 dark:text-error-400'
|
||||||
: 'hover:bg-amber-100 dark:hover:bg-amber-800/40 text-amber-600 dark:text-amber-400'
|
: 'hover:bg-warning-100 dark:hover:bg-warning-800/40 text-warning-600 dark:text-warning-400'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<X className="w-5 h-5" />
|
<X className="w-5 h-5" />
|
||||||
|
|||||||
@@ -29,18 +29,18 @@ function LimitCard({ title, icon, usage, type, daysUntilReset, accentColor = 'br
|
|||||||
let badgeVariant: 'soft' = 'soft';
|
let badgeVariant: 'soft' = 'soft';
|
||||||
let badgeTone: 'brand' | 'warning' | 'danger' | 'success' | 'info' | 'purple' | 'indigo' | 'pink' | 'teal' | 'cyan' = accentColor;
|
let badgeTone: 'brand' | 'warning' | 'danger' | 'success' | 'info' | 'purple' | 'indigo' | 'pink' | 'teal' | 'cyan' = accentColor;
|
||||||
|
|
||||||
// Color mapping for progress bars
|
// Color mapping for progress bars - using CSS variables
|
||||||
const colorMap: Record<string, string> = {
|
const colorMap: Record<string, string> = {
|
||||||
brand: '#0693e3',
|
brand: 'var(--color-primary)',
|
||||||
success: '#0bbf87',
|
success: 'var(--color-success)',
|
||||||
info: '#3b82f6',
|
info: 'var(--color-primary)',
|
||||||
warning: '#ff7a00',
|
warning: 'var(--color-warning)',
|
||||||
danger: '#ef4444',
|
danger: 'var(--color-danger)',
|
||||||
purple: '#8b5cf6',
|
purple: 'var(--color-purple)',
|
||||||
indigo: '#6366f1',
|
indigo: 'var(--color-purple)',
|
||||||
pink: '#ec4899',
|
pink: 'var(--color-purple)',
|
||||||
teal: '#14b8a6',
|
teal: 'var(--color-success)',
|
||||||
cyan: '#06b6d4',
|
cyan: 'var(--color-primary)',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isDanger) {
|
if (isDanger) {
|
||||||
@@ -104,7 +104,7 @@ function LimitCard({ title, icon, usage, type, daysUntilReset, accentColor = 'br
|
|||||||
{/* Warning Message */}
|
{/* Warning Message */}
|
||||||
{isWarning && (
|
{isWarning && (
|
||||||
<div className={`mt-3 flex items-start gap-2 text-xs ${
|
<div className={`mt-3 flex items-start gap-2 text-xs ${
|
||||||
isDanger ? 'text-red-600 dark:text-red-400' : 'text-yellow-600 dark:text-yellow-400'
|
isDanger ? 'text-error-600 dark:text-error-400' : 'text-warning-600 dark:text-warning-400'
|
||||||
}`}>
|
}`}>
|
||||||
<AlertCircle className="w-4 h-4 mt-0.5 flex-shrink-0" />
|
<AlertCircle className="w-4 h-4 mt-0.5 flex-shrink-0" />
|
||||||
<span>
|
<span>
|
||||||
@@ -158,7 +158,7 @@ export default function UsageLimitsPanel() {
|
|||||||
if (error || !summary) {
|
if (error || !summary) {
|
||||||
return (
|
return (
|
||||||
<Card className="p-6 text-center">
|
<Card className="p-6 text-center">
|
||||||
<AlertCircle className="w-12 h-12 text-red-500 mx-auto mb-4" />
|
<AlertCircle className="w-12 h-12 text-error-500 mx-auto mb-4" />
|
||||||
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
||||||
Failed to Load Usage Data
|
Failed to Load Usage Data
|
||||||
</h3>
|
</h3>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ApexOptions } from "apexcharts";
|
|||||||
|
|
||||||
export default function BarChartOne() {
|
export default function BarChartOne() {
|
||||||
const options: ApexOptions = {
|
const options: ApexOptions = {
|
||||||
colors: ["#465fff"],
|
colors: ["var(--color-primary)"],
|
||||||
chart: {
|
chart: {
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "Outfit, sans-serif",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export default function LineChartOne() {
|
|||||||
position: "top",
|
position: "top",
|
||||||
horizontalAlign: "left",
|
horizontalAlign: "left",
|
||||||
},
|
},
|
||||||
colors: ["#465FFF", "#9CB9FF"], // Define line colors
|
colors: ["var(--color-primary)", "var(--color-brand-300)"], // Define line colors
|
||||||
chart: {
|
chart: {
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "Outfit, sans-serif",
|
||||||
height: 310,
|
height: 310,
|
||||||
@@ -88,7 +88,7 @@ export default function LineChartOne() {
|
|||||||
labels: {
|
labels: {
|
||||||
style: {
|
style: {
|
||||||
fontSize: "12px", // Adjust font size for y-axis labels
|
fontSize: "12px", // Adjust font size for y-axis labels
|
||||||
colors: ["#6B7280"], // Color of the labels
|
colors: ["var(--color-gray-500)"], // Color of the labels
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ export default function BulkExportModal({
|
|||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
{/* Header with icon */}
|
{/* Header with icon */}
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
<div className="flex items-center justify-center w-10 h-10 bg-blue-50 rounded-xl dark:bg-blue-500/10">
|
<div className="flex items-center justify-center w-10 h-10 bg-brand-50 rounded-xl dark:bg-brand-500/10">
|
||||||
<InfoIcon className="w-5 h-5 text-blue-500" />
|
<InfoIcon className="w-5 h-5 text-brand-500" />
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-xl font-bold text-gray-800 dark:text-white">
|
<h2 className="text-xl font-bold text-gray-800 dark:text-white">
|
||||||
{title}
|
{title}
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ export default function BulkStatusUpdateModal({
|
|||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
{/* Header with icon */}
|
{/* Header with icon */}
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
<div className="flex items-center justify-center w-10 h-10 bg-blue-50 rounded-xl dark:bg-blue-500/10">
|
<div className="flex items-center justify-center w-10 h-10 bg-brand-50 rounded-xl dark:bg-brand-500/10">
|
||||||
<InfoIcon className="w-5 h-5 text-blue-500" />
|
<InfoIcon className="w-5 h-5 text-brand-500" />
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-xl font-bold text-gray-800 dark:text-white">
|
<h2 className="text-xl font-bold text-gray-800 dark:text-white">
|
||||||
{title}
|
{title}
|
||||||
|
|||||||
@@ -143,10 +143,10 @@ export default function ContentImageCell({ image, maxPromptLength = 100, showPro
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{image.status === 'failed' && (
|
{image.status === 'failed' && (
|
||||||
<div className="w-full h-24 bg-red-100 dark:bg-red-900/20 rounded border border-red-300 dark:border-red-700 flex items-center justify-center">
|
<div className="w-full h-24 bg-error-100 dark:bg-error-900/20 rounded border border-error-300 dark:border-error-700 flex items-center justify-center">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6 mx-auto text-red-500 mb-1"
|
className="w-6 h-6 mx-auto text-error-500 mb-1"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -158,7 +158,7 @@ export default function ContentImageCell({ image, maxPromptLength = 100, showPro
|
|||||||
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p className="text-xs text-red-700 dark:text-red-400">Failed</p>
|
<p className="text-xs text-error-700 dark:text-error-400">Failed</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -18,25 +18,25 @@ export default function GlobalErrorDisplay() {
|
|||||||
{errors.map((error, index) => (
|
{errors.map((error, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg shadow-lg p-4 animate-in slide-in-from-right"
|
className="bg-error-50 dark:bg-error-900/20 border border-error-200 dark:border-error-800 rounded-lg shadow-lg p-4 animate-in slide-in-from-right"
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between gap-2">
|
<div className="flex items-start justify-between gap-2">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-2 mb-1">
|
||||||
<span className="text-red-600 dark:text-red-400 text-lg">⚠️</span>
|
<span className="text-error-600 dark:text-error-400 text-lg">⚠️</span>
|
||||||
<span className="text-sm font-semibold text-red-800 dark:text-red-200">
|
<span className="text-sm font-semibold text-error-800 dark:text-error-200">
|
||||||
{error.source}
|
{error.source}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-red-700 dark:text-red-300 mb-2">
|
<p className="text-sm text-error-700 dark:text-error-300 mb-2">
|
||||||
{error.message}
|
{error.message}
|
||||||
</p>
|
</p>
|
||||||
{error.stack && (
|
{error.stack && (
|
||||||
<details className="mt-2">
|
<details className="mt-2">
|
||||||
<summary className="text-xs text-red-600 dark:text-red-400 cursor-pointer hover:underline">
|
<summary className="text-xs text-error-600 dark:text-error-400 cursor-pointer hover:underline">
|
||||||
Show stack trace
|
Show stack trace
|
||||||
</summary>
|
</summary>
|
||||||
<pre className="mt-2 text-xs bg-red-100 dark:bg-red-900/40 p-2 rounded overflow-auto max-h-32">
|
<pre className="mt-2 text-xs bg-error-100 dark:bg-error-900/40 p-2 rounded overflow-auto max-h-32">
|
||||||
{error.stack}
|
{error.stack}
|
||||||
</pre>
|
</pre>
|
||||||
</details>
|
</details>
|
||||||
@@ -44,7 +44,7 @@ export default function GlobalErrorDisplay() {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => clearError(index)}
|
onClick={() => clearError(index)}
|
||||||
className="text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-200 text-xl leading-none"
|
className="text-error-600 dark:text-error-400 hover:text-error-800 dark:hover:text-error-200 text-xl leading-none"
|
||||||
aria-label="Dismiss error"
|
aria-label="Dismiss error"
|
||||||
>
|
>
|
||||||
×
|
×
|
||||||
@@ -55,7 +55,7 @@ export default function GlobalErrorDisplay() {
|
|||||||
{errors.length > 1 && (
|
{errors.length > 1 && (
|
||||||
<button
|
<button
|
||||||
onClick={clearAllErrors}
|
onClick={clearAllErrors}
|
||||||
className="w-full px-3 py-2 text-xs bg-red-600 text-white rounded hover:bg-red-700"
|
className="w-full px-3 py-2 text-xs bg-error-600 text-white rounded hover:bg-error-700"
|
||||||
>
|
>
|
||||||
Clear All Errors
|
Clear All Errors
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -265,14 +265,14 @@ export default function ImageGenerationCard({
|
|||||||
<div className="border-t border-gray-200 p-5 dark:border-gray-800">
|
<div className="border-t border-gray-200 p-5 dark:border-gray-800">
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
{/* API Provider and Model Display */}
|
{/* API Provider and Model Display */}
|
||||||
<div className="flex items-center gap-3 rounded-lg bg-blue-50 px-4 py-3 dark:bg-blue-900/20">
|
<div className="flex items-center gap-3 rounded-lg bg-brand-50 px-4 py-3 dark:bg-brand-900/20">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="20"
|
width="20"
|
||||||
height="20"
|
height="20"
|
||||||
viewBox="0 0 20 20"
|
viewBox="0 0 20 20"
|
||||||
fill="none"
|
fill="none"
|
||||||
className="text-blue-600 dark:text-blue-400"
|
className="text-brand-600 dark:text-brand-400"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M10 2L3 7V17C3 17.5304 3.21071 18.0391 3.58579 18.4142C3.96086 18.7893 4.46957 19 5 19H15C15.5304 19 16.0391 18.7893 16.4142 18.4142C16.7893 18.0391 17 17.5304 17 17V7L10 2Z"
|
d="M10 2L3 7V17C3 17.5304 3.21071 18.0391 3.58579 18.4142C3.96086 18.7893 4.46957 19 5 19H15C15.5304 19 16.0391 18.7893 16.4142 18.4142C16.7893 18.0391 17 17.5304 17 17V7L10 2Z"
|
||||||
@@ -283,8 +283,8 @@ export default function ImageGenerationCard({
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-medium text-blue-600 dark:text-blue-400">Provider & Model</p>
|
<p className="text-xs font-medium text-brand-600 dark:text-brand-400">Provider & Model</p>
|
||||||
<p className="text-sm font-semibold text-blue-900 dark:text-blue-200">
|
<p className="text-sm font-semibold text-brand-900 dark:text-brand-200">
|
||||||
{getProviderDisplay()}
|
{getProviderDisplay()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -299,7 +299,7 @@ export default function ImageGenerationCard({
|
|||||||
value={prompt}
|
value={prompt}
|
||||||
onChange={(e) => setPrompt(e.target.value)}
|
onChange={(e) => setPrompt(e.target.value)}
|
||||||
rows={6}
|
rows={6}
|
||||||
className="w-full rounded-lg border border-gray-300 px-4 py-3 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
className="w-full rounded-lg border border-gray-300 px-4 py-3 text-sm focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
||||||
placeholder="Describe the visual elements, style, mood, and composition you want in the image..."
|
placeholder="Describe the visual elements, style, mood, and composition you want in the image..."
|
||||||
/>
|
/>
|
||||||
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||||
@@ -316,7 +316,7 @@ export default function ImageGenerationCard({
|
|||||||
value={negativePrompt}
|
value={negativePrompt}
|
||||||
onChange={(e) => setNegativePrompt(e.target.value)}
|
onChange={(e) => setNegativePrompt(e.target.value)}
|
||||||
rows={2}
|
rows={2}
|
||||||
className="w-full rounded-lg border border-gray-300 px-4 py-3 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
className="w-full rounded-lg border border-gray-300 px-4 py-3 text-sm focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
||||||
placeholder="Describe what you DON'T want in the image..."
|
placeholder="Describe what you DON'T want in the image..."
|
||||||
/>
|
/>
|
||||||
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||||
@@ -334,7 +334,7 @@ export default function ImageGenerationCard({
|
|||||||
<select
|
<select
|
||||||
value={imageType}
|
value={imageType}
|
||||||
onChange={(e) => setImageType(e.target.value)}
|
onChange={(e) => setImageType(e.target.value)}
|
||||||
className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
||||||
>
|
>
|
||||||
{typeOptions.map((option) => (
|
{typeOptions.map((option) => (
|
||||||
<option key={option.value} value={option.value}>
|
<option key={option.value} value={option.value}>
|
||||||
@@ -352,7 +352,7 @@ export default function ImageGenerationCard({
|
|||||||
<select
|
<select
|
||||||
value={imageSize}
|
value={imageSize}
|
||||||
onChange={(e) => setImageSize(e.target.value)}
|
onChange={(e) => setImageSize(e.target.value)}
|
||||||
className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
||||||
>
|
>
|
||||||
{sizeOptions.map((option) => (
|
{sizeOptions.map((option) => (
|
||||||
<option key={option.value} value={option.value}>
|
<option key={option.value} value={option.value}>
|
||||||
@@ -370,7 +370,7 @@ export default function ImageGenerationCard({
|
|||||||
<select
|
<select
|
||||||
value={imageFormat}
|
value={imageFormat}
|
||||||
onChange={(e) => setImageFormat(e.target.value)}
|
onChange={(e) => setImageFormat(e.target.value)}
|
||||||
className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500/20 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
|
||||||
>
|
>
|
||||||
{formatOptions.map((option) => (
|
{formatOptions.map((option) => (
|
||||||
<option key={option.value} value={option.value}>
|
<option key={option.value} value={option.value}>
|
||||||
@@ -440,8 +440,8 @@ export default function ImageGenerationCard({
|
|||||||
|
|
||||||
{/* Error display */}
|
{/* Error display */}
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mt-4 rounded-lg border border-red-200 bg-red-50 p-4 dark:border-red-800 dark:bg-red-900/20">
|
<div className="mt-4 rounded-lg border border-error-200 bg-error-50 p-4 dark:border-error-800 dark:bg-error-900/20">
|
||||||
<p className="text-sm text-red-600 dark:text-red-400">{error}</p>
|
<p className="text-sm text-error-600 dark:text-error-400">{error}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -446,11 +446,11 @@ export default function ImageQueueModal({
|
|||||||
const getProgressColor = (status: string) => {
|
const getProgressColor = (status: string) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'completed':
|
case 'completed':
|
||||||
return 'bg-green-500';
|
return 'bg-success-500';
|
||||||
case 'failed':
|
case 'failed':
|
||||||
return 'bg-red-500';
|
return 'bg-error-500';
|
||||||
case 'processing':
|
case 'processing':
|
||||||
return 'bg-blue-500';
|
return 'bg-brand-500';
|
||||||
default:
|
default:
|
||||||
return 'bg-gray-300';
|
return 'bg-gray-300';
|
||||||
}
|
}
|
||||||
@@ -471,7 +471,7 @@ export default function ImageQueueModal({
|
|||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="px-6 py-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
<div className="px-6 py-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<FileIcon className="w-6 h-6 text-blue-500" />
|
<FileIcon className="w-6 h-6 text-brand-500" />
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||||
Generating Images
|
Generating Images
|
||||||
@@ -496,11 +496,11 @@ export default function ImageQueueModal({
|
|||||||
key={item.index}
|
key={item.index}
|
||||||
className={`p-4 rounded-lg border-2 transition-colors ${
|
className={`p-4 rounded-lg border-2 transition-colors ${
|
||||||
item.status === 'processing'
|
item.status === 'processing'
|
||||||
? 'bg-blue-50 dark:bg-blue-900/20 border-blue-500'
|
? 'bg-brand-50 dark:bg-brand-900/20 border-brand-500'
|
||||||
: item.status === 'completed'
|
: item.status === 'completed'
|
||||||
? 'bg-green-50 dark:bg-green-900/20 border-green-500'
|
? 'bg-success-50 dark:bg-success-900/20 border-success-500'
|
||||||
: item.status === 'failed'
|
: item.status === 'failed'
|
||||||
? 'bg-red-50 dark:bg-red-900/20 border-red-500'
|
? 'bg-error-50 dark:bg-error-900/20 border-error-500'
|
||||||
: 'bg-gray-50 dark:bg-gray-700/50 border-gray-300 dark:border-gray-600'
|
: 'bg-gray-50 dark:bg-gray-700/50 border-gray-300 dark:border-gray-600'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -509,7 +509,7 @@ export default function ImageQueueModal({
|
|||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
{/* Header Row */}
|
{/* Header Row */}
|
||||||
<div className="flex items-center gap-3 mb-2">
|
<div className="flex items-center gap-3 mb-2">
|
||||||
<span className="flex items-center justify-center w-6 h-6 rounded-full bg-blue-500 text-white text-xs font-bold">
|
<span className="flex items-center justify-center w-6 h-6 rounded-full bg-brand-500 text-white text-xs font-bold">
|
||||||
{item.index}
|
{item.index}
|
||||||
</span>
|
</span>
|
||||||
<span className="font-semibold text-sm text-gray-900 dark:text-white">
|
<span className="font-semibold text-sm text-gray-900 dark:text-white">
|
||||||
@@ -551,7 +551,7 @@ export default function ImageQueueModal({
|
|||||||
|
|
||||||
{/* Error Message */}
|
{/* Error Message */}
|
||||||
{item.error && (
|
{item.error && (
|
||||||
<div className="mt-2 p-2 bg-red-100 dark:bg-red-900/30 border-l-4 border-red-500 rounded text-xs text-red-700 dark:text-red-300">
|
<div className="mt-2 p-2 bg-error-100 dark:bg-error-900/30 border-l-4 border-error-500 rounded text-xs text-error-700 dark:text-error-300">
|
||||||
{item.error}
|
{item.error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -595,7 +595,7 @@ export default function ImageQueueModal({
|
|||||||
{allDone && (
|
{allDone && (
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
|
className="px-4 py-2 bg-brand-500 text-white rounded-lg hover:bg-brand-600 transition-colors"
|
||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export default function ImageResultCard({
|
|||||||
<div className="border-t border-gray-200 p-5 dark:border-gray-800">
|
<div className="border-t border-gray-200 p-5 dark:border-gray-800">
|
||||||
{errorState ? (
|
{errorState ? (
|
||||||
<div className="flex flex-col items-center justify-center py-12 text-center">
|
<div className="flex flex-col items-center justify-center py-12 text-center">
|
||||||
<div className="mb-4 rounded-full bg-red-100 p-4 dark:bg-red-900/20">
|
<div className="mb-4 rounded-full bg-error-100 p-4 dark:bg-error-900/20">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
@@ -90,7 +90,7 @@ export default function ImageResultCard({
|
|||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
className="text-red-600 dark:text-red-400"
|
className="text-error-600 dark:text-error-400"
|
||||||
>
|
>
|
||||||
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
|
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
|
||||||
<line x1="12" y1="9" x2="12" y2="13" />
|
<line x1="12" y1="9" x2="12" y2="13" />
|
||||||
|
|||||||
@@ -100,10 +100,10 @@ export default function IntegrationCard({
|
|||||||
return 'bg-gray-400 dark:bg-gray-500 animate-pulse'; // Grey while validating (with pulse)
|
return 'bg-gray-400 dark:bg-gray-500 animate-pulse'; // Grey while validating (with pulse)
|
||||||
}
|
}
|
||||||
if (validationStatus === 'success') {
|
if (validationStatus === 'success') {
|
||||||
return 'bg-green-500 dark:bg-green-600'; // Green for success
|
return 'bg-success-500 dark:bg-success-600'; // Green for success
|
||||||
}
|
}
|
||||||
if (validationStatus === 'error') {
|
if (validationStatus === 'error') {
|
||||||
return 'bg-red-500 dark:bg-red-600'; // Red for error
|
return 'bg-error-500 dark:bg-error-600'; // Red for error
|
||||||
}
|
}
|
||||||
return 'bg-gray-400 dark:bg-gray-500'; // Default grey
|
return 'bg-gray-400 dark:bg-gray-500'; // Default grey
|
||||||
};
|
};
|
||||||
@@ -120,7 +120,7 @@ export default function IntegrationCard({
|
|||||||
return { text: 'Enabled', color: 'text-gray-800 dark:text-white', bold: true };
|
return { text: 'Enabled', color: 'text-gray-800 dark:text-white', bold: true };
|
||||||
}
|
}
|
||||||
if (validationStatus === 'error') {
|
if (validationStatus === 'error') {
|
||||||
return { text: 'Error', color: 'text-red-600 dark:text-red-400', bold: false };
|
return { text: 'Error', color: 'text-error-600 dark:text-error-400', bold: false };
|
||||||
}
|
}
|
||||||
return { text: 'Disabled', color: 'text-gray-400 dark:text-gray-500', bold: false };
|
return { text: 'Disabled', color: 'text-gray-400 dark:text-gray-500', bold: false };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -100,18 +100,18 @@ export default function PageHeader({
|
|||||||
}, [activeSite?.id, activeSite?.is_active, hideSiteSector, loadSectorsForSite, addError]);
|
}, [activeSite?.id, activeSite?.is_active, hideSiteSector, loadSectorsForSite, addError]);
|
||||||
|
|
||||||
const badgeColors = {
|
const badgeColors = {
|
||||||
blue: { bg: 'bg-blue-600 dark:bg-blue-500', light: 'bg-blue-100 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300' },
|
blue: { bg: 'bg-brand-600 dark:bg-brand-500', light: 'bg-brand-100 text-brand-700 dark:bg-brand-500/20 dark:text-brand-300' },
|
||||||
green: { bg: 'bg-green-600 dark:bg-green-500', light: 'bg-green-100 text-green-700 dark:bg-green-500/20 dark:text-green-300' },
|
green: { bg: 'bg-success-600 dark:bg-success-500', light: 'bg-success-100 text-success-700 dark:bg-success-500/20 dark:text-success-300' },
|
||||||
purple: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
purple: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
orange: { bg: 'bg-orange-600 dark:bg-orange-500', light: 'bg-orange-100 text-orange-700 dark:bg-orange-500/20 dark:text-orange-300' },
|
orange: { bg: 'bg-warning-600 dark:bg-warning-500', light: 'bg-warning-100 text-warning-700 dark:bg-warning-500/20 dark:text-warning-300' },
|
||||||
red: { bg: 'bg-red-600 dark:bg-red-500', light: 'bg-red-100 text-red-700 dark:bg-red-500/20 dark:text-red-300' },
|
red: { bg: 'bg-error-600 dark:bg-error-500', light: 'bg-error-100 text-error-700 dark:bg-error-500/20 dark:text-error-300' },
|
||||||
indigo: { bg: 'bg-indigo-600 dark:bg-indigo-500', light: 'bg-indigo-100 text-indigo-700 dark:bg-indigo-500/20 dark:text-indigo-300' },
|
indigo: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
yellow: { bg: 'bg-yellow-600 dark:bg-yellow-500', light: 'bg-yellow-100 text-yellow-700 dark:bg-yellow-500/20 dark:text-yellow-300' },
|
yellow: { bg: 'bg-warning-600 dark:bg-warning-500', light: 'bg-warning-100 text-warning-700 dark:bg-warning-500/20 dark:text-warning-300' },
|
||||||
pink: { bg: 'bg-pink-600 dark:bg-pink-500', light: 'bg-pink-100 text-pink-700 dark:bg-pink-500/20 dark:text-pink-300' },
|
pink: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
emerald: { bg: 'bg-emerald-600 dark:bg-emerald-500', light: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-500/20 dark:text-emerald-300' },
|
emerald: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
cyan: { bg: 'bg-cyan-600 dark:bg-cyan-500', light: 'bg-cyan-100 text-cyan-700 dark:bg-cyan-500/20 dark:text-cyan-300' },
|
cyan: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
amber: { bg: 'bg-amber-600 dark:bg-amber-500', light: 'bg-amber-100 text-amber-700 dark:bg-amber-500/20 dark:text-amber-300' },
|
amber: { bg: 'bg-warning-600 dark:bg-warning-500', light: 'bg-warning-100 text-warning-700 dark:bg-warning-500/20 dark:text-warning-300' },
|
||||||
teal: { bg: 'bg-teal-600 dark:bg-teal-500', light: 'bg-teal-100 text-teal-700 dark:bg-teal-500/20 dark:text-teal-300' },
|
teal: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -775,7 +775,7 @@ export default function ProgressModal({
|
|||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
{/* Big centered check icon */}
|
{/* Big centered check icon */}
|
||||||
<div className="flex justify-center mb-4">
|
<div className="flex justify-center mb-4">
|
||||||
<div className="w-16 h-16 rounded-full bg-green-600 dark:bg-green-700 flex items-center justify-center">
|
<div className="w-16 h-16 rounded-full bg-success-600 dark:bg-success-700 flex items-center justify-center">
|
||||||
<svg className="w-10 h-10 text-white" fill="currentColor" viewBox="0 0 20 20">
|
<svg className="w-10 h-10 text-white" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
@@ -783,7 +783,7 @@ export default function ProgressModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Dark success alert box with centered text */}
|
{/* Dark success alert box with centered text */}
|
||||||
<div className="p-5 rounded-lg bg-green-600 dark:bg-green-700 border border-green-700 dark:border-green-600">
|
<div className="p-5 rounded-lg bg-success-600 dark:bg-success-700 border border-success-700 dark:border-success-600">
|
||||||
<div className="text-base font-semibold text-white text-center whitespace-pre-line">
|
<div className="text-base font-semibold text-white text-center whitespace-pre-line">
|
||||||
{successMessage}
|
{successMessage}
|
||||||
</div>
|
</div>
|
||||||
@@ -798,14 +798,14 @@ export default function ProgressModal({
|
|||||||
key={index}
|
key={index}
|
||||||
className={`flex items-center gap-3 p-3 rounded-lg border transition-all ${
|
className={`flex items-center gap-3 p-3 rounded-lg border transition-all ${
|
||||||
item.completed
|
item.completed
|
||||||
? 'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800'
|
? 'bg-success-50 dark:bg-success-900/20 border-success-200 dark:border-success-800'
|
||||||
: 'bg-gray-50 dark:bg-gray-800 border-gray-200 dark:border-gray-700 opacity-60'
|
: 'bg-gray-50 dark:bg-gray-800 border-gray-200 dark:border-gray-700 opacity-60'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{/* Icon - only checkmark for completed, gray circle for pending */}
|
{/* Icon - only checkmark for completed, gray circle for pending */}
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
{item.completed ? (
|
{item.completed ? (
|
||||||
<svg className="w-5 h-5 text-green-600 dark:text-green-400" fill="currentColor" viewBox="0 0 20 20">
|
<svg className="w-5 h-5 text-success-600 dark:text-success-400" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
) : (
|
) : (
|
||||||
@@ -817,7 +817,7 @@ export default function ProgressModal({
|
|||||||
<span
|
<span
|
||||||
className={`flex-1 text-sm font-medium ${
|
className={`flex-1 text-sm font-medium ${
|
||||||
item.completed
|
item.completed
|
||||||
? 'text-green-800 dark:text-green-300'
|
? 'text-success-800 dark:text-success-300'
|
||||||
: 'text-gray-500 dark:text-gray-400'
|
: 'text-gray-500 dark:text-gray-400'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -834,7 +834,7 @@ export default function ProgressModal({
|
|||||||
variant="primary"
|
variant="primary"
|
||||||
size="lg"
|
size="lg"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="bg-green-600 hover:bg-green-700 dark:bg-green-700 dark:hover:bg-green-800 text-white px-8 py-3 text-base font-semibold"
|
className="bg-success-600 hover:bg-success-700 dark:bg-success-700 dark:hover:bg-success-800 text-white px-8 py-3 text-base font-semibold"
|
||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -97,14 +97,14 @@ export default function SectorSelector() {
|
|||||||
onItemClick={() => handleSectorSelect(null)}
|
onItemClick={() => handleSectorSelect(null)}
|
||||||
className={`flex items-center gap-3 px-3 py-2 font-medium rounded-lg text-sm text-left ${
|
className={`flex items-center gap-3 px-3 py-2 font-medium rounded-lg text-sm text-left ${
|
||||||
!activeSector
|
!activeSector
|
||||||
? "bg-blue-50 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300"
|
? "bg-brand-50 text-brand-700 dark:bg-brand-500/20 dark:text-brand-300"
|
||||||
: "text-gray-700 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
|
: "text-gray-700 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span className="flex-1">All Sectors</span>
|
<span className="flex-1">All Sectors</span>
|
||||||
{!activeSector && (
|
{!activeSector && (
|
||||||
<svg
|
<svg
|
||||||
className="w-4 h-4 text-blue-600 dark:text-blue-400"
|
className="w-4 h-4 text-brand-600 dark:text-brand-400"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
viewBox="0 0 20 20"
|
viewBox="0 0 20 20"
|
||||||
>
|
>
|
||||||
@@ -122,14 +122,14 @@ export default function SectorSelector() {
|
|||||||
onItemClick={() => handleSectorSelect(sector.id)}
|
onItemClick={() => handleSectorSelect(sector.id)}
|
||||||
className={`flex items-center gap-3 px-3 py-2 font-medium rounded-lg text-sm text-left ${
|
className={`flex items-center gap-3 px-3 py-2 font-medium rounded-lg text-sm text-left ${
|
||||||
activeSector?.id === sector.id
|
activeSector?.id === sector.id
|
||||||
? "bg-blue-50 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300"
|
? "bg-brand-50 text-brand-700 dark:bg-brand-500/20 dark:text-brand-300"
|
||||||
: "text-gray-700 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
|
: "text-gray-700 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span className="flex-1">{sector.name}</span>
|
<span className="flex-1">{sector.name}</span>
|
||||||
{activeSector?.id === sector.id && (
|
{activeSector?.id === sector.id && (
|
||||||
<svg
|
<svg
|
||||||
className="w-4 h-4 text-blue-600 dark:text-blue-400"
|
className="w-4 h-4 text-brand-600 dark:text-brand-400"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
viewBox="0 0 20 20"
|
viewBox="0 0 20 20"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ export default function SingleRecordStatusUpdateModal({
|
|||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
{/* Header with icon */}
|
{/* Header with icon */}
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
<div className="flex items-center justify-center w-10 h-10 bg-blue-50 rounded-xl dark:bg-blue-500/10">
|
<div className="flex items-center justify-center w-10 h-10 bg-brand-50 rounded-xl dark:bg-brand-500/10">
|
||||||
<InfoIcon className="w-5 h-5 text-blue-500" />
|
<InfoIcon className="w-5 h-5 text-brand-500" />
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-xl font-bold text-gray-800 dark:text-white">
|
<h2 className="text-xl font-bold text-gray-800 dark:text-white">
|
||||||
{title}
|
{title}
|
||||||
|
|||||||
@@ -28,14 +28,14 @@ export default function SiteCard({
|
|||||||
|
|
||||||
const getStatusColor = () => {
|
const getStatusColor = () => {
|
||||||
if (site.is_active) {
|
if (site.is_active) {
|
||||||
return 'bg-green-500 dark:bg-green-600';
|
return 'bg-success-500 dark:bg-success-600';
|
||||||
}
|
}
|
||||||
return 'bg-gray-400 dark:bg-gray-500';
|
return 'bg-gray-400 dark:bg-gray-500';
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStatusText = () => {
|
const getStatusText = () => {
|
||||||
if (site.is_active) {
|
if (site.is_active) {
|
||||||
return { text: 'Active', color: 'text-green-600 dark:text-green-400', bold: true };
|
return { text: 'Active', color: 'text-success-600 dark:text-success-400', bold: true };
|
||||||
}
|
}
|
||||||
return { text: 'Inactive', color: 'text-gray-400 dark:text-gray-500', bold: false };
|
return { text: 'Inactive', color: 'text-gray-400 dark:text-gray-500', bold: false };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ export const ToggleButton: React.FC<ToggleButtonProps> = ({
|
|||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={`inline-flex items-center justify-center w-8 h-8 rounded-lg transition-all duration-200 ${
|
className={`inline-flex items-center justify-center w-8 h-8 rounded-lg transition-all duration-200 ${
|
||||||
isExpanded
|
isExpanded
|
||||||
? 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20'
|
? 'text-brand-600 dark:text-brand-400 bg-brand-50 dark:bg-brand-900/20'
|
||||||
: 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800'
|
: 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800'
|
||||||
} ${className}`}
|
} ${className}`}
|
||||||
aria-label={isExpanded ? 'Collapse content' : 'Expand content'}
|
aria-label={isExpanded ? 'Collapse content' : 'Expand content'}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ export default function ValidationCard({
|
|||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{/* Success Message */}
|
{/* Success Message */}
|
||||||
{testResult.success && (
|
{testResult.success && (
|
||||||
<div className="flex items-center gap-2 text-green-600 dark:text-green-400">
|
<div className="flex items-center gap-2 text-success-600 dark:text-success-400">
|
||||||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
|
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
@@ -171,7 +171,7 @@ export default function ValidationCard({
|
|||||||
|
|
||||||
{/* Error Message */}
|
{/* Error Message */}
|
||||||
{!testResult.success && (
|
{!testResult.success && (
|
||||||
<div className="flex items-center gap-2 text-red-600 dark:text-red-400">
|
<div className="flex items-center gap-2 text-error-600 dark:text-error-400">
|
||||||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
|
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
@@ -181,7 +181,7 @@ export default function ValidationCard({
|
|||||||
|
|
||||||
{/* Detailed Results Box */}
|
{/* Detailed Results Box */}
|
||||||
{testResult.success && (
|
{testResult.success && (
|
||||||
<div className="bg-blue-50 dark:bg-blue-900/20 border-l-4 border-blue-500 p-4 rounded">
|
<div className="bg-brand-50 dark:bg-brand-900/20 border-l-4 border-brand-500 p-4 rounded">
|
||||||
<div className="space-y-2 text-sm">
|
<div className="space-y-2 text-sm">
|
||||||
{integrationId === 'openai' && withResponse ? (
|
{integrationId === 'openai' && withResponse ? (
|
||||||
// OpenAI response test details
|
// OpenAI response test details
|
||||||
@@ -241,7 +241,7 @@ export default function ValidationCard({
|
|||||||
href={testResult.full_response.image_url}
|
href={testResult.full_response.image_url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-blue-600 dark:text-blue-400 hover:underline"
|
className="text-brand-600 dark:text-brand-400 hover:underline"
|
||||||
>
|
>
|
||||||
View Image
|
View Image
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -27,32 +27,32 @@ export const WorkflowInsights: React.FC<WorkflowInsightsProps> = ({ insights, cl
|
|||||||
|
|
||||||
const notificationColors = hasCritical
|
const notificationColors = hasCritical
|
||||||
? {
|
? {
|
||||||
bg: 'bg-amber-50 dark:bg-amber-500/10',
|
bg: 'bg-warning-50 dark:bg-warning-500/10',
|
||||||
border: 'border-amber-300 dark:border-amber-700',
|
border: 'border-warning-300 dark:border-warning-700',
|
||||||
iconBg: 'bg-amber-100 dark:bg-amber-500/20',
|
iconBg: 'bg-warning-100 dark:bg-warning-500/20',
|
||||||
}
|
}
|
||||||
: hasSuccess
|
: hasSuccess
|
||||||
? {
|
? {
|
||||||
bg: 'bg-green-50 dark:bg-green-500/10',
|
bg: 'bg-success-50 dark:bg-success-500/10',
|
||||||
border: 'border-green-300 dark:border-green-700',
|
border: 'border-success-300 dark:border-success-700',
|
||||||
iconBg: 'bg-green-100 dark:bg-green-500/20',
|
iconBg: 'bg-success-100 dark:bg-success-500/20',
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
bg: 'bg-blue-50 dark:bg-blue-500/10',
|
bg: 'bg-brand-50 dark:bg-brand-500/10',
|
||||||
border: 'border-blue-300 dark:border-blue-700',
|
border: 'border-brand-300 dark:border-brand-700',
|
||||||
iconBg: 'bg-blue-100 dark:bg-blue-500/20',
|
iconBg: 'bg-brand-100 dark:bg-brand-500/20',
|
||||||
};
|
};
|
||||||
|
|
||||||
const getIcon = (type: string) => {
|
const getIcon = (type: string) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'success':
|
case 'success':
|
||||||
return <CheckCircleIcon className="w-5 h-5 text-green-600 dark:text-green-400" />;
|
return <CheckCircleIcon className="w-5 h-5 text-success-600 dark:text-success-400" />;
|
||||||
case 'warning':
|
case 'warning':
|
||||||
return <AlertIcon className="w-5 h-5 text-amber-600 dark:text-amber-400" />;
|
return <AlertIcon className="w-5 h-5 text-warning-600 dark:text-warning-400" />;
|
||||||
case 'action':
|
case 'action':
|
||||||
return <BoltIcon className="w-5 h-5 text-blue-600 dark:text-blue-400" />;
|
return <BoltIcon className="w-5 h-5 text-brand-600 dark:text-brand-400" />;
|
||||||
default:
|
default:
|
||||||
return <InfoIcon className="w-5 h-5 text-blue-600 dark:text-blue-400" />;
|
return <InfoIcon className="w-5 h-5 text-brand-600 dark:text-brand-400" />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export const ContentFilter: React.FC<ContentFilterProps> = ({ onFilterChange, cl
|
|||||||
placeholder="Search content..."
|
placeholder="Search content..."
|
||||||
value={filters.search}
|
value={filters.search}
|
||||||
onChange={handleSearchChange}
|
onChange={handleSearchChange}
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-gray-800 dark:border-gray-600 dark:text-white"
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-brand-500 focus:border-transparent dark:bg-gray-800 dark:border-gray-600 dark:text-white"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ export const ContentFilter: React.FC<ContentFilterProps> = ({ onFilterChange, cl
|
|||||||
onClick={() => handleSourceChange('all')}
|
onClick={() => handleSourceChange('all')}
|
||||||
className={`px-3 py-1 rounded-full text-sm font-medium transition-colors ${
|
className={`px-3 py-1 rounded-full text-sm font-medium transition-colors ${
|
||||||
filters.source === 'all'
|
filters.source === 'all'
|
||||||
? 'bg-blue-500 text-white'
|
? 'bg-brand-500 text-white'
|
||||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600'
|
: 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -63,7 +63,7 @@ export const ContentFilter: React.FC<ContentFilterProps> = ({ onFilterChange, cl
|
|||||||
onClick={() => handleSourceChange(source)}
|
onClick={() => handleSourceChange(source)}
|
||||||
className={`px-3 py-1 rounded-full text-sm font-medium transition-colors ${
|
className={`px-3 py-1 rounded-full text-sm font-medium transition-colors ${
|
||||||
filters.source === source
|
filters.source === source
|
||||||
? 'bg-blue-500 text-white'
|
? 'bg-brand-500 text-white'
|
||||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600'
|
: 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ interface SourceBadgeProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sourceConfig = {
|
const sourceConfig = {
|
||||||
igny8: { label: 'IGNY8', color: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300' },
|
igny8: { label: 'IGNY8', color: 'bg-brand-100 text-brand-800 dark:bg-brand-900 dark:text-brand-300' },
|
||||||
wordpress: { label: 'WordPress', color: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300' },
|
wordpress: { label: 'WordPress', color: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300' },
|
||||||
shopify: { label: 'Shopify', color: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300' },
|
shopify: { label: 'Shopify', color: 'bg-success-100 text-success-800 dark:bg-success-900 dark:text-success-300' },
|
||||||
custom: { label: 'Custom', color: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300' },
|
custom: { label: 'Custom', color: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300' },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ interface SyncStatusBadgeProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const statusConfig = {
|
const statusConfig = {
|
||||||
native: { label: 'Native', color: 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-300' },
|
native: { label: 'Native', color: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300' },
|
||||||
imported: { label: 'Imported', color: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300' },
|
imported: { label: 'Imported', color: 'bg-warning-100 text-warning-800 dark:bg-warning-900 dark:text-warning-300' },
|
||||||
synced: { label: 'Synced', color: 'bg-teal-100 text-teal-800 dark:bg-teal-900 dark:text-teal-300' },
|
synced: { label: 'Synced', color: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300' },
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SyncStatusBadge: React.FC<SyncStatusBadgeProps> = ({ status, className = '' }) => {
|
export const SyncStatusBadge: React.FC<SyncStatusBadgeProps> = ({ status, className = '' }) => {
|
||||||
|
|||||||
@@ -35,13 +35,16 @@ interface AIOperationsWidgetProps {
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const operationConfig = {
|
const operationConfig: Record<string, { label: string; icon: typeof GroupIcon; color: string }> = {
|
||||||
clustering: { label: 'Clustering', icon: GroupIcon, color: 'text-purple-600 dark:text-purple-400' },
|
clustering: { label: 'Clustering', icon: GroupIcon, color: 'text-purple-600 dark:text-purple-400' },
|
||||||
ideas: { label: 'Ideas', icon: BoltIcon, color: 'text-orange-600 dark:text-orange-400' },
|
ideas: { label: 'Ideas', icon: BoltIcon, color: 'text-warning-600 dark:text-warning-400' },
|
||||||
content: { label: 'Content', icon: FileTextIcon, color: 'text-green-600 dark:text-green-400' },
|
content: { label: 'Content', icon: FileTextIcon, color: 'text-success-600 dark:text-success-400' },
|
||||||
images: { label: 'Images', icon: FileIcon, color: 'text-pink-600 dark:text-pink-400' },
|
images: { label: 'Images', icon: FileIcon, color: 'text-purple-600 dark:text-purple-400' },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Default config for unknown operation types
|
||||||
|
const defaultConfig = { label: 'Other', icon: BoltIcon, color: 'text-gray-600 dark:text-gray-400' };
|
||||||
|
|
||||||
const periods = [
|
const periods = [
|
||||||
{ value: '7d', label: '7 days' },
|
{ value: '7d', label: '7 days' },
|
||||||
{ value: '30d', label: '30 days' },
|
{ value: '30d', label: '30 days' },
|
||||||
@@ -105,7 +108,7 @@ export default function AIOperationsWidget({ data, onPeriodChange, loading }: AI
|
|||||||
|
|
||||||
{/* Operation Rows */}
|
{/* Operation Rows */}
|
||||||
{data.operations.map((op) => {
|
{data.operations.map((op) => {
|
||||||
const config = operationConfig[op.type];
|
const config = operationConfig[op.type] || defaultConfig;
|
||||||
const Icon = config.icon;
|
const Icon = config.icon;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -144,7 +147,7 @@ export default function AIOperationsWidget({ data, onPeriodChange, loading }: AI
|
|||||||
{/* Stats Footer */}
|
{/* Stats Footer */}
|
||||||
<div className="flex items-center justify-between mt-4 pt-3 border-t border-gray-200 dark:border-gray-700">
|
<div className="flex items-center justify-between mt-4 pt-3 border-t border-gray-200 dark:border-gray-700">
|
||||||
<div className="text-sm text-gray-600 dark:text-gray-400">
|
<div className="text-sm text-gray-600 dark:text-gray-400">
|
||||||
Success Rate: <span className="font-semibold text-green-600 dark:text-green-400">
|
Success Rate: <span className="font-semibold text-success-600 dark:text-success-400">
|
||||||
{loading ? '—' : `${data.totals.successRate}%`}
|
{loading ? '—' : `${data.totals.successRate}%`}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ interface AutomationStatusWidgetProps {
|
|||||||
const statusConfig = {
|
const statusConfig = {
|
||||||
active: {
|
active: {
|
||||||
label: 'Active',
|
label: 'Active',
|
||||||
color: 'text-green-600 dark:text-green-400',
|
color: 'text-success-600 dark:text-success-400',
|
||||||
bgColor: 'bg-green-500',
|
bgColor: 'bg-success-500',
|
||||||
icon: CheckCircleIcon,
|
icon: CheckCircleIcon,
|
||||||
},
|
},
|
||||||
paused: {
|
paused: {
|
||||||
@@ -49,8 +49,8 @@ const statusConfig = {
|
|||||||
},
|
},
|
||||||
failed: {
|
failed: {
|
||||||
label: 'Failed',
|
label: 'Failed',
|
||||||
color: 'text-red-600 dark:text-red-400',
|
color: 'text-error-600 dark:text-error-400',
|
||||||
bgColor: 'bg-red-500',
|
bgColor: 'bg-error-500',
|
||||||
icon: AlertIcon,
|
icon: AlertIcon,
|
||||||
},
|
},
|
||||||
not_configured: {
|
not_configured: {
|
||||||
|
|||||||
@@ -95,11 +95,11 @@ export default function ContentVelocityWidget({ data, loading }: ContentVelocity
|
|||||||
<div className="flex items-center justify-between mt-4 pt-3 border-t border-gray-200 dark:border-gray-700">
|
<div className="flex items-center justify-between mt-4 pt-3 border-t border-gray-200 dark:border-gray-700">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{isPositiveTrend ? (
|
{isPositiveTrend ? (
|
||||||
<TrendingUpIcon className="w-5 h-5 text-green-600" />
|
<TrendingUpIcon className="w-5 h-5 text-success-600" />
|
||||||
) : (
|
) : (
|
||||||
<TrendingDownIcon className="w-5 h-5 text-red-600" />
|
<TrendingDownIcon className="w-5 h-5 text-error-600" />
|
||||||
)}
|
)}
|
||||||
<span className={`text-sm font-semibold ${isPositiveTrend ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}`}>
|
<span className={`text-sm font-semibold ${isPositiveTrend ? 'text-success-600 dark:text-success-400' : 'text-error-600 dark:text-error-400'}`}>
|
||||||
{isPositiveTrend ? '+' : ''}{data.trend}% vs last week
|
{isPositiveTrend ? '+' : ''}{data.trend}% vs last week
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ interface CreditAvailabilityWidgetProps {
|
|||||||
// Average credit costs per operation
|
// Average credit costs per operation
|
||||||
const OPERATION_COSTS = {
|
const OPERATION_COSTS = {
|
||||||
clustering: { label: 'Clustering Runs', cost: 10, icon: GroupIcon, color: 'text-purple-600 dark:text-purple-400' },
|
clustering: { label: 'Clustering Runs', cost: 10, icon: GroupIcon, color: 'text-purple-600 dark:text-purple-400' },
|
||||||
ideas: { label: 'Content Ideas', cost: 2, icon: BoltIcon, color: 'text-orange-600 dark:text-orange-400' },
|
ideas: { label: 'Content Ideas', cost: 2, icon: BoltIcon, color: 'text-warning-600 dark:text-warning-400' },
|
||||||
content: { label: 'Articles', cost: 50, icon: FileTextIcon, color: 'text-green-600 dark:text-green-400' },
|
content: { label: 'Articles', cost: 50, icon: FileTextIcon, color: 'text-success-600 dark:text-success-400' },
|
||||||
images: { label: 'Images', cost: 5, icon: FileIcon, color: 'text-pink-600 dark:text-pink-400' },
|
images: { label: 'Images', cost: 5, icon: FileIcon, color: 'text-purple-600 dark:text-purple-400' },
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function CreditAvailabilityWidget({
|
export default function CreditAvailabilityWidget({
|
||||||
@@ -70,7 +70,7 @@ export default function CreditAvailabilityWidget({
|
|||||||
<div className="w-full bg-white dark:bg-gray-800 rounded-full h-2 mb-1">
|
<div className="w-full bg-white dark:bg-gray-800 rounded-full h-2 mb-1">
|
||||||
<div
|
<div
|
||||||
className={`h-2 rounded-full transition-all ${
|
className={`h-2 rounded-full transition-all ${
|
||||||
usagePercent > 90 ? 'bg-red-500' : usagePercent > 75 ? 'bg-amber-500' : 'bg-green-500'
|
usagePercent > 90 ? 'bg-error-500' : usagePercent > 75 ? 'bg-warning-500' : 'bg-success-500'
|
||||||
}`}
|
}`}
|
||||||
style={{ width: `${Math.max(100 - usagePercent, 0)}%` }}
|
style={{ width: `${Math.max(100 - usagePercent, 0)}%` }}
|
||||||
></div>
|
></div>
|
||||||
@@ -119,8 +119,8 @@ export default function CreditAvailabilityWidget({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span className={`text-lg font-bold ${
|
<span className={`text-lg font-bold ${
|
||||||
op.available > 10 ? 'text-green-600 dark:text-green-400' :
|
op.available > 10 ? 'text-success-600 dark:text-success-400' :
|
||||||
op.available > 0 ? 'text-amber-600 dark:text-amber-400' :
|
op.available > 0 ? 'text-warning-600 dark:text-warning-400' :
|
||||||
'text-gray-400 dark:text-gray-600'
|
'text-gray-400 dark:text-gray-600'
|
||||||
}`}>
|
}`}>
|
||||||
{op.available === 0 ? '—' : op.available > 999 ? '999+' : op.available}
|
{op.available === 0 ? '—' : op.available > 999 ? '999+' : op.available}
|
||||||
@@ -134,7 +134,7 @@ export default function CreditAvailabilityWidget({
|
|||||||
{/* Warning if low */}
|
{/* Warning if low */}
|
||||||
{!loading && availableCredits > 0 && availableCredits < 100 && (
|
{!loading && availableCredits > 0 && availableCredits < 100 && (
|
||||||
<div className="mt-4 pt-3 border-t border-gray-200 dark:border-gray-700">
|
<div className="mt-4 pt-3 border-t border-gray-200 dark:border-gray-700">
|
||||||
<div className="flex items-start gap-2 text-amber-600 dark:text-amber-400">
|
<div className="flex items-start gap-2 text-warning-600 dark:text-warning-400">
|
||||||
<DollarLineIcon className="w-4 h-4 mt-0.5" />
|
<DollarLineIcon className="w-4 h-4 mt-0.5" />
|
||||||
<p className="text-xs">
|
<p className="text-xs">
|
||||||
You're running low on credits. Consider purchasing more to avoid interruptions.
|
You're running low on credits. Consider purchasing more to avoid interruptions.
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default function CreditBalanceWidget() {
|
|||||||
if (error && !balance) {
|
if (error && !balance) {
|
||||||
return (
|
return (
|
||||||
<ComponentCard title="Content Usage" desc="Usage unavailable">
|
<ComponentCard title="Content Usage" desc="Usage unavailable">
|
||||||
<div className="text-sm text-red-600 dark:text-red-400 mb-3">
|
<div className="text-sm text-error-600 dark:text-error-400 mb-3">
|
||||||
Usage unavailable. Please retry.
|
Usage unavailable. Please retry.
|
||||||
</div>
|
</div>
|
||||||
<Button variant="outline" size="sm" onClick={loadBalance}>
|
<Button variant="outline" size="sm" onClick={loadBalance}>
|
||||||
@@ -68,7 +68,7 @@ export default function CreditBalanceWidget() {
|
|||||||
<span className="text-sm font-medium text-success">{balance.credits_remaining}</span>
|
<span className="text-sm font-medium text-success">{balance.credits_remaining}</span>
|
||||||
</div>
|
</div>
|
||||||
{error && (
|
{error && (
|
||||||
<div className="mt-2 text-xs text-amber-600 dark:text-amber-400">
|
<div className="mt-2 text-xs text-warning-600 dark:text-warning-400">
|
||||||
Usage may be outdated. {error}
|
Usage may be outdated. {error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -19,20 +19,20 @@ export interface MetricCardProps {
|
|||||||
|
|
||||||
const accentColors = {
|
const accentColors = {
|
||||||
blue: {
|
blue: {
|
||||||
bg: "bg-blue-50 dark:bg-blue-500/10",
|
bg: "bg-brand-50 dark:bg-brand-500/10",
|
||||||
hover: "hover:bg-blue-100 dark:hover:bg-blue-500/20",
|
hover: "hover:bg-brand-100 dark:hover:bg-brand-500/20",
|
||||||
border: "bg-brand-500",
|
border: "bg-brand-500",
|
||||||
icon: "text-brand-500",
|
icon: "text-brand-500",
|
||||||
},
|
},
|
||||||
green: {
|
green: {
|
||||||
bg: "bg-green-50 dark:bg-green-500/10",
|
bg: "bg-success-50 dark:bg-success-500/10",
|
||||||
hover: "hover:bg-green-100 dark:hover:bg-green-500/20",
|
hover: "hover:bg-success-100 dark:hover:bg-success-500/20",
|
||||||
border: "bg-success-500",
|
border: "bg-success-500",
|
||||||
icon: "text-success-500",
|
icon: "text-success-500",
|
||||||
},
|
},
|
||||||
orange: {
|
orange: {
|
||||||
bg: "bg-amber-50 dark:bg-amber-500/10",
|
bg: "bg-warning-50 dark:bg-warning-500/10",
|
||||||
hover: "hover:bg-amber-100 dark:hover:bg-amber-500/20",
|
hover: "hover:bg-warning-100 dark:hover:bg-warning-500/20",
|
||||||
border: "bg-warning-500",
|
border: "bg-warning-500",
|
||||||
icon: "text-warning-500",
|
icon: "text-warning-500",
|
||||||
},
|
},
|
||||||
@@ -43,14 +43,14 @@ const accentColors = {
|
|||||||
icon: "text-purple-500",
|
icon: "text-purple-500",
|
||||||
},
|
},
|
||||||
red: {
|
red: {
|
||||||
bg: "bg-red-50 dark:bg-red-500/10",
|
bg: "bg-error-50 dark:bg-error-500/10",
|
||||||
hover: "hover:bg-red-100 dark:hover:bg-red-500/20",
|
hover: "hover:bg-error-100 dark:hover:bg-error-500/20",
|
||||||
border: "bg-error-500",
|
border: "bg-error-500",
|
||||||
icon: "text-error-500",
|
icon: "text-error-500",
|
||||||
},
|
},
|
||||||
success: {
|
success: {
|
||||||
bg: "bg-green-50 dark:bg-green-500/10",
|
bg: "bg-success-50 dark:bg-success-500/10",
|
||||||
hover: "hover:bg-green-100 dark:hover:bg-green-500/20",
|
hover: "hover:bg-success-100 dark:hover:bg-success-500/20",
|
||||||
border: "bg-success-500",
|
border: "bg-success-500",
|
||||||
icon: "text-success-500",
|
icon: "text-success-500",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -35,38 +35,38 @@ interface NeedsAttentionBarProps {
|
|||||||
const typeConfig = {
|
const typeConfig = {
|
||||||
pending_review: {
|
pending_review: {
|
||||||
icon: CheckCircleIcon,
|
icon: CheckCircleIcon,
|
||||||
bgColor: 'bg-amber-50 dark:bg-amber-900/20',
|
bgColor: 'bg-warning-50 dark:bg-warning-900/20',
|
||||||
borderColor: 'border-amber-200 dark:border-amber-800',
|
borderColor: 'border-warning-200 dark:border-warning-800',
|
||||||
iconColor: 'text-amber-500',
|
iconColor: 'text-warning-500',
|
||||||
titleColor: 'text-amber-800 dark:text-amber-200',
|
titleColor: 'text-warning-800 dark:text-warning-200',
|
||||||
},
|
},
|
||||||
sync_failed: {
|
sync_failed: {
|
||||||
icon: AlertIcon,
|
icon: AlertIcon,
|
||||||
bgColor: 'bg-red-50 dark:bg-red-900/20',
|
bgColor: 'bg-error-50 dark:bg-error-900/20',
|
||||||
borderColor: 'border-red-200 dark:border-red-800',
|
borderColor: 'border-error-200 dark:border-error-800',
|
||||||
iconColor: 'text-red-500',
|
iconColor: 'text-error-500',
|
||||||
titleColor: 'text-red-800 dark:text-red-200',
|
titleColor: 'text-error-800 dark:text-error-200',
|
||||||
},
|
},
|
||||||
setup_incomplete: {
|
setup_incomplete: {
|
||||||
icon: AlertIcon,
|
icon: AlertIcon,
|
||||||
bgColor: 'bg-blue-50 dark:bg-blue-900/20',
|
bgColor: 'bg-brand-50 dark:bg-brand-900/20',
|
||||||
borderColor: 'border-blue-200 dark:border-blue-800',
|
borderColor: 'border-brand-200 dark:border-brand-800',
|
||||||
iconColor: 'text-blue-500',
|
iconColor: 'text-brand-500',
|
||||||
titleColor: 'text-blue-800 dark:text-blue-200',
|
titleColor: 'text-brand-800 dark:text-brand-200',
|
||||||
},
|
},
|
||||||
automation_failed: {
|
automation_failed: {
|
||||||
icon: AlertIcon,
|
icon: AlertIcon,
|
||||||
bgColor: 'bg-red-50 dark:bg-red-900/20',
|
bgColor: 'bg-error-50 dark:bg-error-900/20',
|
||||||
borderColor: 'border-red-200 dark:border-red-800',
|
borderColor: 'border-error-200 dark:border-error-800',
|
||||||
iconColor: 'text-red-500',
|
iconColor: 'text-error-500',
|
||||||
titleColor: 'text-red-800 dark:text-red-200',
|
titleColor: 'text-error-800 dark:text-error-200',
|
||||||
},
|
},
|
||||||
credits_low: {
|
credits_low: {
|
||||||
icon: AlertIcon,
|
icon: AlertIcon,
|
||||||
bgColor: 'bg-orange-50 dark:bg-orange-900/20',
|
bgColor: 'bg-warning-50 dark:bg-warning-900/20',
|
||||||
borderColor: 'border-orange-200 dark:border-orange-800',
|
borderColor: 'border-warning-200 dark:border-warning-800',
|
||||||
iconColor: 'text-orange-500',
|
iconColor: 'text-warning-500',
|
||||||
titleColor: 'text-orange-800 dark:text-orange-200',
|
titleColor: 'text-warning-800 dark:text-warning-200',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,24 +82,24 @@ export default function NeedsAttentionBar({ items, onDismiss }: NeedsAttentionBa
|
|||||||
{/* Header */}
|
{/* Header */}
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsCollapsed(!isCollapsed)}
|
onClick={() => setIsCollapsed(!isCollapsed)}
|
||||||
className="w-full flex items-center justify-between px-5 py-3 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-t-xl hover:bg-amber-100 dark:hover:bg-amber-900/30 transition-colors"
|
className="w-full flex items-center justify-between px-5 py-3 bg-warning-50 dark:bg-warning-900/20 border border-warning-200 dark:border-warning-800 rounded-t-xl hover:bg-warning-100 dark:hover:bg-warning-900/30 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2.5">
|
<div className="flex items-center gap-2.5">
|
||||||
<AlertIcon className="w-5 h-5 text-amber-600 dark:text-amber-400" />
|
<AlertIcon className="w-5 h-5 text-warning-600 dark:text-warning-400" />
|
||||||
<span className="text-base font-semibold text-amber-800 dark:text-amber-200">
|
<span className="text-base font-semibold text-warning-800 dark:text-warning-200">
|
||||||
Needs Attention ({items.length})
|
Needs Attention ({items.length})
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{isCollapsed ? (
|
{isCollapsed ? (
|
||||||
<ChevronDownIcon className="w-5 h-5 text-amber-600 dark:text-amber-400" />
|
<ChevronDownIcon className="w-5 h-5 text-warning-600 dark:text-warning-400" />
|
||||||
) : (
|
) : (
|
||||||
<ChevronUpIcon className="w-5 h-5 text-amber-600 dark:text-amber-400" />
|
<ChevronUpIcon className="w-5 h-5 text-warning-600 dark:text-warning-400" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
{!isCollapsed && (
|
{!isCollapsed && (
|
||||||
<div className="border border-t-0 border-amber-200 dark:border-amber-800 rounded-b-xl bg-white dark:bg-gray-900 p-4">
|
<div className="border border-t-0 border-warning-200 dark:border-warning-800 rounded-b-xl bg-white dark:bg-gray-900 p-4">
|
||||||
<div className="flex flex-wrap gap-3">
|
<div className="flex flex-wrap gap-3">
|
||||||
{items.map((item) => {
|
{items.map((item) => {
|
||||||
const config = typeConfig[item.type];
|
const config = typeConfig[item.type];
|
||||||
|
|||||||
@@ -34,19 +34,19 @@ const operationConfig = {
|
|||||||
ideas: {
|
ideas: {
|
||||||
label: 'Ideas',
|
label: 'Ideas',
|
||||||
icon: BoltIcon,
|
icon: BoltIcon,
|
||||||
color: 'text-orange-600 dark:text-orange-400',
|
color: 'text-warning-600 dark:text-warning-400',
|
||||||
href: '/planner/ideas',
|
href: '/planner/ideas',
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
label: 'Content',
|
label: 'Content',
|
||||||
icon: FileTextIcon,
|
icon: FileTextIcon,
|
||||||
color: 'text-green-600 dark:text-green-400',
|
color: 'text-success-600 dark:text-success-400',
|
||||||
href: '/writer/content',
|
href: '/writer/content',
|
||||||
},
|
},
|
||||||
images: {
|
images: {
|
||||||
label: 'Images',
|
label: 'Images',
|
||||||
icon: FileIcon,
|
icon: FileIcon,
|
||||||
color: 'text-pink-600 dark:text-pink-400',
|
color: 'text-purple-600 dark:text-purple-400',
|
||||||
href: '/writer/images',
|
href: '/writer/images',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const workflowSteps = [
|
|||||||
description: 'Import your target keywords manually or from CSV',
|
description: 'Import your target keywords manually or from CSV',
|
||||||
href: '/planner/keyword-opportunities',
|
href: '/planner/keyword-opportunities',
|
||||||
actionLabel: 'Add',
|
actionLabel: 'Add',
|
||||||
color: 'text-blue-600 dark:text-blue-400',
|
color: 'text-brand-600 dark:text-brand-400',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
num: 2,
|
num: 2,
|
||||||
@@ -46,7 +46,7 @@ const workflowSteps = [
|
|||||||
description: 'Create content ideas from your keyword clusters',
|
description: 'Create content ideas from your keyword clusters',
|
||||||
href: '/planner/ideas',
|
href: '/planner/ideas',
|
||||||
actionLabel: 'Ideas',
|
actionLabel: 'Ideas',
|
||||||
color: 'text-orange-600 dark:text-orange-400',
|
color: 'text-warning-600 dark:text-warning-400',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
num: 4,
|
num: 4,
|
||||||
@@ -55,7 +55,7 @@ const workflowSteps = [
|
|||||||
description: 'Convert approved ideas into content tasks',
|
description: 'Convert approved ideas into content tasks',
|
||||||
href: '/writer/tasks',
|
href: '/writer/tasks',
|
||||||
actionLabel: 'Tasks',
|
actionLabel: 'Tasks',
|
||||||
color: 'text-indigo-600 dark:text-indigo-400',
|
color: 'text-purple-600 dark:text-purple-400',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
num: 5,
|
num: 5,
|
||||||
@@ -64,7 +64,7 @@ const workflowSteps = [
|
|||||||
description: 'AI writes SEO-optimized articles from tasks',
|
description: 'AI writes SEO-optimized articles from tasks',
|
||||||
href: '/writer/content',
|
href: '/writer/content',
|
||||||
actionLabel: 'Write',
|
actionLabel: 'Write',
|
||||||
color: 'text-green-600 dark:text-green-400',
|
color: 'text-success-600 dark:text-success-400',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
num: 6,
|
num: 6,
|
||||||
@@ -73,7 +73,7 @@ const workflowSteps = [
|
|||||||
description: 'Create featured images and media for articles',
|
description: 'Create featured images and media for articles',
|
||||||
href: '/writer/images',
|
href: '/writer/images',
|
||||||
actionLabel: 'Images',
|
actionLabel: 'Images',
|
||||||
color: 'text-pink-600 dark:text-pink-400',
|
color: 'text-purple-600 dark:text-purple-400',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
num: 7,
|
num: 7,
|
||||||
@@ -82,7 +82,7 @@ const workflowSteps = [
|
|||||||
description: 'Quality check and approve generated content',
|
description: 'Quality check and approve generated content',
|
||||||
href: '/writer/review',
|
href: '/writer/review',
|
||||||
actionLabel: 'Review',
|
actionLabel: 'Review',
|
||||||
color: 'text-amber-600 dark:text-amber-400',
|
color: 'text-warning-600 dark:text-warning-400',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
num: 8,
|
num: 8,
|
||||||
@@ -91,7 +91,7 @@ const workflowSteps = [
|
|||||||
description: 'Push approved content to your WordPress site',
|
description: 'Push approved content to your WordPress site',
|
||||||
href: '/writer/published',
|
href: '/writer/published',
|
||||||
actionLabel: 'Publish',
|
actionLabel: 'Publish',
|
||||||
color: 'text-emerald-600 dark:text-emerald-400',
|
color: 'text-purple-600 dark:text-purple-400',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -30,17 +30,20 @@ interface RecentActivityWidgetProps {
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const activityConfig = {
|
const activityConfig: Record<string, { icon: typeof GroupIcon; color: string; bgColor: string }> = {
|
||||||
clustering: { icon: GroupIcon, color: 'text-purple-600 dark:text-purple-400', bgColor: 'bg-purple-100 dark:bg-purple-900/40' },
|
clustering: { icon: GroupIcon, color: 'text-purple-600 dark:text-purple-400', bgColor: 'bg-purple-100 dark:bg-purple-900/40' },
|
||||||
ideas: { icon: BoltIcon, color: 'text-orange-600 dark:text-orange-400', bgColor: 'bg-orange-100 dark:bg-orange-900/40' },
|
ideas: { icon: BoltIcon, color: 'text-warning-600 dark:text-warning-400', bgColor: 'bg-warning-100 dark:bg-warning-900/40' },
|
||||||
content: { icon: FileTextIcon, color: 'text-green-600 dark:text-green-400', bgColor: 'bg-green-100 dark:bg-green-900/40' },
|
content: { icon: FileTextIcon, color: 'text-success-600 dark:text-success-400', bgColor: 'bg-success-100 dark:bg-success-900/40' },
|
||||||
images: { icon: FileIcon, color: 'text-pink-600 dark:text-pink-400', bgColor: 'bg-pink-100 dark:bg-pink-900/40' },
|
images: { icon: FileIcon, color: 'text-purple-600 dark:text-purple-400', bgColor: 'bg-purple-100 dark:bg-purple-900/40' },
|
||||||
published: { icon: PaperPlaneIcon, color: 'text-emerald-600 dark:text-emerald-400', bgColor: 'bg-emerald-100 dark:bg-emerald-900/40' },
|
published: { icon: PaperPlaneIcon, color: 'text-purple-600 dark:text-purple-400', bgColor: 'bg-purple-100 dark:bg-purple-900/40' },
|
||||||
keywords: { icon: ListIcon, color: 'text-blue-600 dark:text-blue-400', bgColor: 'bg-blue-100 dark:bg-blue-900/40' },
|
keywords: { icon: ListIcon, color: 'text-brand-600 dark:text-brand-400', bgColor: 'bg-brand-100 dark:bg-brand-900/40' },
|
||||||
error: { icon: AlertIcon, color: 'text-red-600 dark:text-red-400', bgColor: 'bg-red-100 dark:bg-red-900/40' },
|
error: { icon: AlertIcon, color: 'text-error-600 dark:text-error-400', bgColor: 'bg-error-100 dark:bg-error-900/40' },
|
||||||
sync: { icon: CheckCircleIcon, color: 'text-teal-600 dark:text-teal-400', bgColor: 'bg-teal-100 dark:bg-teal-900/40' },
|
sync: { icon: CheckCircleIcon, color: 'text-purple-600 dark:text-purple-400', bgColor: 'bg-purple-100 dark:bg-purple-900/40' },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Default config for unknown activity types
|
||||||
|
const defaultActivityConfig = { icon: BoltIcon, color: 'text-gray-600 dark:text-gray-400', bgColor: 'bg-gray-100 dark:bg-gray-900/40' };
|
||||||
|
|
||||||
function formatRelativeTime(date: Date): string {
|
function formatRelativeTime(date: Date): string {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const diffMs = now.getTime() - date.getTime();
|
const diffMs = now.getTime() - date.getTime();
|
||||||
@@ -87,7 +90,7 @@ export default function RecentActivityWidget({ activities, loading }: RecentActi
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
activities.slice(0, 5).map((activity) => {
|
activities.slice(0, 5).map((activity) => {
|
||||||
const config = activityConfig[activity.type];
|
const config = activityConfig[activity.type] || defaultActivityConfig;
|
||||||
const Icon = config.icon;
|
const Icon = config.icon;
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export default function SiteConfigWidget({
|
|||||||
<h3 className="text-base font-semibold text-gray-800 dark:text-gray-200 uppercase tracking-wide">
|
<h3 className="text-base font-semibold text-gray-800 dark:text-gray-200 uppercase tracking-wide">
|
||||||
Site Configuration
|
Site Configuration
|
||||||
</h3>
|
</h3>
|
||||||
<span className={`text-lg font-bold ${completionPercent === 100 ? 'text-green-600' : 'text-amber-600'}`}>
|
<span className={`text-lg font-bold ${completionPercent === 100 ? 'text-success-600' : 'text-warning-600'}`}>
|
||||||
{configuredCount}/{totalCount}
|
{configuredCount}/{totalCount}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -97,13 +97,13 @@ export default function SiteConfigWidget({
|
|||||||
>
|
>
|
||||||
<div className={`w-8 h-8 rounded-lg flex items-center justify-center ${
|
<div className={`w-8 h-8 rounded-lg flex items-center justify-center ${
|
||||||
item.configured
|
item.configured
|
||||||
? 'bg-green-100 dark:bg-green-900/30'
|
? 'bg-success-100 dark:bg-success-900/30'
|
||||||
: 'bg-amber-100 dark:bg-amber-900/30'
|
: 'bg-warning-100 dark:bg-warning-900/30'
|
||||||
}`}>
|
}`}>
|
||||||
<Icon className={`w-5 h-5 ${
|
<Icon className={`w-5 h-5 ${
|
||||||
item.configured
|
item.configured
|
||||||
? 'text-green-600 dark:text-green-400'
|
? 'text-success-600 dark:text-success-400'
|
||||||
: 'text-amber-600 dark:text-amber-400'
|
: 'text-warning-600 dark:text-warning-400'
|
||||||
}`} />
|
}`} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
@@ -113,15 +113,15 @@ export default function SiteConfigWidget({
|
|||||||
<p className={`text-xs ${
|
<p className={`text-xs ${
|
||||||
item.configured
|
item.configured
|
||||||
? 'text-gray-600 dark:text-gray-400'
|
? 'text-gray-600 dark:text-gray-400'
|
||||||
: 'text-amber-600 dark:text-amber-400'
|
: 'text-warning-600 dark:text-warning-400'
|
||||||
}`}>
|
}`}>
|
||||||
{item.detail}
|
{item.detail}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{item.configured ? (
|
{item.configured ? (
|
||||||
<CheckCircleIcon className="w-5 h-5 text-green-600 dark:text-green-400" />
|
<CheckCircleIcon className="w-5 h-5 text-success-600 dark:text-success-400" />
|
||||||
) : (
|
) : (
|
||||||
<AlertIcon className="w-5 h-5 text-amber-600 dark:text-amber-400" />
|
<AlertIcon className="w-5 h-5 text-warning-600 dark:text-warning-400" />
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
@@ -137,7 +137,7 @@ export default function SiteConfigWidget({
|
|||||||
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
|
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
|
||||||
<div
|
<div
|
||||||
className={`h-2 rounded-full transition-all ${
|
className={`h-2 rounded-full transition-all ${
|
||||||
completionPercent === 100 ? 'bg-green-500' : 'bg-amber-500'
|
completionPercent === 100 ? 'bg-success-500' : 'bg-warning-500'
|
||||||
}`}
|
}`}
|
||||||
style={{ width: `${completionPercent}%` }}
|
style={{ width: `${completionPercent}%` }}
|
||||||
></div>
|
></div>
|
||||||
|
|||||||
@@ -34,13 +34,13 @@ interface WorkflowPipelineWidgetProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const stages = [
|
const stages = [
|
||||||
{ key: 'sites', label: 'Sites', icon: GridIcon, href: '/sites', color: 'text-blue-600 dark:text-blue-400' },
|
{ key: 'sites', label: 'Sites', icon: GridIcon, href: '/sites', color: 'text-brand-600 dark:text-brand-400' },
|
||||||
{ key: 'keywords', label: 'Keywords', icon: ListIcon, href: '/planner/keywords', color: 'text-blue-600 dark:text-blue-400' },
|
{ key: 'keywords', label: 'Keywords', icon: ListIcon, href: '/planner/keywords', color: 'text-brand-600 dark:text-brand-400' },
|
||||||
{ key: 'clusters', label: 'Clusters', icon: GroupIcon, href: '/planner/clusters', color: 'text-purple-600 dark:text-purple-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: 'ideas', label: 'Ideas', icon: BoltIcon, href: '/planner/ideas', color: 'text-warning-600 dark:text-warning-400' },
|
||||||
{ key: 'tasks', label: 'Tasks', icon: CheckCircleIcon, href: '/writer/tasks', color: 'text-indigo-600 dark:text-indigo-400' },
|
{ key: 'tasks', label: 'Tasks', icon: CheckCircleIcon, href: '/writer/tasks', color: 'text-purple-600 dark:text-purple-400' },
|
||||||
{ key: 'drafts', label: 'Drafts', icon: FileTextIcon, href: '/writer/content', color: 'text-green-600 dark:text-green-400' },
|
{ key: 'drafts', label: 'Drafts', icon: FileTextIcon, href: '/writer/content', color: 'text-success-600 dark:text-success-400' },
|
||||||
{ key: 'published', label: 'Published', icon: PaperPlaneIcon, href: '/writer/published', color: 'text-emerald-600 dark:text-emerald-400' },
|
{ key: 'published', label: 'Published', icon: PaperPlaneIcon, href: '/writer/published', color: 'text-purple-600 dark:text-purple-400' },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
// Small filled arrow triangle component
|
// Small filled arrow triangle component
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const CountryMap: React.FC<CountryMapProps> = ({ mapColor }) => {
|
|||||||
backgroundColor="transparent"
|
backgroundColor="transparent"
|
||||||
markerStyle={{
|
markerStyle={{
|
||||||
initial: {
|
initial: {
|
||||||
fill: "#465FFF",
|
fill: "var(--color-primary)",
|
||||||
r: 4, // Custom radius for markers
|
r: 4, // Custom radius for markers
|
||||||
} as any, // Type assertion to bypass strict CSS property checks
|
} as any, // Type assertion to bypass strict CSS property checks
|
||||||
}}
|
}}
|
||||||
@@ -24,27 +24,27 @@ const CountryMap: React.FC<CountryMapProps> = ({ mapColor }) => {
|
|||||||
latLng: [37.2580397, -104.657039],
|
latLng: [37.2580397, -104.657039],
|
||||||
name: "United States",
|
name: "United States",
|
||||||
style: {
|
style: {
|
||||||
fill: "#465FFF",
|
fill: "var(--color-primary)",
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: "white",
|
borderColor: "white",
|
||||||
stroke: "#383f47",
|
stroke: "var(--color-gray-700)",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
latLng: [20.7504374, 73.7276105],
|
latLng: [20.7504374, 73.7276105],
|
||||||
name: "India",
|
name: "India",
|
||||||
style: { fill: "#465FFF", borderWidth: 1, borderColor: "white" },
|
style: { fill: "var(--color-primary)", borderWidth: 1, borderColor: "white" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
latLng: [53.613, -11.6368],
|
latLng: [53.613, -11.6368],
|
||||||
name: "United Kingdom",
|
name: "United Kingdom",
|
||||||
style: { fill: "#465FFF", borderWidth: 1, borderColor: "white" },
|
style: { fill: "var(--color-primary)", borderWidth: 1, borderColor: "white" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
latLng: [-25.0304388, 115.2092761],
|
latLng: [-25.0304388, 115.2092761],
|
||||||
name: "Sweden",
|
name: "Sweden",
|
||||||
style: {
|
style: {
|
||||||
fill: "#465FFF",
|
fill: "var(--color-primary)",
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: "white",
|
borderColor: "white",
|
||||||
strokeOpacity: 0,
|
strokeOpacity: 0,
|
||||||
@@ -58,7 +58,7 @@ const CountryMap: React.FC<CountryMapProps> = ({ mapColor }) => {
|
|||||||
zoomStep={1.5}
|
zoomStep={1.5}
|
||||||
regionStyle={{
|
regionStyle={{
|
||||||
initial: {
|
initial: {
|
||||||
fill: mapColor || "#D0D5DD",
|
fill: mapColor || "var(--color-gray-300)",
|
||||||
fillOpacity: 1,
|
fillOpacity: 1,
|
||||||
fontFamily: "Outfit",
|
fontFamily: "Outfit",
|
||||||
stroke: "none",
|
stroke: "none",
|
||||||
@@ -68,17 +68,17 @@ const CountryMap: React.FC<CountryMapProps> = ({ mapColor }) => {
|
|||||||
hover: {
|
hover: {
|
||||||
fillOpacity: 0.7,
|
fillOpacity: 0.7,
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
fill: "#465fff",
|
fill: "var(--color-primary)",
|
||||||
stroke: "none",
|
stroke: "none",
|
||||||
},
|
},
|
||||||
selected: {
|
selected: {
|
||||||
fill: "#465FFF",
|
fill: "var(--color-primary)",
|
||||||
},
|
},
|
||||||
selectedHover: {},
|
selectedHover: {},
|
||||||
}}
|
}}
|
||||||
regionLabelStyle={{
|
regionLabelStyle={{
|
||||||
initial: {
|
initial: {
|
||||||
fill: "#35373e",
|
fill: "var(--color-gray-700)",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontSize: "13px",
|
fontSize: "13px",
|
||||||
stroke: "none",
|
stroke: "none",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useState } from "react";
|
|||||||
|
|
||||||
export default function MonthlySalesChart() {
|
export default function MonthlySalesChart() {
|
||||||
const options: ApexOptions = {
|
const options: ApexOptions = {
|
||||||
colors: ["#465fff"],
|
colors: ["var(--color-primary)"],
|
||||||
chart: {
|
chart: {
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "Outfit, sans-serif",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { MoreDotIcon } from "../../icons";
|
|||||||
export default function MonthlyTarget() {
|
export default function MonthlyTarget() {
|
||||||
const series = [75.55];
|
const series = [75.55];
|
||||||
const options: ApexOptions = {
|
const options: ApexOptions = {
|
||||||
colors: ["#465FFF"],
|
colors: ["var(--color-primary)"],
|
||||||
chart: {
|
chart: {
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "Outfit, sans-serif",
|
||||||
type: "radialBar",
|
type: "radialBar",
|
||||||
@@ -25,7 +25,7 @@ export default function MonthlyTarget() {
|
|||||||
size: "80%",
|
size: "80%",
|
||||||
},
|
},
|
||||||
track: {
|
track: {
|
||||||
background: "#E4E7EC",
|
background: "var(--color-gray-200)",
|
||||||
strokeWidth: "100%",
|
strokeWidth: "100%",
|
||||||
margin: 5, // margin is in pixels
|
margin: 5, // margin is in pixels
|
||||||
},
|
},
|
||||||
@@ -37,7 +37,7 @@ export default function MonthlyTarget() {
|
|||||||
fontSize: "36px",
|
fontSize: "36px",
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
offsetY: -40,
|
offsetY: -40,
|
||||||
color: "#1D2939",
|
color: "var(--color-gray-800)",
|
||||||
formatter: function (val) {
|
formatter: function (val) {
|
||||||
return val + "%";
|
return val + "%";
|
||||||
},
|
},
|
||||||
@@ -47,7 +47,7 @@ export default function MonthlyTarget() {
|
|||||||
},
|
},
|
||||||
fill: {
|
fill: {
|
||||||
type: "solid",
|
type: "solid",
|
||||||
colors: ["#465FFF"],
|
colors: ["var(--color-primary)"],
|
||||||
},
|
},
|
||||||
stroke: {
|
stroke: {
|
||||||
lineCap: "round",
|
lineCap: "round",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default function StatisticsChart() {
|
|||||||
position: "top",
|
position: "top",
|
||||||
horizontalAlign: "left",
|
horizontalAlign: "left",
|
||||||
},
|
},
|
||||||
colors: ["#465FFF", "#9CB9FF"], // Define line colors
|
colors: ["var(--color-primary)", "var(--color-brand-300)"], // Define line colors
|
||||||
chart: {
|
chart: {
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "Outfit, sans-serif",
|
||||||
height: 310,
|
height: 310,
|
||||||
@@ -89,7 +89,7 @@ export default function StatisticsChart() {
|
|||||||
labels: {
|
labels: {
|
||||||
style: {
|
style: {
|
||||||
fontSize: "12px", // Adjust font size for y-axis labels
|
fontSize: "12px", // Adjust font size for y-axis labels
|
||||||
colors: ["#6B7280"], // Color of the labels
|
colors: ["var(--color-gray-500)"], // Color of the labels
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
|
|||||||
@@ -134,9 +134,9 @@ export default function NotificationDropdown() {
|
|||||||
>
|
>
|
||||||
{/* Notification badge */}
|
{/* Notification badge */}
|
||||||
{unreadCount > 0 && (
|
{unreadCount > 0 && (
|
||||||
<span className="absolute -right-0.5 -top-0.5 z-10 flex h-5 w-5 items-center justify-center rounded-full bg-orange-500 text-[10px] font-semibold text-white">
|
<span className="absolute -right-0.5 -top-0.5 z-10 flex h-5 w-5 items-center justify-center rounded-full bg-warning-500 text-[10px] font-semibold text-white">
|
||||||
{unreadCount > 9 ? '9+' : unreadCount}
|
{unreadCount > 9 ? '9+' : unreadCount}
|
||||||
<span className="absolute inline-flex w-full h-full bg-orange-400 rounded-full opacity-75 animate-ping"></span>
|
<span className="absolute inline-flex w-full h-full bg-warning-400 rounded-full opacity-75 animate-ping"></span>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<svg
|
<svg
|
||||||
@@ -243,7 +243,7 @@ export default function NotificationDropdown() {
|
|||||||
notification.actionHref
|
notification.actionHref
|
||||||
)}
|
)}
|
||||||
className={`flex gap-3 rounded-lg border-b border-gray-100 p-3 hover:bg-gray-50 dark:border-gray-800 dark:hover:bg-white/5 ${
|
className={`flex gap-3 rounded-lg border-b border-gray-100 p-3 hover:bg-gray-50 dark:border-gray-800 dark:hover:bg-white/5 ${
|
||||||
!notification.read ? 'bg-blue-50/50 dark:bg-blue-900/10' : ''
|
!notification.read ? 'bg-brand-50/50 dark:bg-brand-900/10' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{/* Icon */}
|
{/* Icon */}
|
||||||
|
|||||||
@@ -105,9 +105,9 @@ export default function NotificationDropdown() {
|
|||||||
>
|
>
|
||||||
{/* Notification badge */}
|
{/* Notification badge */}
|
||||||
{unreadCount > 0 && (
|
{unreadCount > 0 && (
|
||||||
<span className="absolute -right-0.5 -top-0.5 z-10 flex h-5 w-5 items-center justify-center rounded-full bg-orange-500 text-[10px] font-semibold text-white">
|
<span className="absolute -right-0.5 -top-0.5 z-10 flex h-5 w-5 items-center justify-center rounded-full bg-warning-500 text-[10px] font-semibold text-white">
|
||||||
{unreadCount > 9 ? '9+' : unreadCount}
|
{unreadCount > 9 ? '9+' : unreadCount}
|
||||||
<span className="absolute inline-flex w-full h-full bg-orange-400 rounded-full opacity-75 animate-ping"></span>
|
<span className="absolute inline-flex w-full h-full bg-warning-400 rounded-full opacity-75 animate-ping"></span>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<svg
|
<svg
|
||||||
@@ -205,7 +205,7 @@ export default function NotificationDropdown() {
|
|||||||
notification.actionHref
|
notification.actionHref
|
||||||
)}
|
)}
|
||||||
className={`flex gap-3 rounded-lg border-b border-gray-100 p-3 hover:bg-gray-50 dark:border-gray-800 dark:hover:bg-white/5 ${
|
className={`flex gap-3 rounded-lg border-b border-gray-100 p-3 hover:bg-gray-50 dark:border-gray-800 dark:hover:bg-white/5 ${
|
||||||
!notification.read ? 'bg-blue-50/50 dark:bg-blue-900/10' : ''
|
!notification.read ? 'bg-brand-50/50 dark:bg-brand-900/10' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{/* Icon */}
|
{/* Icon */}
|
||||||
|
|||||||
@@ -194,14 +194,14 @@ export default function SiteSwitcher({ hiddenPaths }: SiteSwitcherProps) {
|
|||||||
onItemClick={() => handleSiteSelect(site.id)}
|
onItemClick={() => handleSiteSelect(site.id)}
|
||||||
className={`flex items-center gap-3 px-3 py-2 font-medium rounded-lg text-sm text-left ${
|
className={`flex items-center gap-3 px-3 py-2 font-medium rounded-lg text-sm text-left ${
|
||||||
activeSite?.id === site.id
|
activeSite?.id === site.id
|
||||||
? "bg-blue-50 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300"
|
? "bg-brand-50 text-brand-700 dark:bg-brand-500/20 dark:text-brand-300"
|
||||||
: "text-gray-700 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
|
: "text-gray-700 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span className="flex-1">{site.name}</span>
|
<span className="flex-1">{site.name}</span>
|
||||||
{activeSite?.id === site.id && (
|
{activeSite?.id === site.id && (
|
||||||
<svg
|
<svg
|
||||||
className="w-4 h-4 text-blue-600 dark:text-blue-400"
|
className="w-4 h-4 text-brand-600 dark:text-brand-400"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
viewBox="0 0 20 20"
|
viewBox="0 0 20 20"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ export default function IntegrationStatus({
|
|||||||
const getStatusIcon = () => {
|
const getStatusIcon = () => {
|
||||||
switch (syncStatus) {
|
switch (syncStatus) {
|
||||||
case 'success':
|
case 'success':
|
||||||
return <CheckCircleIcon className="w-5 h-5 text-green-500" />;
|
return <CheckCircleIcon className="w-5 h-5 text-success-500" />;
|
||||||
case 'failed':
|
case 'failed':
|
||||||
return <XCircleIcon className="w-5 h-5 text-red-500" />;
|
return <XCircleIcon className="w-5 h-5 text-error-500" />;
|
||||||
case 'syncing':
|
case 'syncing':
|
||||||
return <RefreshCw className="w-5 h-5 text-blue-500 animate-spin" />;
|
return <RefreshCw className="w-5 h-5 text-brand-500 animate-spin" />;
|
||||||
default:
|
default:
|
||||||
return <ClockIcon className="w-5 h-5 text-gray-400" />;
|
return <ClockIcon className="w-5 h-5 text-gray-400" />;
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ export default function IntegrationStatus({
|
|||||||
<div className="text-xs text-gray-600 dark:text-gray-400">
|
<div className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
<div>Last sync: {formatDate(lastSyncAt)}</div>
|
<div>Last sync: {formatDate(lastSyncAt)}</div>
|
||||||
{syncError && (
|
{syncError && (
|
||||||
<div className="text-red-600 dark:text-red-400 mt-1">
|
<div className="text-error-600 dark:text-error-400 mt-1">
|
||||||
Error: {syncError}
|
Error: {syncError}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const LinkResults: React.FC<LinkResultsProps> = ({
|
|||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">Linking Results</h3>
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">Linking Results</h3>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<PlugInIcon className="w-5 h-5 text-blue-500" />
|
<PlugInIcon className="w-5 h-5 text-brand-500" />
|
||||||
<span className="text-sm text-gray-600 dark:text-gray-400">Version {linkerVersion}</span>
|
<span className="text-sm text-gray-600 dark:text-gray-400">Version {linkerVersion}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -46,14 +46,14 @@ export const LinkResults: React.FC<LinkResultsProps> = ({
|
|||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">Linking Results</h3>
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">Linking Results</h3>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<PlugInIcon className="w-5 h-5 text-blue-500" />
|
<PlugInIcon className="w-5 h-5 text-brand-500" />
|
||||||
<span className="text-sm text-gray-600 dark:text-gray-400">Version {linkerVersion}</span>
|
<span className="text-sm text-gray-600 dark:text-gray-400">Version {linkerVersion}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{linksAdded > 0 ? (
|
{linksAdded > 0 ? (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center gap-2 text-green-600 dark:text-green-400">
|
<div className="flex items-center gap-2 text-success-600 dark:text-success-400">
|
||||||
<CheckCircleIcon className="w-5 h-5" />
|
<CheckCircleIcon className="w-5 h-5" />
|
||||||
<span className="font-medium">{linksAdded} link{linksAdded !== 1 ? 's' : ''} added</span>
|
<span className="font-medium">{linksAdded} link{linksAdded !== 1 ? 's' : ''} added</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,15 +63,15 @@ export const LinkResults: React.FC<LinkResultsProps> = ({
|
|||||||
{/* Stage 3: Group links by cluster match */}
|
{/* Stage 3: Group links by cluster match */}
|
||||||
{links.some(l => l.cluster_match) && (
|
{links.some(l => l.cluster_match) && (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<div className="text-xs font-semibold text-blue-600 dark:text-blue-400 mb-2">
|
<div className="text-xs font-semibold text-brand-600 dark:text-brand-400 mb-2">
|
||||||
Cluster Matches (High Priority)
|
Cluster Matches (High Priority)
|
||||||
</div>
|
</div>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{links.filter(l => l.cluster_match).map((link, index) => (
|
{links.filter(l => l.cluster_match).map((link, index) => (
|
||||||
<li key={`cluster-${index}`} className="flex items-center gap-2 text-sm pl-2 border-l-2 border-blue-500">
|
<li key={`cluster-${index}`} className="flex items-center gap-2 text-sm pl-2 border-l-2 border-brand-500">
|
||||||
<span className="text-gray-600 dark:text-gray-400">"{link.anchor_text || 'Untitled'}"</span>
|
<span className="text-gray-600 dark:text-gray-400">"{link.anchor_text || 'Untitled'}"</span>
|
||||||
<span className="text-gray-400">→</span>
|
<span className="text-gray-400">→</span>
|
||||||
<span className="text-blue-600 dark:text-blue-400">
|
<span className="text-brand-600 dark:text-brand-400">
|
||||||
Content #{link.target_content_id || 'N/A'}
|
Content #{link.target_content_id || 'N/A'}
|
||||||
</span>
|
</span>
|
||||||
{link.relevance_score !== undefined && (
|
{link.relevance_score !== undefined && (
|
||||||
@@ -96,7 +96,7 @@ export const LinkResults: React.FC<LinkResultsProps> = ({
|
|||||||
<li key={`other-${index}`} className="flex items-center gap-2 text-sm">
|
<li key={`other-${index}`} className="flex items-center gap-2 text-sm">
|
||||||
<span className="text-gray-600 dark:text-gray-400">"{link.anchor_text || 'Untitled'}"</span>
|
<span className="text-gray-600 dark:text-gray-400">"{link.anchor_text || 'Untitled'}"</span>
|
||||||
<span className="text-gray-400">→</span>
|
<span className="text-gray-400">→</span>
|
||||||
<span className="text-blue-600 dark:text-blue-400">
|
<span className="text-brand-600 dark:text-brand-400">
|
||||||
Content #{link.target_content_id || 'N/A'}
|
Content #{link.target_content_id || 'N/A'}
|
||||||
</span>
|
</span>
|
||||||
{link.relevance_score !== undefined && (
|
{link.relevance_score !== undefined && (
|
||||||
@@ -117,7 +117,7 @@ export const LinkResults: React.FC<LinkResultsProps> = ({
|
|||||||
<li key={index} className="flex items-center gap-2 text-sm">
|
<li key={index} className="flex items-center gap-2 text-sm">
|
||||||
<span className="text-gray-600 dark:text-gray-400">"{link.anchor_text}"</span>
|
<span className="text-gray-600 dark:text-gray-400">"{link.anchor_text}"</span>
|
||||||
<span className="text-gray-400">→</span>
|
<span className="text-gray-400">→</span>
|
||||||
<span className="text-blue-600 dark:text-blue-400">
|
<span className="text-brand-600 dark:text-brand-400">
|
||||||
Content #{link.target_content_id}
|
Content #{link.target_content_id}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -200,12 +200,12 @@ export default function WorkflowGuide({ onSiteAdded }: WorkflowGuideProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<Card className="rounded-2xl border-2 border-orange-200 bg-gradient-to-br from-orange-50 to-white dark:from-orange-950/20 dark:to-gray-900 dark:border-orange-800 p-6 md:p-8">
|
<Card className="rounded-2xl border-2 border-warning-200 bg-gradient-to-br from-warning-50 to-white dark:from-warning-950/20 dark:to-gray-900 dark:border-warning-800 p-6 md:p-8">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-start justify-between mb-6">
|
<div className="flex items-start justify-between mb-6">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-center gap-3 mb-2">
|
<div className="flex items-center gap-3 mb-2">
|
||||||
<div className="size-12 rounded-xl bg-gradient-to-br from-orange-500 to-orange-600 flex items-center justify-center text-white shadow-lg">
|
<div className="size-12 rounded-xl bg-gradient-to-br from-warning-500 to-warning-600 flex items-center justify-center text-white shadow-lg">
|
||||||
<BoltIcon className="h-6 w-6" />
|
<BoltIcon className="h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -230,9 +230,9 @@ export default function WorkflowGuide({ onSiteAdded }: WorkflowGuideProps) {
|
|||||||
|
|
||||||
{/* Site Integration Option */}
|
{/* Site Integration Option */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<Card className="p-6 border-2 border-blue-200 dark:border-blue-800">
|
<Card className="p-6 border-2 border-brand-200 dark:border-brand-800">
|
||||||
<div className="flex items-start gap-4 mb-6">
|
<div className="flex items-start gap-4 mb-6">
|
||||||
<div className="size-12 rounded-xl bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center text-white flex-shrink-0">
|
<div className="size-12 rounded-xl bg-gradient-to-br from-brand-500 to-brand-600 flex items-center justify-center text-white flex-shrink-0">
|
||||||
<PlugInIcon className="h-6 w-6" />
|
<PlugInIcon className="h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
@@ -252,12 +252,12 @@ export default function WorkflowGuide({ onSiteAdded }: WorkflowGuideProps) {
|
|||||||
onClick={handleWordPressCardClick}
|
onClick={handleWordPressCardClick}
|
||||||
className={`flex items-center justify-between p-4 rounded-lg border-2 transition-all duration-200 group ${
|
className={`flex items-center justify-between p-4 rounded-lg border-2 transition-all duration-200 group ${
|
||||||
isWordPressExpanded
|
isWordPressExpanded
|
||||||
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
|
? 'border-brand-500 bg-brand-50 dark:bg-brand-900/20'
|
||||||
: 'border-gray-200 dark:border-gray-700 hover:border-blue-400 dark:hover:border-blue-600 bg-white dark:bg-gray-800'
|
: 'border-gray-200 dark:border-gray-700 hover:border-brand-400 dark:hover:border-brand-600 bg-white dark:bg-gray-800'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<PlugInIcon className={`w-5 h-5 ${isWordPressExpanded ? 'text-blue-600 dark:text-blue-400' : 'text-blue-600 dark:text-blue-400'}`} />
|
<PlugInIcon className={`w-5 h-5 ${isWordPressExpanded ? 'text-brand-600 dark:text-brand-400' : 'text-brand-600 dark:text-brand-400'}`} />
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<div className="font-semibold text-gray-900 dark:text-white">
|
<div className="font-semibold text-gray-900 dark:text-white">
|
||||||
WordPress Site
|
WordPress Site
|
||||||
@@ -269,8 +269,8 @@ export default function WorkflowGuide({ onSiteAdded }: WorkflowGuideProps) {
|
|||||||
</div>
|
</div>
|
||||||
<ArrowRightIcon className={`w-5 h-5 transition-transform ${isWordPressExpanded ? 'transform rotate-90' : ''} ${
|
<ArrowRightIcon className={`w-5 h-5 transition-transform ${isWordPressExpanded ? 'transform rotate-90' : ''} ${
|
||||||
isWordPressExpanded
|
isWordPressExpanded
|
||||||
? 'text-blue-600 dark:text-blue-400'
|
? 'text-brand-600 dark:text-brand-400'
|
||||||
: 'text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-400'
|
: 'text-gray-400 group-hover:text-brand-600 dark:group-hover:text-brand-400'
|
||||||
}`} />
|
}`} />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -302,7 +302,7 @@ export default function WorkflowGuide({ onSiteAdded }: WorkflowGuideProps) {
|
|||||||
value={siteName}
|
value={siteName}
|
||||||
onChange={(e) => setSiteName(e.target.value)}
|
onChange={(e) => setSiteName(e.target.value)}
|
||||||
placeholder="Enter site name"
|
placeholder="Enter site name"
|
||||||
className="w-full px-4 py-2.5 border-2 border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white text-base focus:border-blue-500 focus:ring-2 focus:ring-blue-200 dark:focus:ring-blue-800"
|
className="w-full px-4 py-2.5 border-2 border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white text-base focus:border-brand-500 focus:ring-2 focus:ring-brand-200 dark:focus:ring-brand-800"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -316,7 +316,7 @@ export default function WorkflowGuide({ onSiteAdded }: WorkflowGuideProps) {
|
|||||||
value={websiteAddress}
|
value={websiteAddress}
|
||||||
onChange={(e) => setWebsiteAddress(e.target.value)}
|
onChange={(e) => setWebsiteAddress(e.target.value)}
|
||||||
placeholder="https://example.com"
|
placeholder="https://example.com"
|
||||||
className="w-full px-4 py-2.5 border-2 border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white text-base focus:border-blue-500 focus:ring-2 focus:ring-blue-200 dark:focus:ring-blue-800"
|
className="w-full px-4 py-2.5 border-2 border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white text-base focus:border-brand-500 focus:ring-2 focus:ring-brand-200 dark:focus:ring-brand-800"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -359,7 +359,7 @@ export default function WorkflowGuide({ onSiteAdded }: WorkflowGuideProps) {
|
|||||||
key={sector.slug}
|
key={sector.slug}
|
||||||
className={`p-4 hover:shadow-lg transition-all duration-200 border-2 cursor-pointer ${
|
className={`p-4 hover:shadow-lg transition-all duration-200 border-2 cursor-pointer ${
|
||||||
selectedSectors.includes(sector.slug)
|
selectedSectors.includes(sector.slug)
|
||||||
? 'border-[var(--color-primary)] bg-blue-50 dark:bg-blue-900/20'
|
? 'border-[var(--color-primary)] bg-brand-50 dark:bg-brand-900/20'
|
||||||
: 'border-gray-200 dark:border-gray-700'
|
: 'border-gray-200 dark:border-gray-700'
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handleSectorToggle(sector.slug)}
|
onClick={() => handleSectorToggle(sector.slug)}
|
||||||
|
|||||||
@@ -29,22 +29,22 @@ export const OptimizationScores: React.FC<OptimizationScoresProps> = ({
|
|||||||
className = '',
|
className = '',
|
||||||
}) => {
|
}) => {
|
||||||
const getScoreColor = (score: number) => {
|
const getScoreColor = (score: number) => {
|
||||||
if (score >= 80) return 'text-green-600 dark:text-green-400';
|
if (score >= 80) return 'text-success-600 dark:text-success-400';
|
||||||
if (score >= 60) return 'text-yellow-600 dark:text-yellow-400';
|
if (score >= 60) return 'text-warning-600 dark:text-warning-400';
|
||||||
return 'text-red-600 dark:text-red-400';
|
return 'text-error-600 dark:text-error-400';
|
||||||
};
|
};
|
||||||
|
|
||||||
const getScoreBgColor = (score: number) => {
|
const getScoreBgColor = (score: number) => {
|
||||||
if (score >= 80) return 'bg-green-100 dark:bg-green-900';
|
if (score >= 80) return 'bg-success-100 dark:bg-success-900';
|
||||||
if (score >= 60) return 'bg-yellow-100 dark:bg-yellow-900';
|
if (score >= 60) return 'bg-warning-100 dark:bg-warning-900';
|
||||||
return 'bg-red-100 dark:bg-red-900';
|
return 'bg-error-100 dark:bg-error-900';
|
||||||
};
|
};
|
||||||
|
|
||||||
const getChangeIcon = (current: number, previous?: number) => {
|
const getChangeIcon = (current: number, previous?: number) => {
|
||||||
if (!previous) return null;
|
if (!previous) return null;
|
||||||
const diff = current - previous;
|
const diff = current - previous;
|
||||||
if (diff > 0) return <ArrowUpIcon className="w-4 h-4 text-green-600" />;
|
if (diff > 0) return <ArrowUpIcon className="w-4 h-4 text-success-600" />;
|
||||||
if (diff < 0) return <ArrowDownIcon className="w-4 h-4 text-red-600" />;
|
if (diff < 0) return <ArrowDownIcon className="w-4 h-4 text-error-600" />;
|
||||||
return <span className="w-4 h-4 text-gray-400">—</span>;
|
return <span className="w-4 h-4 text-gray-400">—</span>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ export const OptimizationScores: React.FC<OptimizationScoresProps> = ({
|
|||||||
{/* Metadata indicators */}
|
{/* Metadata indicators */}
|
||||||
<div className="mt-3 flex flex-wrap gap-2 text-xs">
|
<div className="mt-3 flex flex-wrap gap-2 text-xs">
|
||||||
{scores.has_cluster_mapping && (
|
{scores.has_cluster_mapping && (
|
||||||
<span className="px-2 py-0.5 bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded">
|
<span className="px-2 py-0.5 bg-brand-100 dark:bg-brand-900 text-brand-800 dark:text-brand-200 rounded">
|
||||||
Cluster
|
Cluster
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -192,7 +192,7 @@ export const OptimizationScores: React.FC<OptimizationScoresProps> = ({
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{scores.has_attributes && (
|
{scores.has_attributes && (
|
||||||
<span className="px-2 py-0.5 bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200 rounded">
|
<span className="px-2 py-0.5 bg-success-100 dark:bg-success-900 text-success-800 dark:text-success-200 rounded">
|
||||||
Attributes
|
Attributes
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ export const ScoreComparison: React.FC<ScoreComparisonProps> = ({
|
|||||||
<span
|
<span
|
||||||
className={`text-lg font-bold ${
|
className={`text-lg font-bold ${
|
||||||
overallImprovement.diff > 0
|
overallImprovement.diff > 0
|
||||||
? 'text-green-600 dark:text-green-400'
|
? 'text-success-600 dark:text-success-400'
|
||||||
: overallImprovement.diff < 0
|
: overallImprovement.diff < 0
|
||||||
? 'text-red-600 dark:text-red-400'
|
? 'text-error-600 dark:text-error-400'
|
||||||
: 'text-gray-600 dark:text-gray-400'
|
: 'text-gray-600 dark:text-gray-400'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -84,9 +84,9 @@ export const ScoreComparison: React.FC<ScoreComparisonProps> = ({
|
|||||||
<span
|
<span
|
||||||
className={`text-sm font-medium ${
|
className={`text-sm font-medium ${
|
||||||
improvement.diff > 0
|
improvement.diff > 0
|
||||||
? 'text-green-600 dark:text-green-400'
|
? 'text-success-600 dark:text-success-400'
|
||||||
: improvement.diff < 0
|
: improvement.diff < 0
|
||||||
? 'text-red-600 dark:text-red-400'
|
? 'text-error-600 dark:text-error-400'
|
||||||
: 'text-gray-600 dark:text-gray-400'
|
: 'text-gray-600 dark:text-gray-400'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -95,9 +95,9 @@ export const ScoreComparison: React.FC<ScoreComparisonProps> = ({
|
|||||||
<span
|
<span
|
||||||
className={`text-xs ${
|
className={`text-xs ${
|
||||||
improvement.diff > 0
|
improvement.diff > 0
|
||||||
? 'text-green-600 dark:text-green-400'
|
? 'text-success-600 dark:text-success-400'
|
||||||
: improvement.diff < 0
|
: improvement.diff < 0
|
||||||
? 'text-red-600 dark:text-red-400'
|
? 'text-error-600 dark:text-error-400'
|
||||||
: 'text-gray-500'
|
: 'text-gray-500'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export default function SiteProgressWidget({ blueprintId, siteId }: SiteProgress
|
|||||||
return (
|
return (
|
||||||
<Card className="p-4">
|
<Card className="p-4">
|
||||||
<div className="text-center py-4">
|
<div className="text-center py-4">
|
||||||
<div className="inline-block animate-spin rounded-full h-6 w-6 border-b-2 border-blue-500 mb-2"></div>
|
<div className="inline-block animate-spin rounded-full h-6 w-6 border-b-2 border-brand-500 mb-2"></div>
|
||||||
<div className="text-gray-500 dark:text-gray-400">Loading progress...</div>
|
<div className="text-gray-500 dark:text-gray-400">Loading progress...</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -61,12 +61,12 @@ export default function SiteProgressWidget({ blueprintId, siteId }: SiteProgress
|
|||||||
return (
|
return (
|
||||||
<Card className="p-4">
|
<Card className="p-4">
|
||||||
<div className="text-center py-4">
|
<div className="text-center py-4">
|
||||||
<AlertCircleIcon className="w-8 h-8 text-red-500 mx-auto mb-2" />
|
<AlertCircleIcon className="w-8 h-8 text-error-500 mx-auto mb-2" />
|
||||||
<div className="text-sm text-red-600 dark:text-red-400 mb-3">{error}</div>
|
<div className="text-sm text-error-600 dark:text-error-400 mb-3">{error}</div>
|
||||||
<button
|
<button
|
||||||
onClick={handleRetry}
|
onClick={handleRetry}
|
||||||
disabled={retryCount >= 3}
|
disabled={retryCount >= 3}
|
||||||
className="px-4 py-2 bg-blue-500 hover:bg-blue-600 disabled:bg-gray-400 text-white rounded-lg text-sm font-medium transition-colors"
|
className="px-4 py-2 bg-brand-500 hover:bg-brand-600 disabled:bg-gray-400 text-white rounded-lg text-sm font-medium transition-colors"
|
||||||
aria-label="Retry loading site progress"
|
aria-label="Retry loading site progress"
|
||||||
>
|
>
|
||||||
{retryCount >= 3 ? 'Max retries reached' : 'Retry'}
|
{retryCount >= 3 ? 'Max retries reached' : 'Retry'}
|
||||||
@@ -185,7 +185,7 @@ export default function SiteProgressWidget({ blueprintId, siteId }: SiteProgress
|
|||||||
key={cluster.cluster_id}
|
key={cluster.cluster_id}
|
||||||
className={`p-4 rounded-lg border-2 ${
|
className={`p-4 rounded-lg border-2 ${
|
||||||
cluster.is_complete
|
cluster.is_complete
|
||||||
? 'border-green-200 dark:border-green-800 bg-green-50 dark:bg-green-900/20'
|
? 'border-success-200 dark:border-success-800 bg-success-50 dark:bg-success-900/20'
|
||||||
: 'border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800'
|
: 'border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -199,9 +199,9 @@ export default function SiteProgressWidget({ blueprintId, siteId }: SiteProgress
|
|||||||
{cluster.role}
|
{cluster.role}
|
||||||
</Badge>
|
</Badge>
|
||||||
{cluster.is_complete ? (
|
{cluster.is_complete ? (
|
||||||
<CheckCircleIcon className="w-4 h-4 text-green-600 dark:text-green-400" />
|
<CheckCircleIcon className="w-4 h-4 text-success-600 dark:text-success-400" />
|
||||||
) : (
|
) : (
|
||||||
<AlertCircleIcon className="w-4 h-4 text-amber-600 dark:text-amber-400" />
|
<AlertCircleIcon className="w-4 h-4 text-warning-600 dark:text-warning-400" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-gray-600 dark:text-gray-400">
|
<div className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
@@ -210,7 +210,7 @@ export default function SiteProgressWidget({ blueprintId, siteId }: SiteProgress
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => navigate(`/planner/clusters/${cluster.cluster_id}`)}
|
onClick={() => navigate(`/planner/clusters/${cluster.cluster_id}`)}
|
||||||
className="text-xs text-blue-600 dark:text-blue-400 hover:underline flex items-center gap-1 transition-colors"
|
className="text-xs text-brand-600 dark:text-brand-400 hover:underline flex items-center gap-1 transition-colors"
|
||||||
aria-label={`View cluster ${cluster.cluster_name}`}
|
aria-label={`View cluster ${cluster.cluster_name}`}
|
||||||
>
|
>
|
||||||
View <ArrowRightIcon className="w-3 h-3" />
|
View <ArrowRightIcon className="w-3 h-3" />
|
||||||
@@ -227,8 +227,8 @@ export default function SiteProgressWidget({ blueprintId, siteId }: SiteProgress
|
|||||||
<div
|
<div
|
||||||
className={`h-2 rounded-full ${
|
className={`h-2 rounded-full ${
|
||||||
cluster.is_complete
|
cluster.is_complete
|
||||||
? 'bg-green-500 dark:bg-green-400'
|
? 'bg-success-500 dark:bg-success-400'
|
||||||
: 'bg-blue-500 dark:bg-blue-400'
|
: 'bg-brand-500 dark:bg-brand-400'
|
||||||
}`}
|
}`}
|
||||||
style={{ width: `${completionPercent}%` }}
|
style={{ width: `${completionPercent}%` }}
|
||||||
/>
|
/>
|
||||||
@@ -254,13 +254,13 @@ export default function SiteProgressWidget({ blueprintId, siteId }: SiteProgress
|
|||||||
{/* Validation Messages */}
|
{/* Validation Messages */}
|
||||||
{cluster.validation_messages && cluster.validation_messages.length > 0 && (
|
{cluster.validation_messages && cluster.validation_messages.length > 0 && (
|
||||||
<div className="mt-3 pt-3 border-t border-gray-200 dark:border-gray-700">
|
<div className="mt-3 pt-3 border-t border-gray-200 dark:border-gray-700">
|
||||||
<div className="text-xs font-medium text-red-600 dark:text-red-400 mb-1">
|
<div className="text-xs font-medium text-error-600 dark:text-error-400 mb-1">
|
||||||
Issues:
|
Issues:
|
||||||
</div>
|
</div>
|
||||||
<ul className="text-xs text-gray-600 dark:text-gray-400 space-y-1">
|
<ul className="text-xs text-gray-600 dark:text-gray-400 space-y-1">
|
||||||
{cluster.validation_messages.map((msg, idx) => (
|
{cluster.validation_messages.map((msg, idx) => (
|
||||||
<li key={idx} className="flex items-start gap-1">
|
<li key={idx} className="flex items-start gap-1">
|
||||||
<XCircleIcon className="w-3 h-3 text-red-500 mt-0.5 flex-shrink-0" />
|
<XCircleIcon className="w-3 h-3 text-error-500 mt-0.5 flex-shrink-0" />
|
||||||
<span>{msg}</span>
|
<span>{msg}</span>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
@@ -286,33 +286,33 @@ export default function SiteProgressWidget({ blueprintId, siteId }: SiteProgress
|
|||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{validationFlags.clusters_attached ? (
|
{validationFlags.clusters_attached ? (
|
||||||
<CheckCircleIcon className="w-4 h-4 text-green-600 dark:text-green-400" />
|
<CheckCircleIcon className="w-4 h-4 text-success-600 dark:text-success-400" />
|
||||||
) : (
|
) : (
|
||||||
<XCircleIcon className="w-4 h-4 text-red-600 dark:text-red-400" />
|
<XCircleIcon className="w-4 h-4 text-error-600 dark:text-error-400" />
|
||||||
)}
|
)}
|
||||||
<span className="text-sm text-gray-700 dark:text-gray-300">Clusters Attached</span>
|
<span className="text-sm text-gray-700 dark:text-gray-300">Clusters Attached</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{validationFlags.taxonomies_defined ? (
|
{validationFlags.taxonomies_defined ? (
|
||||||
<CheckCircleIcon className="w-4 h-4 text-green-600 dark:text-green-400" />
|
<CheckCircleIcon className="w-4 h-4 text-success-600 dark:text-success-400" />
|
||||||
) : (
|
) : (
|
||||||
<XCircleIcon className="w-4 h-4 text-red-600 dark:text-red-400" />
|
<XCircleIcon className="w-4 h-4 text-error-600 dark:text-error-400" />
|
||||||
)}
|
)}
|
||||||
<span className="text-sm text-gray-700 dark:text-gray-300">Taxonomies Defined</span>
|
<span className="text-sm text-gray-700 dark:text-gray-300">Taxonomies Defined</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{validationFlags.sitemap_generated ? (
|
{validationFlags.sitemap_generated ? (
|
||||||
<CheckCircleIcon className="w-4 h-4 text-green-600 dark:text-green-400" />
|
<CheckCircleIcon className="w-4 h-4 text-success-600 dark:text-success-400" />
|
||||||
) : (
|
) : (
|
||||||
<XCircleIcon className="w-4 h-4 text-red-600 dark:text-red-400" />
|
<XCircleIcon className="w-4 h-4 text-error-600 dark:text-error-400" />
|
||||||
)}
|
)}
|
||||||
<span className="text-sm text-gray-700 dark:text-gray-300">Sitemap Generated</span>
|
<span className="text-sm text-gray-700 dark:text-gray-300">Sitemap Generated</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{validationFlags.all_pages_generated ? (
|
{validationFlags.all_pages_generated ? (
|
||||||
<CheckCircleIcon className="w-4 h-4 text-green-600 dark:text-green-400" />
|
<CheckCircleIcon className="w-4 h-4 text-success-600 dark:text-success-400" />
|
||||||
) : (
|
) : (
|
||||||
<XCircleIcon className="w-4 h-4 text-red-600 dark:text-red-400" />
|
<XCircleIcon className="w-4 h-4 text-error-600 dark:text-error-400" />
|
||||||
)}
|
)}
|
||||||
<span className="text-sm text-gray-700 dark:text-gray-300">All Pages Generated</span>
|
<span className="text-sm text-gray-700 dark:text-gray-300">All Pages Generated</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -322,10 +322,10 @@ export default function SiteProgressWidget({ blueprintId, siteId }: SiteProgress
|
|||||||
|
|
||||||
{/* Error banner if data loaded but has errors */}
|
{/* Error banner if data loaded but has errors */}
|
||||||
{error && progress && (
|
{error && progress && (
|
||||||
<div className="mt-4 p-3 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
|
<div className="mt-4 p-3 bg-warning-50 dark:bg-warning-900/20 border border-warning-200 dark:border-warning-800 rounded-lg">
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<AlertCircleIcon className="w-4 h-4 text-yellow-600 dark:text-yellow-400 mt-0.5 flex-shrink-0" />
|
<AlertCircleIcon className="w-4 h-4 text-warning-600 dark:text-warning-400 mt-0.5 flex-shrink-0" />
|
||||||
<div className="text-xs text-yellow-800 dark:text-yellow-300">
|
<div className="text-xs text-warning-800 dark:text-warning-300">
|
||||||
Some data may be outdated. <button onClick={handleRetry} className="underline font-medium">Refresh</button>
|
Some data may be outdated. <button onClick={handleRetry} className="underline font-medium">Refresh</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export default function SiteSetupChecklist({
|
|||||||
key={item.id}
|
key={item.id}
|
||||||
className={`w-2 h-2 rounded-full ${
|
className={`w-2 h-2 rounded-full ${
|
||||||
item.completed
|
item.completed
|
||||||
? 'bg-green-500'
|
? 'bg-success-500'
|
||||||
: 'bg-gray-300 dark:bg-gray-600'
|
: 'bg-gray-300 dark:bg-gray-600'
|
||||||
}`}
|
}`}
|
||||||
title={item.label}
|
title={item.label}
|
||||||
@@ -92,7 +92,7 @@ export default function SiteSetupChecklist({
|
|||||||
{completedCount}/{totalCount}
|
{completedCount}/{totalCount}
|
||||||
</span>
|
</span>
|
||||||
{isComplete && (
|
{isComplete && (
|
||||||
<span className="text-xs text-green-600 dark:text-green-400 font-medium">
|
<span className="text-xs text-success-600 dark:text-success-400 font-medium">
|
||||||
✓ Ready
|
✓ Ready
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -116,7 +116,7 @@ export default function SiteSetupChecklist({
|
|||||||
<div className="w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-full mb-4">
|
<div className="w-full h-2 bg-gray-200 dark:bg-gray-700 rounded-full mb-4">
|
||||||
<div
|
<div
|
||||||
className={`h-full rounded-full transition-all duration-500 ${
|
className={`h-full rounded-full transition-all duration-500 ${
|
||||||
isComplete ? 'bg-green-500' : 'bg-blue-500'
|
isComplete ? 'bg-success-500' : 'bg-brand-500'
|
||||||
}`}
|
}`}
|
||||||
style={{ width: `${progressPercent}%` }}
|
style={{ width: `${progressPercent}%` }}
|
||||||
/>
|
/>
|
||||||
@@ -133,7 +133,7 @@ export default function SiteSetupChecklist({
|
|||||||
<div
|
<div
|
||||||
className={`flex-shrink-0 w-5 h-5 rounded-full flex items-center justify-center ${
|
className={`flex-shrink-0 w-5 h-5 rounded-full flex items-center justify-center ${
|
||||||
item.completed
|
item.completed
|
||||||
? 'bg-green-100 dark:bg-green-900/30 text-green-600 dark:text-green-400'
|
? 'bg-success-100 dark:bg-success-900/30 text-success-600 dark:text-success-400'
|
||||||
: 'bg-gray-100 dark:bg-gray-800 text-gray-400 dark:text-gray-500'
|
: 'bg-gray-100 dark:bg-gray-800 text-gray-400 dark:text-gray-500'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -158,9 +158,9 @@ export default function SiteSetupChecklist({
|
|||||||
|
|
||||||
{/* Action button */}
|
{/* Action button */}
|
||||||
{isComplete ? (
|
{isComplete ? (
|
||||||
<div className="flex items-center gap-2 p-3 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg">
|
<div className="flex items-center gap-2 p-3 bg-success-50 dark:bg-success-900/20 border border-success-200 dark:border-success-800 rounded-lg">
|
||||||
<CheckLineIcon className="w-5 h-5 text-green-600 dark:text-green-400" />
|
<CheckLineIcon className="w-5 h-5 text-success-600 dark:text-success-400" />
|
||||||
<span className="text-sm font-medium text-green-700 dark:text-green-300">
|
<span className="text-sm font-medium text-success-700 dark:text-success-300">
|
||||||
Ready to create content!
|
Ready to create content!
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ export default function TemplateLibrary({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{template.featured && (
|
{template.featured && (
|
||||||
<span className="absolute top-2 left-2 bg-yellow-500 text-white text-xs px-2 py-1 rounded">
|
<span className="absolute top-2 left-2 bg-warning-500 text-white text-xs px-2 py-1 rounded">
|
||||||
Featured
|
Featured
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ export default function WordPressIntegrationCard({
|
|||||||
<Card className="p-6">
|
<Card className="p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-3 bg-indigo-100 dark:bg-indigo-900/30 rounded-lg">
|
<div className="p-3 bg-purple-100 dark:bg-purple-900/30 rounded-lg">
|
||||||
<Globe className="w-6 h-6 text-indigo-600 dark:text-indigo-400" />
|
<Globe className="w-6 h-6 text-purple-600 dark:text-purple-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||||
@@ -73,8 +73,8 @@ export default function WordPressIntegrationCard({
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-3 bg-indigo-100 dark:bg-indigo-900/30 rounded-lg">
|
<div className="p-3 bg-purple-100 dark:bg-purple-900/30 rounded-lg">
|
||||||
<Globe className="w-6 h-6 text-indigo-600 dark:text-indigo-400" />
|
<Globe className="w-6 h-6 text-purple-600 dark:text-purple-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||||
@@ -101,13 +101,13 @@ export default function WordPressIntegrationCard({
|
|||||||
<p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Sync Status</p>
|
<p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Sync Status</p>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{integration.sync_status === 'success' || integration.sync_status === 'healthy' ? (
|
{integration.sync_status === 'success' || integration.sync_status === 'healthy' ? (
|
||||||
<CheckCircle className="w-4 h-4 text-green-500" />
|
<CheckCircle className="w-4 h-4 text-success-500" />
|
||||||
) : integration.sync_status === 'failed' || integration.sync_status === 'error' ? (
|
) : integration.sync_status === 'failed' || integration.sync_status === 'error' ? (
|
||||||
<XCircle className="w-4 h-4 text-red-500" />
|
<XCircle className="w-4 h-4 text-error-500" />
|
||||||
) : integration.sync_status === 'warning' ? (
|
) : integration.sync_status === 'warning' ? (
|
||||||
<AlertCircle className="w-4 h-4 text-yellow-500" />
|
<AlertCircle className="w-4 h-4 text-warning-500" />
|
||||||
) : (
|
) : (
|
||||||
<RefreshCw className="w-4 h-4 text-yellow-500 animate-spin" />
|
<RefreshCw className="w-4 h-4 text-warning-500 animate-spin" />
|
||||||
)}
|
)}
|
||||||
<span className="text-sm font-medium text-gray-900 dark:text-white capitalize">
|
<span className="text-sm font-medium text-gray-900 dark:text-white capitalize">
|
||||||
{integration.sync_status === 'healthy' ? 'Healthy' :
|
{integration.sync_status === 'healthy' ? 'Healthy' :
|
||||||
@@ -132,7 +132,7 @@ export default function WordPressIntegrationCard({
|
|||||||
<div className="pt-2 border-t border-gray-200 dark:border-gray-700">
|
<div className="pt-2 border-t border-gray-200 dark:border-gray-700">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<AlertCircle className="w-4 h-4 text-yellow-500" />
|
<AlertCircle className="w-4 h-4 text-warning-500" />
|
||||||
<span className="text-sm text-gray-600 dark:text-gray-400">
|
<span className="text-sm text-gray-600 dark:text-gray-400">
|
||||||
{integration.mismatch_count} sync mismatch{integration.mismatch_count !== 1 ? 'es' : ''} detected
|
{integration.mismatch_count} sync mismatch{integration.mismatch_count !== 1 ? 'es' : ''} detected
|
||||||
</span>
|
</span>
|
||||||
@@ -153,14 +153,14 @@ export default function WordPressIntegrationCard({
|
|||||||
|
|
||||||
{integration.sync_error && (
|
{integration.sync_error && (
|
||||||
<div className="pt-2 border-t border-gray-200 dark:border-gray-700">
|
<div className="pt-2 border-t border-gray-200 dark:border-gray-700">
|
||||||
<div className="p-2 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
|
<div className="p-2 bg-error-50 dark:bg-error-900/20 border border-error-200 dark:border-error-800 rounded-lg">
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<XCircle className="w-4 h-4 text-red-500 mt-0.5 flex-shrink-0" />
|
<XCircle className="w-4 h-4 text-error-500 mt-0.5 flex-shrink-0" />
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<p className="text-xs font-medium text-red-800 dark:text-red-300 mb-1">
|
<p className="text-xs font-medium text-error-800 dark:text-error-300 mb-1">
|
||||||
Sync Error
|
Sync Error
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-red-700 dark:text-red-400">
|
<p className="text-xs text-error-700 dark:text-error-400">
|
||||||
{integration.sync_error}
|
{integration.sync_error}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -201,8 +201,8 @@ export default function WordPressIntegrationForm({
|
|||||||
{/* Header with Toggle */}
|
{/* Header with Toggle */}
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-3 bg-indigo-100 dark:bg-indigo-900/30 rounded-lg">
|
<div className="p-3 bg-purple-100 dark:bg-purple-900/30 rounded-lg">
|
||||||
<Globe className="w-6 h-6 text-indigo-600 dark:text-indigo-400" />
|
<Globe className="w-6 h-6 text-purple-600 dark:text-purple-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||||
@@ -343,7 +343,7 @@ export default function WordPressIntegrationForm({
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-5 py-3 whitespace-nowrap">
|
<td className="px-5 py-3 whitespace-nowrap">
|
||||||
<span className="inline-flex items-center justify-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium bg-green-50 text-green-600 dark:bg-green-500/15 dark:text-green-500">
|
<span className="inline-flex items-center justify-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium bg-success-50 text-success-600 dark:bg-success-500/15 dark:text-success-500">
|
||||||
Active
|
Active
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -387,7 +387,7 @@ export default function WordPressIntegrationForm({
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<DownloadIcon className="w-5 h-5 text-indigo-600 dark:text-indigo-400" />
|
<DownloadIcon className="w-5 h-5 text-purple-600 dark:text-purple-400" />
|
||||||
IGNY8 WP Bridge Plugin
|
IGNY8 WP Bridge Plugin
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ export default function WordPressIntegrationModal({
|
|||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<div className="flex items-center justify-between mb-6">
|
<div className="flex items-center justify-between mb-6">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-2 bg-indigo-100 dark:bg-indigo-900/30 rounded-lg">
|
<div className="p-2 bg-purple-100 dark:bg-purple-900/30 rounded-lg">
|
||||||
<Globe className="w-5 h-5 text-indigo-600 dark:text-indigo-400" />
|
<Globe className="w-5 h-5 text-purple-600 dark:text-purple-400" />
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||||
{initialData ? 'Edit WordPress Integration' : 'Connect WordPress Site'}
|
{initialData ? 'Edit WordPress Integration' : 'Connect WordPress Site'}
|
||||||
@@ -85,10 +85,10 @@ export default function WordPressIntegrationModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4 mb-4">
|
<div className="bg-brand-50 dark:bg-brand-900/20 border border-brand-200 dark:border-brand-800 rounded-lg p-4 mb-4">
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<AlertCircle className="w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0" />
|
<AlertCircle className="w-5 h-5 text-brand-600 dark:text-brand-400 mt-0.5 flex-shrink-0" />
|
||||||
<div className="text-sm text-blue-800 dark:text-blue-300">
|
<div className="text-sm text-brand-800 dark:text-brand-300">
|
||||||
<p className="font-medium mb-1">WordPress Application Password Required</p>
|
<p className="font-medium mb-1">WordPress Application Password Required</p>
|
||||||
<p>
|
<p>
|
||||||
You need to create an Application Password in WordPress. Go to Users → Profile →
|
You need to create an Application Password in WordPress. Go to Users → Profile →
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ const KanbanColumn: React.FC<KanbanColumnProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const getCountBadgeClass = () => {
|
const getCountBadgeClass = () => {
|
||||||
if (status === "in_progress") {
|
if (status === "in_progress") {
|
||||||
return "bg-warning-50 text-warning-700 dark:bg-warning-500/15 dark:text-orange-400";
|
return "bg-warning-50 text-warning-700 dark:bg-warning-500/15 dark:text-warning-400";
|
||||||
}
|
}
|
||||||
if (status === "completed") {
|
if (status === "completed") {
|
||||||
return "bg-success-50 text-success-700 dark:bg-success-500/15 dark:text-success-500";
|
return "bg-success-50 text-success-700 dark:bg-success-500/15 dark:text-success-500";
|
||||||
@@ -378,9 +378,9 @@ const TaskCard: React.FC<TaskCardProps> = ({ task, onClick, onDragStart }) => {
|
|||||||
case "success":
|
case "success":
|
||||||
return "bg-success-50 text-success-700 dark:bg-success-500/15 dark:text-success-500";
|
return "bg-success-50 text-success-700 dark:bg-success-500/15 dark:text-success-500";
|
||||||
case "warning":
|
case "warning":
|
||||||
return "bg-warning-50 text-warning-700 dark:bg-warning-500/15 dark:text-orange-400";
|
return "bg-warning-50 text-warning-700 dark:bg-warning-500/15 dark:text-warning-400";
|
||||||
case "orange":
|
case "orange":
|
||||||
return "bg-orange-400/10 text-orange-400";
|
return "bg-warning-400/10 text-warning-400";
|
||||||
default:
|
default:
|
||||||
return "bg-gray-100 text-gray-700 dark:bg-white/[0.03] dark:text-white/80";
|
return "bg-gray-100 text-gray-700 dark:bg-white/[0.03] dark:text-white/80";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ const TaskListSection: React.FC<TaskListSectionProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const getCountBadgeClass = () => {
|
const getCountBadgeClass = () => {
|
||||||
if (title === "In Progress") {
|
if (title === "In Progress") {
|
||||||
return "bg-warning-50 text-warning-700 dark:bg-warning-500/15 dark:text-orange-400";
|
return "bg-warning-50 text-warning-700 dark:bg-warning-500/15 dark:text-warning-400";
|
||||||
}
|
}
|
||||||
if (title === "Completed") {
|
if (title === "Completed") {
|
||||||
return "bg-success-50 text-success-700 dark:bg-success-500/15 dark:text-success-500";
|
return "bg-success-50 text-success-700 dark:bg-success-500/15 dark:text-success-500";
|
||||||
@@ -313,9 +313,9 @@ const TaskListItem: React.FC<TaskListItemProps> = ({ task, checked, onClick, onC
|
|||||||
case "success":
|
case "success":
|
||||||
return "bg-success-50 text-success-700 dark:bg-success-500/15 dark:text-success-500";
|
return "bg-success-50 text-success-700 dark:bg-success-500/15 dark:text-success-500";
|
||||||
case "warning":
|
case "warning":
|
||||||
return "bg-warning-50 text-warning-700 dark:bg-warning-500/15 dark:text-orange-400";
|
return "bg-warning-50 text-warning-700 dark:bg-warning-500/15 dark:text-warning-400";
|
||||||
case "orange":
|
case "orange":
|
||||||
return "bg-orange-400/10 text-orange-400";
|
return "bg-warning-400/10 text-warning-400";
|
||||||
default:
|
default:
|
||||||
return "bg-gray-100 text-gray-700 dark:bg-white/[0.03] dark:text-white/80";
|
return "bg-gray-100 text-gray-700 dark:bg-white/[0.03] dark:text-white/80";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,34 +73,34 @@ const toneStyles: Record<
|
|||||||
"text-purple-700 ring-1 ring-purple-200 dark:ring-purple-500/30 dark:text-purple-400",
|
"text-purple-700 ring-1 ring-purple-200 dark:ring-purple-500/30 dark:text-purple-400",
|
||||||
},
|
},
|
||||||
indigo: {
|
indigo: {
|
||||||
solid: "bg-indigo-600 text-white",
|
solid: "bg-purple-600 text-white",
|
||||||
soft: "bg-indigo-50 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-400",
|
soft: "bg-purple-50 text-purple-700 dark:bg-purple-500/15 dark:text-purple-400",
|
||||||
outline:
|
outline:
|
||||||
"text-indigo-700 ring-1 ring-indigo-200 dark:ring-indigo-500/30 dark:text-indigo-400",
|
"text-purple-700 ring-1 ring-purple-200 dark:ring-purple-500/30 dark:text-purple-400",
|
||||||
},
|
},
|
||||||
pink: {
|
pink: {
|
||||||
solid: "bg-pink-600 text-white",
|
solid: "bg-purple-600 text-white",
|
||||||
soft: "bg-pink-50 text-pink-700 dark:bg-pink-500/15 dark:text-pink-400",
|
soft: "bg-purple-50 text-purple-700 dark:bg-purple-500/15 dark:text-purple-400",
|
||||||
outline:
|
outline:
|
||||||
"text-pink-700 ring-1 ring-pink-200 dark:ring-pink-500/30 dark:text-pink-400",
|
"text-purple-700 ring-1 ring-purple-200 dark:ring-purple-500/30 dark:text-purple-400",
|
||||||
},
|
},
|
||||||
teal: {
|
teal: {
|
||||||
solid: "bg-teal-600 text-white",
|
solid: "bg-purple-600 text-white",
|
||||||
soft: "bg-teal-50 text-teal-700 dark:bg-teal-500/15 dark:text-teal-400",
|
soft: "bg-purple-50 text-purple-700 dark:bg-purple-500/15 dark:text-purple-400",
|
||||||
outline:
|
outline:
|
||||||
"text-teal-700 ring-1 ring-teal-200 dark:ring-teal-500/30 dark:text-teal-400",
|
"text-purple-700 ring-1 ring-purple-200 dark:ring-purple-500/30 dark:text-purple-400",
|
||||||
},
|
},
|
||||||
cyan: {
|
cyan: {
|
||||||
solid: "bg-cyan-600 text-white",
|
solid: "bg-purple-600 text-white",
|
||||||
soft: "bg-cyan-50 text-cyan-700 dark:bg-cyan-500/15 dark:text-cyan-400",
|
soft: "bg-purple-50 text-purple-700 dark:bg-purple-500/15 dark:text-purple-400",
|
||||||
outline:
|
outline:
|
||||||
"text-cyan-700 ring-1 ring-cyan-200 dark:ring-cyan-500/30 dark:text-cyan-400",
|
"text-purple-700 ring-1 ring-purple-200 dark:ring-purple-500/30 dark:text-purple-400",
|
||||||
},
|
},
|
||||||
blue: {
|
blue: {
|
||||||
solid: "bg-blue-600 text-white",
|
solid: "bg-brand-600 text-white",
|
||||||
soft: "bg-blue-50 text-blue-700 dark:bg-blue-500/15 dark:text-blue-400",
|
soft: "bg-brand-50 text-brand-700 dark:bg-brand-500/15 dark:text-brand-400",
|
||||||
outline:
|
outline:
|
||||||
"text-blue-700 ring-1 ring-blue-200 dark:ring-blue-500/30 dark:text-blue-400",
|
"text-brand-700 ring-1 ring-brand-200 dark:ring-brand-500/30 dark:text-brand-400",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ const gradientTone: Record<ButtonTone, string> = {
|
|||||||
danger:
|
danger:
|
||||||
"text-white shadow-[0_20px_45px_-30px_rgba(239,68,68,0.9)] bg-[linear-gradient(135deg,var(--color-danger)_0%,var(--color-danger-dark)_100%)]",
|
"text-white shadow-[0_20px_45px_-30px_rgba(239,68,68,0.9)] bg-[linear-gradient(135deg,var(--color-danger)_0%,var(--color-danger-dark)_100%)]",
|
||||||
neutral:
|
neutral:
|
||||||
"text-white shadow-theme-lg bg-[linear-gradient(135deg,#0f172a,#1e293b)]",
|
"text-white shadow-theme-lg bg-[linear-gradient(135deg,var(--color-gray-900),var(--color-gray-800))]",
|
||||||
};
|
};
|
||||||
|
|
||||||
const sizeClasses: Record<ButtonSize, string> = {
|
const sizeClasses: Record<ButtonSize, string> = {
|
||||||
|
|||||||
@@ -104,9 +104,8 @@ export default function PricingTable({
|
|||||||
<div className="relative inline-flex items-center justify-center">
|
<div className="relative inline-flex items-center justify-center">
|
||||||
<div className="relative inline-flex p-1 bg-gray-200 rounded-full dark:bg-gray-800 shadow-sm">
|
<div className="relative inline-flex p-1 bg-gray-200 rounded-full dark:bg-gray-800 shadow-sm">
|
||||||
<span
|
<span
|
||||||
className="absolute top-1 left-1 flex h-11 w-[130px] rounded-full shadow-theme-xs duration-200 ease-linear"
|
className="absolute top-1 left-1 flex h-11 w-[130px] rounded-full shadow-theme-xs duration-200 ease-linear bg-gradient-to-br from-brand-500 to-brand-700"
|
||||||
style={{
|
style={{
|
||||||
background: 'linear-gradient(to bottom right, #0693e3, #0472b8)',
|
|
||||||
transform: billingPeriod === 'monthly' ? 'translateX(0)' : 'translateX(130px)',
|
transform: billingPeriod === 'monthly' ? 'translateX(0)' : 'translateX(130px)',
|
||||||
}}
|
}}
|
||||||
></span>
|
></span>
|
||||||
@@ -134,7 +133,7 @@ export default function PricingTable({
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{billingPeriod === 'annually' && (
|
{billingPeriod === 'annually' && (
|
||||||
<span className="absolute left-[calc(100%+1rem)] whitespace-nowrap inline-flex items-center gap-1.5 text-green-600 dark:text-green-400 font-semibold bg-green-50 dark:bg-green-900/20 px-3 py-1.5 rounded-full text-sm">
|
<span className="absolute left-[calc(100%+1rem)] whitespace-nowrap inline-flex items-center gap-1.5 text-success-600 dark:text-success-400 font-semibold bg-success-50 dark:bg-success-900/20 px-3 py-1.5 rounded-full text-sm">
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path
|
<path
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false,
|
|||||||
<ul className="space-y-3 mb-6 flex-grow">
|
<ul className="space-y-3 mb-6 flex-grow">
|
||||||
{plan.features.map((feature, index) => (
|
{plan.features.map((feature, index) => (
|
||||||
<li key={index} className="flex items-start gap-2">
|
<li key={index} className="flex items-start gap-2">
|
||||||
<Check className="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" />
|
<Check className="w-5 h-5 text-success-500 flex-shrink-0 mt-0.5" />
|
||||||
<span className="text-sm text-gray-700 dark:text-gray-300">{feature}</span>
|
<span className="text-sm text-gray-700 dark:text-gray-300">{feature}</span>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
@@ -152,7 +152,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false,
|
|||||||
<div className="text-xs font-semibold text-gray-500 dark:text-gray-400 mb-2">LIMITS</div>
|
<div className="text-xs font-semibold text-gray-500 dark:text-gray-400 mb-2">LIMITS</div>
|
||||||
{plan.max_sites && (
|
{plan.max_sites && (
|
||||||
<li className="flex items-start gap-2">
|
<li className="flex items-start gap-2">
|
||||||
<Check className="w-4 h-4 text-blue-500 flex-shrink-0 mt-0.5" />
|
<Check className="w-4 h-4 text-brand-500 flex-shrink-0 mt-0.5" />
|
||||||
<span className="text-xs text-gray-600 dark:text-gray-400">
|
<span className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
{plan.max_sites === 99999 ? 'Unlimited' : plan.max_sites} Sites
|
{plan.max_sites === 99999 ? 'Unlimited' : plan.max_sites} Sites
|
||||||
</span>
|
</span>
|
||||||
@@ -160,7 +160,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false,
|
|||||||
)}
|
)}
|
||||||
{plan.max_users && (
|
{plan.max_users && (
|
||||||
<li className="flex items-start gap-2">
|
<li className="flex items-start gap-2">
|
||||||
<Check className="w-4 h-4 text-blue-500 flex-shrink-0 mt-0.5" />
|
<Check className="w-4 h-4 text-brand-500 flex-shrink-0 mt-0.5" />
|
||||||
<span className="text-xs text-gray-600 dark:text-gray-400">
|
<span className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
{plan.max_users === 99999 ? 'Unlimited' : plan.max_users} Team Members
|
{plan.max_users === 99999 ? 'Unlimited' : plan.max_users} Team Members
|
||||||
</span>
|
</span>
|
||||||
@@ -168,7 +168,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false,
|
|||||||
)}
|
)}
|
||||||
{plan.max_content_words && (
|
{plan.max_content_words && (
|
||||||
<li className="flex items-start gap-2">
|
<li className="flex items-start gap-2">
|
||||||
<Check className="w-4 h-4 text-blue-500 flex-shrink-0 mt-0.5" />
|
<Check className="w-4 h-4 text-brand-500 flex-shrink-0 mt-0.5" />
|
||||||
<span className="text-xs text-gray-600 dark:text-gray-400">
|
<span className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
{(plan.max_content_words / 1000).toLocaleString()}K Words/month
|
{(plan.max_content_words / 1000).toLocaleString()}K Words/month
|
||||||
</span>
|
</span>
|
||||||
@@ -176,7 +176,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false,
|
|||||||
)}
|
)}
|
||||||
{plan.max_content_ideas && (
|
{plan.max_content_ideas && (
|
||||||
<li className="flex items-start gap-2">
|
<li className="flex items-start gap-2">
|
||||||
<Check className="w-4 h-4 text-blue-500 flex-shrink-0 mt-0.5" />
|
<Check className="w-4 h-4 text-brand-500 flex-shrink-0 mt-0.5" />
|
||||||
<span className="text-xs text-gray-600 dark:text-gray-400">
|
<span className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
{plan.max_content_ideas} Ideas/month
|
{plan.max_content_ideas} Ideas/month
|
||||||
</span>
|
</span>
|
||||||
@@ -184,7 +184,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false,
|
|||||||
)}
|
)}
|
||||||
{plan.max_images_basic && (
|
{plan.max_images_basic && (
|
||||||
<li className="flex items-start gap-2">
|
<li className="flex items-start gap-2">
|
||||||
<Check className="w-4 h-4 text-blue-500 flex-shrink-0 mt-0.5" />
|
<Check className="w-4 h-4 text-brand-500 flex-shrink-0 mt-0.5" />
|
||||||
<span className="text-xs text-gray-600 dark:text-gray-400">
|
<span className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
{plan.max_images_basic} Images/month
|
{plan.max_images_basic} Images/month
|
||||||
</span>
|
</span>
|
||||||
@@ -192,7 +192,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false,
|
|||||||
)}
|
)}
|
||||||
{plan.included_credits && (
|
{plan.included_credits && (
|
||||||
<li className="flex items-start gap-2">
|
<li className="flex items-start gap-2">
|
||||||
<Check className="w-4 h-4 text-blue-500 flex-shrink-0 mt-0.5" />
|
<Check className="w-4 h-4 text-brand-500 flex-shrink-0 mt-0.5" />
|
||||||
<span className="text-xs text-gray-600 dark:text-gray-400">
|
<span className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
{plan.included_credits.toLocaleString()} Content pieces/month
|
{plan.included_credits.toLocaleString()} Content pieces/month
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ export function useImportExport(
|
|||||||
Upload a CSV file (max {maxFileSize / 1024 / 1024}MB)
|
Upload a CSV file (max {maxFileSize / 1024 / 1024}MB)
|
||||||
</p>
|
</p>
|
||||||
{filename === 'keywords' && (
|
{filename === 'keywords' && (
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-300 mt-2 p-2 bg-blue-50 dark:bg-blue-900/20 rounded border border-blue-200 dark:border-blue-800">
|
<p className="text-xs text-gray-600 dark:text-gray-300 mt-2 p-2 bg-brand-50 dark:bg-brand-900/20 rounded border border-brand-200 dark:border-brand-800">
|
||||||
<strong>Expected columns:</strong> keyword, volume, difficulty, country, status
|
<strong>Expected columns:</strong> keyword, volume, difficulty, country, status
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export function createApprovedPageConfig(params: {
|
|||||||
{params.onRowClick ? (
|
{params.onRowClick ? (
|
||||||
<button
|
<button
|
||||||
onClick={() => params.onRowClick!(row)}
|
onClick={() => params.onRowClick!(row)}
|
||||||
className="text-base font-light text-blue-500 hover:text-blue-600 hover:underline text-left transition-colors"
|
className="text-base font-light text-brand-500 hover:text-brand-600 hover:underline text-left transition-colors"
|
||||||
>
|
>
|
||||||
{value || `Content #${row.id}`}
|
{value || `Content #${row.id}`}
|
||||||
</button>
|
</button>
|
||||||
@@ -81,7 +81,7 @@ export function createApprovedPageConfig(params: {
|
|||||||
href={row.external_url}
|
href={row.external_url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-blue-500 hover:text-blue-600 transition-colors"
|
className="text-brand-500 hover:text-brand-600 transition-colors"
|
||||||
title="View on WordPress"
|
title="View on WordPress"
|
||||||
>
|
>
|
||||||
<ArrowRightIcon className="w-4 h-4" />
|
<ArrowRightIcon className="w-4 h-4" />
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export const createContentPageConfig = (
|
|||||||
{handlers.onRowClick ? (
|
{handlers.onRowClick ? (
|
||||||
<button
|
<button
|
||||||
onClick={() => handlers.onRowClick!(row)}
|
onClick={() => handlers.onRowClick!(row)}
|
||||||
className="text-base font-light text-blue-500 hover:text-blue-600 hover:underline text-left transition-colors"
|
className="text-base font-light text-brand-500 hover:text-brand-600 hover:underline text-left transition-colors"
|
||||||
>
|
>
|
||||||
{row.title || `Content #${row.id}`}
|
{row.title || `Content #${row.id}`}
|
||||||
</button>
|
</button>
|
||||||
@@ -324,9 +324,9 @@ export const createContentPageConfig = (
|
|||||||
imageStatus = 'pending';
|
imageStatus = 'pending';
|
||||||
}
|
}
|
||||||
const imageStatusColors: Record<string, string> = {
|
const imageStatusColors: Record<string, string> = {
|
||||||
'pending': 'text-amber-500 dark:text-amber-400',
|
'pending': 'text-warning-500 dark:text-warning-400',
|
||||||
'generated': 'text-green-500 dark:text-green-400',
|
'generated': 'text-success-500 dark:text-success-400',
|
||||||
'failed': 'text-red-500 dark:text-red-400',
|
'failed': 'text-error-500 dark:text-error-400',
|
||||||
};
|
};
|
||||||
const imageStatusTitles: Record<string, string> = {
|
const imageStatusTitles: Record<string, string> = {
|
||||||
'pending': 'Images pending',
|
'pending': 'Images pending',
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export function createReviewPageConfig(params: {
|
|||||||
{params.onRowClick ? (
|
{params.onRowClick ? (
|
||||||
<button
|
<button
|
||||||
onClick={() => params.onRowClick!(row)}
|
onClick={() => params.onRowClick!(row)}
|
||||||
className="text-base font-light text-blue-500 hover:text-blue-600 hover:underline text-left transition-colors"
|
className="text-base font-light text-brand-500 hover:text-brand-600 hover:underline text-left transition-colors"
|
||||||
>
|
>
|
||||||
{value || `Content #${row.id}`}
|
{value || `Content #${row.id}`}
|
||||||
</button>
|
</button>
|
||||||
@@ -202,7 +202,7 @@ export function createReviewPageConfig(params: {
|
|||||||
<span className="text-[11px] font-normal">{label}</span>
|
<span className="text-[11px] font-normal">{label}</span>
|
||||||
</Badge>
|
</Badge>
|
||||||
{row.external_id && (
|
{row.external_id && (
|
||||||
<CheckCircleIcon className="w-3.5 h-3.5 text-green-500" title="Published to WordPress" />
|
<CheckCircleIcon className="w-3.5 h-3.5 text-success-500" title="Published to WordPress" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ const tableActionsConfigs: Record<string, TableActionsConfig> = {
|
|||||||
{
|
{
|
||||||
key: 'view_on_wordpress',
|
key: 'view_on_wordpress',
|
||||||
label: 'View on WordPress',
|
label: 'View on WordPress',
|
||||||
icon: <CheckCircleIcon className="w-5 h-5 text-blue-500" />,
|
icon: <CheckCircleIcon className="w-5 h-5 text-brand-500" />,
|
||||||
variant: 'secondary',
|
variant: 'secondary',
|
||||||
shouldShow: (row: any) => !!row.external_id, // Only show if published
|
shouldShow: (row: any) => !!row.external_id, // Only show if published
|
||||||
},
|
},
|
||||||
@@ -303,7 +303,7 @@ const tableActionsConfigs: Record<string, TableActionsConfig> = {
|
|||||||
{
|
{
|
||||||
key: 'view_on_wordpress',
|
key: 'view_on_wordpress',
|
||||||
label: 'View on Site',
|
label: 'View on Site',
|
||||||
icon: <CheckCircleIcon className="w-5 h-5 text-blue-500" />,
|
icon: <CheckCircleIcon className="w-5 h-5 text-brand-500" />,
|
||||||
variant: 'secondary',
|
variant: 'secondary',
|
||||||
shouldShow: (row: any) => !!row.external_id, // Only show if published
|
shouldShow: (row: any) => !!row.external_id, // Only show if published
|
||||||
},
|
},
|
||||||
@@ -342,7 +342,7 @@ const tableActionsConfigs: Record<string, TableActionsConfig> = {
|
|||||||
{
|
{
|
||||||
key: 'view_on_wordpress',
|
key: 'view_on_wordpress',
|
||||||
label: 'View on WordPress',
|
label: 'View on WordPress',
|
||||||
icon: <CheckCircleIcon className="w-5 h-5 text-blue-500" />,
|
icon: <CheckCircleIcon className="w-5 h-5 text-brand-500" />,
|
||||||
variant: 'secondary',
|
variant: 'secondary',
|
||||||
shouldShow: (row: any) => !!row.external_id, // Only show if published
|
shouldShow: (row: any) => !!row.external_id, // Only show if published
|
||||||
},
|
},
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -30,18 +30,18 @@ const SITE_WITH_ALL_SITES_ROUTES = [
|
|||||||
|
|
||||||
// Badge color mappings for light versions
|
// Badge color mappings for light versions
|
||||||
const badgeColors: Record<string, { bg: string; light: string }> = {
|
const badgeColors: Record<string, { bg: string; light: string }> = {
|
||||||
blue: { bg: 'bg-blue-600 dark:bg-blue-500', light: 'bg-blue-100 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300' },
|
blue: { bg: 'bg-brand-600 dark:bg-brand-500', light: 'bg-brand-100 text-brand-700 dark:bg-brand-500/20 dark:text-brand-300' },
|
||||||
green: { bg: 'bg-green-600 dark:bg-green-500', light: 'bg-green-100 text-green-700 dark:bg-green-500/20 dark:text-green-300' },
|
green: { bg: 'bg-success-600 dark:bg-success-500', light: 'bg-success-100 text-success-700 dark:bg-success-500/20 dark:text-success-300' },
|
||||||
purple: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
purple: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
orange: { bg: 'bg-orange-600 dark:bg-orange-500', light: 'bg-orange-100 text-orange-700 dark:bg-orange-500/20 dark:text-orange-300' },
|
orange: { bg: 'bg-warning-600 dark:bg-warning-500', light: 'bg-warning-100 text-warning-700 dark:bg-warning-500/20 dark:text-warning-300' },
|
||||||
red: { bg: 'bg-red-600 dark:bg-red-500', light: 'bg-red-100 text-red-700 dark:bg-red-500/20 dark:text-red-300' },
|
red: { bg: 'bg-error-600 dark:bg-error-500', light: 'bg-error-100 text-error-700 dark:bg-error-500/20 dark:text-error-300' },
|
||||||
indigo: { bg: 'bg-indigo-600 dark:bg-indigo-500', light: 'bg-indigo-100 text-indigo-700 dark:bg-indigo-500/20 dark:text-indigo-300' },
|
indigo: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
yellow: { bg: 'bg-yellow-600 dark:bg-yellow-500', light: 'bg-yellow-100 text-yellow-700 dark:bg-yellow-500/20 dark:text-yellow-300' },
|
yellow: { bg: 'bg-warning-600 dark:bg-warning-500', light: 'bg-warning-100 text-warning-700 dark:bg-warning-500/20 dark:text-warning-300' },
|
||||||
pink: { bg: 'bg-pink-600 dark:bg-pink-500', light: 'bg-pink-100 text-pink-700 dark:bg-pink-500/20 dark:text-pink-300' },
|
pink: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
emerald: { bg: 'bg-emerald-600 dark:bg-emerald-500', light: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-500/20 dark:text-emerald-300' },
|
emerald: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
cyan: { bg: 'bg-cyan-600 dark:bg-cyan-500', light: 'bg-cyan-100 text-cyan-700 dark:bg-cyan-500/20 dark:text-cyan-300' },
|
cyan: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
amber: { bg: 'bg-amber-600 dark:bg-amber-500', light: 'bg-amber-100 text-amber-700 dark:bg-amber-500/20 dark:text-amber-300' },
|
amber: { bg: 'bg-warning-600 dark:bg-warning-500', light: 'bg-warning-100 text-warning-700 dark:bg-warning-500/20 dark:text-warning-300' },
|
||||||
teal: { bg: 'bg-teal-600 dark:bg-teal-500', light: 'bg-teal-100 text-teal-700 dark:bg-teal-500/20 dark:text-teal-300' },
|
teal: { bg: 'bg-purple-600 dark:bg-purple-500', light: 'bg-purple-100 text-purple-700 dark:bg-purple-500/20 dark:text-purple-300' },
|
||||||
};
|
};
|
||||||
|
|
||||||
const AppHeader: React.FC = () => {
|
const AppHeader: React.FC = () => {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export default function SidebarWidget() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`
|
className={`
|
||||||
mx-auto mb-10 w-full max-w-60 rounded-2xl bg-blue-50 px-4 py-5 text-center dark:bg-blue-900/20`}
|
mx-auto mb-10 w-full max-w-60 rounded-2xl bg-brand-50 px-4 py-5 text-center dark:bg-brand-900/20`}
|
||||||
>
|
>
|
||||||
<ul className="space-y-1 text-sm text-gray-700 dark:text-gray-300">
|
<ul className="space-y-1 text-sm text-gray-700 dark:text-gray-300">
|
||||||
<li>Infinite.</li>
|
<li>Infinite.</li>
|
||||||
|
|||||||
@@ -56,16 +56,16 @@ const CTASection: React.FC<CTASectionProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="py-24 bg-gradient-to-b from-white via-slate-50 to-white">
|
<section className="py-24 bg-gradient-to-b from-white via-gray-50 to-white">
|
||||||
<div className="max-w-5xl mx-auto px-6">
|
<div className="max-w-5xl mx-auto px-6">
|
||||||
<div className="relative overflow-hidden rounded-3xl border-2 border-[var(--color-primary)]/20 bg-gradient-to-br from-[var(--color-primary)]/5 via-[var(--color-purple)]/5 to-[var(--color-success)]/5 p-10 md:p-14 shadow-xl">
|
<div className="relative overflow-hidden rounded-3xl border-2 border-[var(--color-primary)]/20 bg-gradient-to-br from-[var(--color-primary)]/5 via-[var(--color-purple)]/5 to-[var(--color-success)]/5 p-10 md:p-14 shadow-xl">
|
||||||
<div className="absolute inset-0 bg-gradient-to-r from-[var(--color-primary)]/10 via-transparent to-[var(--color-purple)]/10" />
|
<div className="absolute inset-0 bg-gradient-to-r from-[var(--color-primary)]/10 via-transparent to-[var(--color-purple)]/10" />
|
||||||
<div className="absolute -inset-1 bg-gradient-to-r from-[var(--color-primary)]/20 via-[var(--color-purple)]/20 to-[var(--color-success)]/20 rounded-3xl blur-xl -z-10 opacity-50" />
|
<div className="absolute -inset-1 bg-gradient-to-r from-[var(--color-primary)]/20 via-[var(--color-purple)]/20 to-[var(--color-success)]/20 rounded-3xl blur-xl -z-10 opacity-50" />
|
||||||
<div className="relative flex flex-col gap-6">
|
<div className="relative flex flex-col gap-6">
|
||||||
<h3 className="text-3xl md:text-4xl font-semibold text-slate-900 leading-tight">
|
<h3 className="text-3xl md:text-4xl font-semibold text-gray-900 leading-tight">
|
||||||
{title}
|
{title}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-slate-600 text-base md:text-lg max-w-2xl">
|
<p className="text-gray-600 text-base md:text-lg max-w-2xl">
|
||||||
{description}
|
{description}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col sm:flex-row gap-4">
|
<div className="flex flex-col sm:flex-row gap-4">
|
||||||
|
|||||||
@@ -28,19 +28,19 @@ const FeatureGrid: React.FC<FeatureGridProps> = ({ features }) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={feature.title}
|
key={feature.title}
|
||||||
className="relative rounded-3xl border-2 border-slate-200 bg-gradient-to-br from-white to-slate-50/50 p-8 flex flex-col gap-4 group hover:border-[#0693e3]/50 transition-all shadow-sm hover:shadow-xl hover:-translate-y-1"
|
className="relative rounded-3xl border-2 border-gray-200 bg-gradient-to-br from-white to-gray-50/50 p-8 flex flex-col gap-4 group hover:border-[var(--color-primary)]/50 transition-all shadow-sm hover:shadow-xl hover:-translate-y-1"
|
||||||
>
|
>
|
||||||
<div className={`size-12 rounded-2xl bg-gradient-to-br ${gradient} flex items-center justify-center text-white shadow-lg`}>
|
<div className={`size-12 rounded-2xl bg-gradient-to-br ${gradient} flex items-center justify-center text-white shadow-lg`}>
|
||||||
{feature.icon}
|
{feature.icon}
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-xl font-semibold text-slate-900">{feature.title}</h3>
|
<h3 className="text-xl font-semibold text-gray-900">{feature.title}</h3>
|
||||||
<p className="text-sm text-slate-600 leading-relaxed">
|
<p className="text-sm text-gray-600 leading-relaxed">
|
||||||
{feature.description}
|
{feature.description}
|
||||||
</p>
|
</p>
|
||||||
{feature.link && (
|
{feature.link && (
|
||||||
<a
|
<a
|
||||||
href={feature.link.href}
|
href={feature.link.href}
|
||||||
className="inline-flex items-center gap-2 text-sm font-semibold text-[#0693e3] hover:text-[#0472b8] group-hover:gap-3 transition-all"
|
className="inline-flex items-center gap-2 text-sm font-semibold text-[var(--color-primary)] hover:text-[var(--color-brand-700)] group-hover:gap-3 transition-all"
|
||||||
>
|
>
|
||||||
{feature.link.label}
|
{feature.link.label}
|
||||||
<ArrowUpRightIcon className="h-4 w-4" />
|
<ArrowUpRightIcon className="h-4 w-4" />
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ const HeroSection: React.FC<HeroSectionProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative overflow-hidden bg-gradient-to-br from-[#0d1b2a] via-[#142b3f] to-[#1a3a5a]">
|
<section className="relative overflow-hidden bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900">
|
||||||
<div className="absolute inset-0 bg-gradient-to-br from-[var(--color-primary)]/10 via-transparent to-[var(--color-purple)]/10" />
|
<div className="absolute inset-0 bg-gradient-to-br from-[var(--color-primary)]/10 via-transparent to-[var(--color-purple)]/10" />
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_30%_20%,rgba(6,147,227,0.15),transparent_50%)]" />
|
<div className="absolute inset-0 bg-[radial-gradient(circle_at_30%_20%,rgba(6,147,227,0.15),transparent_50%)]" />
|
||||||
<div className="relative max-w-6xl mx-auto px-6 py-24 md:py-32 flex flex-col lg:flex-row gap-16 items-center">
|
<div className="relative max-w-6xl mx-auto px-6 py-24 md:py-32 flex flex-col lg:flex-row gap-16 items-center">
|
||||||
@@ -74,7 +74,7 @@ const HeroSection: React.FC<HeroSectionProps> = ({
|
|||||||
<h1 className="text-4xl md:text-6xl font-semibold leading-tight text-white">
|
<h1 className="text-4xl md:text-6xl font-semibold leading-tight text-white">
|
||||||
{headline}
|
{headline}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-lg md:text-xl text-slate-300 leading-relaxed max-w-xl">
|
<p className="text-lg md:text-xl text-gray-300 leading-relaxed max-w-xl">
|
||||||
{subheadline}
|
{subheadline}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col sm:flex-row gap-4">
|
<div className="flex flex-col sm:flex-row gap-4">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from "react";
|
|||||||
|
|
||||||
const LoadingPage: React.FC = () => {
|
const LoadingPage: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex flex-col items-center justify-center bg-white text-slate-900">
|
<div className="min-h-screen flex flex-col items-center justify-center bg-white text-gray-900">
|
||||||
<div className="flex items-center gap-3 text-lg font-semibold tracking-wide uppercase">
|
<div className="flex items-center gap-3 text-lg font-semibold tracking-wide uppercase">
|
||||||
<span className="h-3 w-3 rounded-full bg-brand-500 animate-pulse" />
|
<span className="h-3 w-3 rounded-full bg-brand-500 animate-pulse" />
|
||||||
Loading experience…
|
Loading experience…
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const LogoCloud: React.FC = () => {
|
|||||||
<section className="py-12 bg-white">
|
<section className="py-12 bg-white">
|
||||||
<div className="max-w-6xl mx-auto px-6">
|
<div className="max-w-6xl mx-auto px-6">
|
||||||
<div className="flex flex-col gap-6 items-center">
|
<div className="flex flex-col gap-6 items-center">
|
||||||
<span className="text-xs uppercase tracking-[0.28em] text-slate-500 font-medium">
|
<span className="text-xs uppercase tracking-[0.28em] text-gray-500 font-medium">
|
||||||
Trusted by modern organic teams
|
Trusted by modern organic teams
|
||||||
</span>
|
</span>
|
||||||
<div className="flex flex-wrap justify-center gap-8 md:gap-12 items-center">
|
<div className="flex flex-wrap justify-center gap-8 md:gap-12 items-center">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const MetricsBar: React.FC<MetricsBarProps> = ({ metrics }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-5xl mx-auto -mt-12 sm:-mt-16 px-6">
|
<div className="max-w-5xl mx-auto -mt-12 sm:-mt-16 px-6">
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 rounded-2xl border-2 border-slate-200 bg-gradient-to-br from-white to-slate-50/50 shadow-xl p-6 backdrop-blur-sm">
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 rounded-2xl border-2 border-gray-200 bg-gradient-to-br from-white to-gray-50/50 shadow-xl p-6 backdrop-blur-sm">
|
||||||
{metrics.map((metric, index) => {
|
{metrics.map((metric, index) => {
|
||||||
const gradient = accentColors[index % accentColors.length];
|
const gradient = accentColors[index % accentColors.length];
|
||||||
return (
|
return (
|
||||||
@@ -28,7 +28,7 @@ const MetricsBar: React.FC<MetricsBarProps> = ({ metrics }) => {
|
|||||||
<div className={`text-3xl font-semibold bg-gradient-to-r ${gradient} bg-clip-text text-transparent`}>
|
<div className={`text-3xl font-semibold bg-gradient-to-r ${gradient} bg-clip-text text-transparent`}>
|
||||||
{metric.value}
|
{metric.value}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm uppercase tracking-[0.2em] text-slate-500 mt-2">
|
<div className="text-sm uppercase tracking-[0.2em] text-gray-500 mt-2">
|
||||||
{metric.label}
|
{metric.label}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ const SectionHeading: React.FC<SectionHeadingProps> = ({
|
|||||||
{eyebrow}
|
{eyebrow}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<h2 className="text-3xl md:text-4xl font-semibold text-slate-900 leading-tight max-w-3xl">
|
<h2 className="text-3xl md:text-4xl font-semibold text-gray-900 leading-tight max-w-3xl">
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
{description && (
|
{description && (
|
||||||
<p className="text-slate-600 max-w-2xl text-base md:text-lg leading-relaxed">
|
<p className="text-gray-600 max-w-2xl text-base md:text-lg leading-relaxed">
|
||||||
{description}
|
{description}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import { testimonials } from "../data/testimonials";
|
|||||||
|
|
||||||
const TestimonialSlider: React.FC = () => {
|
const TestimonialSlider: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<section className="bg-slate-50">
|
<section className="bg-gray-50">
|
||||||
<div className="max-w-6xl mx-auto px-6 py-24 space-y-12">
|
<div className="max-w-6xl mx-auto px-6 py-24 space-y-12">
|
||||||
<div className="flex flex-col items-center gap-4 text-center">
|
<div className="flex flex-col items-center gap-4 text-center">
|
||||||
<span className="inline-flex items-center rounded-full border border-brand-200 bg-brand-50 px-4 py-1 text-xs font-semibold uppercase tracking-[0.2em] text-brand-600">
|
<span className="inline-flex items-center rounded-full border border-brand-200 bg-brand-50 px-4 py-1 text-xs font-semibold uppercase tracking-[0.2em] text-brand-600">
|
||||||
Loved by scaling teams
|
Loved by scaling teams
|
||||||
</span>
|
</span>
|
||||||
<h2 className="text-3xl md:text-4xl font-semibold text-slate-900 leading-tight max-w-2xl">
|
<h2 className="text-3xl md:text-4xl font-semibold text-gray-900 leading-tight max-w-2xl">
|
||||||
Teams ship more content, capture more demand, and see faster ROI with Igny8.
|
Teams ship more content, capture more demand, and see faster ROI with Igny8.
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -17,14 +17,14 @@ const TestimonialSlider: React.FC = () => {
|
|||||||
{testimonials.map((testimonial) => (
|
{testimonials.map((testimonial) => (
|
||||||
<div
|
<div
|
||||||
key={testimonial.name}
|
key={testimonial.name}
|
||||||
className="rounded-3xl border border-slate-200 bg-white p-8 flex flex-col gap-6 relative overflow-hidden shadow-sm hover:shadow-md transition"
|
className="rounded-3xl border border-gray-200 bg-white p-8 flex flex-col gap-6 relative overflow-hidden shadow-sm hover:shadow-md transition"
|
||||||
>
|
>
|
||||||
<div className="absolute -top-16 left-1/2 -translate-x-1/2 h-32 w-[140%] rounded-[50%] bg-brand-100 blur-3xl pointer-events-none" />
|
<div className="absolute -top-16 left-1/2 -translate-x-1/2 h-32 w-[140%] rounded-[50%] bg-brand-100 blur-3xl pointer-events-none" />
|
||||||
<p className="text-base text-slate-700 leading-relaxed relative z-10">
|
<p className="text-base text-gray-700 leading-relaxed relative z-10">
|
||||||
"{testimonial.quote}"
|
"{testimonial.quote}"
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col text-sm text-slate-600 relative z-10">
|
<div className="flex flex-col text-sm text-gray-600 relative z-10">
|
||||||
<span className="font-semibold text-slate-900">{testimonial.name}</span>
|
<span className="font-semibold text-gray-900">{testimonial.name}</span>
|
||||||
<span>
|
<span>
|
||||||
{testimonial.title} · {testimonial.company}
|
{testimonial.title} · {testimonial.company}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -25,15 +25,15 @@ const WorkflowSteps: React.FC<WorkflowStepsProps> = ({ steps }) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={step.title}
|
key={step.title}
|
||||||
className="rounded-3xl border-2 border-slate-200 bg-gradient-to-br from-white to-slate-50/50 p-6 flex flex-col gap-4 hover:border-[var(--color-primary)]/50 transition-all shadow-sm hover:shadow-xl hover:-translate-y-1 group"
|
className="rounded-3xl border-2 border-gray-200 bg-gradient-to-br from-white to-gray-50/50 p-6 flex flex-col gap-4 hover:border-[var(--color-primary)]/50 transition-all shadow-sm hover:shadow-xl hover:-translate-y-1 group"
|
||||||
>
|
>
|
||||||
<div className={`h-12 w-12 rounded-2xl bg-gradient-to-br ${gradient} flex items-center justify-center font-semibold text-white text-xl shadow-lg`}>
|
<div className={`h-12 w-12 rounded-2xl bg-gradient-to-br ${gradient} flex items-center justify-center font-semibold text-white text-xl shadow-lg`}>
|
||||||
{index + 1}
|
{index + 1}
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-semibold text-slate-900 leading-snug group-hover:text-[var(--color-primary)] transition">
|
<h3 className="text-lg font-semibold text-gray-900 leading-snug group-hover:text-[var(--color-primary)] transition">
|
||||||
{step.title}
|
{step.title}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-slate-600 leading-relaxed">
|
<p className="text-sm text-gray-600 leading-relaxed">
|
||||||
{step.subtitle}
|
{step.subtitle}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,18 +15,18 @@ const MarketingLayout: React.FC<MarketingLayoutProps> = ({ children }) => {
|
|||||||
const closeMobile = () => setMobileOpen(false);
|
const closeMobile = () => setMobileOpen(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex flex-col bg-gradient-to-b from-white via-slate-50 to-white text-slate-900">
|
<div className="min-h-screen flex flex-col bg-gradient-to-b from-white via-gray-50 to-white text-gray-900">
|
||||||
<header className="sticky top-0 z-[1100] backdrop-blur-xl bg-white/95 border-b border-slate-200 shadow-sm">
|
<header className="sticky top-0 z-[1100] backdrop-blur-xl bg-white/95 border-b border-gray-200 shadow-sm">
|
||||||
<div className="max-w-6xl mx-auto px-6 py-4 flex items-center justify-between">
|
<div className="max-w-6xl mx-auto px-6 py-4 flex items-center justify-between">
|
||||||
<Link to="/" className="flex items-center gap-3" onClick={closeMobile}>
|
<Link to="/" className="flex items-center gap-3" onClick={closeMobile}>
|
||||||
<span className="h-10 w-10 rounded-xl bg-gradient-to-br from-[var(--color-primary)] to-[var(--color-primary-dark)] flex items-center justify-center text-lg font-bold text-white shadow-lg shadow-[var(--color-primary)]/30">
|
<span className="h-10 w-10 rounded-xl bg-gradient-to-br from-[var(--color-primary)] to-[var(--color-primary-dark)] flex items-center justify-center text-lg font-bold text-white shadow-lg shadow-[var(--color-primary)]/30">
|
||||||
IG
|
IG
|
||||||
</span>
|
</span>
|
||||||
<div className="flex flex-col leading-tight">
|
<div className="flex flex-col leading-tight">
|
||||||
<span className="font-semibold tracking-wide text-slate-900 uppercase">
|
<span className="font-semibold tracking-wide text-gray-900 uppercase">
|
||||||
Igny8
|
Igny8
|
||||||
</span>
|
</span>
|
||||||
<span className="text-xs text-slate-600">AI growth engine</span>
|
<span className="text-xs text-gray-600">AI growth engine</span>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ const MarketingLayout: React.FC<MarketingLayoutProps> = ({ children }) => {
|
|||||||
<Link
|
<Link
|
||||||
key={link.name}
|
key={link.name}
|
||||||
to={link.path}
|
to={link.path}
|
||||||
className={`transition hover:text-[var(--color-primary)] ${isActive ? "text-[var(--color-primary)] font-semibold" : "text-slate-700"}`}
|
className={`transition hover:text-[var(--color-primary)] ${isActive ? "text-[var(--color-primary)] font-semibold" : "text-gray-700"}`}
|
||||||
>
|
>
|
||||||
{link.name}
|
{link.name}
|
||||||
</Link>
|
</Link>
|
||||||
@@ -48,7 +48,7 @@ const MarketingLayout: React.FC<MarketingLayoutProps> = ({ children }) => {
|
|||||||
<div className="hidden lg:flex items-center gap-4">
|
<div className="hidden lg:flex items-center gap-4">
|
||||||
<a
|
<a
|
||||||
href="https://app.igny8.com/login"
|
href="https://app.igny8.com/login"
|
||||||
className="text-sm font-medium text-slate-700 hover:text-slate-900 transition"
|
className="text-sm font-medium text-gray-700 hover:text-gray-900 transition"
|
||||||
>
|
>
|
||||||
Log in
|
Log in
|
||||||
</a>
|
</a>
|
||||||
@@ -61,7 +61,7 @@ const MarketingLayout: React.FC<MarketingLayoutProps> = ({ children }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className="lg:hidden inline-flex items-center justify-center rounded-lg border border-slate-200 p-2 text-slate-700"
|
className="lg:hidden inline-flex items-center justify-center rounded-lg border border-gray-200 p-2 text-gray-700"
|
||||||
onClick={toggleMobile}
|
onClick={toggleMobile}
|
||||||
aria-label="Toggle navigation"
|
aria-label="Toggle navigation"
|
||||||
>
|
>
|
||||||
@@ -70,14 +70,14 @@ const MarketingLayout: React.FC<MarketingLayoutProps> = ({ children }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{mobileOpen && (
|
{mobileOpen && (
|
||||||
<div className="lg:hidden border-t border-slate-200 bg-white backdrop-blur-xl">
|
<div className="lg:hidden border-t border-gray-200 bg-white backdrop-blur-xl">
|
||||||
<nav className="px-6 py-4 flex flex-col gap-3">
|
<nav className="px-6 py-4 flex flex-col gap-3">
|
||||||
{primaryNav.map((link) => (
|
{primaryNav.map((link) => (
|
||||||
<Link
|
<Link
|
||||||
key={link.name}
|
key={link.name}
|
||||||
to={link.path}
|
to={link.path}
|
||||||
onClick={closeMobile}
|
onClick={closeMobile}
|
||||||
className="text-sm font-medium text-slate-700 hover:text-slate-900 transition"
|
className="text-sm font-medium text-gray-700 hover:text-gray-900 transition"
|
||||||
>
|
>
|
||||||
{link.name}
|
{link.name}
|
||||||
</Link>
|
</Link>
|
||||||
@@ -86,7 +86,7 @@ const MarketingLayout: React.FC<MarketingLayoutProps> = ({ children }) => {
|
|||||||
<div className="px-6 pb-6 flex flex-col gap-3">
|
<div className="px-6 pb-6 flex flex-col gap-3">
|
||||||
<a
|
<a
|
||||||
href="https://app.igny8.com/login"
|
href="https://app.igny8.com/login"
|
||||||
className="text-sm font-medium text-slate-700 hover:text-slate-900 transition"
|
className="text-sm font-medium text-gray-700 hover:text-gray-900 transition"
|
||||||
onClick={closeMobile}
|
onClick={closeMobile}
|
||||||
>
|
>
|
||||||
Log in
|
Log in
|
||||||
@@ -105,7 +105,7 @@ const MarketingLayout: React.FC<MarketingLayoutProps> = ({ children }) => {
|
|||||||
|
|
||||||
<main className="flex-1">{children}</main>
|
<main className="flex-1">{children}</main>
|
||||||
|
|
||||||
<footer className="bg-gradient-to-br from-[#0d1b2a] via-[#142b3f] to-[#0d1b2a] border-t border-[#0693e3]/20">
|
<footer className="bg-gradient-to-br from-[#0d1b2a] via-[#142b3f] to-[#0d1b2a] border-t border-[var(--color-primary)]/20">
|
||||||
<div className="max-w-6xl mx-auto px-6 py-16 grid grid-cols-1 md:grid-cols-4 gap-12">
|
<div className="max-w-6xl mx-auto px-6 py-16 grid grid-cols-1 md:grid-cols-4 gap-12">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<Link to="/" className="inline-flex items-center gap-3">
|
<Link to="/" className="inline-flex items-center gap-3">
|
||||||
@@ -116,15 +116,15 @@ const MarketingLayout: React.FC<MarketingLayoutProps> = ({ children }) => {
|
|||||||
<span className="font-semibold tracking-wide text-white uppercase">
|
<span className="font-semibold tracking-wide text-white uppercase">
|
||||||
Igny8
|
Igny8
|
||||||
</span>
|
</span>
|
||||||
<span className="text-xs text-slate-300">
|
<span className="text-xs text-gray-300">
|
||||||
AI + SEO automation suite
|
AI + SEO automation suite
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
<p className="text-sm text-slate-300 max-w-xs">
|
<p className="text-sm text-gray-300 max-w-xs">
|
||||||
Automate keyword intelligence, clustering, content production, and image creation in one unified growth engine.
|
Automate keyword intelligence, clustering, content production, and image creation in one unified growth engine.
|
||||||
</p>
|
</p>
|
||||||
<div className="text-xs text-slate-400">
|
<div className="text-xs text-gray-400">
|
||||||
© {new Date().getFullYear()} Igny8 Labs. All rights reserved.
|
© {new Date().getFullYear()} Igny8 Labs. All rights reserved.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,7 +134,7 @@ const MarketingLayout: React.FC<MarketingLayoutProps> = ({ children }) => {
|
|||||||
<h4 className="text-sm font-semibold text-white uppercase tracking-wide mb-4">
|
<h4 className="text-sm font-semibold text-white uppercase tracking-wide mb-4">
|
||||||
{group.title}
|
{group.title}
|
||||||
</h4>
|
</h4>
|
||||||
<ul className="space-y-3 text-sm text-slate-300">
|
<ul className="space-y-3 text-sm text-gray-300">
|
||||||
{group.links.map((link) => (
|
{group.links.map((link) => (
|
||||||
<li key={link.name}>
|
<li key={link.name}>
|
||||||
<Link to={link.path} className="hover:text-[var(--color-primary)] transition">
|
<Link to={link.path} className="hover:text-[var(--color-primary)] transition">
|
||||||
@@ -146,7 +146,7 @@ const MarketingLayout: React.FC<MarketingLayoutProps> = ({ children }) => {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="border-t border-[var(--color-primary)]/20 py-6 px-6 text-center text-xs text-slate-400">
|
<div className="border-t border-[var(--color-primary)]/20 py-6 px-6 text-center text-xs text-gray-400">
|
||||||
Built for marketers who automate growth with AI.
|
Built for marketers who automate growth with AI.
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -80,17 +80,17 @@ const CaseStudies: React.FC = () => {
|
|||||||
<SEO meta={getMetaTags("caseStudies")} />
|
<SEO meta={getMetaTags("caseStudies")} />
|
||||||
<div className="bg-white">
|
<div className="bg-white">
|
||||||
{/* HERO SECTION */}
|
{/* HERO SECTION */}
|
||||||
<section className="relative overflow-hidden bg-gradient-to-b from-white via-slate-50/50 to-white">
|
<section className="relative overflow-hidden bg-gradient-to-b from-white via-gray-50/50 to-white">
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_50%,rgba(6,147,227,0.03),transparent_60%)]" />
|
<div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_50%,rgba(6,147,227,0.03),transparent_60%)]" />
|
||||||
|
|
||||||
<div className="relative max-w-4xl mx-auto px-6 py-24 md:py-32 text-center z-10">
|
<div className="relative max-w-4xl mx-auto px-6 py-24 md:py-32 text-center z-10">
|
||||||
<span className="inline-flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.28em] text-slate-500 bg-slate-100 px-4 py-2 rounded-full mb-6">
|
<span className="inline-flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.28em] text-gray-500 bg-gray-100 px-4 py-2 rounded-full mb-6">
|
||||||
Case Studies
|
Case Studies
|
||||||
</span>
|
</span>
|
||||||
<h1 className="text-5xl md:text-6xl lg:text-5xl font-bold leading-tight text-slate-900 mb-6">
|
<h1 className="text-5xl md:text-6xl lg:text-5xl font-bold leading-tight text-gray-900 mb-6">
|
||||||
Stories from teams automating their way to category leadership.
|
Stories from teams automating their way to category leadership.
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xl md:text-2xl text-slate-600 mb-10 max-w-2xl mx-auto leading-relaxed">
|
<p className="text-xl md:text-2xl text-gray-600 mb-10 max-w-2xl mx-auto leading-relaxed">
|
||||||
See how publishers, agencies, and SaaS companies transformed their SEO and content operations with Igny8.
|
See how publishers, agencies, and SaaS companies transformed their SEO and content operations with Igny8.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -100,26 +100,26 @@ const CaseStudies: React.FC = () => {
|
|||||||
<section className="max-w-7xl mx-auto px-6 pb-24 space-y-16">
|
<section className="max-w-7xl mx-auto px-6 pb-24 space-y-16">
|
||||||
{caseStudies.map((cs, idx) => {
|
{caseStudies.map((cs, idx) => {
|
||||||
const metricColors = [
|
const metricColors = [
|
||||||
{ border: "border-slate-200", bg: "from-white to-slate-50/50", text: "text-[var(--color-primary)]" },
|
{ border: "border-gray-200", bg: "from-white to-gray-50/50", text: "text-[var(--color-primary)]" },
|
||||||
{ border: "border-slate-200", bg: "from-white to-slate-50/50", text: "text-[#0bbf87]" },
|
{ border: "border-gray-200", bg: "from-white to-gray-50/50", text: "text-[var(--color-success)]" },
|
||||||
{ border: "border-slate-200", bg: "from-white to-slate-50/50", text: "text-[#ff7a00]" },
|
{ border: "border-gray-200", bg: "from-white to-gray-50/50", text: "text-[var(--color-warning)]" },
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={cs.company}
|
key={cs.company}
|
||||||
className="rounded-3xl border-2 border-slate-200 bg-white p-10 md:p-12 grid grid-cols-1 lg:grid-cols-2 gap-12 hover:shadow-xl hover:-translate-y-1 transition-all"
|
className="rounded-3xl border-2 border-gray-200 bg-white p-10 md:p-12 grid grid-cols-1 lg:grid-cols-2 gap-12 hover:shadow-xl hover:-translate-y-1 transition-all"
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className={`size-12 rounded-xl bg-gradient-to-br ${cs.iconColor} flex items-center justify-center text-white shadow-lg`}>
|
<div className={`size-12 rounded-xl bg-gradient-to-br ${cs.iconColor} flex items-center justify-center text-white shadow-lg`}>
|
||||||
<CheckCircleIcon className="h-6 w-6" />
|
<CheckCircleIcon className="h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
<span className="inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold uppercase tracking-[0.2em] bg-slate-100 text-slate-600">
|
<span className="inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold uppercase tracking-[0.2em] bg-gray-100 text-gray-600">
|
||||||
{cs.company}
|
{cs.company}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-3xl md:text-4xl font-bold text-slate-900">{cs.headline}</h3>
|
<h3 className="text-3xl md:text-4xl font-bold text-gray-900">{cs.headline}</h3>
|
||||||
<p className="text-base text-slate-600 leading-relaxed">{cs.summary}</p>
|
<p className="text-base text-gray-600 leading-relaxed">{cs.summary}</p>
|
||||||
<div className="grid grid-cols-3 gap-4 pt-4">
|
<div className="grid grid-cols-3 gap-4 pt-4">
|
||||||
{cs.metrics.map((metric, metricIdx) => {
|
{cs.metrics.map((metric, metricIdx) => {
|
||||||
const metricColor = metricColors[metricIdx % metricColors.length];
|
const metricColor = metricColors[metricIdx % metricColors.length];
|
||||||
@@ -131,7 +131,7 @@ const CaseStudies: React.FC = () => {
|
|||||||
<div className={`text-2xl md:text-3xl font-bold ${metricColor.text}`}>
|
<div className={`text-2xl md:text-3xl font-bold ${metricColor.text}`}>
|
||||||
{metric.value}
|
{metric.value}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-600 font-semibold">
|
<div className="text-xs uppercase tracking-[0.2em] text-gray-600 font-semibold">
|
||||||
{metric.label}
|
{metric.label}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -140,7 +140,7 @@ const CaseStudies: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="rounded-3xl border-2 border-slate-200 bg-gradient-to-br from-slate-50 to-white overflow-hidden shadow-lg">
|
<div className="rounded-3xl border-2 border-gray-200 bg-gradient-to-br from-gray-50 to-white overflow-hidden shadow-lg">
|
||||||
<img
|
<img
|
||||||
src={`/marketing/images/${cs.image}`}
|
src={`/marketing/images/${cs.image}`}
|
||||||
alt={`${cs.company} case study`}
|
alt={`${cs.company} case study`}
|
||||||
@@ -154,22 +154,22 @@ const CaseStudies: React.FC = () => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* RESULTS & ADVISORY BOARD */}
|
{/* RESULTS & ADVISORY BOARD */}
|
||||||
<section className="bg-gradient-to-b from-white via-slate-50/30 to-white py-24">
|
<section className="bg-gradient-to-b from-white via-gray-50/30 to-white py-24">
|
||||||
<div className="max-w-7xl mx-auto px-6 grid grid-cols-1 lg:grid-cols-2 gap-8">
|
<div className="max-w-7xl mx-auto px-6 grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||||
<div className="rounded-2xl border-2 border-slate-200 bg-white p-8 space-y-6 shadow-sm">
|
<div className="rounded-2xl border-2 border-gray-200 bg-white p-8 space-y-6 shadow-sm">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="size-12 rounded-xl bg-gradient-to-br from-[var(--color-primary)] to-[var(--color-primary-dark)] flex items-center justify-center text-white shadow-lg">
|
<div className="size-12 rounded-xl bg-gradient-to-br from-[var(--color-primary)] to-[var(--color-primary-dark)] flex items-center justify-center text-white shadow-lg">
|
||||||
<CheckCircleIcon className="h-6 w-6" />
|
<CheckCircleIcon className="h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-2xl font-bold text-slate-900">
|
<h4 className="text-2xl font-bold text-gray-900">
|
||||||
Results you can expect
|
Results you can expect
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<ul className="space-y-4 text-sm text-slate-700">
|
<ul className="space-y-4 text-sm text-gray-700">
|
||||||
{[
|
{[
|
||||||
{ text: "30-60 day onboarding to deploy automation and Thinker governance.", color: "bg-[#0693e3]" },
|
{ text: "30-60 day onboarding to deploy automation and Thinker governance.", color: "bg-[var(--color-primary)]" },
|
||||||
{ text: "3-5× increase in content throughput without sacrificing editorial quality.", color: "bg-[#0bbf87]" },
|
{ text: "3-5× increase in content throughput without sacrificing editorial quality.", color: "bg-[var(--color-success)]" },
|
||||||
{ text: "Clear ROI dashboards tying automation to revenue outcomes.", color: "bg-[#ff7a00]" },
|
{ text: "Clear ROI dashboards tying automation to revenue outcomes.", color: "bg-[var(--color-warning)]" },
|
||||||
].map((item, index) => (
|
].map((item, index) => (
|
||||||
<li key={item.text} className="flex gap-3">
|
<li key={item.text} className="flex gap-3">
|
||||||
<span className={`mt-1.5 size-2 rounded-full ${item.color} shadow-sm flex-shrink-0`} />
|
<span className={`mt-1.5 size-2 rounded-full ${item.color} shadow-sm flex-shrink-0`} />
|
||||||
@@ -178,16 +178,16 @@ const CaseStudies: React.FC = () => {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-2xl border-2 border-slate-200 bg-white p-8 space-y-6 shadow-sm">
|
<div className="rounded-2xl border-2 border-gray-200 bg-white p-8 space-y-6 shadow-sm">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="size-12 rounded-xl bg-gradient-to-br from-[var(--color-success)] to-[var(--color-success-dark)] flex items-center justify-center text-white shadow-lg">
|
<div className="size-12 rounded-xl bg-gradient-to-br from-[var(--color-success)] to-[var(--color-success-dark)] flex items-center justify-center text-white shadow-lg">
|
||||||
<CheckCircleIcon className="h-6 w-6" />
|
<CheckCircleIcon className="h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-2xl font-bold text-slate-900">
|
<h4 className="text-2xl font-bold text-gray-900">
|
||||||
Customer advisory board
|
Customer advisory board
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-base text-slate-700 leading-relaxed">
|
<p className="text-base text-gray-700 leading-relaxed">
|
||||||
Igny8's roadmap is shaped by an active community of customer strategists, agency partners, and product marketers. Join and get early access to features, template libraries, and industry benchmarks.
|
Igny8's roadmap is shaped by an active community of customer strategists, agency partners, and product marketers. Join and get early access to features, template libraries, and industry benchmarks.
|
||||||
</p>
|
</p>
|
||||||
<button className="inline-flex items-center justify-center gap-2 rounded-xl bg-gradient-to-r from-[var(--color-primary)] to-[var(--color-primary-dark)] text-white px-6 py-3 text-sm font-semibold hover:shadow-lg transition">
|
<button className="inline-flex items-center justify-center gap-2 rounded-xl bg-gradient-to-r from-[var(--color-primary)] to-[var(--color-primary-dark)] text-white px-6 py-3 text-sm font-semibold hover:shadow-lg transition">
|
||||||
@@ -199,7 +199,7 @@ const CaseStudies: React.FC = () => {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* FINAL CTA */}
|
{/* FINAL CTA */}
|
||||||
<section className="relative overflow-hidden bg-gradient-to-br from-[#0693e3] via-[#5d4ae3] to-[#8b5cf6]">
|
<section className="relative overflow-hidden bg-gradient-to-br from-[var(--color-primary)] via-[var(--color-purple)] to-[var(--color-purple-400)]">
|
||||||
{/* Radial glow */}
|
{/* Radial glow */}
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_50%,rgba(255,255,255,0.1),transparent_70%)]" />
|
<div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_50%,rgba(255,255,255,0.1),transparent_70%)]" />
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const Contact: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SEO meta={getMetaTags("contact")} />
|
<SEO meta={getMetaTags("contact")} />
|
||||||
<div className="bg-gradient-to-b from-white via-slate-50/30 to-white text-slate-900">
|
<div className="bg-gradient-to-b from-white via-gray-50/30 to-white text-gray-900">
|
||||||
<section className="max-w-4xl mx-auto px-6 pt-24 pb-12">
|
<section className="max-w-4xl mx-auto px-6 pt-24 pb-12">
|
||||||
<SectionHeading
|
<SectionHeading
|
||||||
eyebrow="Contact"
|
eyebrow="Contact"
|
||||||
@@ -20,87 +20,87 @@ const Contact: React.FC = () => {
|
|||||||
<section className="max-w-5xl mx-auto px-6 pb-24 grid grid-cols-1 lg:grid-cols-2 gap-12">
|
<section className="max-w-5xl mx-auto px-6 pb-24 grid grid-cols-1 lg:grid-cols-2 gap-12">
|
||||||
<form className="rounded-3xl border-2 border-[var(--color-primary)]/30 bg-gradient-to-br from-[var(--color-primary)]/10 via-white to-[var(--color-success)]/5 p-10 space-y-6 shadow-lg">
|
<form className="rounded-3xl border-2 border-[var(--color-primary)]/30 bg-gradient-to-br from-[var(--color-primary)]/10 via-white to-[var(--color-success)]/5 p-10 space-y-6 shadow-lg">
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<label className="flex flex-col gap-2 text-sm text-slate-600">
|
<label className="flex flex-col gap-2 text-sm text-gray-600">
|
||||||
First name
|
First name
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Alex"
|
placeholder="Alex"
|
||||||
className="rounded-xl border-2 border-slate-200 bg-white px-4 py-3 text-sm text-slate-900 placeholder:text-slate-500 focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/20"
|
className="rounded-xl border-2 border-gray-200 bg-white px-4 py-3 text-sm text-gray-900 placeholder:text-gray-500 focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/20"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label className="flex flex-col gap-2 text-sm text-slate-600">
|
<label className="flex flex-col gap-2 text-sm text-gray-600">
|
||||||
Last name
|
Last name
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Rivera"
|
placeholder="Rivera"
|
||||||
className="rounded-xl border-2 border-slate-200 bg-white px-4 py-3 text-sm text-slate-900 placeholder:text-slate-500 focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/20"
|
className="rounded-xl border-2 border-gray-200 bg-white px-4 py-3 text-sm text-gray-900 placeholder:text-gray-500 focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/20"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label className="flex flex-col gap-2 text-sm text-slate-600">
|
<label className="flex flex-col gap-2 text-sm text-gray-600">
|
||||||
Work email
|
Work email
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
placeholder="you@company.com"
|
placeholder="you@company.com"
|
||||||
className="rounded-xl border-2 border-slate-200 bg-white px-4 py-3 text-sm text-slate-900 placeholder:text-slate-500 focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/20"
|
className="rounded-xl border-2 border-gray-200 bg-white px-4 py-3 text-sm text-gray-900 placeholder:text-gray-500 focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/20"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="flex flex-col gap-2 text-sm text-slate-600">
|
<label className="flex flex-col gap-2 text-sm text-gray-600">
|
||||||
Company
|
Company
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Company name"
|
placeholder="Company name"
|
||||||
className="rounded-xl border-2 border-slate-200 bg-white px-4 py-3 text-sm text-slate-900 placeholder:text-slate-500 focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/20"
|
className="rounded-xl border-2 border-gray-200 bg-white px-4 py-3 text-sm text-gray-900 placeholder:text-gray-500 focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/20"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label className="flex flex-col gap-2 text-sm text-slate-600">
|
<label className="flex flex-col gap-2 text-sm text-gray-600">
|
||||||
How can we help?
|
How can we help?
|
||||||
<textarea
|
<textarea
|
||||||
rows={4}
|
rows={4}
|
||||||
placeholder="Tell us about your current workflow, challenges, and goals."
|
placeholder="Tell us about your current workflow, challenges, and goals."
|
||||||
className="rounded-xl border-2 border-slate-200 bg-white px-4 py-3 text-sm text-slate-900 placeholder:text-slate-500 focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/20 resize-none"
|
className="rounded-xl border-2 border-gray-200 bg-white px-4 py-3 text-sm text-gray-900 placeholder:text-gray-500 focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/20 resize-none"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="inline-flex items-center justify-center rounded-full bg-gradient-to-r from-[#0693e3] to-[#0472b8] hover:from-[#0472b8] hover:to-[#0693e3] text-white px-6 py-3 text-sm font-semibold shadow-lg shadow-[#0693e3]/30 transition-all w-full"
|
className="inline-flex items-center justify-center rounded-full bg-gradient-to-r from-[var(--color-primary)] to-[var(--color-brand-700)] hover:from-[var(--color-brand-700)] hover:to-[var(--color-primary)] text-white px-6 py-3 text-sm font-semibold shadow-lg shadow-[var(--color-primary)]/30 transition-all w-full"
|
||||||
>
|
>
|
||||||
Book strategy call
|
Book strategy call
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
<div className="rounded-3xl border-2 border-[#0bbf87]/30 bg-gradient-to-br from-[#0bbf87]/10 to-white p-8 space-y-4 text-sm text-slate-600">
|
<div className="rounded-3xl border-2 border-[var(--color-success)]/30 bg-gradient-to-br from-[var(--color-success)]/10 to-white p-8 space-y-4 text-sm text-gray-600">
|
||||||
<h3 className="text-lg font-semibold text-slate-900 flex items-center gap-2">
|
<h3 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
|
||||||
<span className="size-2 rounded-full bg-[#0bbf87]"></span>
|
<span className="size-2 rounded-full bg-[var(--color-success)]"></span>
|
||||||
Calendly placeholder
|
Calendly placeholder
|
||||||
</h3>
|
</h3>
|
||||||
<div className="aspect-[4/3] rounded-2xl border-2 border-slate-200 bg-gradient-to-br from-slate-50 to-white flex items-center justify-center text-xs text-slate-500 shadow-inner">
|
<div className="aspect-[4/3] rounded-2xl border-2 border-gray-200 bg-gradient-to-br from-gray-50 to-white flex items-center justify-center text-xs text-gray-500 shadow-inner">
|
||||||
Embed Calendly iframe here
|
Embed Calendly iframe here
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
Prefer async? Email us at{" "}
|
Prefer async? Email us at{" "}
|
||||||
<a href="mailto:hello@igny8.com" className="text-[#0693e3] hover:text-[#0472b8] font-semibold">
|
<a href="mailto:hello@igny8.com" className="text-[var(--color-primary)] hover:text-[var(--color-brand-700)] font-semibold">
|
||||||
hello@igny8.com
|
hello@igny8.com
|
||||||
</a>{" "}
|
</a>{" "}
|
||||||
or join our community Slack.
|
or join our community Slack.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="rounded-3xl border-2 border-[#ff7a00]/30 bg-gradient-to-br from-[#ff7a00]/10 to-white p-8 space-y-4">
|
<div className="rounded-3xl border-2 border-[var(--color-warning)]/30 bg-gradient-to-br from-[var(--color-warning)]/10 to-white p-8 space-y-4">
|
||||||
<h3 className="text-lg font-semibold text-slate-900 flex items-center gap-2">
|
<h3 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
|
||||||
<span className="size-2 rounded-full bg-[#ff7a00]"></span>
|
<span className="size-2 rounded-full bg-[var(--color-warning)]"></span>
|
||||||
Support perks
|
Support perks
|
||||||
</h3>
|
</h3>
|
||||||
<ul className="space-y-3 text-sm text-slate-600">
|
<ul className="space-y-3 text-sm text-gray-600">
|
||||||
{[
|
{[
|
||||||
{ text: "24-hour response time on all Launch+ plans.", color: "bg-[#0693e3]" },
|
{ text: "24-hour response time on all Launch+ plans.", color: "bg-[var(--color-primary)]" },
|
||||||
{ text: "Dedicated success architect for Scale and Enterprise.", color: "bg-[#0bbf87]" },
|
{ text: "Dedicated success architect for Scale and Enterprise.", color: "bg-[var(--color-success)]" },
|
||||||
{ text: "Migration services when replacing legacy content stacks.", color: "bg-[#ff7a00]" },
|
{ text: "Migration services when replacing legacy content stacks.", color: "bg-[var(--color-warning)]" },
|
||||||
].map((item) => (
|
].map((item) => (
|
||||||
<li key={item.text} className="flex gap-3">
|
<li key={item.text} className="flex gap-3">
|
||||||
<span className={`mt-1 size-1.5 rounded-full ${item.color} shadow-sm`} />
|
<span className={`mt-1 size-1.5 rounded-full ${item.color} shadow-sm`} />
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user