diff options
| author | MohamedBassem <me@mbassem.com> | 2024-03-16 00:34:04 +0000 |
|---|---|---|
| committer | MohamedBassem <me@mbassem.com> | 2024-03-16 00:34:04 +0000 |
| commit | f6ca0b0c4fb3c1e6d93a00fcce7cb0aee12930c0 (patch) | |
| tree | 126c6d26acb640dc35d953607459df7b0fce3a88 /apps/web/components/dashboard/bookmarks/EditorCard.tsx | |
| parent | 8f9c9036afbd036688cd2805d27328895926a8d9 (diff) | |
| download | karakeep-f6ca0b0c4fb3c1e6d93a00fcce7cb0aee12930c0.tar.zst | |
ui(web): Add an editor card inline in the bookmark grid and remove the top nav buttons
Diffstat (limited to 'apps/web/components/dashboard/bookmarks/EditorCard.tsx')
| -rw-r--r-- | apps/web/components/dashboard/bookmarks/EditorCard.tsx | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/apps/web/components/dashboard/bookmarks/EditorCard.tsx b/apps/web/components/dashboard/bookmarks/EditorCard.tsx new file mode 100644 index 00000000..28e8f41f --- /dev/null +++ b/apps/web/components/dashboard/bookmarks/EditorCard.tsx @@ -0,0 +1,91 @@ +import type { SubmitErrorHandler, SubmitHandler } from "react-hook-form"; +import { ActionButton } from "@/components/ui/action-button"; +import { Form, FormControl, FormField, FormItem } from "@/components/ui/form"; +import { Textarea } from "@/components/ui/textarea"; +import { toast } from "@/components/ui/use-toast"; +import { api } from "@/lib/trpc"; +import { cn } from "@/lib/utils"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +export default function EditorCard({ className }: { className?: string }) { + const formSchema = z.object({ + text: z.string(), + }); + const form = useForm<z.infer<typeof formSchema>>({ + resolver: zodResolver(formSchema), + defaultValues: { + text: "", + }, + }); + + const invalidateBookmarksCache = api.useUtils().bookmarks.invalidate; + const { mutate, isPending } = api.bookmarks.createBookmark.useMutation({ + onSuccess: () => { + invalidateBookmarksCache(); + form.reset(); + }, + onError: () => { + toast({ description: "Something went wrong", variant: "destructive" }); + }, + }); + + const onSubmit: SubmitHandler<z.infer<typeof formSchema>> = (data) => { + const text = data.text.trim(); + try { + new URL(text); + mutate({ type: "link", url: text }); + } catch (e) { + // Not a URL + mutate({ type: "text", text }); + } + }; + const onError: SubmitErrorHandler<z.infer<typeof formSchema>> = (errors) => { + toast({ + description: Object.values(errors) + .map((v) => v.message) + .join("\n"), + variant: "destructive", + }); + }; + + return ( + <Form {...form}> + <form + className={cn( + className, + "flex h-96 flex-col gap-2 rounded-xl bg-white p-4", + )} + onSubmit={form.handleSubmit(onSubmit, onError)} + > + <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 or write a note ..."} + onKeyDown={(e) => { + if (e.key === "Enter" && e.metaKey) { + form.handleSubmit(onSubmit, onError)(); + } + }} + {...field} + /> + </FormControl> + </FormItem> + ); + }} + /> + <ActionButton loading={isPending} type="submit" variant="ghost"> + Save + </ActionButton> + </form> + </Form> + ); +} |
