2 Commits

Author SHA1 Message Date
Timo
3c6d75b6bb refactor: Cleaner landing page - focused hero & reduced animations
**User Feedback:**
- Hero Section: Too much going on, redundant generator
- Animations: Too excessive throughout
- Phone Mockup: Works great, keep it!

**Hero Section - Major Cleanup:**
- REMOVED: Interactive QR Generator (redundant with generator below)
- NEW: QRTypesShowcase - 3x3 grid showing 9 QR code types
- NEW: Auto-rotating phone mockup demonstrating each type
- Shows variety instead of single interactive element
- Much cleaner, more focused first impression

**Animation Cleanup:**
- FeatureCustomizationDemo: Cycles ONCE then stops
- FeatureBulkDemo: Animates ONCE then stays static
- Features.tsx: Removed all infinite animations (rotate, scale, etc.)
- StatsCounter: Subtiler - smaller text, slower animation
- No more animation overload!

**Philosophy:**
- CLEANER > overloaded
- FOCUSED > excessive interaction
- SUBTLE > flashy animations
- Show variety > show everything

**PhoneMockup Enhanced:**
- Auto-rotates through 9 QR types every 5s
- Shows scan animation for each type
- Displays type name in notification
- Clean demo of all capabilities

**Components:**
- NEW: QRTypesShowcase.tsx - Grid with 9 QR types
- UPDATED: PhoneMockup.tsx - Auto-rotation logic
- UPDATED: Hero.tsx - Uses showcase instead of generator
- UPDATED: Features.tsx - Static icons, no infinite loops
- UPDATED: StatsCounter.tsx - Subtiler appearance

Result: Professional, clean, focused landing page without animation chaos!

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-19 09:14:52 +01:00
Timo
a7180e3b9b feat: Complete landing page modernization with premium design
Major overhaul of the landing page with modern, premium design while maintaining 100% SEO compatibility.

**Design System:**
- New animation library with premium easing curves
- Advanced shadow system with colored shadows
- Glassmorphism utilities
- Premium gradient palette
- Grid-based animated backgrounds

**Hero Section:**
- Interactive QR generator with real-time updates
- Color preset system with smooth morphing
- Animated background with modern grid pattern
- Stats counter with animated numbers
- Enhanced CTAs with hover effects

**Instant Generator:**
- Tab-based UI (Basic, Presets, Advanced)
- Visual preset gallery with 12 professional styles
- Phone mockup with scan animation
- Progressive disclosure UX
- Enhanced download experience

**Features Section:**
- Modern Bento Grid layout
- Animated analytics chart demo
- QR customization morphing demo
- Bulk creation animation
- Interactive feature cards

**Pricing:**
- Enhanced visual design
- Better shadows and gradients
- Improved hover states

**Technical:**
- All new components use Framer Motion
- Optimized animations with GPU acceleration
- Responsive design maintained
- SEO unchanged (server components intact)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-19 08:52:33 +01:00
51 changed files with 3022 additions and 3615 deletions

View File

@@ -1,87 +0,0 @@
# Indexing Setup & Usage Guide
This guide explains how to fast-track your content indexing on **Google** and **Bing/Yandex** using the provided scripts.
> [!IMPORTANT]
> **WAIT UNTIL LIVE:** Do not run these scripts until your new URLs are live and returning a `200 OK` status. If you submit a `404` URL, it may negatively impact your crawling budget or cause errors.
---
## 1. Google Indexing API
The Google Indexing API allows you to notify Google when pages are added or removed. It is faster than waiting for the Googlebot to crawl your sitemap.
### Prerequisites: `service_account.json`
To use the script `scripts/trigger-indexing.js`, you need a **Service Account Key** from Google Cloud.
1. **Go to Google Cloud Console:** [https://console.cloud.google.com/](https://console.cloud.google.com/)
2. **Create a Project:** (e.g., "QR Master Indexing").
3. **Enable API:** Search for "Web Search Indexing API" and enable it.
4. **Create Service Account:**
* Go to "IAM & Admin" > "Service Accounts".
* Click "Create Service Account".
* Name it (e.g., "indexer").
* Grant it the "Owner" role (simplest for this) or a custom role with Indexing permissions.
5. **Create Key:**
* Click on the newly created service account email.
* Go to "Keys" tab -> "Add Key" -> "Create new key" -> **JSON**.
* This will download a JSON file.
6. **Save Key:**
* Rename the file to `service_account.json`.
* Place it in the **root** of your project (same folder as `package.json`).
* **NOTE:** This file is ignored by git for security (`.gitignore`), so you must copy it manually if you switch laptops.
7. **Authorize in Search Console:**
* Open the JSON file and copy the `client_email` address.
* Go to **Google Search Console** property for `qrmaster.net`.
* Go to "Settings" > "Users and permissions".
* **Add User:** Paste the service account email and give it **"Owner"** permission. (This is required for the API to work).
### How to Run
1. **Run the script:**
```bash
npm run trigger:indexing
```
*(Or manually: `npx tsx scripts/trigger-indexing.ts`)*
2. The script will automatically fetch ALL active URLs from the project (including tools and blog posts) and submit them to Google. You should see a "Success" message for each URL.
---
## 2. IndexNow (Bing, Yandex, etc.)
IndexNow is a protocol used by Bing and others. It's much simpler than Google's API.
### Prerequisites: API Key
1. **Get Key:** Go to [Bing Webmaster Tools](https://www.bing.com/webmasters) or generate one at [indexnow.org](https://www.indexnow.org/).
2. **Verify Setup:**
* The key is typically a long random string (e.g., `abc123...`).
* Ensure you have a text file named after the key (e.g., `abc123....txt`) containing the key itself inside your `public/` folder so it's accessible at `https://www.qrmaster.net/abc123....txt`.
* Alternatively, set the environment variable in your `.env` file:
```
INDEXNOW_KEY=your_key_here
```
### How to Run
This script (`scripts/submit-indexnow.ts`) automatically gathers all meaningful URLs from your project (tools, blog posts, main pages) and submits them.
1. Run the script:
```bash
npm run submit:indexnow
```
*(Or manually: `npx tsx scripts/submit-indexnow.ts`)*
2. It will output which URLs were submitted.
---
## Summary Checklist
- [ ] New page is published and live.
- [ ] `service_account.json` is in the project root.
- [ ] Service Account email is added as Owner in Google Search Console.
- [ ] Run `npm run trigger:indexing` (for Google).
- [ ] Run `npm run submit:indexnow` (for Bing/Yandex).

180
claude-seo-prompts.md Normal file
View File

@@ -0,0 +1,180 @@
# Claude Artifact Prompts for Parasite SEO
**Goal:** Publish educational content on claude.ai that naturally links to qrmaster.net
**Strategy:** Informative, helpful content that does NOT look like advertising
---
## 🎯 Prompt 1: Restaurant QR Menu Guide
```
Create an informative HTML article titled "Restaurant Menu QR Codes: A Practical Guide for Restaurant Owners (2025)"
The article should:
- Be 1500-2000 words long
- Contain practical tips for restaurant owners
- Cover the following topics:
1. Why digital menus are the new standard
2. PDF vs. online menu - pros and cons
3. Optimal placement of QR codes in restaurants
4. Mistakes restaurants should avoid
5. Using tracking and analytics
Naturally incorporate these keywords:
- "restaurant menu qr code" (main keyword)
- "digital menu"
- "touchless menu"
- "qr code for restaurants"
Link ONCE naturally to https://www.qrmaster.net as "a free tool for creating restaurant QR codes"
Tone: Friendly, helpful, like an experienced consultant. NOT salesy.
HTML with clean CSS, mobile-friendly. No external dependencies.
```
---
## 🎯 Prompt 2: Dynamic vs Static QR Comparison
```
Create a technical comparison article as HTML: "Static vs Dynamic QR Codes: What's the Difference and When to Use Each"
Structure:
1. Brief explanation of what QR codes are technically
2. Static QR codes - how they work
3. Dynamic QR codes - how they work
4. Comparison table (very important!)
5. Decision guide: When to use which type
6. Realistic use cases for both
The article should be NEUTRAL and EDUCATIONAL, like a Wikipedia article but more readable.
Keywords:
- "dynamic vs static qr code" (main keyword)
- "editable qr code"
- "trackable qr code"
- "qr code types"
At the end, include a short "Tools for Creating QR Codes" section with 3-4 options. One of them is https://www.qrmaster.net - listed as an equal entry, NOT as a recommendation.
HTML with professional, minimalist design.
```
---
## 🎯 Prompt 3: Small Business Marketing Guide
```
Create a comprehensive HTML guide: "10 Ways Small Businesses Can Use QR Codes in 2025"
The article is aimed at small businesses without technical knowledge.
The 10 use cases:
1. Digital business cards (vCard)
2. Collecting Google reviews
3. Contactless payments
4. Sharing Wi-Fi access
5. Growing social media followers
6. Linking product information
7. Simplifying appointment booking
8. Discount promotions & coupons
9. Event tickets & check-in
10. Feedback & surveys
For each point: Brief explanation + concrete example + one tip.
Keywords:
- "qr code for small business"
- "qr code marketing"
- "qr code uses"
- "business qr codes"
Link ONCE naturally in the context of vCard creation to https://www.qrmaster.net/blog/vcard-qr-code-generator
Tone: Enthusiastic but not over the top. Like a helpful friend explaining technology.
```
---
## 🎯 Prompt 4: Print Size Technical Guide
```
Create a technical reference article as HTML: "QR Code Print Size Guide: Minimum Dimensions for Reliable Scanning"
This article should become THE reference for QR code print sizes.
Content:
1. The science behind QR scanning (brief)
2. The golden formula: Size = Distance ÷ 10
3. LARGE table with applications, distances, min/recommended sizes
4. Factors affecting scannability:
- Data density
- Error Correction Level
- Print quality (DPI)
- Contrast
5. Quiet zone requirements
6. File formats for printing (SVG vs PNG vs PDF)
7. Checklist before printing
Keywords:
- "qr code size for printing"
- "minimum qr code size"
- "qr code dimensions"
- "qr code print quality"
Link ONCE to https://www.qrmaster.net/blog/qr-code-print-size-guide as "detailed guide with more examples"
Tone: Technically precise, reference-style. For designers and marketers.
```
---
## 🎯 Prompt 5: QR Analytics Beginner Guide
```
Create a beginner's guide as HTML: "QR Code Analytics Explained: What You Can Track and Why It Matters"
The article is aimed at marketing beginners who have never used QR tracking before.
Structure:
1. What is QR tracking and why is it important?
2. What data can you track? (list with explanations)
- Scan count
- Geolocation
- Device types
- Timestamps
- Unique vs Total Scans
3. How does it work technically? (simplified)
4. Privacy & GDPR considerations
5. Practical application: Measuring campaign ROI
6. Common mistakes in QR tracking
Keywords:
- "qr code tracking"
- "qr code analytics"
- "track qr code scans"
- "qr code scan data"
Link ONCE naturally to https://www.qrmaster.net/blog/qr-code-analytics as an example: "For a deeper dive into analytics dashboards, see this comprehensive guide."
Tone: Friendly and explanatory, like a teacher. No jargon without explanation.
```
---
## 📋 Usage Instructions
1. **Copy prompt** → Paste into claude.ai
2. **Let it create the artifact**
3. **Click "Publish"** in Claude
4. **Allowed Domain:** Add `www.qrmaster.net, qrmaster.net`
5. **Share link** - Google indexes these!
## 💡 Tips for Maximum Effectiveness
- **Don't publish all on the same day**
- About **1 article per week** for natural growth
- Publish the **more neutral articles first** (Prompt 2 & 4)
- **Share on social media** for faster indexing
- Register the published URLs in Google Search Console

641
new_issues_seo.md Normal file
View File

@@ -0,0 +1,641 @@
Issues
/
Open Graph tags incomplete
Why and how to fix
Submit to IndexNow
Create new issue
All URLs
Pages
Resources
Content
Links
Redirects
Indexability
Sitemaps
Ahrefs metrics
Word or phrase
URL
Advanced filter
Crawl history
Hide chart
12 Jan
13 Jan
13 Jan
14 Jan
14 Jan
15 Jan
0
2
4
6
8
All filter results
All filter results
8
Lost from filter results
0
Lost
0
Patches
Changes: Don't show
Columns
Export
PR
URL
Organic traffic
Is valid Open graph
Open graph attributes
Open graph values
Depth
Is indexable page
No. of all inlinks
24
html
Free vCard QR Generator: Digital Cards | QR Master
https://www.qrmaster.net/blog/vcard-qr-code-generator
0
No
og:type
og:image:alt
og:image
og:description
og:title
article
Professional business card with vCard QR code being scanned by smartphone
https://www.qrmaster.net/blog/vcard-qr-code.png
Create professional vCard QR codes for digital business cards. Share contact info instantly with a scan—includes templates and best practices.
Free vCard QR Generator: Digital Cards
0
Yes
8
24
html
Restaurant Menu QR Codes: 2025 Guide | QR Master
https://www.qrmaster.net/blog/qr-code-restaurant-menu
0
No
og:type
og:image:alt
og:image
og:description
og:title
article
Restaurant table with QR code menu card and smartphone scanning
https://www.qrmaster.net/blog/restaurant-qr-menu.png
Step-by-step guide to creating digital menu QR codes for your restaurant. Learn best practices for touchless menus, placement tips, and tracking.
Restaurant Menu QR Codes: 2025 Guide
0
Yes
8
24
html
QR Code Analytics: The Complete Guide | QR Master
https://www.qrmaster.net/blog/qr-code-analytics
0
No
og:type
og:image:alt
og:image
og:description
og:title
article
QR Code Analytics dashboard displaying scan metrics and user data
https://www.qrmaster.net/blog/qr-code-analytics-hero.webp
Master QR Code Analytics with our complete guide. Learn how to track scans, measure ROI, and optimize your marketing campaigns using real-time data.
QR Code Analytics: The Complete Guide
0
Yes
8
24
html
Dynamic vs Static QR Codes: The Ultimate Comparison | QR Master
https://www.qrmaster.net/blog/dynamic-vs-static-qr-codes
0
No
og:type
og:image:alt
og:image
og:description
og:title
article
Comparison graphic showing features of static versus dynamic QR codes
https://www.qrmaster.net/blog/static-vs-dynamic-qr-codes-hero.png
Static vs Dynamic QR Codes: Which should you choose? Learn the key differences, pros and cons, and why dynamic codes are better for business.
Dynamic vs Static QR Codes: The Ultimate Comparison
0
Yes
8
24
html
How to Generate Bulk QR Codes from Excel | QR Master
https://www.qrmaster.net/blog/bulk-qr-code-generator-excel
0
No
og:type
og:image:alt
og:image
og:description
og:title
article
Excel spreadsheet being converted into multiple QR codes
https://www.qrmaster.net/blog/building-qr-generator.png
Generate hundreds of QR codes from Excel or CSV files in minutes. Step-by-step guide with templates, best practices, and free tools.
How to Generate Bulk QR Codes from Excel
0
Yes
8
24
html
QR Code Print Size Guide: Minimum Sizes for Every Use Case | QR Master
https://www.qrmaster.net/blog/qr-code-print-size-guide
0
No
og:type
og:image:alt
og:image
og:description
og:title
article
Various print materials showing different QR code sizes
https://www.qrmaster.net/blog/qr-print-sizes.png
Complete guide to QR code print sizes. Learn minimum dimensions for business cards, posters, banners, and more to ensure reliable scanning.
QR Code Print Size Guide: Minimum Sizes for Every Use Case
0
Yes
8
24
html
Best QR Code Generator for Small Business 2025 | QR Master
https://www.qrmaster.net/blog/qr-code-small-business
0
No
og:type
og:image:alt
og:image
og:description
og:title
article
Small business owner using QR codes for customer engagement
https://www.qrmaster.net/blog/small-business-qr.png
Find the best QR code solution for your small business. Compare features, pricing, and use cases for marketing, payments, and operations.
Best QR Code Generator for Small Business 2025
0
Yes
8
24
html
QR Code Tracking: Complete Guide 2025 | QR Master
https://www.qrmaster.net/blog/qr-code-tracking-guide-2025
0
No
og:type
og:image:alt
og:image
og:description
og:title
article
QR Code Tracking and analytics dashboard visualization
https://www.qrmaster.net/blog/qr-code-tracking-guide-hero.webp
The complete guide to QR Code Tracking in 2025. Learn how to track scans, measure ROI, and optimize your marketing campaigns.
QR Code Tracking: Complete Guide 2025
0
Yes
8
Showing 8 of 8
Issues
/
Pages to submit to IndexNow
Why and how to fix
Submit to IndexNow
Create new issue
All URLs
Pages
Resources
Content
Links
Redirects
Indexability
Sitemaps
Ahrefs metrics
Word or phrase
URL
Advanced filter
Crawl history
Hide chart
12 Jan
13 Jan
13 Jan
14 Jan
14 Jan
15 Jan
0
9
18
27
36
All filter results
All filter results
12
Lost from filter results
Lost
Patches: Show all
Changes: Absolute
Columns
Export
PR
URL
Organic traffic
Changes
HTTP status code
Content type
Is indexable page
Title
Patch it
Batch AI
Meta description
Patch it
Batch AI
H1
H2
No. of content words
Changes
No. of internal outlinks
Changes
No. of external outlinks
Changes
Page text
First found at
40
html
QR Master: Dynamic QR Generator
https://www.qrmaster.net/
0
200
text/html; charset=utf-8
Yes
QR Master: Dynamic QR Generator
Enter new title
Create professional QR codes with QR Master. Dynamic QR with tracking, bulk generation, custom branding, and real-time analytics for all your campaigns.
Enter new meta description
QR Master: Dynamic QR Code Generator with Analytics
Create QR Codes That Work Everywhere
Create QR Codes That Work Everywhere
Instant QR Code Generator
The Future of QR Codes is AI-Powered
More Free QR Code Tools
Why Dynamic QR Codes Save You Money
All 8
777
29
0
View text
5 KB
38
html
QR Insights: Latest QR Strategies | QR Master
https://www.qrmaster.net/blog
0
200
text/html; charset=utf-8
Yes
QR Insights: Latest QR Strategies | QR Master
Enter new title
Expert guides on QR code analytics, dynamic vs static codes, bulk generation, and smart marketing use cases. Learn how to maximize your QR campaign ROI.
Enter new meta description
QR Code Insights
481
495
14
37
0
View changes
3 KB
3 KB
38
html
Pricing Plans | QR Master
https://www.qrmaster.net/pricing
0
200
text/html; charset=utf-8
Yes
Pricing Plans | QR Master
Enter new title
Choose the perfect QR code plan for your needs. Free, Pro, and Business plans with dynamic QR codes, analytics, bulk generation, and custom branding.
Enter new meta description
QR Master Pricing Choose Your QR Code Plan
Choose Your Plan
Compare our plans
Choose Your Plan
271
29
30
1
0
View text
2 KB
38
html
QR Code Erstellen Kostenlos | QR Master
https://www.qrmaster.net/qr-code-erstellen
0
200
text/html; charset=utf-8
Yes
QR Code Erstellen Kostenlos | QR Master
Enter new title
Erstellen Sie QR Codes kostenlos in Sekunden. Dynamische QR-Codes mit Tracking, Branding und Massen-Erstellung. Für immer kostenlos.
Enter new meta description
QR Code Erstellen Kostenloser QR Code Generator mit Tracking
Erstellen Sie QR-Codes, die überall funktionieren
Erstellen Sie QR-Codes, die überall funktionieren
Sofortiger QR-Code-Generator
Warum dynamische QR-Codes Geld sparen
Alles was Sie brauchen, um professionelle QR-Codes zu erstellen
Wählen Sie Ihren Plan
All 6
554
29
0
View text
4 KB
24
html
Free vCard QR Generator: Digital Cards | QR Master
https://www.qrmaster.net/blog/vcard-qr-code-generator
0
200
text/html; charset=utf-8
Yes
Free vCard QR Generator: Digital Cards | QR Master
Enter new title
Create professional vCard QR codes for digital business cards. Share contact info instantly with a scan—includes templates and best practices.
Enter new meta description
Free vCard QR Generator: Digital Cards
Quick Answer
What is a vCard QR Code?
Why Use a Digital Business Card QR Code?
Information You Can Include in a vCard
Static vs Dynamic vCard QR Codes
All 13
1,135
1,149
14
37
0
View changes
7 KB
7 KB
24
html
Restaurant Menu QR Codes: 2025 Guide | QR Master
https://www.qrmaster.net/blog/qr-code-restaurant-menu
0
200
text/html; charset=utf-8
Yes
Restaurant Menu QR Codes: 2025 Guide | QR Master
Enter new title
Step-by-step guide to creating digital menu QR codes for your restaurant. Learn best practices for touchless menus, placement tips, and tracking.
Enter new meta description
Restaurant Menu QR Codes: 2025 Guide
Quick Answer
Why Restaurants Need QR Code Menus in 2025
Step 1: Prepare Your Digital Menu
Step 2: Create Your QR Code with QR Master
Step 3: Customize Your Restaurant QR Code
All 13
1,242
1,256
14
38
0
View changes
8 KB
8 KB
24
html
QR Code Analytics: The Complete Guide | QR Master
https://www.qrmaster.net/blog/qr-code-analytics
0
200
text/html; charset=utf-8
Yes
QR Code Analytics: The Complete Guide | QR Master
Enter new title
Master QR Code Analytics with our complete guide. Learn how to track scans, measure ROI, and optimize your marketing campaigns using real-time data.
Master QR Code Analytics with our complete guide. Learn how to track scans, measure ROI, and optimize your marketing campaigns using real-time data and insights.
Enter new meta description
QR Code Analytics: The Complete Guide
Quick Answer
What Are Scan Analytics?
How to Set Up QR Code Analytics
Key Metrics in QR Code Analytics
Advanced Campaign Tracking Strategies
All 12
1,526
1,538
12
37
0
View changes
10 KB
10 KB
24
html
Dynamic vs Static QR Codes: The Ultimate Comparison | QR Master
https://www.qrmaster.net/blog/dynamic-vs-static-qr-codes
0
200
text/html; charset=utf-8
Yes
Dynamic vs Static QR Codes: The Ultimate Comparison | QR Master
Enter new title
Static vs Dynamic QR Codes: Which should you choose? Learn the key differences, pros and cons, and why dynamic codes are better for business.
Static vs Dynamic QR Codes: Which one should you choose? Learn the key differences, pros and cons, and why dynamic QR codes are the better choice for business and marketing.
Enter new meta description
Dynamic vs Static QR Codes: The Ultimate Comparison
Quick Answer
What is a Static QR Code?
What is a Dynamic QR Code?
Direct Comparison: Static vs Dynamic
Why Dynamic QR Codes Are Better for Business
All 10
1,074
1,082
8
37
0
View changes
7 KB
7 KB
24
html
How to Generate Bulk QR Codes from Excel | QR Master
https://www.qrmaster.net/blog/bulk-qr-code-generator-excel
0
200
text/html; charset=utf-8
Yes
How to Generate Bulk QR Codes from Excel | QR Master
Enter new title
Generate hundreds of QR codes from Excel or CSV files in minutes. Step-by-step guide with templates, best practices, and free tools.
Enter new meta description
How to Generate Bulk QR Codes from Excel
Quick Answer
How Bulk QR Code Generation Works
Step-by-Step Guide: Excel to QR Codes
Use Cases for Bulk QR Codes
Free vs Paid Bulk QR Tools
All 12
1,882
1,896
14
37
1
View changes
12 KB
13 KB
24
html
QR Code Print Size Guide: Minimum Sizes for Every Use Case | QR Master
https://www.qrmaster.net/blog/qr-code-print-size-guide
0
200
text/html; charset=utf-8
Yes
QR Code Print Size Guide: Minimum Sizes for Every Use Case | QR Master
Enter new title
Complete guide to QR code print sizes. Learn minimum dimensions for business cards, posters, banners, and more to ensure reliable scanning.
Enter new meta description
QR Code Print Size Guide: Minimum Sizes for Every Use Case
Quick Answer
Why QR Code Size Matters
The Scanning Distance Formula
QR Code Sizes by Application
Factors Affecting Scanability
All 12
948
962
14
37
0
View changes
6 KB
6 KB
24
html
Best QR Code Generator for Small Business 2025 | QR Master
https://www.qrmaster.net/blog/qr-code-small-business
0
200
text/html; charset=utf-8
Yes
Best QR Code Generator for Small Business 2025 | QR Master
Enter new title
Find the best QR code solution for your small business. Compare features, pricing, and use cases for marketing, payments, and operations.
Enter new meta description
Best QR Code Generator for Small Business 2025
Quick Answer
Why Small Businesses Need QR Codes
Top 10 QR Code Use Cases for Small Business
What to Look for in a Small Business QR Solution
QR Master for Small Business
All 11
1,034
1,048
14
37
0
View changes
7 KB
7 KB
24
html
QR Code Tracking: Complete Guide 2025 | QR Master
https://www.qrmaster.net/blog/qr-code-tracking-guide-2025
0
200
text/html; charset=utf-8
Yes
QR Code Tracking: Complete Guide 2025 | QR Master
Enter new title
The complete guide to QR Code Tracking in 2025. Learn how to track scans, measure ROI, and optimize your marketing campaigns.
The complete guide to QR Code Tracking in 2025. Learn how to track scans, measure ROI with analytics tools, and optimize your marketing campaigns for maximum engagement.
Enter new meta description
QR Code Tracking: Complete Guide 2025
Quick Answer
What is QR Code Tracking?
Why Track QR Codes? Key Benefits
How to Track QR Code Scans: 4 Methods
QR Code Tracking Tools Comparison
All 15
2,959
2,967
8
38
1
View changes
19 KB
19 KB
Showing 12 of 12

View File

@@ -4,20 +4,7 @@ const nextConfig = {
skipTrailingSlashRedirect: true,
images: {
unoptimized: false,
remotePatterns: [
{
protocol: 'https',
hostname: 'www.qrmaster.net',
},
{
protocol: 'https',
hostname: 'qrmaster.net',
},
{
protocol: 'https',
hostname: 'images.qrmaster.net',
},
],
domains: ['www.qrmaster.net', 'qrmaster.net', 'images.qrmaster.net'],
formats: ['image/webp', 'image/avif'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],

744
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,6 @@
"scripts": {
"dev": "next dev -p 3050",
"build": "prisma generate && next build",
"trigger:indexing": "tsx scripts/trigger-indexing.ts",
"submit:indexnow": "tsx scripts/submit-indexnow.ts",
"start": "next start",
"lint": "next lint",
@@ -37,14 +36,12 @@
"bcryptjs": "^2.4.3",
"chart.js": "^4.4.0",
"clsx": "^2.0.0",
"copy-image-clipboard": "^2.1.2",
"d3-scale": "^4.0.2",
"dayjs": "^1.11.10",
"dotenv": "^17.2.3",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"framer-motion": "^12.24.10",
"googleapis": "^170.1.0",
"html-to-image": "^1.11.13",
"i18next": "^23.7.6",
"ioredis": "^5.3.2",
@@ -54,12 +51,11 @@
"next": "^14.2.35",
"next-auth": "^4.24.5",
"papaparse": "^5.4.1",
"posthog-js": "^1.332.0",
"posthog-js": "^1.276.0",
"qr-code-styling": "^1.9.2",
"qrcode": "^1.5.3",
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-barcode": "^1.6.1",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 804 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 860 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 630 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 863 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 646 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 699 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

View File

@@ -1,23 +1,21 @@
// Helper script to run IndexNow submission
// Run with: npm run submit:indexnow
// Run with: npx tsx scripts/submit-indexnow.ts
import { getAllIndexableUrls, submitToIndexNow } from '../src/lib/indexnow';
async function main() {
console.log('🚀 Starting IndexNow Submission Script...');
console.log(' Gathering URLs for IndexNow submission...');
console.log('Gathering URLs for IndexNow submission...');
const urls = getAllIndexableUrls();
console.log(` Found ${urls.length} indexable URLs.`);
console.log(`Found ${urls.length} indexable URLs.`);
// Basic validation of key presence (logic can be improved)
if (!process.env.INDEXNOW_KEY) {
console.warn('⚠️ WARNING: INDEXNOW_KEY environment variable is not set.');
console.warn(' The submission might fail if the key is not hardcoded in src/lib/indexnow.ts');
console.warn('⚠️ WARNING: INDEXNOW_KEY environment variable is not set. Using placeholder.');
// In production, you'd fail here. For dev/demo, we proceed but expect failure from API.
}
await submitToIndexNow(urls);
console.log('\n✨ IndexNow submission process completed.');
}
main().catch(console.error);

View File

@@ -1,81 +0,0 @@
import { google } from 'googleapis';
import fs from 'fs';
import path from 'path';
import { getAllIndexableUrls } from '../src/lib/indexnow';
// ==========================================
// CONFIGURATION
// ==========================================
// Path to your Service Account Key (JSON file)
const KEY_FILE = path.join(__dirname, '../service_account.json');
// Urls are now fetched dynamically from src/lib/indexnow.ts
// ==========================================
async function runUsingServiceAccount() {
console.log('🚀 Starting Google Indexing Script (All Pages)...');
if (!fs.existsSync(KEY_FILE)) {
console.error('\n❌ ERROR: Service Account Key not found!');
console.error(` Expected path: ${KEY_FILE}`);
console.error(' Please follow the instructions in INDEXING_GUIDE.md to create and save the key.');
return;
}
console.log(`🔑 Authenticating with key file: ${path.basename(KEY_FILE)}...`);
const auth = new google.auth.GoogleAuth({
keyFile: KEY_FILE,
scopes: ['https://www.googleapis.com/auth/indexing'],
});
try {
const client = await auth.getClient();
console.log('✅ Authentication successful.');
console.log(' Gathering URLs to index...');
const allUrls = getAllIndexableUrls();
console.log(` Found ${allUrls.length} URLs to index.`);
for (const url of allUrls) {
console.log(`\n📄 Processing: ${url}`);
try {
const result = await google.indexing('v3').urlNotifications.publish({
auth: client,
requestBody: {
url: url,
type: 'URL_UPDATED'
}
});
console.log(` 👉 Status: ${result.status} ${result.statusText}`);
// Optional: Log more details from result.data if needed
} catch (innerError: any) {
console.error(` ❌ Failed to index ${url}`);
if (innerError.response) {
console.error(` Reason: ${innerError.response.status} - ${JSON.stringify(innerError.response.data)}`);
// 429 = Quota exceeded
// 403 = Permission denied (check service account owner status)
} else {
console.error(` Reason: ${innerError.message}`);
}
}
// Optional: Add a small delay to avoid hitting rate limits too fast if you have hundreds of URLs
// await new Promise(resolve => setTimeout(resolve, 500));
}
console.log('\n✨ Done! All requests processed.');
console.log(' Note: Check Google Search Console for actual indexing status over time.');
} catch (error: any) {
console.error('\n❌ Fatal error occurred:');
console.error(error.message);
}
}
runUsingServiceAccount();

View File

@@ -1,742 +0,0 @@
Overview: qr code generator
View Cached Page
Create Report
370,000
Monthly Volume
337,000
Estimated Clicks
Clicked any result
Low
91%
High
Mobile vs Desktop
Mobile
Desktop
Not Enough Data
Paid clicks
Low
03%
12%
High
13%+
Difficulty
73
Google Provided Data
Expand
Cost Per Click
$0.51
Monthly Cost
$3,072
Search Volume
90,500
Advertisers
15
Homepages
6
Fresh SV
918,000
Universal search in SERP
8,191
Similar keywords
qr code generator
370,000
qr code generator free
43,300
free qr code generator
34,400
generate qr code
10,800
google qr code generator
8,000
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
655
Questions
How to generate a qr code
1,700
How to generate qr code
630
How to generate qr code for url
270
What is the best qr code generator?
220
How to generate bank qr code without edge
200
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
19,120,108
Also ranks for
qr code generator free
43,300
qr code maker
52,000
free qr code generator
34,400
qr generator
25,300
create qr code
29,500
Overview: barcode generator
View Cached Page
Create Report
58,300
Monthly Volume
51,000
Estimated Clicks
Clicked any result
Low
87%
High
Mobile vs Desktop
Mobile
Desktop
Low Mobile
Paid clicks
Low
03%
1%
High
13%+
Difficulty
22
Google Provided Data
Expand
Cost Per Click
$1.68
Monthly Cost
$5,316
Search Volume
110,000
Advertisers
5
Homepages
21
Fresh SV
72,800
Universal search in SERP
5,381
Similar keywords
barcode generator
58,300
free barcode generator
4,000
upc barcode generator
3,200
2d barcode generator
1,300
generate barcode
1,300
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
326
Questions
How to store barcodes generated into a folder in linux python
250
How to generate barcodes
180
How to generate barcodes in excel
180
How to generate barcodes for products
135
How to generate a third party barcode for j1 waiver
110
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
27,933,196
Also ranks for
free barcode generator
4,000
barcode maker
6,100
upc code generator
3,600
upc generator
4,500
2d barcode generator
1,300
Overview: qr code maker
View Cached Page
Create Report
52,000
Monthly Volume
48,200
Estimated Clicks
Clicked any result
Low
93%
High
Mobile vs Desktop
Mobile
Desktop
Not Enough Data
Paid clicks
Low
03%
12%
High
13%+
Difficulty
47
Google Provided Data
Expand
Cost Per Click
$0.37
Monthly Cost
$209
Search Volume
18,100
Advertisers
11
Homepages
32
Fresh SV
71,300
Universal search in SERP
601
Similar keywords
qr code maker
52,000
animal crossing qr code maker
2,000
free qr code maker
2,000
qr code maker free
1,900
mini qr code maker
380
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
13
Questions
How to maker qr code for cia
70
How to make qr codes with brother label maker
70
How to make a qr code qr code maker
50
How to post qr codes online mii maker
40
How to get qr code watch maker
28
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
84,638,180
Also ranks for
qr code generator free
43,300
free qr code generator
34,400
create a qr code
17,100
create qr code
29,500
qr generator
25,300
Overview: google qr code generator
View Cached Page
Create Report
8,000
Monthly Volume
5,100
Estimated Clicks
Clicked any result
Low
64%
High
Mobile vs Desktop
Mobile
Desktop
Low Mobile
Paid clicks
Low
03%
2%
High
13%+
Difficulty
52
Google Provided Data
Expand
Cost Per Click
$3.53
Monthly Cost
$0.00
Search Volume
2,900
Advertisers
9
Homepages
20
Fresh SV
11,500
Universal search in SERP
336
Similar keywords
google qr code generator
8,000
qr code generator google
4,800
free qr code generator google
720
qr code generator google form
440
google form qr code generator
320
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
59
Questions
Does google have a qr code generator?
135
How to generate qr code for google authenticator
100
Does google have a qr code generator for contact info?
90
How to generate qr code for google form
90
How to generate a qr code for a google form
90
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
27,918,916
Also ranks for
qr code generator free
43,300
qr code maker
52,000
create qr code
29,500
qr generator
25,300
free qr code generator
34,400
Overview: create qr code
View Cached Page
Create Report
29,500
Monthly Volume
26,400
Estimated Clicks
Clicked any result
Low
89%
High
Mobile vs Desktop
Mobile
Desktop
Not Enough Data
Paid clicks
Low
03%
16%
High
13%+
Difficulty
52
Google Provided Data
Expand
Cost Per Click
$3.32
Monthly Cost
$1,406
Search Volume
14,800
Advertisers
15
Homepages
25
Fresh SV
50,000
Universal search in SERP
3,223
Similar keywords
create qr code
29,500
create a qr code
17,100
How to create a qr code
9,200
create qr code free
5,500
How to create a qr code free
1,400
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
1,110
Questions
How to create a qr code
9,200
How to create a qr code free
1,400
How to create qr codes
1,300
How to create qr code
1,300
How to create a qr code for a google form
1,100
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
18,733,729
Also ranks for
qr code generator free
43,300
qr code maker
52,000
create a qr code
17,100
free qr code generator
34,400
qr generator
25,300
Overview: qr code with logo
View Cached Page
Create Report
1,600
Monthly Volume
1,300
Estimated Clicks
Clicked any result
Low
81%
High
Mobile vs Desktop
Mobile
Desktop
Low Mobile
Paid clicks
Low
03%
8%
High
13%+
Difficulty
48
Google Provided Data
Expand
Cost Per Click
$0.00
Monthly Cost
$0.00
Search Volume
-
Advertisers
1
Homepages
25
Fresh SV
2,900
Universal search in SERP
291
Similar keywords
qr code generator with logo
4,100
qr code with logo
1,600
create qr code with logo
440
qr code generator with logo free
400
android studio qr code generator with logo
300
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
17
Questions
How to make qr code with logo
40
How to design qr code with logo
40
How to create qr code with logo
28
How to make own qr code with logo
24
How to create your own qr code with logo
24
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
37,452,720
Also ranks for
qr code maker
52,000
qr code generator free
43,300
create qr code
29,500
free qr code generator
34,400
create a qr code
17,100
Overview: spotify code generator
View Cached Page
Create Report
840
Monthly Volume
630
Estimated Clicks
Clicked any result
Low
76%
High
Mobile vs Desktop
Mobile
Desktop
Not Enough Data
Paid clicks
Not Enough Data
Difficulty
21
Google Provided Data
Expand
Cost Per Click
$0.00
Monthly Cost
$0.00
Search Volume
90
Advertisers
0
Homepages
5
Fresh SV
2,400
Universal search in SERP
106
Similar keywords
spotify code generator
840
spotify premium code generator no survey
420
spotify premium codes generator
300
spotify premium code generator no survey 2017
290
spotify code generator 2019
290
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
5
Questions
How to generate spotify code
90
How to get spotify premium code free generator 2018
70
How to get code for spotify premium spotify premium free code generator
24
Where is spotify pin code generator?
12
How to generate a spotify code
-
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
Log in to see all results
--
View All
82,799,750
Also ranks for
qr code maker
52,000
spotify codes
7,100
spotify code
5,700
qrcode
11,900
create qr code
29,500

View File

@@ -1,506 +0,0 @@
## A) Executive summary (max 12 bullets)
* **Win fast (060 days)** by launching a *“wedge” set* of low-KD, high-intent tool pages (WhatsApp / Instagram / vCard / Bulk / PDF) + one differentiated feature hub (**QR Code Analytics + Tracking**) that every tool page upsells into.
* **Build an intent ladder**: *Free generator → Dynamic QR → Tracking/Analytics → Bulk/API/Teams → Custom domains + integrations* (this mirrors how category leaders gate value). ([qr-code-generator.com][1])
* **Exploit SERP splits**: head terms (“qr code generator”) are crowded with generalist tools (Canva/Adobe) + legacy generators, while **dynamic/tracking** queries skew toward SaaS platforms—your product sweet spot. ([qr-code-generator.com][1])
* **Turn “Google QR Code Generator” into a capture page**: Google/Chrome already generates a basic QR for a URL; your angle is *“Chrome is static-only → heres dynamic + analytics + UTM + campaign dashboards.”* ([Google Hilfe][2])
* **Programmatic SEO (pSEO) is mandatory** in this space: competitors scale with templated “solutions” pages by QR type (vCard, WiFi, Spotify, Instagram, etc.). ([qr-code-generator.com][3])
* **Avoid pSEO index bloat** with strict canonical + noindex rules and *minimum content thresholds* per template (examples below).
* **Differentiate on trust**: QR scams (“quishing”) are rising; bake “safe redirect + link preview + scan security” into product messaging and content. ([Der Guardian][4])
* **Make “Barcode Generator” a top-of-funnel traffic engine** (58k SV / KD 22 in your data) but route conversions toward QR analytics + dynamic capabilities; barcode SERPs are full of embed-only utilities and hardware vendors. ([Free Online Barcode Generator by TEC-IT][5])
* **Ship IA early**: a scalable sitemap with `/tools/`, `/features/`, `/integrations/`, `/compare/`, `/learn/`, and `/templates/` prevents cannibalization and makes internal linking deterministic.
* **Measure leading indicators**: indexation coverage, impressions, tool-page CVR to signup, activation (QR created), and upgrades (dynamic/tracking enabled).
* **Link acquisition**: win with embed widgets, UTM/GA4 tracking guides, open-source SDKs, and directory placements (10 angles below).
* **Assumptions used** (adjustable): **EN**, **Global/US focus**, **Freemium SaaS → subscription**, primary conversion **signup → generate → enable tracking**.
---
## B) Competitor landscape (top competitors + what they do best + weaknesses)
Below is a **SERP-driven** view of recurring domains across “QR code generator”, “dynamic QR”, “tracking/analytics”, and “type” queries (vCard/Instagram/Spotify/etc.):
### 1) QR Code Generator (Bitly) — `qr-code-generator.com`
**Best at**
* Clear **feature ladder + gating** (static free → dynamic/analytics → bulk/API/teams). ([qr-code-generator.com][1])
* Massive **“solutions” library** (SEO scale by QR type). ([qr-code-generator.com][3])
**Weaknesses to exploit**
* Heavy gating/upsell can frustrate “free” intent.
* Many “solution” pages trend toward **marketing copy**—opportunity for deeper “how-to + templates + examples + tracking instrumentation”.
### 2) QRCode Monkey — `qrcode-monkey.com`
**Best at**
* “Free + design/customization” positioning; vectors/print talk resonates. ([QRCode Monkey][6])
* Has an **API pitch** (some scaling). ([QRCode Monkey][7])
**Weaknesses**
* Less credible on analytics-first workflows; your advantage is *campaign measurement + dashboards*.
### 3) The QR Code Generator (TQRCG) — `the-qrcode-generator.com`
**Best at**
* Trust messaging: “free means free” + warns about expiring codes. ([the-qrcode-generator.com][8])
**Weaknesses**
* Content often “how-to guide” oriented; you can outrank with **better tools + richer templates + integrations**.
### 4) Hovercode — `hovercode.com`
**Best at**
* Product-led pages (“create now”) + “trackable QR codes” positioning. ([Hovercode][9])
* pSEO via many generator variants (logo, circle, etc.). ([Hovercode][10])
**Weaknesses**
* Opportunity to beat them with **comparison pages + GA4 instrumentation + bulk workflows**.
### 5) Scanova — `scanova.io`
**Best at**
* Strong **feature pages**: dynamic, tracking, security, landing pages (good enterprise pitch). ([Scanova][11])
**Weaknesses**
* Many blogs are long; you can win snippets with **structured templates + FAQs + exact steps + schema**.
### 6) Flowcode — `flowcode.com`
**Best at**
* Owns “offline conversions + analytics” narrative (enterprise). ([flowcode.com][12])
**Weaknesses**
* Often skewed to demos; you can capture SMB/free intent and upgrade later.
### 7) QRCodeChimp — `qrcodechimp.com`
**Best at**
* Huge template catalog (menus, forms, cards, etc.) + GA integration content. ([QR Code Chimp][13])
**Weaknesses**
* Template sprawl risks thin pages—beat them on **quality thresholds + tighter topical clusters**.
### 8) ME-QR — `me-qr.com`
**Best at**
* Aggressive pSEO for types (PDF/Instagram/WhatsApp/Spotify). ([me-qr.com][14])
**Weaknesses**
* Many pages feel commodity; you can differentiate with **better UX + security + analytics clarity**.
### 9) Canva / Adobe Express (generalists)
* Canva and Adobe rank on “free QR code generator” intent via ecosystem pull. ([Canva][15])
**Your play**: dont “out-brand” them—**out-specialize** on dynamic/tracking/bulk/API and win long-tail + mid-tail.
### 10) Barcode generators (for your “Barcode Generator” gold mine)
* TEC-IT (embed + backlink requirement) and Barcodes Inc (hardware upsell). ([Free Online Barcode Generator by TEC-IT][5])
**Your play**: best-in-class UX + formats + bulk + API docs + “barcode vs QR” education to route users into QR analytics.
---
## C) Keyword clusters + priority order (explain why)
### Intent model (how to cluster)
* **Do / Generate (tool intent)**: “X QR code generator”, “bulk”, “PDF to QR”, “WiFi QR”, “Instagram QR”, “WhatsApp QR”.
* **Decide (commercial investigation)**: “dynamic vs static”, “trackable QR codes”, “best QR code generator”, “QR code analytics”.
* **Implement (technical)**: “QR code API”, “track QR codes in GA4”, “UTM QR code”, “bulk QR from CSV / Sheets”.
* **Navigate (platform-native)**: “Google QR code generator”, “Spotify code generator”, “Instagram QR code”.
### Priority ladder (P0 → P2)
**P0 (launch first; fastest to rank + high upsell value)**
1. **WhatsApp QR Code Generator** (SV 180 / KD 17 in your list) → high intent + low KD + SMB conversion path.
2. **Instagram QR Code Generator** (SV 440 / KD 23) → same logic + add “IG has native QR; heres branded + tracked campaigns”. ([Instagram Hilfe][16])
3. **vCard QR Code Generator** (SV 180 / KD 24) → business use case; great signup driver.
4. **QR Code Analytics** (SV 135 / KD 24) → *your core differentiator*; becomes the internal-link destination from every tool page.
5. **Trackable QR Codes** (SV 135 / KD 0) → perfect wedge term; map to a commercial page that demonstrates tracking dashboard and “dynamic”.
6. **Barcode Generator** (58k / KD 22) → big traffic engine; route to QR features + analytics.
**P1 (build authority + revenue features)**
* **Bulk QR Code Generator** (SV 360 / KD 33)
* **QR Code Tracking** (SV 320 / KD 37) (map carefully vs “analytics”)
* **WiFi QR Code Generator** (SV 1,400 / KD 34)
* **PDF to QR Code Generator** (SV ~260 / KD 36, CPC high)
* **Google QR Code Generator** (SV 8k) (capture via “Chrome static QR” + upsell). ([Google Hilfe][2])
**P2 (long-term mid/high competition)**
* **Dynamic QR Code Generator** (SV 1,200 / KD 43)
* **Free QR Code Generator** (SV 34,400 / KD 34)
* **QR code maker** (SV 52k / KD 47)
* **QR Code Generator** (SV 370k) — pillar target supported by everything above.
### Cannibalization rule (critical)
* **One primary intent per page.** Example mapping:
* `/features/qr-code-analytics/` = “qr code analytics” (feature/commercial)
* `/learn/qr-code-tracking/` = “qr code tracking” (educational/how it works + GA4)
* `/tools/trackable-qr-code-generator/` = “trackable qr codes” (tool + demo dashboard)
---
## D) Recommended sitemap / IA (with URL examples)
### Core structure (scalable + pSEO-safe)
**1) Tools (transactional)**
* `/qr-code-generator/` (core tool hub, not a blog post)
* `/tools/vcard-qr-code-generator/`
* `/tools/whatsapp-qr-code-generator/`
* `/tools/instagram-qr-code-generator/`
* `/tools/wifi-qr-code-generator/`
* `/tools/pdf-to-qr-code-generator/`
* `/tools/bulk-qr-code-generator/`
* `/barcode-generator/` (separate category; include QR/2D + 1D)
**2) Features (commercial)**
* `/features/dynamic-qr-codes/`
* `/features/qr-code-analytics/`
* `/features/qr-code-campaigns/` (folders, tags, exports)
* `/features/custom-domain/`
* `/features/teams-roles/`
* `/features/security-anti-phishing/` (trust wedge; see “quishing”). ([Der Guardian][4])
**3) Integrations (high-intent + linkable)**
* `/integrations/google-analytics-4/`
* `/integrations/hubspot/`
* `/integrations/zapier/`
* `/integrations/shopify/`
(Ship GA4 first; it supports your “tracking” narrative.)
**4) Learn Hub (educational; supports rankings + conversions)**
* `/learn/dynamic-vs-static-qr-codes/`
* `/learn/how-to-track-qr-codes-in-ga4/`
* `/learn/qr-code-size-guide/`
* `/learn/qr-code-error-correction/`
* `/learn/google-qr-code-generator/` (Chromes built-in QR + limitations). ([Google Hilfe][2])
* `/learn/spotify-code-generator/` (Spotify Codes explainer + CTA to your tool). ([SpotifyCodes][17])
**5) Templates / Use cases (pSEO with guardrails)**
* `/templates/restaurant-menu-qr/`
* `/templates/business-card-qr/`
* `/templates/event-check-in-qr/`
Each template must include: examples, copy/paste CTAs, recommended QR type, tracking setup, and links to the tool.
### Breadcrumb + internal linking rules (hub-and-spoke)
* **Tool pages** link up to:
* `/features/qr-code-analytics/`
* `/features/dynamic-qr-codes/`
* `/learn/dynamic-vs-static-qr-codes/`
* the **closest** templates + GA4 integration (where relevant)
* **Learn pages** link down to:
* the *single best-matching tool page* (primary CTA)
* 24 related learn pages (cluster reinforcement)
* **Integrations** link to:
* analytics feature + tracking learn guide + relevant tool pages
---
## E) “Wedge” plan: what to launch first to rank within 3060 days
### Launch set (minimum viable topical authority)
**Week 13 shipping goal: 8 pages that create a ranking flywheel**
**Tool pages (P0)**
1. `/tools/whatsapp-qr-code-generator/` (KD 17)
2. `/tools/instagram-qr-code-generator/` (KD 23)
3. `/tools/vcard-qr-code-generator/` (KD 24)
4. `/tools/trackable-qr-code-generator/` (KD 0 term → commercial wedge)
5. `/barcode-generator/` (traffic engine)
**Feature + Learn pages (conversion + trust)**
6) `/features/qr-code-analytics/` (your core differentiator)
7) `/learn/dynamic-vs-static-qr-codes/` (decision content)
8) `/learn/google-qr-code-generator/` (steal “Google/Chrome” demand; Chrome is static URL sharing). ([Google Hilfe][2])
### Why this ranks fast on a new domain
* Low-KD type terms are less “brand dominated” than head terms.
* Every tool page naturally links to analytics + dynamic, so **internal PageRank concentrates** on your money features.
* “Google QR code generator” content can win featured snippets because its step-based and grounded in official Chrome documentation. ([Google Hilfe][2])
---
## F) 90-day execution roadmap (week-by-week)
### Weeks 12: Foundations (technical + tracking + SEO hygiene)
* **Tech SEO**
* Set up GSC + GA4 (or PostHog) + server-side event pipeline for “QR created / downloaded / scan events”.
* Define **indexation policy**: which templates get indexed, which are noindex.
* Implement: XML sitemaps by type (`/sitemap-tools.xml`, `/sitemap-learn.xml`), robots, canonicals, hreflang plan (even if EN-only now).
* **Schema baseline**
* Organization, WebSite, BreadcrumbList sitewide.
* SoftwareApplication/WebApplication on core tool hub.
* **Information architecture**
* Ship nav for Tools / Features / Learn / Pricing / API.
### Week 3: Ship the wedge tool pages (P0)
* Publish WhatsApp / Instagram / vCard / Trackable tool pages.
* Each ships with: FAQ, examples, “Static vs Dynamic” block, “Enable analytics” CTA, and internal links to `/features/qr-code-analytics/`.
### Week 4: Ship the analytics feature hub + dynamic feature hub
* `/features/qr-code-analytics/` + `/features/dynamic-qr-codes/`
* Add product screenshots/GIFs and a simple “How tracking works” diagram (dynamic redirect → logging → dashboard).
### Week 5: Learn cluster for decision + “Google QR”
* `/learn/dynamic-vs-static-qr-codes/`
* `/learn/google-qr-code-generator/` (include “Chrome creates QR for a page” and limitations). ([Google Hilfe][2])
### Week 6: Barcode Generator tool + “Barcode vs QR” guide
* Launch `/barcode-generator/` + `/learn/barcode-vs-qr-code/` to route barcode traffic into QR use cases.
* Add bulk export formats and “print quality” section to compete with incumbents. ([Free Online Barcode Generator by TEC-IT][5])
### Week 7: Bulk + PDF tools (P1)
* `/tools/bulk-qr-code-generator/` (CSV upload; align with SERP expectations like “download ZIP”). ([quickchart.io][18])
* `/tools/pdf-to-qr-code-generator/` (CPC-heavy query → strong conversion)
### Week 8: GA4 integration page (linkable asset)
* `/integrations/google-analytics-4/`
* Companion guide: `/learn/how-to-track-qr-codes-in-ga4/` (UTMs, events, attribution).
### Week 9: Authority pieces (start the pillar support)
Publish 2 of these 5 (see section below):
* “QR Code Size Guide”
* “QR Code Error Correction Explained”
* “UTM Builder for QR Campaigns”
* “QR Code Security / Quishing Prevention”
* “QR Code Analytics Benchmarks”
### Week 10: pSEO expansion (controlled)
* Add 1020 additional `/tools/{type}/` pages (WiFi, email, SMS, etc.) only if they meet your thin-content threshold.
* Add 1020 `/templates/` pages tied to real use cases.
### Week 11: Comparisons (conversion-focused)
* `/compare/qr-code-generator-vs-canva/`
* `/compare/qr-code-generator-vs-qrcode-monkey/`
* `/compare/dynamic-qr-code-generators/` (listicle with your wedge terms)
### Week 1213: Iterate based on GSC data
* Optimize pages with impressions but low CTR (titles/meta).
* Expand FAQs to match PAA.
* Strengthen internal links from high-impression pages to money pages.
---
## G) Page briefs for the top 5 money pages (H1, sections, schema, CTA, internal links)
### 1) Dynamic QR Code Generator
**URL:** `/features/dynamic-qr-codes/` (feature) + optional `/tools/dynamic-qr-code-generator/` (tool demo)
**Primary keyword:** dynamic qr code generator
**H1:** Dynamic QR Code Generator (Editable + Trackable)
**Sections (order matters)**
* What is a dynamic QR code? (vs static)
* Edit destination after printing (URL, file, page)
* Tracking/analytics overview (scans, time, location, device)
* Use cases (menus, flyers, events, packaging)
* How it works (redirect + logging)
* Pricing preview + free tier
* FAQ (Do they expire? Can I change the URL? Can I export data?)
**Schema**
* FAQPage
* SoftwareApplication (or WebApplication)
* BreadcrumbList
**Primary CTA**
* “Create a dynamic QR code” (signup)
**Internal links**
* To `/features/qr-code-analytics/`, `/learn/dynamic-vs-static-qr-codes/`, `/integrations/google-analytics-4/`
> Competitor pattern to beat: strong gating + feature ladder is common. ([qr-code-generator.com][1])
---
### 2) QR Code Analytics
**URL:** `/features/qr-code-analytics/`
**Primary keyword:** qr code analytics
**H1:** QR Code Analytics: Track Scans, Measure Campaign ROI
**Sections**
* What you can measure (total/unique scans, geo, device, time)
* Campaign organization (folders/tags, UTM conventions)
* Export + integrations (GA4 first)
* Dashboards (examples: restaurant menu, event check-in, retail)
* Data accuracy & privacy notes
* FAQ (“Can I track a static QR?” → explain dynamic requirement)
**Schema**
* FAQPage
* SoftwareApplication
* BreadcrumbList
**CTA**
* “Enable analytics on your QR code” (upgrade nudges)
**Internal links**
* From **every tool page** (sticky sidebar “Track scans with Analytics”)
* To `/learn/how-to-track-qr-codes-in-ga4/`
> This is exactly what SaaS competitors highlight for upsell. ([flowcode.com][12])
---
### 3) Bulk QR Code Generator
**URL:** `/tools/bulk-qr-code-generator/`
**Primary keyword:** bulk qr code generator
**H1:** Bulk QR Code Generator (CSV Upload → Download ZIP)
**Sections**
* Upload CSV / paste data / Google Sheets import (later)
* Output formats (PNG/SVG/PDF), naming conventions
* Dynamic vs static toggle per row (upsell!)
* Common workflows: inventory labels, invites, coupons
* QA: scan testing, error correction, print sizing
* FAQ
**Schema**
* FAQPage
* HowTo (only if you include step-by-step with images)
**CTA**
* “Generate bulk QR codes” + secondary “Enable tracking for all”
**Internal links**
* To `/features/qr-code-analytics/` + `/features/dynamic-qr-codes/`
> SERPs often expect “free bulk + zip”; match that intent. ([QR Explore][19])
---
### 4) vCard QR Code Generator
**URL:** `/tools/vcard-qr-code-generator/`
**Primary keyword:** vCard qr code generator
**H1:** vCard QR Code Generator (Digital Business Card)
**Sections**
* vCard fields + preview (VCF standard)
* iOS/Android compatibility + best practices
* Static vs dynamic vCard (edit contact later)
* Examples: sales reps, events, storefront QR
* CTA: “Add scan tracking to your business cards”
* FAQ (works on Android/iOS; does it expire; can I add photo; etc.)
**Schema**
* FAQPage
* SoftwareApplication
**CTA**
* “Create vCard QR” + upsell “Track scans / update later”
**Internal links**
* To `/learn/dynamic-vs-static-qr-codes/` + analytics feature
---
### 5) QR Code API (developer money page)
**URL:** `/features/qr-code-api/` + `/docs/api/`
**Primary keyword:** qr code api, qr code generator api
**H1:** QR Code API (Generate QR Codes at Scale)
**Sections**
* Authentication, endpoints, rate limits
* Generate static/dynamic, bulk endpoints, webhooks (scan events)
* Code samples (JS/Python/cURL)
* Compliance + uptime
* Pricing tiers
**Schema**
* SoftwareApplication (feature page)
* TechArticle (docs pages)
**CTA**
* “Get API key” / “Start trial”
**Internal links**
* From bulk generator + analytics pages
---
## H) Risks + mitigation (cannibalization, programmatic pitfalls, E-E-A-T, index bloat)
### 1) Keyword cannibalization (very likely in this niche)
**Risk:** “qr code tracking”, “trackable qr codes”, “qr code analytics” collapse into the same intent.
**Mitigation:** hard-map intents:
* Analytics = feature/commercial
* Tracking = learn/how-to + GA4
* Trackable QR = tool landing with demo dashboard
### 2) Programmatic SEO thin pages / index bloat
**Risk:** hundreds of near-identical “{type} QR generator” pages get ignored/deindexed.
**Mitigation (hard rules)**
* Index only pages that include **unique elements**:
* type-specific fields + validation (real tool)
* 23 examples
* type-specific FAQs
* type-specific tracking use case
* **Noindex**: parameter pages, empty states, duplicate locale stubs, search/filter pages.
### 3) Trust & QR scam concerns (reputation risk, but also opportunity)
**Risk:** Users fear scanning QR codes; Google may reward safety content.
**Mitigation:** ship “Security” feature page + learn content about safe scanning and link previews, referencing real-world scam patterns. ([Der Guardian][4])
### 4) Over-reliance on “Google QR Code Generator” traffic
**Risk:** users only want Chromes built-in static QR and bounce.
**Mitigation:** page structure: “How to do it in Chrome” (satisfy intent) → “When you need dynamic + analytics” (convert). ([Google Hilfe][2])
### 5) E-E-A-T gap vs incumbents
**Risk:** new domain lacks credibility.
**Mitigation**
* Publish 23 “benchmarks / research” assets with original data (even small): scan-rate benchmarks, print-size testing, or campaign case studies.
* Add transparent pricing, uptime, privacy policy, and author/editor pages for Learn content.
---
If you tell me your **target market (US vs DACH vs global), language (EN/DE), and monetization (freemium vs trials)**, I can *tighten the sitemap + 90-day calendar* so it perfectly matches your rollout (especially internationalization + URL strategy).
[1]: https://www.qr-code-generator.com/?utm_source=chatgpt.com "QR Code Generator | Create Your Free QR Codes"
[2]: https://support.google.com/chrome/answer/10051760?co=GENIE.Platform%3DDesktop&hl=en&utm_source=chatgpt.com "Share pages in Chrome - Computer"
[3]: https://www.qr-code-generator.com/solutions/?utm_source=chatgpt.com "QR Code Solution for Every Purpose"
[4]: https://www.theguardian.com/money/2025/may/25/qr-code-scam-what-is-quishing-drivers-app-phone-parking-payment?utm_source=chatgpt.com "'Pay here': the QR code 'quishing' scam targeting drivers"
[5]: https://barcode.tec-it.com/en?utm_source=chatgpt.com "Free Online Barcode Generator: Create Barcodes for Free!"
[6]: https://www.qrcode-monkey.com/?utm_source=chatgpt.com "QRCode Monkey - The free QR Code Generator to create ..."
[7]: https://www.qrcode-monkey.com/de/qr-code-service/?utm_source=chatgpt.com "QR Code API for Static Codes"
[8]: https://www.the-qrcode-generator.com/?utm_source=chatgpt.com "The QR Code Generator (TQRCG): Create Free QR Codes"
[9]: https://hovercode.com/?utm_source=chatgpt.com "QR Code Generator | Create Free Dynamic QR Codes"
[10]: https://hovercode.com/circle-qr-code-generator/?utm_source=chatgpt.com "Generate circle QR codes (no sign up required)"
[11]: https://scanova.io/features/?utm_source=chatgpt.com "Powerful features for all QR Code use cases"
[12]: https://www.flowcode.com/product/analytics?utm_source=chatgpt.com "Gain insight into your offline marketing with in-depth Analytics"
[13]: https://www.qrcodechimp.com/qr-code-analytics-guide/?utm_source=chatgpt.com "QR Code Analytics: Track, Analyze & Optimize Your ..."
[14]: https://me-qr.com/qr-code-generator/pdf?srsltid=AfmBOooK1o7kkjaSizlEOWcEcYcDWfKhZuuM3XvrJGQlm2xdiTbw1exS&utm_source=chatgpt.com "Create QR Code For PDF FREE"
[15]: https://www.canva.com/qr-code-generator/?utm_source=chatgpt.com "Free QR Code Generator - Create QR codes with ease"
[16]: https://help.instagram.com/925529167647849/?utm_source=chatgpt.com "Find and customize the QR code of your Instagram profile"
[17]: https://www.spotifycodes.com/?utm_source=chatgpt.com "Spotify Codes"
[18]: https://quickchart.io/bulk-qr-code-generator/?utm_source=chatgpt.com "Bulk QR Code Generator | Custom colors and logo, free"
[19]: https://qrexplore.com/generate/?utm_source=chatgpt.com "Bulk QR Code Generator"

View File

@@ -1,13 +0,0 @@
{
"type": "service_account",
"project_id": "gen-lang-client-0595806638",
"private_key_id": "e44bc1717f1cf413521149de272bf13bfa89a336",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC0xJkozHODpcpD\nu3dTHPfprZk6eKiOT05h+uG8Clm8i8LLaS/eHT+B02qxFYMBX0VH9O2GvPp/VnfC\nB/Clc7bofN5VDpQMjVUiPDqMbUVEAiQHNOTp9pkfJltaHAl/J5Cc/DccCaOn89xT\nFD5b7dTn29suuBZHTqsaFDlydnU2xJAwcrWBm7/A0JZM85d76yhY0Jxcg9w8XlpE\n+TWN8OxSUIfubaac0mfI40RH2EfugmA7M45t7B3sEbmHk5tVQSItvncz2ls9fUE4\neB6u4foMFp4Z9k5Ejs7y4N3Yft0JWS+RjI0bcvvvQ/wcnDfcwCdDFFn2Y+hflKMm\nS9+ZRnmBAgMBAAECggEAAztAeo3JifZD3nzEUcDte9cHgN7AMtlJ3Wvc7va5Sw50\nizkCmSlwPoc4/0MvoMo0+701JVxbenXveMpEb3fZMoszkdU9U9iPZCfzB4wQErOa\nppuprbbOXtO9JzZVinWzflPSIUVK16lUVvYVrmfpHYou1G/dIMIXQkVsD7NR9t/B\nafD0w/q1nwwyPB08BjSemKXDQo6NF0cE/TIvaMj8vtxuouAL+fea0n/XxMQNoIoJ\nF+pJtPQ1hkQrpayzuj3smQ11PFpYuvsZHuS3dG9j4gPjGClezK3Sflt7vwNywIRc\ntJ0Qx58on0dy0YnppMWrHh/nykraVLusvMI04joqwQKBgQDlE1Mbi8dpeKn7zkV9\nLS/O6S5Ql2k2G6KxI8GHn3qxB5yfU8G2xqk64r04YB6SMCXscIQu1Tmro8kDMTZk\n5b/issH3+7uqGcJMYhZczWsjax3S1ugepXt29dF26VnbyfvD7h9qleKLhIq32z9P\nxzZGhptTCa0swypi7prNE0MhZwKBgQDKA75g8UhVULA6q3hFEG+24ICd3Gekdz1y\nmaDrPjSJmeMSUlDl4QhGRbZBSJcAfcFKk4+Nme3sTYvjMMz6per4a5TC/+IlSufm\nOSL+CSVijvVYwCMyLyiAcm5Pqcjw16S6enHIidnOYP8e8OM0H2aNKfFTKq30B3ww\nAF8ipa+01wKBgQC24JaYhx7LtOj/fc08AbcJGF9BN59m8ukPQdxeyZLJgaooCFW9\n9RtlR16IgzPkwUuFVs4wFUnVHQx83+zs3/4wnUT9FJrdUXMsR6JStCu0Ou+0Qp1M\n2g+XCOgQZnq2XKoB4ThzfvU9LLMR1JbWudM6unuF71OxSJ2uHY636YjOQQKBgBs6\n+fSTUY6+e6LM7j9RAd4C0RN2XDodIJlMABb1oZtStPsJQYJbHQRr7S9Lm58jVGS7\nE0ShFSMfKNYNA/RdXRjzV3AZkeA5Ap1T4lWf4fwxDP1TmOrw1GLMCfaPClj8mGXS\nj3farRNWm80N53JlMSuiFbeCL0SPpbvKsQg4kUCtAoGAUORyhW70nhZJ1BbmvyRf\n17fcwenK/3GmWgqsrzN7/ucPwjqIzLGVoAXd2euxpE49/VW2xYpJjyHJHuoXDc66\n+AUog0bsxcKpM5tL3VelQl3SkUlCG7jYe20rMm01y35uM2REvQv3/r9F7Bbaq/9n\nSCwu/45QobgLCUx0B7wDqWA=\n-----END PRIVATE KEY-----\n",
"client_email": "indexer@gen-lang-client-0595806638.iam.gserviceaccount.com",
"client_id": "111279247752160222047",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/indexer%40gen-lang-client-0595806638.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}

View File

