diff --git a/COMMIT_MSG_HOMEPAGE.txt b/COMMIT_MSG_HOMEPAGE.txt new file mode 100644 index 0000000..15d17a1 --- /dev/null +++ b/COMMIT_MSG_HOMEPAGE.txt @@ -0,0 +1,11 @@ +Homepage fertig: Horizontales Scrollen, größere Sections, How-it-works überarbeitet + +Homepage abgeschlossen + +- Horizontales Scrollen: Features, How it works, Pricing und FAQ in einem + horizontalen Scroll-Container mit Snap, Tastatur- und Touch-Navigation +- Zentrierung: Sections und Inhalte zentriert, overflow-x auf Body verhindert +- Größen: Moderate Schrift- und Abstände in Features, Pricing, FAQ +- How it works: Vergrößert (Titel 4xl–6xl, große Step-Cards, größere Icons und CTA) +- Navbar: Links springen in die passende Horizontal-Section +- Neue Komponente: HorizontalScrollNav (Dots), Hover-Pfeile, Scrollbar ausgeblendet diff --git a/client/src/components/landing/HorizontalScrollNav.tsx b/client/src/components/landing/HorizontalScrollNav.tsx new file mode 100644 index 0000000..0f5757d --- /dev/null +++ b/client/src/components/landing/HorizontalScrollNav.tsx @@ -0,0 +1,60 @@ +import React from 'react' + +interface Section { + id: string + name: string +} + +interface HorizontalScrollNavProps { + sections: Section[] + activeIndex: number + onNavigate: (index: number) => void +} + +export function HorizontalScrollNav({ + sections, + activeIndex, + onNavigate +}: HorizontalScrollNavProps) { + return ( + <> + {/* Desktop - Vertical Dots rechts */} +
+ {sections.map((section, index) => ( +
+ + {/* Mobile - Horizontal Dots unten */} +
+ {sections.map((section, index) => ( +
+ + ) +} diff --git a/client/src/components/landing/Navbar.tsx b/client/src/components/landing/Navbar.tsx index afa4e01..56ecef0 100644 --- a/client/src/components/landing/Navbar.tsx +++ b/client/src/components/landing/Navbar.tsx @@ -14,6 +14,24 @@ export function Navbar() { const scrollToSection = useCallback((sectionId: string) => { setIsMenuOpen(false) + // Horizontal scroll sections + const horizontalSections = ['features', 'how-it-works', 'pricing', 'faq'] + + if (horizontalSections.includes(sectionId)) { + // Dispatch custom event for horizontal scroll + const event = new CustomEvent('scrollToHorizontalSection', { + detail: { sectionId } + }) + window.dispatchEvent(event) + + // If not on home page, navigate first + if (location.pathname !== '/') { + navigate('/') + } + return + } + + // Vertical scroll for other sections // If not on home page, navigate first if (location.pathname !== '/') { navigate('/') diff --git a/client/src/index.css b/client/src/index.css index bc4be53..48a6794 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -84,6 +84,7 @@ /* Base styles */ html { scroll-behavior: smooth; + overflow-x: hidden; /* Prevent horizontal scroll on body */ } body { @@ -93,6 +94,8 @@ body { /* Improve touch scrolling on mobile */ -webkit-overflow-scrolling: touch; overflow-scrolling: touch; + /* Prevent horizontal scroll */ + overflow-x: hidden; /* Base colors - Tailwind will handle dark mode */ background-color: var(--color-slate-50); color: var(--color-slate-900); @@ -324,3 +327,38 @@ body { html:not(.dark-mode-initialized) body { transition: none; } + +/* Horizontal Scroll Container Styles */ +/* Hide scrollbar but keep functionality */ +.scrollbar-hide { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} + +.scrollbar-hide::-webkit-scrollbar { + display: none; /* Chrome, Safari, Opera */ +} + +/* Snap scroll behavior */ +.snap-x { + scroll-snap-type: x mandatory; +} + +.snap-center { + scroll-snap-align: center; +} + +.snap-mandatory { + scroll-snap-type: x mandatory; +} + +/* Smooth scrolling for horizontal containers */ +.scroll-smooth { + scroll-behavior: smooth; + -webkit-overflow-scrolling: touch; +} + +/* Ensure sections take full viewport width */ +.w-screen { + width: 100vw; +} diff --git a/client/src/pages/Home.tsx b/client/src/pages/Home.tsx index 9242847..33a22c4 100644 --- a/client/src/pages/Home.tsx +++ b/client/src/pages/Home.tsx @@ -1,25 +1,187 @@ +import { useRef, useState, useEffect, useCallback } from 'react' +import { ChevronLeft, ChevronRight } from 'lucide-react' import { Navbar } from '@/components/landing/Navbar' import { Hero } from '@/components/landing/Hero' import { Features } from '@/components/landing/Features' import { HowItWorks } from '@/components/landing/HowItWorks' import { Testimonials } from '@/components/landing/Testimonials' -import { TrustSection } from '@/components/landing/TrustSection' import { Pricing } from '@/components/landing/Pricing' import { FAQ } from '@/components/landing/FAQ' import { Footer } from '@/components/landing/Footer' +import { HorizontalScrollNav } from '@/components/landing/HorizontalScrollNav' + +const sections = [ + { id: 'features', name: 'Features' }, + { id: 'how-it-works', name: 'How It Works' }, + { id: 'pricing', name: 'Pricing' }, + { id: 'faq', name: 'FAQ' } +] export function Home() { + const scrollContainerRef = useRef(null) + const [activeIndex, setActiveIndex] = useState(0) + + // Scroll to specific section + const scrollToSection = useCallback((index: number) => { + const container = scrollContainerRef.current + if (!container) return + + const sectionWidth = container.clientWidth + container.scrollTo({ + left: index * sectionWidth, + behavior: 'smooth' + }) + }, []) + + // Track active section based on scroll position + useEffect(() => { + const container = scrollContainerRef.current + if (!container) return + + const handleScroll = () => { + const scrollLeft = container.scrollLeft + const sectionWidth = container.clientWidth + const index = Math.round(scrollLeft / sectionWidth) + setActiveIndex(index) + } + + container.addEventListener('scroll', handleScroll, { passive: true }) + return () => container.removeEventListener('scroll', handleScroll) + }, []) + + // Keyboard navigation + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + // Only handle arrow keys when horizontal scroll container is in view + const container = scrollContainerRef.current + if (!container) return + + const rect = container.getBoundingClientRect() + const isVisible = rect.top < window.innerHeight && rect.bottom > 0 + + if (!isVisible) return + + if (e.key === 'ArrowRight' && activeIndex < 3) { + e.preventDefault() + scrollToSection(activeIndex + 1) + } else if (e.key === 'ArrowLeft' && activeIndex > 0) { + e.preventDefault() + scrollToSection(activeIndex - 1) + } + } + + window.addEventListener('keydown', handleKeyDown) + return () => window.removeEventListener('keydown', handleKeyDown) + }, [activeIndex, scrollToSection]) + + // Listen for custom events from Navbar + useEffect(() => { + const handleHorizontalScroll = (e: Event) => { + const customEvent = e as CustomEvent<{ sectionId: string }> + const sectionId = customEvent.detail.sectionId + const sectionIndex = sections.findIndex(s => s.id === sectionId) + if (sectionIndex !== -1) { + // Small delay to ensure container is ready + setTimeout(() => { + scrollToSection(sectionIndex) + }, 100) + } + } + + window.addEventListener('scrollToHorizontalSection', handleHorizontalScroll as EventListener) + return () => { + window.removeEventListener('scrollToHorizontalSection', handleHorizontalScroll as EventListener) + } + }, [scrollToSection]) + return (
+ {/* NAVBAR - fixed top */} - - - - - - - -
) }