Added beta testing for user_id=1 for all requests
This commit is contained in:
@@ -2,11 +2,9 @@ import React, { useState } from 'react';
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Container,
|
Container,
|
||||||
Grid,
|
|
||||||
Alert,
|
Alert,
|
||||||
Snackbar,
|
Snackbar,
|
||||||
useTheme,
|
useTheme
|
||||||
useMediaQuery
|
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
@@ -15,12 +13,8 @@ import AskAlwrityIcon from '../../assets/images/AskAlwrity-min.ico';
|
|||||||
// Shared components
|
// Shared components
|
||||||
import DashboardHeader from '../shared/DashboardHeader';
|
import DashboardHeader from '../shared/DashboardHeader';
|
||||||
import SystemStatusIndicator from '../ContentPlanningDashboard/components/SystemStatusIndicator';
|
import SystemStatusIndicator from '../ContentPlanningDashboard/components/SystemStatusIndicator';
|
||||||
import SearchFilter from '../shared/SearchFilter';
|
|
||||||
import ToolCard from '../shared/ToolCard';
|
|
||||||
import CategoryHeader from '../shared/CategoryHeader';
|
|
||||||
import LoadingSkeleton from '../shared/LoadingSkeleton';
|
import LoadingSkeleton from '../shared/LoadingSkeleton';
|
||||||
import ErrorDisplay from '../shared/ErrorDisplay';
|
import ErrorDisplay from '../shared/ErrorDisplay';
|
||||||
import EmptyState from '../shared/EmptyState';
|
|
||||||
import ContentLifecyclePillars from './ContentLifecyclePillars';
|
import ContentLifecyclePillars from './ContentLifecyclePillars';
|
||||||
import AnalyticsInsights from './components/AnalyticsInsights';
|
import AnalyticsInsights from './components/AnalyticsInsights';
|
||||||
import ToolsModal from './components/ToolsModal';
|
import ToolsModal from './components/ToolsModal';
|
||||||
@@ -61,7 +55,6 @@ const MainDashboard: React.FC = () => {
|
|||||||
setSelectedSubCategory,
|
setSelectedSubCategory,
|
||||||
showSnackbar,
|
showSnackbar,
|
||||||
hideSnackbar,
|
hideSnackbar,
|
||||||
clearFilters,
|
|
||||||
} = useDashboardStore();
|
} = useDashboardStore();
|
||||||
|
|
||||||
// Workflow store hooks
|
// Workflow store hooks
|
||||||
@@ -219,7 +212,7 @@ const MainDashboard: React.FC = () => {
|
|||||||
// Close modal if search query is too short
|
// Close modal if search query is too short
|
||||||
setToolsModalOpen(false);
|
setToolsModalOpen(false);
|
||||||
}
|
}
|
||||||
}, [searchQuery, toolCategories]);
|
}, [searchQuery]);
|
||||||
|
|
||||||
// Close modal and clear search
|
// Close modal and clear search
|
||||||
const handleCloseModal = () => {
|
const handleCloseModal = () => {
|
||||||
@@ -232,11 +225,7 @@ const MainDashboard: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const filteredCategories = getFilteredCategories(
|
// Note: filteredCategories removed as it's not used in the current implementation
|
||||||
toolCategories,
|
|
||||||
selectedCategory,
|
|
||||||
searchQuery
|
|
||||||
);
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <LoadingSkeleton />;
|
return <LoadingSkeleton />;
|
||||||
@@ -334,6 +323,8 @@ const MainDashboard: React.FC = () => {
|
|||||||
collapsed={sidebarCollapsed}
|
collapsed={sidebarCollapsed}
|
||||||
onToggleCollapse={() => setSidebarCollapsed(!sidebarCollapsed)}
|
onToggleCollapse={() => setSidebarCollapsed(!sidebarCollapsed)}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
favorites={favorites}
|
||||||
|
onToolClick={handleToolClick}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
Divider
|
Divider
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { styled } from '@mui/material/styles';
|
import { styled } from '@mui/material/styles';
|
||||||
import { keyframes } from '@mui/system';
|
|
||||||
import {
|
import {
|
||||||
CheckCircle as CheckIcon,
|
CheckCircle as CheckIcon,
|
||||||
WarningAmber as WarningIcon,
|
WarningAmber as WarningIcon,
|
||||||
@@ -53,43 +52,64 @@ interface AnalyticsInsightsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ColumnCard = styled(Card)(({ theme }) => ({
|
const ColumnCard = styled(Card)(({ theme }) => ({
|
||||||
background: 'linear-gradient(180deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0.08) 100%)',
|
background: 'linear-gradient(135deg, rgba(15, 23, 42, 0.8) 0%, rgba(30, 41, 59, 0.7) 100%)',
|
||||||
border: '1px solid rgba(255,255,255,0.16)',
|
border: '1px solid rgba(148, 163, 184, 0.15)',
|
||||||
backdropFilter: 'blur(18px)',
|
backdropFilter: 'blur(20px)',
|
||||||
WebkitBackdropFilter: 'blur(18px)',
|
WebkitBackdropFilter: 'blur(20px)',
|
||||||
borderRadius: theme.spacing(2),
|
borderRadius: theme.spacing(3),
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
boxShadow: '0 8px 20px rgba(0,0,0,0.28), inset 0 1px 0 rgba(255,255,255,0.22)',
|
boxShadow: '0 20px 40px -12px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.05)',
|
||||||
transition: 'transform 0.3s ease, box-shadow 0.3s ease',
|
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||||
|
position: 'relative',
|
||||||
|
'&::before': {
|
||||||
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
background: 'linear-gradient(135deg, rgba(59, 130, 246, 0.02) 0%, rgba(147, 51, 234, 0.01) 100%)',
|
||||||
|
zIndex: -1,
|
||||||
|
},
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
transform: 'translateY(-3px)',
|
transform: 'translateY(-4px)',
|
||||||
boxShadow: '0 12px 28px rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.28)'
|
boxShadow: '0 32px 64px -12px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.08)',
|
||||||
|
border: '1px solid rgba(148, 163, 184, 0.25)',
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const Pill = styled('div')<{ color: string }>(() => ({
|
// Pill component removed as it's not used
|
||||||
width: 10,
|
|
||||||
height: 10,
|
|
||||||
borderRadius: 6,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const GradientHeader = styled(Box)<{ gradient: string }>(({ gradient }) => ({
|
const GradientHeader = styled(Box)<{ gradient: string }>(({ gradient }) => ({
|
||||||
background: gradient,
|
background: gradient,
|
||||||
padding: '8px 12px',
|
padding: '12px 16px',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: 6,
|
gap: 8,
|
||||||
|
position: 'relative',
|
||||||
|
'&::after': {
|
||||||
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
height: '1px',
|
||||||
|
background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.3) 50%, transparent 100%)',
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const Badge = styled('span')(({ theme }) => ({
|
const Badge = styled('span')(({ theme }) => ({
|
||||||
background: 'rgba(255,255,255,0.15)',
|
background: 'rgba(255,255,255,0.2)',
|
||||||
border: '1px solid rgba(255,255,255,0.35)',
|
border: '1px solid rgba(255,255,255,0.4)',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
borderRadius: 999,
|
borderRadius: 12,
|
||||||
padding: '1px 6px',
|
padding: '4px 8px',
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
fontSize: '0.65rem'
|
fontSize: '0.7rem',
|
||||||
|
backdropFilter: 'blur(8px)',
|
||||||
|
boxShadow: '0 2px 8px rgba(0,0,0,0.2)',
|
||||||
|
textShadow: '0 1px 2px rgba(0,0,0,0.3)'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
@@ -263,20 +283,129 @@ const AnalyticsInsights: React.FC<AnalyticsInsightsProps> = ({ data, onActionCli
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 1, mb: 1.5 }}>
|
<Box sx={{
|
||||||
<Box sx={{ position: 'relative', overflow: 'hidden' }}>
|
mt: 1.4,
|
||||||
<Typography
|
mb: 1.4,
|
||||||
variant="h6"
|
p: 2.1,
|
||||||
sx={{
|
background: 'linear-gradient(135deg, rgba(15, 23, 42, 0.95) 0%, rgba(30, 41, 59, 0.9) 100%)',
|
||||||
fontWeight: 800,
|
backdropFilter: 'blur(24px)',
|
||||||
mb: 1.5,
|
border: '1px solid rgba(148, 163, 184, 0.1)',
|
||||||
fontSize: '1.1rem',
|
borderRadius: 4,
|
||||||
color: 'rgba(255,255,255,0.95)',
|
boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.05)',
|
||||||
}}
|
position: 'relative',
|
||||||
>
|
overflow: 'hidden',
|
||||||
Today's Analytics Insights
|
'&::before': {
|
||||||
</Typography>
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
background: 'linear-gradient(135deg, rgba(59, 130, 246, 0.03) 0%, rgba(147, 51, 234, 0.02) 100%)',
|
||||||
|
zIndex: -1,
|
||||||
|
},
|
||||||
|
}}>
|
||||||
|
<Box sx={{
|
||||||
|
position: 'relative',
|
||||||
|
overflow: 'hidden',
|
||||||
|
mb: 2.1,
|
||||||
|
pb: 1.4,
|
||||||
|
borderBottom: '1px solid rgba(148, 163, 184, 0.1)',
|
||||||
|
'&::after': {
|
||||||
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
height: '1px',
|
||||||
|
background: 'linear-gradient(90deg, transparent 0%, rgba(59, 130, 246, 0.3) 50%, transparent 100%)',
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
width: '100%'
|
||||||
|
}}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||||
|
<TrendingUpIcon sx={{ color: '#3b82f6', fontSize: '1.5rem' }} />
|
||||||
|
<Typography
|
||||||
|
variant="h5"
|
||||||
|
sx={{
|
||||||
|
fontWeight: 800,
|
||||||
|
fontSize: '1.4rem',
|
||||||
|
color: '#ffffff',
|
||||||
|
textShadow: '0 2px 4px rgba(0,0,0,0.3)',
|
||||||
|
background: 'linear-gradient(135deg, #ffffff 0%, #e2e8f0 100%)',
|
||||||
|
backgroundClip: 'text',
|
||||||
|
WebkitBackgroundClip: 'text',
|
||||||
|
WebkitTextFillColor: 'transparent',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Today's Analytics Insights
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Chat with Analytics Pro Button - Inline */}
|
||||||
|
<Button
|
||||||
|
disabled
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
background: 'linear-gradient(135deg, rgba(148, 163, 184, 0.1) 0%, rgba(100, 116, 139, 0.1) 100%)',
|
||||||
|
border: '1px solid rgba(148, 163, 184, 0.2)',
|
||||||
|
borderRadius: 2,
|
||||||
|
px: 2,
|
||||||
|
py: 0.8,
|
||||||
|
color: 'rgba(148, 163, 184, 0.6)',
|
||||||
|
fontSize: '0.8rem',
|
||||||
|
fontWeight: 600,
|
||||||
|
textTransform: 'none',
|
||||||
|
backdropFilter: 'blur(8px)',
|
||||||
|
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
|
||||||
|
position: 'relative',
|
||||||
|
overflow: 'hidden',
|
||||||
|
minWidth: 'auto',
|
||||||
|
'&::before': {
|
||||||
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
background: 'linear-gradient(135deg, rgba(148, 163, 184, 0.05) 0%, rgba(100, 116, 139, 0.05) 100%)',
|
||||||
|
zIndex: -1,
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
background: 'linear-gradient(135deg, rgba(148, 163, 184, 0.1) 0%, rgba(100, 116, 139, 0.1) 100%)',
|
||||||
|
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
|
||||||
|
},
|
||||||
|
'&.Mui-disabled': {
|
||||||
|
background: 'linear-gradient(135deg, rgba(148, 163, 184, 0.1) 0%, rgba(100, 116, 139, 0.1) 100%)',
|
||||||
|
color: 'rgba(148, 163, 184, 0.6)',
|
||||||
|
border: '1px solid rgba(148, 163, 184, 0.2)',
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
💬 Chat
|
||||||
|
<Chip
|
||||||
|
label="Pro"
|
||||||
|
size="small"
|
||||||
|
sx={{
|
||||||
|
ml: 1,
|
||||||
|
background: 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)',
|
||||||
|
color: 'white',
|
||||||
|
fontSize: '0.6rem',
|
||||||
|
fontWeight: 700,
|
||||||
|
height: 18,
|
||||||
|
'& .MuiChip-label': {
|
||||||
|
px: 0.8,
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Stack direction={{ xs: 'column', md: 'row' }} spacing={1}>
|
<Stack direction={{ xs: 'column', md: 'row' }} spacing={1}>
|
||||||
{columns.map((col) => {
|
{columns.map((col) => {
|
||||||
const isHovered = hovered === col.key;
|
const isHovered = hovered === col.key;
|
||||||
@@ -291,27 +420,60 @@ const AnalyticsInsights: React.FC<AnalyticsInsightsProps> = ({ data, onActionCli
|
|||||||
<Badge>{col.items.length}</Badge>
|
<Badge>{col.items.length}</Badge>
|
||||||
</GradientHeader>
|
</GradientHeader>
|
||||||
|
|
||||||
<CardContent sx={{ p: 1, '&:last-child': { pb: 1 } }}>
|
<CardContent sx={{ p: 1.4, '&:last-child': { pb: 1.4 } }}>
|
||||||
<Stack spacing={0.5}>
|
<Stack spacing={1.05}>
|
||||||
{visibleItems.map((insight) => (
|
{visibleItems.map((insight) => (
|
||||||
<Box key={insight.id} sx={{
|
<Box key={insight.id} sx={{
|
||||||
background: 'rgba(255,255,255,0.08)',
|
background: 'rgba(15, 23, 42, 0.4)',
|
||||||
border: '1px solid rgba(255,255,255,0.18)',
|
border: '1px solid rgba(148, 163, 184, 0.1)',
|
||||||
borderRadius: 1.5,
|
borderRadius: 2,
|
||||||
p: 0.8
|
p: 1.05,
|
||||||
|
backdropFilter: 'blur(8px)',
|
||||||
|
transition: 'all 0.2s ease-in-out',
|
||||||
|
'&:hover': {
|
||||||
|
background: 'rgba(15, 23, 42, 0.6)',
|
||||||
|
border: '1px solid rgba(148, 163, 184, 0.2)',
|
||||||
|
transform: 'translateY(-1px)',
|
||||||
|
boxShadow: '0 4px 12px rgba(0,0,0,0.2)',
|
||||||
|
}
|
||||||
}}>
|
}}>
|
||||||
<Stack direction="row" spacing={0.5} alignItems="center" sx={{ mb: 0.1 }}>
|
<Stack direction="row" spacing={0.7} alignItems="center" sx={{ mb: 0.7 }}>
|
||||||
<Typography variant="body2" sx={{ color: 'rgba(255,255,255,0.95)', fontWeight: 700, fontSize: '0.8rem' }}>
|
<Typography variant="body2" sx={{
|
||||||
|
color: '#ffffff',
|
||||||
|
fontWeight: 700,
|
||||||
|
fontSize: '0.85rem',
|
||||||
|
textShadow: '0 1px 2px rgba(0,0,0,0.3)'
|
||||||
|
}}>
|
||||||
{insight.title}
|
{insight.title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<TrendChip trend={insight.trend} />
|
<TrendChip trend={insight.trend} />
|
||||||
</Stack>
|
</Stack>
|
||||||
<Typography variant="caption" sx={{ color: 'rgba(255,255,255,0.8)', fontSize: '0.7rem', lineHeight: 1.2 }}>
|
<Typography variant="body2" sx={{
|
||||||
|
color: 'rgba(255,255,255,0.8)',
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
lineHeight: 1.4,
|
||||||
|
mb: 0.7
|
||||||
|
}}>
|
||||||
{insight.description}
|
{insight.description}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Stack direction="row" spacing={0.5} sx={{ mt: 0.5 }}>
|
<Stack direction="row" spacing={0.7} sx={{ mt: 0.7 }}>
|
||||||
<Chip size="small" label={`${insight.metric}: ${insight.value}`} sx={{ color: 'rgba(255,255,255,0.95)', background: 'rgba(255,255,255,0.12)', border: '1px solid rgba(255,255,255,0.24)', fontWeight: 700, fontSize: '0.65rem', height: 20 }} />
|
<Chip size="small" label={`${insight.metric}: ${insight.value}`} sx={{
|
||||||
<Chip size="small" label={insight.platform} sx={{ color: 'rgba(255,255,255,0.85)', background: 'rgba(255,255,255,0.08)', fontSize: '0.65rem', height: 20 }} />
|
color: '#ffffff',
|
||||||
|
background: 'rgba(59, 130, 246, 0.2)',
|
||||||
|
border: '1px solid rgba(59, 130, 246, 0.3)',
|
||||||
|
fontWeight: 700,
|
||||||
|
fontSize: '0.7rem',
|
||||||
|
height: 24,
|
||||||
|
backdropFilter: 'blur(8px)'
|
||||||
|
}} />
|
||||||
|
<Chip size="small" label={insight.platform} sx={{
|
||||||
|
color: 'rgba(255,255,255,0.9)',
|
||||||
|
background: 'rgba(148, 163, 184, 0.15)',
|
||||||
|
border: '1px solid rgba(148, 163, 184, 0.2)',
|
||||||
|
fontSize: '0.7rem',
|
||||||
|
height: 24,
|
||||||
|
backdropFilter: 'blur(8px)'
|
||||||
|
}} />
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ const AnalyzePillarChips: React.FC<AnalyzePillarChipsProps> = ({
|
|||||||
isHovered,
|
isHovered,
|
||||||
pillarColor
|
pillarColor
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
// Today's tasks for Analyze pillar
|
// Today's tasks for Analyze pillar
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ import { motion, AnimatePresence } from 'framer-motion';
|
|||||||
import {
|
import {
|
||||||
Search,
|
Search,
|
||||||
Filter,
|
Filter,
|
||||||
Settings,
|
|
||||||
ChevronLeft,
|
ChevronLeft,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
Activity,
|
Activity,
|
||||||
Zap
|
Zap,
|
||||||
|
Star
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
// Shared components
|
// Shared components
|
||||||
@@ -38,6 +38,8 @@ interface CompactSidebarProps {
|
|||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
onToggleCollapse: () => void;
|
onToggleCollapse: () => void;
|
||||||
theme: any;
|
theme: any;
|
||||||
|
favorites?: string[];
|
||||||
|
onToolClick?: (tool: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session control for animation
|
// Session control for animation
|
||||||
@@ -69,8 +71,18 @@ const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
|||||||
onCategoryClick,
|
onCategoryClick,
|
||||||
collapsed,
|
collapsed,
|
||||||
onToggleCollapse,
|
onToggleCollapse,
|
||||||
theme
|
theme,
|
||||||
|
favorites = [],
|
||||||
|
onToolClick
|
||||||
}) => {
|
}) => {
|
||||||
|
// State for search expansion on hover
|
||||||
|
const [isSearchExpanded, setIsSearchExpanded] = useState(false);
|
||||||
|
// State for sidebar hover expansion
|
||||||
|
const [isSidebarHovered, setIsSidebarHovered] = useState(false);
|
||||||
|
// State for favorites expansion on hover
|
||||||
|
const [isFavoritesExpanded, setIsFavoritesExpanded] = useState(false);
|
||||||
|
// Track original collapsed state for hover behavior
|
||||||
|
const [wasOriginallyCollapsed, setWasOriginallyCollapsed] = useState(false);
|
||||||
const [isAnimating, setIsAnimating] = useState(false);
|
const [isAnimating, setIsAnimating] = useState(false);
|
||||||
const [rippleIndex, setRippleIndex] = useState(-1);
|
const [rippleIndex, setRippleIndex] = useState(-1);
|
||||||
const [shouldAutoExpand, setShouldAutoExpand] = useState(false);
|
const [shouldAutoExpand, setShouldAutoExpand] = useState(false);
|
||||||
@@ -105,7 +117,7 @@ const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
|||||||
setIsAnimating(true);
|
setIsAnimating(true);
|
||||||
markAnimationShown();
|
markAnimationShown();
|
||||||
}
|
}
|
||||||
}, []); // Empty dependency array - only run once on mount
|
}, [collapsed, userHasInteracted]); // Include dependencies to avoid warning
|
||||||
|
|
||||||
// Handle auto-expand animation
|
// Handle auto-expand animation
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -157,6 +169,25 @@ const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
|||||||
boxShadow: { duration: 2, ease: 'easeInOut' }
|
boxShadow: { duration: 2, ease: 'easeInOut' }
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
setIsSidebarHovered(true);
|
||||||
|
if (collapsed) {
|
||||||
|
setUserHasInteracted(true);
|
||||||
|
setWasOriginallyCollapsed(true);
|
||||||
|
// Temporarily expand the sidebar on hover
|
||||||
|
onToggleCollapse();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
setIsSidebarHovered(false);
|
||||||
|
setIsSearchExpanded(false);
|
||||||
|
setIsFavoritesExpanded(false);
|
||||||
|
// Collapse back if it was originally collapsed
|
||||||
|
if (wasOriginallyCollapsed) {
|
||||||
|
onToggleCollapse();
|
||||||
|
setWasOriginallyCollapsed(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Paper
|
<Paper
|
||||||
elevation={0}
|
elevation={0}
|
||||||
@@ -164,24 +195,39 @@ const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
height: 'fit-content',
|
height: 'fit-content',
|
||||||
minHeight: '400px',
|
minHeight: '400px',
|
||||||
background: 'linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%)',
|
background: 'linear-gradient(135deg, rgba(15, 23, 42, 0.95) 0%, rgba(30, 41, 59, 0.9) 100%)',
|
||||||
backdropFilter: 'blur(10px)',
|
backdropFilter: 'blur(24px)',
|
||||||
border: '1px solid rgba(255,255,255,0.1)',
|
border: '1px solid rgba(148, 163, 184, 0.1)',
|
||||||
borderRadius: 3,
|
borderRadius: 4,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
boxShadow: '0 8px 32px rgba(0,0,0,0.1)',
|
boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.05)',
|
||||||
|
position: 'relative',
|
||||||
|
'&::before': {
|
||||||
|
content: '""',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
background: 'linear-gradient(135deg, rgba(59, 130, 246, 0.03) 0%, rgba(147, 51, 234, 0.02) 100%)',
|
||||||
|
zIndex: -1,
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
border: '1px solid rgba(148, 163, 184, 0.2)',
|
||||||
|
boxShadow: '0 32px 64px -12px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(255, 255, 255, 0.08)',
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
p: collapsed ? 1 : 2,
|
p: collapsed ? 1.5 : 2.5,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
borderBottom: '1px solid rgba(255,255,255,0.1)',
|
borderBottom: '1px solid rgba(148, 163, 184, 0.1)',
|
||||||
minHeight: 56,
|
minHeight: 56,
|
||||||
background: 'linear-gradient(90deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)',
|
background: 'linear-gradient(90deg, rgba(59, 130, 246, 0.05) 0%, rgba(147, 51, 234, 0.03) 100%)',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
'&::before': {
|
'&::before': {
|
||||||
content: '""',
|
content: '""',
|
||||||
@@ -190,7 +236,7 @@ const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
height: '1px',
|
height: '1px',
|
||||||
background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.2) 50%, transparent 100%)',
|
background: 'linear-gradient(90deg, transparent 0%, rgba(59, 130, 246, 0.3) 50%, transparent 100%)',
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -270,11 +316,12 @@ const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
|||||||
{/* Search Section */}
|
{/* Search Section */}
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
mb: 2,
|
mb: 2,
|
||||||
p: 2,
|
p: 2.5,
|
||||||
backgroundColor: 'rgba(255,255,255,0.03)',
|
backgroundColor: 'rgba(15, 23, 42, 0.4)',
|
||||||
borderRadius: 2,
|
borderRadius: 3,
|
||||||
border: '1px solid rgba(255,255,255,0.05)',
|
border: '1px solid rgba(148, 163, 184, 0.1)',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
backdropFilter: 'blur(8px)',
|
||||||
'&::before': {
|
'&::before': {
|
||||||
content: '""',
|
content: '""',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -282,7 +329,11 @@ const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
height: '1px',
|
height: '1px',
|
||||||
background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.1) 50%, transparent 100%)',
|
background: 'linear-gradient(90deg, transparent 0%, rgba(59, 130, 246, 0.3) 50%, transparent 100%)',
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
border: '1px solid rgba(148, 163, 184, 0.2)',
|
||||||
|
backgroundColor: 'rgba(15, 23, 42, 0.6)',
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<Typography variant="subtitle2" sx={{
|
<Typography variant="subtitle2" sx={{
|
||||||
@@ -311,172 +362,94 @@ const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Divider sx={{ my: 2, borderColor: 'rgba(255,255,255,0.1)' }} />
|
|
||||||
|
|
||||||
{/* Quick Stats */}
|
|
||||||
<Box sx={{
|
{/* Favorites Section */}
|
||||||
mb: 2,
|
{favorites.length > 0 && (
|
||||||
p: 2,
|
<>
|
||||||
backgroundColor: 'rgba(255,255,255,0.03)',
|
<Divider sx={{ my: 2, borderColor: 'rgba(255,255,255,0.1)' }} />
|
||||||
borderRadius: 2,
|
|
||||||
border: '1px solid rgba(255,255,255,0.05)',
|
<Box sx={{
|
||||||
position: 'relative',
|
p: 2,
|
||||||
'&::before': {
|
backgroundColor: 'rgba(15, 23, 42, 0.4)',
|
||||||
content: '""',
|
borderRadius: 3,
|
||||||
position: 'absolute',
|
border: '1px solid rgba(148, 163, 184, 0.1)',
|
||||||
top: 0,
|
position: 'relative',
|
||||||
left: 0,
|
backdropFilter: 'blur(8px)',
|
||||||
right: 0,
|
'&::before': {
|
||||||
height: '1px',
|
content: '""',
|
||||||
background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.1) 50%, transparent 100%)',
|
position: 'absolute',
|
||||||
}
|
top: 0,
|
||||||
}}>
|
left: 0,
|
||||||
<Typography variant="subtitle2" sx={{
|
right: 0,
|
||||||
mb: 1,
|
height: '1px',
|
||||||
color: 'rgba(255,255,255,0.9)',
|
background: 'linear-gradient(90deg, transparent 0%, rgba(251, 191, 36, 0.3) 50%, transparent 100%)',
|
||||||
fontWeight: 'bold',
|
},
|
||||||
display: 'flex',
|
'&:hover': {
|
||||||
alignItems: 'center',
|
border: '1px solid rgba(148, 163, 184, 0.2)',
|
||||||
gap: 1
|
backgroundColor: 'rgba(15, 23, 42, 0.6)',
|
||||||
}}>
|
}
|
||||||
<Activity size={16} color="rgba(255,255,255,0.7)" />
|
}}>
|
||||||
Quick Stats
|
<Typography variant="subtitle2" sx={{
|
||||||
</Typography>
|
mb: 1.5,
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
color: 'rgba(255,255,255,0.9)',
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
fontWeight: 'bold',
|
||||||
<Typography variant="caption" sx={{ color: 'rgba(255,255,255,0.7)' }}>
|
display: 'flex',
|
||||||
Total Tools
|
alignItems: 'center',
|
||||||
|
gap: 1
|
||||||
|
}}>
|
||||||
|
<Star size={16} color="#fbbf24" />
|
||||||
|
Favorite Tools
|
||||||
</Typography>
|
</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)' }} />
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||||
|
{favorites.slice(0, 5).map((favoriteTool, index) => (
|
||||||
{/* Category Quick Access */}
|
<Box
|
||||||
<Box sx={{
|
key={index}
|
||||||
p: 2,
|
sx={{
|
||||||
backgroundColor: 'rgba(255,255,255,0.03)',
|
p: 1.5,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
border: '1px solid rgba(255,255,255,0.05)',
|
backgroundColor: 'rgba(251, 191, 36, 0.05)',
|
||||||
position: 'relative',
|
border: '1px solid rgba(251, 191, 36, 0.1)',
|
||||||
'&::before': {
|
cursor: 'pointer',
|
||||||
content: '""',
|
transition: 'all 0.2s ease-in-out',
|
||||||
position: 'absolute',
|
'&:hover': {
|
||||||
top: 0,
|
backgroundColor: 'rgba(251, 191, 36, 0.1)',
|
||||||
left: 0,
|
border: '1px solid rgba(251, 191, 36, 0.2)',
|
||||||
right: 0,
|
transform: 'translateY(-1px)',
|
||||||
height: '1px',
|
boxShadow: '0 4px 12px rgba(251, 191, 36, 0.2)',
|
||||||
background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.1) 50%, transparent 100%)',
|
}
|
||||||
}
|
}}
|
||||||
}}>
|
onClick={() => onToolClick && onToolClick({ name: favoriteTool })}
|
||||||
<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
|
<Typography variant="body2" sx={{
|
||||||
label={`${categoryId} (${toolCount})`}
|
color: 'rgba(255,255,255,0.9)',
|
||||||
size="small"
|
fontSize: '13px',
|
||||||
onClick={() => {
|
fontWeight: 500,
|
||||||
setUserHasInteracted(true);
|
display: 'flex',
|
||||||
onCategoryClick(categoryId, category);
|
alignItems: 'center',
|
||||||
}}
|
gap: 1
|
||||||
sx={{
|
}}>
|
||||||
backgroundColor: selectedCategory === categoryId
|
<Star size={12} color="#fbbf24" />
|
||||||
? 'rgba(74, 222, 128, 0.2)'
|
{favoriteTool}
|
||||||
: isRippling
|
</Typography>
|
||||||
? 'rgba(74, 222, 128, 0.15)'
|
</Box>
|
||||||
: 'rgba(255,255,255,0.05)',
|
))}
|
||||||
color: selectedCategory === categoryId || isRippling ? '#4ade80' : '#ffffff',
|
|
||||||
border: selectedCategory === categoryId
|
{favorites.length > 5 && (
|
||||||
? '1px solid rgba(74, 222, 128, 0.3)'
|
<Typography variant="caption" sx={{
|
||||||
: isRippling
|
color: 'rgba(255,255,255,0.6)',
|
||||||
? '1px solid rgba(74, 222, 128, 0.4)'
|
textAlign: 'center',
|
||||||
: '1px solid rgba(255,255,255,0.1)',
|
mt: 1,
|
||||||
cursor: 'pointer',
|
fontStyle: 'italic'
|
||||||
transition: 'all 0.2s ease-in-out',
|
}}>
|
||||||
position: 'relative',
|
+{favorites.length - 5} more favorites
|
||||||
overflow: 'hidden',
|
</Typography>
|
||||||
'&::before': isRippling ? {
|
)}
|
||||||
content: '""',
|
</Box>
|
||||||
position: 'absolute',
|
</Box>
|
||||||
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 */
|
/* Collapsed State - Enhanced Icons with Depth */
|
||||||
@@ -486,53 +459,109 @@ const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
|||||||
whileHover={{ scale: 1.1, y: -2 }}
|
whileHover={{ scale: 1.1, y: -2 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
setIsSearchExpanded(true);
|
||||||
|
setUserHasInteracted(true);
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
setTimeout(() => setIsSearchExpanded(false), 1000);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<IconButton
|
<Box sx={{ position: 'relative' }}>
|
||||||
size="small"
|
<IconButton
|
||||||
sx={{
|
size="small"
|
||||||
color: searchQuery ? '#4ade80' : 'rgba(255,255,255,0.8)',
|
sx={{
|
||||||
backgroundColor: searchQuery
|
color: searchQuery ? '#4ade80' : 'rgba(255,255,255,0.8)',
|
||||||
? '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
|
backgroundColor: searchQuery
|
||||||
? 'rgba(74, 222, 128, 0.25)'
|
? 'rgba(74, 222, 128, 0.15)'
|
||||||
: 'rgba(255,255,255,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
|
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 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 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)',
|
: '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)',
|
||||||
transform: 'translateY(-2px)'
|
backdropFilter: 'blur(10px)',
|
||||||
}
|
position: 'relative',
|
||||||
}}
|
overflow: 'hidden',
|
||||||
>
|
'&::before': {
|
||||||
<Search size={18} />
|
content: '""',
|
||||||
</IconButton>
|
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>
|
||||||
|
|
||||||
|
{/* Expanded Search Input */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{isSearchExpanded && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -20, scale: 0.8 }}
|
||||||
|
animate={{ opacity: 1, x: 0, scale: 1 }}
|
||||||
|
exit={{ opacity: 0, x: -20, scale: 0.8 }}
|
||||||
|
transition={{ duration: 0.3, ease: "easeOut" }}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: 50,
|
||||||
|
top: 0,
|
||||||
|
zIndex: 1000,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.9)',
|
||||||
|
backdropFilter: 'blur(20px)',
|
||||||
|
borderRadius: 2,
|
||||||
|
p: 1,
|
||||||
|
border: '1px solid rgba(255,255,255,0.2)',
|
||||||
|
boxShadow: '0 8px 32px rgba(0,0,0,0.3)',
|
||||||
|
minWidth: 200,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Search tools..."
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => onSearchChange(e.target.value)}
|
||||||
|
style={{
|
||||||
|
background: 'transparent',
|
||||||
|
border: 'none',
|
||||||
|
outline: 'none',
|
||||||
|
color: 'white',
|
||||||
|
fontSize: '14px',
|
||||||
|
width: '100%',
|
||||||
|
padding: '8px 12px',
|
||||||
|
}}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</Box>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
@@ -591,6 +620,134 @@ const CompactSidebar: React.FC<CompactSidebarProps> = ({
|
|||||||
</motion.div>
|
</motion.div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
|
{/* Favorites Star Icon */}
|
||||||
|
<Tooltip title="Favorite Tools">
|
||||||
|
<motion.div
|
||||||
|
whileHover={{ scale: 1.1, y: -2 }}
|
||||||
|
whileTap={{ scale: 0.95 }}
|
||||||
|
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
setIsFavoritesExpanded(true);
|
||||||
|
setUserHasInteracted(true);
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
setTimeout(() => setIsFavoritesExpanded(false), 1000);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ position: 'relative' }}>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
sx={{
|
||||||
|
color: favorites.length > 0 ? '#fbbf24' : 'rgba(255,255,255,0.8)',
|
||||||
|
backgroundColor: favorites.length > 0
|
||||||
|
? 'rgba(251, 191, 36, 0.15)'
|
||||||
|
: 'rgba(255,255,255,0.08)',
|
||||||
|
border: favorites.length > 0
|
||||||
|
? '2px solid rgba(251, 191, 36, 0.4)'
|
||||||
|
: '2px solid rgba(255,255,255,0.15)',
|
||||||
|
borderRadius: '12px',
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
boxShadow: favorites.length > 0
|
||||||
|
? '0 8px 25px rgba(251, 191, 36, 0.3), 0 0 20px rgba(251, 191, 36, 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: favorites.length > 0
|
||||||
|
? 'linear-gradient(135deg, rgba(251, 191, 36, 0.1) 0%, rgba(245, 158, 11, 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: favorites.length > 0
|
||||||
|
? 'rgba(251, 191, 36, 0.25)'
|
||||||
|
: 'rgba(255,255,255,0.15)',
|
||||||
|
boxShadow: favorites.length > 0
|
||||||
|
? '0 12px 35px rgba(251, 191, 36, 0.4), 0 0 30px rgba(251, 191, 36, 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)'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Star size={18} />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
{/* Expanded Favorites List */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{isFavoritesExpanded && favorites.length > 0 && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -20, scale: 0.8 }}
|
||||||
|
animate={{ opacity: 1, x: 0, scale: 1 }}
|
||||||
|
exit={{ opacity: 0, x: -20, scale: 0.8 }}
|
||||||
|
transition={{ duration: 0.3, ease: "easeOut" }}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: 50,
|
||||||
|
top: 0,
|
||||||
|
zIndex: 1000,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.9)',
|
||||||
|
backdropFilter: 'blur(20px)',
|
||||||
|
borderRadius: 2,
|
||||||
|
p: 1,
|
||||||
|
border: '1px solid rgba(255,255,255,0.2)',
|
||||||
|
boxShadow: '0 8px 32px rgba(0,0,0,0.3)',
|
||||||
|
minWidth: 200,
|
||||||
|
maxHeight: 300,
|
||||||
|
overflowY: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="subtitle2" sx={{
|
||||||
|
color: '#fbbf24',
|
||||||
|
mb: 1,
|
||||||
|
px: 1,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 1
|
||||||
|
}}>
|
||||||
|
<Star size={16} />
|
||||||
|
Favorite Tools
|
||||||
|
</Typography>
|
||||||
|
{favorites.map((favoriteTool, index) => (
|
||||||
|
<Box
|
||||||
|
key={index}
|
||||||
|
sx={{
|
||||||
|
p: 1,
|
||||||
|
borderRadius: 1,
|
||||||
|
cursor: 'pointer',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'rgba(255,255,255,0.1)',
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onClick={() => onToolClick && onToolClick({ name: favoriteTool })}
|
||||||
|
>
|
||||||
|
<Typography variant="body2" sx={{ color: 'white', fontSize: '12px' }}>
|
||||||
|
{favoriteTool}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</Box>
|
||||||
|
</motion.div>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
<Divider sx={{ width: '100%', borderColor: 'rgba(255,255,255,0.1)' }} />
|
<Divider sx={{ width: '100%', borderColor: 'rgba(255,255,255,0.1)' }} />
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ const EngagePillarChips: React.FC<EngagePillarChipsProps> = ({
|
|||||||
isHovered,
|
isHovered,
|
||||||
pillarColor
|
pillarColor
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
// Today's tasks for Engage pillar
|
// Today's tasks for Engage pillar
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Typography,
|
|
||||||
Chip,
|
Chip,
|
||||||
Tooltip
|
Tooltip
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
@@ -33,7 +32,7 @@ const EnhancedTodayChip: React.FC<EnhancedTodayChipProps> = ({
|
|||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
const [shouldShake, setShouldShake] = useState(false);
|
const [shouldShake, setShouldShake] = useState(false);
|
||||||
const [userManuallyClosed, setUserManuallyClosed] = useState(false);
|
const [userManuallyClosed, setUserManuallyClosed] = useState(false);
|
||||||
const { workflowProgress, navigationState, currentWorkflow } = useWorkflowStore();
|
const { currentWorkflow } = useWorkflowStore();
|
||||||
|
|
||||||
// Prefer live workflow tasks (to reflect updated statuses), fallback to props
|
// Prefer live workflow tasks (to reflect updated statuses), fallback to props
|
||||||
const liveTasks = currentWorkflow?.tasks && Array.isArray(currentWorkflow.tasks) && currentWorkflow.tasks.length > 0
|
const liveTasks = currentWorkflow?.tasks && Array.isArray(currentWorkflow.tasks) && currentWorkflow.tasks.length > 0
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const WorkflowHeroSection: React.FC<WorkflowHeroSectionProps> = ({
|
|||||||
exit={{ opacity: 0, y: -20 }}
|
exit={{ opacity: 0, y: -20 }}
|
||||||
transition={{ duration: 0.6, ease: "easeOut" }}
|
transition={{ duration: 0.6, ease: "easeOut" }}
|
||||||
>
|
>
|
||||||
{/* Backdrop Overlay - Only over pillars section */}
|
{/* Banner Overlay - Covers task workflow area with constrained width */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -49,23 +49,27 @@ const WorkflowHeroSection: React.FC<WorkflowHeroSectionProps> = ({
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
|
||||||
backdropFilter: 'blur(6px)',
|
|
||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
borderRadius: 2, // Match the parent container's border radius
|
borderRadius: 2, // Match the parent container's border radius
|
||||||
|
px: 2, // Add horizontal padding to constrain width
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Hero Content */}
|
{/* Hero Content - Full Coverage */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
maxWidth: isMobile ? '90%' : '500px',
|
|
||||||
px: 3,
|
px: 3,
|
||||||
py: 4,
|
py: 4,
|
||||||
background: 'linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%)',
|
background: 'linear-gradient(135deg, rgba(255,255,255,0.036) 0%, rgba(255,255,255,0.018) 100%)',
|
||||||
backdropFilter: 'blur(20px)',
|
backdropFilter: 'blur(20px)',
|
||||||
borderRadius: 3,
|
borderRadius: 3,
|
||||||
border: '1px solid rgba(255,255,255,0.2)',
|
border: '1px solid rgba(255,255,255,0.2)',
|
||||||
@@ -127,8 +131,29 @@ const WorkflowHeroSection: React.FC<WorkflowHeroSectionProps> = ({
|
|||||||
animate={{ opacity: 1, scale: 1 }}
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
transition={{ duration: 0.8, delay: 0.2 }}
|
transition={{ duration: 0.8, delay: 0.2 }}
|
||||||
>
|
>
|
||||||
{/* Icon */}
|
{/* Main Heading with Rocket */}
|
||||||
<Box sx={{ mb: 2 }}>
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
gap: 2,
|
||||||
|
mb: 2
|
||||||
|
}}>
|
||||||
|
<Typography
|
||||||
|
variant={isMobile ? "h5" : "h4"}
|
||||||
|
sx={{
|
||||||
|
fontWeight: 800,
|
||||||
|
color: '#ffffff',
|
||||||
|
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>
|
||||||
|
|
||||||
<motion.div
|
<motion.div
|
||||||
animate={{
|
animate={{
|
||||||
rotate: [0, 5, -5, 0],
|
rotate: [0, 5, -5, 0],
|
||||||
@@ -142,7 +167,7 @@ const WorkflowHeroSection: React.FC<WorkflowHeroSectionProps> = ({
|
|||||||
>
|
>
|
||||||
<Rocket
|
<Rocket
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: isMobile ? 40 : 48,
|
fontSize: isMobile ? 32 : 40,
|
||||||
color: '#FF6B35',
|
color: '#FF6B35',
|
||||||
filter: 'drop-shadow(0 4px 8px rgba(255,107,53,0.3))'
|
filter: 'drop-shadow(0 4px 8px rgba(255,107,53,0.3))'
|
||||||
}}
|
}}
|
||||||
@@ -150,38 +175,7 @@ const WorkflowHeroSection: React.FC<WorkflowHeroSectionProps> = ({
|
|||||||
</motion.div>
|
</motion.div>
|
||||||
</Box>
|
</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 */}
|
{/* 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 */}
|
{/* CTA Button */}
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -251,7 +245,7 @@ const WorkflowHeroSection: React.FC<WorkflowHeroSectionProps> = ({
|
|||||||
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isLoading ? 'Starting...' : '🚀 Start Your Journey'}
|
{isLoading ? 'Starting...' : 'Start Today\'s Tasks'}
|
||||||
</Button>
|
</Button>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user