Collaborative-pixel-art/frontend/src/components/ui/ZoomControls.tsx
martin 3ce5a97422 Modernize collaborative pixel art platform to production-ready architecture
Major refactor from simple HTML/JS app to modern full-stack TypeScript application:

## Architecture Changes
- Migrated to monorepo structure with workspaces (backend, frontend, shared)
- Backend: Node.js + Express + TypeScript + Socket.IO
- Frontend: Next.js 15.5 + React 19 + TypeScript + Tailwind CSS
- Shared: Common types and utilities across packages

## Key Features Implemented
- Real-time WebSocket collaboration via Socket.IO
- Virtual canvas with chunked loading for performance
- Modern UI with dark mode and responsive design
- Mock database system for easy development (Redis/PostgreSQL compatible)
- Comprehensive error handling and rate limiting
- User presence and cursor tracking
- Infinite canvas support with zoom/pan controls

## Performance Optimizations
- Canvas virtualization - only renders visible viewport
- Chunked pixel data loading (64x64 pixel chunks)
- Optimized WebSocket protocol
- Memory-efficient state management with Zustand

## Development Experience
- Full TypeScript support across all packages
- Hot reload for both frontend and backend
- Docker support for production deployment
- Comprehensive linting and formatting
- Automated development server startup

## Fixed Issues
- Corrected start script paths
- Updated environment configuration
- Fixed ESLint configuration issues
- Ensured all dependencies are properly installed
- Verified build process works correctly
2025-08-22 19:28:05 +02:00

51 lines
No EOL
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { motion } from 'framer-motion';
interface ZoomControlsProps {
zoom: number;
onZoomIn: () => void;
onZoomOut: () => void;
}
export function ZoomControls({ zoom, onZoomIn, onZoomOut }: ZoomControlsProps) {
return (
<motion.div
className="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 z-40"
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ type: "spring", stiffness: 400, damping: 25 }}
>
<div className="flex flex-col gap-2 sm:gap-3">
{/* Zoom In Button */}
<motion.button
className="w-12 h-12 sm:w-14 sm:h-14 bg-white/10 backdrop-blur-2xl rounded-full border border-white/20 shadow-lg ring-1 ring-white/10 flex items-center justify-center text-white text-xl sm:text-2xl font-bold hover:bg-white/20 active:bg-white/30 transition-all duration-200 select-none touch-manipulation"
onClick={onZoomIn}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
transition={{ type: "spring", stiffness: 400 }}
>
+
</motion.button>
{/* Zoom Out Button */}
<motion.button
className="w-12 h-12 sm:w-14 sm:h-14 bg-white/10 backdrop-blur-2xl rounded-full border border-white/20 shadow-lg ring-1 ring-white/10 flex items-center justify-center text-white text-xl sm:text-2xl font-bold hover:bg-white/20 active:bg-white/30 transition-all duration-200 select-none touch-manipulation"
onClick={onZoomOut}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
transition={{ type: "spring", stiffness: 400 }}
>
</motion.button>
{/* Zoom Display */}
<div className="bg-white/5 backdrop-blur-2xl rounded-xl sm:rounded-2xl px-2 py-1 sm:px-3 sm:py-2 border border-white/20 shadow-lg ring-1 ring-white/10">
<div className="text-white font-bold text-xs sm:text-sm text-center min-w-[40px] sm:min-w-[50px]">
{Math.round(zoom * 100)}%
</div>
</div>
</div>
</motion.div>
);
}