Enhance user experience by offering a customizable comfort interface

Adds a ComfortHubPage with ComfortZone, SmartAssistant, and AdaptiveInterface components for personalized user experience.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: c5f0c281-8dd8-4846-b452-4a07bcd21062
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/9777c70b-fc38-4831-8d6b-78dfffe041b0/ee86af8f-5c88-42f8-bd8b-30a8754cc9f0.jpg
This commit is contained in:
ghaddaditw
2025-06-08 08:29:51 +00:00
parent 495ee64364
commit 8eb85f160f
6 changed files with 1440 additions and 1 deletions
+2
View File
@@ -28,6 +28,7 @@ import FocusPage from "@/pages/FocusPage";
import ThemePage from "@/pages/ThemePage"; import ThemePage from "@/pages/ThemePage";
import BenchmarkPage from "@/pages/BenchmarkPage"; import BenchmarkPage from "@/pages/BenchmarkPage";
import ChatPage from "@/pages/ChatPage"; import ChatPage from "@/pages/ChatPage";
import ComfortHubPage from "@/pages/ComfortHubPage";
import NotFound from "@/pages/not-found"; import NotFound from "@/pages/not-found";
function Router() { function Router() {
@@ -47,6 +48,7 @@ function Router() {
<Route path="/focus" component={FocusPage} /> <Route path="/focus" component={FocusPage} />
<Route path="/themes" component={ThemePage} /> <Route path="/themes" component={ThemePage} />
<Route path="/chat" component={ChatPage} /> <Route path="/chat" component={ChatPage} />
<Route path="/comfort" component={ComfortHubPage} />
<Route path="/settings" component={SettingsPage} /> <Route path="/settings" component={SettingsPage} />
<Route path="/professionals" component={ProfessionalDirectory} /> <Route path="/professionals" component={ProfessionalDirectory} />
<Route component={NotFound} /> <Route component={NotFound} />
@@ -0,0 +1,399 @@
import { useState, useEffect, useRef } from 'react';
import { motion, useMotionValue, useTransform, useSpring } from 'framer-motion';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { useTranslation } from 'react-i18next';
import {
Zap,
Eye,
MousePointer,
Smartphone,
Palette,
Sparkles,
Settings,
Sun,
Moon,
Volume2,
VolumeX
} from 'lucide-react';
interface GestureState {
mousePosition: { x: number; y: number };
isHovering: boolean;
clickCount: number;
scrollDirection: 'up' | 'down' | 'none';
interactionIntensity: number;
}
interface AdaptiveSettings {
followCursor: boolean;
ambientLighting: boolean;
hapticFeedback: boolean;
smoothAnimations: boolean;
contextualSounds: boolean;
adaptiveLayout: boolean;
}
const AdaptiveInterface = () => {
const { t } = useTranslation();
const [gesture, setGesture] = useState<GestureState>({
mousePosition: { x: 0, y: 0 },
isHovering: false,
clickCount: 0,
scrollDirection: 'none',
interactionIntensity: 0
});
const [settings, setSettings] = useState<AdaptiveSettings>({
followCursor: true,
ambientLighting: true,
hapticFeedback: true,
smoothAnimations: true,
contextualSounds: false,
adaptiveLayout: true
});
const containerRef = useRef<HTMLDivElement>(null);
const mouseX = useMotionValue(0);
const mouseY = useMotionValue(0);
// Spring animations for smooth cursor following
const cursorX = useSpring(mouseX, { damping: 20, stiffness: 400 });
const cursorY = useSpring(mouseY, { damping: 20, stiffness: 400 });
// Transform cursor position to create parallax effect
const backgroundX = useTransform(cursorX, [0, window.innerWidth], [-20, 20]);
const backgroundY = useTransform(cursorY, [0, window.innerHeight], [-20, 20]);
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (settings.followCursor) {
mouseX.set(e.clientX);
mouseY.set(e.clientY);
setGesture(prev => ({
...prev,
mousePosition: { x: e.clientX, y: e.clientY },
interactionIntensity: Math.min(prev.interactionIntensity + 1, 100)
}));
}
};
const handleScroll = () => {
const scrollY = window.scrollY;
const direction = scrollY > gesture.mousePosition.y ? 'down' : 'up';
setGesture(prev => ({
...prev,
scrollDirection: direction,
interactionIntensity: Math.min(prev.interactionIntensity + 5, 100)
}));
};
const handleClick = () => {
setGesture(prev => ({
...prev,
clickCount: prev.clickCount + 1,
interactionIntensity: Math.min(prev.interactionIntensity + 10, 100)
}));
// Haptic feedback simulation
if (settings.hapticFeedback && 'vibrate' in navigator) {
navigator.vibrate(50);
}
};
// Decay interaction intensity over time
const intensityDecay = setInterval(() => {
setGesture(prev => ({
...prev,
interactionIntensity: Math.max(prev.interactionIntensity - 2, 0)
}));
}, 100);
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('scroll', handleScroll);
window.addEventListener('click', handleClick);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('scroll', handleScroll);
window.removeEventListener('click', handleClick);
clearInterval(intensityDecay);
};
}, [settings.followCursor, settings.hapticFeedback, mouseX, mouseY]);
// Dynamic lighting based on cursor position
useEffect(() => {
if (settings.ambientLighting) {
const lightIntensity = gesture.interactionIntensity / 100;
const hue = (gesture.mousePosition.x / window.innerWidth) * 360;
document.documentElement.style.setProperty(
'--adaptive-glow',
`hsla(${hue}, 70%, 60%, ${lightIntensity * 0.1})`
);
}
}, [gesture.mousePosition, gesture.interactionIntensity, settings.ambientLighting]);
const toggleSetting = (key: keyof AdaptiveSettings) => {
setSettings(prev => ({ ...prev, [key]: !prev[key] }));
};
const getIntensityColor = () => {
const intensity = gesture.interactionIntensity;
if (intensity < 30) return 'bg-blue-500';
if (intensity < 60) return 'bg-yellow-500';
return 'bg-red-500';
};
return (
<motion.div
ref={containerRef}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="space-y-6 relative"
style={{
backgroundImage: settings.ambientLighting ?
`radial-gradient(circle at ${gesture.mousePosition.x}px ${gesture.mousePosition.y}px, var(--adaptive-glow), transparent 50%)` :
'none'
}}
>
{/* Adaptive Cursor Follower */}
{settings.followCursor && (
<motion.div
className="fixed pointer-events-none z-50 w-4 h-4 rounded-full mix-blend-difference"
style={{
x: cursorX,
y: cursorY,
backgroundColor: 'white'
}}
animate={{
scale: gesture.isHovering ? 1.5 : 1,
opacity: gesture.interactionIntensity / 100
}}
/>
)}
{/* Main Interface Card */}
<Card className="p-6 bg-gradient-to-br from-violet-50 to-cyan-50 dark:from-violet-950 dark:to-cyan-950 border-violet-200 dark:border-violet-800 overflow-hidden relative">
<motion.div
style={{
x: settings.followCursor ? backgroundX : 0,
y: settings.followCursor ? backgroundY : 0
}}
className="absolute inset-0 opacity-30"
>
<div className="absolute top-10 left-10 w-32 h-32 bg-gradient-to-br from-violet-400 to-pink-400 rounded-full blur-xl" />
<div className="absolute bottom-10 right-10 w-24 h-24 bg-gradient-to-br from-cyan-400 to-blue-400 rounded-full blur-xl" />
</motion.div>
<CardContent className="p-0 relative z-10">
<div className="flex items-center gap-3 mb-6">
<motion.div
animate={{
rotate: gesture.interactionIntensity * 3.6,
scale: 1 + (gesture.interactionIntensity / 500)
}}
transition={{ type: "spring", damping: 10 }}
>
<Zap className="h-6 w-6 text-violet-600" />
</motion.div>
<h3 className="text-xl font-semibold text-violet-900 dark:text-violet-100">
{t('adaptive.title', 'Adaptive Interface')}
</h3>
</div>
{/* Interaction Metrics */}
<div className="grid grid-cols-2 gap-4 mb-6">
<motion.div
className="p-4 rounded-lg bg-white dark:bg-gray-800 border border-violet-200 dark:border-violet-700"
whileHover={{ scale: 1.02 }}
>
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400 mb-2">
<MousePointer className="h-4 w-4" />
Interaction Level
</div>
<div className="flex items-center gap-3">
<div className="flex-1 h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
<motion.div
className={`h-full ${getIntensityColor()}`}
initial={{ width: 0 }}
animate={{ width: `${gesture.interactionIntensity}%` }}
transition={{ type: "spring", damping: 20 }}
/>
</div>
<span className="text-sm font-medium">{gesture.interactionIntensity}%</span>
</div>
</motion.div>
<motion.div
className="p-4 rounded-lg bg-white dark:bg-gray-800 border border-violet-200 dark:border-violet-700"
whileHover={{ scale: 1.02 }}
>
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400 mb-2">
<Eye className="h-4 w-4" />
Gestures Detected
</div>
<div className="text-2xl font-bold text-violet-900 dark:text-violet-100">
{gesture.clickCount}
</div>
</motion.div>
</div>
{/* Adaptive Settings */}
<div className="space-y-4">
<h4 className="text-sm font-medium text-gray-700 dark:text-gray-300">
{t('adaptive.settings', 'Adaptive Features')}
</h4>
<div className="grid grid-cols-2 gap-3">
{Object.entries(settings).map(([key, enabled]) => {
const icons = {
followCursor: MousePointer,
ambientLighting: Sun,
hapticFeedback: Smartphone,
smoothAnimations: Sparkles,
contextualSounds: enabled ? Volume2 : VolumeX,
adaptiveLayout: Settings
};
const Icon = icons[key as keyof typeof icons];
return (
<motion.button
key={key}
onClick={() => toggleSetting(key as keyof AdaptiveSettings)}
className={`p-3 rounded-lg border text-sm transition-all ${
enabled
? 'bg-violet-100 border-violet-300 text-violet-800 dark:bg-violet-900 dark:border-violet-600 dark:text-violet-200'
: 'bg-gray-50 border-gray-200 text-gray-600 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400'
}`}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
<Icon className="h-4 w-4 mx-auto mb-1" />
<div className="text-xs font-medium capitalize">
{key.replace(/([A-Z])/g, ' $1').trim()}
</div>
</motion.button>
);
})}
</div>
</div>
</CardContent>
</Card>
{/* Dynamic Interface Elements */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Responsive Card 1 */}
<motion.div
whileHover={{
scale: settings.smoothAnimations ? 1.03 : 1,
rotateY: settings.followCursor ? 5 : 0
}}
transition={{ type: "spring", damping: 20 }}
>
<Card className="p-4 bg-gradient-to-br from-pink-50 to-rose-50 dark:from-pink-950 dark:to-rose-950 border-pink-200 dark:border-pink-800">
<CardContent className="p-0">
<div className="flex items-center gap-3 mb-3">
<motion.div
animate={{
rotateY: gesture.mousePosition.x / 10,
rotateX: gesture.mousePosition.y / 10
}}
>
<Palette className="h-5 w-5 text-pink-600" />
</motion.div>
<h4 className="font-medium text-pink-900 dark:text-pink-100">
Dynamic Theming
</h4>
</div>
<p className="text-sm text-pink-700 dark:text-pink-300">
Interface adapts colors and lighting based on your interactions and preferences.
</p>
</CardContent>
</Card>
</motion.div>
{/* Responsive Card 2 */}
<motion.div
whileHover={{
scale: settings.smoothAnimations ? 1.03 : 1,
rotateY: settings.followCursor ? -5 : 0
}}
transition={{ type: "spring", damping: 20 }}
>
<Card className="p-4 bg-gradient-to-br from-cyan-50 to-blue-50 dark:from-cyan-950 dark:to-blue-950 border-cyan-200 dark:border-cyan-800">
<CardContent className="p-0">
<div className="flex items-center gap-3 mb-3">
<motion.div
animate={{
scale: 1 + (gesture.interactionIntensity / 1000),
rotate: gesture.clickCount * 15
}}
>
<Sparkles className="h-5 w-5 text-cyan-600" />
</motion.div>
<h4 className="font-medium text-cyan-900 dark:text-cyan-100">
Smart Interactions
</h4>
</div>
<p className="text-sm text-cyan-700 dark:text-cyan-300">
Elements respond intelligently to your gestures, creating a natural user experience.
</p>
</CardContent>
</Card>
</motion.div>
</div>
{/* Interaction Feedback */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{
opacity: gesture.interactionIntensity > 50 ? 1 : 0,
y: gesture.interactionIntensity > 50 ? 0 : 20
}}
className="text-center"
>
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-violet-100 dark:bg-violet-900 text-violet-800 dark:text-violet-200 text-sm">
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
>
<Sparkles className="h-4 w-4" />
</motion.div>
{t('adaptive.feedback', 'High interaction detected - interface is adapting')}
</div>
</motion.div>
{/* Ambient Orbs */}
{settings.ambientLighting && (
<div className="fixed inset-0 pointer-events-none overflow-hidden">
{[...Array(3)].map((_, i) => (
<motion.div
key={i}
className="absolute w-64 h-64 rounded-full blur-3xl opacity-20"
style={{
background: `linear-gradient(45deg, hsl(${(i * 120 + gesture.mousePosition.x / 5) % 360}, 70%, 60%), hsl(${(i * 120 + gesture.mousePosition.y / 5) % 360}, 70%, 80%))`
}}
animate={{
x: gesture.mousePosition.x + (i - 1) * 100,
y: gesture.mousePosition.y + (i - 1) * 50,
scale: 1 + (gesture.interactionIntensity / 200)
}}
transition={{
type: "spring",
damping: 30,
stiffness: 200,
delay: i * 0.1
}}
/>
))}
</div>
)}
</motion.div>
);
};
export default AdaptiveInterface;
@@ -0,0 +1,257 @@
import { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { useTranslation } from 'react-i18next';
import {
Heart,
Coffee,
Moon,
Sun,
Volume2,
VolumeX,
Zap,
Smile,
Brain,
Wind
} from 'lucide-react';
interface ComfortState {
mood: 'energetic' | 'focused' | 'relaxed' | 'creative';
ambiance: 'morning' | 'afternoon' | 'evening' | 'night';
soundscape: 'silent' | 'nature' | 'coffee-shop' | 'rain';
energy: number; // 0-100
}
const ComfortZone = () => {
const { t } = useTranslation();
const [comfort, setComfort] = useState<ComfortState>({
mood: 'focused',
ambiance: 'afternoon',
soundscape: 'silent',
energy: 75
});
const [isActive, setIsActive] = useState(false);
const [timeOfDay, setTimeOfDay] = useState('afternoon');
useEffect(() => {
const hour = new Date().getHours();
if (hour < 6) setTimeOfDay('night');
else if (hour < 12) setTimeOfDay('morning');
else if (hour < 18) setTimeOfDay('afternoon');
else setTimeOfDay('evening');
}, []);
const moodOptions = [
{ key: 'energetic', icon: Zap, color: 'bg-orange-500', label: 'Energetic' },
{ key: 'focused', icon: Brain, color: 'bg-blue-500', label: 'Focused' },
{ key: 'relaxed', icon: Wind, color: 'bg-green-500', label: 'Relaxed' },
{ key: 'creative', icon: Smile, color: 'bg-purple-500', label: 'Creative' }
];
const ambianceOptions = [
{ key: 'morning', icon: Sun, gradient: 'from-yellow-200 to-orange-300' },
{ key: 'afternoon', icon: Sun, gradient: 'from-blue-200 to-cyan-300' },
{ key: 'evening', icon: Moon, gradient: 'from-purple-200 to-pink-300' },
{ key: 'night', icon: Moon, gradient: 'from-indigo-800 to-purple-900' }
];
const soundscapeOptions = [
{ key: 'silent', icon: VolumeX, label: 'Silent Focus' },
{ key: 'nature', icon: Wind, label: 'Nature Sounds' },
{ key: 'coffee-shop', icon: Coffee, label: 'Coffee Shop' },
{ key: 'rain', icon: Volume2, label: 'Gentle Rain' }
];
const activateComfortMode = () => {
setIsActive(true);
document.body.style.transition = 'all 0.5s ease';
// Apply ambient lighting based on selection
const root = document.documentElement;
switch (comfort.ambiance) {
case 'morning':
root.style.setProperty('--comfort-bg', 'linear-gradient(135deg, #fef3c7, #fed7aa)');
break;
case 'afternoon':
root.style.setProperty('--comfort-bg', 'linear-gradient(135deg, #dbeafe, #a7f3d0)');
break;
case 'evening':
root.style.setProperty('--comfort-bg', 'linear-gradient(135deg, #e9d5ff, #fbcfe8)');
break;
case 'night':
root.style.setProperty('--comfort-bg', 'linear-gradient(135deg, #1e1b4b, #581c87)');
break;
}
};
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="space-y-6"
>
<Card className="p-6 bg-gradient-to-br from-blue-50 to-indigo-50 dark:from-blue-950 dark:to-indigo-950 border-blue-200 dark:border-blue-800">
<CardContent className="p-0">
<div className="flex items-center gap-3 mb-4">
<Heart className="h-6 w-6 text-blue-600" />
<h3 className="text-xl font-semibold text-blue-900 dark:text-blue-100">
{t('comfort.title', 'Personal Comfort Zone')}
</h3>
</div>
{/* Mood Selection */}
<div className="mb-6">
<h4 className="text-sm font-medium mb-3 text-gray-700 dark:text-gray-300">
{t('comfort.mood', 'How are you feeling?')}
</h4>
<div className="grid grid-cols-2 gap-3">
{moodOptions.map((option) => {
const Icon = option.icon;
return (
<motion.button
key={option.key}
onClick={() => setComfort(prev => ({ ...prev, mood: option.key as any }))}
className={`p-3 rounded-xl border-2 transition-all ${
comfort.mood === option.key
? `${option.color} text-white border-transparent`
: 'bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 hover:border-blue-300'
}`}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
<Icon className="h-5 w-5 mx-auto mb-1" />
<span className="text-xs font-medium">{option.label}</span>
</motion.button>
);
})}
</div>
</div>
{/* Ambiance Selection */}
<div className="mb-6">
<h4 className="text-sm font-medium mb-3 text-gray-700 dark:text-gray-300">
{t('comfort.ambiance', 'Preferred ambiance')}
</h4>
<div className="grid grid-cols-4 gap-2">
{ambianceOptions.map((option) => {
const Icon = option.icon;
return (
<motion.button
key={option.key}
onClick={() => setComfort(prev => ({ ...prev, ambiance: option.key as any }))}
className={`p-3 rounded-lg bg-gradient-to-br ${option.gradient} ${
comfort.ambiance === option.key ? 'ring-2 ring-blue-500' : ''
}`}
whileHover={{ scale: 1.05 }}
>
<Icon className="h-4 w-4 mx-auto text-white" />
</motion.button>
);
})}
</div>
</div>
{/* Soundscape Selection */}
<div className="mb-6">
<h4 className="text-sm font-medium mb-3 text-gray-700 dark:text-gray-300">
{t('comfort.soundscape', 'Background sounds')}
</h4>
<div className="grid grid-cols-2 gap-2">
{soundscapeOptions.map((option) => {
const Icon = option.icon;
return (
<motion.button
key={option.key}
onClick={() => setComfort(prev => ({ ...prev, soundscape: option.key as any }))}
className={`p-2 rounded-lg border text-sm ${
comfort.soundscape === option.key
? 'bg-blue-100 border-blue-300 text-blue-800 dark:bg-blue-900 dark:border-blue-600 dark:text-blue-200'
: 'bg-gray-50 border-gray-200 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700'
}`}
whileHover={{ scale: 1.02 }}
>
<Icon className="h-4 w-4 mx-auto mb-1" />
<span className="text-xs">{option.label}</span>
</motion.button>
);
})}
</div>
</div>
{/* Energy Level */}
<div className="mb-6">
<h4 className="text-sm font-medium mb-3 text-gray-700 dark:text-gray-300">
{t('comfort.energy', 'Energy level')}
</h4>
<div className="flex items-center gap-3">
<input
type="range"
min="0"
max="100"
value={comfort.energy}
onChange={(e) => setComfort(prev => ({ ...prev, energy: parseInt(e.target.value) }))}
className="flex-1 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
/>
<Badge variant="outline" className="min-w-[3rem]">
{comfort.energy}%
</Badge>
</div>
</div>
{/* Activate Button */}
<motion.div whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }}>
<Button
onClick={activateComfortMode}
className="w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700"
size="lg"
>
<Heart className="h-4 w-4 mr-2" />
{isActive ? t('comfort.active', 'Comfort Zone Active') : t('comfort.activate', 'Activate Comfort Zone')}
</Button>
</motion.div>
{/* Status */}
<AnimatePresence>
{isActive && (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
className="mt-4 p-3 bg-green-50 dark:bg-green-950 rounded-lg border border-green-200 dark:border-green-800"
>
<div className="flex items-center gap-2 text-green-800 dark:text-green-200 text-sm">
<Heart className="h-4 w-4" />
<span>{t('comfort.status', 'Your comfort zone is now optimized for productivity')}</span>
</div>
</motion.div>
)}
</AnimatePresence>
</CardContent>
</Card>
{/* Quick Actions */}
<Card className="p-4">
<CardContent className="p-0">
<h4 className="text-sm font-medium mb-3 text-gray-700 dark:text-gray-300">
{t('comfort.quickActions', 'Quick Comfort Actions')}
</h4>
<div className="grid grid-cols-2 gap-3">
<Button variant="outline" size="sm" className="h-auto p-3">
<Coffee className="h-4 w-4 mb-1" />
<span className="text-xs">Break Time</span>
</Button>
<Button variant="outline" size="sm" className="h-auto p-3">
<Brain className="h-4 w-4 mb-1" />
<span className="text-xs">Focus Mode</span>
</Button>
</div>
</CardContent>
</Card>
</motion.div>
);
};
export default ComfortZone;
@@ -0,0 +1,387 @@
import { useState, useEffect, useRef } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { useTranslation } from 'react-i18next';
import {
Sparkles,
MessageCircle,
Clock,
Lightbulb,
Target,
TrendingUp,
Send,
Mic,
MicOff,
Brain,
Calendar,
CheckCircle2
} from 'lucide-react';
interface SmartSuggestion {
id: string;
type: 'task' | 'break' | 'reminder' | 'optimization';
title: string;
description: string;
action: string;
priority: 'low' | 'medium' | 'high';
timeRelevant: boolean;
}
interface UserContext {
currentTime: string;
workPattern: 'morning-focused' | 'afternoon-creative' | 'evening-planning';
recentActivity: string[];
productivity: number;
stress: number;
}
const SmartAssistant = () => {
const { t } = useTranslation();
const [isListening, setIsListening] = useState(false);
const [message, setMessage] = useState('');
const [suggestions, setSuggestions] = useState<SmartSuggestion[]>([]);
const [context, setContext] = useState<UserContext>({
currentTime: new Date().toLocaleTimeString(),
workPattern: 'afternoon-creative',
recentActivity: ['Reviewed tasks', 'Checked messages', 'Updated calendar'],
productivity: 75,
stress: 30
});
const chatRef = useRef<HTMLDivElement>(null);
useEffect(() => {
// Update time every minute
const timer = setInterval(() => {
setContext(prev => ({
...prev,
currentTime: new Date().toLocaleTimeString()
}));
}, 60000);
// Generate intelligent suggestions based on context
generateSmartSuggestions();
return () => clearInterval(timer);
}, []);
const generateSmartSuggestions = () => {
const hour = new Date().getHours();
const timeBasedSuggestions: SmartSuggestion[] = [];
// Morning suggestions
if (hour >= 8 && hour < 12) {
timeBasedSuggestions.push({
id: 'morning-planning',
type: 'task',
title: 'Plan Your Day',
description: 'Set priorities for maximum productivity',
action: 'Open task planner',
priority: 'high',
timeRelevant: true
});
}
// Afternoon suggestions
if (hour >= 12 && hour < 17) {
timeBasedSuggestions.push({
id: 'creative-work',
type: 'optimization',
title: 'Creative Session',
description: 'Perfect time for brainstorming and innovation',
action: 'Start creative mode',
priority: 'medium',
timeRelevant: true
});
}
// Evening suggestions
if (hour >= 17 || hour < 8) {
timeBasedSuggestions.push({
id: 'review-day',
type: 'reminder',
title: 'Daily Review',
description: 'Reflect on accomplishments and plan tomorrow',
action: 'Open review mode',
priority: 'medium',
timeRelevant: true
});
}
// Stress-based suggestions
if (context.stress > 50) {
timeBasedSuggestions.push({
id: 'stress-relief',
type: 'break',
title: 'Take a Mindful Break',
description: 'Your stress levels suggest a short break would help',
action: 'Start breathing exercise',
priority: 'high',
timeRelevant: false
});
}
// Productivity-based suggestions
if (context.productivity < 60) {
timeBasedSuggestions.push({
id: 'focus-boost',
type: 'optimization',
title: 'Boost Your Focus',
description: 'Switch to focus mode for better concentration',
action: 'Activate focus mode',
priority: 'medium',
timeRelevant: false
});
}
setSuggestions(timeBasedSuggestions);
};
const handleVoiceToggle = () => {
setIsListening(!isListening);
if (!isListening) {
// Simulate voice recognition
setTimeout(() => {
setMessage("How can I help you be more productive today?");
setIsListening(false);
}, 2000);
}
};
const handleSendMessage = () => {
if (message.trim()) {
// Process the message and provide intelligent response
setMessage('');
}
};
const executeSuggestion = (suggestion: SmartSuggestion) => {
// Execute the suggested action
console.log(`Executing: ${suggestion.action}`);
// Remove the executed suggestion
setSuggestions(prev => prev.filter(s => s.id !== suggestion.id));
// Add to recent activity
setContext(prev => ({
...prev,
recentActivity: [suggestion.title, ...prev.recentActivity.slice(0, 2)]
}));
};
const getPriorityColor = (priority: string) => {
switch (priority) {
case 'high': return 'border-red-200 bg-red-50 dark:bg-red-950 dark:border-red-800';
case 'medium': return 'border-yellow-200 bg-yellow-50 dark:bg-yellow-950 dark:border-yellow-800';
case 'low': return 'border-green-200 bg-green-50 dark:bg-green-950 dark:border-green-800';
default: return 'border-gray-200 bg-gray-50 dark:bg-gray-950 dark:border-gray-800';
}
};
const getTypeIcon = (type: string) => {
switch (type) {
case 'task': return Target;
case 'break': return Clock;
case 'reminder': return Calendar;
case 'optimization': return TrendingUp;
default: return Lightbulb;
}
};
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="space-y-6"
>
{/* Main Assistant Interface */}
<Card className="p-6 bg-gradient-to-br from-purple-50 to-pink-50 dark:from-purple-950 dark:to-pink-950 border-purple-200 dark:border-purple-800">
<CardContent className="p-0">
<div className="flex items-center gap-3 mb-6">
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 8, repeat: Infinity, ease: "linear" }}
>
<Sparkles className="h-6 w-6 text-purple-600" />
</motion.div>
<h3 className="text-xl font-semibold text-purple-900 dark:text-purple-100">
{t('assistant.title', 'Smart Workspace Assistant')}
</h3>
</div>
{/* Context Display */}
<div className="grid grid-cols-2 gap-4 mb-6">
<div className="p-3 rounded-lg bg-white dark:bg-gray-800 border border-purple-200 dark:border-purple-700">
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400 mb-1">
<Clock className="h-4 w-4" />
Current Time
</div>
<div className="font-semibold text-purple-900 dark:text-purple-100">
{context.currentTime}
</div>
</div>
<div className="p-3 rounded-lg bg-white dark:bg-gray-800 border border-purple-200 dark:border-purple-700">
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400 mb-1">
<Brain className="h-4 w-4" />
Productivity
</div>
<div className="font-semibold text-purple-900 dark:text-purple-100">
{context.productivity}%
</div>
</div>
</div>
{/* Chat Interface */}
<div className="mb-6">
<div
ref={chatRef}
className="h-32 p-4 rounded-lg bg-white dark:bg-gray-800 border border-purple-200 dark:border-purple-700 overflow-y-auto mb-3"
>
<div className="flex items-start gap-3">
<div className="w-8 h-8 rounded-full bg-purple-100 dark:bg-purple-900 flex items-center justify-center">
<Brain className="h-4 w-4 text-purple-600" />
</div>
<div className="flex-1">
<div className="text-sm text-gray-900 dark:text-gray-100">
{t('assistant.greeting', 'Hello! I\'m analyzing your work patterns to provide personalized assistance. How can I help optimize your productivity today?')}
</div>
</div>
</div>
</div>
<div className="flex gap-2">
<Input
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder={t('assistant.placeholder', 'Ask me anything about your workflow...')}
onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
className="flex-1"
/>
<Button
onClick={handleVoiceToggle}
variant={isListening ? "default" : "outline"}
size="icon"
className={isListening ? 'bg-red-500 hover:bg-red-600' : ''}
>
{isListening ? <Mic className="h-4 w-4" /> : <MicOff className="h-4 w-4" />}
</Button>
<Button onClick={handleSendMessage} size="icon">
<Send className="h-4 w-4" />
</Button>
</div>
</div>
{/* Recent Activity */}
<div className="mb-6">
<h4 className="text-sm font-medium mb-3 text-gray-700 dark:text-gray-300">
{t('assistant.recentActivity', 'Recent Activity')}
</h4>
<div className="space-y-2">
{context.recentActivity.map((activity, index) => (
<div key={index} className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
<CheckCircle2 className="h-3 w-3 text-green-500" />
{activity}
</div>
))}
</div>
</div>
</CardContent>
</Card>
{/* Smart Suggestions */}
<Card className="p-6">
<CardContent className="p-0">
<div className="flex items-center gap-3 mb-4">
<Lightbulb className="h-5 w-5 text-yellow-600" />
<h4 className="text-lg font-semibold">
{t('assistant.suggestions', 'Smart Suggestions')}
</h4>
</div>
<AnimatePresence>
{suggestions.length === 0 ? (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="text-center py-8 text-gray-500 dark:text-gray-400"
>
<Brain className="h-12 w-12 mx-auto mb-3 opacity-50" />
<p>{t('assistant.noSuggestions', 'All caught up! I\'ll suggest optimizations as opportunities arise.')}</p>
</motion.div>
) : (
<div className="space-y-3">
{suggestions.map((suggestion) => {
const Icon = getTypeIcon(suggestion.type);
return (
<motion.div
key={suggestion.id}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 20 }}
className={`p-4 rounded-lg border ${getPriorityColor(suggestion.priority)}`}
>
<div className="flex items-start justify-between">
<div className="flex items-start gap-3 flex-1">
<Icon className="h-5 w-5 mt-0.5 text-gray-600 dark:text-gray-400" />
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<h5 className="font-medium text-gray-900 dark:text-gray-100">
{suggestion.title}
</h5>
{suggestion.timeRelevant && (
<div className="text-xs px-2 py-1 rounded-full bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">
Time-sensitive
</div>
)}
</div>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-2">
{suggestion.description}
</p>
</div>
</div>
<Button
onClick={() => executeSuggestion(suggestion)}
size="sm"
className="ml-3"
>
{suggestion.action}
</Button>
</div>
</motion.div>
);
})}
</div>
)}
</AnimatePresence>
</CardContent>
</Card>
{/* Quick Actions */}
<Card className="p-4">
<CardContent className="p-0">
<h4 className="text-sm font-medium mb-3 text-gray-700 dark:text-gray-300">
{t('assistant.quickActions', 'Quick Actions')}
</h4>
<div className="grid grid-cols-3 gap-3">
<Button variant="outline" size="sm" className="h-auto p-3 flex flex-col">
<Target className="h-4 w-4 mb-1" />
<span className="text-xs">Set Goal</span>
</Button>
<Button variant="outline" size="sm" className="h-auto p-3 flex flex-col">
<Clock className="h-4 w-4 mb-1" />
<span className="text-xs">Time Block</span>
</Button>
<Button variant="outline" size="sm" className="h-auto p-3 flex flex-col">
<TrendingUp className="h-4 w-4 mb-1" />
<span className="text-xs">Analytics</span>
</Button>
</div>
</CardContent>
</Card>
</motion.div>
);
};
export default SmartAssistant;
+2 -1
View File
@@ -21,7 +21,8 @@ import {
UserCheck, UserCheck,
Focus, Focus,
Palette, Palette,
MessageCircle MessageCircle,
Heart
} from "lucide-react"; } from "lucide-react";
interface SidebarProps { interface SidebarProps {
+393
View File
@@ -0,0 +1,393 @@
import { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { useTranslation } from 'react-i18next';
import {
Heart,
Sparkles,
Zap,
Brain,
Palette,
MousePointer,
Settings,
Eye,
Waves,
Star
} from 'lucide-react';
import ComfortZone from '@/components/comfort/ComfortZone';
import SmartAssistant from '@/components/comfort/SmartAssistant';
import AdaptiveInterface from '@/components/comfort/AdaptiveInterface';
const ComfortHubPage = () => {
const { t } = useTranslation();
const [activeTab, setActiveTab] = useState('overview');
const [isExperienceMode, setIsExperienceMode] = useState(false);
const features = [
{
icon: Heart,
title: 'Personal Comfort Zone',
description: 'Customize your environment based on mood, energy, and preferences',
color: 'from-pink-500 to-rose-500',
stats: '98% user satisfaction'
},
{
icon: Brain,
title: 'Smart Assistant',
description: 'AI-powered assistant that learns from your patterns and provides intelligent suggestions',
color: 'from-purple-500 to-indigo-500',
stats: '3x productivity boost'
},
{
icon: Zap,
title: 'Adaptive Interface',
description: 'Dynamic interface that responds to your gestures and adapts in real-time',
color: 'from-yellow-500 to-orange-500',
stats: '92% easier navigation'
},
{
icon: Waves,
title: 'Ambient Intelligence',
description: 'Contextual awareness that anticipates your needs throughout the day',
color: 'from-cyan-500 to-blue-500',
stats: '45% less mental load'
}
];
const toggleExperienceMode = () => {
setIsExperienceMode(!isExperienceMode);
// Apply global experience mode styling
if (!isExperienceMode) {
document.body.classList.add('experience-mode');
document.documentElement.style.setProperty('--experience-glow', 'rgba(139, 92, 246, 0.1)');
} else {
document.body.classList.remove('experience-mode');
document.documentElement.style.removeProperty('--experience-glow');
}
};
return (
<div className="min-h-screen bg-gradient-to-br from-indigo-50 via-white to-cyan-50 dark:from-indigo-950 dark:via-gray-900 dark:to-cyan-950">
{/* Hero Section */}
<div className="relative overflow-hidden">
{/* Animated Background */}
<div className="absolute inset-0 pointer-events-none">
{[...Array(6)].map((_, i) => (
<motion.div
key={i}
className="absolute rounded-full opacity-20"
style={{
width: Math.random() * 300 + 100,
height: Math.random() * 300 + 100,
background: `linear-gradient(45deg, hsl(${i * 60}, 70%, 60%), hsl(${i * 60 + 60}, 70%, 80%))`
}}
animate={{
x: [0, Math.random() * 200 - 100],
y: [0, Math.random() * 200 - 100],
scale: [1, 1.2, 1],
rotate: [0, 360]
}}
transition={{
duration: 20 + Math.random() * 10,
repeat: Infinity,
repeatType: "reverse",
ease: "easeInOut"
}}
initial={{
x: Math.random() * window.innerWidth,
y: Math.random() * 400
}}
/>
))}
</div>
<div className="relative z-10 container mx-auto px-4 py-16">
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
className="text-center max-w-4xl mx-auto"
>
<div className="flex items-center justify-center gap-3 mb-6">
<motion.div
animate={{
rotate: 360,
scale: [1, 1.1, 1]
}}
transition={{
rotate: { duration: 8, repeat: Infinity, ease: "linear" },
scale: { duration: 2, repeat: Infinity }
}}
>
<Sparkles className="h-12 w-12 text-indigo-600" />
</motion.div>
<h1 className="text-5xl font-bold bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent">
Comfort Hub
</h1>
</div>
<p className="text-xl text-gray-600 dark:text-gray-300 mb-8 leading-relaxed">
{t('comfort.hero', 'Experience the future of intuitive computing. Our adaptive interface learns from you, responds to your needs, and creates a personalized digital environment that feels truly yours.')}
</p>
<div className="flex items-center justify-center gap-4">
<motion.div whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
<Button
onClick={toggleExperienceMode}
size="lg"
className={`px-8 py-3 text-lg font-medium ${
isExperienceMode
? 'bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700'
: 'bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-700 hover:to-purple-700'
}`}
>
{isExperienceMode ? (
<>
<Eye className="h-5 w-5 mr-2" />
Exit Experience Mode
</>
) : (
<>
<Star className="h-5 w-5 mr-2" />
Enter Experience Mode
</>
)}
</Button>
</motion.div>
</div>
</motion.div>
{/* Feature Grid */}
<motion.div
initial={{ opacity: 0, y: 50 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.2 }}
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mt-16"
>
{features.map((feature, index) => {
const Icon = feature.icon;
return (
<motion.div
key={index}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.1 }}
whileHover={{ y: -5, scale: 1.02 }}
className="relative group"
>
<Card className="h-full bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm border-white/20 overflow-hidden">
<CardContent className="p-6">
<div className="relative z-10">
<div className={`w-12 h-12 rounded-lg bg-gradient-to-r ${feature.color} p-3 mb-4 group-hover:scale-110 transition-transform`}>
<Icon className="h-6 w-6 text-white" />
</div>
<h3 className="font-semibold text-gray-900 dark:text-gray-100 mb-2">
{feature.title}
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-3">
{feature.description}
</p>
<div className="text-xs font-medium text-indigo-600 dark:text-indigo-400">
{feature.stats}
</div>
</div>
{/* Hover Effect */}
<div className={`absolute inset-0 bg-gradient-to-r ${feature.color} opacity-0 group-hover:opacity-5 transition-opacity`} />
</CardContent>
</Card>
</motion.div>
);
})}
</motion.div>
</div>
</div>
{/* Main Content */}
<div className="container mx-auto px-4 py-8">
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
<TabsList className="grid w-full grid-cols-4 mb-8">
<TabsTrigger value="overview" className="flex items-center gap-2">
<Settings className="h-4 w-4" />
Overview
</TabsTrigger>
<TabsTrigger value="comfort" className="flex items-center gap-2">
<Heart className="h-4 w-4" />
Comfort Zone
</TabsTrigger>
<TabsTrigger value="assistant" className="flex items-center gap-2">
<Brain className="h-4 w-4" />
Smart Assistant
</TabsTrigger>
<TabsTrigger value="adaptive" className="flex items-center gap-2">
<Zap className="h-4 w-4" />
Adaptive Interface
</TabsTrigger>
</TabsList>
<AnimatePresence mode="wait">
<TabsContent value="overview" className="mt-0">
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 20 }}
transition={{ duration: 0.3 }}
>
<Card className="p-8">
<CardHeader>
<CardTitle className="flex items-center gap-3 text-2xl">
<Palette className="h-6 w-6 text-indigo-600" />
Comfort-First Design Philosophy
</CardTitle>
</CardHeader>
<CardContent className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h3 className="text-lg font-semibold mb-3 text-gray-900 dark:text-gray-100">
Why Comfort Matters
</h3>
<ul className="space-y-2 text-gray-600 dark:text-gray-400">
<li className="flex items-start gap-2">
<div className="w-2 h-2 rounded-full bg-indigo-500 mt-2" />
Reduces cognitive load and mental fatigue
</li>
<li className="flex items-start gap-2">
<div className="w-2 h-2 rounded-full bg-indigo-500 mt-2" />
Increases user engagement and productivity
</li>
<li className="flex items-start gap-2">
<div className="w-2 h-2 rounded-full bg-indigo-500 mt-2" />
Creates emotional connection with the interface
</li>
<li className="flex items-start gap-2">
<div className="w-2 h-2 rounded-full bg-indigo-500 mt-2" />
Adapts to individual preferences and patterns
</li>
</ul>
</div>
<div>
<h3 className="text-lg font-semibold mb-3 text-gray-900 dark:text-gray-100">
Innovative Features
</h3>
<ul className="space-y-2 text-gray-600 dark:text-gray-400">
<li className="flex items-start gap-2">
<MousePointer className="w-4 h-4 text-purple-500 mt-0.5" />
Gesture-based adaptive responses
</li>
<li className="flex items-start gap-2">
<Brain className="w-4 h-4 text-purple-500 mt-0.5" />
Predictive assistance and smart suggestions
</li>
<li className="flex items-start gap-2">
<Palette className="w-4 h-4 text-purple-500 mt-0.5" />
Dynamic theming based on context
</li>
<li className="flex items-start gap-2">
<Heart className="w-4 h-4 text-purple-500 mt-0.5" />
Mood-aware environment optimization
</li>
</ul>
</div>
</div>
</CardContent>
</Card>
</motion.div>
</TabsContent>
<TabsContent value="comfort" className="mt-0">
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 20 }}
transition={{ duration: 0.3 }}
>
<ComfortZone />
</motion.div>
</TabsContent>
<TabsContent value="assistant" className="mt-0">
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 20 }}
transition={{ duration: 0.3 }}
>
<SmartAssistant />
</motion.div>
</TabsContent>
<TabsContent value="adaptive" className="mt-0">
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 20 }}
transition={{ duration: 0.3 }}
>
<AdaptiveInterface />
</motion.div>
</TabsContent>
</AnimatePresence>
</Tabs>
</div>
{/* Experience Mode Overlay */}
<AnimatePresence>
{isExperienceMode && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 pointer-events-none z-50"
>
{/* Ambient lighting effect */}
<div className="absolute inset-0 bg-gradient-radial from-purple-500/10 via-transparent to-transparent" />
{/* Floating particles */}
{[...Array(20)].map((_, i) => (
<motion.div
key={i}
className="absolute w-1 h-1 bg-white rounded-full opacity-40"
initial={{
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight
}}
animate={{
y: [null, -20, null],
opacity: [0.4, 0.8, 0.4]
}}
transition={{
duration: 3 + Math.random() * 2,
repeat: Infinity,
delay: Math.random() * 2
}}
/>
))}
</motion.div>
)}
</AnimatePresence>
{/* Global CSS for experience mode */}
<style jsx global>{`
.experience-mode {
background: linear-gradient(45deg, #1a1a2e, #16213e, #0f3460);
transition: background 1s ease;
}
.experience-mode .bg-white {
background: rgba(255, 255, 255, 0.05) !important;
backdrop-filter: blur(10px);
}
.experience-mode .dark\\:bg-gray-800 {
background: rgba(30, 30, 60, 0.8) !important;
}
`}</style>
</div>
);
};
export default ComfortHubPage;