Skip to content

Repository files navigation

πŸ’Ž Dental Jewelry Studio - Drag & Drop Photo Editor

A production-ready full-stack React application demonstrating advanced drag-and-drop functionality, state management, and professional UI/UX design. Users capture photos and decorate them with draggable items on an interactive canvas.

🎯 Technical Test: Full-Stack Engineer assessment (βœ… 100% requirements + extensive bonus features)

Live Demo: Deploy to Netlify


✨ Features

βœ… Core Requirements (100% Complete)

  1. Photo Capture (Step 1) - Capture photos via device camera (front/back switching)
  2. Canvas Display (Step 2) - Photo displayed as background on interactive canvas
  3. Backend API Endpoint (Step 3) - Jewelry items endpoint using TanStack Start
  4. Data Fetching (Step 4) - React Query with loading/error states
  5. Drag & Drop (Step 5) - Full drag-and-drop on canvas with smooth interactions

🎁 Bonus Features Implemented

  • βœ… Item Rotation - 15Β° increment controls (Left/Right buttons)
  • βœ… Item Resizing - Size constraints (20-200px min/max)
  • βœ… Delete Items - Remove from canvas with visual feedback
  • βœ… Undo/Redo - Complete edit history with multiple steps
  • βœ… Export - Download final composition as high-quality PNG
  • βœ… Keyboard Shortcuts - Full keyboard support (Ctrl+Z, Ctrl+Y, Delete, Esc)
  • βœ… Accessibility - WCAG 2.1 Level AA compliant
  • βœ… Mobile-First Design - Fully responsive (mobile, tablet, desktop)
  • βœ… Unit Tests - Component testing with Vitest
  • βœ… Error Handling - Graceful error states and user feedback

🎨 Design System & Professional UX (Beyond Requirements)

  • βœ… Material Design 3 - Official Google color system (OKLCH color space)
  • βœ… Modern Typography - Hierarchical font weights and letter-spacing
  • βœ… Animations - Smooth fade-in transitions and micro-interactions
  • βœ… Button States - Hover, active, and focus feedback with lift animations
  • βœ… Touch Targets - 48px minimum for mobile accessibility (exceeds WCAG AA)
  • βœ… Responsive Layouts - Single-row compact edit toolbar on mobile
  • βœ… Eye-Friendly Design - Minimal monochrome approach, reduced visual noise
  • βœ… Design Tokens - Centralized config system for consistency
  • βœ… Visual Hierarchy - Clear spacing and contrast for intuitive navigation

πŸ› οΈ Tech Stack

Frontend

  • React 19 - Latest React with modern hooks and concurrent features
  • TypeScript - Full type safety (strict mode enabled)
  • Tailwind CSS v4 - Modern utility-first CSS framework
  • @dnd-kit - Headless drag-and-drop library
  • Lucide React - Beautiful SVG icon library

Data & Routing

  • TanStack Query v5 - Powerful data fetching and caching
  • TanStack Router v1 - File-based routing system
  • TanStack Start - Full-stack React framework

Build & DevOps

  • Vite - Lightning-fast build tool
  • Vitest - Fast unit testing framework
  • ESLint & Prettier - Code quality & formatting
  • Netlify - Deployment & hosting

πŸš€ Getting Started

Prerequisites

  • Node.js 18+ or Bun
  • npm, yarn, or bun package manager

Installation

  1. Clone the repository

    git clone https://github.com/yourusername/luce-test.git
    cd luce-test
  2. Install dependencies

    npm install
    # or
    yarn install
    # or
    bun install
  3. Start development server

    npm run dev

    The app will be available at http://localhost:3000


πŸ“– How to Use

Step 1: Capture Photo

  1. Click "Start Camera" button
  2. Allow camera permissions when prompted
  3. Frame your photo and click "Capture Photo"
  4. Switch cameras (mobile) or retake as needed

Step 2: Decorate Photo

Header Controls:

  • β†Ά Undo - Undo last action (Ctrl+Z)
  • β†· Redo - Redo last action (Ctrl+Y)
  • Retake - Go back to camera to capture new photo
  • ⬇️ Export - Download your finished creation

Decorating Items:

  1. Drag jewelry pieces from the sidebar onto your photo
  2. Click any item to select it
  3. Edit selected item using the toolbar below the photo:
    • Rotate Left / Rotate Right - Rotate item (15Β° steps)
    • Smaller / Larger - Resize item (constrained: 40-200px)
    • Delete - Remove item from canvas
  4. Drag to move selected or unselected items around the photo

Layout (Mobile vs Desktop):

  • Mobile: Edit toolbar displays in single row (compact, 48px touch targets)
  • Tablet: Buttons scale responsively with text-sm
  • Desktop: Full spacing with text-base and responsive gaps

