save
This commit is contained in:
parent
18fd3ede2c
commit
dc24d5b6ed
117 changed files with 36876 additions and 7 deletions
257
client/limo-mobile-h5/app/m-space/page.tsx
Normal file
257
client/limo-mobile-h5/app/m-space/page.tsx
Normal file
|
@ -0,0 +1,257 @@
|
|||
"use client"
|
||||
|
||||
import type React from "react"
|
||||
|
||||
import { useState, useRef } from "react"
|
||||
import Image from "next/image"
|
||||
import { X, Heart, MessageCircle, Share, Play, Volume2, VolumeX } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
|
||||
interface VideoData {
|
||||
id: number
|
||||
venue: string
|
||||
title: string
|
||||
description: string
|
||||
likes: number
|
||||
comments: number
|
||||
shares: number
|
||||
videoUrl: string
|
||||
thumbnail: string
|
||||
isLiked: boolean
|
||||
}
|
||||
|
||||
const mockVideos: VideoData[] = [
|
||||
{
|
||||
id: 1,
|
||||
venue: "RONIN黄金篮球馆",
|
||||
title: "精彩三分球集锦",
|
||||
description: "今日比赛精彩瞬间,连续三分命中!#篮球 #精彩瞬间",
|
||||
likes: 1234,
|
||||
comments: 89,
|
||||
shares: 45,
|
||||
videoUrl: "/placeholder.svg?height=800&width=400&text=Basketball+Highlights",
|
||||
thumbnail: "/placeholder.svg?height=800&width=400&text=Basketball+Game+1",
|
||||
isLiked: false,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
venue: "Panda惊怒熊猫运动俱乐部",
|
||||
title: "激烈对抗瞬间",
|
||||
description: "双方激烈对抗,精彩防守反击!#运动 #篮球对抗",
|
||||
likes: 2156,
|
||||
comments: 156,
|
||||
shares: 78,
|
||||
videoUrl: "/placeholder.svg?height=800&width=400&text=Basketball+Defense",
|
||||
thumbnail: "/placeholder.svg?height=800&width=400&text=Basketball+Game+2",
|
||||
isLiked: true,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
venue: "星光篮球场",
|
||||
title: "完美扣篮时刻",
|
||||
description: "力量与技巧的完美结合,震撼扣篮!#扣篮 #力量",
|
||||
likes: 3421,
|
||||
comments: 234,
|
||||
shares: 123,
|
||||
videoUrl: "/placeholder.svg?height=800&width=400&text=Basketball+Dunk",
|
||||
thumbnail: "/placeholder.svg?height=800&width=400&text=Basketball+Game+3",
|
||||
isLiked: false,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
venue: "蓝天体育馆",
|
||||
title: "团队配合精彩",
|
||||
description: "完美的团队配合,流畅的传球配合!#团队 #配合",
|
||||
likes: 987,
|
||||
comments: 67,
|
||||
shares: 34,
|
||||
videoUrl: "/placeholder.svg?height=800&width=400&text=Team+Play",
|
||||
thumbnail: "/placeholder.svg?height=800&width=400&text=Basketball+Game+4",
|
||||
isLiked: false,
|
||||
},
|
||||
]
|
||||
|
||||
export default function MSpacePage() {
|
||||
const [currentIndex, setCurrentIndex] = useState(0)
|
||||
const [videos, setVideos] = useState(mockVideos)
|
||||
const [isPlaying, setIsPlaying] = useState(true)
|
||||
const [isMuted, setIsMuted] = useState(false)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const startY = useRef(0)
|
||||
const currentY = useRef(0)
|
||||
|
||||
const handleTouchStart = (e: React.TouchEvent) => {
|
||||
startY.current = e.touches[0].clientY
|
||||
}
|
||||
|
||||
const handleTouchMove = (e: React.TouchEvent) => {
|
||||
currentY.current = e.touches[0].clientY
|
||||
}
|
||||
|
||||
const handleTouchEnd = () => {
|
||||
const deltaY = startY.current - currentY.current
|
||||
const threshold = 50
|
||||
|
||||
if (Math.abs(deltaY) > threshold) {
|
||||
if (deltaY > 0 && currentIndex < videos.length - 1) {
|
||||
// 向上滑动,下一个视频
|
||||
setCurrentIndex(currentIndex + 1)
|
||||
} else if (deltaY < 0 && currentIndex > 0) {
|
||||
// 向下滑动,上一个视频
|
||||
setCurrentIndex(currentIndex - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleLike = (videoId: number) => {
|
||||
setVideos(
|
||||
videos.map((video) => {
|
||||
if (video.id === videoId) {
|
||||
return {
|
||||
...video,
|
||||
isLiked: !video.isLiked,
|
||||
likes: video.isLiked ? video.likes - 1 : video.likes + 1,
|
||||
}
|
||||
}
|
||||
return video
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
const formatNumber = (num: number) => {
|
||||
if (num >= 1000) {
|
||||
return (num / 1000).toFixed(1) + "k"
|
||||
}
|
||||
return num.toString()
|
||||
}
|
||||
|
||||
const currentVideo = videos[currentIndex]
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black overflow-hidden">
|
||||
{/* Header - Minimized */}
|
||||
<div className="absolute top-0 left-0 right-0 z-20 p-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Link href="/">
|
||||
<div className="w-8 h-8 bg-black bg-opacity-30 rounded-full flex items-center justify-center">
|
||||
<X className="w-4 h-4 text-white" />
|
||||
</div>
|
||||
</Link>
|
||||
<div className="text-white text-sm font-medium">M空间</div>
|
||||
<div className="w-8 h-8"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Video Container */}
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="h-full w-full relative"
|
||||
onTouchStart={handleTouchStart}
|
||||
onTouchMove={handleTouchMove}
|
||||
onTouchEnd={handleTouchEnd}
|
||||
style={{
|
||||
transform: `translateY(-${currentIndex * 100}%)`,
|
||||
transition: "transform 0.3s ease-out",
|
||||
}}
|
||||
>
|
||||
{videos.map((video, index) => (
|
||||
<div key={video.id} className="absolute inset-0 w-full h-full" style={{ top: `${index * 100}%` }}>
|
||||
{/* Video Background */}
|
||||
<div className="relative w-full h-full">
|
||||
<Image
|
||||
src={video.thumbnail || "/placeholder.svg"}
|
||||
alt={video.title}
|
||||
fill
|
||||
className="object-cover"
|
||||
priority={Math.abs(index - currentIndex) <= 1}
|
||||
/>
|
||||
|
||||
{/* Video Overlay */}
|
||||
<div className="absolute inset-0 bg-black bg-opacity-10" />
|
||||
|
||||
{/* Play/Pause Button - Minimized */}
|
||||
<div
|
||||
className="absolute inset-0 flex items-center justify-center"
|
||||
onClick={() => setIsPlaying(!isPlaying)}
|
||||
>
|
||||
{!isPlaying && (
|
||||
<div className="w-12 h-12 bg-white bg-opacity-20 rounded-full flex items-center justify-center">
|
||||
<Play className="w-6 h-6 text-white ml-0.5" fill="currentColor" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Side Actions - Minimized */}
|
||||
<div className="absolute right-3 bottom-24 flex flex-col items-center space-y-4">
|
||||
{/* Like Button */}
|
||||
<div className="flex flex-col items-center">
|
||||
<button
|
||||
onClick={() => handleLike(video.id)}
|
||||
className={`w-9 h-9 rounded-full flex items-center justify-center ${
|
||||
video.isLiked ? "bg-red-500" : "bg-black bg-opacity-20"
|
||||
}`}
|
||||
>
|
||||
<Heart
|
||||
className={`w-4 h-4 ${video.isLiked ? "text-white" : "text-white"}`}
|
||||
fill={video.isLiked ? "currentColor" : "none"}
|
||||
/>
|
||||
</button>
|
||||
<span className="text-white text-xs mt-1 font-medium">{formatNumber(video.likes)}</span>
|
||||
</div>
|
||||
|
||||
{/* Comment Button */}
|
||||
<div className="flex flex-col items-center">
|
||||
<button className="w-9 h-9 bg-black bg-opacity-20 rounded-full flex items-center justify-center">
|
||||
<MessageCircle className="w-4 h-4 text-white" />
|
||||
</button>
|
||||
<span className="text-white text-xs mt-1 font-medium">{formatNumber(video.comments)}</span>
|
||||
</div>
|
||||
|
||||
{/* Share Button */}
|
||||
<div className="flex flex-col items-center">
|
||||
<button className="w-9 h-9 bg-black bg-opacity-20 rounded-full flex items-center justify-center">
|
||||
<Share className="w-4 h-4 text-white" />
|
||||
</button>
|
||||
<span className="text-white text-xs mt-1 font-medium">{formatNumber(video.shares)}</span>
|
||||
</div>
|
||||
|
||||
{/* Volume Button */}
|
||||
<button
|
||||
onClick={() => setIsMuted(!isMuted)}
|
||||
className="w-9 h-9 bg-black bg-opacity-20 rounded-full flex items-center justify-center"
|
||||
>
|
||||
{isMuted ? <VolumeX className="w-4 h-4 text-white" /> : <Volume2 className="w-4 h-4 text-white" />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Bottom Info - Minimized */}
|
||||
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/50 to-transparent p-3 pb-6">
|
||||
<div className="max-w-xs">
|
||||
<h3 className="text-white font-medium text-base mb-1">{video.venue}</h3>
|
||||
<p className="text-white text-sm opacity-90 leading-relaxed line-clamp-2">{video.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress Indicator - Minimized */}
|
||||
<div className="absolute right-1 top-1/2 transform -translate-y-1/2 flex flex-col space-y-1">
|
||||
{videos.map((_, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={`w-0.5 h-6 rounded-full ${idx === currentIndex ? "bg-white" : "bg-white bg-opacity-30"}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Swipe Hint - Minimized */}
|
||||
{currentIndex === 0 && (
|
||||
<div className="absolute bottom-16 left-1/2 transform -translate-x-1/2 text-white text-xs opacity-60 animate-bounce">
|
||||
上滑查看更多
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue