aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/client/pages/StudyPage.tsx
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-14 23:05:43 +0900
committernsfisis <nsfisis@gmail.com>2026-02-14 23:05:43 +0900
commitc1cb543875edee1aa9cc160a78b610e06ea139e7 (patch)
tree9cb5254c8f874e985b1bfd1a5cb5ab6fb89efb93 /src/client/pages/StudyPage.tsx
parent8883b0beb78b794d74fd5a1dad641b687b308dbd (diff)
downloadkioku-c1cb543875edee1aa9cc160a78b610e06ea139e7.tar.gz
kioku-c1cb543875edee1aa9cc160a78b610e06ea139e7.tar.zst
kioku-c1cb543875edee1aa9cc160a78b610e06ea139e7.zip
feat(study): add edit button to study session cards
Allow editing note content directly from the study screen via a pen icon button or the E key shortcut. Keyboard shortcuts are disabled while the edit modal is open to prevent accidental card flips/ratings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src/client/pages/StudyPage.tsx')
-rw-r--r--src/client/pages/StudyPage.tsx59
1 files changed, 57 insertions, 2 deletions
diff --git a/src/client/pages/StudyPage.tsx b/src/client/pages/StudyPage.tsx
index 33fd290..c8eb603 100644
--- a/src/client/pages/StudyPage.tsx
+++ b/src/client/pages/StudyPage.tsx
@@ -2,6 +2,7 @@ import {
faCheck,
faChevronLeft,
faCircleCheck,
+ faPen,
faRotateLeft,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@@ -17,6 +18,7 @@ import {
import { Link, useLocation, useParams } from "wouter";
import { ApiClientError, apiClient } from "../api";
import { studyDataAtomFamily } from "../atoms";
+import { EditNoteModal } from "../components/EditNoteModal";
import { ErrorBoundary } from "../components/ErrorBoundary";
import { queryClient } from "../queryClient";
import { renderCard } from "../utils/templateRenderer";
@@ -60,6 +62,7 @@ function StudySession({
null,
);
const pendingReviewRef = useRef<PendingReview | null>(null);
+ const [editingNoteId, setEditingNoteId] = useState<string | null>(null);
// Keep ref in sync with state for cleanup effect
useEffect(() => {
@@ -174,6 +177,14 @@ function StudySession({
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (isSubmitting) return;
+ if (editingNoteId) return;
+
+ // Edit: E key to open edit modal
+ if (e.key === "e" && cards[currentIndex]) {
+ e.preventDefault();
+ setEditingNoteId(cards[currentIndex].noteId);
+ return;
+ }
// Undo: Ctrl+Z / Cmd+Z anytime, or z when card is not flipped
if (
@@ -206,7 +217,16 @@ function StudySession({
}
}
},
- [isFlipped, isSubmitting, handleFlip, handleRating, handleUndo],
+ [
+ isFlipped,
+ isSubmitting,
+ editingNoteId,
+ cards,
+ currentIndex,
+ handleFlip,
+ handleRating,
+ handleUndo,
+ ],
);
useEffect(() => {
@@ -395,11 +415,37 @@ function StudySession({
: "bg-ivory/50"
}`}
>
+ {/* Edit button */}
+ {/* biome-ignore lint/a11y/useSemanticElements: Cannot nest <button> inside parent <button>, using span with role="button" instead */}
+ <span
+ role="button"
+ tabIndex={0}
+ data-testid="edit-card-button"
+ onClick={(e) => {
+ e.stopPropagation();
+ setEditingNoteId(currentCard.noteId);
+ }}
+ onKeyDown={(e) => {
+ if (e.key === "Enter" || e.key === " ") {
+ e.stopPropagation();
+ e.preventDefault();
+ setEditingNoteId(currentCard.noteId);
+ }
+ }}
+ className="absolute top-3 right-3 w-8 h-8 flex items-center justify-center text-muted hover:text-slate transition-colors rounded-lg hover:bg-ivory"
+ aria-label="Edit card"
+ >
+ <FontAwesomeIcon
+ icon={faPen}
+ className="w-3.5 h-3.5"
+ aria-hidden="true"
+ />
+ </span>
{/* New card badge */}
{currentCard.state === 0 && (
<span
data-testid="new-card-badge"
- className="absolute top-3 right-3 bg-primary/10 text-primary text-xs font-medium px-2 py-0.5 rounded-full"
+ className="absolute top-3 right-10 bg-primary/10 text-primary text-xs font-medium px-2 py-0.5 rounded-full"
>
New
</span>
@@ -456,6 +502,15 @@ function StudySession({
)}
</div>
)}
+
+ {/* Edit Note Modal */}
+ <EditNoteModal
+ isOpen={!!editingNoteId}
+ deckId={deckId}
+ noteId={editingNoteId}
+ onClose={() => setEditingNoteId(null)}
+ onNoteUpdated={() => setEditingNoteId(null)}
+ />
</div>
);
}