From afbbc043f162de560dc72761f696ab5ddf890640 Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Thu, 21 Aug 2025 23:00:56 +1000 Subject: [PATCH 1/2] Add keyboard shortcut for creating event --- components/form/task.tsx | 27 +++----------------- components/project/events/full-calendar.tsx | 7 ++++-- hooks/use-keyboard-shortcut.ts | 28 +++++++++++++++++++++ 3 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 hooks/use-keyboard-shortcut.ts diff --git a/components/form/task.tsx b/components/form/task.tsx index 6096bb8c..e4e66dd8 100644 --- a/components/form/task.tsx +++ b/components/form/task.tsx @@ -2,10 +2,11 @@ import * as Dialog from "@radix-ui/react-dialog"; import { X } from "lucide-react"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useRef, useState } from "react"; import { Input } from "@/components/ui/input"; import { Kbd } from "@/components/ui/kbd"; import { cn } from "@/lib/utils"; +import { useKeyboardShortcut } from "@/hooks/use-keyboard-shortcut"; import { Button } from "../ui/button"; export default function InlineTaskForm({ @@ -17,29 +18,7 @@ export default function InlineTaskForm({ const [value, setValue] = useState(""); const inputRef = useRef(null); - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if ((e.key === "n" || e.key === "N") && !e.metaKey && !e.ctrlKey && !e.altKey && !e.repeat) { - const target = e.target as HTMLElement; - - // Check if we're in an input field, textarea, or any contentEditable element - if ( - target.tagName === "INPUT" || - target.tagName === "TEXTAREA" || - target.isContentEditable || - target.closest('[contenteditable="true"]') - ) { - return; - } - - e.preventDefault(); - setIsCreating(true); - } - }; - - document.addEventListener("keydown", handleKeyDown); - return () => document.removeEventListener("keydown", handleKeyDown); - }, []); + useKeyboardShortcut("n", () => setIsCreating(true)); const handleSubmit = useCallback(async () => { await action(value); diff --git a/components/project/events/full-calendar.tsx b/components/project/events/full-calendar.tsx index 64fdfcb9..20817470 100644 --- a/components/project/events/full-calendar.tsx +++ b/components/project/events/full-calendar.tsx @@ -2,6 +2,7 @@ import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; +import { Kbd } from "@/components/ui/kbd"; import type { CalendarEvent } from "@/drizzle/types"; import { useIsMobile } from "@/hooks/use-mobile"; import { cn } from "@/lib/utils"; @@ -27,11 +28,11 @@ import { import { ChevronLeftIcon, ChevronRightIcon, - PlusCircleIcon, } from "lucide-react"; import { parseAsBoolean, useQueryState } from "nuqs"; import { useCallback, useMemo, useState } from "react"; import { rrulestr } from "rrule"; +import { useKeyboardShortcut } from "@/hooks/use-keyboard-shortcut"; interface Event { id: number; @@ -76,6 +77,8 @@ export function FullCalendar({ parseAsBoolean.withDefault(false), ); + useKeyboardShortcut("n", () => setCreate(true)); + const [selectedDay, setSelectedDay] = useState(today); const [currentMonth, setCurrentMonth] = useState(format(today, "MMM-yyyy")); const firstDayCurrentMonth = useMemo( @@ -235,8 +238,8 @@ export function FullCalendar({ className="w-full gap-2 md:w-auto" onClick={() => setCreate(true)} > -