import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { Check, Pencil, Plus, X } from "lucide-react"; import { useState } from "react"; import { api } from "../api/client"; import type { Book } from "../api/types"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { toast } from "./Toaster"; type Locator = Record; /** 书签面板内容(供 ReaderNav 的「书签」选项卡承载);跳转后由调用方负责关抽屉. */ export function BookmarksTab({ book, capture, seek, }: { book: Book; capture: () => { locator: Locator; percent: number }; seek: (locator: Locator) => void; }) { const qc = useQueryClient(); const [note, setNote] = useState(""); const [editId, setEditId] = useState(null); const [editVal, setEditVal] = useState(""); const q = useQuery({ queryKey: ["bookmarks", book.id], queryFn: () => api.listBookmarks(book.id) }); const items = q.data ?? []; const invalidate = () => qc.invalidateQueries({ queryKey: ["bookmarks", book.id] }); const fail = (e: unknown) => toast("err", e instanceof Error ? e.message : "书签操作失败"); const add = useMutation({ mutationFn: () => { const { locator, percent } = capture(); return api.createBookmark(book.id, locator, percent, note.trim()); }, onSuccess: () => { setNote(""); invalidate(); toast("ok", "已加书签"); }, onError: fail, }); const patch = useMutation({ mutationFn: (v: { id: number; note: string }) => api.patchBookmark(v.id, v.note), onSuccess: () => { setEditId(null); invalidate(); }, onError: fail, }); const del = useMutation({ mutationFn: (id: number) => api.deleteBookmark(id), onSuccess: invalidate, onError: fail, }); return ( <>
setNote(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter" && !add.isPending) add.mutate(); }} />
); }