diff --git a/src/components/AppHeader.tsx b/src/components/AppHeader.tsx
index 236a799..86eb809 100644
--- a/src/components/AppHeader.tsx
+++ b/src/components/AppHeader.tsx
@@ -167,7 +167,7 @@ export function AppHeader() {
"gap-1.5 flex-shrink-0",
machineErrorMessage || pyodideError
? "animate-pulse hover:animate-none"
- : "invisible pointer-events-none"
+ : "invisible pointer-events-none",
)}
title="Click to view error details"
aria-label="View error details"
diff --git a/src/components/FileUpload.tsx b/src/components/FileUpload.tsx
index e0004b8..010f815 100644
--- a/src/components/FileUpload.tsx
+++ b/src/components/FileUpload.tsx
@@ -233,188 +233,188 @@ export function FileUpload() {
- {resumeAvailable && resumeFileName && (
-
-
-
- {isLoading && !pyodideReady
- ? "Please wait - initializing Python environment..."
- : pyodideLoadingStep || "Initializing Python environment..."}
-
-
- {pyodideProgress.toFixed(0)}%
-
+ {resumeAvailable && resumeFileName && (
+
+
+ Cached: "{resumeFileName}"
+
-
-
- {isLoading && !pyodideReady
- ? "File dialog will open automatically when ready"
- : "This only happens once on first use"}
-
-
- )}
-
- {/* Error/warning messages with smooth transition - placed after buttons */}
-
- {pesData && !canUploadPattern(machineStatus) && (
-
-
- Cannot upload while {getMachineStateCategory(machineStatus)}
-
-
)}
- {pesData && boundsCheck.error && (
-
-
- Pattern too large: {boundsCheck.error}
-
-
- )}
-
+ {isLoading &&
}
- {isUploading && uploadProgress < 100 && (
-
-
-
- Uploading
-
-
- {uploadProgress > 0
- ? uploadProgress.toFixed(1) + "%"
- : "Starting..."}
-
+ {!isLoading && pesData && (
+
-
- )}
+
+ {/* Pyodide initialization progress indicator - shown when initializing or waiting */}
+ {!pyodideReady && pyodideProgress > 0 && (
+
+
+
+ {isLoading && !pyodideReady
+ ? "Please wait - initializing Python environment..."
+ : pyodideLoadingStep || "Initializing Python environment..."}
+
+
+ {pyodideProgress.toFixed(0)}%
+
+
+
+
+ {isLoading && !pyodideReady
+ ? "File dialog will open automatically when ready"
+ : "This only happens once on first use"}
+
+
+ )}
+
+ {/* Error/warning messages with smooth transition - placed after buttons */}
+
+ {pesData && !canUploadPattern(machineStatus) && (
+
+
+ Cannot upload while {getMachineStateCategory(machineStatus)}
+
+
+ )}
+
+ {pesData && boundsCheck.error && (
+
+
+ Pattern too large: {boundsCheck.error}
+
+
+ )}
+
+
+ {isUploading && uploadProgress < 100 && (
+
+
+
+ Uploading
+
+
+ {uploadProgress > 0
+ ? uploadProgress.toFixed(1) + "%"
+ : "Starting..."}
+
+
+
+
+ )}
);
diff --git a/src/components/PatternInfo.tsx b/src/components/PatternInfo.tsx
index 04256ac..a8fcc20 100644
--- a/src/components/PatternInfo.tsx
+++ b/src/components/PatternInfo.tsx
@@ -23,10 +23,18 @@ export function PatternInfo({
- Size
+
+ Size
+
- {((pesData.bounds.maxX - pesData.bounds.minX) / 10).toFixed(1)} x{" "}
- {((pesData.bounds.maxY - pesData.bounds.minY) / 10).toFixed(1)} mm
+ {((pesData.bounds.maxX - pesData.bounds.minX) / 10).toFixed(
+ 1,
+ )}{" "}
+ x{" "}
+ {((pesData.bounds.maxY - pesData.bounds.minY) / 10).toFixed(
+ 1,
+ )}{" "}
+ mm
@@ -45,7 +53,8 @@ export function PatternInfo({
{pesData.penStitches?.stitches.length.toLocaleString() ||
pesData.stitchCount.toLocaleString()}
{pesData.penStitches &&
- pesData.penStitches.stitches.length !== pesData.stitchCount && (
+ pesData.penStitches.stitches.length !==
+ pesData.stitchCount && (
{pesData.uniqueColors.slice(0, 8).map((color, idx) => {
- // Primary metadata: brand and catalog number
- const primaryMetadata = [
- color.brand,
- color.catalogNumber ? `#${color.catalogNumber}` : null,
- ]
- .filter(Boolean)
- .join(" ");
+ // Primary metadata: brand and catalog number
+ const primaryMetadata = [
+ color.brand,
+ color.catalogNumber ? `#${color.catalogNumber}` : null,
+ ]
+ .filter(Boolean)
+ .join(" ");
- // Secondary metadata: chart and description
- const secondaryMetadata = [color.chart, color.description]
- .filter(Boolean)
- .join(" ");
+ // Secondary metadata: chart and description
+ const secondaryMetadata = [color.chart, color.description]
+ .filter(Boolean)
+ .join(" ");
- const metadata = [primaryMetadata, secondaryMetadata]
- .filter(Boolean)
- .join(" • ");
+ const metadata = [primaryMetadata, secondaryMetadata]
+ .filter(Boolean)
+ .join(" • ");
- // Show which thread blocks use this color in PatternSummaryCard
- const threadNumbers = color.threadIndices
- .map((i) => i + 1)
- .join(", ");
- const tooltipText = showThreadBlocks
- ? metadata
- ? `Color ${idx + 1}: ${color.hex} - ${metadata}`
- : `Color ${idx + 1}: ${color.hex}`
- : metadata
- ? `Color ${idx + 1}: ${color.hex}\n${metadata}\nUsed in thread blocks: ${threadNumbers}`
- : `Color ${idx + 1}: ${color.hex}\nUsed in thread blocks: ${threadNumbers}`;
+ // Show which thread blocks use this color in PatternSummaryCard
+ const threadNumbers = color.threadIndices
+ .map((i) => i + 1)
+ .join(", ");
+ const tooltipText = showThreadBlocks
+ ? metadata
+ ? `Color ${idx + 1}: ${color.hex} - ${metadata}`
+ : `Color ${idx + 1}: ${color.hex}`
+ : metadata
+ ? `Color ${idx + 1}: ${color.hex}\n${metadata}\nUsed in thread blocks: ${threadNumbers}`
+ : `Color ${idx + 1}: ${color.hex}\nUsed in thread blocks: ${threadNumbers}`;
- return (
-
+ return (
+
+
+
+
+
+ {tooltipText}
+
+
+ );
+ })}
+ {pesData.uniqueColors.length > 8 && (
+
-
+
+ +{pesData.uniqueColors.length - 8}
+
-
- {tooltipText}
+
+
+ {pesData.uniqueColors.length - 8} more{" "}
+ {pesData.uniqueColors.length - 8 === 1 ? "color" : "colors"}
+
- );
- })}
- {pesData.uniqueColors.length > 8 && (
-
-
-
- +{pesData.uniqueColors.length - 8}
-
-
-
-
- {pesData.uniqueColors.length - 8} more{" "}
- {pesData.uniqueColors.length - 8 === 1 ? "color" : "colors"}
-
-
-
- )}
+ )}
diff --git a/src/components/ProgressMonitor.tsx b/src/components/ProgressMonitor.tsx
index 1c9be6a..793afe6 100644
--- a/src/components/ProgressMonitor.tsx
+++ b/src/components/ProgressMonitor.tsx
@@ -17,7 +17,13 @@ import {
canResumeSewing,
} from "../utils/machineStateHelpers";
import { calculatePatternTime } from "../utils/timeCalculation";
-import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card";
+import {
+ Card,
+ CardHeader,
+ CardTitle,
+ CardDescription,
+ CardContent,
+} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Progress } from "@/components/ui/progress";
@@ -170,246 +176,246 @@ export function ProgressMonitor() {