press releases
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import type { Metadata } from 'next';
|
||||
import SeoJsonLd from '@/components/SeoJsonLd';
|
||||
import { organizationSchema, websiteSchema, softwareApplicationSchema } from '@/lib/schema';
|
||||
import { organizationSchema, websiteSchema, softwareApplicationSchema, reviewSchema, aggregateRatingSchema } from '@/lib/schema';
|
||||
import { getFeaturedTestimonials, getAggregateRating } from '@/lib/testimonial-data';
|
||||
import HomePageClient from '@/components/marketing/HomePageClient';
|
||||
|
||||
function truncateAtWord(text: string, maxLength: number): string {
|
||||
@@ -52,9 +53,19 @@ export async function generateMetadata(): Promise<Metadata> {
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
const featuredTestimonials = getFeaturedTestimonials();
|
||||
const aggregateRating = getAggregateRating();
|
||||
const reviewSchemas = featuredTestimonials.map(t => reviewSchema(t));
|
||||
|
||||
return (
|
||||
<>
|
||||
<SeoJsonLd data={[websiteSchema(), organizationSchema(), softwareApplicationSchema()]} />
|
||||
<SeoJsonLd data={[
|
||||
websiteSchema(),
|
||||
organizationSchema(),
|
||||
softwareApplicationSchema(),
|
||||
aggregateRatingSchema(aggregateRating),
|
||||
...reviewSchemas
|
||||
]} />
|
||||
|
||||
{/* Server-rendered SEO content for crawlers */}
|
||||
<div className="sr-only" aria-hidden="false">
|
||||
|
||||
139
src/app/(main)/(marketing)/press/page.tsx
Normal file
139
src/app/(main)/(marketing)/press/page.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
import React from 'react';
|
||||
import { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import SeoJsonLd from '@/components/SeoJsonLd';
|
||||
import { organizationSchema, websiteSchema } from '@/lib/schema';
|
||||
import { ChevronRight, ExternalLink, Newspaper, Award, Calendar } from 'lucide-react';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Press & News | QR Master',
|
||||
description: 'Latest news, press releases, and updates from QR Master. Stay informed about new features, company announcements, and industry insights.',
|
||||
keywords: ['qr master press', 'qr code generator news', 'company updates', 'press releases'],
|
||||
openGraph: {
|
||||
title: 'Press & News | QR Master',
|
||||
description: 'Latest news, press releases, and updates from QR Master.',
|
||||
url: 'https://www.qrmaster.net/press',
|
||||
type: 'website',
|
||||
}
|
||||
};
|
||||
|
||||
export default function PressPage() {
|
||||
const pressReleases = [
|
||||
{
|
||||
id: "launch-2026",
|
||||
title: "qrmaster.net Launches Free, Professional QR Code Generator for Global Users",
|
||||
date: "January 27, 2026",
|
||||
excerpt: "Duesseldorf-based startup unveils qrmaster.net, a comprehensive, free online QR code generator designed to serve as the ultimate bridge between the physical and digital worlds.",
|
||||
bullets: [
|
||||
"Advanced tracking capabilities with UTM builder for GA4 integration",
|
||||
"100% Free professional templates and design customization",
|
||||
"Privacy-focused architecture with no data selling",
|
||||
"Dynamic QR codes that can be edited after printing"
|
||||
],
|
||||
link: "https://www.prlog.org/13123883-qrmasternet-launches-free-professional-qr-code-generator-for-global-users.html",
|
||||
source: "PRLog"
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SeoJsonLd data={[organizationSchema(), websiteSchema()]} />
|
||||
|
||||
<div className="bg-white min-h-screen">
|
||||
{/* Hero Section */}
|
||||
<section className="relative overflow-hidden bg-gradient-to-br from-gray-900 to-gray-800 text-white py-20 sm:py-24">
|
||||
<div className="absolute inset-0 bg-[url('/grid-pattern.svg')] opacity-10"></div>
|
||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl relative z-10">
|
||||
<div className="max-w-3xl">
|
||||
<h1 className="text-4xl sm:text-5xl font-bold mb-6 tracking-tight">
|
||||
Newsroom
|
||||
</h1>
|
||||
<p className="text-xl text-gray-300 max-w-2xl leading-relaxed">
|
||||
Latest updates, press releases, and announcements from the QR Master team.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Press Releases List */}
|
||||
<section className="py-16 sm:py-24">
|
||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-5xl">
|
||||
<div className="flex items-center gap-3 mb-12">
|
||||
<Newspaper className="w-6 h-6 text-blue-600" />
|
||||
<h2 className="text-2xl font-bold text-gray-900">Latest Releases</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-12">
|
||||
{pressReleases.map((pr) => (
|
||||
<div key={pr.id} className="group relative bg-white border border-gray-100 rounded-2xl shadow-sm hover:shadow-md transition-all duration-300 overflow-hidden">
|
||||
<div className="absolute top-0 left-0 w-1 h-full bg-blue-600 opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
||||
|
||||
<div className="p-8 sm:p-10">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6">
|
||||
<div className="flex items-center gap-2 text-sm text-gray-500 font-medium">
|
||||
<Calendar className="w-4 h-4" />
|
||||
{pr.date}
|
||||
</div>
|
||||
<span className="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-blue-50 text-blue-700">
|
||||
Press Release
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl sm:text-3xl font-bold text-gray-900 mb-4 group-hover:text-blue-600 transition-colors">
|
||||
<a href={pr.link} target="_blank" rel="noopener noreferrer" className="focus:outline-none">
|
||||
<span className="absolute inset-0" aria-hidden="true"></span>
|
||||
{pr.title}
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
<p className="text-gray-600 text-lg mb-8 leading-relaxed">
|
||||
{pr.excerpt}
|
||||
</p>
|
||||
|
||||
<div className="bg-gray-50 rounded-xl p-6 mb-8">
|
||||
<h4 className="text-sm font-semibold text-gray-900 uppercase tracking-wider mb-4">Highlights</h4>
|
||||
<ul className="grid sm:grid-cols-2 gap-4">
|
||||
{pr.bullets.map((bullet, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2 text-gray-700">
|
||||
<span className="mt-1.5 w-1.5 h-1.5 rounded-full bg-blue-500 flex-shrink-0"></span>
|
||||
<span>{bullet}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between mt-auto">
|
||||
<div className="flex items-center gap-2 text-sm text-gray-500">
|
||||
<span>Source:</span>
|
||||
<span className="font-semibold text-gray-900">{pr.source}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 text-blue-600 font-semibold group-hover:gap-2 transition-all">
|
||||
Read full release <ExternalLink className="w-4 h-4" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Media Kit CTA (Future proofing) */}
|
||||
<section className="bg-gray-50 py-16 border-t border-gray-100">
|
||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-5xl text-center">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-4">Media Inquiries</h2>
|
||||
<p className="text-gray-600 mb-8 max-w-xl mx-auto">
|
||||
For press inquiries, assets, or interview requests from our leadership team.
|
||||
</p>
|
||||
<a href="mailto:press@qrmaster.net">
|
||||
<Button variant="outline" size="lg">
|
||||
Contact Press Team
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
142
src/app/(main)/(marketing)/testimonials/page.tsx
Normal file
142
src/app/(main)/(marketing)/testimonials/page.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
import React from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Metadata } from 'next';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import SeoJsonLd from '@/components/SeoJsonLd';
|
||||
import { organizationSchema, reviewSchema, aggregateRatingSchema } from '@/lib/schema';
|
||||
import { testimonials, getAggregateRating } from '@/lib/testimonial-data';
|
||||
import { Testimonials } from '@/components/marketing/Testimonials';
|
||||
import { Star } from 'lucide-react';
|
||||
|
||||
function truncateAtWord(text: string, maxLength: number): string {
|
||||
if (text.length <= maxLength) return text;
|
||||
const truncated = text.slice(0, maxLength);
|
||||
const lastSpace = truncated.lastIndexOf(' ');
|
||||
return lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated;
|
||||
}
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
const title = truncateAtWord('Customer Testimonials | QR Master Reviews', 60);
|
||||
const description = truncateAtWord(
|
||||
'Read what our customers say about QR Master. Real reviews from businesses using dynamic QR codes for restaurants, pottery, retail, events, and more.',
|
||||
160
|
||||
);
|
||||
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
keywords: ['qr master reviews', 'qr code testimonials', 'customer reviews', 'qr code generator reviews', 'dynamic qr code reviews'],
|
||||
alternates: {
|
||||
canonical: 'https://www.qrmaster.net/testimonials',
|
||||
},
|
||||
openGraph: {
|
||||
title,
|
||||
description,
|
||||
url: 'https://www.qrmaster.net/testimonials',
|
||||
type: 'website',
|
||||
images: [
|
||||
{
|
||||
url: 'https://www.qrmaster.net/og-image.png',
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: 'QR Master Customer Testimonials',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
title,
|
||||
description,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function TestimonialsPage() {
|
||||
const aggregateRating = getAggregateRating();
|
||||
const reviewSchemas = testimonials.map(t => reviewSchema(t));
|
||||
|
||||
return (
|
||||
<>
|
||||
<SeoJsonLd data={[
|
||||
organizationSchema(),
|
||||
aggregateRatingSchema(aggregateRating),
|
||||
...reviewSchemas
|
||||
]} />
|
||||
|
||||
<div className="bg-white">
|
||||
{/* Hero Section with Aggregate Rating */}
|
||||
<section className="relative overflow-hidden bg-gradient-to-br from-blue-50 via-white to-purple-50 py-20 sm:py-24">
|
||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-5xl text-center">
|
||||
<h1 className="text-4xl sm:text-5xl font-bold text-gray-900 leading-tight mb-6">
|
||||
Customer <span className="text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-purple-600">Testimonials</span>
|
||||
</h1>
|
||||
<p className="text-xl text-gray-600 max-w-2xl mx-auto mb-8 leading-relaxed">
|
||||
Real experiences from businesses using QR Master to create dynamic QR codes
|
||||
</p>
|
||||
|
||||
{/* Aggregate Rating Display */}
|
||||
<div className="flex flex-col items-center justify-center gap-3 mb-10">
|
||||
<div className="flex gap-1" aria-label={`${aggregateRating.ratingValue} out of 5 stars`}>
|
||||
{[...Array(5)].map((_, index) => (
|
||||
<Star
|
||||
key={index}
|
||||
className={`w-8 h-8 ${
|
||||
index < aggregateRating.ratingValue
|
||||
? 'fill-yellow-400 text-yellow-400'
|
||||
: 'fill-gray-200 text-gray-200'
|
||||
}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-lg text-gray-700">
|
||||
<span className="font-bold text-2xl">{aggregateRating.ratingValue}</span> out of 5 stars
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
Based on {aggregateRating.reviewCount} {aggregateRating.reviewCount === 1 ? 'review' : 'reviews'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||
<Link href="/signup">
|
||||
<Button size="lg" className="text-lg px-8 py-6 shadow-lg shadow-blue-500/25">
|
||||
Get Started Free
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Testimonials Grid */}
|
||||
<Testimonials
|
||||
testimonials={testimonials}
|
||||
showAll={true}
|
||||
title="What Our Customers Are Saying"
|
||||
subtitle="Discover how businesses use QR Master for their unique needs"
|
||||
/>
|
||||
|
||||
{/* CTA Section */}
|
||||
<section className="py-20 bg-gradient-to-br from-blue-50 via-white to-purple-50">
|
||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-4xl text-center">
|
||||
<h2 className="text-3xl sm:text-4xl font-bold text-gray-900 mb-6">
|
||||
Ready to create your own QR codes?
|
||||
</h2>
|
||||
<p className="text-xl text-gray-600 mb-10 max-w-2xl mx-auto">
|
||||
Join businesses using QR Master to create dynamic, trackable QR codes for their products, menus, events, and campaigns.
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center">
|
||||
<Link href="/signup">
|
||||
<Button size="lg" className="text-lg px-8 py-6">
|
||||
Start Free Today
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/pricing">
|
||||
<Button variant="outline" size="lg" className="text-lg px-8 py-6">
|
||||
View Pricing
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -175,6 +175,18 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
||||
changeFrequency: 'yearly',
|
||||
priority: 0.6,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/press`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.7,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/testimonials`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.7,
|
||||
},
|
||||
|
||||
|
||||
...toolPages,
|
||||
|
||||
Reference in New Issue
Block a user