feat: adjust mobile style, add force landscape button

This commit is contained in:
shinya
2025-06-23 13:24:18 +08:00
parent 157297c05d
commit 50c9957be8
11 changed files with 87 additions and 33 deletions

View File

@@ -111,7 +111,7 @@ function DetailPageClient() {
return (
<PageLayout activePath='/detail'>
<div className='px-4 sm:px-10 py-4 sm:py-8 overflow-visible'>
<div className='px-2 sm:px-10 py-4 sm:py-8 overflow-visible'>
{/* 顶部返回按钮已移入右侧信息容器 */}
{loading ? (
<div className='flex items-center justify-center min-h-[60vh]'>
@@ -144,7 +144,7 @@ function DetailPageClient() {
window.location.href = '/';
}
}}
className='absolute top-0 left-0 -translate-x-[60%] -translate-y-[30%] sm:-translate-x-[180%] sm:-translate-y-1/2 p-2 rounded transition-colors'
className='absolute top-0 left-0 -translate-x-[40%] -translate-y-[30%] sm:-translate-x-[180%] sm:-translate-y-1/2 p-2 rounded transition-colors'
>
<svg
className='h-5 w-5 text-gray-500 hover:text-green-600 transition-colors'
@@ -309,7 +309,7 @@ function DetailPageClient() {
{detail.episodes.length}
</div>
</div>
<div className='grid grid-cols-3 gap-2 sm:flex sm:flex-wrap sm:gap-4'>
<div className='grid grid-cols-3 gap-2 sm:grid-cols-[repeat(auto-fit,_minmax(6rem,_1fr))] sm:gap-4'>
{detail.episodes.map((episode, idx) => (
<a
key={idx}

View File

@@ -200,7 +200,7 @@ function DoubanPageClient() {
) : (
<>
{/* 内容网格 */}
<div className='grid grid-cols-2 gap-x-2 gap-y-12 px-2 sm:grid-cols-[repeat(auto-fit,minmax(180px,1fr))] sm:gap-x-8 sm:gap-y-20 sm:px-4'>
<div className='grid grid-cols-3 gap-x-2 gap-y-12 px-0 sm:px-2 sm:grid-cols-[repeat(auto-fit,minmax(180px,1fr))] sm:gap-x-8 sm:gap-y-20 sm:px-4'>
{loading
? // 显示骨架屏
skeletonData.map((index) => (

View File

@@ -130,7 +130,7 @@ function HomeClient() {
return (
<PageLayout>
<div className='px-4 sm:px-10 py-4 sm:py-8 overflow-visible'>
<div className='px-2 sm:px-10 py-4 sm:py-8 overflow-visible'>
{/* 顶部 Tab 切换 */}
<div className='mb-8 flex justify-center'>
<CapsuleSwitch
@@ -150,7 +150,7 @@ function HomeClient() {
<h2 className='mb-4 text-xl font-bold text-gray-800 text-left'>
</h2>
<div className='justify-start grid grid-cols-2 gap-x-2 gap-y-20 px-2 sm:grid-cols-[repeat(auto-fill,_minmax(11rem,_1fr))] sm:gap-x-8 sm:px-4'>
<div className='justify-start grid grid-cols-3 gap-x-2 gap-y-14 sm:gap-y-20 px-2 sm:grid-cols-[repeat(auto-fill,_minmax(11rem,_1fr))] sm:gap-x-8 sm:px-4'>
{favoriteItems.map((item) => (
<div key={item.id + item.source} className='w-full'>
<VideoCard {...item} from='favorites' />
@@ -175,7 +175,7 @@ function HomeClient() {
{collections.map((collection) => (
<div
key={collection.title}
className='min-w-[180px] w-44 sm:min-w-[280px] sm:w-72'
className='min-w-[150px] w-44 sm:min-w-[280px] sm:w-72'
>
<CollectionCard
title={collection.title}
@@ -201,7 +201,7 @@ function HomeClient() {
Array.from({ length: 8 }).map((_, index) => (
<div
key={index}
className='min-w-[140px] w-36 sm:min-w-[180px] sm:w-44'
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
>
<div className='relative aspect-[2/3] w-full overflow-hidden rounded-lg bg-gray-200 animate-pulse'>
<div className='absolute inset-0 bg-gray-300'></div>
@@ -213,7 +213,7 @@ function HomeClient() {
hotMovies.map((movie, index) => (
<div
key={index}
className='min-w-[140px] w-36 sm:min-w-[180px] sm:w-44'
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
>
<DemoCard title={movie.title} poster={movie.poster} />
</div>
@@ -232,7 +232,7 @@ function HomeClient() {
Array.from({ length: 8 }).map((_, index) => (
<div
key={index}
className='min-w-[140px] w-36 sm:min-w-[180px] sm:w-44'
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
>
<div className='relative aspect-[2/3] w-full overflow-hidden rounded-lg bg-gray-200 animate-pulse'>
<div className='absolute inset-0 bg-gray-300'></div>
@@ -244,7 +244,7 @@ function HomeClient() {
hotTvShows.map((show, index) => (
<div
key={index}
className='min-w-[140px] w-36 sm:min-w-[180px] sm:w-44'
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
>
<DemoCard title={show.title} poster={show.poster} />
</div>

View File

@@ -90,6 +90,12 @@ function PlayPageClient() {
// 是否显示旋转提示5s 后自动隐藏)
const [showOrientationTip, setShowOrientationTip] = useState(false);
const orientationTipTimeoutRef = useRef<NodeJS.Timeout | null>(null);
// 当前是否处于竖屏,用于控制"强制横屏"按钮显隐
const [isPortrait, setIsPortrait] = useState(
typeof window !== 'undefined'
? window.matchMedia('(orientation: portrait)').matches
: true
);
// 长按三倍速相关状态
const [isLongPressing, setIsLongPressing] = useState(false);
@@ -1029,6 +1035,9 @@ function PlayPageClient() {
const update = () => {
const portrait = mql.matches;
// 更新竖屏状态
setIsPortrait(portrait);
// 在进入竖屏时显示提示5 秒后自动隐藏
if (portrait) {
setShowOrientationTip(true);
@@ -1068,7 +1077,25 @@ function PlayPageClient() {
};
}, []);
// 进入/退出全屏锁定/解锁横屏
// 用户点击悬浮按钮 -> 请求全屏锁定横屏
const handleForceLandscape = async () => {
try {
const el: any = artRef.current || document.documentElement;
if (el.requestFullscreen) {
await el.requestFullscreen();
} else if (el.webkitRequestFullscreen) {
el.webkitRequestFullscreen();
}
if (screen.orientation && (screen.orientation as any).lock) {
await (screen.orientation as any).lock('landscape');
}
} catch (err) {
console.warn('强制横屏失败:', err);
}
};
// 进入/退出全屏时锁定/解锁横屏(保持原有逻辑)
useEffect(() => {
if (typeof document === 'undefined') return;
@@ -1293,6 +1320,28 @@ function PlayPageClient() {
</div>
)}
{/* 强制横屏按钮:仅在移动端竖屏时显示 */}
{isPortrait && (
<button
onClick={handleForceLandscape}
className='fixed bottom-16 left-4 z-[195] w-10 h-10 rounded-full bg-gray-800 text-white flex items-center justify-center md:hidden'
>
<svg
className='w-6 h-6'
fill='none'
stroke='currentColor'
viewBox='0 0 24 24'
>
<path
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth={2}
d='M3 18v-6a3 3 0 013-3h12M21 6v6a3 3 0 01-3 3H6'
/>
</svg>
</button>
)}
{/* 换源加载遮罩 */}
{sourceChanging && (
<div className='fixed inset-0 bg-black/50 z-[200] flex items-center justify-center'>

View File

@@ -1,3 +1,4 @@
/* eslint-disable react-hooks/exhaustive-deps */
'use client';
import { Search } from 'lucide-react';
@@ -37,8 +38,10 @@ function SearchPageClient() {
const searchInputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
// 自动聚焦搜索框
searchInputRef.current?.focus();
// 自动聚焦搜索框:仅当 URL 中没有搜索参数时
if (!searchParams.get('q')) {
searchInputRef.current?.focus();
}
// 加载搜索历史
(async () => {
@@ -125,7 +128,7 @@ function SearchPageClient() {
</div>
) : showResults ? (
// 搜索结果
<div className='justify-start grid grid-cols-2 gap-x-2 gap-y-20 px-2 sm:grid-cols-[repeat(auto-fill,_minmax(11rem,_1fr))] sm:gap-x-8 sm:px-4'>
<div className='justify-start grid grid-cols-3 gap-x-2 gap-y-14 sm:gap-y-20 px-0 sm:px-2 sm:grid-cols-[repeat(auto-fill,_minmax(11rem,_1fr))] sm:gap-x-8 sm:px-4'>
{searchResults.map((item) => (
<div key={item.id} className='w-full'>
<VideoCard {...item} from='search' />