From 23bc97528882e293883fff896b4ac1c5d8030371 Mon Sep 17 00:00:00 2001
From: MohamedBassem <me@mbassem.com>
Date: Sun, 31 Mar 2024 19:04:44 +0100
Subject: feature(web): Add ⌘ + E shortcut for quickly focusing on the editor
 card. Fixes #58
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../components/dashboard/bookmarks/EditorCard.tsx  | 97 +++++++++++++++-------
 1 file changed, 67 insertions(+), 30 deletions(-)

(limited to 'apps/web/components/dashboard/bookmarks/EditorCard.tsx')

diff --git a/apps/web/components/dashboard/bookmarks/EditorCard.tsx b/apps/web/components/dashboard/bookmarks/EditorCard.tsx
index adada927..28686e6c 100644
--- a/apps/web/components/dashboard/bookmarks/EditorCard.tsx
+++ b/apps/web/components/dashboard/bookmarks/EditorCard.tsx
@@ -1,17 +1,44 @@
 import type { SubmitErrorHandler, SubmitHandler } from "react-hook-form";
+import { useEffect, useImperativeHandle, useRef } from "react";
 import { ActionButton } from "@/components/ui/action-button";
-import { Form, FormControl, FormField, FormItem } from "@/components/ui/form";
+import { Form, FormControl, FormItem } from "@/components/ui/form";
 import { Separator } from "@/components/ui/separator";
 import { Textarea } from "@/components/ui/textarea";
+import {
+  Tooltip,
+  TooltipContent,
+  TooltipProvider,
+  TooltipTrigger,
+} from "@/components/ui/tooltip";
 import { toast } from "@/components/ui/use-toast";
 import { useClientConfig } from "@/lib/clientConfig";
 import { api } from "@/lib/trpc";
 import { cn } from "@/lib/utils";
 import { zodResolver } from "@hookform/resolvers/zod";
+import { Info } from "lucide-react";
 import { useForm } from "react-hook-form";
 import { z } from "zod";
 
+function useFocusOnKeyPress(inputRef: React.RefObject<HTMLTextAreaElement>) {
+  useEffect(() => {
+    function handleKeyPress(e: KeyboardEvent) {
+      if (!inputRef.current) {
+        return;
+      }
+      if ((e.metaKey || e.ctrlKey) && e.code === "KeyE") {
+        inputRef.current.focus();
+      }
+    }
+    document.addEventListener("keydown", handleKeyPress);
+    return () => {
+      document.removeEventListener("keydown", handleKeyPress);
+    };
+  }, [inputRef]);
+}
+
 export default function EditorCard({ className }: { className?: string }) {
+  const inputRef = useRef<HTMLTextAreaElement>(null);
+
   const demoMode = !!useClientConfig().demoMode;
   const formSchema = z.object({
     text: z.string(),
@@ -22,6 +49,9 @@ export default function EditorCard({ className }: { className?: string }) {
       text: "",
     },
   });
+  const { ref, ...textFieldProps } = form.register("text");
+  useImperativeHandle(ref, () => inputRef.current);
+  useFocusOnKeyPress(inputRef);
 
   const invalidateBookmarksCache = api.useUtils().bookmarks.invalidate;
   const { mutate, isPending } = api.bookmarks.createBookmark.useMutation({
@@ -62,36 +92,43 @@ export default function EditorCard({ className }: { className?: string }) {
         )}
         onSubmit={form.handleSubmit(onSubmit, onError)}
       >
-        <p className="text-sm">NEW ITEM</p>
+        <div className="flex justify-between">
+          <p className="text-sm">NEW ITEM</p>
+          <TooltipProvider delayDuration={0}>
+            <Tooltip>
+              <TooltipTrigger asChild>
+                <Info size={15} />
+              </TooltipTrigger>
+              <TooltipContent className="w-52">
+                <p className="text-center">
+                  You can quickly focus on this field by pressing ⌘ + E
+                </p>
+              </TooltipContent>
+            </Tooltip>
+          </TooltipProvider>
+        </div>
         <Separator />
-        <FormField
-          control={form.control}
-          name="text"
-          render={({ field }) => {
-            return (
-              <FormItem className="flex-1">
-                <FormControl>
-                  <Textarea
-                    disabled={isPending}
-                    className="h-full w-full resize-none border-none text-lg focus-visible:ring-0"
-                    placeholder={
-                      "Paste a link, write a note or drag and drop an image in here ..."
-                    }
-                    onKeyDown={(e) => {
-                      if (demoMode) {
-                        return;
-                      }
-                      if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
-                        form.handleSubmit(onSubmit, onError)();
-                      }
-                    }}
-                    {...field}
-                  />
-                </FormControl>
-              </FormItem>
-            );
-          }}
-        />
+        <FormItem className="flex-1">
+          <FormControl>
+            <Textarea
+              ref={inputRef}
+              disabled={isPending}
+              className="h-full w-full resize-none border-none text-lg focus-visible:ring-0"
+              placeholder={
+                "Paste a link, write a note or drag and drop an image in here ..."
+              }
+              onKeyDown={(e) => {
+                if (demoMode) {
+                  return;
+                }
+                if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
+                  form.handleSubmit(onSubmit, onError)();
+                }
+              }}
+              {...textFieldProps}
+            />
+          </FormControl>
+        </FormItem>
         <ActionButton loading={isPending} type="submit" variant="default">
           {form.formState.dirtyFields.text
             ? demoMode
-- 
cgit v1.2.3-70-g09d2

