Fix, complete all tool updates

This commit is contained in:
Timo Knuth
2026-01-10 00:26:05 +01:00
parent eb2faec952
commit fb9058688e
49 changed files with 13409 additions and 13409 deletions

View File

@@ -1,253 +1,253 @@
'use client';
import React from 'react';
import Link from 'next/link';
import { motion, Variants } from 'framer-motion';
import {
Link as LinkIcon,
User,
Mail,
Calendar,
Facebook,
Instagram,
Phone,
MessageSquare,
Type,
Music,
Twitter,
MessageCircle,
Wifi,
Youtube,
Bitcoin,
MapPin,
CreditCard,
Video,
Users
} from 'lucide-react';
const TOOLS = [
{
icon: LinkIcon,
name: 'URL',
description: 'Open any website',
href: '/tools/url-qr-code',
color: 'text-blue-500',
bg: 'bg-blue-50'
},
{
icon: User,
name: 'vCard',
description: 'Share contact details',
href: '/tools/vcard-qr-code',
color: 'text-rose-500',
bg: 'bg-rose-50'
},
{
icon: Type,
name: 'Text',
description: 'Display plain text',
href: '/tools/text-qr-code',
color: 'text-slate-500',
bg: 'bg-slate-50'
},
{
icon: Mail,
name: 'Email',
description: 'Send an email',
href: '/tools/email-qr-code',
color: 'text-red-500',
bg: 'bg-red-50'
},
{
icon: MessageSquare,
name: 'SMS',
description: 'Send a text message',
href: '/tools/sms-qr-code',
color: 'text-green-500',
bg: 'bg-green-50'
},
{
icon: Wifi,
name: 'WiFi',
description: 'Connect to WiFi',
href: '/tools/wifi-qr-code',
color: 'text-indigo-500',
bg: 'bg-indigo-50'
},
{
icon: Bitcoin,
name: 'Crypto',
description: 'Receive payments',
href: '/tools/crypto-qr-code',
color: 'text-orange-500',
bg: 'bg-orange-50'
},
{
icon: Calendar,
name: 'Event',
description: 'Save calendar event',
href: '/tools/event-qr-code',
color: 'text-violet-500',
bg: 'bg-violet-50'
},
{
icon: Facebook,
name: 'Facebook',
description: 'Open Facebook page',
href: '/tools/facebook-qr-code',
color: 'text-blue-600',
bg: 'bg-blue-50'
},
{
icon: Instagram,
name: 'Instagram',
description: 'Open Instagram profile',
href: '/tools/instagram-qr-code',
color: 'text-pink-500',
bg: 'bg-pink-50'
},
{
icon: Twitter,
name: 'Twitter',
description: 'Open Twitter profile',
href: '/tools/twitter-qr-code',
color: 'text-sky-500',
bg: 'bg-sky-50'
},
{
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-pink-600',
bg: 'bg-pink-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: 'Phone',
description: 'Call phone number',
href: '/tools/phone-qr-code',
color: 'text-blue-400',
bg: 'bg-blue-50'
},
{
icon: CreditCard,
name: 'PayPal',
description: 'Receive PayPal payments',
href: '/tools/paypal-qr-code',
color: 'text-blue-700',
bg: 'bg-blue-50'
},
{
icon: Video,
name: 'Zoom',
description: 'Join Zoom meeting',
href: '/tools/zoom-qr-code',
color: 'text-sky-500',
bg: 'bg-sky-50'
},
{
icon: Users,
name: 'Teams',
description: 'Join Teams meeting',
href: '/tools/teams-qr-code',
color: 'text-violet-500',
bg: 'bg-violet-50'
}
];
// Animation variants
const containerVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.05
}
}
};
const itemVariants: Variants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.4
}
}
};
export function FreeToolsGrid() {
return (
<section id="tools" className="py-24 bg-slate-50/50 border-t border-slate-100">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.5 }}
className="text-center mb-16"
>
<h2 className="text-3xl lg:text-4xl font-bold text-slate-900 mb-4">
More Free QR Code Tools
</h2>
<p className="text-lg text-slate-600 max-w-2xl mx-auto">
Create specialized QR codes for every need. Completely free and no signup required.
</p>
</motion.div>
<motion.div
variants={containerVariants}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-50px" }}
className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-4 gap-4 md:gap-6"
>
{TOOLS.map((tool) => (
<motion.div key={tool.name} variants={itemVariants}>
<Link
href={tool.href}
className="group flex flex-col items-center p-5 md:p-6 rounded-2xl border border-slate-200/80 bg-white hover:border-primary-200 hover:shadow-xl hover:shadow-primary-500/10 transition-all duration-300"
>
<div className={`w-12 h-12 md:w-14 md:h-14 rounded-xl ${tool.bg} flex items-center justify-center mb-3 md:mb-4 group-hover:scale-110 transition-transform duration-300`}>
<tool.icon className={`w-6 h-6 md:w-7 md:h-7 ${tool.color}`} />
</div>
<h3 className="text-base md:text-lg font-semibold text-slate-900 mb-0.5">
{tool.name}
</h3>
<p className="text-xs md:text-sm text-slate-500 text-center">
{tool.description}
</p>
</Link>
</motion.div>
))}
</motion.div>
</div>
</section>
);
}
'use client';
import React from 'react';
import Link from 'next/link';
import { motion, Variants } from 'framer-motion';
import {
Link as LinkIcon,
User,
Mail,
Calendar,
Facebook,
Instagram,
Phone,
MessageSquare,
Type,
Music,
Twitter,
MessageCircle,
Wifi,
Youtube,
Bitcoin,
MapPin,
CreditCard,
Video,
Users
} from 'lucide-react';
const TOOLS = [
{
icon: LinkIcon,
name: 'URL',
description: 'Open any website',
href: '/tools/url-qr-code',
color: 'text-blue-500',
bg: 'bg-blue-50'
},
{
icon: User,
name: 'vCard',
description: 'Share contact details',
href: '/tools/vcard-qr-code',
color: 'text-rose-500',
bg: 'bg-rose-50'
},
{
icon: Type,
name: 'Text',
description: 'Display plain text',
href: '/tools/text-qr-code',
color: 'text-slate-500',
bg: 'bg-slate-50'
},
{
icon: Mail,
name: 'Email',
description: 'Send an email',
href: '/tools/email-qr-code',
color: 'text-red-500',
bg: 'bg-red-50'
},
{
icon: MessageSquare,
name: 'SMS',
description: 'Send a text message',
href: '/tools/sms-qr-code',
color: 'text-green-500',
bg: 'bg-green-50'
},
{
icon: Wifi,
name: 'WiFi',
description: 'Connect to WiFi',
href: '/tools/wifi-qr-code',
color: 'text-indigo-500',
bg: 'bg-indigo-50'
},
{
icon: Bitcoin,
name: 'Crypto',
description: 'Receive payments',
href: '/tools/crypto-qr-code',
color: 'text-orange-500',
bg: 'bg-orange-50'
},
{
icon: Calendar,
name: 'Event',
description: 'Save calendar event',
href: '/tools/event-qr-code',
color: 'text-violet-500',
bg: 'bg-violet-50'
},
{
icon: Facebook,
name: 'Facebook',
description: 'Open Facebook page',
href: '/tools/facebook-qr-code',
color: 'text-blue-600',
bg: 'bg-blue-50'
},
{
icon: Instagram,
name: 'Instagram',
description: 'Open Instagram profile',
href: '/tools/instagram-qr-code',
color: 'text-pink-500',
bg: 'bg-pink-50'
},
{
icon: Twitter,
name: 'Twitter',
description: 'Open Twitter profile',
href: '/tools/twitter-qr-code',
color: 'text-sky-500',
bg: 'bg-sky-50'
},
{
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-pink-600',
bg: 'bg-pink-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: 'Phone',
description: 'Call phone number',
href: '/tools/phone-qr-code',
color: 'text-blue-400',
bg: 'bg-blue-50'
},
{
icon: CreditCard,
name: 'PayPal',
description: 'Receive PayPal payments',
href: '/tools/paypal-qr-code',
color: 'text-blue-700',
bg: 'bg-blue-50'
},
{
icon: Video,
name: 'Zoom',
description: 'Join Zoom meeting',
href: '/tools/zoom-qr-code',
color: 'text-sky-500',
bg: 'bg-sky-50'
},
{
icon: Users,
name: 'Teams',
description: 'Join Teams meeting',
href: '/tools/teams-qr-code',
color: 'text-violet-500',
bg: 'bg-violet-50'
}
];
// Animation variants
const containerVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.05
}
}
};
const itemVariants: Variants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.4
}
}
};
export function FreeToolsGrid() {
return (
<section id="tools" className="py-24 bg-slate-50/50 border-t border-slate-100">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.5 }}
className="text-center mb-16"
>
<h2 className="text-3xl lg:text-4xl font-bold text-slate-900 mb-4">
More Free QR Code Tools
</h2>
<p className="text-lg text-slate-600 max-w-2xl mx-auto">
Create specialized QR codes for every need. Completely free and no signup required.
</p>
</motion.div>
<motion.div
variants={containerVariants}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-50px" }}
className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-4 gap-4 md:gap-6"
>
{TOOLS.map((tool) => (
<motion.div key={tool.name} variants={itemVariants}>
<Link
href={tool.href}
className="group flex flex-col items-center p-5 md:p-6 rounded-2xl border border-slate-200/80 bg-white hover:border-primary-200 hover:shadow-xl hover:shadow-primary-500/10 transition-all duration-300"
>
<div className={`w-12 h-12 md:w-14 md:h-14 rounded-xl ${tool.bg} flex items-center justify-center mb-3 md:mb-4 group-hover:scale-110 transition-transform duration-300`}>
<tool.icon className={`w-6 h-6 md:w-7 md:h-7 ${tool.color}`} />
</div>
<h3 className="text-base md:text-lg font-semibold text-slate-900 mb-0.5">
{tool.name}
</h3>
<p className="text-xs md:text-sm text-slate-500 text-center">
{tool.description}
</p>
</Link>
</motion.div>
))}
</motion.div>
</div>
</section>
);
}

