diff --git a/src/app/detail/page.tsx b/src/app/detail/page.tsx index 755a273..0a3c7d7 100644 --- a/src/app/detail/page.tsx +++ b/src/app/detail/page.tsx @@ -59,7 +59,7 @@ export default function DetailPage() {
未找到视频详情
) : ( -
+
{/* 主信息区:左图右文 */}
{/* 封面 */} diff --git a/src/app/globals.css b/src/app/globals.css index bf6a451..60d9647 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -2,10 +2,27 @@ @tailwind components; @tailwind utilities; +@layer utilities { + .scrollbar-hide { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + } + + .scrollbar-hide::-webkit-scrollbar { + display: none; /* Chrome, Safari and Opera */ + } +} + :root { --foreground-rgb: 255, 255, 255; } +html, +body { + height: 100%; + overflow-x: hidden; +} + body { color: rgb(var(--foreground-rgb)); background: linear-gradient( @@ -18,7 +35,6 @@ body { #d3dde6 100% ); background-attachment: fixed; - min-height: 100vh; } /* 自定义滚动条样式 */ diff --git a/src/app/page.tsx b/src/app/page.tsx index bc37984..669b52c 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -5,6 +5,7 @@ import { useState } from 'react'; import CapsuleSwitch from '@/components/CapsuleSwitch'; import DemoCard from '@/components/DemoCard'; import PageLayout from '@/components/layout/PageLayout'; +import ScrollableRow from '@/components/ScrollableRow'; import VideoCard from '@/components/VideoCard'; const defaultPoster = @@ -45,6 +46,38 @@ const mockData = { source: 'dyttzy', source_name: '电影天堂', }, + { + id: '332', + title: '三体', + poster: defaultPoster, + source: 'dyttzy', + source_name: '电影天堂', + episodes: 30, + }, + { + id: '4231', + title: '狂飙', + poster: defaultPoster, + episodes: 39, + source: 'dyttzy', + source_name: '电影天堂', + }, + { + id: '3342', + title: '三体', + poster: defaultPoster, + source: 'dyttzy', + source_name: '电影天堂', + episodes: 30, + }, + { + id: '8', + title: '狂飙', + poster: defaultPoster, + episodes: 39, + source: 'dyttzy', + source_name: '电影天堂', + }, ], }; @@ -66,49 +99,49 @@ export default function Home() { />
-
+
{/* 继续观看 */} -
+

继续观看

-
- {[...mockData.recentMovies, ...mockData.recentTvShows] - .slice(0, 4) - .map((item) => ( -
+ + {[...mockData.recentMovies, ...mockData.recentTvShows].map( + (item) => ( +
- ))} -
+ ) + )} +
{/* 最新电影 */} -
+

最新电影

-
+ {mockData.recentMovies.map((movie) => ( -
+
))} -
+
{/* 最新电视剧 */} -
+

最新电视剧

-
+ {mockData.recentTvShows.map((show) => ( -
+
))} -
+
diff --git a/src/app/search/page.tsx b/src/app/search/page.tsx index daf82d2..ebfc2ee 100644 --- a/src/app/search/page.tsx +++ b/src/app/search/page.tsx @@ -75,7 +75,7 @@ export default function SearchPage() { return ( -
+
{/* 搜索框 */}
@@ -94,21 +94,21 @@ export default function SearchPage() {
{/* 搜索结果或搜索历史 */} -
+
{isLoading ? (
) : showResults ? ( // 搜索结果 -
+
{searchResults.map((item) => (
))} {searchResults.length === 0 && ( -
+
未找到相关结果
)} diff --git a/src/components/DemoCard.tsx b/src/components/DemoCard.tsx index d712cdb..ef7426d 100644 --- a/src/components/DemoCard.tsx +++ b/src/components/DemoCard.tsx @@ -62,7 +62,7 @@ const DemoCard = ({ title, poster }: DemoCardProps) => { return (
{/* 海报图片 - 2:3 比例 */} @@ -84,7 +84,7 @@ const DemoCard = ({ title, poster }: DemoCardProps) => {
{/* 信息层 */} -
+
{title} diff --git a/src/components/ScrollableRow.tsx b/src/components/ScrollableRow.tsx new file mode 100644 index 0000000..f8859c2 --- /dev/null +++ b/src/components/ScrollableRow.tsx @@ -0,0 +1,155 @@ +import { ChevronLeft, ChevronRight } from 'lucide-react'; +import { useEffect, useRef, useState } from 'react'; + +interface ScrollableRowProps { + children: React.ReactNode; +} + +export default function ScrollableRow({ children }: ScrollableRowProps) { + const containerRef = useRef(null); + const [showLeftScroll, setShowLeftScroll] = useState(false); + const [showRightScroll, setShowRightScroll] = useState(false); + const [isHovered, setIsHovered] = useState(false); + + const checkScroll = () => { + if (containerRef.current) { + const { scrollWidth, clientWidth, scrollLeft } = containerRef.current; + + // 计算是否需要左右滚动按钮 + const threshold = 1; // 容差值,避免浮点误差 + const canScrollRight = + scrollWidth - (scrollLeft + clientWidth) > threshold; + const canScrollLeft = scrollLeft > threshold; + + setShowRightScroll(canScrollRight); + setShowLeftScroll(canScrollLeft); + } + }; + + useEffect(() => { + // 多次延迟检查,确保内容已完全渲染 + checkScroll(); + + // 监听窗口大小变化 + window.addEventListener('resize', checkScroll); + + // 创建一个 ResizeObserver 来监听容器大小变化 + const resizeObserver = new ResizeObserver(() => { + // 延迟执行检查 + checkScroll(); + }); + + if (containerRef.current) { + resizeObserver.observe(containerRef.current); + } + + return () => { + window.removeEventListener('resize', checkScroll); + resizeObserver.disconnect(); + }; + }, [children]); // 依赖 children,当子组件变化时重新检查 + + // 添加一个额外的效果来监听子组件的变化 + useEffect(() => { + if (containerRef.current) { + // 监听 DOM 变化 + const observer = new MutationObserver(() => { + setTimeout(checkScroll, 100); + }); + + observer.observe(containerRef.current, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: ['style', 'class'], + }); + + return () => observer.disconnect(); + } + }, []); + + const handleScrollRightClick = () => { + if (containerRef.current) { + containerRef.current.scrollBy({ left: 800, behavior: 'smooth' }); + } + }; + + const handleScrollLeftClick = () => { + if (containerRef.current) { + containerRef.current.scrollBy({ left: -800, behavior: 'smooth' }); + } + }; + + return ( +
{ + setIsHovered(true); + // 当鼠标进入时重新检查一次 + checkScroll(); + }} + onMouseLeave={() => setIsHovered(false)} + > +
+ {children} +
+ {showLeftScroll && ( +
+
e.stopPropagation()} + /> +
+ +
+
+ )} + + {showRightScroll && ( +
+
e.stopPropagation()} + /> +
+ +
+
+ )} +
+ ); +} diff --git a/src/components/VideoCard.tsx b/src/components/VideoCard.tsx index 11ee878..3db633d 100644 --- a/src/components/VideoCard.tsx +++ b/src/components/VideoCard.tsx @@ -78,7 +78,7 @@ export default function VideoCard({ return ( -
+
{/* 海报图片 - 2:3 比例 */}
{title} @@ -122,7 +122,7 @@ export default function VideoCard({
{/* 信息层 */} -
+
{title} diff --git a/src/components/layout/PageLayout.tsx b/src/components/layout/PageLayout.tsx index ef3cf0c..356455e 100644 --- a/src/components/layout/PageLayout.tsx +++ b/src/components/layout/PageLayout.tsx @@ -10,10 +10,10 @@ const PageLayout = ({ children, activePath = '/' }: PageLayoutProps) => { const { isCollapsed } = useSidebar(); return ( -
+