import 'package:flutter/material.dart'; import '../constants.dart'; import '../models/entry_drag_state.dart'; import '../services/layout_coordinate_service.dart'; import '../services/time_scale_service.dart'; import '../state/timeline_viewport_notifier.dart'; /// A semi-transparent ghost overlay showing where an entry will land. /// /// Displayed during drag operations to give visual feedback about the /// target position. class GhostOverlay extends StatelessWidget { const GhostOverlay({ required this.dragState, required this.viewport, required this.contentWidth, required this.laneHeight, super.key, }); final EntryDragState dragState; final TimelineViewportNotifier viewport; final double contentWidth; final double laneHeight; @override Widget build(BuildContext context) { final startX = TimeScaleService.mapTimeToPosition( dragState.targetStart, viewport.start, viewport.end, ); final endX = TimeScaleService.mapTimeToPosition( dragState.targetEnd, viewport.start, viewport.end, ); // Use centralized coordinate service to ensure ghost matches pill layout final left = LayoutCoordinateService.normalizedToWidgetX( normalizedX: startX, contentWidth: contentWidth, ); final width = LayoutCoordinateService.calculateItemWidth( normalizedWidth: endX - startX, contentWidth: contentWidth, ); final top = LayoutCoordinateService.laneToY( lane: dragState.targetLane, laneHeight: laneHeight, ); final scheme = Theme.of(context).colorScheme; return Positioned( left: left.clamp(0.0, double.infinity), width: width.clamp(0.0, double.infinity), top: top, height: laneHeight, child: IgnorePointer( child: Container( decoration: BoxDecoration( color: scheme.primary.withValues(alpha: 0.3), borderRadius: BorderRadius.circular( ZTimelineConstants.pillBorderRadius, ), border: Border.all( color: scheme.primary.withValues(alpha: 0.6), width: 2, ), ), ), ), ); } }