videofolxtv/client/src/pages/home.tsx
sebastjanartic 9150630330 Organize website support links into two distinct rows
Restructure the display of support links on multiple pages by grouping them into two rows for improved visual layout and readability.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 890577b1-c154-40a4-a177-a0c6d55320c3
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/890577b1-c154-40a4-a177-a0c6d55320c3/DyHCx4q
2025-09-01 21:40:51 +00:00

263 lines
12 KiB
TypeScript

import { useState, useEffect } from "react";
import { useQuery } from "@tanstack/react-query";
import { type Video } from "@shared/schema";
import NetflixGrid from "@/components/netflix-grid";
import { Link } from "wouter";
import { Input } from "@/components/ui/input";
import { Search, Menu, X } from "lucide-react";
interface VideosResponse {
videos: Video[];
total: number;
hasMore: boolean;
}
export default function Home() {
const [searchQuery, setSearchQuery] = useState("");
const [allVideos, setAllVideos] = useState<Video[]>([]);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
// Fetch videos with optimized loading
const { data: videosResponse, isLoading, refetch } = useQuery<VideosResponse>({
queryKey: ["/api/videos", {
limit: 150,
offset: 0,
search: searchQuery || undefined
}],
queryFn: async ({ queryKey }) => {
const [, params] = queryKey as [string, any];
const searchParams = new URLSearchParams();
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined) {
searchParams.append(key, String(value));
}
});
const response = await fetch(`/api/videos?${searchParams}`);
if (!response.ok) {
throw new Error('Failed to fetch videos');
}
return response.json();
},
staleTime: 5 * 60 * 1000,
gcTime: 10 * 60 * 1000,
refetchOnWindowFocus: false,
refetchOnReconnect: false
});
// Update videos when new data comes in
useEffect(() => {
if (videosResponse) {
setAllVideos(videosResponse.videos);
}
}, [videosResponse]);
// Only refetch when search changes
useEffect(() => {
if (searchQuery !== undefined) {
refetch();
}
}, [searchQuery, refetch]);
return (
<div className="has-fixed-header" style={{minHeight: '100vh', background: 'linear-gradient(135deg, hsl(250, 50%, 15%) 0%, hsl(240, 30%, 25%) 100%)', color: 'white'}}>
{/* STICKY 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 gradient-primary 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">go4.video</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-bunny-blue transition-colors group">
Home
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-purple-400 via-blue-500 to-purple-600 transition-all duration-300 group-hover:w-full"></span>
</Link>
<Link href="/folx-stadl" className="relative text-bunny-light hover:text-bunny-blue transition-colors group">
FOLX STADL
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-purple-400 via-blue-500 to-purple-600 transition-all duration-300 group-hover:w-full"></span>
</Link>
<Link href="/geschichte-lied" className="relative text-bunny-light hover:text-bunny-blue transition-colors group">
DIE GESCHICHTE DES LIEDES
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-purple-400 via-blue-500 to-purple-600 transition-all duration-300 group-hover:w-full"></span>
</Link>
<Link href="/gipfelstammtisch" className="relative text-bunny-light hover:text-bunny-blue transition-colors group">
GIPFELSTAMMTISCH
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-purple-400 via-blue-500 to-purple-600 transition-all duration-300 group-hover:w-full"></span>
</Link>
</nav>
<div className="relative">
<Input
type="search"
placeholder="Search..."
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-bunny-blue 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-bunny-blue transition-colors font-medium py-1 border-l-2 border-transparent hover:border-bunny-blue pl-3"
onClick={() => setIsMobileMenuOpen(false)}
>
Home
</Link>
<Link
href="/folx-stadl"
className="text-bunny-light hover:text-bunny-blue transition-colors font-medium py-1 border-l-2 border-transparent hover:border-bunny-blue pl-3"
onClick={() => setIsMobileMenuOpen(false)}
>
FOLX STADL
</Link>
<Link
href="/geschichte-lied"
className="text-bunny-light hover:text-bunny-blue transition-colors font-medium py-1 border-l-2 border-transparent hover:border-bunny-blue pl-3"
onClick={() => setIsMobileMenuOpen(false)}
>
DIE GESCHICHTE DES LIEDES
</Link>
<Link
href="/gipfelstammtisch"
className="text-bunny-light hover:text-bunny-blue transition-colors font-medium py-1 border-l-2 border-transparent hover:border-bunny-blue pl-3"
onClick={() => setIsMobileMenuOpen(false)}
>
GIPFELSTAMMTISCH
</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="Search..."
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-bunny-blue 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>
<main className="w-full pt-8 pb-8 relative">
<div className="container">
<NetflixGrid
videos={allVideos}
isLoading={isLoading}
/>
</div>
</main>
{/* Footer */}
<footer className="bg-bunny-dark/90 border-t border-white/10 py-8 mt-12">
<div className="container">
<div className="grid grid-cols-2 md:grid-cols-4 gap-6 md:gap-8 text-sm">
{/* Company Info */}
<div className="col-span-1">
<div className="flex items-center space-x-2 mb-4">
<div className="w-8 h-8 gradient-primary rounded-lg flex items-center justify-center">
<div className="w-0 h-0 border-l-[8px] border-l-white border-y-[6px] border-y-transparent ml-1"></div>
</div>
<h3 className="text-xl font-bold text-white">go4.video</h3>
</div>
<div>
<h4 className="text-white font-semibold mb-3">Kategorien</h4>
<ul className="space-y-2">
<li><a href="#" className="text-bunny-muted hover:text-white transition-colors">Volksmusik</a></li>
<li><a href="#" className="text-bunny-muted hover:text-white transition-colors">Dokumentationen</a></li>
<li><a href="#" className="text-bunny-muted hover:text-white transition-colors">Interviews</a></li>
<li><a href="#" className="text-bunny-muted hover:text-white transition-colors">Shows</a></li>
</ul>
</div>
</div>
{/* Navigation */}
<div className="col-span-1">
<div className="pt-2"></div>
<h4 className="text-white font-semibold mb-4">Navigation</h4>
<ul className="space-y-2">
<li><Link href="/" className="text-bunny-muted hover:text-white transition-colors">Home</Link></li>
<li><Link href="/folx-stadl" className="text-bunny-muted hover:text-white transition-colors">FOLX STADL</Link></li>
<li><Link href="/geschichte-lied" className="text-bunny-muted hover:text-white transition-colors">DIE GESCHICHTE DES LIEDES</Link></li>
<li><Link href="/gipfelstammtisch" className="text-bunny-muted hover:text-white transition-colors">GIPFELSTAMMTISCH</Link></li>
</ul>
</div>
{/* Support Links */}
<div className="col-span-1">
<div className="pt-2 pl-4 space-y-1">
<div className="flex gap-4">
<a href="#" className="text-bunny-muted hover:text-white transition-colors text-sm">Hilfe & FAQ</a>
<span className="text-bunny-muted">|</span>
<a href="#" className="text-bunny-muted hover:text-white transition-colors text-sm">Kontakt</a>
</div>
<div className="flex gap-4">
<a href="#" className="text-bunny-muted hover:text-white transition-colors text-sm">Datenschutz</a>
<span className="text-bunny-muted">|</span>
<a href="#" className="text-bunny-muted hover:text-white transition-colors text-sm">Impressum</a>
</div>
</div>
</div>
</div>
{/* Copyright */}
<div className="border-t border-white/10 mt-8 pt-6 text-center">
<p className="text-bunny-muted text-sm">
© 2025 go4.video. Alle Rechte vorbehalten. | Powered by Bunny.net CDN
</p>
</div>
</div>
</footer>
</div>
);
}