feat(web): iconify reader chrome, move 连读/预读 into 更多 menu with slider

This commit is contained in:
2026-09-08 21:29:01 +08:00
parent 9c2b7e2074
commit d2c852d6f0
8 changed files with 132 additions and 63 deletions
+57 -25
View File
@@ -1,4 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import { BookOpenCheck, Check, ChevronLeft, ChevronRight, PanelLeft, Settings2 } from "lucide-react";
import { DropdownMenu } from "radix-ui";
import { useEffect, useMemo, useRef, useState, type MouseEvent } from "react";
import { api, formatPageUrl } from "../api/client";
import { btn } from "../components/ui";
@@ -296,7 +298,7 @@ export default function CbzReader({ book, initialLocator, initialPercent, chrome
<span className="text-sm text-stone-500">— 全书完 —</span>
) : (
<button className={btn} onClick={() => goPage(chapters![ci + 1].start)}>
本章完 · 下一章 →
本章完 · 下一章 <ChevronRight size={14} className="inline" />
</button>
)}
</div>
@@ -340,49 +342,79 @@ export default function CbzReader({ book, initialLocator, initialPercent, chrome
</span>
</div>
<div className="mt-1 flex items-center gap-2 pb-1 text-sm">
{chapters && chapters.length >= 2 && (
<button
className={"rd-btn" + (continuous ? " rd-btn-on" : "")}
aria-pressed={continuous}
onClick={() => setContinuous(!continuous)}
>
连读{continuous ? "·开" : "·关"}
</button>
)}
{locked && (
<button
className="rd-btn"
aria-label="预读:锁定章节末尾时提前挂载并解码其后 N 章"
onClick={() => setPrefetch((p) => (p + 1) % 4)}
>
预读 {prefetch} 章
</button>
)}
<button
className="rd-btn"
className="rd-btn inline-flex items-center gap-1.5"
aria-expanded={!!nav}
aria-controls="reader-nav"
onClick={() => setNav(nav ? null : chapters ? "toc" : "bm")}
>
导航
<PanelLeft size={14} /> 导航
</button>
{chapters && (
<>
<span className="text-xs tabular-nums opacity-60">
{ci + 1}/{chapters.length}
</span>
<button className="rd-btn" disabled={ci === 0} onClick={() => goPage(chapters[ci - 1].start)}>
← 上一章
<button
className="rd-btn inline-flex items-center gap-0.5"
disabled={ci === 0}
onClick={() => goPage(chapters[ci - 1].start)}
>
<ChevronLeft size={14} /> 上一章
</button>
<button
className="rd-btn"
className="rd-btn inline-flex items-center gap-0.5"
disabled={ci === chapters.length - 1}
onClick={() => goPage(chapters[ci + 1].start)}
>
下一章 →
下一章 <ChevronRight size={14} />
</button>
</>
)}
{chapters && chapters.length >= 2 && (
<DropdownMenu.Root>
<DropdownMenu.Trigger className="rd-btn ml-auto inline-flex items-center gap-1.5" aria-label="更多阅读选项">
<Settings2 size={14} /> 更多
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
align="end"
side="top"
className="rd-divider z-50 min-w-44 rounded-md border bg-[var(--rd-bg,#171512)] p-1 shadow-2xl"
style={{ color: "var(--rd-fg,#c6c0b6)" }}
>
<DropdownMenu.CheckboxItem
className="rd-row rd-highlight cursor-pointer"
style={{ display: "flex", alignItems: "center", gap: 8 }}
checked={continuous}
onCheckedChange={(v) => setContinuous(!!v)}
>
<BookOpenCheck size={14} /> 连读(滑动跨章)
<DropdownMenu.ItemIndicator style={{ marginLeft: "auto" }}>
<Check size={14} />
</DropdownMenu.ItemIndicator>
</DropdownMenu.CheckboxItem>
{locked && (
<div className="px-2.5 pb-1.5 pt-2">
<div className="mb-1 text-xs opacity-60">
预读:锁章末尾时提前挂载其后 N 章 · 当前 {prefetch}
</div>
<input
type="range"
min={0}
max={3}
step={1}
value={prefetch}
aria-label="预读章数"
className="rd-range"
onChange={(e) => setPrefetch(Number(e.target.value))}
/>
</div>
)}
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
)}
</div>
</div>
) : (