respira/src/components/PatternSummaryCard.tsx
Jan-Henrik Bruhn bd80e95004 feature: Migrate SkeletonLoader and PatternSummaryCard to shadcn/ui
- Replace SkeletonLoader with shadcn Skeleton component
- Simplify gradient animation to use shadcn's built-in pulse
- Migrate PatternSummaryCard to shadcn Card and Button
- Replace custom delete button with shadcn Button (outline variant)
- Use Loader2 from lucide-react for loading spinner

Code reduction:
- SkeletonLoader: Removed 8 lines of custom gradient classes
- Delete button: ~70% reduction (200+ char className → cleaner Button)
- Card wrapper: Semantic Card structure vs verbose div classes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-20 15:44:51 +01:00

75 lines
2.5 KiB
TypeScript

import { useShallow } from "zustand/react/shallow";
import { useMachineStore } from "../stores/useMachineStore";
import { usePatternStore } from "../stores/usePatternStore";
import { canDeletePattern } from "../utils/machineStateHelpers";
import { PatternInfo } from "./PatternInfo";
import { DocumentTextIcon, TrashIcon } from "@heroicons/react/24/solid";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Loader2 } from "lucide-react";
export function PatternSummaryCard() {
// Machine store
const { machineStatus, isDeleting, deletePattern } = useMachineStore(
useShallow((state) => ({
machineStatus: state.machineStatus,
isDeleting: state.isDeleting,
deletePattern: state.deletePattern,
})),
);
// Pattern store
const { pesData, currentFileName } = usePatternStore(
useShallow((state) => ({
pesData: state.pesData,
currentFileName: state.currentFileName,
})),
);
if (!pesData) return null;
const canDelete = canDeletePattern(machineStatus);
return (
<Card className="border-l-4 border-primary-600 dark:border-primary-500">
<CardContent className="p-4">
<div className="flex items-start gap-3 mb-3">
<DocumentTextIcon className="w-6 h-6 text-primary-600 dark:text-primary-400 flex-shrink-0 mt-0.5" />
<div className="flex-1 min-w-0">
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-1">
Active Pattern
</h3>
<p
className="text-xs text-gray-600 dark:text-gray-400 truncate"
title={currentFileName}
>
{currentFileName}
</p>
</div>
</div>
<PatternInfo pesData={pesData} />
{canDelete && (
<Button
onClick={deletePattern}
disabled={isDeleting}
variant="outline"
className="w-full bg-danger-50 dark:bg-danger-900/20 text-danger-700 dark:text-danger-300 border-danger-300 dark:border-danger-700 hover:bg-danger-100 dark:hover:bg-danger-900/30"
>
{isDeleting ? (
<>
<Loader2 className="w-3 h-3 animate-spin" />
Deleting...
</>
) : (
<>
<TrashIcon className="w-3 h-3" />
Delete Pattern
</>
)}
</Button>
)}
</CardContent>
</Card>
);
}