diff options
| author | kamtschatka <sschatka@gmail.com> | 2024-05-19 13:13:54 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-19 12:13:54 +0100 |
| commit | d1ad84be48bb3b6914c0d478d13f92861889c466 (patch) | |
| tree | 2f3f4f748b85b101d8f5b56473cf2d36944b1a1d /apps/web/components/dashboard/bookmarks | |
| parent | cb62db781235fbc4b1fe92a3f8b26dadb5181963 (diff) | |
| download | karakeep-d1ad84be48bb3b6914c0d478d13f92861889c466.tar.zst | |
feature(web): Allow adding multiple URLs at once #158 (#167)
Added a reusable dialog
opening a dialog that allows you to decide if you want to import multiple URLs at once if you provide only that
Co-authored-by: kamtschatka <simon.schatka@gmx.at>
Diffstat (limited to 'apps/web/components/dashboard/bookmarks')
| -rw-r--r-- | apps/web/components/dashboard/bookmarks/EditorCard.tsx | 79 |
1 files changed, 74 insertions, 5 deletions
diff --git a/apps/web/components/dashboard/bookmarks/EditorCard.tsx b/apps/web/components/dashboard/bookmarks/EditorCard.tsx index 7c036c04..8425f669 100644 --- a/apps/web/components/dashboard/bookmarks/EditorCard.tsx +++ b/apps/web/components/dashboard/bookmarks/EditorCard.tsx @@ -1,9 +1,10 @@ import type { SubmitErrorHandler, SubmitHandler } from "react-hook-form"; -import { useEffect, useImperativeHandle, useRef } from "react"; +import React, { useEffect, useImperativeHandle, useRef } from "react"; import Link from "next/link"; import { ActionButton } from "@/components/ui/action-button"; import { Form, FormControl, FormItem } from "@/components/ui/form"; import InfoTooltip from "@/components/ui/info-tooltip"; +import MultipleChoiceDialog from "@/components/ui/multiple-choice-dialog"; import { Separator } from "@/components/ui/separator"; import { Textarea } from "@/components/ui/textarea"; import { toast } from "@/components/ui/use-toast"; @@ -34,9 +35,17 @@ function useFocusOnKeyPress(inputRef: React.RefObject<HTMLTextAreaElement>) { }, [inputRef]); } +interface MultiUrlImportState { + urls: URL[]; + text: string; +} + export default function EditorCard({ className }: { className?: string }) { const inputRef = useRef<HTMLTextAreaElement>(null); + const [multiUrlImportState, setMultiUrlImportState] = + React.useState<MultiUrlImportState | null>(null); + const demoMode = !!useClientConfig().demoMode; const formSchema = z.object({ text: z.string(), @@ -76,14 +85,31 @@ export default function EditorCard({ className }: { className?: string }) { }, }); - const onSubmit: SubmitHandler<z.infer<typeof formSchema>> = (data) => { - const text = data.text.trim(); - try { - const url = new URL(text); + function tryToImportUrls(text: string): void { + const lines = text.split("\n"); + const urls: URL[] = []; + for (const line of lines) { + // parsing can also throw an exception, but will be caught outside + const url = new URL(line); if (url.protocol != "http:" && url.protocol != "https:") { throw new Error("Invalid URL"); } + urls.push(url); + } + + if (urls.length === 1) { + // Only 1 url in the textfield --> simply import it mutate({ type: "link", url: text }); + return; + } + // multiple urls found --> ask the user if it should be imported as multiple URLs or as a text bookmark + setMultiUrlImportState({ urls, text }); + } + + const onSubmit: SubmitHandler<z.infer<typeof formSchema>> = (data) => { + const text = data.text.trim(); + try { + tryToImportUrls(text); } catch (e) { // Not a URL mutate({ type: "text", text }); @@ -150,6 +176,49 @@ export default function EditorCard({ className }: { className?: string }) { : "Press ⌘ + Enter to Save" : "Save"} </ActionButton> + + {multiUrlImportState && ( + <MultipleChoiceDialog + open={true} + title={`Import URLs as separate Bookmarks?`} + description={`The input contains multiple URLs on separate lines. Do you want to import them as separate bookmarks?`} + onOpenChange={(open) => { + if (!open) { + setMultiUrlImportState(null); + } + }} + actionButtons={[ + () => ( + <ActionButton + type="button" + variant="secondary" + loading={isPending} + onClick={() => { + mutate({ type: "text", text: multiUrlImportState.text }); + setMultiUrlImportState(null); + }} + > + Import as Text Bookmark + </ActionButton> + ), + () => ( + <ActionButton + type="button" + variant="destructive" + loading={isPending} + onClick={() => { + multiUrlImportState.urls.forEach((url) => + mutate({ type: "link", url: url.toString() }), + ); + setMultiUrlImportState(null); + }} + > + Import as separate Bookmarks + </ActionButton> + ), + ]} + ></MultipleChoiceDialog> + )} </form> </Form> ); |
