veza/apps/web/src/components/views/SocialView.tsx
senke ed011ddd45 feat: Visual masterpiece - true light mode & premium UI
🎨 **True Light/Dark Mode**
- Implemented proper light mode with inverted color scheme
- Smooth theme transitions (0.3s ease)
- Light mode colors: white backgrounds, dark text, vibrant accents
- System theme detection with proper class application

🌈 **Enhanced Theme System**
- 4 color themes work in both light and dark modes
- Cyber (cyan/magenta), Ocean (blue/teal), Forest (green/lime), Sunset (orange/purple)
- Theme-specific glassmorphism effects
- Proper contrast in light mode

 **Premium Animations**
- Float, glow-pulse, slide-in, scale-in, rotate-in animations
- Smooth page transitions
- Hover effects with depth (lift, glow, scale)
- Micro-interactions on all interactive elements

🎯 **Visual Polish**
- Enhanced glassmorphism for light/dark modes
- Custom scrollbar with theme colors
- Beautiful text selection
- Focus indicators for accessibility
- Premium utility classes

🔧 **Technical Improvements**
- Updated UIStore to properly apply light/dark classes
- Added data-theme attribute for CSS targeting
- Smooth scroll behavior
- Optimized transitions

The app is now a visual masterpiece with perfect light/dark mode support!
2026-01-11 02:32:21 +01:00

141 lines
7.5 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { Card } from '../ui/card';
import { Button } from '../ui/button';
import { TrendingUp, Users, Hash, MoreHorizontal, Play } from 'lucide-react';
import { trackService } from '@/services/trackService';
import { useToast } from '@/context/ToastContext';
import { useAudio } from '@/context/AudioContext';
import { Track } from '@/types/api';
import { logger } from '@/utils/logger';
interface SocialViewProps {
onViewProfile: (userId: string | null) => void;
}
export const SocialView: React.FC<SocialViewProps> = ({ onViewProfile }) => {
const { addToast: _addToast } = useToast();
const { playTrack } = useAudio();
const [activeTab, setActiveTab] = useState('feed');
const [feedTracks, setFeedTracks] = useState<Track[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadFeed = async () => {
setLoading(true);
try {
// Using recent tracks as the "Feed"
const res = await trackService.list({ limit: 10, sort_by: 'created_at' });
setFeedTracks(res.tracks);
} catch (e) {
logger.error('Error loading feed tracks', {
error: e instanceof Error ? e.message : String(e),
stack: e instanceof Error ? e.stack : undefined,
});
} finally {
setLoading(false);
}
};
loadFeed();
}, []);
return (
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 animate-fadeIn pb-20">
{/* Sidebar */}
<div className="hidden lg:block lg:col-span-3 space-y-6">
<Card variant="glass" className="p-0 overflow-hidden">
<div className="h-20 bg-gradient-gaming"></div>
<div className="px-4 pb-4">
<div className="relative -mt-10 mb-3 cursor-pointer" onClick={() => onViewProfile(null)}>
<div className="w-20 h-20 rounded-full border-4 border-kodo-graphite overflow-hidden bg-black">
<img src="https://picsum.photos/id/237/200/200" className="w-full h-full object-cover" />
</div>
</div>
<h3 className="font-bold text-white text-lg">My Profile</h3>
<p className="text-sm text-gray-400 mb-4">View your stats</p>
</div>
</Card>
<Card variant="default" className="p-2">
<nav className="space-y-1">
<button onClick={() => setActiveTab('feed')} className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium ${activeTab === 'feed' ? 'bg-kodo-cyan/10 text-kodo-cyan' : 'text-gray-400 hover:text-white'}`}>
<TrendingUp className="w-4 h-4" /> Fresh Tracks
</button>
<button className="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium text-gray-400 hover:text-white">
<Users className="w-4 h-4" /> Communities
</button>
</nav>
</Card>
</div>
{/* Feed Content */}
<div className="col-span-1 lg:col-span-6 space-y-6">
<div className="mb-4">
<h2 className="text-2xl font-bold text-white mb-1">Community Feed</h2>
<p className="text-gray-400 text-xs">New uploads from the network</p>
</div>
{loading ? (
<div className="text-center py-10">Loading feed...</div>
) : (
feedTracks.map(track => (
<Card key={track.id} variant="default" className="p-0 overflow-hidden mb-4 border-transparent hover:border-kodo-steel/50">
<div className="p-4 flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-gray-700 overflow-hidden">
<img src={track.coverUrl} className="w-full h-full object-cover" />
</div>
<div>
<div className="font-bold text-white text-sm">{track.artist}</div>
<div className="text-xs text-gray-500">uploaded a new track</div>
</div>
<Button variant="ghost" size="sm" className="ml-auto"><MoreHorizontal className="w-4 h-4" /></Button>
</div>
{/* Track Embed Look */}
<div className="px-4 pb-4">
<div className="bg-kodo-ink p-3 rounded-xl flex items-center gap-4 border border-kodo-steel group cursor-pointer" onClick={() => playTrack(track)}>
<div className="w-16 h-16 rounded overflow-hidden relative">
<img src={track.coverUrl} className="w-full h-full object-cover" />
<div className="absolute inset-0 bg-black/30 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
<Play className="w-6 h-6 text-white fill-current" />
</div>
</div>
<div className="flex-1">
<h4 className="font-bold text-white">{track.title}</h4>
<p className="text-xs text-gray-400">{track.genre || 'Electronic'}</p>
</div>
<div className="text-xs text-gray-500 font-mono pr-2">{track.duration}</div>
</div>
</div>
<div className="px-4 py-3 border-t border-kodo-steel/30 flex gap-4 text-xs text-gray-400">
<button className="hover:text-white">Like ({track.like_count})</button>
<button className="hover:text-white">Comment</button>
<button className="hover:text-white">Share</button>
</div>
</Card>
))
)}
{feedTracks.length === 0 && !loading && (
<div className="text-center py-20 text-gray-500">No recent activity.</div>
)}
</div>
{/* Right Sidebar */}
<div className="hidden lg:block lg:col-span-3 space-y-6">
<Card variant="manga">
<h3 className="font-bold text-sm text-gray-300 uppercase tracking-wider mb-4 flex items-center gap-2">
<Hash className="w-4 h-4 text-kodo-magenta" /> Trending Tags
</h3>
<div className="flex flex-wrap gap-2">
{['#Techno', '#Synthwave', '#NewGear', '#Tutorial'].map(t => (
<span key={t} className="text-xs bg-black/20 px-2 py-1 rounded text-gray-400 cursor-pointer hover:text-white hover:bg-black/40">{t}</span>
))}
</div>
</Card>
</div>
</div>
);
};