feat: finish new play page

This commit is contained in:
shinya
2025-07-07 23:04:02 +08:00
parent 0abeae5bda
commit 43d2bd27cf
7 changed files with 857 additions and 2382 deletions

View File

@@ -0,0 +1,13 @@
import { ArrowLeft } from 'lucide-react';
export function BackButton() {
return (
<button
onClick={() => window.history.back()}
className='w-10 h-10 p-2 rounded-full flex items-center justify-center text-gray-600 hover:bg-gray-200/50 dark:text-gray-300 dark:hover:bg-gray-700/50 transition-colors'
aria-label='Back'
>
<ArrowLeft className='w-full h-full' />
</button>
);
}

View File

@@ -1,5 +1,6 @@
/* eslint-disable @next/next/no-img-element */
import { useRouter } from 'next/navigation';
import React, {
useCallback,
useEffect,
@@ -48,6 +49,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
sourceSearchLoading = false,
sourceSearchError = null,
}) => {
const router = useRouter();
const pageCount = Math.ceil(totalEpisodes / episodesPerPage);
// 主要的 tab 状态:'episodes' 或 'sources'
@@ -123,7 +125,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
);
return (
<div className='md:ml-6 px-6 py-0 h-full rounded-2xl bg-black/10 dark:bg-white/5 flex flex-col border border-white/0 dark:border-white/30 overflow-hidden'>
<div className='md:ml-2 px-4 py-0 h-full rounded-xl bg-black/10 dark:bg-white/5 flex flex-col border border-white/0 dark:border-white/30 overflow-hidden'>
{/* 主要的 Tab 切换 - 无缝融入设计 */}
<div className='flex mb-1 -mx-6 flex-shrink-0'>
<div
@@ -345,6 +347,20 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
</div>
);
})}
<div className='flex-shrink-0 mt-auto pt-2 border-t border-gray-400 dark:border-gray-700'>
<button
onClick={() => {
if (videoTitle) {
router.push(
`/search?q=${encodeURIComponent(videoTitle)}`
);
}
}}
className='w-full text-center text-xs text-gray-500 dark:text-gray-400 hover:text-green-500 dark:hover:text-green-400 transition-colors py-2'
>
</button>
</div>
</div>
)}
</div>

View File

@@ -2,14 +2,27 @@
import Link from 'next/link';
import { BackButton } from './BackButton';
import { LogoutButton } from './LogoutButton';
import { useSite } from './SiteProvider';
import { ThemeToggle } from './ThemeToggle';
const MobileHeader = () => {
interface MobileHeaderProps {
showBackButton?: boolean;
}
const MobileHeader = ({ showBackButton = false }: MobileHeaderProps) => {
const { siteName } = useSite();
return (
<header className='md:hidden relative w-full bg-white/70 backdrop-blur-xl border-b border-gray-200/50 shadow-sm dark:bg-gray-900/70 dark:border-gray-700/50'>
{/* 返回按钮 */}
{showBackButton && (
<div className='absolute top-1/2 left-4 -translate-y-1/2'>
<BackButton />
</div>
)}
{/* 站点名称 */}
<div className='h-12 flex items-center justify-center'>
<Link
href='/'
@@ -18,6 +31,8 @@ const MobileHeader = () => {
{siteName}
</Link>
</div>
{/* 右侧按钮 */}
<div className='absolute top-1/2 right-4 -translate-y-1/2 flex items-center gap-2'>
<LogoutButton />
<ThemeToggle />

View File

@@ -1,7 +1,7 @@
import { BackButton } from './BackButton';
import { LogoutButton } from './LogoutButton';
import MobileBottomNav from './MobileBottomNav';
import MobileHeader from './MobileHeader';
import { useSidebar } from './Sidebar';
import Sidebar from './Sidebar';
import { ThemeToggle } from './ThemeToggle';
@@ -11,40 +11,48 @@ interface PageLayoutProps {
}
const PageLayout = ({ children, activePath = '/' }: PageLayoutProps) => {
const { isCollapsed } = useSidebar();
return (
<>
{/* 桌面端布局 */}
<div className='hidden md:grid md:grid-cols-[auto_1fr] w-full'>
<Sidebar activePath={activePath} />
<div
className={`relative min-w-0 transition-all duration-300 ${
isCollapsed ? 'col-start-2' : 'col-start-2'
}`}
>
<div className='w-full min-h-screen'>
{/* 移动端头部 */}
<MobileHeader showBackButton={activePath === '/play'} />
{/* 主要布局容器 */}
<div className='flex md:grid md:grid-cols-[auto_1fr] w-full min-h-screen md:min-h-auto'>
{/* 侧边栏 - 桌面端显示,移动端隐藏 */}
<div className='hidden md:block'>
<Sidebar activePath={activePath} />
</div>
{/* 主内容区域 */}
<div className='relative min-w-0 flex-1 transition-all duration-300'>
{/* 桌面端左上角返回按钮 */}
<div className='absolute top-3 left-1 z-20 hidden md:flex'>
<BackButton />
</div>
{/* 桌面端顶部按钮 */}
<div className='absolute top-2 right-4 z-20 hidden md:flex items-center gap-2'>
<LogoutButton />
<ThemeToggle />
</div>
{children}
{/* 主内容 */}
<main
className='flex-1 md:min-h-0 mb-14 md:mb-0'
style={{
paddingBottom: 'calc(3.5rem + env(safe-area-inset-bottom))',
}}
>
{children}
</main>
</div>
</div>
{/* 移动端布局 */}
<div className='md:hidden flex flex-col min-h-screen w-full'>
<MobileHeader />
<main
className='flex-1 mb-14'
style={{
paddingBottom: 'calc(3.5rem + env(safe-area-inset-bottom))',
}}
>
{children}
</main>
{/* 移动端底部导航 */}
<div className='md:hidden'>
<MobileBottomNav activePath={activePath} />
</div>
</>
</div>
);
};