Something went wrong. Try again.
A very simple bookmarking webapp pinboard.ing
Something went wrong. Try again.
5.5 kB · 150 lines
TSX
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151import { LoaderIcon, PencilIcon, XIcon } from "lucide-solid"import { useMutation, useQueryClient } from "@tanstack/solid-query"import { createSignal, Show } from "solid-js"import { client } from "../apiclient.ts"import { Bookmark } from "../../server/utils/bookmarks.ts"import "./BookmarkEditModal.css"import "./ui/button.css"import { useWebHaptics } from "../utils/haptics.ts"
interface BookmarkEditModalProps { bookmark: Bookmark & { id: string }}
export function BookmarkEditModal(props: BookmarkEditModalProps) { const haptics = useWebHaptics()
const queryClient = useQueryClient() const [title, setTitle] = createSignal(props.bookmark.title) const [description, setDescription] = createSignal( props.bookmark.description, )
const editBookmark = useMutation(() => ({ mutationFn: async () => { const res = await client.api.v1.bookmarks[":id"].$put({ param: { id: props.bookmark.id }, json: { title: title().trim(), description: description().trim(), }, }) if (!res.ok) { const data = await res.json() haptics.trigger([ { duration: 40, intensity: 0.7 }, { delay: 40, duration: 40, intensity: 0.7 }, { delay: 40, duration: 40, intensity: 0.9 }, { delay: 40, duration: 50, intensity: 0.6 }, ]) throw new Error( "error" in data ? data.error : "Failed to update bookmark", ) } return await res.json() }, onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: [client.api.v1.bookmarks.all.$url().pathname], }) // Close the modal const dialog = document.getElementById( `edit-${props.bookmark.id}`, ) as HTMLDialogElement | null dialog?.requestClose() }, }))
const handleSubmit = (e: SubmitEvent) => { e.preventDefault() const titleValue = title().trim() if (titleValue) { editBookmark.mutate() } }
return ( <> <button type="button" command="show-modal" commandfor={`edit-${props.bookmark.id}`} class="bookmark-edit button-icon button-ghost" onClick={() => haptics.trigger()} > <PencilIcon size={16} /> </button> <dialog id={`edit-${props.bookmark.id}`} class="bookmark-edit-modal" > <div class="title"> <h2>Edit bookmark</h2>
<button type="button" commandfor={`edit-${props.bookmark.id}`} command="close" class="button-ghost button-icon" > <XIcon size={16} /> </button> </div>
<form onSubmit={handleSubmit} class="edit-form"> <div class="input-group"> <label for={`title-${props.bookmark.id}`}>Title</label> <input id={`title-${props.bookmark.id}`} type="text" required value={title()} onInput={(e) => setTitle(e.currentTarget.value)} disabled={editBookmark.isPending} maxlength="200" /> </div>
<div class="input-group"> <label for={`description-${props.bookmark.id}`}> Description </label> <textarea id={`description-${props.bookmark.id}`} value={description()} onInput={(e) => setDescription(e.currentTarget.value)} disabled={editBookmark.isPending} maxlength="500" /> </div>
<button type="submit" class="button" disabled={editBookmark.isPending || !title()?.trim()} > <Show when={!editBookmark.isPending} fallback={ <> <LoaderIcon size={16} class="spinner" /> Saving... </> } > Save changes </Show> </button> </form>
<Show when={editBookmark.isError}> <div class="error-message"> {editBookmark.error?.message ?? "Failed to update bookmark"} </div> </Show> </dialog> </> )}