diff --git a/src/components/FileUpload/FileUpload.tsx b/src/components/FileUpload/FileUpload.tsx index 991cd12..da0ec2e 100644 --- a/src/components/FileUpload/FileUpload.tsx +++ b/src/components/FileUpload/FileUpload.tsx @@ -20,7 +20,7 @@ import { usePatternRotationUpload, usePatternValidation, } from "@/hooks"; -import { useDisplayFilename } from "../../hooks/domain/useDisplayFilename"; +import { getDisplayFilename } from "../../utils/displayFilename"; import { PatternInfoSkeleton } from "../SkeletonLoader"; import { PatternInfo } from "../PatternInfo"; import { DocumentTextIcon } from "@heroicons/react/24/solid"; @@ -105,7 +105,7 @@ export function FileUpload() { // Use prop pesData if available (from cached pattern), otherwise use local state const pesData = pesDataProp || localPesData; // Use currentFileName from App state, or local fileName, or resumeFileName for display - const displayFileName = useDisplayFilename({ + const displayFileName = getDisplayFilename({ currentFileName, localFileName: fileName, resumeFileName, @@ -229,6 +229,7 @@ export function FileUpload() { isConnected={isConnected} isUploading={isUploading} uploadProgress={uploadProgress} + boundsFits={boundsCheck.fits} boundsError={boundsCheck.error} onUpload={handleUpload} patternUploaded={patternUploaded} diff --git a/src/components/FileUpload/PyodideProgress.tsx b/src/components/FileUpload/PyodideProgress.tsx index d6a6538..e8c3868 100644 --- a/src/components/FileUpload/PyodideProgress.tsx +++ b/src/components/FileUpload/PyodideProgress.tsx @@ -25,7 +25,7 @@ export function PyodideProgress({
- {isFileLoading && !pyodideReady + {isFileLoading ? "Please wait - initializing Python environment..." : pyodideLoadingStep || "Initializing Python environment..."} @@ -35,7 +35,7 @@ export function PyodideProgress({

- {isFileLoading && !pyodideReady + {isFileLoading ? "File dialog will open automatically when ready" : "This only happens once on first use"}

diff --git a/src/components/FileUpload/UploadButton.tsx b/src/components/FileUpload/UploadButton.tsx index f933729..22d7912 100644 --- a/src/components/FileUpload/UploadButton.tsx +++ b/src/components/FileUpload/UploadButton.tsx @@ -17,6 +17,7 @@ interface UploadButtonProps { isConnected: boolean; isUploading: boolean; uploadProgress: number; + boundsFits: boolean; boundsError: string | null; onUpload: () => Promise; patternUploaded: boolean; @@ -28,6 +29,7 @@ export function UploadButton({ isConnected, isUploading, uploadProgress, + boundsFits, boundsError, onUpload, patternUploaded, @@ -43,7 +45,7 @@ export function UploadButton({ return (
diff --git a/src/constants/workflowSteps.ts b/src/constants/workflowSteps.ts index 63b7864..264ccea 100644 --- a/src/constants/workflowSteps.ts +++ b/src/constants/workflowSteps.ts @@ -3,9 +3,9 @@ */ export interface WorkflowStep { - id: number; - label: string; - description: string; + readonly id: number; + readonly label: string; + readonly description: string; } export const WORKFLOW_STEPS: readonly WorkflowStep[] = [ diff --git a/src/hooks/domain/useDisplayFilename.ts b/src/utils/displayFilename.ts similarity index 84% rename from src/hooks/domain/useDisplayFilename.ts rename to src/utils/displayFilename.ts index f239ed2..39cae3c 100644 --- a/src/hooks/domain/useDisplayFilename.ts +++ b/src/utils/displayFilename.ts @@ -1,5 +1,5 @@ /** - * useDisplayFilename Hook + * getDisplayFilename Utility * * Determines which filename to display based on priority: * 1. currentFileName (from pattern store) @@ -8,7 +8,7 @@ * 4. Empty string */ -export function useDisplayFilename(options: { +export function getDisplayFilename(options: { currentFileName: string | null; localFileName: string; resumeFileName: string | null; diff --git a/src/utils/threadMetadata.ts b/src/utils/threadMetadata.ts index 5433b10..0854573 100644 --- a/src/utils/threadMetadata.ts +++ b/src/utils/threadMetadata.ts @@ -1,6 +1,54 @@ /** - * Format thread metadata for display + * Format thread metadata for display. + * * Combines brand, catalog number, chart, and description into a readable string + * using the following rules: + * + * - The primary part consists of the brand and catalog number: + * - The brand (if present) appears first. + * - The catalog number (if present) is prefixed with `#` and appended after + * the brand, separated by a single space (e.g. `"DMC #310"`). + * - The secondary part consists of the chart and description: + * - The chart is omitted if it is `null`/empty or exactly equal to + * `threadCatalogNumber`. + * - The chart (when shown) and the description are joined with a single + * space (e.g. `"Anchor 24-colour Black"`). + * - The primary and secondary parts are joined with `" • "` (space, bullet, + * space). If either part is empty, only the non-empty part is returned. + * + * Examples: + * + * - Brand and catalog only: + * - Input: + * - `threadBrand: "DMC"` + * - `threadCatalogNumber: "310"` + * - `threadChart: null` + * - `threadDescription: null` + * - Output: `"DMC #310"` + * + * - Brand, catalog, and description: + * - Input: + * - `threadBrand: "DMC"` + * - `threadCatalogNumber: "310"` + * - `threadChart: null` + * - `threadDescription: "Black"` + * - Output: `"DMC #310 • Black"` + * + * - Brand, catalog, chart (different from catalog), and description: + * - Input: + * - `threadBrand: "Anchor"` + * - `threadCatalogNumber: "403"` + * - `threadChart: "24-colour"` + * - `threadDescription: "Black"` + * - Output: `"Anchor #403 • 24-colour Black"` + * + * - Chart equal to catalog number (chart omitted): + * - Input: + * - `threadBrand: "DMC"` + * - `threadCatalogNumber: "310"` + * - `threadChart: "310"` + * - `threadDescription: "Black"` + * - Output: `"DMC #310 • Black"` */ interface ThreadMetadata {