mirror of
https://github.com/jhbruhn/respira.git
synced 2026-03-13 18:28:41 +00:00
- Move FileUpload into dedicated folder with sub-components - Extract FileSelector, PyodideProgress, UploadButton, UploadProgress, BoundsValidator - Create useDisplayFilename hook for filename priority logic - Reduce FileUpload.tsx from 391 to 261 lines (33% reduction) Part of #33: Extract sub-components from large components 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
92 lines
2.4 KiB
TypeScript
92 lines
2.4 KiB
TypeScript
/**
|
|
* FileSelector Component
|
|
*
|
|
* Renders file input and selection button, handles native vs web file selection
|
|
*/
|
|
|
|
import { FolderOpenIcon, CheckCircleIcon } from "@heroicons/react/24/solid";
|
|
import { Loader2 } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import type { IFileService } from "../../platform/interfaces/IFileService";
|
|
|
|
interface FileSelectorProps {
|
|
fileService: IFileService;
|
|
isLoading: boolean;
|
|
isDisabled: boolean;
|
|
onFileChange: (event?: React.ChangeEvent<HTMLInputElement>) => Promise<void>;
|
|
displayFileName: string;
|
|
patternUploaded: boolean;
|
|
}
|
|
|
|
export function FileSelector({
|
|
fileService,
|
|
isLoading,
|
|
isDisabled,
|
|
onFileChange,
|
|
patternUploaded,
|
|
}: FileSelectorProps) {
|
|
const hasNativeDialogs = fileService.hasNativeDialogs();
|
|
|
|
return (
|
|
<>
|
|
<input
|
|
type="file"
|
|
accept=".pes"
|
|
onChange={onFileChange}
|
|
id="file-input"
|
|
className="hidden"
|
|
disabled={isDisabled}
|
|
/>
|
|
<Button
|
|
asChild={!hasNativeDialogs && !isDisabled}
|
|
onClick={hasNativeDialogs ? () => onFileChange() : undefined}
|
|
disabled={isDisabled}
|
|
variant="outline"
|
|
className="flex-[2]"
|
|
>
|
|
{hasNativeDialogs ? (
|
|
<>
|
|
{isLoading ? (
|
|
<>
|
|
<Loader2 className="w-3.5 h-3.5 animate-spin" />
|
|
<span>Loading...</span>
|
|
</>
|
|
) : patternUploaded ? (
|
|
<>
|
|
<CheckCircleIcon className="w-3.5 h-3.5" />
|
|
<span>Locked</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<FolderOpenIcon className="w-3.5 h-3.5" />
|
|
<span>Choose PES File</span>
|
|
</>
|
|
)}
|
|
</>
|
|
) : (
|
|
<label
|
|
htmlFor="file-input"
|
|
className="flex items-center gap-2 cursor-pointer"
|
|
>
|
|
{isLoading ? (
|
|
<>
|
|
<Loader2 className="w-3.5 h-3.5 animate-spin" />
|
|
<span>Loading...</span>
|
|
</>
|
|
) : patternUploaded ? (
|
|
<>
|
|
<CheckCircleIcon className="w-3.5 h-3.5" />
|
|
<span>Locked</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<FolderOpenIcon className="w-3.5 h-3.5" />
|
|
<span>Choose PES File</span>
|
|
</>
|
|
)}
|
|
</label>
|
|
)}
|
|
</Button>
|
|
</>
|
|
);
|
|
}
|