Erste Aenderungen

This commit is contained in:
Marc Wieland
2025-04-20 17:15:07 +02:00
parent a517191176
commit 79aa26d48a
17 changed files with 418 additions and 184 deletions

View File

@@ -15,7 +15,7 @@ const Footer = () => {
<span className="font-bold text-xl">TG Laudenbach</span>
</div>
<p className="text-gray-400">
Volleyball mit Leidenschaft und Teamgeist seit 1975.
Volleyball seit 1974.
</p>
<div className="flex space-x-4">
<Button variant="ghost" size="icon" className="text-gray-400 hover:text-white">

View File

@@ -1,24 +1,28 @@
import { Button } from "@/components/ui/button";
import { Volleyball } from "lucide-react";
const Hero = () => {
return (
<div className="hero-pattern pt-28 pb-16">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div
className="relative min-h-[600px] md:min-h-[700px] lg:min-h-[800px] bg-cover bg-center bg-no-repeat pt-28 pb-16"
style={{ backgroundImage: "url('/images/abteilung-bg.jpg')" }}
>
<div className="absolute inset-0 bg-black/15 z-0" />
<div className="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex flex-col md:flex-row items-center">
<div className="md:w-1/2 text-white">
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold">
Willkommen beim <span className="text-white">TG Laudenbach</span>
Willkommen bei der <span className="text-white">TG Laudenbach - Abteilung Volleyball</span>
</h1>
<p className="mt-4 text-lg md:text-xl">
Volleyball mit Leidenschaft und Teamgeist - werde Teil unserer Gemeinschaft!
Volleyball mit Leidenschaft und Teamgeist werde Teil unserer Gemeinschaft!
</p>
<div className="mt-8 flex flex-wrap gap-4">
<Button className="bg-white text-frog-700 hover:bg-gray-100">
Training besuchen
</Button>
<Button variant="outline" className="text-white border-white hover:bg-white/10">
<Button className="bg-white text-frog-700 hover:bg-gray-100">
Teams kennenlernen
</Button>
</div>

View File

@@ -2,6 +2,7 @@
import { useState } from 'react';
import { Button } from "@/components/ui/button";
import { Menu, X, Volleyball } from "lucide-react";
import {Link} from "react-router-dom";
const Navbar = () => {
const [isMenuOpen, setIsMenuOpen] = useState(false);
@@ -11,7 +12,7 @@ const Navbar = () => {
};
return (
<nav className="bg-white shadow-md fixed w-full z-50">
<nav className="fixed top-0 left-0 w-full z-50 bg-white/30 backdrop-blur-md border-b border-white/20">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16 items-center">
<div className="flex items-center">
@@ -27,7 +28,11 @@ const Navbar = () => {
<a href="#gallery" className="text-gray-700 hover:text-frog-600 px-3 py-2 rounded-md font-medium">Galerie</a>
<a href="#about" className="text-gray-700 hover:text-frog-600 px-3 py-2 rounded-md font-medium">Über uns</a>
<a href="#contact" className="text-gray-700 hover:text-frog-600 px-3 py-2 rounded-md font-medium">Kontakt</a>
<Button className="bg-frog-500 hover:bg-frog-600 text-white">Mitglied werden</Button>
<Link to="/mitglied-werden" className="w-full">
<Button className="w-full bg-frog-500 hover:bg-frog-600 text-white">
Mitglied werden
</Button>
</Link>
</div>
{/* Mobile menu button */}

View File

@@ -2,6 +2,7 @@
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { ArrowRight } from "lucide-react";
import {Link} from "react-router-dom";
const NewsSection = () => {
const news = [
@@ -59,9 +60,11 @@ const NewsSection = () => {
</div>
<div className="text-center mt-12">
<Button variant="outline" className="border-frog-500 text-frog-600 hover:bg-frog-50">
Alle Neuigkeiten
</Button>
<Link to="/alle-neuigkeiten">
<Button variant="outline" className="border-frog-500 text-frog-600 hover:bg-frog-50">
Alle Neuigkeiten
</Button>
</Link>
</div>
</div>
</section>

View File

@@ -1,7 +1,9 @@
import { useKeenSlider } from "keen-slider/react";
import { useRef } from "react";
import { ChevronLeft, ChevronRight, Users } from "lucide-react";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Users } from "lucide-react";
import {Link} from "react-router-dom";
const TeamSection = () => {
const teams = [
@@ -32,40 +34,92 @@ const TeamSection = () => {
league: "Hobby",
description: "Für alle, die Volleyball zum Spaß spielen möchten. Anfänger und Fortgeschrittene sind willkommen!",
trainingTimes: "Mo 18:00 - 20:00 Uhr"
},
{
id: 5,
name: "U12",
league: "Jugendliga",
description: "Unsere kleinsten Stars sammeln erste Spielerfahrung in der U12-Jugendliga.",
trainingTimes: "Mi 16:00 - 17:30 Uhr"
},
{
id: 6,
name: "Mixed-Team",
league: "Hobbyliga",
description: "Spaß, Gemeinschaft und gemischte Teams unser Mixed-Team steht für Vielfalt!",
trainingTimes: "Fr 19:00 - 21:00 Uhr"
}
];
const [sliderRef, slider] = useKeenSlider<HTMLDivElement>({
slides: {
perView: 1,
spacing: 16,
},
breakpoints: {
"(min-width: 640px)": {
slides: { perView: 2, spacing: 16 },
},
"(min-width: 1024px)": {
slides: { perView: 3, spacing: 20 },
},
"(min-width: 1280px)": {
slides: { perView: 4, spacing: 24 },
},
},
});
return (
<section id="team" className="py-16">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl font-bold text-gray-900">Unsere Teams</h2>
<p className="mt-4 text-xl text-gray-600">Von Anfängern bis Leistungssport - für jeden ist etwas dabei</p>
<p className="mt-4 text-xl text-gray-600">Von Anfängern bis Leistungssport für jeden ist etwas dabei</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
{teams.map((team) => (
<Card key={team.id} className="hover:shadow-lg transition-shadow border-t-4 border-t-frog-500">
<CardHeader>
<CardTitle className="flex items-center">
<Users className="h-5 w-5 mr-2 text-frog-500" />
{team.name}
</CardTitle>
<CardDescription>{team.league}</CardDescription>
</CardHeader>
<CardContent>
<p className="text-sm text-gray-600 mb-4">{team.description}</p>
<div className="text-sm font-medium">
<span className="text-frog-600">Training:</span> {team.trainingTimes}
</div>
</CardContent>
<CardFooter>
<Button variant="outline" size="sm" className="w-full border-frog-500 text-frog-600 hover:bg-frog-50">
Team Details
</Button>
</CardFooter>
</Card>
))}
<div className="relative">
{/* Navigation Buttons */}
<button
onClick={() => slider.current?.prev()}
className="absolute left-0 top-1/2 -translate-y-1/2 z-10 bg-white rounded-full p-2 shadow-md hover:bg-frog-100"
>
<ChevronLeft className="text-frog-600" />
</button>
<button
onClick={() => slider.current?.next()}
className="absolute right-0 top-1/2 -translate-y-1/2 z-10 bg-white rounded-full p-2 shadow-md hover:bg-frog-100"
>
<ChevronRight className="text-frog-600" />
</button>
<div ref={sliderRef} className="keen-slider">
{teams.map((team) => (
<div key={team.id} className="keen-slider__slide">
<Card className="h-full hover:shadow-lg transition-shadow border-t-4 border-t-frog-500">
<CardHeader>
<CardTitle className="flex items-center">
<Users className="h-5 w-5 mr-2 text-frog-500" />
{team.name}
</CardTitle>
<CardDescription>{team.league}</CardDescription>
</CardHeader>
<CardContent>
<p className="text-sm text-gray-600 mb-4">{team.description}</p>
<div className="text-sm font-medium">
<span className="text-frog-600">Training:</span> {team.trainingTimes}
</div>
</CardContent>
<CardFooter>
<Link to={`/teams/${team.id}`} className="w-full">
<Button variant="outline" size="sm" className="w-full border-frog-500 text-frog-600 hover:bg-frog-50">
Team Details
</Button>
</Link>
</CardFooter>
</Card>
</div>
))}
</div>
</div>
</div>
</section>

19
src/layout/Layout.tsx Normal file
View File

@@ -0,0 +1,19 @@
import Navbar from "@/components/Navbar";
import Footer from "@/components/Footer";
import { ReactNode } from "react";
type LayoutProps = {
children: ReactNode;
};
const Layout = ({ children }: LayoutProps) => {
return (
<div className="min-h-screen bg-white flex flex-col">
<Navbar />
<main className="flex-1 pt-16">{children}</main>
<Footer />
</div>
);
};
export default Layout;

View File

@@ -1,5 +1,49 @@
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import "keen-slider/keen-slider.min.css";
createRoot(document.getElementById("root")!).render(<App />);
import Index from "./pages/Index";
import MitgliedWerdenPage from "./pages/MitgliedWerden";
import AlleNeuigkeitenPage from "./pages/AlleNeuigkeiten";
import Layout from "./layout/Layout";
import TeamDetailPage from "./pages/TeamDetailPage";
import "./index.css"
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route
path="/"
element={
<Layout>
<Index />
</Layout>
}
/>
<Route
path="/mitglied-werden"
element={
<Layout>
<MitgliedWerdenPage />
</Layout>
}
/>
<Route
path="/alle-neuigkeiten"
element={
<Layout>
<AlleNeuigkeitenPage />
</Layout>
}
/>
<Route path="/teams/:id" element={<Layout><TeamDetailPage /></Layout>} />
</Routes>
</BrowserRouter>
</React.StrictMode>
);

View File

@@ -0,0 +1,52 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
const news = [
{
id: 1,
title: "Saisonstart 2023/24",
date: "15. September 2023",
description: "Die neue Saison beginnt mit einem Heimspiel gegen VfB Mosbach. Kommt vorbei und unterstützt unser Team!",
image: "https://images.unsplash.com/photo-1612872087720-bb876e2e67d1?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80"
},
{
id: 2,
title: "Beachvolleyball-Turnier",
date: "3. Juli 2023",
description: "Unser jährliches Beachvolleyball-Turnier war ein voller Erfolg! 24 Teams kämpften um den Sieg.",
image: "https://images.unsplash.com/photo-1583514555852-6f77e7c9e081?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80"
},
{
id: 3,
title: "Neuer Trainer für die Jugendmannschaft",
date: "21. Mai 2023",
description: "Wir freuen uns, Marc Schneider als neuen Trainer für unsere U16-Mannschaft begrüßen zu dürfen.",
image: "https://images.unsplash.com/photo-1547347298-4074fc3086f0?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80"
},
// 🔜 später kannst du hier easy mehr News reinladen oder aus ner API holen
];
const AlleNeuigkeitenPage = () => {
return (
<div className="max-w-5xl mx-auto px-4 py-12">
<h1 className="text-3xl font-bold text-center mb-8 text-frog-600">Alle Neuigkeiten</h1>
<div className="grid md:grid-cols-2 gap-6">
{news.map((item) => (
<Card key={item.id} className="overflow-hidden">
<div className="h-48 overflow-hidden">
<img src={item.image} alt={item.title} className="w-full h-full object-cover" />
</div>
<CardHeader>
<CardTitle>{item.title}</CardTitle>
<CardDescription>{item.date}</CardDescription>
</CardHeader>
<CardContent>
<p>{item.description}</p>
</CardContent>
</Card>
))}
</div>
</div>
);
};
export default AlleNeuigkeitenPage;

View File

@@ -11,14 +11,12 @@ import Footer from "@/components/Footer";
const Index = () => {
return (
<div className="min-h-screen bg-white">
<Navbar />
<Hero />
<NewsSection />
<TeamSection />
<GallerySection />
<AboutSection />
<ContactSection />
<Footer />
</div>
);
};

View File

@@ -0,0 +1,26 @@
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
const MitgliedWerdenPage = () => {
return (
<div className="flex justify-center mt-10">
<Card className="w-full max-w-md">
<CardContent className="p-6">
<h1 className="text-2xl font-bold mb-4 text-center">Mitglied werden</h1>
<form className="space-y-4">
<Input placeholder="Vorname" />
<Input placeholder="Nachname" />
<Input placeholder="E-Mail" type="email" />
<Input placeholder="Geburtsdatum" type="date" />
<Button type="submit" className="w-full bg-frog-500 hover:bg-frog-600 text-white">
Absenden
</Button>
</form>
</CardContent>
</Card>
</div>
);
};
export default MitgliedWerdenPage;

View File

@@ -0,0 +1,37 @@
import { useParams } from "react-router-dom";
const teamData = [
{
id: "1",
name: "Damen I",
league: "Landesliga Nord",
description: "Unsere erste Damenmannschaft ...",
trainingTimes: "Di & Do 19:00 - 21:00 Uhr",
},
{
id: "2",
name: "Herren I",
league: "Bezirksliga",
description: "Das Herrenteam kämpft ...",
trainingTimes: "Mo & Mi 20:00 - 22:00 Uhr",
},
// usw...
];
const TeamDetailPage = () => {
const { id } = useParams();
const team = teamData.find((t) => t.id === id);
if (!team) return <p>Team nicht gefunden 🐸</p>;
return (
<div className="max-w-3xl mx-auto py-12 px-4">
<h1 className="text-4xl font-bold text-frog-600 mb-2">{team.name}</h1>
<p className="text-gray-700 mb-2">{team.league}</p>
<p className="text-gray-600 mb-4">{team.description}</p>
<p className="text-sm text-frog-700 font-medium">Training: {team.trainingTimes}</p>
</div>
);
};
export default TeamDetailPage;

0
src/routes.tsx Normal file
View File