diff --git a/src/client/components/Modal.tsx b/src/client/components/Modal.tsx
index 68eafa2..203d1c5 100644
--- a/src/client/components/Modal.tsx
+++ b/src/client/components/Modal.tsx
@@ -1,15 +1,35 @@
-import type { ReactNode } from "react";
+import { useEffect, type ReactNode } from "react";
export function Modal({
maxWidth = "max-w-sm",
children,
+ onClose,
+ labelledBy,
}: {
maxWidth?: string;
children: ReactNode;
+ onClose?: () => void;
+ labelledBy?: string;
}) {
+ useEffect(() => {
+ if (!onClose) return;
+
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key !== "Escape" || event.defaultPrevented) return;
+ event.preventDefault();
+ onClose();
+ };
+
+ window.addEventListener("keydown", handleKeyDown);
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, [onClose]);
+
return (
{children}
diff --git a/src/client/components/table/ExportToSheetsModal.tsx b/src/client/components/table/ExportToSheetsModal.tsx
index 896b0a8..2971519 100644
--- a/src/client/components/table/ExportToSheetsModal.tsx
+++ b/src/client/components/table/ExportToSheetsModal.tsx
@@ -28,13 +28,17 @@ export function ExportToSheetsModal() {
};
return (
-
+
-
+
Copied {rowCount} row{rowCount === 1 ? "" : "s"} to your clipboard
diff --git a/src/client/features/rank-tracking/CheckConfirmModal.tsx b/src/client/features/rank-tracking/CheckConfirmModal.tsx
index c33fa65..93a8f6e 100644
--- a/src/client/features/rank-tracking/CheckConfirmModal.tsx
+++ b/src/client/features/rank-tracking/CheckConfirmModal.tsx
@@ -34,9 +34,13 @@ export function CheckConfirmModal({
Math.ceil(totalChecks / KEYWORDS_PER_BATCH) * SECONDS_PER_BATCH;
return (
-
+
-
+
Check {keywordCount} keyword
{keywordCount !== 1 ? "s" : ""}
diff --git a/src/client/features/rank-tracking/KeywordSuggestionStep.tsx b/src/client/features/rank-tracking/KeywordSuggestionStep.tsx
index edaf762..7405ce9 100644
--- a/src/client/features/rank-tracking/KeywordSuggestionStep.tsx
+++ b/src/client/features/rank-tracking/KeywordSuggestionStep.tsx
@@ -255,7 +255,9 @@ export function KeywordSuggestionStep({
const sectionHeader = (title: string) => (
-
{title}
+
+ {title}
+
diff --git a/src/client/features/rank-tracking/RankTrackingConfigModal.tsx b/src/client/features/rank-tracking/RankTrackingConfigModal.tsx
index 8fd4fac..9348120 100644
--- a/src/client/features/rank-tracking/RankTrackingConfigModal.tsx
+++ b/src/client/features/rank-tracking/RankTrackingConfigModal.tsx
@@ -127,8 +127,14 @@ export function RankTrackingConfigModal({
const isPending = createMutation.isPending || updateMutation.isPending;
if (step === "keywords" && createdConfigId) {
+ const closeKeywordStep = () => onSaved(createdConfigId);
+
return (
-
+
onSaved(id)}
- onClose={() => onSaved(createdConfigId ?? undefined)}
+ onClose={closeKeywordStep}
/>
);
}
return (
-
+
-
+
{isEdit ? "Edit Domain Config" : "Add Domain"}
{archiveTarget && (
-
-
+ setArchiveTarget(null)}
+ labelledBy="archive-domain-title"
+ >
+
Archive {archiveTarget.domain}?
diff --git a/src/client/features/rank-tracking/RankTrackingTable.tsx b/src/client/features/rank-tracking/RankTrackingTable.tsx
index 2da9feb..b24d9af 100644
--- a/src/client/features/rank-tracking/RankTrackingTable.tsx
+++ b/src/client/features/rank-tracking/RankTrackingTable.tsx
@@ -129,8 +129,13 @@ export function RankTrackingTable({
{/* Confirm modal */}
{showConfirm && (
-
- Remove keywords?
+ setShowConfirm(false)}
+ labelledBy="remove-keywords-title"
+ >
+
+ Remove keywords?
+
This will stop tracking {selectedCount} keyword
{selectedCount !== 1 ? "s" : ""}. Historical ranking data is