View File

@@ -1,56 +1,56 @@
'use client';
import React from 'react';
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 { ScrollToTop } from '@/components/ui/ScrollToTop';
import { FreeToolsGrid } from '@/components/marketing/FreeToolsGrid';
import en from '@/i18n/en.json';
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 />
<StaticVsDynamic t={t} />
<Features t={t} />
{/* Pricing Section */}
<Pricing t={t} />
{/* FAQ Section */}
<FAQ t={t} />
{/* Scroll to Top Button */}
<ScrollToTop />
</>
);
}
'use client';
import React from 'react';
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 { ScrollToTop } from '@/components/ui/ScrollToTop';
import { FreeToolsGrid } from '@/components/marketing/FreeToolsGrid';
import en from '@/i18n/en.json';
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 />
<StaticVsDynamic t={t} />
<Features t={t} />
{/* Pricing Section */}
<Pricing t={t} />
{/* FAQ Section */}
<FAQ t={t} />
{/* Scroll to Top Button */}
<ScrollToTop />
</>
);
}

View File

@@ -1,81 +1,81 @@
import React from 'react';
import Link from 'next/link';
import { ChevronRight, Home } from 'lucide-react';
interface BreadcrumbItem {
name: string;
url: string;
}
interface BreadcrumbSchemaProps {
items: BreadcrumbItem[];
showUI?: boolean;
}
/**
* Generates JSON-LD BreadcrumbList schema for SEO
* Optionally renders visible breadcrumb navigation
*/
export function BreadcrumbSchema({ items, showUI = false }: BreadcrumbSchemaProps) {
const breadcrumbSchema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url,
})),
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbSchema) }}
/>
{showUI && (
<nav aria-label="Breadcrumb" className="bg-white/95 backdrop-blur-sm border-b border-slate-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<ol className="flex items-center gap-1 py-3 text-sm">
{items.map((item, index) => (
<li key={item.url} className="flex items-center">
{index > 0 && (
<ChevronRight className="w-4 h-4 text-slate-400 mx-1" />
)}
{index === items.length - 1 ? (
<span className="text-slate-600 font-medium truncate max-w-[200px]">
{item.name}
</span>
) : (
<Link
href={item.url.replace('https://qrmaster.io', '')}
className="text-slate-500 hover:text-indigo-600 transition-colors flex items-center gap-1"
>
{index === 0 && <Home className="w-4 h-4" />}
<span className="hidden sm:inline">{item.name}</span>
</Link>
)}
</li>
))}
</ol>
</div>
</nav>
)}
</>
);
}
/**
* Pre-configured breadcrumb for tool pages
* Renders: Home > Free QR Code Tools > [Tool Name]
*/
export function ToolBreadcrumb({ toolName, toolSlug }: { toolName: string; toolSlug: string }) {
const items: BreadcrumbItem[] = [
{ name: 'Home', url: 'https://qrmaster.io/' },
{ name: 'Free QR Code Tools', url: 'https://qrmaster.io/#tools' },
{ name: toolName, url: `https://qrmaster.io/tools/${toolSlug}` },
];
return <BreadcrumbSchema items={items} showUI={true} />;
}
import React from 'react';
import Link from 'next/link';
import { ChevronRight, Home } from 'lucide-react';
interface BreadcrumbItem {
name: string;
url: string;
}
interface BreadcrumbSchemaProps {
items: BreadcrumbItem[];
showUI?: boolean;
}
/**
* Generates JSON-LD BreadcrumbList schema for SEO
* Optionally renders visible breadcrumb navigation
*/
export function BreadcrumbSchema({ items, showUI = false }: BreadcrumbSchemaProps) {
const breadcrumbSchema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url,
})),
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbSchema) }}
/>
{showUI && (
<nav aria-label="Breadcrumb" className="bg-white/95 backdrop-blur-sm border-b border-slate-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<ol className="flex items-center gap-1 py-3 text-sm">
{items.map((item, index) => (
<li key={item.url} className="flex items-center">
{index > 0 && (
<ChevronRight className="w-4 h-4 text-slate-400 mx-1" />
)}
{index === items.length - 1 ? (
<span className="text-slate-600 font-medium truncate max-w-[200px]">
{item.name}
</span>
) : (
<Link
href={item.url.replace('https://qrmaster.io', '')}
className="text-slate-500 hover:text-indigo-600 transition-colors flex items-center gap-1"
>
{index === 0 && <Home className="w-4 h-4" />}
<span className="hidden sm:inline">{item.name}</span>
</Link>
)}
</li>
))}
</ol>
</div>
</nav>
)}
</>
);
}
/**
* Pre-configured breadcrumb for tool pages
* Renders: Home > Free QR Code Tools > [Tool Name]
*/
export function ToolBreadcrumb({ toolName, toolSlug }: { toolName: string; toolSlug: string }) {
const items: BreadcrumbItem[] = [
{ name: 'Home', url: 'https://qrmaster.io/' },
{ name: 'Free QR Code Tools', url: 'https://qrmaster.io/#tools' },
{ name: toolName, url: `https://qrmaster.io/tools/${toolSlug}` },
];
return <BreadcrumbSchema items={items} showUI={true} />;
}

View File

@@ -1,24 +1,24 @@
import * as React from "react"
import { cn } from "@/lib/utils"
export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> { }
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Textarea.displayName = "Textarea"
export { Textarea }
import * as React from "react"
import { cn } from "@/lib/utils"
export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> { }
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Textarea.displayName = "Textarea"
export { Textarea }