修复搜索页返回重置和顶部栏按钮问题
This commit is contained in:
@@ -71,6 +71,7 @@ export default function MangaDetailPage() {
|
|||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const mangaId = searchParams.get('mangaId') || '';
|
const mangaId = searchParams.get('mangaId') || '';
|
||||||
const sourceId = searchParams.get('sourceId') || '';
|
const sourceId = searchParams.get('sourceId') || '';
|
||||||
|
const returnTo = searchParams.get('returnTo') || '/manga';
|
||||||
const [detail, setDetail] = useState<MangaDetail | null>(null);
|
const [detail, setDetail] = useState<MangaDetail | null>(null);
|
||||||
const [history, setHistory] = useState<Record<string, MangaReadRecord>>({});
|
const [history, setHistory] = useState<Record<string, MangaReadRecord>>({});
|
||||||
const [shelf, setShelf] = useState<Record<string, MangaShelfItem>>({});
|
const [shelf, setShelf] = useState<Record<string, MangaShelfItem>>({});
|
||||||
@@ -140,7 +141,7 @@ export default function MangaDetailPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const chapterHref = (chapter: MangaChapter) =>
|
const chapterHref = (chapter: MangaChapter) =>
|
||||||
`/manga/read?mangaId=${mangaId}&sourceId=${sourceId}&chapterId=${chapter.id}&title=${encodeURIComponent(detail?.title || '')}&cover=${encodeURIComponent(detail?.cover || '')}&sourceName=${encodeURIComponent(detail?.sourceName || '')}&chapterName=${encodeURIComponent(chapter.name)}`;
|
`/manga/read?mangaId=${mangaId}&sourceId=${sourceId}&chapterId=${chapter.id}&title=${encodeURIComponent(detail?.title || '')}&cover=${encodeURIComponent(detail?.cover || '')}&sourceName=${encodeURIComponent(detail?.sourceName || '')}&chapterName=${encodeURIComponent(chapter.name)}&returnTo=${encodeURIComponent(returnTo)}`;
|
||||||
|
|
||||||
if (!detail) return <MangaDetailSkeleton />;
|
if (!detail) return <MangaDetailSkeleton />;
|
||||||
|
|
||||||
@@ -175,7 +176,7 @@ export default function MangaDetailPage() {
|
|||||||
)}
|
)}
|
||||||
{currentRecord && (
|
{currentRecord && (
|
||||||
<Link
|
<Link
|
||||||
href={`/manga/read?mangaId=${mangaId}&sourceId=${sourceId}&chapterId=${currentRecord.chapterId}&title=${encodeURIComponent(detail.title)}&cover=${encodeURIComponent(detail.cover)}&sourceName=${encodeURIComponent(detail.sourceName)}&chapterName=${encodeURIComponent(currentRecord.chapterName)}`}
|
href={`/manga/read?mangaId=${mangaId}&sourceId=${sourceId}&chapterId=${currentRecord.chapterId}&title=${encodeURIComponent(detail.title)}&cover=${encodeURIComponent(detail.cover)}&sourceName=${encodeURIComponent(detail.sourceName)}&chapterName=${encodeURIComponent(currentRecord.chapterName)}&returnTo=${encodeURIComponent(returnTo)}`}
|
||||||
className='rounded-2xl border border-sky-300 px-5 py-3 text-sm font-medium text-sky-700 transition hover:bg-sky-50 dark:text-sky-300 dark:hover:bg-sky-950/30'
|
className='rounded-2xl border border-sky-300 px-5 py-3 text-sm font-medium text-sky-700 transition hover:bg-sky-50 dark:text-sky-300 dark:hover:bg-sky-950/30'
|
||||||
>
|
>
|
||||||
<Clock3 className='mr-2 inline h-4 w-4' />继续阅读 第 {currentRecord.pageIndex + 1}/{currentRecord.pageCount} 页
|
<Clock3 className='mr-2 inline h-4 w-4' />继续阅读 第 {currentRecord.pageIndex + 1}/{currentRecord.pageCount} 页
|
||||||
|
|||||||
+156
-18
@@ -1,13 +1,16 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { Search } from 'lucide-react';
|
import { Search } from 'lucide-react';
|
||||||
import { useEffect, useState } from 'react';
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { deleteMangaShelf, getAllMangaShelf, saveMangaShelf } from '@/lib/db.client';
|
import { deleteMangaShelf, getAllMangaShelf, saveMangaShelf } from '@/lib/db.client';
|
||||||
import { MangaSearchItem, MangaShelfItem, MangaSource } from '@/lib/manga.types';
|
import { MangaSearchItem, MangaShelfItem, MangaSource } from '@/lib/manga.types';
|
||||||
|
|
||||||
import MangaCard from '@/components/MangaCard';
|
import MangaCard from '@/components/MangaCard';
|
||||||
|
|
||||||
|
const MANGA_SEARCH_STATE_KEY = 'manga_search_state';
|
||||||
|
|
||||||
function MangaCardSkeleton({ withButton = false }: { withButton?: boolean }) {
|
function MangaCardSkeleton({ withButton = false }: { withButton?: boolean }) {
|
||||||
return (
|
return (
|
||||||
<div className='space-y-2'>
|
<div className='space-y-2'>
|
||||||
@@ -24,6 +27,11 @@ function MangaCardSkeleton({ withButton = false }: { withButton?: boolean }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function MangaPage() {
|
export default function MangaPage() {
|
||||||
|
const router = useRouter();
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
const urlQuery = searchParams.get('q')?.trim() || '';
|
||||||
|
const urlSourceId = searchParams.get('sourceId') || '';
|
||||||
|
|
||||||
const [query, setQuery] = useState('');
|
const [query, setQuery] = useState('');
|
||||||
const [sources, setSources] = useState<MangaSource[]>([]);
|
const [sources, setSources] = useState<MangaSource[]>([]);
|
||||||
const [sourceId, setSourceId] = useState('');
|
const [sourceId, setSourceId] = useState('');
|
||||||
@@ -31,6 +39,64 @@ export default function MangaPage() {
|
|||||||
const [shelf, setShelf] = useState<Record<string, MangaShelfItem>>({});
|
const [shelf, setShelf] = useState<Record<string, MangaShelfItem>>({});
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
const [hasSearched, setHasSearched] = useState(false);
|
||||||
|
const [lastSearchedQuery, setLastSearchedQuery] = useState('');
|
||||||
|
const [lastSearchedSourceId, setLastSearchedSourceId] = useState('');
|
||||||
|
const restoredRef = useRef(false);
|
||||||
|
|
||||||
|
const getCacheKey = useCallback((keyword: string, selectedSourceId: string) => {
|
||||||
|
return `manga_search_cache_${selectedSourceId || 'all'}_${keyword.trim()}`;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getCachedResults = useCallback(
|
||||||
|
(keyword: string, selectedSourceId: string) => {
|
||||||
|
if (typeof window === 'undefined' || !keyword.trim()) return null;
|
||||||
|
try {
|
||||||
|
const cached = sessionStorage.getItem(getCacheKey(keyword, selectedSourceId));
|
||||||
|
return cached ? (JSON.parse(cached) as MangaSearchItem[]) : null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[getCacheKey]
|
||||||
|
);
|
||||||
|
|
||||||
|
const setCachedResults = useCallback(
|
||||||
|
(keyword: string, selectedSourceId: string, nextResults: MangaSearchItem[]) => {
|
||||||
|
if (typeof window === 'undefined' || !keyword.trim()) return;
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem(getCacheKey(keyword, selectedSourceId), JSON.stringify(nextResults));
|
||||||
|
} catch {
|
||||||
|
// ignore session cache failures
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[getCacheKey]
|
||||||
|
);
|
||||||
|
|
||||||
|
const saveSearchState = useCallback((nextState: { query: string; sourceId: string; results: MangaSearchItem[] }) => {
|
||||||
|
if (typeof window === 'undefined') return;
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem(MANGA_SEARCH_STATE_KEY, JSON.stringify(nextState));
|
||||||
|
} catch {
|
||||||
|
// ignore session cache failures
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const restoreSearchState = useCallback(() => {
|
||||||
|
if (typeof window === 'undefined') return null;
|
||||||
|
try {
|
||||||
|
const cached = sessionStorage.getItem(MANGA_SEARCH_STATE_KEY);
|
||||||
|
return cached
|
||||||
|
? (JSON.parse(cached) as {
|
||||||
|
query: string;
|
||||||
|
sourceId: string;
|
||||||
|
results: MangaSearchItem[];
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch('/api/manga/sources')
|
fetch('/api/manga/sources')
|
||||||
@@ -41,25 +107,97 @@ export default function MangaPage() {
|
|||||||
getAllMangaShelf().then(setShelf).catch(() => undefined);
|
getAllMangaShelf().then(setShelf).catch(() => undefined);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const performSearch = useCallback(
|
||||||
|
async (keyword: string, selectedSourceId: string) => {
|
||||||
|
const trimmedQuery = keyword.trim();
|
||||||
|
if (!trimmedQuery) return;
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
setError('');
|
||||||
|
setHasSearched(true);
|
||||||
|
setLastSearchedQuery(trimmedQuery);
|
||||||
|
setLastSearchedSourceId(selectedSourceId);
|
||||||
|
|
||||||
|
const cached = getCachedResults(trimmedQuery, selectedSourceId);
|
||||||
|
if (cached) {
|
||||||
|
setResults(cached);
|
||||||
|
saveSearchState({ query: trimmedQuery, sourceId: selectedSourceId, results: cached });
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const params = new URLSearchParams({ q: trimmedQuery });
|
||||||
|
if (selectedSourceId) params.set('sourceId', selectedSourceId);
|
||||||
|
const res = await fetch(`/api/manga/search?${params.toString()}`);
|
||||||
|
const data = await res.json();
|
||||||
|
if (!res.ok) throw new Error(data.error || '搜索失败');
|
||||||
|
const nextResults = data.results || [];
|
||||||
|
setResults(nextResults);
|
||||||
|
setCachedResults(trimmedQuery, selectedSourceId, nextResults);
|
||||||
|
saveSearchState({ query: trimmedQuery, sourceId: selectedSourceId, results: nextResults });
|
||||||
|
} catch (err) {
|
||||||
|
setError((err as Error).message);
|
||||||
|
setResults([]);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[getCachedResults, saveSearchState, setCachedResults]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!restoredRef.current) {
|
||||||
|
restoredRef.current = true;
|
||||||
|
|
||||||
|
if (!urlQuery) {
|
||||||
|
const cachedState = restoreSearchState();
|
||||||
|
if (cachedState?.query?.trim()) {
|
||||||
|
setQuery(cachedState.query);
|
||||||
|
setSourceId(cachedState.sourceId || '');
|
||||||
|
setResults(cachedState.results || []);
|
||||||
|
setHasSearched(true);
|
||||||
|
setLastSearchedQuery(cachedState.query);
|
||||||
|
setLastSearchedSourceId(cachedState.sourceId || '');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setQuery(urlQuery);
|
||||||
|
setSourceId(urlSourceId);
|
||||||
|
|
||||||
|
if (!urlQuery) {
|
||||||
|
setResults([]);
|
||||||
|
setHasSearched(false);
|
||||||
|
setLastSearchedQuery('');
|
||||||
|
setLastSearchedSourceId('');
|
||||||
|
setError('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void performSearch(urlQuery, urlSourceId);
|
||||||
|
}, [performSearch, restoreSearchState, urlQuery, urlSourceId]);
|
||||||
|
|
||||||
const handleSearch = async (e: React.FormEvent) => {
|
const handleSearch = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!query.trim()) return;
|
const trimmedQuery = query.trim();
|
||||||
setLoading(true);
|
if (!trimmedQuery) return;
|
||||||
setError('');
|
|
||||||
try {
|
const params = new URLSearchParams({ q: trimmedQuery });
|
||||||
const params = new URLSearchParams({ q: query.trim() });
|
if (sourceId) params.set('sourceId', sourceId);
|
||||||
if (sourceId) params.set('sourceId', sourceId);
|
router.replace(`/manga?${params.toString()}`);
|
||||||
const res = await fetch(`/api/manga/search?${params.toString()}`);
|
await performSearch(trimmedQuery, sourceId);
|
||||||
const data = await res.json();
|
|
||||||
if (!res.ok) throw new Error(data.error || '搜索失败');
|
|
||||||
setResults(data.results || []);
|
|
||||||
} catch (err) {
|
|
||||||
setError((err as Error).message);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const returnTo = useMemo(() => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (lastSearchedQuery) params.set('q', lastSearchedQuery);
|
||||||
|
if (lastSearchedSourceId) params.set('sourceId', lastSearchedSourceId);
|
||||||
|
const queryString = params.toString();
|
||||||
|
return queryString ? `/manga?${queryString}` : '/manga';
|
||||||
|
}, [lastSearchedQuery, lastSearchedSourceId]);
|
||||||
|
|
||||||
const toggleShelf = async (item: MangaSearchItem) => {
|
const toggleShelf = async (item: MangaSearchItem) => {
|
||||||
const key = `${item.sourceId}+${item.id}`;
|
const key = `${item.sourceId}+${item.id}`;
|
||||||
if (shelf[key]) {
|
if (shelf[key]) {
|
||||||
@@ -133,7 +271,7 @@ export default function MangaPage() {
|
|||||||
</div>
|
</div>
|
||||||
) : results.length === 0 ? (
|
) : results.length === 0 ? (
|
||||||
<div className='rounded-2xl bg-gray-50 p-10 text-center text-sm text-gray-500 dark:bg-gray-900/50'>
|
<div className='rounded-2xl bg-gray-50 p-10 text-center text-sm text-gray-500 dark:bg-gray-900/50'>
|
||||||
请输入关键词开始搜索漫画
|
{hasSearched ? '没有找到相关漫画' : '请输入关键词开始搜索漫画'}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className='grid grid-cols-2 gap-4 md:grid-cols-4 xl:grid-cols-6'>
|
<div className='grid grid-cols-2 gap-4 md:grid-cols-4 xl:grid-cols-6'>
|
||||||
@@ -143,7 +281,7 @@ export default function MangaPage() {
|
|||||||
<div key={key} className='space-y-2'>
|
<div key={key} className='space-y-2'>
|
||||||
<MangaCard
|
<MangaCard
|
||||||
item={item}
|
item={item}
|
||||||
href={`/manga/detail?mangaId=${item.id}&sourceId=${item.sourceId}&title=${encodeURIComponent(item.title)}&cover=${encodeURIComponent(item.cover)}&sourceName=${encodeURIComponent(item.sourceName)}&description=${encodeURIComponent(item.description || '')}&author=${encodeURIComponent(item.author || '')}&status=${encodeURIComponent(item.status || '')}`}
|
href={`/manga/detail?mangaId=${item.id}&sourceId=${item.sourceId}&title=${encodeURIComponent(item.title)}&cover=${encodeURIComponent(item.cover)}&sourceName=${encodeURIComponent(item.sourceName)}&description=${encodeURIComponent(item.description || '')}&author=${encodeURIComponent(item.author || '')}&status=${encodeURIComponent(item.status || '')}&returnTo=${encodeURIComponent(returnTo)}`}
|
||||||
subtitle={item.author || item.status || item.description}
|
subtitle={item.author || item.status || item.description}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { ArrowDownWideNarrow, ArrowUpWideNarrow } from 'lucide-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
import { type MouseEvent, useEffect, useMemo, useRef, useState } from 'react';
|
import { type MouseEvent, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { ArrowDownWideNarrow, ArrowUpWideNarrow } from 'lucide-react';
|
|
||||||
|
|
||||||
import { getAllMangaReadRecords, saveMangaReadRecord } from '@/lib/db.client';
|
import { getAllMangaReadRecords, saveMangaReadRecord } from '@/lib/db.client';
|
||||||
import type { MangaChapter, MangaDetail, MangaReadRecord } from '@/lib/manga.types';
|
import type { MangaChapter, MangaDetail, MangaReadRecord } from '@/lib/manga.types';
|
||||||
@@ -78,6 +78,7 @@ export default function MangaReadPage() {
|
|||||||
const cover = searchParams.get('cover') || '';
|
const cover = searchParams.get('cover') || '';
|
||||||
const sourceName = searchParams.get('sourceName') || sourceId;
|
const sourceName = searchParams.get('sourceName') || sourceId;
|
||||||
const chapterName = searchParams.get('chapterName') || '章节';
|
const chapterName = searchParams.get('chapterName') || '章节';
|
||||||
|
const returnTo = searchParams.get('returnTo') || '/manga';
|
||||||
|
|
||||||
const [pages, setPages] = useState<string[]>([]);
|
const [pages, setPages] = useState<string[]>([]);
|
||||||
const [activePage, setActivePage] = useState(0);
|
const [activePage, setActivePage] = useState(0);
|
||||||
@@ -752,7 +753,7 @@ export default function MangaReadPage() {
|
|||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={chapter.id}
|
key={chapter.id}
|
||||||
href={`/manga/read?mangaId=${mangaId}&sourceId=${sourceId}&chapterId=${chapter.id}&title=${encodeURIComponent(title)}&cover=${encodeURIComponent(cover)}&sourceName=${encodeURIComponent(sourceName)}&chapterName=${encodeURIComponent(chapter.name)}`}
|
href={`/manga/read?mangaId=${mangaId}&sourceId=${sourceId}&chapterId=${chapter.id}&title=${encodeURIComponent(title)}&cover=${encodeURIComponent(cover)}&sourceName=${encodeURIComponent(sourceName)}&chapterName=${encodeURIComponent(chapter.name)}&returnTo=${encodeURIComponent(returnTo)}`}
|
||||||
className={`group relative block rounded-2xl px-4 py-3 text-sm transition ${
|
className={`group relative block rounded-2xl px-4 py-3 text-sm transition ${
|
||||||
active
|
active
|
||||||
? 'bg-sky-600 text-white'
|
? 'bg-sky-600 text-white'
|
||||||
@@ -790,7 +791,7 @@ export default function MangaReadPage() {
|
|||||||
<div className='mt-6 flex flex-col gap-3'>
|
<div className='mt-6 flex flex-col gap-3'>
|
||||||
{nextChapter ? (
|
{nextChapter ? (
|
||||||
<Link
|
<Link
|
||||||
href={`/manga/read?mangaId=${mangaId}&sourceId=${sourceId}&chapterId=${nextChapter.id}&title=${encodeURIComponent(title)}&cover=${encodeURIComponent(cover)}&sourceName=${encodeURIComponent(sourceName)}&chapterName=${encodeURIComponent(nextChapter.name)}`}
|
href={`/manga/read?mangaId=${mangaId}&sourceId=${sourceId}&chapterId=${nextChapter.id}&title=${encodeURIComponent(title)}&cover=${encodeURIComponent(cover)}&sourceName=${encodeURIComponent(sourceName)}&chapterName=${encodeURIComponent(nextChapter.name)}&returnTo=${encodeURIComponent(returnTo)}`}
|
||||||
className='rounded-2xl bg-sky-600 px-4 py-3 text-sm font-medium text-white transition hover:bg-sky-700'
|
className='rounded-2xl bg-sky-600 px-4 py-3 text-sm font-medium text-white transition hover:bg-sky-700'
|
||||||
>
|
>
|
||||||
下一话:{nextChapter.name}
|
下一话:{nextChapter.name}
|
||||||
@@ -894,7 +895,7 @@ export default function MangaReadPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href={`/manga/detail?mangaId=${mangaId}&sourceId=${sourceId}&title=${encodeURIComponent(title)}&cover=${encodeURIComponent(cover)}&sourceName=${encodeURIComponent(sourceName)}`}
|
href={`/manga/detail?mangaId=${mangaId}&sourceId=${sourceId}&title=${encodeURIComponent(title)}&cover=${encodeURIComponent(cover)}&sourceName=${encodeURIComponent(sourceName)}&returnTo=${encodeURIComponent(returnTo)}`}
|
||||||
className='sr-only'
|
className='sr-only'
|
||||||
>
|
>
|
||||||
返回详情
|
返回详情
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ function getMeta(pathname: string, searchParams: ReturnType<typeof useSearchPara
|
|||||||
return {
|
return {
|
||||||
title: searchParams.get('title') || '漫画详情',
|
title: searchParams.get('title') || '漫画详情',
|
||||||
subtitle: searchParams.get('sourceName') || '漫画详情',
|
subtitle: searchParams.get('sourceName') || '漫画详情',
|
||||||
backHref: '/manga',
|
backHref: searchParams.get('returnTo') || '/manga',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (pathname === '/manga/read') {
|
if (pathname === '/manga/read') {
|
||||||
@@ -41,10 +41,11 @@ function getMeta(pathname: string, searchParams: ReturnType<typeof useSearchPara
|
|||||||
const title = searchParams.get('title') || '漫画阅读';
|
const title = searchParams.get('title') || '漫画阅读';
|
||||||
const cover = searchParams.get('cover') || '';
|
const cover = searchParams.get('cover') || '';
|
||||||
const sourceName = searchParams.get('sourceName') || sourceId;
|
const sourceName = searchParams.get('sourceName') || sourceId;
|
||||||
|
const returnTo = searchParams.get('returnTo') || '/manga';
|
||||||
return {
|
return {
|
||||||
title,
|
title,
|
||||||
subtitle: searchParams.get('chapterName') || '章节',
|
subtitle: searchParams.get('chapterName') || '章节',
|
||||||
backHref: `/manga/detail?mangaId=${encodeURIComponent(mangaId)}&sourceId=${encodeURIComponent(sourceId)}&title=${encodeURIComponent(title)}&cover=${encodeURIComponent(cover)}&sourceName=${encodeURIComponent(sourceName)}`,
|
backHref: `/manga/detail?mangaId=${encodeURIComponent(mangaId)}&sourceId=${encodeURIComponent(sourceId)}&title=${encodeURIComponent(title)}&cover=${encodeURIComponent(cover)}&sourceName=${encodeURIComponent(sourceName)}&returnTo=${encodeURIComponent(returnTo)}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return { title: '漫画展馆', subtitle: '搜索漫画并加入书架' };
|
return { title: '漫画展馆', subtitle: '搜索漫画并加入书架' };
|
||||||
@@ -63,7 +64,7 @@ export default function MangaLayout({ children }: MangaLayoutProps) {
|
|||||||
<div className='min-h-screen bg-gray-50 text-gray-900 dark:bg-black dark:text-gray-100'>
|
<div className='min-h-screen bg-gray-50 text-gray-900 dark:bg-black dark:text-gray-100'>
|
||||||
<header className='fixed inset-x-0 top-0 z-[999] border-b border-gray-200/70 bg-white/85 backdrop-blur-xl shadow-sm dark:border-gray-800/80 dark:bg-gray-950/85'>
|
<header className='fixed inset-x-0 top-0 z-[999] border-b border-gray-200/70 bg-white/85 backdrop-blur-xl shadow-sm dark:border-gray-800/80 dark:bg-gray-950/85'>
|
||||||
<div className='mx-auto flex h-14 max-w-7xl items-center gap-3 px-3 sm:h-16 sm:px-6'>
|
<div className='mx-auto flex h-14 max-w-7xl items-center gap-3 px-3 sm:h-16 sm:px-6'>
|
||||||
<div className='flex min-w-0 items-center gap-2'>
|
<div className='flex min-w-0 flex-1 items-center gap-2'>
|
||||||
{meta.backHref ? (
|
{meta.backHref ? (
|
||||||
<Link
|
<Link
|
||||||
href={meta.backHref}
|
href={meta.backHref}
|
||||||
@@ -115,7 +116,7 @@ export default function MangaLayout({ children }: MangaLayoutProps) {
|
|||||||
})}
|
})}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div className={`${isReadingPage ? 'flex' : 'hidden md:flex'} items-center gap-2`}>
|
<div className={`${isReadingPage ? 'ml-auto flex shrink-0' : 'ml-auto hidden md:flex'} items-center gap-2`}>
|
||||||
{isReadingPage ? (
|
{isReadingPage ? (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
|
|||||||
Reference in New Issue
Block a user