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:
@@ -28,6 +28,7 @@ import FocusPage from "@/pages/FocusPage";
|
||||
import ThemePage from "@/pages/ThemePage";
|
||||
import BenchmarkPage from "@/pages/BenchmarkPage";
|
||||
import ChatPage from "@/pages/ChatPage";
|
||||
import ComfortHubPage from "@/pages/ComfortHubPage";
|
||||
import NotFound from "@/pages/not-found";
|
||||
|
||||
function Router() {
|
||||
@@ -47,6 +48,7 @@ function Router() {
|
||||
<Route path="/focus" component={FocusPage} />
|
||||
<Route path="/themes" component={ThemePage} />
|
||||
<Route path="/chat" component={ChatPage} />
|
||||
<Route path="/comfort" component={ComfortHubPage} />
|
||||
<Route path="/settings" component={SettingsPage} />
|
||||
<Route path="/professionals" component={ProfessionalDirectory} />
|
||||
<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;
|
||||
@@ -21,7 +21,8 @@ import {
|
||||
UserCheck,
|
||||
Focus,
|
||||
Palette,
|
||||
MessageCircle
|
||||
MessageCircle,
|
||||
Heart
|
||||
} from "lucide-react";
|
||||
|
||||
interface SidebarProps {
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user