diff --git a/Auto Run Docs/SpecKit-web-header-analyzer-Phase-03-Header-Input.md b/Auto Run Docs/SpecKit-web-header-analyzer-Phase-03-Header-Input.md index 65b918b..ec01181 100644 --- a/Auto Run Docs/SpecKit-web-header-analyzer-Phase-03-Header-Input.md +++ b/Auto Run Docs/SpecKit-web-header-analyzer-Phase-03-Header-Input.md @@ -31,7 +31,9 @@ This phase implements the user-facing input layer: a multi-line textarea for pas - [x] T016 [US1] Create main page layout in `frontend/src/app/page.tsx` with dark hacker theme (#1e1e2e background, monospace code areas, project title). Responsive from 320px to 2560px (NFR-04) - [x] T017 [P] [US1] Create `frontend/src/components/HeaderInput.tsx` — multi-line textarea for SMTP headers with placeholder, character count, clear button (FontAwesome icon), monospace styling, keyboard accessible (NFR-02), validation for empty and oversized >1MB input (NFR-10). Verify `HeaderInput.test.tsx` passes (TDD Green) - [x] T018 [P] [US1] Create `frontend/src/components/FileDropZone.tsx` — drag-and-drop zone accepting `.eml` and `.txt` files, reads client-side via File API (FR-02), populates HeaderInput on drop, shows drag-over highlight and rejection feedback, FontAwesome upload icon. Verify `FileDropZone.test.tsx` passes (TDD Green) -- [ ] T019 [US1] Create `frontend/src/components/AnalyseButton.tsx` — primary action button with FontAwesome analyse icon, Ctrl+Enter shortcut (FR-05), disabled when input empty, loading state during analysis (NFR-05), hacker accent colour. Verify `AnalyseButton.test.tsx` passes (TDD Green) +- [x] T019 [US1] Create `frontend/src/components/AnalyseButton.tsx` — primary action button with FontAwesome analyse icon, Ctrl+Enter shortcut (FR-05), disabled when input empty, loading state during analysis (NFR-05), hacker accent colour. Verify `AnalyseButton.test.tsx` passes (TDD Green) + +Note: `npx vitest run src/__tests__/AnalyseButton.test.tsx` passes; Vitest emits existing act() environment warnings. ## Completion diff --git a/frontend/src/components/AnalyseButton.tsx b/frontend/src/components/AnalyseButton.tsx new file mode 100644 index 0000000..bb4d699 --- /dev/null +++ b/frontend/src/components/AnalyseButton.tsx @@ -0,0 +1,52 @@ +"use client"; + +import { useEffect, useMemo } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faMagnifyingGlass, faSpinner } from "@fortawesome/free-solid-svg-icons"; + +type AnalyseButtonProps = { + hasInput: boolean; + onAnalyse: () => void; + isLoading?: boolean; +}; + +export default function AnalyseButton({ + hasInput, + onAnalyse, + isLoading = false, +}: AnalyseButtonProps) { + const isDisabled = useMemo(() => !hasInput || isLoading, [hasInput, isLoading]); + + useEffect(() => { + const handleShortcut = (event: KeyboardEvent) => { + if (!event.ctrlKey || event.key !== "Enter") { + return; + } + + if (isDisabled) { + return; + } + + event.preventDefault(); + onAnalyse(); + }; + + window.addEventListener("keydown", handleShortcut); + return () => { + window.removeEventListener("keydown", handleShortcut); + }; + }, [isDisabled, onAnalyse]); + + return ( + + ); +}