mirror of
https://github.com/jhbruhn/respira.git
synced 2026-04-28 01:55:45 +00:00
Extract three complex inline components into separate files: - ThreadLegend: Thread color display with metadata (52 lines extracted) - PatternPositionIndicator: Position/rotation display with locked state (49 lines extracted) - ZoomControls: Zoom and pan control buttons (41 lines extracted) Benefits: - Reduced PatternCanvas.tsx from 730 to 608 lines (-122 lines) - Cleaner component separation and reusability - Better testability for individual UI components - Removed unused icon imports (PlusIcon, MinusIcon, etc.) - Single responsibility per component Total refactoring impact (Phase 1+2): - Before: 786 lines in single file - After: 608 lines main + 3 focused components - Reduction: -178 lines of complex inline code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
/**
|
|
* PatternPositionIndicator Component
|
|
*
|
|
* Displays the current pattern position and rotation
|
|
* Shows locked state when pattern is uploaded or being uploaded
|
|
*/
|
|
|
|
import { LockClosedIcon } from "@heroicons/react/24/solid";
|
|
|
|
interface PatternPositionIndicatorProps {
|
|
offset: { x: number; y: number };
|
|
rotation?: number;
|
|
isLocked: boolean;
|
|
isUploading: boolean;
|
|
}
|
|
|
|
export function PatternPositionIndicator({
|
|
offset,
|
|
rotation = 0,
|
|
isLocked,
|
|
isUploading,
|
|
}: PatternPositionIndicatorProps) {
|
|
return (
|
|
<div
|
|
className={`absolute bottom-16 sm:bottom-20 right-2 sm:right-5 backdrop-blur-sm p-2 sm:p-2.5 px-2.5 sm:px-3.5 rounded-lg shadow-lg z-[11] min-w-[160px] sm:min-w-[180px] transition-colors ${
|
|
isUploading || isLocked
|
|
? "bg-amber-50/95 dark:bg-amber-900/80 border-2 border-amber-300 dark:border-amber-600"
|
|
: "bg-white/95 dark:bg-gray-800/95"
|
|
}`}
|
|
>
|
|
<div className="flex items-center justify-between mb-1">
|
|
<div className="text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase tracking-wider">
|
|
Pattern Position:
|
|
</div>
|
|
{(isUploading || isLocked) && (
|
|
<div className="flex items-center gap-1 text-amber-600 dark:text-amber-400">
|
|
<LockClosedIcon className="w-3 h-3 sm:w-3.5 sm:h-3.5" />
|
|
<span className="text-xs font-bold">
|
|
{isUploading ? "UPLOADING" : "LOCKED"}
|
|
</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="text-sm font-semibold text-primary-600 dark:text-primary-400 mb-1">
|
|
X: {(offset.x / 10).toFixed(1)}mm, Y: {(offset.y / 10).toFixed(1)}mm
|
|
</div>
|
|
{!isUploading && !isLocked && rotation !== 0 && (
|
|
<div className="text-sm font-semibold text-primary-600 dark:text-primary-400 mb-1">
|
|
Rotation: {rotation.toFixed(1)}°
|
|
</div>
|
|
)}
|
|
<div className="text-xs text-gray-600 dark:text-gray-400 italic">
|
|
{isUploading
|
|
? "Uploading pattern..."
|
|
: isLocked
|
|
? "Pattern locked • Drag background to pan"
|
|
: "Drag pattern to move • Drag background to pan"}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|