mirror of
https://github.com/jhbruhn/respira.git
synced 2026-01-27 10:23:41 +00:00
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>
This commit is contained in:
parent
365b0c7ae3
commit
bd80e95004
2 changed files with 45 additions and 57 deletions
|
|
@ -4,6 +4,9 @@ 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
|
||||
|
|
@ -27,61 +30,46 @@ export function PatternSummaryCard() {
|
|||
|
||||
const canDelete = canDeletePattern(machineStatus);
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 p-4 rounded-lg shadow-md border-l-4 border-primary-600 dark:border-primary-500">
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<PatternInfo pesData={pesData} />
|
||||
<PatternInfo pesData={pesData} />
|
||||
|
||||
{canDelete && (
|
||||
<button
|
||||
onClick={deletePattern}
|
||||
disabled={isDeleting}
|
||||
className="w-full flex items-center justify-center gap-2 px-3 py-2.5 sm:py-2 bg-danger-50 dark:bg-danger-900/20 text-danger-700 dark:text-danger-300 rounded border border-danger-300 dark:border-danger-700 hover:bg-danger-100 dark:hover:bg-danger-900/30 text-sm font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer"
|
||||
>
|
||||
{isDeleting ? (
|
||||
<>
|
||||
<svg
|
||||
className="w-3 h-3 animate-spin"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
></circle>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
Deleting...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<TrashIcon className="w-3 h-3" />
|
||||
Delete Pattern
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface SkeletonLoaderProps {
|
||||
className?: string;
|
||||
variant?: "text" | "rect" | "circle";
|
||||
|
|
@ -7,9 +10,6 @@ export function SkeletonLoader({
|
|||
className = "",
|
||||
variant = "rect",
|
||||
}: SkeletonLoaderProps) {
|
||||
const baseClasses =
|
||||
"animate-pulse bg-gradient-to-r from-gray-200 via-gray-300 to-gray-200 dark:from-gray-700 dark:via-gray-600 dark:to-gray-700 bg-[length:200%_100%]";
|
||||
|
||||
const variantClasses = {
|
||||
text: "h-4 rounded",
|
||||
rect: "rounded-lg",
|
||||
|
|
@ -17,7 +17,7 @@ export function SkeletonLoader({
|
|||
};
|
||||
|
||||
return (
|
||||
<div className={`${baseClasses} ${variantClasses[variant]} ${className}`} />
|
||||
<Skeleton className={cn(variantClasses[variant], className)} />
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue