feat: Add 19 free QR code tools with SEO optimization

- Added PayPal, Zoom, Teams QR generators
- Added lazy loading for html-to-image (performance)
- Created 19 OG images for social sharing
- Added robots.txt and updated sitemap
- Fixed mobile navigation with accordion menu
- Added 7 color options per generator
- Fixed crypto QR with universal/wallet mode toggle
- Hero QR codes all point to qrmaster.net
This commit is contained in:
Timo Knuth
2026-01-10 00:22:07 +01:00
parent e539aaf9a1
commit eb2faec952
70 changed files with 12803 additions and 592 deletions

View File

@@ -0,0 +1,253 @@
'use client';
import React, { useState, useRef } from 'react';
import Link from 'next/link';
import { QRCodeSVG } from 'qrcode.react';
import {
Music,
Download,
Check,
Sparkles,
Video,
Share2
} from 'lucide-react';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { cn } from '@/lib/utils';
// Brand Colors
const BRAND = {
paleGrey: '#EBEBDF',
richBlue: '#1A1265',
richBlueLight: '#2A2275',
};
// QR Color Options - TikTok Theme
const QR_COLORS = [
{ name: 'TikTok Black', value: '#000000' },
{ name: 'TikTok Pink', value: '#FE2C55' },
{ name: 'TikTok Cyan', value: '#25F4EE' },
{ name: 'Deep Blue', value: '#1A1265' },
{ name: 'Purple', value: '#7C3AED' },
{ name: 'Emerald', value: '#10B981' },
{ name: 'Rose', value: '#F43F5E' },
];
// Frame Options
const FRAME_OPTIONS = [
{ id: 'none', label: 'No Frame' },
{ id: 'scanme', label: 'Scan Me' },
{ id: 'follow', label: 'Follow' },
{ id: 'watch', label: 'Watch' },
];
export default function TiktokGenerator() {
const [username, setUsername] = useState('');
const [qrColor, setQrColor] = useState('#000000');
const [frameType, setFrameType] = useState('none');
const qrRef = useRef<HTMLDivElement>(null);
// TikTok URL: https://www.tiktok.com/@username
const getUrl = () => {
const cleanUser = username.replace(/^@/, '').replace(/https?:\/\/(www\.)?tiktok\.com\/@?/, '').replace(/\/$/, '');
return cleanUser ? `https://www.tiktok.com/@${cleanUser}` : 'https://www.tiktok.com';
};
const handleDownload = async (format: 'png' | 'svg') => {
if (!qrRef.current) return;
try {
if (format === 'png') {
const { toPng } = await import('html-to-image');
const dataUrl = await toPng(qrRef.current, { cacheBust: true, pixelRatio: 3 });
const link = document.createElement('a');
link.download = `tiktok-qr-code.png`;
link.href = dataUrl;
link.click();
} else {
const svgData = qrRef.current.querySelector('svg')?.outerHTML;
if (svgData) {
const blob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `tiktok-qr-code.svg`;
link.click();
}
}
} catch (err) {
console.error('Download failed', err);
}
};
const getFrameLabel = () => {
const frame = FRAME_OPTIONS.find(f => f.id === frameType);
return frame?.id !== 'none' ? frame?.label : null;
};
return (
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
{/* Main Generator Card */}
<div className="bg-white rounded-3xl shadow-2xl shadow-slate-900/10 overflow-hidden border border-slate-100">
<div className="grid lg:grid-cols-2">
{/* LEFT: Input Section */}
<div className="p-8 lg:p-10 space-y-8 border-r border-slate-100">
{/* TikTok Details */}
<div className="space-y-6">
<h2 className="text-lg font-bold text-slate-900 flex items-center gap-2">
<Music className="w-5 h-5 text-black" />
TikTok Username
</h2>
<div>
<label className="block text-sm font-medium text-slate-700 mb-2">Username</label>
<Input
placeholder="@username"
value={username}
onChange={(e) => setUsername(e.target.value)}
className="h-12 text-base rounded-xl border-slate-200 focus:border-black focus:ring-black"
/>
<p className="text-xs text-slate-500 mt-2">Enter your TikTok handle (e.g. @charlidamelio).</p>
</div>
</div>
<div className="border-t border-slate-100"></div>
{/* Design Options */}
<div className="space-y-6">
<h2 className="text-lg font-bold text-slate-900 flex items-center gap-2">
<Sparkles className="w-5 h-5 text-black" />
Design Options
</h2>
{/* Color Picker */}
<div>
<label className="block text-sm font-medium text-slate-700 mb-3">QR Code Color</label>
<div className="flex flex-wrap gap-2">
{QR_COLORS.map((c) => (
<button
key={c.name}
onClick={() => setQrColor(c.value)}
className={cn(
"w-9 h-9 rounded-full border-2 flex items-center justify-center transition-all hover:scale-110",
qrColor === c.value ? "border-slate-900 ring-2 ring-offset-2 ring-slate-200" : "border-white shadow-md"
)}
style={{ backgroundColor: c.value }}
aria-label={`Select ${c.name}`}
title={c.name}
>
{qrColor === c.value && <Check className="w-4 h-4 text-white" strokeWidth={3} />}
</button>
))}
</div>
</div>
{/* Frame Selector */}
<div>
<label className="block text-sm font-medium text-slate-700 mb-3">Frame Label</label>
<div className="grid grid-cols-4 gap-2">
{FRAME_OPTIONS.map((frame) => (
<button
key={frame.id}
onClick={() => setFrameType(frame.id)}
className={cn(
"py-2.5 px-3 rounded-lg text-sm font-medium transition-all border",
frameType === frame.id
? "bg-black text-white border-black"
: "bg-slate-50 text-slate-600 border-slate-200 hover:border-slate-300"
)}
>
{frame.label}
</button>
))}
</div>
</div>
</div>
</div>
{/* RIGHT: Preview Section */}
<div className="p-8 lg:p-10 flex flex-col items-center justify-center" style={{ backgroundColor: BRAND.paleGrey }}>
{/* QR Card with Frame */}
<div
ref={qrRef}
className="bg-white rounded-3xl shadow-xl p-8 flex flex-col items-center"
style={{ minWidth: '320px' }}
>
{/* Frame Label */}
{getFrameLabel() && (
<div
className="mb-5 px-8 py-2.5 rounded-full text-white font-bold text-sm tracking-widest uppercase shadow-md"
style={{ backgroundColor: qrColor }}
>
{getFrameLabel()}
</div>
)}
{/* QR Code */}
<div className="bg-white">
<QRCodeSVG
value={getUrl()}
size={240}
level="M"
includeMargin={false}
fgColor={qrColor}
/>
</div>
{/* Info Preview */}
<div className="mt-6 text-center max-w-[260px]">
<h3 className="font-bold text-slate-900 text-lg flex items-center justify-center gap-2 truncate">
<Music className="w-4 h-4 text-slate-400 shrink-0" />
<span className="truncate">{username || '@username'}</span>
</h3>
<div className="text-xs text-slate-500 mt-1">Opens in TikTok</div>
</div>
</div>
{/* Download Buttons */}
<div className="flex items-center gap-3 mt-8">
<Button
onClick={() => handleDownload('png')}
className="bg-black hover:bg-slate-800 text-white shadow-lg"
>
<Download className="w-4 h-4 mr-2" />
Download PNG
</Button>
<Button
onClick={() => handleDownload('svg')}
variant="outline"
className="border-slate-300 hover:bg-white"
>
<Download className="w-4 h-4 mr-2" />
SVG
</Button>
</div>
<p className="text-xs text-slate-500 mt-4 text-center">
Scanning redirects directly to your TikTok profile.
</p>
</div>
</div>
</div>
{/* Upsell Banner */}
<div className="mt-8 bg-gradient-to-r from-[#000000] via-[#25F4EE] to-[#FE2C55] rounded-2xl p-6 flex flex-col sm:flex-row items-center justify-between gap-4">
<div className="text-white text-center sm:text-left">
<h3 className="font-bold text-lg">Cross-promote on Socials?</h3>
<p className="text-white/80 text-sm mt-1">
Use one Dynamic Link to share your TikTok, Insta, and YouTube all at once.
</p>
</div>
<Link href="/signup">
<Button className="bg-white text-black hover:bg-slate-100 shrink-0 shadow-lg">
Create All-in-One Link
</Button>
</Link>
</div>
</div>
);
}

