SEO V2
This commit is contained in:
@@ -42,8 +42,9 @@ const TOOLS = [
|
||||
{ icon: Youtube, name: 'YouTube', description: 'Open YouTube video', href: '/tools/youtube-qr-code', color: 'text-red-600', bg: 'bg-red-50' },
|
||||
{ icon: MessageCircle, name: 'WhatsApp', description: 'Send WhatsApp message', href: '/tools/whatsapp-qr-code', color: 'text-green-600', bg: 'bg-green-50' },
|
||||
{ icon: Music, name: 'TikTok', description: 'Open TikTok profile', href: '/tools/tiktok-qr-code', color: 'text-slate-900', bg: 'bg-slate-100' },
|
||||
{ icon: MapPin, name: 'Location', description: 'Share GPS coordinates', href: '/tools/location-qr-code', color: 'text-emerald-500', bg: 'bg-emerald-50' },
|
||||
{ icon: Phone, name: 'Call', description: 'Start a phone call', href: '/tools/phone-qr-code', color: 'text-teal-500', bg: 'bg-teal-50' },
|
||||
{ icon: MapPin, name: 'Location', description: 'Share GPS coordinates', href: '/tools/geolocation-qr-code', color: 'text-emerald-500', bg: 'bg-emerald-50' },
|
||||
{ icon: Phone, name: 'Call', description: 'Start a phone call', href: '/tools/call-qr-code-generator', color: 'text-teal-500', bg: 'bg-teal-50' },
|
||||
{ icon: Star, name: 'Google Review', description: 'Collect more reviews', href: '/tools/google-review-qr-code', color: 'text-yellow-500', bg: 'bg-yellow-50' },
|
||||
{ icon: Barcode, name: 'Barcode', description: 'Free online barcode generator', href: '/tools/barcode-generator', color: 'text-amber-600', bg: 'bg-amber-50' },
|
||||
];
|
||||
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
'use client';
|
||||
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Hero } from '@/components/marketing/Hero';
|
||||
import AIComingSoonBanner from '@/components/marketing/AIComingSoonBanner';
|
||||
import { StatsStrip } from '@/components/marketing/StatsStrip';
|
||||
import { TemplateCards } from '@/components/marketing/TemplateCards';
|
||||
import { InstantGenerator } from '@/components/marketing/InstantGenerator';
|
||||
import { StaticVsDynamic } from '@/components/marketing/StaticVsDynamic';
|
||||
import { Features } from '@/components/marketing/Features';
|
||||
import { Pricing } from '@/components/marketing/Pricing';
|
||||
import { FAQ } from '@/components/marketing/FAQ';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { ReprintCalculatorTeaser } from '@/components/marketing/ReprintCalculatorTeaser';
|
||||
import { ScrollToTop } from '@/components/ui/ScrollToTop';
|
||||
import { FreeToolsGrid } from '@/components/marketing/FreeToolsGrid';
|
||||
import { TestimonialsCarousel } from '@/components/marketing/TestimonialsCarousel';
|
||||
import { testimonials } from '@/lib/testimonial-data';
|
||||
import AIComingSoonBanner from '@/components/marketing/AIComingSoonBanner';
|
||||
import { StatsStrip } from '@/components/marketing/StatsStrip';
|
||||
import { TemplateCards } from '@/components/marketing/TemplateCards';
|
||||
import { InstantGenerator } from '@/components/marketing/InstantGenerator';
|
||||
import { StaticVsDynamic } from '@/components/marketing/StaticVsDynamic';
|
||||
import { Features } from '@/components/marketing/Features';
|
||||
import { Pricing } from '@/components/marketing/Pricing';
|
||||
import { FAQ } from '@/components/marketing/FAQ';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { ReprintCalculatorTeaser } from '@/components/marketing/ReprintCalculatorTeaser';
|
||||
import { ScrollToTop } from '@/components/ui/ScrollToTop';
|
||||
import { FreeToolsGrid } from '@/components/marketing/FreeToolsGrid';
|
||||
import { TestimonialsCarousel } from '@/components/marketing/TestimonialsCarousel';
|
||||
import { testimonials } from '@/lib/testimonial-data';
|
||||
import en from '@/i18n/en.json';
|
||||
import { allUseCases } from '@/lib/growth-pages';
|
||||
|
||||
export default function HomePageClient() {
|
||||
// Always use English for marketing pages
|
||||
const t = en;
|
||||
|
||||
const industries = [
|
||||
'Restaurant Chain',
|
||||
'Tech Startup',
|
||||
'Real Estate',
|
||||
'Event Agency',
|
||||
'Retail Store',
|
||||
'Healthcare',
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero t={t} />
|
||||
|
||||
{/* Main Interaction: Generator */}
|
||||
<InstantGenerator t={t} />
|
||||
|
||||
<AIComingSoonBanner />
|
||||
|
||||
import { publishedUseCases } from '@/lib/growth-pages';
|
||||
|
||||
export default function HomePageClient() {
|
||||
// Always use English for marketing pages
|
||||
const t = en;
|
||||
|
||||
const industries = [
|
||||
'Restaurant Chain',
|
||||
'Tech Startup',
|
||||
'Real Estate',
|
||||
'Event Agency',
|
||||
'Retail Store',
|
||||
'Healthcare',
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero t={t} />
|
||||
|
||||
{/* Main Interaction: Generator */}
|
||||
<InstantGenerator t={t} />
|
||||
|
||||
<AIComingSoonBanner />
|
||||
|
||||
{/* Free Tools Grid */}
|
||||
<FreeToolsGrid />
|
||||
|
||||
@@ -133,7 +133,7 @@ export default function HomePageClient() {
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
||||
{allUseCases.slice(0, 8).map((item) => (
|
||||
{publishedUseCases.slice(0, 8).map((item) => (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
@@ -157,22 +157,22 @@ export default function HomePageClient() {
|
||||
</section>
|
||||
|
||||
{/* Testimonials Carousel */}
|
||||
<TestimonialsCarousel testimonials={testimonials} />
|
||||
|
||||
<React.Fragment>
|
||||
<StaticVsDynamic t={t} />
|
||||
<ReprintCalculatorTeaser />
|
||||
<Features t={t} />
|
||||
</React.Fragment>
|
||||
|
||||
{/* Pricing Section */}
|
||||
<Pricing t={t} />
|
||||
|
||||
{/* FAQ Section */}
|
||||
<FAQ t={t} />
|
||||
|
||||
{/* Scroll to Top Button */}
|
||||
<ScrollToTop />
|
||||
</>
|
||||
);
|
||||
}
|
||||
<TestimonialsCarousel testimonials={testimonials} />
|
||||
|
||||
<React.Fragment>
|
||||
<StaticVsDynamic t={t} />
|
||||
<ReprintCalculatorTeaser />
|
||||
<Features t={t} />
|
||||
</React.Fragment>
|
||||
|
||||
{/* Pricing Section */}
|
||||
<Pricing t={t} />
|
||||
|
||||
{/* FAQ Section */}
|
||||
<FAQ t={t} />
|
||||
|
||||
{/* Scroll to Top Button */}
|
||||
<ScrollToTop />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
300
src/components/marketing/MarketingDeLayout.tsx
Normal file
300
src/components/marketing/MarketingDeLayout.tsx
Normal file
@@ -0,0 +1,300 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Footer } from '@/components/ui/Footer';
|
||||
import de from '@/i18n/de.json';
|
||||
import { ChevronDown, Wifi, Contact, MessageCircle, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users, Star, Barcode as BarcodeIcon } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function MarketingLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
const [toolsOpen, setToolsOpen] = useState(false);
|
||||
const [mobileToolsOpen, setMobileToolsOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
setScrolled(window.scrollY > 20);
|
||||
};
|
||||
|
||||
// Check immediately on mount
|
||||
handleScroll();
|
||||
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
// Close simple menus when path changes
|
||||
useEffect(() => {
|
||||
setMobileMenuOpen(false);
|
||||
setToolsOpen(false);
|
||||
}, [pathname]);
|
||||
|
||||
// Always German for this layout
|
||||
const t = de;
|
||||
|
||||
const tools = [
|
||||
{ name: 'URL / Link', description: 'Link to any website', href: '/tools/url-qr-code', icon: Link2, color: 'text-blue-500', bgColor: 'bg-blue-50' },
|
||||
{ name: 'Text', description: 'Plain text message', href: '/tools/text-qr-code', icon: Type, color: 'text-slate-500', bgColor: 'bg-slate-50' },
|
||||
{ name: 'WiFi', description: 'Share WiFi credentials', href: '/tools/wifi-qr-code', icon: Wifi, color: 'text-indigo-500', bgColor: 'bg-indigo-50' },
|
||||
{ name: 'VCard', description: 'Digital business card', href: '/tools/vcard-qr-code', icon: Contact, color: 'text-pink-500', bgColor: 'bg-pink-50' },
|
||||
{ name: 'WhatsApp', description: 'Start a chat', href: '/tools/whatsapp-qr-code', icon: MessageCircle, color: 'text-green-500', bgColor: 'bg-green-50' },
|
||||
{ name: 'Email', description: 'Compose an email', href: '/tools/email-qr-code', icon: Mail, color: 'text-amber-500', bgColor: 'bg-amber-50' },
|
||||
{ name: 'SMS', description: 'Send a text message', href: '/tools/sms-qr-code', icon: MessageSquare, color: 'text-cyan-500', bgColor: 'bg-cyan-50' },
|
||||
{ name: 'Call', description: 'Anruf starten', href: '/tools/call-qr-code-generator', icon: Phone, color: 'text-violet-500', bgColor: 'bg-violet-50' },
|
||||
{ name: 'Event', description: 'Add calendar event', href: '/tools/event-qr-code', icon: Calendar, color: 'text-red-500', bgColor: 'bg-red-50' },
|
||||
{ name: 'Location', description: 'Share a place', href: '/tools/geolocation-qr-code', icon: MapPin, color: 'text-emerald-500', bgColor: 'bg-emerald-50' },
|
||||
{ name: 'Facebook', description: 'Facebook profile/page', href: '/tools/facebook-qr-code', icon: Facebook, color: 'text-blue-600', bgColor: 'bg-blue-50' },
|
||||
{ name: 'Instagram', description: 'Instagram profile', href: '/tools/instagram-qr-code', icon: Instagram, color: 'text-pink-600', bgColor: 'bg-pink-50' },
|
||||
{ name: 'Twitter / X', description: 'Twitter profile', href: '/tools/twitter-qr-code', icon: Twitter, color: 'text-sky-500', bgColor: 'bg-sky-50' },
|
||||
{ name: 'YouTube', description: 'YouTube video/channel', href: '/tools/youtube-qr-code', icon: Youtube, color: 'text-red-600', bgColor: 'bg-red-50' },
|
||||
{ name: 'TikTok', description: 'TikTok profile', href: '/tools/tiktok-qr-code', icon: Music, color: 'text-slate-800', bgColor: 'bg-slate-100' },
|
||||
{ name: 'Crypto', description: 'Share wallet address', href: '/tools/crypto-qr-code', icon: Bitcoin, color: 'text-orange-500', bgColor: 'bg-orange-50' },
|
||||
{ name: 'PayPal', description: 'Receive payments', href: '/tools/paypal-qr-code', icon: CreditCard, color: 'text-blue-700', bgColor: 'bg-blue-50' },
|
||||
{ name: 'Zoom', description: 'Join Zoom meeting', href: '/tools/zoom-qr-code', icon: Video, color: 'text-sky-500', bgColor: 'bg-sky-50' },
|
||||
{ name: 'Teams', description: 'Join Teams meeting', href: '/tools/teams-qr-code', icon: Users, color: 'text-violet-500', bgColor: 'bg-violet-50' },
|
||||
{ name: 'Google Bewertungen', description: 'Mehr Bewertungen sammeln', href: '/tools/google-review-qr-code', icon: Star, color: 'text-yellow-500', bgColor: 'bg-yellow-50' },
|
||||
{ name: 'Barcode', description: 'Barcode erstellen', href: '/tools/barcode-generator', icon: BarcodeIcon, color: 'text-slate-800', bgColor: 'bg-slate-100' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white">
|
||||
{/* Server-rendered navigation links for SEO (crawlers) - Placed first for priority */}
|
||||
<div className="sr-only" aria-hidden="false">
|
||||
<nav aria-label="Seitenübersicht">
|
||||
<ul>
|
||||
<li><a href="/qr-code-erstellen">Startseite</a></li>
|
||||
<li><a href="/de/preise">Preise</a></li>
|
||||
<li><a href="/de/qr-codes-fuer-fitnessstudios">QR-Codes für Fitnessstudios</a></li>
|
||||
<li><a href="/de/qr-codes-fuer-events">QR-Codes für Events</a></li>
|
||||
<li><a href="/de/qr-codes-fuer-immobilienschilder">QR-Codes für Immobilienschilder</a></li>
|
||||
<li><a href="/blog">Blog</a></li>
|
||||
<li><a href="/faq">FAQ</a></li>
|
||||
<li><a href="/login">Anmelden</a></li>
|
||||
<li><a href="/signup">Registrieren</a></li>
|
||||
{/* Tools */}
|
||||
<li><a href="/tools/url-qr-code">URL QR Code</a></li>
|
||||
<li><a href="/tools/text-qr-code">Text QR Code</a></li>
|
||||
<li><a href="/tools/wifi-qr-code">WLAN QR Code</a></li>
|
||||
<li><a href="/tools/vcard-qr-code">vCard QR Code</a></li>
|
||||
<li><a href="/tools/whatsapp-qr-code">WhatsApp QR Code</a></li>
|
||||
<li><a href="/tools/email-qr-code">Email QR Code</a></li>
|
||||
<li><a href="/tools/sms-qr-code">SMS QR Code</a></li>
|
||||
<li><a href="/tools/call-qr-code-generator">Call / Anruf QR Code</a></li>
|
||||
<li><a href="/tools/event-qr-code">Event QR Code</a></li>
|
||||
<li><a href="/tools/geolocation-qr-code">Standort QR Code</a></li>
|
||||
<li><a href="/tools/facebook-qr-code">Facebook QR Code</a></li>
|
||||
<li><a href="/tools/instagram-qr-code">Instagram QR Code</a></li>
|
||||
<li><a href="/tools/twitter-qr-code">Twitter QR Code</a></li>
|
||||
<li><a href="/tools/youtube-qr-code">YouTube QR Code</a></li>
|
||||
<li><a href="/tools/tiktok-qr-code">TikTok QR Code</a></li>
|
||||
<li><a href="/tools/crypto-qr-code">Crypto QR Code</a></li>
|
||||
<li><a href="/tools/paypal-qr-code">PayPal QR Code</a></li>
|
||||
<li><a href="/tools/zoom-qr-code">Zoom QR Code</a></li>
|
||||
<li><a href="/tools/teams-qr-code">Teams QR Code</a></li>
|
||||
<li><a href="/tools/google-review-qr-code">Google Bewertungen QR Code</a></li>
|
||||
<li><a href="/tools/barcode-generator">Barcode Generator</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{/* Header */}
|
||||
<header
|
||||
className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200 shadow-sm"
|
||||
|
||||
>
|
||||
<nav className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl h-20 flex items-center justify-between">
|
||||
{/* Logo */}
|
||||
<Link href="/qr-code-erstellen" className="flex items-center space-x-3 group">
|
||||
<div className="relative w-16 h-16 overflow-hidden rounded-full shadow-indigo-200 shadow-lg group-hover:scale-105 transition-transform duration-200">
|
||||
<Image
|
||||
src="/logo.svg"
|
||||
alt="QR Master"
|
||||
fill
|
||||
sizes="64px"
|
||||
className="object-cover"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
<span className="text-xl font-bold text-slate-900 tracking-tight group-hover:text-indigo-600 transition-colors">QR Master</span>
|
||||
</Link>
|
||||
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<div className="hidden md:flex items-center space-x-1">
|
||||
|
||||
{/* Tools Dropdown */}
|
||||
<div
|
||||
className="relative group px-3 py-2"
|
||||
onMouseEnter={() => setToolsOpen(true)}
|
||||
onMouseLeave={() => setToolsOpen(false)}
|
||||
>
|
||||
<button className="flex items-center space-x-1 text-sm font-medium text-slate-600 group-hover:text-slate-900 transition-colors">
|
||||
<span>{t.nav.tools}</span>
|
||||
<ChevronDown className={cn("w-4 h-4 transition-transform duration-200", toolsOpen && "rotate-180")} />
|
||||
</button>
|
||||
|
||||
<AnimatePresence>
|
||||
{toolsOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 10 }}
|
||||
transition={{ duration: 0.15 }}
|
||||
className="absolute left-1/2 -translate-x-1/2 top-full mt-2 w-[750px] bg-white rounded-2xl shadow-lg border border-slate-100 p-4 overflow-hidden"
|
||||
>
|
||||
<div className="grid grid-cols-3 gap-1">
|
||||
{tools.map((tool) => (
|
||||
<Link
|
||||
key={tool.name}
|
||||
href={tool.href}
|
||||
className="flex items-center space-x-3 p-2.5 rounded-xl transition-colors hover:bg-slate-50"
|
||||
>
|
||||
<div className={cn("p-2 rounded-lg shrink-0", tool.bgColor, tool.color)}>
|
||||
<tool.icon className="w-4 h-4" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm font-semibold text-slate-900">{tool.name}</div>
|
||||
<p className="text-xs text-slate-500 leading-snug">{tool.description}</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-3 pt-3 border-t border-slate-100 -mx-4 -mb-4 px-4 py-3 text-center bg-slate-50/50">
|
||||
<p className="text-xs text-slate-500 font-medium">{t.nav.all_free}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
<Link href="/#features" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors">
|
||||
{t.nav.features}
|
||||
</Link>
|
||||
<Link href="/de/preise" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors">
|
||||
{t.nav.pricing}
|
||||
</Link>
|
||||
<Link href="/blog" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors">
|
||||
{t.nav.blog}
|
||||
</Link>
|
||||
<Link href="/#faq" className="px-3 py-2 text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors">
|
||||
{t.nav.faq}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="hidden md:flex items-center space-x-4">
|
||||
<Link href="/login" className="text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors">
|
||||
{t.nav.login}
|
||||
</Link>
|
||||
|
||||
<Link href="/signup">
|
||||
<Button className={cn(
|
||||
"font-semibold shadow-lg shadow-indigo-500/20 transition-all hover:scale-105",
|
||||
scrolled ? "bg-blue-600 text-white hover:bg-blue-700" : "bg-blue-600 text-white hover:bg-blue-700"
|
||||
)}>
|
||||
{t.nav.cta || "Get Started Free"}
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button - Always dark */}
|
||||
<button
|
||||
className="md:hidden p-2 text-slate-900"
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
{mobileMenuOpen ? (
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
) : (
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
||||
)}
|
||||
</svg>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
{/* Mobile Menu */}
|
||||
<AnimatePresence>
|
||||
{mobileMenuOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: 'auto' }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
className="md:hidden bg-white border-b border-slate-100 overflow-hidden"
|
||||
>
|
||||
<div className="container mx-auto px-4 py-6 space-y-2">
|
||||
{/* Free Tools Accordion */}
|
||||
<button
|
||||
onClick={() => setMobileToolsOpen(!mobileToolsOpen)}
|
||||
className="flex items-center justify-between w-full px-4 py-3 rounded-xl hover:bg-slate-50 text-slate-700 font-semibold"
|
||||
>
|
||||
<span>{t.nav.tools}</span>
|
||||
<ChevronDown className={cn("w-5 h-5 transition-transform", mobileToolsOpen && "rotate-180")} />
|
||||
</button>
|
||||
|
||||
<AnimatePresence>
|
||||
{mobileToolsOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: 'auto' }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
className="overflow-hidden"
|
||||
>
|
||||
<div className="max-h-[50vh] overflow-y-auto pl-4 space-y-1 border-l-2 border-slate-100 ml-4">
|
||||
{tools.map((tool) => (
|
||||
<Link
|
||||
key={tool.name}
|
||||
href={tool.href}
|
||||
className="flex items-center gap-3 px-4 py-2.5 rounded-lg hover:bg-slate-50 text-slate-600 text-sm"
|
||||
onClick={() => { setMobileMenuOpen(false); setMobileToolsOpen(false); }}
|
||||
>
|
||||
<tool.icon className={cn("w-4 h-4", tool.color)} />
|
||||
{tool.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="h-px bg-slate-100 my-2"></div>
|
||||
|
||||
<Link href="/#features" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.features}</Link>
|
||||
<Link href="/de/preise" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.pricing}</Link>
|
||||
<Link href="/blog" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.blog}</Link>
|
||||
<Link href="/#faq" className="block px-4 py-3 text-slate-700 font-medium rounded-xl hover:bg-slate-50" onClick={() => setMobileMenuOpen(false)}>{t.nav.faq}</Link>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 pt-4">
|
||||
<Link href="/login" onClick={() => setMobileMenuOpen(false)}>
|
||||
<Button variant="outline" className="w-full justify-center">{t.nav.login}</Button>
|
||||
</Link>
|
||||
<Link href="/signup" onClick={() => setMobileMenuOpen(false)}>
|
||||
<Button className="w-full justify-center bg-indigo-600 hover:bg-indigo-700">{t.nav.cta}</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</header>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="pt-20">
|
||||
{children}
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<Footer t={t} />
|
||||
</div >
|
||||
);
|
||||
}
|
||||
@@ -38,6 +38,40 @@ type LinkCard = {
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type UseCaseTemplateLabels = {
|
||||
badge: string;
|
||||
subBenefits: { title: string; body: string }[];
|
||||
nowLabel: string;
|
||||
setupPreviewLabel: string;
|
||||
comparisonLeftTitle: string;
|
||||
comparisonRightTitle: string;
|
||||
guidelinesEyebrow: string;
|
||||
relatedResourcesTitle: string;
|
||||
faqTitle?: string;
|
||||
nextStepEyebrow: string;
|
||||
ctaBannerTitle: string;
|
||||
};
|
||||
|
||||
const defaultLabels: UseCaseTemplateLabels = {
|
||||
badge: "Use Case",
|
||||
subBenefits: [
|
||||
{ title: "Print Stability", body: "Keep printed tables & flyers clean and permanent" },
|
||||
{ title: "Instant Redirection", body: "Update links instantly without reprinting codes" },
|
||||
{ title: "Attribution Flows", body: "Built-in campaign tracking and flow analysis" },
|
||||
{ title: "Mobile Optimized", body: "Designed to load fast on mobile data connections" },
|
||||
],
|
||||
nowLabel: "now",
|
||||
setupPreviewLabel: "Setup Preview",
|
||||
comparisonLeftTitle: "Static QR",
|
||||
comparisonRightTitle: "Dynamic QR",
|
||||
guidelinesEyebrow: "Standard Guidelines",
|
||||
relatedResourcesTitle: "Related resources",
|
||||
nextStepEyebrow: "Next step",
|
||||
ctaBannerTitle: "Start with a QR setup that keeps your print permanent.",
|
||||
};
|
||||
|
||||
const subBenefitIcons = [ShieldCheck, RefreshCw, BarChart3, Zap];
|
||||
|
||||
type UseCasePageTemplateProps = {
|
||||
title: string;
|
||||
description: string;
|
||||
@@ -78,16 +112,19 @@ type UseCasePageTemplateProps = {
|
||||
authoritySignals?: string[];
|
||||
directAnswer?: string;
|
||||
schemaData?: Record<string, unknown>[];
|
||||
labels?: UseCaseTemplateLabels;
|
||||
};
|
||||
|
||||
export function buildUseCaseMetadata({
|
||||
title,
|
||||
description,
|
||||
canonicalPath,
|
||||
dePath,
|
||||
}: {
|
||||
title: string;
|
||||
description: string;
|
||||
canonicalPath: string;
|
||||
dePath?: string;
|
||||
}): Metadata {
|
||||
const canonical = `https://www.qrmaster.net${canonicalPath}`;
|
||||
|
||||
@@ -101,6 +138,7 @@ export function buildUseCaseMetadata({
|
||||
languages: {
|
||||
"x-default": canonical,
|
||||
en: canonical,
|
||||
...(dePath ? { de: `https://www.qrmaster.net${dePath}` } : {}),
|
||||
},
|
||||
},
|
||||
openGraph: {
|
||||
@@ -395,6 +433,7 @@ export function UseCasePageTemplate({
|
||||
authoritySignals = [],
|
||||
directAnswer,
|
||||
schemaData = [],
|
||||
labels = defaultLabels,
|
||||
}: UseCasePageTemplateProps) {
|
||||
return (
|
||||
<>
|
||||
@@ -419,7 +458,7 @@ export function UseCasePageTemplate({
|
||||
<div className="grid gap-16 lg:grid-cols-[1.15fr_0.85fr] lg:items-center">
|
||||
<div className="space-y-8">
|
||||
<div className="inline-flex items-center rounded-md border border-slate-200 bg-slate-50 px-3 py-1 text-xs font-semibold tracking-wider text-slate-500 uppercase shadow-sm">
|
||||
<span>Use Case</span>
|
||||
<span>{labels.badge}</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-5">
|
||||
@@ -433,12 +472,7 @@ export function UseCasePageTemplate({
|
||||
|
||||
{/* Sub-benefits (Styled as authentic, clean Framer-style Apple Notification banners) */}
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
{[
|
||||
{ title: "Print Stability", body: "Keep printed tables & flyers clean and permanent", icon: ShieldCheck },
|
||||
{ title: "Instant Redirection", body: "Update links instantly without reprinting codes", icon: RefreshCw },
|
||||
{ title: "Attribution Flows", body: "Built-in campaign tracking and flow analysis", icon: BarChart3 },
|
||||
{ title: "Mobile Optimized", body: "Designed to load fast on mobile data connections", icon: Zap },
|
||||
].map((item) => (
|
||||
{labels.subBenefits.map((benefit, idx) => ({ ...benefit, icon: subBenefitIcons[idx % subBenefitIcons.length] })).map((item) => (
|
||||
<div
|
||||
key={item.title}
|
||||
className="flex items-center gap-3.5 rounded-[1.25rem] bg-[#f4f4f5]/90 border border-slate-200/30 p-3.5 shadow-[0_8px_24px_rgba(0,0,0,0.02)] backdrop-blur-md transition-all duration-200 hover:scale-[1.01] hover:bg-[#f4f4f5]"
|
||||
@@ -449,7 +483,7 @@ export function UseCasePageTemplate({
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-baseline justify-between">
|
||||
<span className="text-[13px] font-semibold text-slate-900 truncate">{item.title}</span>
|
||||
<span className="text-[10px] text-slate-400 font-medium shrink-0 ml-2">now</span>
|
||||
<span className="text-[10px] text-slate-400 font-medium shrink-0 ml-2">{labels.nowLabel}</span>
|
||||
</div>
|
||||
<p className="text-[12px] text-slate-500 leading-snug mt-0.5">{item.body}</p>
|
||||
</div>
|
||||
@@ -502,7 +536,7 @@ export function UseCasePageTemplate({
|
||||
<span className="w-2 h-2 rounded-full bg-rose-400/80" />
|
||||
<span className="w-2 h-2 rounded-full bg-amber-400/80" />
|
||||
<span className="w-2 h-2 rounded-full bg-emerald-400/80" />
|
||||
<span className="text-[9px] text-slate-400 font-semibold ml-4 tracking-wide uppercase">Setup Preview</span>
|
||||
<span className="text-[9px] text-slate-400 font-semibold ml-4 tracking-wide uppercase">{labels.setupPreviewLabel}</span>
|
||||
</div>
|
||||
{/* Visual Container */}
|
||||
<div className="relative aspect-[4/3] overflow-hidden rounded-xl bg-slate-50/50">
|
||||
@@ -536,8 +570,8 @@ export function UseCasePageTemplate({
|
||||
whatIsIt={answer}
|
||||
whenToUse={whenToUse}
|
||||
comparison={{
|
||||
leftTitle: "Static QR",
|
||||
rightTitle: "Dynamic QR",
|
||||
leftTitle: labels.comparisonLeftTitle,
|
||||
rightTitle: labels.comparisonRightTitle,
|
||||
items: comparisonItems,
|
||||
}}
|
||||
howTo={{
|
||||
@@ -613,7 +647,7 @@ export function UseCasePageTemplate({
|
||||
<div className="flex items-center justify-between gap-4 border-b border-slate-100 pb-5">
|
||||
<div>
|
||||
<div className="text-xs font-semibold uppercase tracking-wider text-slate-450">
|
||||
Standard Guidelines
|
||||
{labels.guidelinesEyebrow}
|
||||
</div>
|
||||
<h2 className="mt-2 text-2xl font-bold text-slate-900 sm:text-3xl -tracking-[0.02em]">
|
||||
{checklistTitle}
|
||||
@@ -645,7 +679,7 @@ export function UseCasePageTemplate({
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-slate-50 border border-slate-100 text-slate-550">
|
||||
<Link2 className="h-5 w-5" />
|
||||
</div>
|
||||
<h2 className="text-2xl font-bold text-slate-900 sm:text-3xl -tracking-[0.02em]">Related resources</h2>
|
||||
<h2 className="text-2xl font-bold text-slate-900 sm:text-3xl -tracking-[0.02em]">{labels.relatedResourcesTitle}</h2>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 space-y-4">
|
||||
@@ -676,7 +710,7 @@ export function UseCasePageTemplate({
|
||||
|
||||
{/* FAQs */}
|
||||
<div className="container mx-auto max-w-5xl px-4 pb-12 sm:px-6 lg:px-8">
|
||||
<FAQSection items={faq} title={`${title} FAQ`} />
|
||||
<FAQSection items={faq} title={labels.faqTitle ?? `${title} FAQ`} />
|
||||
</div>
|
||||
|
||||
{/* Bottom CTA Banner (Flat light-gray card, no gradients) */}
|
||||
@@ -686,10 +720,10 @@ export function UseCasePageTemplate({
|
||||
<div className="relative z-10 flex flex-col gap-8 lg:flex-row lg:items-center lg:justify-between">
|
||||
<div className="max-w-2xl space-y-3">
|
||||
<div className="text-xs font-semibold uppercase tracking-wider text-slate-450">
|
||||
Next step
|
||||
{labels.nextStepEyebrow}
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl -tracking-[0.02em] leading-tight text-slate-950">
|
||||
Start with a QR setup that keeps your print permanent.
|
||||
{labels.ctaBannerTitle}
|
||||
</h2>
|
||||
<p className="text-base leading-relaxed text-slate-500">
|
||||
{description}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Link from 'next/link';
|
||||
import en from '@/i18n/en.json';
|
||||
import { Instagram, Twitter, Linkedin, Facebook } from 'lucide-react';
|
||||
import { allUseCases } from '@/lib/growth-pages';
|
||||
import { publishedUseCases } from '@/lib/growth-pages';
|
||||
import { industryPages } from '@/lib/industry-pages';
|
||||
|
||||
interface FooterProps {
|
||||
@@ -93,7 +93,7 @@ export function Footer({ variant = 'marketing', t }: FooterProps) {
|
||||
<div>
|
||||
<h3 className={`font-semibold mb-4 ${isDashboard ? 'text-gray-900' : ''}`}>Use Cases</h3>
|
||||
<ul className={`space-y-2 ${isDashboard ? 'text-gray-500' : 'text-gray-400'}`}>
|
||||
{allUseCases.map((uc) => (
|
||||
{publishedUseCases.map((uc) => (
|
||||
<li key={uc.slug}>
|
||||
<Link href={uc.href} className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>
|
||||
{uc.title}
|
||||
|
||||
Reference in New Issue
Block a user