优化漫画界面

This commit is contained in:
mtvpls
2026-04-16 23:28:19 +08:00
parent 68274900b4
commit d3b267380f
14 changed files with 1593 additions and 1275 deletions
+78 -64
View File
@@ -1,6 +1,6 @@
'use client';
'use client';
import { BookOpen, ChevronLeft, History, Home, Search, Settings2 } from 'lucide-react';
import { BookOpen, ChevronLeft, History, Home, List, Search, Settings2 } from 'lucide-react';
import Link from 'next/link';
import { usePathname, useSearchParams } from 'next/navigation';
@@ -62,66 +62,83 @@ export default function MangaLayout({ children }: MangaLayoutProps) {
return (
<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'>
<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'>
{meta.backHref ? (
<Link
href={meta.backHref}
className='flex h-10 w-10 items-center justify-center rounded-full text-gray-600 transition hover:bg-gray-100 hover:text-sky-600 dark:text-gray-300 dark:hover:bg-gray-800'
>
<ChevronLeft className='h-5 w-5' />
</Link>
) : (
<Link
href='/'
className='flex h-10 items-center rounded-full px-3 text-sm font-semibold text-sky-600 transition hover:bg-sky-50 dark:hover:bg-sky-950/40'
>
{siteName}
</Link>
)}
<div className='min-w-0'>
<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'>
{meta.backHref ? (
<Link
href={meta.backHref}
className='flex h-10 w-10 items-center justify-center rounded-full text-gray-600 transition hover:bg-gray-100 hover:text-sky-600 dark:text-gray-300 dark:hover:bg-gray-800'
>
<ChevronLeft className='h-5 w-5' />
</Link>
) : (
<Link
href='/'
className='flex h-10 items-center rounded-full px-3 text-sm font-semibold text-sky-600 transition hover:bg-sky-50 dark:hover:bg-sky-950/40'
>
{siteName}
</Link>
)}
<div className='min-w-0'>
<div className='group relative'>
<div className='truncate text-sm font-semibold sm:text-base'>{meta.title}</div>
{meta.subtitle && (
<div className='truncate text-xs text-gray-500 dark:text-gray-400'>
{meta.subtitle}
</div>
)}
<div className='absolute top-full left-1/2 transform -translate-x-1/2 mt-2 px-3 py-2 bg-gray-800 dark:bg-gray-900 text-white text-sm rounded-lg shadow-xl opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 ease-out z-[100] pointer-events-none w-max max-w-[85vw] whitespace-normal break-words text-center sm:max-w-none sm:whitespace-nowrap'>
<div className='text-sm'>{meta.title}</div>
</div>
</div>
{meta.subtitle && (
<div className='truncate text-xs text-gray-500 dark:text-gray-400'>
{meta.subtitle}
</div>
)}
</div>
</div>
<nav className='ml-auto hidden items-center gap-2 lg:flex'>
{sectionTabs.map((tab) => {
const Icon = tab.icon;
const active = isActive(tab.href);
return (
<Link
key={tab.href}
href={tab.href}
className={`inline-flex items-center gap-2 rounded-full px-4 py-2 text-sm transition ${
active
? 'bg-sky-600 text-white shadow-sm'
: 'text-gray-600 hover:bg-gray-100 hover:text-sky-600 dark:text-gray-300 dark:hover:bg-gray-800'
}`}
>
<Icon className='h-4 w-4' />
{tab.label}
</Link>
);
})}
</nav>
<nav className='ml-auto hidden items-center gap-2 lg:flex'>
{sectionTabs.map((tab) => {
const Icon = tab.icon;
const active = isActive(tab.href);
return (
<Link
key={tab.href}
href={tab.href}
className={`inline-flex items-center gap-2 rounded-full px-4 py-2 text-sm transition ${
active
? 'bg-sky-600 text-white shadow-sm'
: 'text-gray-600 hover:bg-gray-100 hover:text-sky-600 dark:text-gray-300 dark:hover:bg-gray-800'
}`}
>
<Icon className='h-4 w-4' />
{tab.label}
</Link>
);
})}
</nav>
<div className={`${isReadingPage ? 'flex' : 'hidden md:flex'} items-center gap-2`}>
{isReadingPage ? (
<button
type='button'
className='inline-flex h-10 w-10 items-center justify-center rounded-full text-gray-600 transition hover:bg-gray-100 hover:text-sky-600 dark:text-gray-300 dark:hover:bg-gray-800'
onClick={() => {
window.dispatchEvent(new CustomEvent('manga-read-toggle-settings'));
}}
aria-label='阅读设置'
>
<Settings2 className='h-5 w-5' />
</button>
<>
<button
type='button'
className='inline-flex h-10 w-10 items-center justify-center rounded-full text-gray-600 transition hover:bg-gray-100 hover:text-sky-600 dark:text-gray-300 dark:hover:bg-gray-800'
onClick={() => {
window.dispatchEvent(new CustomEvent('manga-read-toggle-chapters'));
}}
aria-label='章节列表'
>
<List className='h-5 w-5' />
</button>
<button
type='button'
className='inline-flex h-10 w-10 items-center justify-center rounded-full text-gray-600 transition hover:bg-gray-100 hover:text-sky-600 dark:text-gray-300 dark:hover:bg-gray-800'
onClick={() => {
window.dispatchEvent(new CustomEvent('manga-read-toggle-settings'));
}}
aria-label='阅读设置'
>
<Settings2 className='h-5 w-5' />
</button>
</>
) : (
<>
<ThemeToggle />
@@ -134,15 +151,16 @@ export default function MangaLayout({ children }: MangaLayoutProps) {
</header>
<main
className='mx-auto max-w-7xl px-3 pb-24 pt-20 sm:px-6 sm:pb-28 sm:pt-24'
style={{ paddingBottom: isReadingPage ? undefined : 'calc(5rem + env(safe-area-inset-bottom))' }}
className={`mx-auto max-w-7xl px-3 pt-20 sm:px-6 sm:pt-24 ${
isReadingPage ? 'pb-24 sm:pb-28 lg:pb-10' : 'pb-[calc(5rem+env(safe-area-inset-bottom))] sm:pb-[calc(5rem+env(safe-area-inset-bottom))] lg:pb-10'
}`}
>
{children}
</main>
{!isReadingPage && (
<nav
className='fixed inset-x-0 bottom-0 z-[998] border-t border-gray-200/70 bg-white/92 backdrop-blur-xl dark:border-gray-800/80 dark:bg-gray-950/92'
className='fixed inset-x-0 bottom-0 z-[998] border-t border-gray-200/70 bg-white/92 backdrop-blur-xl dark:border-gray-800/80 dark:bg-gray-950/92 lg:hidden'
style={{ paddingBottom: 'env(safe-area-inset-bottom)' }}
>
<div className='mx-auto grid max-w-3xl grid-cols-4'>
@@ -157,16 +175,12 @@ export default function MangaLayout({ children }: MangaLayoutProps) {
>
<Icon
className={`h-5 w-5 ${
active
? 'text-sky-600 dark:text-sky-400'
: 'text-gray-500 dark:text-gray-400'
active ? 'text-sky-600 dark:text-sky-400' : 'text-gray-500 dark:text-gray-400'
}`}
/>
<span
className={
active
? 'text-sky-600 dark:text-sky-400'
: 'text-gray-600 dark:text-gray-300'
active ? 'text-sky-600 dark:text-sky-400' : 'text-gray-600 dark:text-gray-300'
}
>
{tab.label}