ALwrity LinkedIn Writer: Billing Dashboard: Compact View, Billing Overview, System Health Indicator, Cost Breakdown, Usage Trends, Usage Alerts, Comprehensive API Breakdown
This commit is contained in:
@@ -32,6 +32,7 @@ import AnalyzePillarChips from './components/AnalyzePillarChips';
|
||||
import EngagePillarChips from './components/EngagePillarChips';
|
||||
import EnhancedTodayChip from './components/EnhancedTodayChip';
|
||||
import OnboardingModal from './components/OnboardingModal';
|
||||
import WorkflowHeroSection from './components/WorkflowHeroSection';
|
||||
import { pillarData } from './components/PillarData';
|
||||
import { useWorkflowStore } from '../../stores/workflowStore';
|
||||
|
||||
@@ -487,6 +488,14 @@ const ContentLifecyclePillars: React.FC = () => {
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const [onboardingModalOpen, setOnboardingModalOpen] = useState(false);
|
||||
|
||||
// Workflow store hooks
|
||||
const {
|
||||
currentWorkflow,
|
||||
workflowProgress,
|
||||
isLoading: workflowLoading,
|
||||
startWorkflow,
|
||||
} = useWorkflowStore();
|
||||
|
||||
const handleOnboardingClick = () => {
|
||||
setOnboardingModalOpen(true);
|
||||
};
|
||||
@@ -495,6 +504,20 @@ const ContentLifecyclePillars: React.FC = () => {
|
||||
setOnboardingModalOpen(false);
|
||||
};
|
||||
|
||||
const handleStartWorkflow = async () => {
|
||||
try {
|
||||
if (currentWorkflow) {
|
||||
await startWorkflow(currentWorkflow.id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to start workflow:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Check if workflow is active (in progress or completed)
|
||||
const isWorkflowActive = currentWorkflow?.workflowStatus === 'in_progress' ||
|
||||
currentWorkflow?.workflowStatus === 'completed';
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
@@ -503,7 +526,8 @@ const ContentLifecyclePillars: React.FC = () => {
|
||||
background: 'linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)',
|
||||
backdropFilter: 'blur(8px)',
|
||||
borderRadius: 2,
|
||||
mb: 4
|
||||
mb: 4,
|
||||
position: 'relative', // For hero section positioning
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="xl">
|
||||
@@ -530,6 +554,13 @@ const ContentLifecyclePillars: React.FC = () => {
|
||||
))}
|
||||
</Box>
|
||||
</Container>
|
||||
|
||||
{/* Hero Section Overlay */}
|
||||
<WorkflowHeroSection
|
||||
onStartWorkflow={handleStartWorkflow}
|
||||
isWorkflowActive={isWorkflowActive}
|
||||
isLoading={workflowLoading}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Onboarding Modal */}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Container,
|
||||
@@ -24,6 +24,8 @@ import EmptyState from '../shared/EmptyState';
|
||||
import ContentLifecyclePillars from './ContentLifecyclePillars';
|
||||
import AnalyticsInsights from './components/AnalyticsInsights';
|
||||
import ToolsModal from './components/ToolsModal';
|
||||
import EnhancedBillingDashboard from '../billing/EnhancedBillingDashboard';
|
||||
import CompactSidebar from './components/CompactSidebar';
|
||||
|
||||
// Shared types and utilities
|
||||
import { Tool } from '../shared/types';
|
||||
@@ -41,6 +43,9 @@ const MainDashboard: React.FC = () => {
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Sidebar state
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(true);
|
||||
|
||||
// Zustand store hooks
|
||||
const {
|
||||
loading,
|
||||
@@ -272,7 +277,13 @@ const MainDashboard: React.FC = () => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="xl" sx={{ position: 'relative', zIndex: 1 }}>
|
||||
<Container
|
||||
maxWidth="xl"
|
||||
sx={{
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<AnimatePresence>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
@@ -302,22 +313,39 @@ const MainDashboard: React.FC = () => {
|
||||
{/* Content Lifecycle Pillars - First Panel */}
|
||||
<ContentLifecyclePillars />
|
||||
|
||||
{/* Search and Filter */}
|
||||
<SearchFilter
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
onClearSearch={() => setSearchQuery('')}
|
||||
selectedCategory={selectedCategory}
|
||||
onCategoryChange={setSelectedCategory}
|
||||
selectedSubCategory={selectedSubCategory}
|
||||
onSubCategoryChange={setSelectedSubCategory}
|
||||
toolCategories={toolCategories}
|
||||
theme={theme}
|
||||
onCategoryClick={handleCategoryClick}
|
||||
/>
|
||||
{/* Side-by-side layout for Areas 2 and 3 */}
|
||||
<Box sx={{ display: 'flex', gap: 3, mt: 3 }}>
|
||||
{/* Area 2: Search Tools Sidebar */}
|
||||
<Box sx={{
|
||||
width: sidebarCollapsed ? 60 : 280,
|
||||
transition: 'width 0.3s ease-in-out',
|
||||
flexShrink: 0
|
||||
}}>
|
||||
<CompactSidebar
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
onClearSearch={() => setSearchQuery('')}
|
||||
selectedCategory={selectedCategory}
|
||||
onCategoryChange={setSelectedCategory}
|
||||
selectedSubCategory={selectedSubCategory}
|
||||
onSubCategoryChange={setSelectedSubCategory}
|
||||
toolCategories={toolCategories}
|
||||
onCategoryClick={handleCategoryClick}
|
||||
collapsed={sidebarCollapsed}
|
||||
onToggleCollapse={() => setSidebarCollapsed(!sidebarCollapsed)}
|
||||
theme={theme}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Analytics Insights - Good/Bad/Ugly */}
|
||||
<AnalyticsInsights />
|
||||
{/* Area 3: Analytics and Billing */}
|
||||
<Box sx={{ flex: 1, minWidth: 0 }}>
|
||||
{/* Analytics Insights - Good/Bad/Ugly */}
|
||||
<AnalyticsInsights />
|
||||
|
||||
{/* Billing & Usage Dashboard */}
|
||||
<EnhancedBillingDashboard />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Tools Modal */}
|
||||
<ToolsModal
|
||||
|
||||
@@ -263,7 +263,7 @@ const AnalyticsInsights: React.FC<AnalyticsInsightsProps> = ({ data, onActionCli
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ mt: 2, mb: 2.9 }}>
|
||||
<Box sx={{ mt: 1, mb: 1.5 }}>
|
||||
<Box sx={{ position: 'relative', overflow: 'hidden' }}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
@@ -277,7 +277,7 @@ const AnalyticsInsights: React.FC<AnalyticsInsightsProps> = ({ data, onActionCli
|
||||
Today's Analytics Insights
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack direction={{ xs: 'column', md: 'row' }} spacing={1.5}>
|
||||
<Stack direction={{ xs: 'column', md: 'row' }} spacing={1}>
|
||||
{columns.map((col) => {
|
||||
const isHovered = hovered === col.key;
|
||||
const visibleItems = isHovered ? col.items : col.items.slice(0, 1);
|
||||
@@ -291,16 +291,16 @@ const AnalyticsInsights: React.FC<AnalyticsInsightsProps> = ({ data, onActionCli
|
||||
<Badge>{col.items.length}</Badge>
|
||||
</GradientHeader>
|
||||
|
||||
<CardContent sx={{ p: 1.5 }}>
|
||||
<Stack spacing={1}>
|
||||
<CardContent sx={{ p: 1, '&:last-child': { pb: 1 } }}>
|
||||
<Stack spacing={0.5}>
|
||||
{visibleItems.map((insight) => (
|
||||
<Box key={insight.id} sx={{
|
||||
background: 'rgba(255,255,255,0.08)',
|
||||
border: '1px solid rgba(255,255,255,0.18)',
|
||||
borderRadius: 1.5,
|
||||
p: 1
|
||||
p: 0.8
|
||||
}}>
|
||||
<Stack direction="row" spacing={0.5} alignItems="center" sx={{ mb: 0.25 }}>
|
||||
<Stack direction="row" spacing={0.5} alignItems="center" sx={{ mb: 0.1 }}>
|
||||
<Typography variant="body2" sx={{ color: 'rgba(255,255,255,0.95)', fontWeight: 700, fontSize: '0.8rem' }}>
|
||||
{insight.title}
|
||||
</Typography>
|
||||
|
||||
@@ -0,0 +1,685 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Paper,
|
||||
Typography,
|
||||
Chip,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
Divider,
|
||||
} from '@mui/material';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
Search,
|
||||
Filter,
|
||||
Settings,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Activity,
|
||||
Zap
|
||||
} from 'lucide-react';
|
||||
|
||||
// Shared components
|
||||
import SearchFilter from '../../shared/SearchFilter';
|
||||
|
||||
// Types
|
||||
import { ToolCategories } from '../../shared/types';
|
||||
|
||||
interface CompactSidebarProps {
|
||||
searchQuery: string;
|
||||
onSearchChange: (query: string) => void;
|
||||
onClearSearch: () => void;
|
||||
selectedCategory: string | null;
|
||||
onCategoryChange: (category: string | null) => void;
|
||||
selectedSubCategory: string | null;
|
||||
onSubCategoryChange: (subCategory: string | null) => void;
|
||||
toolCategories: ToolCategories;
|
||||
onCategoryClick: (categoryName: string | null, categoryData?: any) => void;
|
||||
collapsed: boolean;
|
||||
onToggleCollapse: () => void;
|
||||
theme: any;
|
||||
}
|
||||
|
||||
// Session control for animation
|
||||
const SIDEBAR_ANIMATION_KEY = 'sidebar_animation_shown';
|
||||
const ANIMATION_COOLDOWN = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
|
||||
|
||||
const shouldShowAnimation = (): boolean => {
|
||||
const lastShown = localStorage.getItem(SIDEBAR_ANIMATION_KEY);
|
||||
if (!lastShown) return true;
|
||||
|
||||
const lastShownTime = parseInt(lastShown, 10);
|
||||
const now = Date.now();
|
||||
return (now - lastShownTime) > ANIMATION_COOLDOWN;
|
||||
};
|
||||
|
||||
const markAnimationShown = (): void => {
|
||||
localStorage.setItem(SIDEBAR_ANIMATION_KEY, Date.now().toString());
|
||||
};
|
||||
|
||||
const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
||||
searchQuery,
|
||||
onSearchChange,
|
||||
onClearSearch,
|
||||
selectedCategory,
|
||||
onCategoryChange,
|
||||
selectedSubCategory,
|
||||
onSubCategoryChange,
|
||||
toolCategories,
|
||||
onCategoryClick,
|
||||
collapsed,
|
||||
onToggleCollapse,
|
||||
theme
|
||||
}) => {
|
||||
const [isAnimating, setIsAnimating] = useState(false);
|
||||
const [rippleIndex, setRippleIndex] = useState(-1);
|
||||
const [shouldAutoExpand, setShouldAutoExpand] = useState(false);
|
||||
const [userHasInteracted, setUserHasInteracted] = useState(false);
|
||||
|
||||
// Calculate total tools count
|
||||
const totalTools = Object.values(toolCategories).reduce((sum, category) => {
|
||||
if ('tools' in category) {
|
||||
return sum + category.tools.length;
|
||||
} else if ('subCategories' in category) {
|
||||
return sum + Object.values(category.subCategories).reduce((subSum, subCat) => subSum + subCat.tools.length, 0);
|
||||
}
|
||||
return sum;
|
||||
}, 0);
|
||||
|
||||
// Ripple effect for chips
|
||||
const startRippleEffect = useCallback(() => {
|
||||
const categoryEntries = Object.entries(toolCategories).slice(0, 5);
|
||||
categoryEntries.forEach((_, index) => {
|
||||
setTimeout(() => {
|
||||
setRippleIndex(index);
|
||||
// Reset ripple after animation
|
||||
setTimeout(() => setRippleIndex(-1), 1000);
|
||||
}, index * 200); // 200ms delay between each chip
|
||||
});
|
||||
}, [toolCategories]);
|
||||
|
||||
// Check if we should show the animation on mount (only once)
|
||||
useEffect(() => {
|
||||
if (shouldShowAnimation() && collapsed && !userHasInteracted) {
|
||||
setShouldAutoExpand(true);
|
||||
setIsAnimating(true);
|
||||
markAnimationShown();
|
||||
}
|
||||
}, []); // Empty dependency array - only run once on mount
|
||||
|
||||
// Handle auto-expand animation
|
||||
useEffect(() => {
|
||||
if (shouldAutoExpand && collapsed && !userHasInteracted) {
|
||||
// Auto-expand after a short delay
|
||||
const expandTimer = setTimeout(() => {
|
||||
onToggleCollapse(); // Expand the sidebar
|
||||
}, 500);
|
||||
|
||||
// Start ripple effect after sidebar is expanded
|
||||
const rippleTimer = setTimeout(() => {
|
||||
startRippleEffect();
|
||||
}, 1000);
|
||||
|
||||
// Auto-collapse after 2 seconds
|
||||
const collapseTimer = setTimeout(() => {
|
||||
onToggleCollapse(); // Collapse the sidebar
|
||||
setIsAnimating(false);
|
||||
setShouldAutoExpand(false);
|
||||
}, 3000);
|
||||
|
||||
return () => {
|
||||
clearTimeout(expandTimer);
|
||||
clearTimeout(rippleTimer);
|
||||
clearTimeout(collapseTimer);
|
||||
};
|
||||
}
|
||||
}, [shouldAutoExpand, collapsed, onToggleCollapse, startRippleEffect, userHasInteracted]);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ x: -300, opacity: 0 }}
|
||||
animate={{
|
||||
x: 0,
|
||||
opacity: 1,
|
||||
...(isAnimating && {
|
||||
scale: [1, 1.02, 1],
|
||||
boxShadow: [
|
||||
'0 8px 32px rgba(0,0,0,0.1)',
|
||||
'0 12px 40px rgba(74, 222, 128, 0.2)',
|
||||
'0 8px 32px rgba(0,0,0,0.1)'
|
||||
]
|
||||
})
|
||||
}}
|
||||
transition={{
|
||||
duration: 0.3,
|
||||
...(isAnimating && {
|
||||
scale: { duration: 2, ease: 'easeInOut' },
|
||||
boxShadow: { duration: 2, ease: 'easeInOut' }
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
width: '100%',
|
||||
height: 'fit-content',
|
||||
minHeight: '400px',
|
||||
background: 'linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
border: '1px solid rgba(255,255,255,0.1)',
|
||||
borderRadius: 3,
|
||||
overflow: 'hidden',
|
||||
boxShadow: '0 8px 32px rgba(0,0,0,0.1)',
|
||||
}}
|
||||
>
|
||||
{/* Header */}
|
||||
<Box
|
||||
sx={{
|
||||
p: collapsed ? 1 : 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
borderBottom: '1px solid rgba(255,255,255,0.1)',
|
||||
minHeight: 56,
|
||||
background: 'linear-gradient(90deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)',
|
||||
position: 'relative',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: '1px',
|
||||
background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.2) 50%, transparent 100%)',
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Animation indicator */}
|
||||
{isAnimating && !collapsed && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.8 }}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: -8,
|
||||
right: -8,
|
||||
width: 16,
|
||||
height: 16,
|
||||
borderRadius: '50%',
|
||||
background: 'linear-gradient(45deg, #4ade80, #22c55e)',
|
||||
boxShadow: '0 0 10px rgba(74, 222, 128, 0.6)',
|
||||
zIndex: 10
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 2, repeat: Infinity, ease: 'linear' }}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
borderRadius: '50%',
|
||||
border: '2px solid transparent',
|
||||
borderTop: '2px solid rgba(255,255,255,0.8)',
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
{!collapsed && (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<Box sx={{
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: '50%',
|
||||
background: 'linear-gradient(45deg, #4ade80, #22c55e)',
|
||||
boxShadow: '0 0 8px rgba(74, 222, 128, 0.4)'
|
||||
}} />
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold', color: '#ffffff' }}>
|
||||
Tools
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
<Tooltip title={collapsed ? "Expand sidebar" : "Collapse sidebar"}>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => {
|
||||
setUserHasInteracted(true);
|
||||
onToggleCollapse();
|
||||
}}
|
||||
sx={{
|
||||
color: 'rgba(255,255,255,0.7)',
|
||||
backgroundColor: 'rgba(255,255,255,0.05)',
|
||||
border: '1px solid rgba(255,255,255,0.1)',
|
||||
'&:hover': {
|
||||
color: '#ffffff',
|
||||
backgroundColor: 'rgba(255,255,255,0.1)',
|
||||
transform: 'scale(1.05)'
|
||||
},
|
||||
transition: 'all 0.2s ease-in-out'
|
||||
}}
|
||||
>
|
||||
{collapsed ? <ChevronRight size={16} /> : <ChevronLeft size={16} />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
{/* Content */}
|
||||
<Box sx={{ p: collapsed ? 1 : 2, height: 'calc(100% - 56px)', overflow: 'auto' }}>
|
||||
{!collapsed ? (
|
||||
<>
|
||||
{/* Search Section */}
|
||||
<Box sx={{
|
||||
mb: 2,
|
||||
p: 2,
|
||||
backgroundColor: 'rgba(255,255,255,0.03)',
|
||||
borderRadius: 2,
|
||||
border: '1px solid rgba(255,255,255,0.05)',
|
||||
position: 'relative',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: '1px',
|
||||
background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.1) 50%, transparent 100%)',
|
||||
}
|
||||
}}>
|
||||
<Typography variant="subtitle2" sx={{
|
||||
mb: 1,
|
||||
color: 'rgba(255,255,255,0.9)',
|
||||
fontWeight: 'bold',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1
|
||||
}}>
|
||||
<Search size={16} color="rgba(255,255,255,0.7)" />
|
||||
Search Tools
|
||||
</Typography>
|
||||
<SearchFilter
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={onSearchChange}
|
||||
onClearSearch={onClearSearch}
|
||||
selectedCategory={selectedCategory}
|
||||
onCategoryChange={onCategoryChange}
|
||||
selectedSubCategory={selectedSubCategory}
|
||||
onSubCategoryChange={onSubCategoryChange}
|
||||
toolCategories={toolCategories}
|
||||
theme={theme}
|
||||
onCategoryClick={onCategoryClick}
|
||||
compact={true}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ my: 2, borderColor: 'rgba(255,255,255,0.1)' }} />
|
||||
|
||||
{/* Quick Stats */}
|
||||
<Box sx={{
|
||||
mb: 2,
|
||||
p: 2,
|
||||
backgroundColor: 'rgba(255,255,255,0.03)',
|
||||
borderRadius: 2,
|
||||
border: '1px solid rgba(255,255,255,0.05)',
|
||||
position: 'relative',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: '1px',
|
||||
background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.1) 50%, transparent 100%)',
|
||||
}
|
||||
}}>
|
||||
<Typography variant="subtitle2" sx={{
|
||||
mb: 1,
|
||||
color: 'rgba(255,255,255,0.9)',
|
||||
fontWeight: 'bold',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1
|
||||
}}>
|
||||
<Activity size={16} color="rgba(255,255,255,0.7)" />
|
||||
Quick Stats
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography variant="caption" sx={{ color: 'rgba(255,255,255,0.7)' }}>
|
||||
Total Tools
|
||||
</Typography>
|
||||
<Chip
|
||||
label={totalTools}
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: 'rgba(74, 222, 128, 0.2)',
|
||||
color: '#4ade80',
|
||||
border: '1px solid rgba(74, 222, 128, 0.3)'
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography variant="caption" sx={{ color: 'rgba(255,255,255,0.7)' }}>
|
||||
Categories
|
||||
</Typography>
|
||||
<Chip
|
||||
label={Object.keys(toolCategories).length}
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: 'rgba(59, 130, 246, 0.2)',
|
||||
color: '#3b82f6',
|
||||
border: '1px solid rgba(59, 130, 246, 0.3)'
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ my: 2, borderColor: 'rgba(255,255,255,0.1)' }} />
|
||||
|
||||
{/* Category Quick Access */}
|
||||
<Box sx={{
|
||||
p: 2,
|
||||
backgroundColor: 'rgba(255,255,255,0.03)',
|
||||
borderRadius: 2,
|
||||
border: '1px solid rgba(255,255,255,0.05)',
|
||||
position: 'relative',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: '1px',
|
||||
background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.1) 50%, transparent 100%)',
|
||||
}
|
||||
}}>
|
||||
<Typography variant="subtitle2" sx={{
|
||||
mb: 1,
|
||||
color: 'rgba(255,255,255,0.9)',
|
||||
fontWeight: 'bold',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1
|
||||
}}>
|
||||
<Zap size={16} color="rgba(255,255,255,0.7)" />
|
||||
Quick Access
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
{Object.entries(toolCategories).slice(0, 5).map(([categoryId, category], index) => {
|
||||
const toolCount = 'tools' in category
|
||||
? category.tools.length
|
||||
: Object.values(category.subCategories).reduce((sum, subCat) => sum + subCat.tools.length, 0);
|
||||
|
||||
const isRippling = rippleIndex === index;
|
||||
|
||||
return (
|
||||
<Tooltip key={categoryId} title={`${categoryId} (${toolCount} tools)`}>
|
||||
<motion.div
|
||||
animate={isRippling ? {
|
||||
scale: [1, 1.05, 1],
|
||||
boxShadow: [
|
||||
'0 0 0 rgba(74, 222, 128, 0)',
|
||||
'0 0 20px rgba(74, 222, 128, 0.6)',
|
||||
'0 0 0 rgba(74, 222, 128, 0)'
|
||||
]
|
||||
} : {}}
|
||||
transition={{ duration: 1, ease: 'easeInOut' }}
|
||||
>
|
||||
<Chip
|
||||
label={`${categoryId} (${toolCount})`}
|
||||
size="small"
|
||||
onClick={() => {
|
||||
setUserHasInteracted(true);
|
||||
onCategoryClick(categoryId, category);
|
||||
}}
|
||||
sx={{
|
||||
backgroundColor: selectedCategory === categoryId
|
||||
? 'rgba(74, 222, 128, 0.2)'
|
||||
: isRippling
|
||||
? 'rgba(74, 222, 128, 0.15)'
|
||||
: 'rgba(255,255,255,0.05)',
|
||||
color: selectedCategory === categoryId || isRippling ? '#4ade80' : '#ffffff',
|
||||
border: selectedCategory === categoryId
|
||||
? '1px solid rgba(74, 222, 128, 0.3)'
|
||||
: isRippling
|
||||
? '1px solid rgba(74, 222, 128, 0.4)'
|
||||
: '1px solid rgba(255,255,255,0.1)',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.2s ease-in-out',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
'&::before': isRippling ? {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: '-100%',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent)',
|
||||
animation: 'shimmer 1s ease-in-out',
|
||||
'@keyframes shimmer': {
|
||||
'0%': { left: '-100%' },
|
||||
'100%': { left: '100%' }
|
||||
}
|
||||
} : {},
|
||||
'&:hover': {
|
||||
backgroundColor: selectedCategory === categoryId
|
||||
? 'rgba(74, 222, 128, 0.3)'
|
||||
: 'rgba(255,255,255,0.15)',
|
||||
transform: 'translateY(-1px)',
|
||||
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
/* Collapsed State - Enhanced Icons with Depth */
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2, pt: 2 }}>
|
||||
<Tooltip title="Search Tools">
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.1, y: -2 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
||||
>
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{
|
||||
color: searchQuery ? '#4ade80' : 'rgba(255,255,255,0.8)',
|
||||
backgroundColor: searchQuery
|
||||
? 'rgba(74, 222, 128, 0.15)'
|
||||
: 'rgba(255,255,255,0.08)',
|
||||
border: searchQuery
|
||||
? '2px solid rgba(74, 222, 128, 0.4)'
|
||||
: '2px solid rgba(255,255,255,0.15)',
|
||||
borderRadius: '12px',
|
||||
width: 40,
|
||||
height: 40,
|
||||
boxShadow: searchQuery
|
||||
? '0 8px 25px rgba(74, 222, 128, 0.3), 0 0 20px rgba(74, 222, 128, 0.2), inset 0 1px 0 rgba(255,255,255,0.2)'
|
||||
: '0 6px 20px rgba(0,0,0,0.15), 0 0 15px rgba(255,255,255,0.1), inset 0 1px 0 rgba(255,255,255,0.1)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: searchQuery
|
||||
? 'linear-gradient(135deg, rgba(74, 222, 128, 0.1) 0%, rgba(34, 197, 94, 0.1) 100%)'
|
||||
: 'linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)',
|
||||
borderRadius: '10px',
|
||||
zIndex: -1
|
||||
},
|
||||
'&:hover': {
|
||||
color: '#ffffff',
|
||||
backgroundColor: searchQuery
|
||||
? 'rgba(74, 222, 128, 0.25)'
|
||||
: 'rgba(255,255,255,0.15)',
|
||||
boxShadow: searchQuery
|
||||
? '0 12px 35px rgba(74, 222, 128, 0.4), 0 0 30px rgba(74, 222, 128, 0.3), inset 0 1px 0 rgba(255,255,255,0.3)'
|
||||
: '0 10px 30px rgba(0,0,0,0.2), 0 0 25px rgba(255,255,255,0.15), inset 0 1px 0 rgba(255,255,255,0.2)',
|
||||
transform: 'translateY(-2px)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Search size={18} />
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Filter Categories">
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.1, y: -2 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
||||
>
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{
|
||||
color: selectedCategory ? '#3b82f6' : 'rgba(255,255,255,0.8)',
|
||||
backgroundColor: selectedCategory
|
||||
? 'rgba(59, 130, 246, 0.15)'
|
||||
: 'rgba(255,255,255,0.08)',
|
||||
border: selectedCategory
|
||||
? '2px solid rgba(59, 130, 246, 0.4)'
|
||||
: '2px solid rgba(255,255,255,0.15)',
|
||||
borderRadius: '12px',
|
||||
width: 40,
|
||||
height: 40,
|
||||
boxShadow: selectedCategory
|
||||
? '0 8px 25px rgba(59, 130, 246, 0.3), 0 0 20px rgba(59, 130, 246, 0.2), inset 0 1px 0 rgba(255,255,255,0.2)'
|
||||
: '0 6px 20px rgba(0,0,0,0.15), 0 0 15px rgba(255,255,255,0.1), inset 0 1px 0 rgba(255,255,255,0.1)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: selectedCategory
|
||||
? 'linear-gradient(135deg, rgba(59, 130, 246, 0.1) 0%, rgba(37, 99, 235, 0.1) 100%)'
|
||||
: 'linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)',
|
||||
borderRadius: '10px',
|
||||
zIndex: -1
|
||||
},
|
||||
'&:hover': {
|
||||
color: '#ffffff',
|
||||
backgroundColor: selectedCategory
|
||||
? 'rgba(59, 130, 246, 0.25)'
|
||||
: 'rgba(255,255,255,0.15)',
|
||||
boxShadow: selectedCategory
|
||||
? '0 12px 35px rgba(59, 130, 246, 0.4), 0 0 30px rgba(59, 130, 246, 0.3), inset 0 1px 0 rgba(255,255,255,0.3)'
|
||||
: '0 10px 30px rgba(0,0,0,0.2), 0 0 25px rgba(255,255,255,0.15), inset 0 1px 0 rgba(255,255,255,0.2)',
|
||||
transform: 'translateY(-2px)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Filter size={18} />
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
</Tooltip>
|
||||
|
||||
<Divider sx={{ width: '100%', borderColor: 'rgba(255,255,255,0.1)' }} />
|
||||
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
|
||||
{Object.entries(toolCategories).slice(0, 4).map(([categoryId, category]) => {
|
||||
const toolCount = 'tools' in category
|
||||
? category.tools.length
|
||||
: Object.values(category.subCategories).reduce((sum, subCat) => sum + subCat.tools.length, 0);
|
||||
|
||||
const isSelected = selectedCategory === categoryId;
|
||||
|
||||
return (
|
||||
<Tooltip key={categoryId} title={`${categoryId} (${toolCount})`}>
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.15, y: -3 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: isSelected
|
||||
? 'rgba(74, 222, 128, 0.2)'
|
||||
: 'rgba(255,255,255,0.08)',
|
||||
border: isSelected
|
||||
? '2px solid rgba(74, 222, 128, 0.5)'
|
||||
: '2px solid rgba(255,255,255,0.2)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
boxShadow: isSelected
|
||||
? '0 8px 25px rgba(74, 222, 128, 0.3), 0 0 20px rgba(74, 222, 128, 0.2), inset 0 1px 0 rgba(255,255,255,0.2)'
|
||||
: '0 6px 20px rgba(0,0,0,0.15), 0 0 15px rgba(255,255,255,0.1), inset 0 1px 0 rgba(255,255,255,0.1)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: isSelected
|
||||
? 'linear-gradient(135deg, rgba(74, 222, 128, 0.1) 0%, rgba(34, 197, 94, 0.1) 100%)'
|
||||
: 'linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)',
|
||||
borderRadius: '50%',
|
||||
zIndex: -1
|
||||
},
|
||||
'&:hover': {
|
||||
backgroundColor: isSelected
|
||||
? 'rgba(74, 222, 128, 0.3)'
|
||||
: 'rgba(255,255,255,0.15)',
|
||||
boxShadow: isSelected
|
||||
? '0 12px 35px rgba(74, 222, 128, 0.4), 0 0 30px rgba(74, 222, 128, 0.3), inset 0 1px 0 rgba(255,255,255,0.3)'
|
||||
: '0 10px 30px rgba(0,0,0,0.2), 0 0 25px rgba(255,255,255,0.15), inset 0 1px 0 rgba(255,255,255,0.2)',
|
||||
transform: 'translateY(-3px)'
|
||||
}
|
||||
}}
|
||||
onClick={() => {
|
||||
setUserHasInteracted(true);
|
||||
onCategoryClick(categoryId, category);
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
color: isSelected ? '#4ade80' : '#ffffff',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '0.75rem',
|
||||
textShadow: '0 1px 2px rgba(0,0,0,0.3)'
|
||||
}}
|
||||
>
|
||||
{categoryId.charAt(0).toUpperCase()}
|
||||
</Typography>
|
||||
</Box>
|
||||
</motion.div>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Paper>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CompactSidebar;
|
||||
@@ -0,0 +1,279 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
Button,
|
||||
useTheme,
|
||||
useMediaQuery
|
||||
} from '@mui/material';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
PlayArrow,
|
||||
TrendingUp,
|
||||
Rocket,
|
||||
ArrowRight,
|
||||
Star
|
||||
} from '@mui/icons-material';
|
||||
|
||||
interface WorkflowHeroSectionProps {
|
||||
onStartWorkflow: () => void;
|
||||
isWorkflowActive: boolean;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
const WorkflowHeroSection: React.FC<WorkflowHeroSectionProps> = ({
|
||||
onStartWorkflow,
|
||||
isWorkflowActive,
|
||||
isLoading
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
// Show hero section only when workflow is not started, not in progress, and not completed
|
||||
const shouldShowHero = !isWorkflowActive;
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{shouldShowHero && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -20 }}
|
||||
transition={{ duration: 0.6, ease: "easeOut" }}
|
||||
>
|
||||
{/* Backdrop Overlay - Only over pillars section */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
backdropFilter: 'blur(6px)',
|
||||
zIndex: 10,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 2, // Match the parent container's border radius
|
||||
}}
|
||||
>
|
||||
{/* Hero Content */}
|
||||
<Box
|
||||
sx={{
|
||||
textAlign: 'center',
|
||||
maxWidth: isMobile ? '90%' : '500px',
|
||||
px: 3,
|
||||
py: 4,
|
||||
background: 'linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%)',
|
||||
backdropFilter: 'blur(20px)',
|
||||
borderRadius: 3,
|
||||
border: '1px solid rgba(255,255,255,0.2)',
|
||||
boxShadow: '0 15px 30px rgba(0,0,0,0.3), 0 0 0 1px rgba(255,255,255,0.1)',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: 'linear-gradient(45deg, rgba(255,107,53,0.1) 0%, rgba(255,140,66,0.1) 50%, rgba(255,107,53,0.1) 100%)',
|
||||
backgroundSize: '200% 200%',
|
||||
animation: 'gradientShift 6s ease-in-out infinite',
|
||||
zIndex: -1,
|
||||
},
|
||||
'@keyframes gradientShift': {
|
||||
'0%, 100%': { backgroundPosition: '0% 50%' },
|
||||
'50%': { backgroundPosition: '100% 50%' },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{/* Floating Sparkles */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 20,
|
||||
right: 20,
|
||||
animation: 'float 3s ease-in-out infinite',
|
||||
'@keyframes float': {
|
||||
'0%, 100%': { transform: 'translateY(0px)' },
|
||||
'50%': { transform: 'translateY(-10px)' },
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Star sx={{ color: 'rgba(255,255,255,0.6)', fontSize: 24 }} />
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
bottom: 20,
|
||||
left: 20,
|
||||
animation: 'float 3s ease-in-out infinite 1.5s',
|
||||
'@keyframes float': {
|
||||
'0%, 100%': { transform: 'translateY(0px)' },
|
||||
'50%': { transform: 'translateY(-10px)' },
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TrendingUp sx={{ color: 'rgba(255,255,255,0.6)', fontSize: 24 }} />
|
||||
</Box>
|
||||
|
||||
{/* Main Content */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8, delay: 0.2 }}
|
||||
>
|
||||
{/* Icon */}
|
||||
<Box sx={{ mb: 2 }}>
|
||||
<motion.div
|
||||
animate={{
|
||||
rotate: [0, 5, -5, 0],
|
||||
scale: [1, 1.1, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
repeatType: "reverse"
|
||||
}}
|
||||
>
|
||||
<Rocket
|
||||
sx={{
|
||||
fontSize: isMobile ? 40 : 48,
|
||||
color: '#FF6B35',
|
||||
filter: 'drop-shadow(0 4px 8px rgba(255,107,53,0.3))'
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
</Box>
|
||||
|
||||
{/* Main Heading */}
|
||||
<Typography
|
||||
variant={isMobile ? "h5" : "h4"}
|
||||
sx={{
|
||||
fontWeight: 800,
|
||||
color: '#ffffff',
|
||||
mb: 1.5,
|
||||
textShadow: '0 4px 8px rgba(0,0,0,0.3)',
|
||||
background: 'linear-gradient(135deg, #ffffff 0%, #f0f0f0 100%)',
|
||||
backgroundClip: 'text',
|
||||
WebkitBackgroundClip: 'text',
|
||||
WebkitTextFillColor: 'transparent',
|
||||
}}
|
||||
>
|
||||
Grow Your Business Now
|
||||
</Typography>
|
||||
|
||||
{/* Supporting Text */}
|
||||
<Typography
|
||||
variant={isMobile ? "body2" : "body1"}
|
||||
sx={{
|
||||
color: 'rgba(255,255,255,0.9)',
|
||||
mb: 3,
|
||||
lineHeight: 1.5,
|
||||
maxWidth: '400px',
|
||||
mx: 'auto',
|
||||
textShadow: '0 2px 4px rgba(0,0,0,0.3)',
|
||||
}}
|
||||
>
|
||||
Start your personalized content workflow and watch your digital marketing transform.
|
||||
Our AI-powered system will guide you through every step of your content journey.
|
||||
</Typography>
|
||||
|
||||
{/* CTA Button */}
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="large"
|
||||
startIcon={<PlayArrow />}
|
||||
endIcon={<ArrowRight />}
|
||||
onClick={onStartWorkflow}
|
||||
disabled={isLoading}
|
||||
sx={{
|
||||
background: 'linear-gradient(135deg, #FF6B35 0%, #E55A2B 100%)',
|
||||
border: '2px solid transparent',
|
||||
borderRadius: 2,
|
||||
px: 4,
|
||||
py: 1.5,
|
||||
fontSize: isMobile ? '0.9rem' : '1rem',
|
||||
fontWeight: 700,
|
||||
textTransform: 'none',
|
||||
boxShadow: '0 6px 24px rgba(255,107,53,0.4), 0 0 0 1px rgba(255,255,255,0.2)',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
'&:hover': {
|
||||
background: 'linear-gradient(135deg, #E55A2B 0%, #D1491F 100%)',
|
||||
boxShadow: '0 12px 40px rgba(255,107,53,0.6), 0 0 0 1px rgba(255,255,255,0.3)',
|
||||
transform: 'translateY(-2px)',
|
||||
},
|
||||
'&:disabled': {
|
||||
background: 'rgba(255,255,255,0.1)',
|
||||
color: 'rgba(255,255,255,0.5)',
|
||||
},
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: '-100%',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
background: 'linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent)',
|
||||
animation: 'shimmer 2.5s infinite',
|
||||
zIndex: 1,
|
||||
},
|
||||
'&::after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: -4,
|
||||
left: -4,
|
||||
right: -4,
|
||||
bottom: -4,
|
||||
background: 'linear-gradient(45deg, #FF6B35, #FF8C42, #FF6B35, #FF8C42)',
|
||||
backgroundSize: '400% 400%',
|
||||
borderRadius: 'inherit',
|
||||
zIndex: -1,
|
||||
animation: 'borderGlow 3s ease-in-out infinite',
|
||||
},
|
||||
'@keyframes shimmer': {
|
||||
'0%': { left: '-100%' },
|
||||
'100%': { left: '100%' },
|
||||
},
|
||||
'@keyframes borderGlow': {
|
||||
'0%, 100%': { backgroundPosition: '0% 50%' },
|
||||
'50%': { backgroundPosition: '100% 50%' },
|
||||
},
|
||||
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
}}
|
||||
>
|
||||
{isLoading ? 'Starting...' : '🚀 Start Your Journey'}
|
||||
</Button>
|
||||
</motion.div>
|
||||
|
||||
{/* Additional Info */}
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
color: 'rgba(255,255,255,0.7)',
|
||||
mt: 2,
|
||||
display: 'block',
|
||||
textShadow: '0 1px 2px rgba(0,0,0,0.3)',
|
||||
}}
|
||||
>
|
||||
✨ Personalized workflow • 🎯 AI-powered guidance • 📈 Business growth
|
||||
</Typography>
|
||||
</motion.div>
|
||||
</Box>
|
||||
</Box>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkflowHeroSection;
|
||||
Reference in New Issue
Block a user