git-subtree-dir: manga-site git-subtree-split: f2ef775f7095dc2b107b576cd4053593e89dd887
91 lines
2.3 KiB
TypeScript
91 lines
2.3 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Link from "next/link";
|
|
|
|
type ChapterLite = {
|
|
number: number;
|
|
title: string;
|
|
};
|
|
|
|
type Props = {
|
|
mangaSlug: string;
|
|
chapters: ChapterLite[];
|
|
};
|
|
|
|
export type ReadingProgress = {
|
|
chapter: number;
|
|
page: number;
|
|
};
|
|
|
|
function storageKey(slug: string) {
|
|
return `sunnymh:last-read:${slug}`;
|
|
}
|
|
|
|
export function readProgress(slug: string): ReadingProgress | null {
|
|
if (typeof window === "undefined") return null;
|
|
const raw = window.localStorage.getItem(storageKey(slug));
|
|
if (!raw) return null;
|
|
// New format: JSON { chapter, page }
|
|
if (raw.startsWith("{")) {
|
|
try {
|
|
const parsed = JSON.parse(raw) as ReadingProgress;
|
|
if (
|
|
typeof parsed.chapter === "number" &&
|
|
typeof parsed.page === "number" &&
|
|
parsed.chapter > 0 &&
|
|
parsed.page > 0
|
|
) {
|
|
return parsed;
|
|
}
|
|
} catch {
|
|
return null;
|
|
}
|
|
return null;
|
|
}
|
|
// Legacy format: bare chapter number
|
|
const n = Number(raw);
|
|
return Number.isFinite(n) && n > 0 ? { chapter: n, page: 1 } : null;
|
|
}
|
|
|
|
export function writeProgress(slug: string, progress: ReadingProgress) {
|
|
if (typeof window === "undefined") return;
|
|
window.localStorage.setItem(storageKey(slug), JSON.stringify(progress));
|
|
}
|
|
|
|
export function ReadingProgressButton({ mangaSlug, chapters }: Props) {
|
|
const [progress, setProgress] = useState<ReadingProgress | null>(null);
|
|
|
|
useEffect(() => {
|
|
setProgress(readProgress(mangaSlug));
|
|
}, [mangaSlug]);
|
|
|
|
if (chapters.length === 0) return null;
|
|
const first = chapters[0];
|
|
const resumeChapter =
|
|
progress !== null
|
|
? chapters.find((c) => c.number === progress.chapter)
|
|
: null;
|
|
const target = resumeChapter ?? first;
|
|
|
|
return (
|
|
<Link
|
|
href={`/manga/${mangaSlug}/${target.number}`}
|
|
scroll={false}
|
|
className="flex items-center justify-center gap-3 w-full py-3 mb-6 px-4 text-sm font-semibold bg-accent hover:bg-accent-hover text-white rounded-xl transition-colors active:scale-[0.98]"
|
|
>
|
|
{resumeChapter ? (
|
|
<>
|
|
<span>继续阅读</span>
|
|
<span className="opacity-50">·</span>
|
|
<span className="truncate">
|
|
#{resumeChapter.number} {resumeChapter.title}
|
|
</span>
|
|
</>
|
|
) : (
|
|
"开始阅读"
|
|
)}
|
|
</Link>
|
|
);
|
|
}
|