videofolxtv/client/src/pages/GeschichteLiedPage.tsx
sebastjanartic f90d639dbd Adjust spacing and ad placement on various content pages
Modify pagination margin and conditionally render inline ads on FolxStadlPage, GeschichteLiedPage, and GipfelstammtischPage to improve layout and ad visibility.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 401e2ec0-e00d-4f10-9d0e-60f3d479f9a5
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/60d372ff-2c10-46c7-b01b-10c3435136b0/401e2ec0-e00d-4f10-9d0e-60f3d479f9a5/aTy9jKE
2025-09-28 20:24:21 +00:00

384 lines
17 KiB
TypeScript

import { useQuery } from '@tanstack/react-query';
import { Link, useLocation } from 'wouter';
import { ArrowLeft, ChevronLeft, ChevronRight, Menu, X } from 'lucide-react';
import VideoCard from '@/components/video-card';
import BunnyVideoModal from '@/components/bunny-video-modal';
import { Button } from '@/components/ui/button';
import { useState, useEffect } from 'react';
import type { Video } from '@shared/schema';
import { Input } from '@/components/ui/input';
import { Search } from 'lucide-react';
import AdSenseAd from '@/components/adsense-ad';
import HeaderAd from '@/components/HeaderAd';
import InlineAd from '@/components/InlineAd';
export default function GeschichteLiedPage() {
const [selectedVideo, setSelectedVideo] = useState<Video | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
const [, setLocation] = useLocation();
const [touchStart, setTouchStart] = useState<number>(0);
const [touchEnd, setTouchEnd] = useState<number>(0);
const itemsPerPage = 10;
const { data, isLoading } = useQuery<{videos: Video[], total: number}>({
queryKey: ['/api/videos?limit=600'],
select: (response) => response || { videos: [], total: 0 }
});
const videos = data?.videos || [];
// Filter all Die Geschichte des Liedes videos
const geschichteVideos = videos.filter(video =>
video.title.includes("Die Geschichte des Liedes") ||
video.title.includes("Geschichte des Liedes") ||
video.title.includes("GESCHICHTE DES LIEDES")
);
// Pagination logic
const totalPages = Math.ceil(geschichteVideos.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const currentVideos = geschichteVideos.slice(startIndex, endIndex);
const handleVideoClick = (video: Video) => {
// Navigate to individual video page with show context
const shortId = video.id.replace(/-/g, '').substring(0, 8);
setLocation(`/video/${shortId}?show=geschichte-lied`);
};
const handleCloseModal = () => {
setIsModalOpen(false);
setSelectedVideo(null);
};
// Touch handlers for swipe navigation
const handleTouchStart = (e: React.TouchEvent) => {
setTouchEnd(0);
setTouchStart(e.targetTouches[0].clientX);
};
const handleTouchMove = (e: React.TouchEvent) => {
e.preventDefault();
setTouchEnd(e.targetTouches[0].clientX);
};
const handleTouchEnd = () => {
if (!touchStart || !touchEnd) return;
const distance = touchStart - touchEnd;
const isLeftSwipe = distance > 30;
const isRightSwipe = distance < -30;
if (isLeftSwipe && currentPage < totalPages) {
setCurrentPage(currentPage + 1);
}
if (isRightSwipe && currentPage > 1) {
setCurrentPage(currentPage - 1);
}
};
if (isLoading) {
return (
<div className="min-h-screen bg-bunny-dark flex items-center justify-center">
<div className="text-center">
<div className="w-16 h-16 bg-[#da234d] rounded-lg flex items-center justify-center shadow-lg animate-pulse mb-4 mx-auto">
<div className="w-0 h-0 border-l-[12px] border-l-white border-y-[9px] border-y-transparent ml-1"></div>
</div>
<h3 className="text-white text-xl font-bold mb-2">video.folx.tv</h3>
<p className="text-bunny-light">Loading GESCHICHTE DES LIEDES...</p>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-bunny-dark text-white has-fixed-header">
{/* Header */}
<div className="header-sticky bg-transparent overflow-hidden">
<div className="container py-6">
<div className="flex items-center justify-between">
{/* Left side - Logo */}
<div className="flex items-center space-x-6 flex-1">
<Link href="/" className="flex items-center space-x-3 hover:opacity-80 transition-opacity py-4">
<div className="w-10 h-10 bg-[#da234d] rounded-lg flex items-center justify-center shadow-lg">
<div className="w-0 h-0 border-l-[11px] border-l-white border-y-[8px] border-y-transparent ml-1"></div>
</div>
<h1 className="text-2xl font-bold text-white tracking-wide">video.folx.tv</h1>
</Link>
</div>
{/* Right side - Navigation + Search */}
<div className="flex items-center gap-4">
{/* Desktop navigation */}
<div className="hidden md:flex items-center space-x-6">
<nav className="flex space-x-6">
<Link href="/" className="relative text-bunny-light hover:text-white transition-colors group">
Startseite
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#da234d] transition-all duration-300 group-hover:w-full"></span>
</Link>
<Link href="/folx-stadl" className="relative text-bunny-light hover:text-white transition-colors group">
FOLX STADL
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#da234d] transition-all duration-300 group-hover:w-full"></span>
</Link>
<Link href="/geschichte-lied" className="relative text-bunny-light hover:text-white transition-colors group">
DIE GESCHICHTE DES LIEDES
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#da234d] transition-all duration-300 group-hover:w-full"></span>
</Link>
<Link href="/gipfelstammtisch" className="relative text-bunny-light hover:text-white transition-colors group">
GIPFELSTAMMTISCH
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-[#da234d] transition-all duration-300 group-hover:w-full"></span>
</Link>
<Link href="/live" className="relative text-red-500 hover:text-red-400 transition-colors group font-bold flex items-center space-x-1">
<span className="w-2 h-2 bg-red-500 rounded-full animate-pulse"></span>
<span>LIVE</span>
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-red-400 via-red-500 to-red-600 transition-all duration-300 group-hover:w-full"></span>
</Link>
</nav>
<div className="relative">
<Input
type="search"
placeholder="Suchen..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="bg-white border border-gray-300 rounded-lg px-4 py-1.5 pl-10 text-sm text-gray-900 placeholder-gray-500 focus:outline-none focus:border-[#da234d] transition-colors w-56"
/>
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
</div>
</div>
{/* Mobile menu button */}
<button
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
className="md:hidden p-2 rounded-lg bg-white/10 hover:bg-white/20 transition-colors"
data-testid="button-mobile-menu"
>
{isMobileMenuOpen ? (
<X className="w-6 h-6 text-white" />
) : (
<Menu className="w-6 h-6 text-white" />
)}
</button>
</div>
</div>
</div>
{/* Mobile menu dropdown */}
{isMobileMenuOpen && (
<div className="md:hidden border-t border-white/20 bg-bunny-dark/95 backdrop-blur-md">
<div className="px-6 py-4">
{/* Navigation Section */}
<div className="mb-6">
<h3 className="text-white text-xs font-semibold uppercase tracking-wider mb-3 opacity-70">Navigation</h3>
<nav className="flex flex-col space-y-4">
<Link
href="/"
className="text-bunny-light hover:text-white transition-colors font-medium py-1 border-l-2 border-transparent hover:border-[#da234d] pl-3"
onClick={() => setIsMobileMenuOpen(false)}
>
Startseite
</Link>
<Link
href="/folx-stadl"
className="text-bunny-light hover:text-white transition-colors font-medium py-1 border-l-2 border-transparent hover:border-[#da234d] pl-3"
onClick={() => setIsMobileMenuOpen(false)}
>
FOLX STADL
</Link>
<Link
href="/geschichte-lied"
className="text-bunny-light hover:text-white transition-colors font-medium py-1 border-l-2 border-transparent hover:border-[#da234d] pl-3"
onClick={() => setIsMobileMenuOpen(false)}
>
DIE GESCHICHTE DES LIEDES
</Link>
<Link
href="/gipfelstammtisch"
className="text-bunny-light hover:text-white transition-colors font-medium py-1 border-l-2 border-transparent hover:border-[#da234d] pl-3"
onClick={() => setIsMobileMenuOpen(false)}
>
GIPFELSTAMMTISCH
</Link>
<Link
href="/live"
className="text-red-500 hover:text-red-400 transition-colors font-bold py-1 border-l-2 border-transparent hover:border-red-500 pl-3 flex items-center space-x-2"
onClick={() => setIsMobileMenuOpen(false)}
>
<span className="w-2 h-2 bg-red-500 rounded-full animate-pulse"></span>
<span>LIVE</span>
</Link>
</nav>
</div>
{/* Separator */}
<div className="border-t border-white/10 mb-4"></div>
{/* Search Section */}
<div>
<h3 className="text-white text-xs font-semibold uppercase tracking-wider mb-3 opacity-70">Suchen</h3>
<div className="relative">
<Input
type="search"
placeholder="Suchen..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="bg-white/10 border border-white/20 rounded-lg px-4 py-2.5 pl-10 text-sm text-white placeholder-white/60 focus:outline-none focus:border-[#da234d] focus:bg-white/15 transition-all w-full"
/>
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-white/60 w-4 h-4" />
</div>
</div>
</div>
</div>
)}
</div>
{/* Fixed Header Ad */}
<HeaderAd />
{/* Main Content */}
<div
className="container pt-8 pb-8"
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
>
{/* Video List with Descriptions */}
<div className="space-y-6">
{currentVideos.map((video, index) => (
<div key={video.id}>
<div className="bg-black/20 backdrop-blur-sm rounded-lg p-4">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{/* Video Card */}
<div className="md:col-span-1">
<VideoCard
video={video}
onClick={handleVideoClick}
className="w-full hover:scale-102 transition-all duration-300 rounded-lg overflow-hidden"
hideOverlay={true}
/>
</div>
{/* Video Description */}
<div className="md:col-span-2 space-y-3">
{/* Artist in UPPERCASE - first line */}
<h3 className="text-xl font-bold text-white uppercase">
{(video.title.split(' - ')[0] || 'video.folx.tv')}
</h3>
{/* Song title - second line */}
<h4 className="text-lg font-medium text-white/90 -mt-1">
{(video.title.split(' - ')[1] || video.title)}
</h4>
<p className="text-bunny-light text-sm leading-relaxed">
{video.description || "Keine Beschreibung für diese Sendung verfügbar."}
</p>
<div className="flex items-center gap-4 text-xs text-bunny-muted">
<span>{Math.floor(video.duration / 60)}:{(video.duration % 60).toString().padStart(2, '0')} min</span>
<span>{video.views} Aufrufe</span>
</div>
</div>
</div>
</div>
{/* Add inline ad after every second video (index 1, 3, 5...) */}
{index > 0 && (index + 1) % 2 === 0 && (
<InlineAd />
)}
</div>
))}
{geschichteVideos.length === 0 && (
<div className="text-center py-16">
<p className="text-bunny-muted text-lg">Keine "Die Geschichte des Liedes" Videos gefunden</p>
</div>
)}
</div>
{/* Bottom Pagination */}
{totalPages > 1 && (
<div className="mt-8 mb-10 flex justify-center gap-1 px-4 overflow-x-auto">
{Array.from({ length: Math.min(totalPages, 5) }, (_, i) => {
let pageNum;
if (totalPages <= 5) {
pageNum = i + 1;
} else if (currentPage <= 3) {
pageNum = i + 1;
} else if (currentPage >= totalPages - 2) {
pageNum = totalPages - 4 + i;
} else {
pageNum = currentPage - 2 + i;
}
return (
<Button
key={pageNum}
variant={currentPage === pageNum ? "default" : "outline"}
size="sm"
onClick={() => setCurrentPage(pageNum)}
className={currentPage === pageNum
? "bg-[#da234d] text-white border-none shadow-lg h-10 w-10 p-0 flex items-center justify-center"
: "border-white/20 text-white hover:bg-white/10 h-10 w-10 p-0 flex items-center justify-center"
}
>
{pageNum}
</Button>
);
})}
</div>
)}
</div>
{/* Final inline ad before footer */}
<div className="hidden lg:block container mt-16">
<InlineAd />
</div>
{/* Footer */}
<footer className="bg-bunny-dark/90 border-t border-white/10 py-8 mt-12">
<div className="container">
<div className="flex flex-col items-center justify-center space-y-4">
{/* Logo */}
<div className="flex items-center space-x-2">
<div className="w-8 h-8 bg-[#da234d] rounded-lg flex items-center justify-center shadow-lg">
<div className="w-0 h-0 border-l-[8px] border-l-white border-y-[6px] border-y-transparent ml-1 drop-shadow-sm"></div>
</div>
<h3 className="text-xl font-bold text-white">video.folx.tv</h3>
</div>
{/* Legal Links */}
<div className="flex items-center space-x-6 text-sm">
<Link href="/impressum" className="text-bunny-muted hover:text-white transition-colors">
Impressum
</Link>
<Link href="/privacy" className="text-bunny-muted hover:text-white transition-colors">
Datenschutz
</Link>
<Link href="/terms" className="text-bunny-muted hover:text-white transition-colors">
Nutzungsbedingungen
</Link>
</div>
{/* Copyright */}
<p className="text-bunny-muted text-sm text-center">
© 2025 video.folx.tv. Alle Rechte vorbehalten.
</p>
</div>
</div>
</footer>
{/* Video Modal */}
{selectedVideo && (
<BunnyVideoModal
video={selectedVideo}
isOpen={isModalOpen}
onClose={handleCloseModal}
videos={geschichteVideos}
onVideoChange={setSelectedVideo}
/>
)}
</div>
);
}