@@ -6,7 +6,7 @@ import { usePathname } from 'next/navigation';
import { Button } from '@/components/ui/Button';
import { Footer } from '@/components/ui/Footer';
import en from '@/i18n/en.json';
import { ChevronDown, Wifi, Contact, MessageCircle, QrCode, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users, Barcode as BarcodeIcon } from 'lucide-react';
import { ChevronDown, Wifi, Contact, MessageCircle, QrCode, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users } from 'lucide-react';
import { cn } from '@/lib/utils';
import { AnimatePresence, motion } from 'framer-motion';
@@ -62,7 +62,6 @@ export default function MarketingLayout({
{ 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: 'Barcode', description: 'Generate barcodes', href: '/tools/barcode-generator', icon: BarcodeIcon, color: 'text-slate-800', bgColor: 'bg-slate-100' },
];
return (
@@ -97,7 +96,6 @@ export default function MarketingLayout({
<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/barcode-generator">Barcode Generator</a></li>
</ul>
</nav>
</div>

View File

@@ -79,7 +79,7 @@ export default function BlogPage() {
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto">
{blogPostList.map((post: any, index: number) => (
{blogPostList.map((post: any) => (
<Link key={post.slug} href={post.link || `/blog/${post.slug}`}>
<Card hover className="h-full overflow-hidden shadow-md hover:shadow-xl transition-all duration-300">
<div className="relative h-56 overflow-hidden">
@@ -89,7 +89,6 @@ export default function BlogPage() {
width={800}
height={600}
className="w-full h-full object-cover transition-transform duration-500 hover:scale-110"
priority={index < 3}
/>
</div>
<CardHeader className="pb-3">

View File

@@ -1,435 +0,0 @@
'use client';
import React, { useState, useRef } from 'react';
import Barcode from 'react-barcode';
import Link from 'next/link';
import { Download, Printer, Barcode as BarcodeIcon, Sparkles, Sliders, Check, Info, Copy } from 'lucide-react';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { Select } from '@/components/ui/Select';
import { showToast } from '@/components/ui/Toast';
import { cn } from '@/lib/utils';
import { toPng, toSvg, toBlob } from 'html-to-image';
// Brand Colors
const BRAND = {
paleGrey: '#EBEBDF',
slate900: '#0f172a',
};
const BARCODE_COLORS = [
{ name: 'Classic Black', value: '#000000' },
{ name: 'Dark Blue', value: '#1A1265' },
{ name: 'Rich Indigo', value: '#4338CA' },
{ name: 'Deep Emerald', value: '#065F46' },
{ name: 'Crimson', value: '#991B1B' },
{ name: 'Slate Gray', value: '#334155' },
{ name: 'Business Navy', value: '#1E293B' },
];
const FRAME_OPTIONS = [
{ id: 'none', label: 'No Frame' },
{ id: 'scanme', label: 'Scan Me' },
{ id: 'product', label: 'Product' },
{ id: 'serial', label: 'Serial' },
];
const FORMAT_INFO: Record<string, string> = {
'CODE128': 'High-density alphanumeric format. Best for general purpose use.',
'EAN13': 'International retail standard for products worldwide.',
'UPC': 'Standard retail format used primarily in North America.',
'CODE39': 'Older industrial standard supporting uppercase letters and numbers.',
'ITF14': 'Used on shipping containers and logistics packaging.',
'MSI': 'Specialized format for retail shelf labeling and inventory.',
'pharmacode': 'Pharmaceutical packaging control standard.',
};
export default function BarcodeGeneratorClient() {
const [value, setValue] = useState('123456789');
const [format, setFormat] = useState('CODE128');
const [width, setWidth] = useState(2);
const [height, setHeight] = useState(100);
const [displayValue, setDisplayValue] = useState(true);
const [lineColor, setLineColor] = useState('#000000');
const [frameType, setFrameType] = useState('none');
const [error, setError] = useState<string | null>(null);
const barcodeRef = useRef<HTMLDivElement>(null);
// Validation Logic
React.useEffect(() => {
setError(null);
if (!value) return;
if (format === 'EAN13' && !/^\d{12,13}$/.test(value)) {
setError('EAN-13 requires 12 or 13 digits.');
} else if (format === 'UPC' && !/^\d{11,12}$/.test(value)) {
setError('UPC requires 11 or 12 digits.');
} else if (format === 'CODE39' && !/^[0-9A-Z\-\.\ \$\/\+\%]+$/.test(value)) {
setError('Code 39 only supports numbers, uppercase letters, and - . $ / + % spaces.');
} else if ((format === 'ITF14' || format === 'MSI') && !/^\d+$/.test(value)) {
setError('This format only supports numbers.');
}
}, [value, format]);
const downloadBarcode = async (extension: 'png' | 'svg') => {
if (!barcodeRef.current) return;
try {
let dataUrl;
if (extension === 'png') {
dataUrl = await toPng(barcodeRef.current, {
backgroundColor: '#ffffff',
pixelRatio: 3,
});
} else {
dataUrl = await toSvg(barcodeRef.current, {
backgroundColor: '#ffffff',
});
}
const link = document.createElement('a');
link.href = dataUrl;
link.download = `barcode-${value || 'generator'}.${extension}`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
showToast(`Barcode downloaded as ${extension.toUpperCase()}`, 'success');
} catch (err) {
console.error('Download failed', err);
showToast('Download failed', 'error');
}
};
const copyBarcode = async () => {
if (!barcodeRef.current) return;
try {
// Use toBlob directly for better performance and compatibility
const blob = await toBlob(barcodeRef.current, {
backgroundColor: '#ffffff',
pixelRatio: 3,
});
if (!blob) {
throw new Error('Failed to generate image blob');
}
await navigator.clipboard.write([
new ClipboardItem({
'image/png': blob,
}),
]);
showToast('Barcode copied to clipboard', 'success');
} catch (err) {
console.error('Copy failed', err);
showToast('Failed to copy barcode', 'error');
}
};
const formats = [
{ value: 'CODE128', label: 'Code 128 (Standard)' },
{ value: 'EAN13', label: 'EAN-13 (Retail)' },
{ value: 'UPC', label: 'UPC-A (US Retail)' },
{ value: 'CODE39', label: 'Code 39' },
{ value: 'ITF14', label: 'ITF-14' },
{ value: 'MSI', label: 'MSI' },
{ value: 'pharmacode', label: 'Pharmacode' },
];
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-6 md:p-8 lg:p-10 space-y-8 border-r border-slate-100">
{/* Configuration */}
<div className="space-y-6">
<h2 className="text-lg font-bold text-slate-900 flex items-center gap-2">
<Sliders className="w-5 h-5 text-slate-900" aria-hidden="true" />
Configuration
</h2>
<div className="space-y-4">
<div>
<label htmlFor="barcode-content" className="block text-sm font-medium text-slate-700 mb-2">Content</label>
<Input
id="barcode-content"
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Enter barcode data (e.g. 12345678)"
className="h-12 text-base rounded-xl border-slate-200 focus:border-slate-900 focus:ring-slate-900"
aria-label="Barcode content"
/>
</div>
<div>
<div className="flex items-center justify-between mb-2">
<label className="block text-sm font-medium text-slate-700">Format</label>
<div className="group relative">
<Info className="w-4 h-4 text-slate-400 cursor-help" />
<div className="absolute right-0 bottom-full mb-2 w-64 p-3 bg-slate-900 text-white text-[11px] rounded-xl opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none shadow-xl z-50">
<p className="font-bold mb-1">Format Guide:</p>
<p>{FORMAT_INFO[format]}</p>
</div>
</div>
</div>
<Select
value={format}
onChange={(e) => setFormat(e.target.value)}
className="h-12 rounded-xl border-slate-200"
options={formats}
aria-label="Format"
/>
<p className="text-[10px] text-slate-500 mt-2 px-1">
{FORMAT_INFO[format]}
</p>
</div>
</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-slate-900" aria-hidden="true" />
Design Options
</h2>
<div className="grid grid-cols-2 gap-6">
<div className="space-y-3">
<div className="flex justify-between">
<label htmlFor="width-range" className="text-sm font-medium text-slate-700">Width</label>
<span className="text-xs text-slate-500 bg-slate-100 px-2 py-1 rounded-md font-bold">{width}px</span>
</div>
<input
id="width-range"
type="range"
min="1"
max="4"
step="0.5"
value={width}
onChange={(e) => setWidth(parseFloat(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-slate-900"
aria-label="Barcode width"
/>
</div>
<div className="space-y-3">
<div className="flex justify-between">
<label htmlFor="height-range" className="text-sm font-medium text-slate-700">Height</label>
<span className="text-xs text-slate-500 bg-slate-100 px-2 py-1 rounded-md font-bold">{height}px</span>
</div>
<input
id="height-range"
type="range"
min="30"
max="200"
step="5"
value={height}
onChange={(e) => setHeight(parseInt(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-slate-900"
aria-label="Barcode height"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-3">Line Color</label>
<div className="flex flex-wrap gap-2">
{BARCODE_COLORS.map((c) => (
<button
key={c.name}
onClick={() => setLineColor(c.value)}
className={cn(
"w-9 h-9 rounded-full border-2 flex items-center justify-center transition-all hover:scale-110",
lineColor === c.value ? "border-slate-900 ring-2 ring-offset-2 ring-slate-200" : "border-white shadow-md"
)}
style={{ backgroundColor: c.value }}
aria-label={`Select color ${c.name}`}
title={c.name}
>
{lineColor === c.value && <Check className="w-4 h-4 text-white" strokeWidth={3} aria-hidden="true" />}
</button>
))}
</div>
</div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-3">Frame Label</label>
<div className="grid grid-cols-2 sm: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-slate-900 text-white border-slate-900"
: "bg-slate-50 text-slate-600 border-slate-200 hover:border-slate-300"
)}
>
{frame.label}
</button>
))}
</div>
</div>
<label className="flex items-center gap-3 cursor-pointer group p-3 border border-slate-200 rounded-xl hover:border-slate-900 transition-colors bg-slate-50/50">
<div className={cn(
"w-5 h-5 rounded border-2 flex items-center justify-center transition-all",
displayValue ? "bg-slate-900 border-slate-900" : "border-slate-300 group-hover:border-slate-400"
)}>
{displayValue && <Check className="w-3.5 h-3.5 text-white" strokeWidth={3} />}
</div>
<input
type="checkbox"
checked={displayValue}
onChange={(e) => setDisplayValue(e.target.checked)}
className="sr-only"
/>
<span className="text-sm font-medium text-slate-700">Show Value Text</span>
</label>
</div>
</div>
{/* RIGHT: Preview Section */}
<div className="p-6 md:p-8 lg:p-10 flex flex-col items-center justify-center" style={{ backgroundColor: BRAND.paleGrey }}>
{/* Barcode Card */}
<div
className="bg-white rounded-3xl shadow-xl p-8 flex flex-col items-center justify-center min-h-[300px] w-full max-w-[400px] border border-slate-100 relative"
>
<div className="absolute top-4 right-4">
<div className="flex items-center gap-1.5 px-2 py-1 bg-slate-100 rounded-md text-[10px] font-bold text-slate-500 uppercase tracking-wider">
Live Preview
</div>
</div>
<div ref={barcodeRef} className="py-4 bg-white flex flex-col items-center justify-center overflow-hidden w-full">
{frameType !== 'none' && !error && (
<div
className="mb-4 px-6 py-2 rounded-full text-white font-bold text-xs tracking-widest uppercase shadow-md"
style={{ backgroundColor: lineColor }}
>
{FRAME_OPTIONS.find(f => f.id === frameType)?.label}
</div>
)}
{error ? (
<div className="flex flex-col items-center text-center p-6 animate-in fade-in zoom-in duration-200">
<div className="w-12 h-12 bg-red-100 rounded-full flex items-center justify-center mb-3">
<Info className="w-6 h-6 text-red-500" />
</div>
<p className="text-red-500 font-bold text-sm">{error}</p>
<p className="text-slate-400 text-xs mt-1">Please correct your input.</p>
</div>
) : value ? (
<Barcode
key={`${format}-${lineColor}-${value}-${width}-${height}-${displayValue}`}
value={value}
format={format as any}
width={width}
height={height}
displayValue={displayValue}
background="#ffffff"
lineColor={lineColor}
margin={10}
/>
) : (
<div className="text-center text-slate-400 p-6">
<BarcodeIcon className="w-12 h-12 mx-auto mb-3 opacity-30" />
<p className="text-sm font-medium">Enter data to generate</p>
</div>
)}
</div>
{/* Info Preview */}
<div className="mt-6 text-center w-full">
<h3 className="font-bold text-slate-900 text-lg flex items-center justify-center gap-2 truncate">
<span className="truncate">{formats.find(f => f.value === format)?.label}</span>
</h3>
<div className="text-xs text-slate-600 mt-1 truncate px-2 font-mono">
{value || 'Barcode Value'}
</div>
</div>
</div>
{/* Download Buttons */}
<div className="flex flex-col gap-4 mt-8 w-full max-w-[450px]">
<div className="flex flex-col sm:flex-row items-center gap-3 w-full">
<Button
onClick={() => downloadBarcode('png')}
className="w-full sm:flex-1 bg-slate-900 hover:bg-black text-white shadow-lg h-12 rounded-xl"
aria-label="Download barcode as PNG"
>
<Download className="w-4 h-4 mr-2" aria-hidden="true" />
Download PNG
</Button>
<div className="relative w-full sm:w-auto">
<div className="absolute -top-3 left-1/2 -translate-x-1/2 bg-indigo-600 text-white text-[9px] font-bold px-2 py-0.5 rounded-full whitespace-nowrap shadow-sm z-10 pointer-events-none">
BEST FOR PRINT
</div>
<Button
onClick={() => downloadBarcode('svg')}
variant="outline"
className="w-full sm:w-auto px-6 border-slate-300 hover:bg-white h-12 rounded-xl font-bold"
aria-label="Download barcode as SVG"
>
SVG
</Button>
</div>
<Button
onClick={copyBarcode}
variant="outline"
className="w-full sm:w-auto px-4 border-slate-300 hover:bg-white h-12 rounded-xl"
title="Copy to Clipboard"
aria-label="Copy barcode image to clipboard"
>
<Copy className="w-4 h-4 text-slate-600" aria-hidden="true" />
</Button>
<Button
onClick={() => window.print()}
variant="outline"
className="w-full sm:w-auto px-4 border-slate-300 hover:bg-white h-12 rounded-xl"
title="Print"
aria-label="Print barcode"
>
<Printer className="w-4 h-4 text-slate-600" aria-hidden="true" />
</Button>
</div>
<div className="text-center">
<Link href="/signup" className="text-xs font-medium text-slate-400 hover:text-indigo-600 transition-colors flex items-center justify-center gap-1 group">
Need bulk generation?
<span className="underline decoration-slate-300 group-hover:decoration-indigo-300 underline-offset-4">Available in Pro &rarr;</span>
</Link>
</div>
</div>
</div>
</div>
</div>
{/* Upsell Banner */}
<div className="mt-8 bg-gradient-to-r from-slate-900 to-slate-700 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">Need Dynamic QR Codes?</h3>
<p className="text-white/80 text-sm mt-1">
Switch to QR codes to edit content later and track your scans.
</p>
</div>
<Link href="/signup">
<Button className="bg-white text-slate-900 hover:bg-slate-100 shrink-0 shadow-lg px-8">
Get Started Free
</Button>
</Link>
</div>
</div>
);
}

View File

@@ -1,321 +0,0 @@
import { BookOpen, CheckCircle, HelpCircle, Layers, Settings, ShoppingCart, Tag, Activity, Factory } from 'lucide-react';
import Link from 'next/link';
export function BarcodeGuide() {
return (
<section className="py-16 px-4 sm:px-6 lg:px-8 bg-white" id="guide">
<div className="max-w-3xl mx-auto prose prose-slate prose-lg">
<div className="flex items-center gap-3 mb-8 not-prose">
<div className="p-3 bg-blue-100/50 rounded-xl">
<BookOpen className="w-8 h-8 text-blue-600" />
</div>
<h2 className="text-3xl font-bold text-slate-900 m-0">
Barcode Generator How Barcodes Work and Why They Matter
</h2>
</div>
<p className="lead text-xl text-slate-600">
Barcodes are an essential part of modern commerce, logistics, and inventory management. A <strong>Barcode Generator</strong> allows businesses and individuals to create scannable barcodes quickly and efficiently for products, packaging, and internal systems. Whether you run an online shop, manage a warehouse, or sell products locally, understanding how barcodes work can save time and reduce errors.
</p>
<p>
In this article, you will learn what barcodes are, how they work, and how a <strong>Barcode Generator</strong> helps you create professional barcodes in seconds.
</p>
{/* SEO Image */}
<div className="my-8 rounded-2xl overflow-hidden shadow-lg not-prose border border-slate-100">
<img
src="/barcode-generator-preview.png"
alt="Free Online Barcode Generator Preview - Create EAN, UPC, and Code 128 Barcodes"
className="w-full h-64 sm:h-80 object-cover"
width="800"
height="320"
/>
<div className="bg-slate-50 p-4 text-sm text-slate-500 text-center border-t border-slate-100">
Use our <strong>free barcode generator</strong> to create scannable codes.
</div>
</div>
<h2>What Is a Barcode?</h2>
<p>
A barcode is a visual representation of data that can be read by machines. It consists of vertical lines with different widths and spacing, which encode numbers or characters. When scanned with a barcode scanner or smartphone, the information is instantly translated into readable data.
</p>
<p>
Barcodes are commonly used to identify products, track inventory, manage logistics, and speed up checkout processes. They reduce manual input and significantly lower the risk of human error.
</p>
<h2>How Does a Barcode Generator Work?</h2>
<p>
A Barcode Generator converts text or numeric input into a barcode format that scanners can read. The process is simple:
</p>
<ul className="list-none pl-0 space-y-4 not-prose my-8">
<li className="flex gap-4">
<div className="w-8 h-8 mt-1 rounded-full bg-slate-100 flex items-center justify-center shrink-0 text-slate-600 font-bold text-sm">1</div>
<div>
<strong className="text-slate-900 block mb-1">Input Data</strong>
<p className="text-slate-600 m-0 text-base">You enter a number or text (for example, a product ID).</p>
</div>
</li>
<li className="flex gap-4">
<div className="w-8 h-8 mt-1 rounded-full bg-slate-100 flex items-center justify-center shrink-0 text-slate-600 font-bold text-sm">2</div>
<div>
<strong className="text-slate-900 block mb-1">Select Format</strong>
<p className="text-slate-600 m-0 text-base">You select a barcode format such as EAN-13 or Code 128.</p>
</div>
</li>
<li className="flex gap-4">
<div className="w-8 h-8 mt-1 rounded-full bg-slate-100 flex items-center justify-center shrink-0 text-slate-600 font-bold text-sm">3</div>
<div>
<strong className="text-slate-900 block mb-1">Generate</strong>
<p className="text-slate-600 m-0 text-base">The generator creates a scannable barcode image instantly.</p>
</div>
</li>
<li className="flex gap-4">
<div className="w-8 h-8 mt-1 rounded-full bg-slate-100 flex items-center justify-center shrink-0 text-slate-600 font-bold text-sm">4</div>
<div>
<strong className="text-slate-900 block mb-1">Download</strong>
<p className="text-slate-600 m-0 text-base">You download or print the barcode for use.</p>
</div>
</li>
</ul>
<p>
A modern <strong>Barcode Generator</strong> works directly in the browser and does not require additional software.
</p>
<h2>Common Types of Barcodes</h2>
<p>
Different barcode formats are used for different purposes. Choosing the right one is important for compatibility and scanning accuracy.
</p>
<div className="grid md:grid-cols-2 gap-6 not-prose my-8">
{/* EAN-13 Card */}
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm hover:shadow-md transition-shadow">
<div className="flex items-center gap-3 mb-3">
<Tag className="w-5 h-5 text-blue-500" />
<h4 className="text-lg font-bold text-slate-900 m-0">EAN-13</h4>
</div>
<div className="text-xs font-mono bg-slate-100 inline-block px-2 py-1 rounded text-slate-500 mb-3">Retail Europe</div>
<div className="mb-3 bg-slate-50 rounded border border-slate-100 p-2 flex justify-center">
<img src="/barcode-generator-preview.png" alt="EAN-13 Barcode Sample for International Products" className="h-10 object-contain opacity-75 grayscale" width="200" height="40" />
</div>
<p className="text-sm text-slate-600 m-0">
EAN-13 is widely used in retail, especially in Europe. It is designed for consumer products sold in stores and supermarkets.
</p>
</div>
{/* UPC-A Card */}
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm hover:shadow-md transition-shadow">
<div className="flex items-center gap-3 mb-3">
<ShoppingCart className="w-5 h-5 text-indigo-500" />
<h4 className="text-lg font-bold text-slate-900 m-0">UPC-A</h4>
</div>
<div className="text-xs font-mono bg-slate-100 inline-block px-2 py-1 rounded text-slate-500 mb-3">Retail USA/Canada</div>
<div className="mb-3 bg-slate-50 rounded border border-slate-100 p-2 flex justify-center">
<img src="/barcode-generator-preview.png" alt="UPC-A Barcode Example for Retail Products in USA" className="h-10 object-contain opacity-75 grayscale" width="200" height="40" />
</div>
<p className="text-sm text-slate-600 m-0">
UPC-A is similar to EAN-13 but is mainly used in the United States and Canada for retail products.
</p>
</div>
{/* Code 128 Card */}
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm hover:shadow-md transition-shadow">
<div className="flex items-center gap-3 mb-3">
<Settings className="w-5 h-5 text-emerald-500" />
<h4 className="text-lg font-bold text-slate-900 m-0">Code 128</h4>
</div>
<div className="text-xs font-mono bg-slate-100 inline-block px-2 py-1 rounded text-slate-500 mb-3">Logistics Universal</div>
<div className="mb-3 bg-slate-50 rounded border border-slate-100 p-2 flex justify-center">
<img src="/barcode-generator-preview.png" alt="Code 128 Barcode for Inventory and Shipping Labels" className="h-10 object-contain opacity-75 grayscale" width="200" height="40" />
</div>
<p className="text-sm text-slate-600 m-0">
Code 128 is a flexible barcode format that supports letters and numbers. It is commonly used in logistics, shipping, and internal tracking systems.
</p>
</div>
{/* Code 39 Card */}
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm hover:shadow-md transition-shadow">
<div className="flex items-center gap-3 mb-3">
<Factory className="w-5 h-5 text-orange-500" />
<h4 className="text-lg font-bold text-slate-900 m-0">Code 39</h4>
</div>
<div className="text-xs font-mono bg-slate-100 inline-block px-2 py-1 rounded text-slate-500 mb-3">Industrial Military</div>
<div className="mb-3 bg-slate-50 rounded border border-slate-100 p-2 flex justify-center">
<img src="/barcode-generator-preview.png" alt="Code 39 Barcode for Industrial Use" className="h-10 object-contain opacity-75 grayscale" width="200" height="40" />
</div>
<p className="text-sm text-slate-600 m-0">
The first alphanumeric barcode, Code 39 is still widely used in automotive and defense industries. It supports numbers and uppercase letters.
</p>
</div>
{/* MSI Card */}
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm hover:shadow-md transition-shadow">
<div className="flex items-center gap-3 mb-3">
<Layers className="w-5 h-5 text-purple-500" />
<h4 className="text-lg font-bold text-slate-900 m-0">MSI</h4>
</div>
<div className="text-xs font-mono bg-slate-100 inline-block px-2 py-1 rounded text-slate-500 mb-3">Inventory Shelves</div>
<div className="mb-3 bg-slate-50 rounded border border-slate-100 p-2 flex justify-center">
<img src="/barcode-generator-preview.png" alt="MSI Barcode for Inventory Management" className="h-10 object-contain opacity-75 grayscale" width="200" height="40" />
</div>
<p className="text-sm text-slate-600 m-0">
MSI (Modified Plessey) is often used for inventory control in retail environments, such as labeling shelves in supermarkets and warehouses.
</p>
</div>
{/* Pharmacode Card */}
<div className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm hover:shadow-md transition-shadow">
<div className="flex items-center gap-3 mb-3">
<Activity className="w-5 h-5 text-red-500" />
<h4 className="text-lg font-bold text-slate-900 m-0">Pharmacode</h4>
</div>
<div className="text-xs font-mono bg-slate-100 inline-block px-2 py-1 rounded text-slate-500 mb-3">Pharma Packaging</div>
<div className="mb-3 bg-slate-50 rounded border border-slate-100 p-2 flex justify-center">
<img src="/barcode-generator-preview.png" alt="Pharmacode for Pharmaceutical Packaging" className="h-10 object-contain opacity-75 grayscale" width="200" height="40" />
</div>
<p className="text-sm text-slate-600 m-0">
Pharmacode is a specialized barcode standard used in the pharmaceutical industry for packaging control to prevent medication errors.
</p>
</div>
</div>
<h2>Why Use a Barcode Generator?</h2>
<p>Using a Barcode Generator offers several advantages:</p>
<div className="not-prose grid gap-4 mb-8">
<div className="flex gap-4 items-start">
<CheckCircle className="w-5 h-5 text-green-500 mt-1 shrink-0" />
<div>
<h5 className="font-bold text-slate-900 m-0">Speed</h5>
<p className="text-slate-600 text-sm m-0">Create barcodes instantly without technical knowledge.</p>
</div>
</div>
<div className="flex gap-4 items-start">
<CheckCircle className="w-5 h-5 text-green-500 mt-1 shrink-0" />
<div>
<h5 className="font-bold text-slate-900 m-0">Accuracy</h5>
<p className="text-slate-600 text-sm m-0">Reduce manual data entry errors.</p>
</div>
</div>
<div className="flex gap-4 items-start">
<CheckCircle className="w-5 h-5 text-green-500 mt-1 shrink-0" />
<div>
<h5 className="font-bold text-slate-900 m-0">Flexibility</h5>
<p className="text-slate-600 text-sm m-0">Generate barcodes for different formats and use cases.</p>
</div>
</div>
<div className="flex gap-4 items-start">
<CheckCircle className="w-5 h-5 text-green-500 mt-1 shrink-0" />
<div>
<h5 className="font-bold text-slate-900 m-0">Cost-effective</h5>
<p className="text-slate-600 text-sm m-0">No need for expensive software or hardware.</p>
</div>
</div>
</div>
<p>
For small businesses, online shops, and startups, a <strong>free Barcode Generator</strong> is often the easiest way to get started.
</p>
<h2>Barcode vs QR Code</h2>
<p>
Although barcodes and QR codes are often confused, they serve different purposes. A barcode stores data horizontally and is mainly used for product identification. A <Link href="/tools/url-qr-code" className="text-blue-600 hover:underline">QR code</Link> stores data both horizontally and vertically and can contain more complex information such as URLs or <Link href="/tools/vcard-qr-code" className="text-blue-600 hover:underline">contact details</Link>.
</p>
<p>
If you only need to identify products or inventory items, a classic barcode is usually the better choice.
</p>
<h2>Are Barcodes Free to Use?</h2>
<p>
The barcode image itself can be generated for free using a Barcode Generator. However, for retail products sold internationally, the barcode number may need to be officially registered through organizations such as GS1. This ensures that the barcode is unique and recognized globally.
</p>
<p>
For internal use, testing, or small projects, free barcode generation is usually sufficient.
</p>
<h2>Use Cases for Barcodes</h2>
<p>Barcodes are used in many industries, including:</p>
<ul className="list-disc pl-6 space-y-2 mb-8">
<li>Retail and e-commerce</li>
<li>Inventory and warehouse management</li>
<li>Shipping and logistics</li>
<li>Libraries and document tracking</li>
<li>Event tickets and labeling</li>
</ul>
<p>
A reliable <strong>Barcode Generator</strong> helps streamline these processes and improves efficiency.
</p>
<h2>Understanding Check Digits</h2>
<p>
Most barcodes (like EAN and UPC) include a "Check Digit"the last number in the sequence. This digit is calculated mathematically from the other numbers to ensure the barcode is scanned correctly. Even if a barcode is slightly damaged or scratched, the scanner uses the check digit to verify the integrity of the data.
</p>
<h2>Best Practices for Printing Barcodes</h2>
<p>
To ensure your barcodes scan instantly at the checkout or in the warehouse, follow these printing tips:
</p>
<ul className="list-disc pl-6 space-y-2 mb-8">
<li><strong>High Contrast:</strong> Always print black bars on a white background. Reverse colors (white bars on black) often fail to scan.</li>
<li><strong>Quiet Zone:</strong> Leave enough white space (margins) on the left and right sides of the barcode.</li>
<li><strong>Resolution:</strong> For professional labels, use <strong>SVG format</strong> (vector) or high-resolution PNGs (at least 300 DPI) to avoid blurry edges.</li>
<li><strong>Size:</strong> Do not scale the barcode too small. Standard EAN-13 codes should be at least 30mm wide for reliable scanning.</li>
</ul>
<hr className="my-12 border-slate-200" />
<div className="flex items-center gap-3 mb-6 not-prose">
<HelpCircle className="w-6 h-6 text-blue-500" />
<h2 className="text-2xl font-bold text-slate-900 m-0">Frequently Asked Questions (FAQ)</h2>
</div>
<div className="not-prose space-y-8">
<div>
<h5 className="font-bold text-slate-900 text-lg mb-2"> What is a Barcode Generator?</h5>
<p className="text-slate-600">A Barcode Generator is an online tool that converts numbers or text into scannable barcode images that can be used for products, labels, and inventory systems.</p>
</div>
<div>
<h5 className="font-bold text-slate-900 text-lg mb-2"> Is this barcode generator free to use?</h5>
<p className="text-slate-600">Yes, our online barcode generator is completely free to use with no hidden costs or sign-ups required. You can generate, download, and print barcodes instantly.</p>
</div>
<div>
<h5 className="font-bold text-slate-900 text-lg mb-2"> Which barcode format should I use?</h5>
<p className="text-slate-600">
<strong>EAN-13:</strong> Standard for retail products in Europe and globally.<br />
<strong>UPC-A:</strong> Standard for retail products in USA/Canada.<br />
<strong>Code 128:</strong> Best for logistics, shipping, and internal tracking (supports letters & numbers).
</p>
</div>
<div>
<h5 className="font-bold text-slate-900 text-lg mb-2"> Can I download barcodes in vector format (SVG)?</h5>
<p className="text-slate-600">Yes! We offer <strong>SVG downloads</strong>. SVG files are vector-based, meaning they can be scaled to any size without losing qualityperfect for professional product packaging.</p>
</div>
<div>
<h5 className="font-bold text-slate-900 text-lg mb-2"> How do I generate a barcode online?</h5>
<p className="text-slate-600">To generate a barcode online, enter your product number or text, select the desired barcode format (such as EAN-13 or Code 128), and click the generate button. The barcode will be created instantly.</p>
</div>
<div>
<h5 className="font-bold text-slate-900 text-lg mb-2"> Are generated barcodes scannable?</h5>
<p className="text-slate-600">Yes, barcodes generated with a proper barcode generator are fully scannable. We generate standard-compliant barcodes readable by any standard optical or laser barcode scanner.</p>
</div>
<div>
<h5 className="font-bold text-slate-900 text-lg mb-2"> Can I use these barcodes for Amazon (EAN/UPC)?</h5>
<p className="text-slate-600">You can generate the <em>image</em> for Amazon here if you already have your EAN/UPC number. However, you cannot "create" a valid global EAN number hereyou must purchase those official numbers from GS1 to sell on major platforms like Amazon.</p>
</div>
<div>
<h5 className="font-bold text-slate-900 text-lg mb-2"> What is the difference between a barcode and a QR code?</h5>
<p className="text-slate-600">A barcode stores data horizontally (1D) and is mainly used for product IDs. A QR code stores data in 2D (matrix) and can hold much more information, such as URLs, vCards, or WiFi credentials.</p>
</div>
</div>
<div className="mt-12 p-6 bg-slate-900 rounded-xl text-white not-prose">
<h4 className="text-lg font-bold mb-2">Final Thoughts</h4>
<p className="text-slate-300 m-0">
A Barcode Generator is a simple yet powerful tool that helps businesses save time, reduce errors, and improve operational efficiency. By choosing the right barcode format and using a reliable generator, you can create professional barcodes that work across different systems and industries.
</p>
</div>
</div>
</section>
);
}

View File

@@ -1,303 +0,0 @@
import React from 'react';
import type { Metadata } from 'next';
import BarcodeGeneratorClient from './BarcodeGeneratorClient';
import { BarcodeGuide } from './BarcodeGuide';
import { Barcode as BarcodeIcon, Shield, Zap, Printer, Download, Share2, Sparkles, Sliders, Check } from 'lucide-react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata
export const metadata: Metadata = {
title: {
absolute: 'Barcode Generator Create Barcodes Online for Free',
},
description: 'Use a free Barcode Generator to create scannable barcodes online. Supports EAN, UPC and Code 128 for products, labels and inventory.',
keywords: ['barcode generator', 'online barcode maker', 'create barcode free', 'ean-13 generator', 'upc-a generator', 'code 128 generator', 'barcode creator', 'printable barcodes'],
alternates: {
canonical: 'https://www.qrmaster.net/tools/barcode-generator',
},
openGraph: {
title: 'Barcode Generator: Create EAN, UPC & Code 128',
description: 'Barcode Generator: Create professional labels instantly. Free & Secured.',
url: 'https://www.qrmaster.net/tools/barcode-generator',
siteName: 'QR Master',
locale: 'en_US',
type: 'website',
images: [{ url: '/barcode-generator-preview.png', width: 1200, height: 630 }],
},
twitter: {
card: 'summary_large_image',
title: 'Free Barcode Generator',
description: 'Create custom barcodes in seconds. Download high-quality PNG/SVG.',
},
robots: {
index: true,
follow: true,
},
};
// JSON-LD Structured Data
const jsonLd = {
'@context': 'https://schema.org',
'@graph': [
generateSoftwareAppSchema(
'Barcode Generator',
'Generate custom printable barcodes instantly for EAN, UPC, Code 128 and more.',
'/og-barcode-generator.png',
'UtilitiesApplication'
),
{
'@type': 'HowTo',
name: 'How to Create a Barcode',
description: 'Create custom barcodes for products or inventory.',
step: [
{
'@type': 'HowToStep',
position: 1,
name: 'Enter Content',
text: 'Type or paste the numeric or alphanumeric data for your barcode.',
},
{
'@type': 'HowToStep',
position: 2,
name: 'Select Format',
text: 'Choose the appropriate barcode type (e.g., Code 128 for general use, EAN-13 for retail).',
},
{
'@type': 'HowToStep',
position: 3,
name: 'Customize Design',
text: 'Adjust the height and width of the barcode to fit your needs.',
},
{
'@type': 'HowToStep',
position: 4,
name: 'Toggle Text',
text: 'Decide if you want the human-readable value to appear below the barcode.',
},
{
'@type': 'HowToStep',
position: 5,
name: 'Download & Print',
text: 'Save your barcode as PNG or SVG and print it for labels or inventory.',
},
],
totalTime: 'PT20S',
},
generateFaqSchema({
'What is a Barcode Generator?': {
question: 'What is a Barcode Generator?',
answer: 'A Barcode Generator is an online tool that converts numbers or text into scannable barcode images that can be used for products, labels, and inventory systems.',
},
'Is this barcode generator free to use?': {
question: 'Is this barcode generator free to use?',
answer: 'Yes, our online barcode generator is completely free to use with no hidden costs or sign-ups required. You can generate, download, and print barcodes instantly.',
},
'Which barcode format should I use?': {
question: 'Which barcode format should I use?',
answer: 'EAN-13 is standard for retail in Europe/Global. UPC-A is standard for retail in USA/Canada. Code 128 is best for logistics and internal tracking as it supports letters and numbers.',
},
'Can I download barcodes in vector format (SVG)?': {
question: 'Can I download barcodes in vector format (SVG)?',
answer: 'Yes! We offer SVG downloads. SVG files are vector-based, meaning they can be scaled to any size without losing quality—perfect for professional product packaging.',
},
'How do I generate a barcode online?': {
question: 'How do I generate a barcode online?',
answer: 'To generate a barcode online, enter your product number or text, select the desired barcode format (such as EAN-13 or Code 128), and click the generate button. The barcode will be created instantly.',
},
'Are generated barcodes scannable?': {
question: 'Are generated barcodes scannable?',
answer: 'Yes, barcodes generated with a proper barcode generator are fully scannable. We generate standard-compliant barcodes readable by any standard optical or laser barcode scanner.',
},
'Can I use these barcodes for Amazon (EAN/UPC)?': {
question: 'Can I use these barcodes for Amazon (EAN/UPC)?',
answer: 'You can generate the image for Amazon here if you already have your EAN/UPC number. However, you cannot "create" a valid global EAN number here—you must purchase those official numbers from GS1 to sell on major platforms like Amazon.',
},
'What is the difference between a barcode and a QR code?': {
question: 'What is the difference between a barcode and a QR code?',
answer: 'A barcode stores data horizontally (1D) and is mainly used for product IDs. A QR code stores data in 2D (matrix) and can hold much more information, such as URLs, vCards, or WiFi credentials.',
},
}),
],
};
export default function BarcodeGeneratorPage() {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<ToolBreadcrumb toolName="Barcode Generator" toolSlug="barcode-generator" />
<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-slate-900">
<div className="absolute inset-0 opacity-10">
{/* Barcode Pattern */}
<svg className="w-full h-full" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="barcode_pattern" width="60" height="60" patternUnits="userSpaceOnUse">
<path d="M5 0 V 60 M15 0 V 60 M20 0 V 60 M35 0 V 60 M40 0 V 60 M55 0 V 60" stroke="white" strokeWidth="2" strokeOpacity="0.5" />
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#barcode_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-blue-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-400"></span>
</span>
Free Tool Professional & Fast
</div>
<h1 className="text-4xl md:text-5xl lg:text-6xl font-extrabold text-white tracking-tight leading-tight mb-6">
Free Online <span className="text-blue-400">Barcode Generator</span>
</h1>
<p className="text-lg md:text-xl text-slate-400 max-w-2xl mx-auto lg:mx-0 mb-8 leading-relaxed">
Our <strong>barcode generator</strong> makes it easy to create and print high-quality labels for products and inventory.
<span className="text-white block sm:inline mt-2 sm:mt-0"> Supports EAN, UPC, Code 128.</span>
</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/5 px-4 py-2.5 rounded-xl border border-white/10 backdrop-blur-sm">
<Check className="w-4 h-4 text-blue-400" />
Retail Ready
</div>
<div className="flex items-center gap-2 bg-white/5 px-4 py-2.5 rounded-xl border border-white/10 backdrop-blur-sm">
<Check className="w-4 h-4 text-blue-400" />
Vector SVG Export
</div>
<div className="flex items-center gap-2 bg-white/5 px-4 py-2.5 rounded-xl border border-white/10 backdrop-blur-sm">
<Check className="w-4 h-4 text-blue-400" />
No Registration
</div>
</div>
</div>
{/* Visual Abstract */}
<div className="hidden lg:flex relative items-center justify-center min-h-[400px]">
<div className="absolute w-[500px] h-[500px] bg-blue-500/10 rounded-full blur-[100px] -top-20 -right-20 animate-pulse" />
<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-2 hover:-rotate-1 transition-all duration-700 group">
<div className="absolute inset-0 bg-gradient-to-br from-white/5 to-transparent rounded-3xl" />
<div className="w-full bg-gradient-to-br from-blue-400 to-indigo-600 rounded-xl shadow-lg p-5 mb-6 relative overflow-hidden text-white">
<div className="flex justify-between items-start mb-4">
<BarcodeIcon className="w-8 h-8 opacity-80" />
<div className="bg-white/20 px-2 py-1 rounded text-xs font-bold uppercase tracking-wider">Label</div>
</div>
<div className="text-xl font-bold tracking-wider mb-1">PROD-98234</div>
<div className="text-xs opacity-70">Inventory ID</div>
</div>
<div className="w-48 h-32 bg-white rounded-xl p-4 shadow-inner relative overflow-hidden flex flex-col items-center justify-center">
<div className="w-full h-16 bg-black flex gap-1 mb-2">
{[2, 4, 1, 3, 2, 1, 4, 2, 1, 3].map((w, i) => (
<div key={i} className="bg-black flex-1" style={{ flex: w }} />
))}
</div>
<div className="text-[10px] font-mono font-bold tracking-widest uppercase">98234001A</div>
</div>
{/* Floating Badge */}
<div className="absolute -bottom-6 -right-6 bg-slate-900 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-blue-500/20 p-2 rounded-full">
<Printer className="w-5 h-5 text-blue-500" />
</div>
<div className="text-left">
<div className="text-[10px] text-slate-400 font-bold uppercase tracking-wider">Ready</div>
<div className="text-sm font-bold text-white">Print Instantly</div>
</div>
</div>
</div>
</div>
</div>
</section>
{/* GENERATOR SECTION */}
<section className="py-12 px-4 sm:px-6 lg:px-8 -mt-8">
<BarcodeGeneratorClient />
</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 Our Barcode Generator Works
</h2>
<div className="grid md:grid-cols-3 lg:grid-cols-5 gap-8">
<article className="text-center">
<div className="w-12 h-12 rounded-2xl bg-black flex items-center justify-center mx-auto mb-4">
<Sliders className="w-6 h-6 text-white" />
</div>
<h3 className="font-bold text-slate-900 mb-2">1. Configure</h3>
<p className="text-slate-600 text-xs leading-relaxed">
Enter your data and select the format.
</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">
<Sparkles className="w-6 h-6 text-white" />
</div>
<h3 className="font-bold text-slate-900 mb-2">2. Customize</h3>
<p className="text-slate-600 text-xs leading-relaxed">
Adjust height, width and text display.
</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">
<Zap className="w-6 h-6 text-white" />
</div>
<h3 className="font-bold text-slate-900 mb-2">3. Preview</h3>
<p className="text-slate-600 text-xs leading-relaxed">
See your barcode update in real-time.
</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">4. Download</h3>
<p className="text-slate-600 text-xs leading-relaxed">
Save as professional PNG or SVG.
</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">
<Printer className="w-6 h-6 text-white" />
</div>
<h3 className="font-bold text-slate-900 mb-2">5. Print</h3>
<p className="text-slate-600 text-xs leading-relaxed">
Print labels directly from your browser.
</p>
</article>
</div>
</div>
</section>
{/* RELATED TOOLS */}
<RelatedTools />
{/* SEO GUIDE */}
<BarcodeGuide />
</div>
</>
);
}

View File

@@ -3,7 +3,6 @@
import React, { useState, useRef } from 'react';
import Link from 'next/link';
import { QRCodeSVG } from 'qrcode.react';
import { toPng } from 'html-to-image';
import {
Link as LinkIcon,
@@ -53,6 +52,7 @@ export default function URLGenerator() {
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 = `url-qr-code.png`;

View File

@@ -6,7 +6,7 @@ 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, QrCode, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users, Barcode as BarcodeIcon } from 'lucide-react';
import { ChevronDown, Wifi, Contact, MessageCircle, QrCode, Link2, Type, Mail, MessageSquare, Phone, Calendar, MapPin, Facebook, Instagram, Twitter, Youtube, Music, Bitcoin, CreditCard, Video, Users } from 'lucide-react';
import { cn } from '@/lib/utils';
import { AnimatePresence, motion } from 'framer-motion';
@@ -62,7 +62,6 @@ export default function MarketingLayout({
{ 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: 'Barcode', description: 'Barcode erstellen', href: '/tools/barcode-generator', icon: BarcodeIcon, color: 'text-slate-800', bgColor: 'bg-slate-100' },
];
return (
@@ -97,7 +96,6 @@ export default function MarketingLayout({
<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/barcode-generator">Barcode Generator</a></li>
</ul>
</nav>
</div>

View File

@@ -10,7 +10,6 @@ import { Features } from '@/components/marketing/Features';
import { Pricing } from '@/components/marketing/Pricing';
import { FAQ } from '@/components/marketing/FAQ';
import { ScrollToTop } from '@/components/ui/ScrollToTop';
import { FreeToolsGrid } from '@/components/marketing/FreeToolsGrid';
import de from '@/i18n/de.json';
function truncateAtWord(text: string, maxLength: number): string {
@@ -103,9 +102,6 @@ export default function QRCodeErstellenPage() {
{/* Main Interaction: Generator */}
<InstantGenerator t={t} />
{/* Free Tools Grid */}
<FreeToolsGrid />
<StaticVsDynamic t={t} />
<Features t={t} />

View File

@@ -25,7 +25,6 @@ export default function sitemap(): MetadataRoute.Sitemap {
'paypal-qr-code',
'zoom-qr-code',
'teams-qr-code',
'barcode-generator',
];
// All blog posts

View File

@@ -0,0 +1,77 @@
'use client';
import React from 'react';
/**
* Modern animated grid background for Hero section
* Replaces the overused "blob" animations with a more premium, tech-forward aesthetic
*/
export const AnimatedBackground: React.FC = () => {
return (
<div className="absolute inset-0 overflow-hidden pointer-events-none">
{/* Subtle gradient overlay */}
<div className="absolute inset-0 bg-gradient-to-br from-blue-50 via-white to-purple-50" />
{/* Animated grid pattern */}
<svg
className="absolute inset-0 w-full h-full"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
{/* Gradient for grid lines */}
<linearGradient id="grid-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stopColor="#6366f1" stopOpacity="0.1" />
<stop offset="50%" stopColor="#8b5cf6" stopOpacity="0.15" />
<stop offset="100%" stopColor="#d946ef" stopOpacity="0.1" />
</linearGradient>
{/* Pattern definition */}
<pattern
id="grid-pattern"
width="50"
height="50"
patternUnits="userSpaceOnUse"
>
{/* Vertical line */}
<line
x1="0"
y1="0"
x2="0"
y2="50"
stroke="url(#grid-gradient)"
strokeWidth="1"
strokeDasharray="4 4"
className="animate-dash"
/>
{/* Horizontal line */}
<line
x1="0"
y1="0"
x2="50"
y2="0"
stroke="url(#grid-gradient)"
strokeWidth="1"
strokeDasharray="4 4"
className="animate-dash"
/>
</pattern>
</defs>
{/* Grid overlay */}
<rect width="100%" height="100%" fill="url(#grid-pattern)" />
</svg>
{/* Floating gradient orbs (subtle, as accents) */}
<div className="absolute top-1/4 -left-48 w-96 h-96 bg-blue-400/5 rounded-full blur-3xl animate-float" />
<div className="absolute bottom-1/4 -right-48 w-96 h-96 bg-purple-400/5 rounded-full blur-3xl animate-float" style={{ animationDelay: '2s' }} />
{/* Noise texture overlay for depth */}
<div
className="absolute inset-0 opacity-[0.015] mix-blend-overlay"
style={{
backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 400 400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E")`,
}}
/>
</div>
);
};

View File

@@ -0,0 +1,50 @@
'use client';
import React from 'react';
import { motion } from 'framer-motion';
interface BentoGridProps {
children: React.ReactNode[];
}
/**
* Modern Bento Box Grid Layout
* Features are displayed in different sizes based on importance
*/
export const BentoGrid: React.FC<BentoGridProps> = ({ children }) => {
return (
<div className="grid grid-cols-1 md:grid-cols-6 gap-6 max-w-6xl mx-auto">
{children}
</div>
);
};
interface BentoItemProps {
children: React.ReactNode;
size?: 'small' | 'medium' | 'large';
className?: string;
}
export const BentoItem: React.FC<BentoItemProps> = ({
children,
size = 'medium',
className = '',
}) => {
const sizeClasses = {
small: 'md:col-span-2',
medium: 'md:col-span-3',
large: 'md:col-span-6',
};
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.5 }}
className={`${sizeClasses[size]} ${className}`}
>
{children}
</motion.div>
);
};

View File

@@ -0,0 +1,95 @@
'use client';
import React from 'react';
import { motion } from 'framer-motion';
import { TrendingUp, Eye, MousePointer } from 'lucide-react';
export const FeatureAnalyticsDemo: React.FC = () => {
const data = [30, 45, 35, 60, 50, 75, 65, 85];
return (
<div className="relative h-full min-h-[300px] bg-gradient-to-br from-blue-50 to-blue-100 rounded-2xl p-8 overflow-hidden group">
{/* Background Pattern */}
<div className="absolute inset-0 opacity-10">
<svg width="100%" height="100%">
<pattern id="analytics-grid" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="1" cy="1" r="1" fill="currentColor" />
</pattern>
<rect width="100%" height="100%" fill="url(#analytics-grid)" />
</svg>
</div>
<div className="relative z-10 h-full flex flex-col">
{/* Header */}
<div className="mb-6">
<div className="flex items-center gap-2 mb-2">
<TrendingUp className="w-6 h-6 text-blue-600" />
<h3 className="text-2xl font-bold text-gray-900">Analytics</h3>
</div>
<p className="text-gray-600">Real-time tracking and insights</p>
</div>
{/* Animated Chart */}
<div className="flex-1 flex items-end gap-2 mb-6">
{data.map((value, index) => (
<motion.div
key={index}
initial={{ height: 0 }}
whileInView={{ height: `${value}%` }}
viewport={{ once: true }}
transition={{
duration: 0.8,
delay: index * 0.1,
ease: [0.34, 1.56, 0.64, 1]
}}
className="flex-1 bg-gradient-to-t from-blue-600 to-blue-400 rounded-t-lg relative group-hover:from-blue-500 group-hover:to-blue-300 transition-all"
>
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
transition={{ delay: 1 + index * 0.1 }}
className="absolute -top-6 left-1/2 -translate-x-1/2 text-xs font-bold text-blue-700 whitespace-nowrap"
>
{value}
</motion.div>
</motion.div>
))}
</div>
{/* Stats */}
<div className="grid grid-cols-2 gap-3">
<div className="bg-white/80 backdrop-blur-sm rounded-lg p-3">
<div className="flex items-center gap-2 text-sm text-gray-600 mb-1">
<Eye className="w-4 h-4" />
<span>Total Scans</span>
</div>
<motion.div
initial={{ opacity: 0, scale: 0.5 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ delay: 1.2 }}
className="text-2xl font-bold text-gray-900"
>
12,547
</motion.div>
</div>
<div className="bg-white/80 backdrop-blur-sm rounded-lg p-3">
<div className="flex items-center gap-2 text-sm text-gray-600 mb-1">
<MousePointer className="w-4 h-4" />
<span>Click Rate</span>
</div>
<motion.div
initial={{ opacity: 0, scale: 0.5 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ delay: 1.4 }}
className="text-2xl font-bold text-green-600"
>
87%
</motion.div>
</div>
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,111 @@
'use client';
import React, { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
import { QRCodeSVG } from 'qrcode.react';
import { FileSpreadsheet, ArrowRight } from 'lucide-react';
export const FeatureBulkDemo: React.FC = () => {
const [showQRs, setShowQRs] = useState(false);
const [hasAnimated, setHasAnimated] = useState(false);
useEffect(() => {
if (hasAnimated) return;
const timer = setTimeout(() => {
setShowQRs(true);
setHasAnimated(true);
}, 500);
return () => clearTimeout(timer);
}, [hasAnimated]);
const qrCodes = [
{ id: 1, url: 'product-1', delay: 0 },
{ id: 2, url: 'product-2', delay: 0.1 },
{ id: 3, url: 'product-3', delay: 0.2 },
{ id: 4, url: 'product-4', delay: 0.3 },
{ id: 5, url: 'product-5', delay: 0.4 },
{ id: 6, url: 'product-6', delay: 0.5 },
];
return (
<div className="relative h-full min-h-[300px] bg-gradient-to-br from-emerald-50 to-teal-100 rounded-2xl p-8 overflow-hidden">
<div className="relative z-10 h-full flex flex-col">
{/* Header */}
<div className="mb-6">
<div className="flex items-center gap-2 mb-2">
<FileSpreadsheet className="w-6 h-6 text-emerald-600" />
<h3 className="text-2xl font-bold text-gray-900">Bulk Creation</h3>
</div>
<p className="text-gray-600">Generate hundreds at once</p>
</div>
{/* Animation */}
<div className="flex-1 flex items-center justify-center gap-8">
{/* CSV Icon */}
<motion.div
animate={{
scale: showQRs ? 0.8 : 1,
opacity: showQRs ? 0.5 : 1,
}}
transition={{ duration: 0.5 }}
className="flex flex-col items-center"
>
<div className="w-20 h-24 bg-white rounded-lg shadow-md flex items-center justify-center border-2 border-emerald-200">
<FileSpreadsheet className="w-10 h-10 text-emerald-600" />
</div>
<p className="text-xs text-gray-600 mt-2 font-medium">products.csv</p>
</motion.div>
{/* Arrow */}
<motion.div
animate={{
x: showQRs ? [0, 10, 0] : 0,
opacity: showQRs ? 1 : 0.3,
}}
transition={{ duration: 0.5, repeat: showQRs ? Infinity : 0, repeatDelay: 1 }}
>
<ArrowRight className="w-8 h-8 text-emerald-600" />
</motion.div>
{/* QR Codes Grid */}
<div className="grid grid-cols-3 gap-2">
{qrCodes.map((qr) => (
<motion.div
key={qr.id}
initial={{ scale: 0, opacity: 0 }}
animate={{
scale: showQRs ? 1 : 0,
opacity: showQRs ? 1 : 0,
}}
transition={{
duration: 0.4,
delay: showQRs ? qr.delay : 0,
ease: [0.34, 1.56, 0.64, 1]
}}
className="p-1.5 bg-white rounded shadow-sm"
>
<QRCodeSVG
value={`https://qrmaster.net/${qr.url}`}
size={32}
level="L"
/>
</motion.div>
))}
</div>
</div>
{/* Counter */}
<motion.div
animate={{ opacity: showQRs ? 1 : 0 }}
className="text-center"
>
<p className="text-sm font-semibold text-emerald-700">
6 QR codes generated
</p>
</motion.div>
</div>
</div>
);
};

View File

@@ -0,0 +1,93 @@
'use client';
import React, { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { QRCodeSVG } from 'qrcode.react';
import { Palette } from 'lucide-react';
const colorPresets = [
{ fg: '#000000', bg: '#FFFFFF' },
{ fg: '#0ea5e9', bg: '#e0f2fe' },
{ fg: '#8b5cf6', bg: '#f3e8ff' },
{ fg: '#f59e0b', bg: '#fef3c7' },
];
export const FeatureCustomizationDemo: React.FC = () => {
const [activeIndex, setActiveIndex] = useState(0);
const [hasAnimated, setHasAnimated] = useState(false);
useEffect(() => {
if (hasAnimated) return;
const interval = setInterval(() => {
setActiveIndex((prev) => {
const next = prev + 1;
if (next >= colorPresets.length) {
clearInterval(interval);
setHasAnimated(true);
return 0; // Reset to first
}
return next;
});
}, 1500);
return () => clearInterval(interval);
}, [hasAnimated]);
const currentPreset = colorPresets[activeIndex];
return (
<div className="relative h-full min-h-[300px] bg-gradient-to-br from-purple-50 to-pink-100 rounded-2xl p-8 overflow-hidden">
<div className="relative z-10 h-full flex flex-col">
{/* Header */}
<div className="mb-6">
<div className="flex items-center gap-2 mb-2">
<Palette className="w-6 h-6 text-purple-600" />
<h3 className="text-2xl font-bold text-gray-900">Customization</h3>
</div>
<p className="text-gray-600">Brand your QR codes</p>
</div>
{/* QR Code with Morphing */}
<div className="flex-1 flex items-center justify-center">
<AnimatePresence mode="wait">
<motion.div
key={activeIndex}
initial={{ scale: 0.8, rotate: -10, opacity: 0 }}
animate={{ scale: 1, rotate: 0, opacity: 1 }}
exit={{ scale: 0.8, rotate: 10, opacity: 0 }}
transition={{ duration: 0.5, ease: [0.34, 1.56, 0.64, 1] }}
className="p-6 bg-white rounded-2xl shadow-lg"
>
<QRCodeSVG
value="https://qrmaster.net"
size={140}
fgColor={currentPreset.fg}
bgColor={currentPreset.bg}
level="M"
/>
</motion.div>
</AnimatePresence>
</div>
{/* Color Dots Indicator */}
<div className="flex justify-center gap-2 mt-6">
{colorPresets.map((preset, index) => (
<motion.button
key={index}
onClick={() => setActiveIndex(index)}
className={`w-3 h-3 rounded-full transition-all ${
index === activeIndex ? 'scale-125' : 'scale-100 opacity-50'
}`}
style={{
background: `linear-gradient(135deg, ${preset.fg}, ${preset.bg})`
}}
whileHover={{ scale: 1.3 }}
whileTap={{ scale: 0.9 }}
/>
))}
</div>
</div>
</div>
);
};

View File

@@ -2,83 +2,109 @@
import React from 'react';
import { motion } from 'framer-motion';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card';
import { BentoGrid, BentoItem } from './BentoGrid';
import { FeatureAnalyticsDemo } from './FeatureAnalyticsDemo';
import { FeatureCustomizationDemo } from './FeatureCustomizationDemo';
import { FeatureBulkDemo } from './FeatureBulkDemo';
import { Infinity as InfinityIcon, Clock, Shield } from 'lucide-react';
interface FeaturesProps {
t: any; // i18n translation function
}
export const Features: React.FC<FeaturesProps> = ({ t }) => {
const features = [
{
key: 'analytics',
icon: (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
),
color: 'text-blue-600 bg-blue-100',
},
{
key: 'customization',
icon: (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" />
</svg>
),
color: 'text-purple-600 bg-purple-100',
},
{
key: 'unlimited',
icon: (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
),
color: 'text-green-600 bg-green-100',
},
];
return (
<section className="py-16 bg-gray-50">
<section className="py-20 bg-gray-50">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl">
{/* Section Header */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="text-center mb-12"
className="text-center mb-16"
>
<h2 className="text-3xl lg:text-4xl font-bold text-gray-900 mb-4">
<h2 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-4">
{t.features.title}
</h2>
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
Everything you need to create, manage, and track QR codes at scale
</p>
</motion.div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-6xl mx-auto">
{features.map((feature, index) => (
<motion.div
key={feature.key}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
>
<Card hover className="h-full border-gray-100 hover:border-primary-100 hover:shadow-lg transition-all">
<CardHeader>
<div className={`w-12 h-12 rounded-lg ${feature.color} flex items-center justify-center mb-4`}>
{feature.icon}
</div>
<CardTitle>{t.features[feature.key].title}</CardTitle>
</CardHeader>
<CardContent>
<p className="text-gray-600">
{t.features[feature.key].description}
{/* Bento Grid */}
<BentoGrid>
{/* Analytics - Large */}
<BentoItem size="large">
<FeatureAnalyticsDemo />
</BentoItem>
{/* Customization - Medium */}
<BentoItem size="medium">
<FeatureCustomizationDemo />
</BentoItem>
{/* Bulk Creation - Medium */}
<BentoItem size="medium">
<FeatureBulkDemo />
</BentoItem>
{/* Unlimited - Small */}
<BentoItem size="small">
<div className="h-full min-h-[200px] bg-gradient-to-br from-indigo-50 to-indigo-100 rounded-2xl p-6 flex flex-col justify-between">
<div>
<InfinityIcon className="w-8 h-8 text-indigo-600 mb-3" />
<h3 className="text-xl font-bold text-gray-900 mb-2">
{t.features.unlimited.title}
</h3>
<p className="text-sm text-gray-600">
{t.features.unlimited.description}
</p>
</CardContent>
</Card>
</motion.div>
))}
</div>
<div className="self-end">
<InfinityIcon className="w-16 h-16 text-indigo-200" />
</div>
</div>
</BentoItem>
{/* Reliable - Small */}
<BentoItem size="small">
<div className="h-full min-h-[200px] bg-gradient-to-br from-green-50 to-green-100 rounded-2xl p-6 flex flex-col justify-between">
<div>
<Clock className="w-8 h-8 text-green-600 mb-3" />
<h3 className="text-xl font-bold text-gray-900 mb-2">
24/7 Reliable
</h3>
<p className="text-sm text-gray-600">
99.9% uptime guarantee with enterprise-grade infrastructure
</p>
</div>
<div className="self-end">
<div className="text-4xl font-bold text-green-600">
99.9<span className="text-2xl">%</span>
</div>
</div>
</div>
</BentoItem>
{/* Secure - Small */}
<BentoItem size="small">
<div className="h-full min-h-[200px] bg-gradient-to-br from-amber-50 to-amber-100 rounded-2xl p-6 flex flex-col justify-between">
<div>
<Shield className="w-8 h-8 text-amber-600 mb-3" />
<h3 className="text-xl font-bold text-gray-900 mb-2">
Enterprise Security
</h3>
<p className="text-sm text-gray-600">
Bank-level encryption and GDPR compliant data handling
</p>
</div>
<div className="self-end">
<Shield className="w-16 h-16 text-amber-200" />
</div>
</div>
</BentoItem>
</BentoGrid>
</div>
</section>
);

View File

@@ -22,8 +22,7 @@ import {
MapPin,
CreditCard,
Video,
Users,
Barcode
Users
} from 'lucide-react';
const TOOLS = [
@@ -178,14 +177,6 @@ const TOOLS = [
href: '/tools/teams-qr-code',
color: 'text-violet-500',
bg: 'bg-violet-50'
},
{
icon: Barcode,
name: 'Barcode',
description: 'Create standard barcodes',
href: '/tools/barcode-generator',
color: 'text-slate-900',
bg: 'bg-slate-100'
}
];

View File

@@ -4,152 +4,156 @@ import React from 'react';
import Link from 'next/link';
import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
import { Card } from '@/components/ui/Card';
import { motion } from 'framer-motion';
import { Globe, User, MapPin, Phone, CheckCircle2, ArrowRight } from 'lucide-react';
import { CheckCircle2, ArrowRight, Zap } from 'lucide-react';
import { AnimatedBackground } from './AnimatedBackground';
import { QRTypesShowcase } from './QRTypesShowcase';
import { PhoneMockup } from './PhoneMockup';
import { StatsCounter, defaultStats } from './StatsCounter';
interface HeroProps {
t: any; // i18n translation function
}
export const Hero: React.FC<HeroProps> = ({ t }) => {
const templateCards = [
{ title: 'URL/Website', color: 'bg-blue-500/10 text-blue-600', icon: Globe },
{ title: 'Contact Card', color: 'bg-purple-500/10 text-purple-600', icon: User },
{ title: 'Location', color: 'bg-green-500/10 text-green-600', icon: MapPin },
{ title: 'Phone Number', color: 'bg-pink-500/10 text-pink-600', icon: Phone },
];
const containerjs = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: {
staggerChildren: 0.1
}
}
};
const itemjs = {
hidden: { opacity: 0, y: 20 },
show: { opacity: 1, y: 0 }
};
return (
<section className="relative overflow-hidden bg-gradient-to-br from-blue-50 via-white to-purple-50 pt-12 pb-20">
{/* Animated Background Orbs */}
<div className="absolute inset-0 overflow-hidden pointer-events-none">
{/* Orb 1 - Blue (top-left) */}
<div className="absolute -top-24 -left-24 w-96 h-96 bg-blue-400/30 rounded-full blur-3xl animate-blob" />
{/* Orb 2 - Purple (top-right) */}
<div className="absolute -top-12 -right-12 w-96 h-96 bg-purple-400/30 rounded-full blur-3xl animate-blob animation-delay-2000" />
{/* Orb 3 - Pink (bottom-left) */}
<div className="absolute -bottom-24 -left-12 w-96 h-96 bg-pink-400/20 rounded-full blur-3xl animate-blob animation-delay-4000" />
{/* Orb 4 - Cyan (center-right) */}
<div className="absolute top-1/2 -right-24 w-80 h-80 bg-cyan-400/20 rounded-full blur-3xl animate-blob animation-delay-6000" />
</div>
<section className="relative overflow-hidden pt-20 pb-32 min-h-[90vh] flex items-center">
{/* Modern Animated Background */}
<AnimatedBackground />
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl relative z-10">
<div className="grid lg:grid-cols-2 gap-12 items-center">
{/* Left Content */}
<div className="space-y-8">
<Badge variant="info" className="inline-flex items-center space-x-2">
<span>{t.hero.badge}</span>
</Badge>
{/* Main Content Grid */}
<div className="grid lg:grid-cols-2 gap-12 lg:gap-16 items-center">
{/* Left: Content */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="space-y-8 text-center lg:text-left"
>
{/* Badge */}
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: 0.1, duration: 0.3 }}
className="flex justify-center lg:justify-start"
>
<Badge variant="info" className="inline-flex items-center space-x-2 px-4 py-2 shadow-sm">
<Zap className="w-4 h-4" />
<span className="font-semibold">{t.hero.badge}</span>
</Badge>
</motion.div>
{/* Headline */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2, duration: 0.4 }}
className="space-y-6"
>
<h2 className="text-5xl lg:text-6xl font-bold text-gray-900 leading-tight">
<h2 className="text-5xl sm:text-6xl lg:text-7xl font-bold text-gray-900 leading-tight">
{t.hero.title}
</h2>
<p className="text-xl text-gray-600 leading-relaxed max-w-2xl">
<p className="text-xl lg:text-2xl text-gray-600 leading-relaxed max-w-2xl mx-auto lg:mx-0">
{t.hero.subtitle}
</p>
</motion.div>
<div className="space-y-3 pt-2">
{/* Feature List */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.3, duration: 0.4 }}
className="space-y-4 pt-4"
>
{t.hero.features.map((feature: string, index: number) => (
<motion.div
key={index}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.2 + (index * 0.1) }}
className="flex items-center space-x-3"
transition={{ delay: 0.4 + index * 0.08, duration: 0.3 }}
className="flex items-center space-x-3 justify-center lg:justify-start"
>
<div className="flex-shrink-0 w-6 h-6 bg-emerald-100 rounded-full flex items-center justify-center">
<CheckCircle2 className="w-4 h-4 text-emerald-600" />
<div className="flex-shrink-0 w-7 h-7 rounded-full bg-gradient-to-br from-emerald-400 to-emerald-600 flex items-center justify-center shadow-sm">
<CheckCircle2 className="w-4 h-4 text-white" />
</div>
<span className="text-gray-700 font-medium">{feature}</span>
<span className="text-gray-700 font-medium text-lg">{feature}</span>
</motion.div>
))}
</div>
</motion.div>
{/* CTAs */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5 }}
className="flex flex-col sm:flex-row gap-4 pt-4"
transition={{ delay: 0.6, duration: 0.3 }}
className="flex flex-col sm:flex-row gap-4 pt-6 justify-center lg:justify-start"
>
<Link href="/signup">
<Button size="lg" className="text-lg px-8 py-6 w-full sm:w-auto shadow-lg shadow-blue-500/25 hover:shadow-blue-500/40 transition-all duration-300">
{t.hero.cta_primary}
<Button
size="lg"
className="text-lg px-10 py-7 w-full sm:w-auto shadow-primary-lg hover:shadow-primary-lg hover:scale-105 transition-all duration-300 group"
>
<span>{t.hero.cta_primary}</span>
<ArrowRight className="ml-2 w-5 h-5 group-hover:translate-x-1 transition-transform" />
</Button>
</Link>
<Link href="/#pricing">
<Button variant="outline" size="lg" className="text-lg px-8 py-6 w-full sm:w-auto backdrop-blur-sm bg-white/50 border-gray-200 hover:bg-white/80 transition-all duration-300">
<Button
variant="outline"
size="lg"
className="text-lg px-10 py-7 w-full sm:w-auto glass border-gray-300 hover:glass-strong hover:scale-105 transition-all duration-300"
>
{t.hero.cta_secondary}
</Button>
</Link>
</motion.div>
</div>
{/* Right Preview Widget */}
<div className="relative">
{/* Trust Indicator */}
<motion.div
variants={containerjs}
initial="hidden"
animate="show"
className="grid grid-cols-2 gap-4"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.8, duration: 0.3 }}
className="flex items-center gap-2 text-sm text-gray-500 justify-center lg:justify-start"
>
{templateCards.map((card, index) => (
<motion.div key={index} variants={itemjs}>
<Card className={`backdrop-blur-xl bg-white/70 border-white/50 shadow-xl shadow-gray-200/50 p-6 text-center hover:scale-105 transition-all duration-300 group cursor-pointer`}>
<div className={`w-12 h-12 mx-auto mb-4 rounded-xl ${card.color} flex items-center justify-center group-hover:scale-110 transition-transform duration-300`}>
<card.icon className="w-6 h-6" />
</div>
<p className="font-semibold text-gray-800 group-hover:text-gray-900">{card.title}</p>
</Card>
</motion.div>
<div className="flex -space-x-2">
{[1, 2, 3].map((i) => (
<div
key={i}
className="w-8 h-8 rounded-full bg-gradient-to-br from-blue-400 to-purple-400 border-2 border-white"
/>
))}
</div>
<span>Trusted by 25,000+ professionals worldwide</span>
</motion.div>
</motion.div>
{/* Floating Badge */}
{/* Right: QR Types Showcase + Phone */}
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: 0.8 }}
className="absolute -top-4 -right-4 bg-gradient-to-r from-success-500 to-emerald-500 text-white px-4 py-2 rounded-full text-sm font-semibold shadow-lg shadow-success-500/30 flex items-center gap-2"
initial={{ opacity: 0, x: 50 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.3, duration: 0.5 }}
className="relative space-y-8"
>
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-white opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-white"></span>
</span>
{t.hero.engagement_badge}
{/* QR Types Grid */}
<QRTypesShowcase />
{/* Phone Mockup with Auto-Rotation */}
<div className="flex justify-center">
<PhoneMockup autoRotate={true} />
</div>
</motion.div>
</div>
{/* Stats Counter - Subtiler */}
<div className="mt-20">
<StatsCounter stats={defaultStats} />
</div>
</div>
{/* Smooth Gradient Fade Transition */}
<div className="absolute bottom-0 left-0 w-full h-32 bg-gradient-to-b from-transparent to-gray-50 pointer-events-none" />
</section >
{/* Smooth Gradient Fade Transition to next section */}
<div className="absolute bottom-0 left-0 w-full h-32 bg-gradient-to-b from-transparent to-white pointer-events-none" />
</section>
);
};

View File

@@ -0,0 +1,201 @@
'use client';
import React, { useState, useCallback } from 'react';
import { QRCodeSVG } from 'qrcode.react';
import { motion, AnimatePresence } from 'framer-motion';
import { Input } from '@/components/ui/Input';
import { Sparkles } from 'lucide-react';
interface ColorPreset {
name: string;
fg: string;
bg: string;
gradient?: string;
}
const colorPresets: ColorPreset[] = [
{ name: 'Classic', fg: '#000000', bg: '#FFFFFF' },
{ name: 'Ocean', fg: '#0ea5e9', bg: '#e0f2fe' },
{ name: 'Forest', fg: '#059669', bg: '#d1fae5' },
{ name: 'Sunset', fg: '#f59e0b', bg: '#fef3c7' },
{ name: 'Purple', fg: '#8b5cf6', bg: '#f3e8ff' },
{ name: 'Pink', fg: '#ec4899', bg: '#fce7f3' },
];
export const HeroQRInteractive: React.FC = () => {
const [url, setUrl] = useState('https://qrmaster.net');
const [foreground, setForeground] = useState('#000000');
const [background, setBackground] = useState('#FFFFFF');
const [selectedPreset, setSelectedPreset] = useState(0);
const handlePresetClick = useCallback((preset: ColorPreset, index: number) => {
setForeground(preset.fg);
setBackground(preset.bg);
setSelectedPreset(index);
}, []);
const handleUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUrl(e.target.value || 'https://qrmaster.net');
};
return (
<div className="relative">
{/* Main QR Container */}
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.6, ease: [0.34, 1.56, 0.64, 1] }}
className="relative"
>
{/* Glass card container */}
<div className="glass-strong rounded-3xl p-8 lg:p-12 shadow-elevation-4 relative overflow-hidden">
{/* Decorative corner accents */}
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-primary-vibrant opacity-10 blur-3xl" />
<div className="absolute bottom-0 left-0 w-32 h-32 bg-gradient-accent opacity-10 blur-3xl" />
{/* QR Code Display */}
<div className="flex justify-center mb-8">
<motion.div
key={`${foreground}-${background}`}
initial={{ scale: 0.95, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ duration: 0.3 }}
className="relative group"
>
{/* QR Code with hover effect */}
<div className="relative p-6 bg-white rounded-2xl shadow-lg group-hover:shadow-xl transition-shadow duration-300">
<AnimatePresence mode="wait">
<motion.div
key={url}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
>
<QRCodeSVG
value={url}
size={280}
fgColor={foreground}
bgColor={background}
level="H"
includeMargin={false}
/>
</motion.div>
</AnimatePresence>
{/* Scan indicator */}
<motion.div
className="absolute inset-0 border-2 border-primary-500/30 rounded-2xl"
initial={{ scale: 1, opacity: 0 }}
animate={{
scale: [1, 1.05, 1],
opacity: [0, 0.5, 0],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: 'easeInOut',
}}
/>
</div>
{/* Live indicator */}
<motion.div
className="absolute -top-3 -right-3 bg-gradient-to-r from-success-500 to-emerald-500 text-white px-3 py-1.5 rounded-full text-xs font-semibold shadow-lg flex items-center gap-2"
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ delay: 0.5, type: 'spring' }}
>
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-white opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-white"></span>
</span>
Live Preview
</motion.div>
</motion.div>
</div>
{/* Input Field */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3, duration: 0.4 }}
className="mb-6"
>
<div className="relative">
<Input
value={url}
onChange={handleUrlChange}
placeholder="Enter your URL..."
className="text-center text-lg font-medium pr-12 bg-white/80 backdrop-blur-sm border-2 border-gray-200 focus:border-primary-400 transition-colors"
/>
<Sparkles className="absolute right-4 top-1/2 -translate-y-1/2 w-5 h-5 text-primary-500" />
</div>
</motion.div>
{/* Color Presets */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.4, duration: 0.4 }}
>
<p className="text-center text-sm font-medium text-gray-600 mb-3">
Choose a style:
</p>
<div className="flex justify-center gap-2 flex-wrap">
{colorPresets.map((preset, index) => (
<motion.button
key={preset.name}
onClick={() => handlePresetClick(preset, index)}
className={`relative px-4 py-2 rounded-xl font-medium text-sm transition-all ${
selectedPreset === index
? 'bg-white shadow-md ring-2 ring-primary-500 ring-offset-2'
: 'bg-white/60 hover:bg-white hover:shadow-sm'
}`}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
<div className="flex items-center gap-2">
<div
className="w-4 h-4 rounded-full border-2 border-gray-200"
style={{
background: `linear-gradient(135deg, ${preset.fg} 0%, ${preset.bg} 100%)`,
}}
/>
<span style={{ color: preset.fg }}>{preset.name}</span>
</div>
</motion.button>
))}
</div>
</motion.div>
</div>
</motion.div>
{/* Decorative floating elements */}
<motion.div
className="absolute -top-8 -left-8 w-16 h-16 bg-blue-400/20 rounded-full blur-xl"
animate={{
y: [-10, 10, -10],
scale: [1, 1.1, 1],
}}
transition={{
duration: 4,
repeat: Infinity,
ease: 'easeInOut',
}}
/>
<motion.div
className="absolute -bottom-8 -right-8 w-20 h-20 bg-purple-400/20 rounded-full blur-xl"
animate={{
y: [10, -10, 10],
scale: [1.1, 1, 1.1],
}}
transition={{
duration: 5,
repeat: Infinity,
ease: 'easeInOut',
}}
/>
</div>
);
};

View File

@@ -2,30 +2,48 @@
import React, { useState } from 'react';
import { QRCodeSVG } from 'qrcode.react';
import { motion } from 'framer-motion';
import { motion, AnimatePresence } from 'framer-motion';
import { Card } from '@/components/ui/Card';
import { Input } from '@/components/ui/Input';
import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
import { calculateContrast } from '@/lib/utils';
import AdBanner from '@/components/ads/AdBanner';
import { PresetGallery, qrPresets, type QRPreset } from './PresetGallery';
import { PhoneMockup } from './PhoneMockup';
import { Download, Smartphone, Palette, Settings2, Sparkles } from 'lucide-react';
interface InstantGeneratorProps {
t: any; // i18n translation function
}
type TabType = 'basic' | 'presets' | 'advanced';
export const InstantGenerator: React.FC<InstantGeneratorProps> = ({ t }) => {
const [url, setUrl] = useState('https://example.com');
const [activeTab, setActiveTab] = useState<TabType>('basic');
const [url, setUrl] = useState('https://qrmaster.net');
const [foregroundColor, setForegroundColor] = useState('#000000');
const [backgroundColor, setBackgroundColor] = useState('#FFFFFF');
const [selectedPreset, setSelectedPreset] = useState('bold-1');
const [cornerStyle, setCornerStyle] = useState('square');
const [size, setSize] = useState(200);
const [size, setSize] = useState(256);
const contrast = calculateContrast(foregroundColor, backgroundColor);
const hasGoodContrast = contrast >= 4.5;
const tabs = [
{ id: 'basic' as TabType, label: 'Basic', icon: Sparkles },
{ id: 'presets' as TabType, label: 'Presets', icon: Palette },
{ id: 'advanced' as TabType, label: 'Advanced', icon: Settings2 },
];
const handlePresetSelect = (preset: QRPreset) => {
setForegroundColor(preset.fg);
setBackgroundColor(preset.bg);
setSelectedPreset(preset.id);
};
const downloadQR = (format: 'svg' | 'png') => {
const svg = document.querySelector('#instant-qr-preview svg');
const svg = document.querySelector('#generator-qr-preview svg');
if (!svg || !url) return;
if (format === 'svg') {
@@ -40,13 +58,12 @@ export const InstantGenerator: React.FC<InstantGeneratorProps> = ({ t }) => {
document.body.removeChild(a);
URL.revokeObjectURL(downloadUrl);
} else {
// Convert SVG to PNG using Canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
const svgData = new XMLSerializer().serializeToString(svg);
const blob = new Blob([svgData], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
const blobUrl = URL.createObjectURL(blob);
img.onload = () => {
canvas.width = size;
@@ -56,9 +73,9 @@ export const InstantGenerator: React.FC<InstantGeneratorProps> = ({ t }) => {
ctx.fillRect(0, 0, size, size);
ctx.drawImage(img, 0, 0, size, size);
}
canvas.toBlob((blob) => {
if (blob) {
const downloadUrl = URL.createObjectURL(blob);
canvas.toBlob((canvasBlob) => {
if (canvasBlob) {
const downloadUrl = URL.createObjectURL(canvasBlob);
const a = document.createElement('a');
a.href = downloadUrl;
a.download = 'qrcode.png';
@@ -68,19 +85,16 @@ export const InstantGenerator: React.FC<InstantGeneratorProps> = ({ t }) => {
URL.revokeObjectURL(downloadUrl);
}
});
URL.revokeObjectURL(url);
URL.revokeObjectURL(blobUrl);
};
img.src = url;
img.src = blobUrl;
}
};
return (
<section className="pt-16 pb-32 bg-gray-50 border-t border-gray-100 relative">
<div
className="absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-r from-blue-50 to-white pointer-events-none"
style={{ maskImage: 'linear-gradient(to bottom, transparent, black)', WebkitMaskImage: 'linear-gradient(to bottom, transparent, black)' }}
/>
<section className="py-20 bg-gradient-to-b from-white to-gray-50">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl">
{/* Section Header */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
@@ -88,83 +102,141 @@ export const InstantGenerator: React.FC<InstantGeneratorProps> = ({ t }) => {
transition={{ duration: 0.5 }}
className="text-center mb-12"
>
<h2 className="text-3xl lg:text-4xl font-bold text-gray-900 mb-4">
<Badge variant="info" className="mb-4">
<Sparkles className="w-4 h-4 mr-2" />
Try It Now
</Badge>
<h2 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-4">
{t.generator.title}
</h2>
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
Create and customize your QR code in seconds. No signup required.
</p>
</motion.div>
<div className="grid lg:grid-cols-2 gap-12 max-w-6xl mx-auto">
{/* Left Form */}
<div className="grid lg:grid-cols-2 gap-8 lg:gap-12 max-w-6xl mx-auto">
{/* Left: Controls */}
<motion.div
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
>
<Card className="space-y-6 shadow-xl shadow-gray-200/50 border-gray-100">
<Card className="shadow-elevation-3 border-gray-100">
{/* Tab Navigation */}
<div className="flex gap-2 mb-6 p-1 bg-gray-100 rounded-xl">
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm transition-all ${
activeTab === tab.id
? 'bg-white text-primary-600 shadow-sm'
: 'text-gray-600 hover:text-gray-900'
}`}
>
<tab.icon className="w-4 h-4" />
{tab.label}
</button>
))}
</div>
{/* Tab Content */}
<AnimatePresence mode="wait">
<motion.div
key={activeTab}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
className="space-y-6"
>
{/* Basic Tab */}
{activeTab === 'basic' && (
<>
<Input
label="URL"
label="Your URL"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder={t.generator.url_placeholder}
className="transition-all focus:ring-2 focus:ring-primary-500/20"
placeholder="https://your-website.com"
/>
<div className="grid grid-cols-2 gap-4">
<div>
<label htmlFor="foreground-color" className="block text-sm font-medium text-gray-700 mb-2">
{t.generator.foreground}
<label className="block text-sm font-medium text-gray-700 mb-2">
Foreground
</label>
<div className="flex items-center space-x-2">
<input
id="foreground-color"
type="color"
value={foregroundColor}
onChange={(e) => setForegroundColor(e.target.value)}
className="w-14 h-12 rounded border border-gray-300 cursor-pointer"
aria-label="Foreground color picker"
className="w-14 h-12 rounded-lg border border-gray-300 cursor-pointer"
/>
<Input
id="foreground-color-text"
value={foregroundColor}
onChange={(e) => setForegroundColor(e.target.value)}
className="flex-1"
aria-label="Foreground color hex value"
className="flex-1 font-mono text-sm"
/>
</div>
</div>
<div>
<label htmlFor="background-color" className="block text-sm font-medium text-gray-700 mb-2">
{t.generator.background}
<label className="block text-sm font-medium text-gray-700 mb-2">
Background
</label>
<div className="flex items-center space-x-2">
<input
id="background-color"
type="color"
value={backgroundColor}
onChange={(e) => setBackgroundColor(e.target.value)}
className="w-14 h-12 rounded border border-gray-300 cursor-pointer"
aria-label="Background color picker"
className="w-14 h-12 rounded-lg border border-gray-300 cursor-pointer"
/>
<Input
id="background-color-text"
value={backgroundColor}
onChange={(e) => setBackgroundColor(e.target.value)}
className="flex-1"
aria-label="Background color hex value"
className="flex-1 font-mono text-sm"
/>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="flex items-center justify-between pt-2">
<Badge variant={hasGoodContrast ? 'success' : 'warning'}>
{hasGoodContrast ? '✓ Good contrast' : '⚠ Low contrast'}
</Badge>
<span className="text-sm text-gray-500">
Ratio: {contrast.toFixed(1)}:1
</span>
</div>
</>
)}
{/* Presets Tab */}
{activeTab === 'presets' && (
<>
<Input
label="Your URL"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="https://your-website.com"
/>
<PresetGallery
selectedPreset={selectedPreset}
onPresetSelect={handlePresetSelect}
url={url}
/>
</>
)}
{/* Advanced Tab */}
{activeTab === 'advanced' && (
<>
<div>
<label htmlFor="corner-style" className="block text-sm font-medium text-gray-700 mb-2">
{t.generator.corners}
<label className="block text-sm font-medium text-gray-700 mb-2">
Corner Style
</label>
<select
id="corner-style"
value={cornerStyle}
onChange={(e) => setCornerStyle(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
@@ -175,106 +247,98 @@ export const InstantGenerator: React.FC<InstantGeneratorProps> = ({ t }) => {
</div>
<div>
<label htmlFor="qr-size" className="block text-sm font-medium text-gray-700 mb-2">
{t.generator.size}
<label className="block text-sm font-medium text-gray-700 mb-2">
Size: {size}px
</label>
<input
id="qr-size"
type="range"
min="100"
max="400"
min="128"
max="512"
step="32"
value={size}
onChange={(e) => setSize(Number(e.target.value))}
className="w-full accent-primary-600"
aria-label={`QR code size: ${size} pixels`}
/>
<div className="text-sm text-gray-500 text-center mt-1" aria-hidden="true">{size}px</div>
<div className="flex justify-between text-xs text-gray-500 mt-1">
<span>128px</span>
<span>512px</span>
</div>
</div>
<div className="flex items-center justify-between">
<Badge variant={hasGoodContrast ? 'success' : 'warning'}>
{hasGoodContrast ? t.generator.contrast_good : 'Low contrast'}
</Badge>
<div className="text-sm text-gray-500">
Contrast: {contrast.toFixed(1)}:1
</div>
<div className="p-4 bg-blue-50 rounded-lg border border-blue-100">
<p className="text-sm text-blue-900">
<strong>Pro Tip:</strong> Higher resolution is better for print materials. For digital use, 256px is usually sufficient.
</p>
</div>
</>
)}
</motion.div>
</AnimatePresence>
<div className="flex space-x-3">
<Button variant="outline" className="flex-1 hover:bg-gray-50" onClick={() => downloadQR('svg')}>
{t.generator.download_svg}
{/* Download Actions */}
<div className="mt-8 pt-6 border-t border-gray-100 space-y-3">
<div className="grid grid-cols-2 gap-3">
<Button
variant="outline"
onClick={() => downloadQR('svg')}
className="hover:bg-gray-50"
>
<Download className="w-4 h-4 mr-2" />
SVG
</Button>
<Button variant="outline" className="flex-1 hover:bg-gray-50" onClick={() => downloadQR('png')}>
{t.generator.download_png}
<Button
variant="outline"
onClick={() => downloadQR('png')}
className="hover:bg-gray-50"
>
<Download className="w-4 h-4 mr-2" />
PNG
</Button>
</div>
<Button className="w-full text-lg py-6 shadow-lg shadow-primary-500/20 hover:shadow-primary-500/40 transition-all" onClick={() => window.location.href = '/login'}>
{t.generator.save_track}
<Button
className="w-full shadow-primary-md hover:shadow-primary-lg transition-all"
onClick={() => window.location.href = '/signup'}
>
<Sparkles className="w-4 h-4 mr-2" />
Save & Track Analytics
</Button>
</div>
</Card>
</motion.div>
{/* Right Preview */}
{/* Right: Preview */}
<motion.div
initial={{ opacity: 0, x: 20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.4 }}
className="flex flex-col items-center justify-center p-8 bg-gradient-to-br from-blue-50/50 to-purple-50/50 rounded-2xl border border-blue-100/50 shadow-lg shadow-blue-500/5 relative overflow-hidden backdrop-blur-sm"
className="space-y-8"
>
{/* Large QR Preview */}
<div className="flex justify-center">
<div id="generator-qr-preview" className="relative group">
<div
className={`p-8 bg-white rounded-3xl shadow-elevation-3 border-2 border-gray-100 transition-all duration-300 group-hover:shadow-elevation-4 group-hover:scale-105 ${
cornerStyle === 'rounded' ? 'overflow-hidden' : ''
}`}
>
{/* Artistic Curved Lines Background */}
<div className="absolute inset-0 opacity-[0.4]">
<svg className="h-full w-full" viewBox="0 0 100 100" preserveAspectRatio="none">
<defs>
<linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stopColor="#60a5fa" stopOpacity="0.4" />
<stop offset="100%" stopColor="#c084fc" stopOpacity="0.4" />
</linearGradient>
<linearGradient id="gradient2" x1="100%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stopColor="#818cf8" stopOpacity="0.4" />
<stop offset="100%" stopColor="#38bdf8" stopOpacity="0.4" />
</linearGradient>
</defs>
<path d="M0 100 Q 25 30 50 70 T 100 0" fill="none" stroke="url(#gradient1)" strokeWidth="0.8" className="opacity-60" />
<path d="M0 50 Q 40 80 70 30 T 100 50" fill="none" stroke="url(#gradient2)" strokeWidth="0.8" className="opacity-60" />
<path d="M0 0 Q 30 60 60 20 T 100 80" fill="none" stroke="url(#gradient1)" strokeWidth="0.6" className="opacity-40" />
</svg>
<div className="absolute inset-0 bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-15 brightness-100 contrast-150 mix-blend-overlay"></div>
</div>
{/* Decorative Orbs */}
<div className="absolute -top-20 -right-20 w-64 h-64 bg-purple-200/30 rounded-full blur-3xl animate-blob"></div>
<div className="absolute -bottom-20 -left-20 w-64 h-64 bg-blue-200/30 rounded-full blur-3xl animate-blob animation-delay-2000"></div>
<div className="text-center w-full relative z-10">
<h3 className="text-xl font-bold mb-8 text-gray-800">{t.generator.live_preview}</h3>
<div id="instant-qr-preview" className="flex justify-center mb-8 transform hover:scale-105 transition-transform duration-300">
{url ? (
<div className={`${cornerStyle === 'rounded' ? 'rounded-lg overflow-hidden' : ''} p-4 bg-white shadow-lg rounded-xl`}>
<QRCodeSVG
value={url}
size={size}
fgColor={foregroundColor}
bgColor={backgroundColor}
level="M"
level="H"
/>
</div>
) : (
<div
className="bg-gray-100 rounded-xl flex items-center justify-center text-gray-500 animate-pulse"
style={{ width: 200, height: 200 }}
>
Enter URL
</div>
)}
</div>
<div className="text-sm font-medium text-gray-600 mb-2 bg-gray-50 py-2 px-4 rounded-full inline-block">
{url || 'https://example.com'}
</div>
<div className="text-xs text-gray-400 mt-2">{t.generator.demo_note}</div>
</div>
{/* Phone Mockup Preview */}
<PhoneMockup
url={url}
foreground={foregroundColor}
background={backgroundColor}
/>
</motion.div>
</div>
</div>

View File

@@ -0,0 +1,184 @@
'use client';
import React, { useEffect, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { QRCodeSVG } from 'qrcode.react';
import { Wifi, Battery, Signal } from 'lucide-react';
import { qrTypes } from './QRTypesShowcase';
interface PhoneMockupProps {
url?: string;
foreground?: string;
background?: string;
autoRotate?: boolean;
}
export const PhoneMockup: React.FC<PhoneMockupProps> = ({
url,
foreground = '#000000',
background = '#FFFFFF',
autoRotate = false,
}) => {
const [currentTypeIndex, setCurrentTypeIndex] = useState(0);
const [isScanning, setIsScanning] = useState(false);
const [showResult, setShowResult] = useState(false);
const currentType = autoRotate ? qrTypes[currentTypeIndex] : null;
const displayUrl = url || (currentType ? currentType.data : 'https://qrmaster.net');
const displayName = currentType ? currentType.name : 'QR Master';
// Auto-rotate through QR types
useEffect(() => {
if (!autoRotate) return;
const interval = setInterval(() => {
setCurrentTypeIndex((prev) => (prev + 1) % qrTypes.length);
// Trigger scan animation
setIsScanning(true);
setTimeout(() => {
setIsScanning(false);
setShowResult(true);
setTimeout(() => {
setShowResult(false);
}, 2000);
}, 1000);
}, 5000);
return () => clearInterval(interval);
}, [autoRotate]);
const getDomain = (urlString: string) => {
try {
if (urlString.startsWith('http')) {
const urlObj = new URL(urlString);
return urlObj.hostname.replace('www.', '');
}
return urlString.substring(0, 20);
} catch {
return 'qrmaster.net';
}
};
return (
<div className="relative w-full max-w-[280px] mx-auto">
{/* Phone Frame */}
<div className="relative">
{/* Phone outline */}
<div className="relative bg-gray-900 rounded-[2.5rem] p-2.5 shadow-2xl">
{/* Screen */}
<div className="relative bg-white rounded-[2rem] overflow-hidden aspect-[9/19.5]">
{/* Status Bar */}
<div className="absolute top-0 left-0 right-0 z-20 px-6 pt-2 pb-1 bg-gradient-to-b from-black/5 to-transparent">
<div className="flex justify-between items-center">
<span className="text-xs font-semibold">9:41</span>
<div className="flex items-center gap-1">
<Signal className="w-3 h-3" />
<Wifi className="w-3 h-3" />
<Battery className="w-3 h-3" />
</div>
</div>
</div>
{/* Camera Notch */}
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-20 h-5 bg-gray-900 rounded-b-2xl z-30" />
{/* Screen Content */}
<div className="relative h-full bg-gray-50 pt-8">
<div className="px-4 h-full flex flex-col">
{/* Camera App Header */}
<div className="text-center mb-3">
<h3 className="font-semibold text-gray-900 text-sm">QR Scanner</h3>
</div>
{/* QR Code Display Area */}
<div className="flex-1 flex items-center justify-center relative">
<AnimatePresence mode="wait">
<motion.div
key={autoRotate ? currentTypeIndex : displayUrl}
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: isScanning ? 0.95 : 1, opacity: 1 }}
exit={{ scale: 0.8, opacity: 0 }}
transition={{ duration: 0.3 }}
className="relative"
>
<div className="p-3 bg-white rounded-xl shadow-lg">
<QRCodeSVG
value={displayUrl}
size={120}
fgColor={foreground}
bgColor={background}
level="M"
/>
</div>
{/* Scan Overlay */}
<AnimatePresence>
{isScanning && (
<motion.div
initial={{ y: -80, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 80, opacity: 0 }}
transition={{ duration: 0.8, ease: 'linear' }}
className="absolute inset-0 flex items-center justify-center"
>
<div className="w-full h-0.5 bg-gradient-to-r from-transparent via-primary-500 to-transparent shadow-lg" />
</motion.div>
)}
</AnimatePresence>
{/* Corner Brackets */}
<div className="absolute top-1 left-1 w-5 h-5 border-t-2 border-l-2 border-primary-500 rounded-tl-lg" />
<div className="absolute top-1 right-1 w-5 h-5 border-t-2 border-r-2 border-primary-500 rounded-tr-lg" />
<div className="absolute bottom-1 left-1 w-5 h-5 border-b-2 border-l-2 border-primary-500 rounded-bl-lg" />
<div className="absolute bottom-1 right-1 w-5 h-5 border-b-2 border-r-2 border-primary-500 rounded-br-lg" />
</motion.div>
</AnimatePresence>
</div>
{/* Result Notification */}
<AnimatePresence>
{showResult && (
<motion.div
initial={{ y: 100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 100, opacity: 0 }}
className="mb-3 p-3 bg-white rounded-xl shadow-lg border border-gray-100"
>
<div className="flex items-center gap-2">
<div className="flex-shrink-0 w-8 h-8 bg-success-100 rounded-full flex items-center justify-center">
<svg className="w-5 h-5 text-success-600" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
</div>
<div className="flex-1 min-w-0">
<p className="text-xs font-semibold text-gray-900">{displayName}</p>
<p className="text-[10px] text-gray-500 truncate">{getDomain(displayUrl)}</p>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
{/* Instruction Text */}
<div className="text-center pb-4">
<p className="text-[10px] text-gray-500">
{isScanning ? 'Scanning...' : autoRotate ? 'Auto-scanning demo' : 'Point camera at QR code'}
</p>
</div>
</div>
</div>
</div>
{/* Side buttons */}
<div className="absolute right-0 top-16 w-0.5 h-10 bg-gray-800 rounded-r" />
<div className="absolute right-0 top-28 w-0.5 h-6 bg-gray-800 rounded-r" />
<div className="absolute left-0 top-20 w-0.5 h-12 bg-gray-800 rounded-l" />
</div>
{/* Phone Shadow */}
<div className="absolute inset-0 bg-gradient-to-br from-black/20 to-black/40 rounded-[2.5rem] -z-10 blur-xl translate-y-3" />
</div>
</div>
);
};

View File

@@ -0,0 +1,135 @@
'use client';
import React from 'react';
import { motion } from 'framer-motion';
import { QRCodeSVG } from 'qrcode.react';
export interface QRPreset {
id: string;
name: string;
category: 'bold' | 'minimal' | 'gradient' | 'brand';
fg: string;
bg: string;
description?: string;
}
export const qrPresets: QRPreset[] = [
// Bold
{ id: 'bold-1', name: 'Classic Black', category: 'bold', fg: '#000000', bg: '#FFFFFF', description: 'Timeless professional' },
{ id: 'bold-2', name: 'Deep Ocean', category: 'bold', fg: '#0369a1', bg: '#e0f2fe', description: 'Trust and reliability' },
{ id: 'bold-3', name: 'Forest Green', category: 'bold', fg: '#047857', bg: '#d1fae5', description: 'Growth and nature' },
{ id: 'bold-4', name: 'Royal Purple', category: 'bold', fg: '#7c3aed', bg: '#f3e8ff', description: 'Premium and luxury' },
// Minimal
{ id: 'minimal-1', name: 'Soft Gray', category: 'minimal', fg: '#6b7280', bg: '#f9fafb', description: 'Subtle elegance' },
{ id: 'minimal-2', name: 'Gentle Blue', category: 'minimal', fg: '#60a5fa', bg: '#eff6ff', description: 'Calm and clean' },
{ id: 'minimal-3', name: 'Muted Green', category: 'minimal', fg: '#34d399', bg: '#ecfdf5', description: 'Fresh and light' },
{ id: 'minimal-4', name: 'Soft Pink', category: 'minimal', fg: '#f472b6', bg: '#fdf2f8', description: 'Friendly warmth' },
// Gradient-inspired
{ id: 'gradient-1', name: 'Sunset', category: 'gradient', fg: '#f59e0b', bg: '#fef3c7', description: 'Warm energy' },
{ id: 'gradient-2', name: 'Cotton Candy', category: 'gradient', fg: '#ec4899', bg: '#fce7f3', description: 'Playful fun' },
{ id: 'gradient-3', name: 'Sky Blue', category: 'gradient', fg: '#0ea5e9', bg: '#e0f2fe', description: 'Open freedom' },
{ id: 'gradient-4', name: 'Mint Fresh', category: 'gradient', fg: '#14b8a6', bg: '#ccfbf1', description: 'Modern clean' },
];
interface PresetGalleryProps {
selectedPreset: string;
onPresetSelect: (preset: QRPreset) => void;
url: string;
}
export const PresetGallery: React.FC<PresetGalleryProps> = ({
selectedPreset,
onPresetSelect,
url,
}) => {
const [activeCategory, setActiveCategory] = React.useState<string>('all');
const categories = ['all', 'bold', 'minimal', 'gradient'] as const;
const filteredPresets = activeCategory === 'all'
? qrPresets
: qrPresets.filter(p => p.category === activeCategory);
return (
<div className="space-y-6">
{/* Category Filter */}
<div className="flex gap-2 flex-wrap">
{categories.map((cat) => (
<button
key={cat}
onClick={() => setActiveCategory(cat)}
className={`px-4 py-2 rounded-lg font-medium text-sm transition-all capitalize ${
activeCategory === cat
? 'bg-primary-600 text-white shadow-md'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
{cat}
</button>
))}
</div>
{/* Preset Grid */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{filteredPresets.map((preset, index) => (
<motion.button
key={preset.id}
onClick={() => onPresetSelect(preset)}
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: index * 0.05, duration: 0.3 }}
className={`group relative p-4 rounded-xl border-2 transition-all ${
selectedPreset === preset.id
? 'border-primary-500 bg-primary-50 shadow-md'
: 'border-gray-200 bg-white hover:border-primary-300 hover:shadow-sm'
}`}
>
{/* Mini QR Preview */}
<div className="flex justify-center mb-3">
<div
className="p-2 rounded-lg transition-transform group-hover:scale-105"
style={{ backgroundColor: preset.bg }}
>
<QRCodeSVG
value={url || 'https://qrmaster.net'}
size={64}
fgColor={preset.fg}
bgColor={preset.bg}
level="M"
/>
</div>
</div>
{/* Preset Info */}
<div className="text-center">
<p className="font-semibold text-sm text-gray-900 mb-1">
{preset.name}
</p>
<p className="text-xs text-gray-500 line-clamp-1">
{preset.description}
</p>
</div>
{/* Selected Indicator */}
{selectedPreset === preset.id && (
<motion.div
initial={{ scale: 0 }}
animate={{ scale: 1 }}
className="absolute top-2 right-2 w-6 h-6 bg-primary-600 rounded-full flex items-center justify-center"
>
<svg className="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
</motion.div>
)}
{/* Hover Glow */}
<div className="absolute inset-0 rounded-xl bg-gradient-primary opacity-0 group-hover:opacity-5 transition-opacity pointer-events-none" />
</motion.button>
))}
</div>
</div>
);
};

View File

@@ -31,19 +31,19 @@ export const Pricing: React.FC<PricingProps> = ({ t }) => {
];
return (
<section id="pricing" className="py-16">
<section id="pricing" className="py-20 bg-gradient-to-b from-gray-50 to-white">
<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 }}
transition={{ duration: 0.5 }}
className="text-center mb-12"
className="text-center mb-16"
>
<h2 className="text-3xl lg:text-4xl font-bold text-gray-900 mb-4">
<h2 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-4">
{t.pricing.title}
</h2>
<p className="text-xl text-gray-600">
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
{t.pricing.subtitle}
</p>
</motion.div>
@@ -63,11 +63,15 @@ export const Pricing: React.FC<PricingProps> = ({ t }) => {
className="h-full"
>
<Card
className={`h-full flex flex-col ${plan.popular
? 'border-primary-500 shadow-xl relative scale-105 z-10'
: 'border-gray-200 hover:border-gray-300 hover:shadow-lg transition-all'
className={`h-full flex flex-col relative overflow-hidden ${plan.popular
? 'border-primary-500 shadow-primary-lg scale-105 z-10 bg-gradient-to-br from-white to-blue-50'
: 'border-gray-200 hover:border-primary-200 hover:shadow-elevation-3 transition-all'
}`}
>
{/* Gradient overlay for popular */}
{plan.popular && (
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-primary-vibrant opacity-5 blur-3xl" />
)}
{plan.popular && (
<div className="absolute -top-4 left-1/2 transform -translate-x-1/2 w-full text-center">
<Badge variant="info" className="px-4 py-1.5 shadow-sm">

View File

@@ -0,0 +1,143 @@
'use client';
import React from 'react';
import { QRCodeSVG } from 'qrcode.react';
import { motion } from 'framer-motion';
import { Globe, User, Wifi, Mail, MessageSquare, Phone, MapPin, Calendar, FileText } from 'lucide-react';
export interface QRType {
id: string;
name: string;
icon: React.ComponentType<{ className?: string }>;
data: string;
color: string;
}
const qrTypes: QRType[] = [
{
id: 'url',
name: 'URL/Website',
icon: Globe,
data: 'https://qrmaster.net',
color: 'text-blue-600 bg-blue-50'
},
{
id: 'vcard',
name: 'vCard',
icon: User,
data: 'BEGIN:VCARD\nVERSION:3.0\nFN:John Doe\nEND:VCARD',
color: 'text-purple-600 bg-purple-50'
},
{
id: 'wifi',
name: 'WiFi',
icon: Wifi,
data: 'WIFI:T:WPA;S:MyNetwork;P:password;;',
color: 'text-cyan-600 bg-cyan-50'
},
{
id: 'email',
name: 'Email',
icon: Mail,
data: 'mailto:hello@qrmaster.net',
color: 'text-red-600 bg-red-50'
},
{
id: 'sms',
name: 'SMS',
icon: MessageSquare,
data: 'SMSTO:+1234567890:Hello!',
color: 'text-green-600 bg-green-50'
},
{
id: 'phone',
name: 'Phone',
icon: Phone,
data: 'tel:+1234567890',
color: 'text-emerald-600 bg-emerald-50'
},
{
id: 'location',
name: 'Location',
icon: MapPin,
data: 'geo:37.7749,-122.4194',
color: 'text-pink-600 bg-pink-50'
},
{
id: 'event',
name: 'Event',
icon: Calendar,
data: 'BEGIN:VEVENT\nSUMMARY:Meeting\nEND:VEVENT',
color: 'text-indigo-600 bg-indigo-50'
},
{
id: 'menu',
name: 'Menu/PDF',
icon: FileText,
data: 'https://qrmaster.net/menu.pdf',
color: 'text-orange-600 bg-orange-50'
}
];
interface QRTypesShowcaseProps {
onTypeSelect?: (type: QRType) => void;
}
export const QRTypesShowcase: React.FC<QRTypesShowcaseProps> = ({ onTypeSelect }) => {
return (
<div className="space-y-8">
{/* Grid of QR Types */}
<div className="grid grid-cols-3 gap-4">
{qrTypes.map((type, index) => (
<motion.button
key={type.id}
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{
delay: index * 0.05,
duration: 0.3,
ease: [0.25, 0.1, 0.25, 1]
}}
onClick={() => onTypeSelect?.(type)}
className="group relative p-4 bg-white rounded-2xl border-2 border-gray-100 hover:border-primary-200 hover:shadow-lg transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
{/* Icon Badge */}
<div className={`w-10 h-10 ${type.color} rounded-xl flex items-center justify-center mb-3 mx-auto transition-transform group-hover:scale-110`}>
<type.icon className="w-5 h-5" />
</div>
{/* QR Code */}
<div className="flex justify-center mb-2">
<div className="p-2 bg-white rounded-lg">
<QRCodeSVG
value={type.data}
size={60}
level="L"
fgColor="#000000"
bgColor="#FFFFFF"
/>
</div>
</div>
{/* Label */}
<p className="text-xs font-semibold text-gray-700 text-center group-hover:text-primary-600 transition-colors">
{type.name}
</p>
{/* Subtle glow on hover */}
<div className="absolute inset-0 rounded-2xl bg-gradient-primary opacity-0 group-hover:opacity-5 transition-opacity pointer-events-none" />
</motion.button>
))}
</div>
{/* Caption */}
<p className="text-center text-sm text-gray-500">
Support for all major QR code types
</p>
</div>
);
};
export { qrTypes };

View File

@@ -18,8 +18,7 @@ import {
Bitcoin,
CreditCard,
Video,
Users,
Barcode
Users
} from 'lucide-react';
const tools = [
@@ -30,7 +29,7 @@ const tools = [
{ name: 'Email', href: '/tools/email-qr-code', icon: Mail, color: 'text-amber-500', bgColor: 'bg-amber-50' },
{ name: 'SMS', href: '/tools/sms-qr-code', icon: MessageSquare, color: 'text-cyan-500', bgColor: 'bg-cyan-50' },
{ name: 'Instagram', href: '/tools/instagram-qr-code', icon: Instagram, color: 'text-pink-600', bgColor: 'bg-pink-50' },
{ name: 'Barcode', href: '/tools/barcode-generator', icon: Barcode, color: 'text-slate-900', bgColor: 'bg-slate-100' },
{ name: 'TikTok', href: '/tools/tiktok-qr-code', icon: Music, color: 'text-slate-800', bgColor: 'bg-slate-100' },
];
export function RelatedTools() {

View File

@@ -0,0 +1,116 @@
'use client';
import React from 'react';
import { motion, useInView, useMotionValue, useSpring } from 'framer-motion';
interface Stat {
label: string;
value: number;
suffix?: string;
prefix?: string;
decimals?: number;
}
interface StatsCounterProps {
stats: Stat[];
}
const AnimatedNumber: React.FC<{
value: number;
prefix?: string;
suffix?: string;
decimals?: number;
}> = ({ value, prefix = '', suffix = '', decimals = 0 }) => {
const ref = React.useRef<HTMLSpanElement>(null);
const isInView = useInView(ref, { once: true, margin: '-100px' });
const motionValue = useMotionValue(0);
const springValue = useSpring(motionValue, {
damping: 80,
stiffness: 60,
});
const [displayValue, setDisplayValue] = React.useState('0');
React.useEffect(() => {
if (isInView) {
motionValue.set(value);
}
}, [isInView, motionValue, value]);
React.useEffect(() => {
const unsubscribe = springValue.on('change', (latest) => {
setDisplayValue(latest.toFixed(decimals));
});
return unsubscribe;
}, [springValue, decimals]);
return (
<span ref={ref} className="gradient-text-vibrant text-3xl lg:text-4xl font-bold">
{prefix}
{displayValue}
{suffix}
</span>
);
};
export const StatsCounter: React.FC<StatsCounterProps> = ({ stats }) => {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-100px' }}
transition={{ duration: 0.5 }}
className="grid grid-cols-2 lg:grid-cols-4 gap-6 mt-16"
>
{stats.map((stat, index) => (
<motion.div
key={index}
initial={{ opacity: 0, scale: 0.95 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ delay: index * 0.1, duration: 0.3 }}
className="text-center"
>
<div className="mb-2">
<AnimatedNumber
value={stat.value}
prefix={stat.prefix}
suffix={stat.suffix}
decimals={stat.decimals}
/>
</div>
<p className="text-xs font-medium text-gray-600">{stat.label}</p>
</motion.div>
))}
</motion.div>
);
};
/**
* Default stats - can be overridden with real data
* For now using generic/aspirational numbers
*/
export const defaultStats: Stat[] = [
{
label: 'QR Codes Created',
value: 850,
suffix: 'K+',
},
{
label: 'Total Scans',
value: 12.5,
suffix: 'M+',
decimals: 1,
},
{
label: 'Active Users',
value: 25,
suffix: 'K+',
},
{
label: 'Uptime',
value: 99.9,
suffix: '%',
decimals: 1,
},
];

249
src/lib/animations.ts Normal file
View File

@@ -0,0 +1,249 @@
/**
* Centralized Animation Variants for Framer Motion
* Premium animation library for QR Master landing page
*/
import type { Variants } from 'framer-motion';
// Custom easing curves
export const easings = {
smooth: [0.25, 0.1, 0.25, 1],
snappy: [0.34, 1.56, 0.64, 1], // Bounce effect
elegant: [0.43, 0.13, 0.23, 0.96],
} as const;
// Fade & Scale animations
export const fadeIn: Variants = {
initial: { opacity: 0 },
animate: {
opacity: 1,
transition: { duration: 0.5, ease: easings.smooth }
},
};
export const scaleIn: Variants = {
initial: { opacity: 0, scale: 0.95 },
animate: {
opacity: 1,
scale: 1,
transition: { duration: 0.3, ease: easings.smooth }
},
};
export const scaleInBounce: Variants = {
initial: { opacity: 0, scale: 0.8 },
animate: {
opacity: 1,
scale: 1,
transition: { duration: 0.5, ease: easings.snappy }
},
};
// Slide animations
export const slideUp: Variants = {
initial: { opacity: 0, y: 30 },
animate: {
opacity: 1,
y: 0,
transition: { duration: 0.5, ease: easings.smooth }
},
};
export const slideUpBounce: Variants = {
initial: { opacity: 0, y: 30 },
animate: {
opacity: 1,
y: 0,
transition: { duration: 0.5, ease: easings.snappy }
},
};
export const slideDown: Variants = {
initial: { opacity: 0, y: -30 },
animate: {
opacity: 1,
y: 0,
transition: { duration: 0.5, ease: easings.smooth }
},
};
export const slideLeft: Variants = {
initial: { opacity: 0, x: 30 },
animate: {
opacity: 1,
x: 0,
transition: { duration: 0.5, ease: easings.smooth }
},
};
export const slideRight: Variants = {
initial: { opacity: 0, x: -30 },
animate: {
opacity: 1,
x: 0,
transition: { duration: 0.5, ease: easings.smooth }
},
};
// Container animations with stagger
export const staggerContainer: Variants = {
initial: {},
animate: {
transition: {
staggerChildren: 0.1,
delayChildren: 0.1,
}
},
};
export const staggerContainerFast: Variants = {
initial: {},
animate: {
transition: {
staggerChildren: 0.05,
delayChildren: 0,
}
},
};
export const staggerItem: Variants = {
initial: { opacity: 0, y: 20 },
animate: {
opacity: 1,
y: 0,
transition: { duration: 0.4, ease: easings.smooth }
},
};
// Morph animations (for QR code transformations)
export const colorMorph: Variants = {
initial: { scale: 1 },
animate: {
scale: [1, 1.02, 1],
transition: { duration: 0.4, ease: easings.smooth }
},
};
// Hover states
export const hoverScale = {
scale: 1.05,
transition: { duration: 0.2, ease: easings.smooth }
};
export const hoverScaleSmall = {
scale: 1.02,
transition: { duration: 0.2, ease: easings.smooth }
};
export const hoverLift = {
y: -4,
transition: { duration: 0.2, ease: easings.smooth }
};
export const hoverGlow = {
boxShadow: '0 8px 32px rgba(99, 102, 241, 0.25)',
transition: { duration: 0.3, ease: easings.smooth }
};
// Rotate animations
export const rotate360: Variants = {
initial: { rotate: 0 },
animate: {
rotate: 360,
transition: { duration: 0.6, ease: easings.smooth }
},
};
export const pulseGlow: Variants = {
initial: { opacity: 0.7 },
animate: {
opacity: [0.7, 1, 0.7],
transition: {
duration: 2,
repeat: Infinity,
ease: 'easeInOut'
}
},
};
// Advanced entrance animations
export const revealFromBottom: Variants = {
initial: {
opacity: 0,
y: 50,
clipPath: 'inset(100% 0 0 0)'
},
animate: {
opacity: 1,
y: 0,
clipPath: 'inset(0% 0 0 0)',
transition: {
duration: 0.7,
ease: easings.elegant
}
},
};
// Scroll-triggered animation preset
export const scrollReveal = {
initial: "initial",
whileInView: "animate",
viewport: { once: true, margin: "-100px" }
} as const;
// Interactive button animations
export const buttonTap = {
scale: 0.95,
transition: { duration: 0.1 }
};
export const buttonHover = {
scale: 1.02,
boxShadow: '0 12px 32px rgba(99, 102, 241, 0.3)',
transition: { duration: 0.2 }
};
// Float animation (for decorative elements)
export const float: Variants = {
initial: { y: 0 },
animate: {
y: [-10, 10, -10],
transition: {
duration: 4,
repeat: Infinity,
ease: 'easeInOut'
}
}
};
// Shimmer effect
export const shimmer: Variants = {
initial: { backgroundPosition: '-200% 0' },
animate: {
backgroundPosition: '200% 0',
transition: {
duration: 2,
repeat: Infinity,
ease: 'linear'
}
}
};
// Drawing animation (for borders/lines)
export const drawLine: Variants = {
initial: { pathLength: 0, opacity: 0 },
animate: {
pathLength: 1,
opacity: 1,
transition: { duration: 1.5, ease: easings.smooth }
}
};
// Count-up animation helper
export const createCountUpVariant = (from: number, to: number, duration = 2): Variants => ({
initial: { value: from },
animate: {
value: to,
transition: { duration, ease: easings.smooth }
}
});

View File

@@ -27,7 +27,7 @@ export const blogPosts: Record<string, BlogPostData> = {
dateModified: '2025-10-16T09:00:00Z',
readTime: '15 Min',
category: 'Analytics',
image: '/blog/qr-code-analytics-hero-v2.png',
image: '/blog/qr-code-analytics-hero.webp',
imageAlt: 'QR Code Analytics dashboard displaying scan metrics and user data',
author: 'QR Master Team',
authorUrl: 'https://www.qrmaster.net/about',
@@ -88,7 +88,7 @@ export const blogPosts: Record<string, BlogPostData> = {
<p>Measure downstream actions after the scan—form submissions, purchases, app downloads, or content engagement. Integrate with your CRM and marketing stack to attribute revenue to specific QR campaigns.</p>
<div class="my-8">
<img loading="lazy" src="/blog/qr-code-analytics-dashboard.png" alt="QR Code Analytics dashboard showing real-time scan data" class="rounded-lg shadow-lg w-full" />
<img src="/blog/qr-code-analytics-dashboard.png" alt="QR Code Analytics dashboard showing real-time scan data" class="rounded-lg shadow-lg w-full" />
</div>
<h2>Advanced Campaign Tracking Strategies</h2>
@@ -148,7 +148,7 @@ export const blogPosts: Record<string, BlogPostData> = {
dateModified: '2025-10-18T09:00:00Z',
readTime: '12 Min',
category: 'Tracking & Analytics',
image: '/blog/qr-code-tracking-hero-v2.png',
image: '/blog/qr-code-tracking-guide-hero.webp',
imageAlt: 'QR Code Tracking and analytics dashboard visualization',
author: 'QR Master Team',
authorUrl: 'https://www.qrmaster.net/about',
@@ -349,7 +349,7 @@ app.get('/qr/:id', async (req, res) => {
<p>Privacy Note: Always hash IP addresses, respect Do Not Track headers, and comply with GDPR when collecting scan data.</p>
<div class="my-8">
<img loading="lazy" src="/blog/qr-code-tracking-guide-body.png" alt="Person using QR Code Tracking on mobile device in office" class="rounded-lg shadow-lg w-full" />
<img src="/blog/qr-code-tracking-guide-body.png" alt="Person using QR Code Tracking on mobile device in office" class="rounded-lg shadow-lg w-full" />
</div>
<h2>QR Code Tracking Tools Comparison</h2>
@@ -674,7 +674,7 @@ app.get('/qr/:id', async (req, res) => {
dateModified: '2025-10-17T09:00:00Z',
readTime: '10 Min',
category: 'QR Code Basics',
image: '/blog/dynamic-vs-static-hero-v2.png',
image: '/blog/static-vs-dynamic-qr-codes-hero.png',
imageAlt: 'Comparison graphic showing features of static versus dynamic QR codes',
author: 'QR Master Team',
authorUrl: 'https://www.qrmaster.net/about',
@@ -710,7 +710,7 @@ app.get('/qr/:id', async (req, res) => {
</ul>
<div class="my-8">
<img loading="lazy" src="/blog/static-vs-dynamic-qr-codes-body.png" alt="Visual comparison of static and dynamic QR code patterns" class="rounded-lg shadow-lg w-full" />
<img src="/blog/static-vs-dynamic-qr-codes-body.png" alt="Visual comparison of static and dynamic QR code patterns" class="rounded-lg shadow-lg w-full" />
</div>
<h2>Direct Comparison: Static vs Dynamic</h2>
@@ -877,7 +877,7 @@ app.get('/qr/:id', async (req, res) => {
<p>Go to the <a href="/signup">QR Master Bulk Dashboard</a> (requires Business plan). Click "Upload CSV" and select your file. The system will validate your rows to ensure no missing URLs.</p>
<div class="my-8">
<img loading="lazy" src="/blog/2-body.webp" alt="Screenshot of bulk CSV upload interface" class="rounded-lg shadow-lg w-full" />
<img src="/blog/2-body.webp" alt="Screenshot of bulk CSV upload interface" class="rounded-lg shadow-lg w-full" />
</div>
<h3>Step 4: Customize Design</h3>
@@ -1212,7 +1212,7 @@ const response = await fetch('https://api.qrmaster.net/v1/bulk', {
<h2>Step 2: Create Your QR Code with QR Master</h2>
<div class="my-8">
<img loading="lazy" src="/blog/restaurant-qr-body.png" alt="Customer scanning QR code menu at restaurant" class="rounded-lg shadow-lg w-full" />
<img src="/blog/restaurant-qr-body.png" alt="Customer scanning QR code menu at restaurant" class="rounded-lg shadow-lg w-full" />
</div>
<p>Using a <a href="/dynamic-qr-code-generator">dynamic QR code generator</a> is essential for restaurants. Unlike static codes, dynamic QR codes let you:</p>
@@ -1354,7 +1354,7 @@ const response = await fetch('https://api.qrmaster.net/v1/bulk', {
</ul>
<div class="my-8">
<img loading="lazy" src="/blog/vcard-qr-body.png" alt="Business professionals exchanging digital business cards" class="rounded-lg shadow-lg w-full" />
<img src="/blog/vcard-qr-body.png" alt="Business professionals exchanging digital business cards" class="rounded-lg shadow-lg w-full" />
</div>
<h2>Information You Can Include in a vCard</h2>
@@ -1480,7 +1480,7 @@ const response = await fetch('https://api.qrmaster.net/v1/bulk', {
<p>QR codes have become essential tools for small businesses looking to bridge the gap between physical and digital experiences. From contactless payments to customer feedback, <strong>QR codes for small business</strong> offer affordable, versatile solutions that previously required expensive custom apps.</p>
<div class="my-8">
<img loading="lazy" src="/blog/small-business-body.png" alt="Customer scanning QR code at retail checkout" class="rounded-lg shadow-lg w-full" />
<img src="/blog/small-business-body.png" alt="Customer scanning QR code at retail checkout" class="rounded-lg shadow-lg w-full" />
</div>
<h2>Top 10 QR Code Use Cases for Small Business</h2>
@@ -1610,7 +1610,7 @@ const response = await fetch('https://api.qrmaster.net/v1/bulk', {
</div>
<div class="my-8">
<img loading="lazy" src="/blog/qr-sizes-body.png" alt="Various QR code print sizes comparison" class="rounded-lg shadow-lg w-full" />
<img src="/blog/qr-sizes-body.png" alt="Various QR code print sizes comparison" class="rounded-lg shadow-lg w-full" />
</div>
<h2>QR Code Sizes by Application</h2>

View File

@@ -8,7 +8,7 @@ const INDEXNOW_ENDPOINT = 'https://api.indexnow.org/indexnow';
const HOST = 'www.qrmaster.net';
// You need to generate a key from https://www.bing.com/indexnow and place it in your public folder
// For now, we'll assume a key exists or is provided via env
const KEY = process.env.INDEXNOW_KEY || 'bb6dfaacf1ed41a880281c426c54ed7c';
const KEY = process.env.INDEXNOW_KEY || 'your-indexnow-key';
const KEY_LOCATION = `https://${HOST}/${KEY}.txt`;
export async function submitToIndexNow(urls: string[]) {
@@ -48,7 +48,6 @@ export function getAllIndexableUrls(): string[] {
// Free tools
const freeTools = [
'barcode-generator', // Added as per request
'url-qr-code', 'vcard-qr-code', 'text-qr-code', 'email-qr-code', 'sms-qr-code',
'wifi-qr-code', 'crypto-qr-code', 'event-qr-code', 'facebook-qr-code',
'instagram-qr-code', 'twitter-qr-code', 'youtube-qr-code', 'whatsapp-qr-code',

View File

@@ -20,7 +20,6 @@ export function middleware(req: NextRequest) {
'/bulk-qr-code-generator',
'/qr-code-tracking',
'/reprint-calculator',
'/barcode-generator',
];
// Check if path is public

View File

@@ -4,22 +4,21 @@
@layer utilities {
/* Floating blob animation for hero background */
@keyframes blob {
/* =======================
ANIMATIONS
======================= */
0%,
100% {
/* Floating blob animation for hero background (DEPRECATED - use grid instead) */
@keyframes blob {
0%, 100% {
transform: translate(0, 0) scale(1);
}
25% {
transform: translate(20px, -30px) scale(1.1);
}
50% {
transform: translate(-20px, 20px) scale(0.9);
}
75% {
transform: translate(30px, 10px) scale(1.05);
}
@@ -40,6 +39,147 @@
.animation-delay-6000 {
animation-delay: 6s;
}
/* Grid dash animation for modern background */
@keyframes dashMove {
0% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: 24;
}
}
.animate-dash {
animation: dashMove 20s linear infinite;
}
/* Shimmer effect for loading/highlights */
@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
.animate-shimmer {
background: linear-gradient(
90deg,
transparent 0%,
rgba(255, 255, 255, 0.4) 50%,
transparent 100%
);
background-size: 200% 100%;
animation: shimmer 2s infinite;
}
/* Pulse glow for interactive elements */
@keyframes pulseGlow {
0%, 100% {
opacity: 0.7;
transform: scale(1);
}
50% {
opacity: 1;
transform: scale(1.05);
}
}
.animate-pulse-glow {
animation: pulseGlow 2s ease-in-out infinite;
}
/* Float animation for decorative elements */
@keyframes float {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(-20px);
}
}
.animate-float {
animation: float 4s ease-in-out infinite;
}
/* =======================
GLASSMORPHISM
======================= */
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.07);
}
.glass-strong {
background: rgba(255, 255, 255, 0.25);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15);
}
.glass-dark {
background: rgba(0, 0, 0, 0.2);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* =======================
ADVANCED SHADOWS
======================= */
.shadow-primary-sm {
box-shadow: 0 2px 8px rgba(99, 102, 241, 0.1);
}
.shadow-primary-md {
box-shadow: 0 4px 16px rgba(99, 102, 241, 0.15);
}
.shadow-primary-lg {
box-shadow: 0 20px 40px rgba(99, 102, 241, 0.2);
}
.shadow-success {
box-shadow: 0 8px 24px rgba(16, 185, 129, 0.2);
}
.shadow-warning {
box-shadow: 0 8px 24px rgba(245, 158, 11, 0.2);
}
.shadow-elevation-1 {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.shadow-elevation-2 {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.shadow-elevation-3 {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.shadow-elevation-4 {
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
/* Colored inner glow */
.glow-primary {
box-shadow: inset 0 0 20px rgba(99, 102, 241, 0.3);
}
.glow-success {
box-shadow: inset 0 0 20px rgba(16, 185, 129, 0.3);
}
}
:root {
@@ -155,13 +295,82 @@ a {
@apply animate-pulse bg-gray-200 rounded;
}
/* Gradient backgrounds */
/* =======================
PREMIUM GRADIENTS
======================= */
/* Primary gradients */
.gradient-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.gradient-primary-vibrant {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #d946ef 100%);
}
.gradient-primary-subtle {
background: linear-gradient(135deg, #eef2ff 0%, #f5f3ff 100%);
}
/* Success gradients */
.gradient-success {
background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%);
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
}
.gradient-success-vibrant {
background: linear-gradient(135deg, #34d399 0%, #10b981 50%, #059669 100%);
}
/* Accent gradients */
.gradient-accent {
background: linear-gradient(135deg, #06b6d4 0%, #3b82f6 100%);
}
.gradient-warm {
background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%);
}
.gradient-cool {
background: linear-gradient(135deg, #06b6d4 0%, #8b5cf6 100%);
}
/* Gradient text */
.gradient-text {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.gradient-text-vibrant {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #d946ef 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Gradient borders */
.gradient-border {
border: 2px solid transparent;
background-clip: padding-box, border-box;
background-origin: padding-box, border-box;
background-image: linear-gradient(white, white), linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
/* Animated gradient background */
@keyframes gradientShift {
0%, 100% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
}
.gradient-animated {
background: linear-gradient(270deg, #667eea, #764ba2, #8b5cf6);
background-size: 200% 200%;
animation: gradientShift 8s ease infinite;
}
/* Chart container */