View File

@@ -0,0 +1,362 @@
import React from 'react';
import type { Metadata } from 'next';
import TiktokGenerator from './TikTokGenerator';
import { Music, Shield, Zap, Smartphone, Video, Heart, Download, Share2 } from 'lucide-react';
import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
// SEO Optimized Metadata
export const metadata: Metadata = {
title: 'Free TikTok QR Code Generator | Get Followers | QR Master',
description: 'Create a QR code for your TikTok profile. Scanners are redirected to the TikTok app instantly to follow you. Customize with colors and frames.',
keywords: ['tiktok qr code', 'tik tok qr generator', 'tiktok follow qr', 'social media qr code', 'tiktok profile qr'],
alternates: {
canonical: 'https://qrmaster.io/tools/tiktok-qr-code',
},
openGraph: {
title: 'Free TikTok QR Code Generator | QR Master',
description: 'Generate QR codes to grow your TikTok following. Instant app redirect.',
type: 'website',
url: 'https://qrmaster.io/tools/tiktok-qr-code',
images: [{ url: '/og-tiktok-generator.png', width: 1200, height: 630 }],
},
twitter: {
card: 'summary_large_image',
title: 'Free TikTok QR Code Generator',
description: 'Create QR codes for TikTok. Get more followers.',
},
robots: {
index: true,
follow: true,
},
};
// JSON-LD Structured Data
const jsonLd = {
'@context': 'https://schema.org',
'@graph': [
{
'@type': 'SoftwareApplication',
name: 'TikTok QR Code Generator',
applicationCategory: 'UtilitiesApplication',
operatingSystem: 'Web Browser',
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.9',
ratingCount: '1560',
},
description: 'Generate QR codes that direct users to a TikTok profile.',
},
{
'@type': 'HowTo',
name: 'How to Create a TikTok QR Code',
description: 'Create a QR code that opens a TikTok profile.',
step: [
{
'@type': 'HowToStep',
position: 1,
name: 'Enter Username',
text: 'Type your TikTok handle (e.g. @user).',
},
{
'@type': 'HowToStep',
position: 2,
name: 'Customize',
text: 'Select colors like Cyan or Pink to match the TikTok brand.',
},
{
'@type': 'HowToStep',
position: 3,
name: 'Download',
text: 'Save the QR code.',
},
{
'@type': 'HowToStep',
position: 4,
name: 'Test',
text: 'Scan the code to ensure it links to your profile.',
},
{
'@type': 'HowToStep',
position: 5,
name: 'Share',
text: 'Share it on other social media or print it out.',
},
],
totalTime: 'PT30S',
},
{
'@type': 'FAQPage',
mainEntity: [
{
'@type': 'Question',
name: 'Does it open the TikTok app?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes! If the app is installed, the QR code will deep-link directly to your profile in the TikTok app.',
},
},
{
'@type': 'Question',
name: 'What is a TikCode?',
acceptedAnswer: {
'@type': 'Answer',
text: 'TikCode was TikTok\'s proprietary QR code system. They have moved towards standard QR codes, which is what our tool generates. These are more compatible with standard camera apps.',
},
},
{
'@type': 'Question',
name: 'Is it free?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, this generator is completely free.',
},
},
{
'@type': 'Question',
name: 'Can I track who scanned my code?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No, this is a static QR code. For analytics, you need a Dynamic QR Code.',
},
},
{
'@type': 'Question',
name: 'Is it safe?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. The QR code simply contains a link to your TikTok profile. No personal data is collected.',
},
},
],
},
],
};
export default function TiktokQRCodePage() {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<ToolBreadcrumb toolName="TikTok QR Code Generator" toolSlug="tiktok-qr-code" />
<div className="min-h-screen" style={{ backgroundColor: '#EBEBDF' }}>
{/* HERO SECTION */}
<section className="relative pt-20 pb-20 lg:pt-32 lg:pb-32 px-4 sm:px-6 lg:px-8 overflow-hidden bg-black">
<div className="absolute inset-0 opacity-20">
{/* TikTok Pattern */}
<svg className="w-full h-full" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="tt_pattern" width="60" height="60" patternUnits="userSpaceOnUse">
<circle cx="30" cy="30" r="2" fill="cyan" />
<circle cx="40" cy="40" r="2" fill="magenta" />
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#tt_pattern)" />
</svg>
</div>
<div className="max-w-7xl mx-auto grid lg:grid-cols-2 gap-12 items-center relative z-10">
<div className="text-center lg:text-left">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/10 text-white/90 text-sm font-medium mb-6 backdrop-blur-sm border border-white/10 hover:bg-white/20 transition-colors cursor-default">
<span className="flex h-2 w-2 relative">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-cyan-400"></span>
</span>
Free Tool No Signup Required
</div>
<h1 className="text-4xl md:text-5xl lg:text-6xl font-extrabold text-white tracking-tight leading-tight mb-6">
Go Viral with <br className="hidden lg:block" />
<span className="text-transparent bg-clip-text bg-gradient-to-r from-[#25F4EE] to-[#FE2C55]">TikTok QR Codes</span>
</h1>
<p className="text-lg md:text-xl text-slate-400 max-w-2xl mx-auto lg:mx-0 mb-8 leading-relaxed">
Share your TikTok immediately. A quick scan sends fans straight to your profile to follow and watch.
<strong className="text-white block sm:inline mt-2 sm:mt-0"> Grow your audience.</strong>
</p>
<div className="flex flex-wrap justify-center lg:justify-start gap-4 text-sm font-medium text-white/80">
<div className="flex items-center gap-2 bg-white/10 px-4 py-2.5 rounded-xl border border-white/10 backdrop-blur-sm">
<Music className="w-4 h-4 text-[#25F4EE]" />
Get Followers
</div>
<div className="flex items-center gap-2 bg-white/10 px-4 py-2.5 rounded-xl border border-white/10 backdrop-blur-sm">
<Video className="w-4 h-4 text-[#FE2C55]" />
Share Videos
</div>
<div className="flex items-center gap-2 bg-white/10 px-4 py-2.5 rounded-xl border border-white/10 backdrop-blur-sm">
<Smartphone className="w-4 h-4 text-white" />
Deep Link
</div>
</div>
</div>
{/* Visual Abstract */}
<div className="hidden lg:flex relative items-center justify-center min-h-[400px]">
{/* Glow Effects */}
<div className="absolute w-[300px] h-[300px] bg-[#25F4EE]/20 rounded-full blur-[80px] -top-10 -right-10 animate-pulse" />
<div className="absolute w-[300px] h-[300px] bg-[#FE2C55]/20 rounded-full blur-[80px] bottom-10 left-10 animate-pulse delay-75" />
<div className="relative w-80 h-96 bg-white/5 backdrop-blur-xl border border-white/20 rounded-3xl shadow-2xl flex flex-col items-center justify-center p-8 transform rotate-3 hover:rotate-0 transition-all duration-700 group">
<div className="absolute inset-0 bg-gradient-to-br from-white/10 to-transparent rounded-3xl" />
<div className="w-20 h-20 rounded-full bg-black border-2 border-[#25F4EE] p-1 mb-6 shadow-[#FE2C55]/50 shadow-lg relative">
<div className="w-full h-full rounded-full bg-slate-800 flex items-center justify-center overflow-hidden">
<Music className="w-10 h-10 text-white animate-bounce" />
</div>
<div className="absolute -bottom-1 -right-1 bg-[#FE2C55] w-6 h-6 rounded-full border-2 border-black flex items-center justify-center">
<Heart className="w-3 h-3 text-white fill-current" />
</div>
</div>
<div className="w-48 h-48 bg-white rounded-xl p-2 shadow-inner relative overflow-hidden flex items-center justify-center">
<QRCodeSVG value="https://www.qrmaster.net" size={170} fgColor="#000000" level="Q" />
</div>
{/* Floating Badge */}
<div className="absolute -bottom-6 -right-6 bg-black border border-white/10 py-3 px-5 rounded-xl shadow-xl flex items-center gap-3 transform transition-transform hover:scale-105 duration-300">
<div className="bg-white/10 p-2 rounded-full">
<Music className="w-5 h-5 text-[#25F4EE]" />
</div>
<div className="text-left">
<div className="text-[10px] text-slate-400 font-bold uppercase tracking-wider">TikTok</div>
<div className="text-sm font-bold text-white">Following</div>
</div>
</div>
</div>
</div>
</div>
</section>
{/* GENERATOR SECTION */}
<section className="py-12 px-4 sm:px-6 lg:px-8 -mt-8">
<TiktokGenerator />
</section>
{/* HOW IT WORKS */}
<section className="py-16 px-4 sm:px-6 lg:px-8 bg-white">
<div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-slate-900 text-center mb-12">
How TikTok QR Codes Work
</h2>
<div className="grid md:grid-cols-3 lg:grid-cols-5 gap-8">
<article className="text-center">
<div className="w-14 h-14 rounded-2xl bg-black flex items-center justify-center mx-auto mb-4">
<Music className="w-7 h-7 text-[#25F4EE]" />
</div>
<h3 className="font-bold text-slate-900 mb-2">1. Enter Handle</h3>
<p className="text-slate-600 text-sm">
Type in your username. No password required.
</p>
</article>
<article className="text-center">
<div className="w-14 h-14 rounded-2xl bg-black flex items-center justify-center mx-auto mb-4">
<Smartphone className="w-7 h-7 text-[#FE2C55]" />
</div>
<h3 className="font-bold text-slate-900 mb-2">2. Scan</h3>
<p className="text-slate-600 text-sm">
Fans scan the code to instantly find you in the app.
</p>
</article>
<article className="text-center">
<div className="w-12 h-12 rounded-2xl bg-black flex items-center justify-center mx-auto mb-4">
<Download className="w-6 h-6 text-white" />
</div>
<h3 className="font-bold text-slate-900 mb-2">3. Download</h3>
<p className="text-slate-600 text-xs leading-relaxed">
Save your custom QR code.
</p>
</article>
<article className="text-center">
<div className="w-12 h-12 rounded-2xl bg-black flex items-center justify-center mx-auto mb-4">
<Heart className="w-6 h-6 text-white" />
</div>
<h3 className="font-bold text-slate-900 mb-2">4. Follow</h3>
<p className="text-slate-600 text-xs leading-relaxed">
Fans scan to find you instantly.
</p>
</article>
<article className="text-center">
<div className="w-12 h-12 rounded-2xl bg-black flex items-center justify-center mx-auto mb-4">
<Share2 className="w-6 h-6 text-white" />
</div>
<h3 className="font-bold text-slate-900 mb-2">5. Viral</h3>
<p className="text-slate-600 text-xs leading-relaxed">
Grow your audience everywhere.
</p>
</article>
</div>
</div>
</section>
{/* FAQ SECTION */}
<section className="py-16 px-4 sm:px-6 lg:px-8" style={{ backgroundColor: '#EBEBDF' }}>
<div className="max-w-3xl mx-auto">
<h2 className="text-3xl font-bold text-slate-900 text-center mb-4">
Frequently Asked Questions
</h2>
<p className="text-slate-600 text-center mb-10">
Common questions about TikTok QR codes.
</p>
<div className="space-y-4">
<FaqItem
question="Does this replace the in-app QR code?"
answer="You can use either! The advantage of our generator is that you can print high-resolution versions for large posters, customize the color/frame, and it works with any standard QR scanner."
/>
<FaqItem
question="Can I link to a specific video?"
answer="Yes, just paste the full video URL (e.g. tiktok.com/@user/video/123...) instead of your username."
/>
<FaqItem
question="Is it free?"
answer="Yes, completely free from start to finish."
/>
<FaqItem
question="Can I track who scanned my code?"
answer="No, this is a static QR code. For analytics, you need a Dynamic QR Code."
/>
<FaqItem
question="Is it safe?"
answer="Yes. The QR code simply contains a link to your TikTok profile. No personal data is collected."
/>
</div>
</div>
</section>
</div>
</>
);
}
function FaqItem({ question, answer }: { question: string; answer: string }) {
return (
<details className="group bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
<summary className="flex items-center justify-between p-5 cursor-pointer list-none text-slate-900 font-semibold hover:bg-slate-50 transition-colors">
{question}
<span className="transition group-open:rotate-180 text-slate-400">
<svg fill="none" height="20" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" viewBox="0 0 24 24" width="20">
<path d="M6 9l6 6 6-6" />
</svg>
</span>
</summary>
<div className="text-slate-600 px-5 pb-5 pt-0 leading-relaxed text-sm">
{answer}
</div>
</details>
);
}