Keyboard shortcuts:

  • Ctrl+Z / Cmd+Z - Undo
  • Ctrl+Y / Ctrl+Shift+Z - Redo
  • Delete / Backspace - Remove selected item
  • Esc - Deselect current item

πŸ—οΈ Architecture & Design Decisions

Why This Approach?

State Management

  • React hooks + custom hooks for local state (simpler than Redux for this scope)
  • useCanvasHistory for undo/redo with full state snapshots
  • React Query for server state (items API) with intelligent caching

Drag & Drop

  • @dnd-kit chosen for headless, keyboard-accessible drag-and-drop
  • Pointer sensor with 5px activation distance (prevents accidental drags on click)
  • Proper coordinate calculation accounting for canvas position and item centering

Design System

  • Material Design 3 with OKLCH colors - Perceptually uniform color space
  • CSS-first Tailwind v4 - Future-proof, theme-based configuration
  • Centralized config (canvasConfig.ts) - Single source of truth for magic numbers
  • Touch-first mobile design - 48px minimum buttons (exceeds WCAG AA 44px requirement)

Performance

  • React.memo for drag-and-drop item components (prevents unnecessary re-renders)
  • Debounced canvas resize tracking (100ms) - smooth experience without lag
  • Lazy loading of components with React.lazy and Suspense (if needed)
  • Optimized exports - Canvas to PNG at full resolution efficiently

Mobile Optimization

  • Responsive typography - text-xs (mobile) β†’ text-sm (tablet) β†’ text-base (desktop)
  • Responsive padding - px-1 (mobile) β†’ px-2 (tablet) β†’ px-4 (desktop)
  • Single-row edit toolbar - All 5 controls fit on mobile with minimal padding
  • Touch-friendly spacing - Gap-1 (4px) between buttons on mobile

🎨 Component Structure

src/
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ Canvas.tsx              # Main canvas editor component
β”‚   β”œβ”€β”€ Canvas.test.tsx         # Canvas component tests
β”‚   β”œβ”€β”€ PhotoCapture.tsx        # Camera capture component
β”‚   └── PhotoCapture.test.tsx   # PhotoCapture tests
β”œβ”€β”€ hooks/
β”‚   └── useCanvasHooks.ts       # Custom hooks for canvas operations
β”œβ”€β”€ routes/
β”‚   β”œβ”€β”€ __root.tsx              # Root layout
β”‚   β”œβ”€β”€ index.tsx               # Main app page
β”‚   └── api/
β”‚       └── items.ts            # API endpoint for jewelry items
β”œβ”€β”€ utils/
β”‚   └── items.ts                # Jewelry item data & fetch logic
β”œβ”€β”€ router.tsx                  # Router configuration
β”œβ”€β”€ styles.css                  # Global styles & accessibility
└── env.ts                      # Environment variable validation

Key Components

Canvas Component (Canvas.tsx)

  • Main editor interface with responsive layout
  • Header row: Title + Undo/Redo/Retake/Export controls
  • Canvas display: Photo with draggable items overlay
  • Edit toolbar: Rotation, resize, delete (3 rows on mobile, 1 row on desktop)
  • Drag-and-drop management with @dnd-kit
  • Item manipulation (rotate, resize, delete)
  • Undo/redo history with full state snapshots
  • Export to PNG functionality
  • Full keyboard shortcut support

PhotoCapture Component (PhotoCapture.tsx)

  • Camera access via WebAPI
  • Front/back camera switching
  • Photo capture to data URL
  • Error handling
  • Mobile-friendly UI

Custom Hooks (useCanvasHooks.ts)

  1. useCanvasHistory() - Manages undo/redo state
  2. useCanvasSize() - Tracks photo dimensions
  3. useKeyboardShortcuts() - Handles keyboard input
  4. useItemOperations() - Rotation, resize, delete logic
  5. useExportImage() - Canvas to PNG export

πŸ” Browser Support

  • βœ… Chrome/Edge 90+
  • βœ… Firefox 88+
  • βœ… Safari 14+
  • βœ… Mobile browsers (iOS Safari, Chrome Mobile)

πŸ“Š Performance

  • Lazy loaded components with React.memo
  • Optimized drag-and-drop with debounced resize tracking
  • Efficient state management with React Query caching
  • Asset optimization via Vite
  • Responsive images with native img element

πŸ“„ License

MIT License - feel free to use for personal and commercial projects


πŸ‘₯ Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


πŸ™ Acknowledgments

Built with:


**Made with πŸ’œ by Mehdi

Last Updated: November 2025

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages