Yves Gugger 02545ffe76
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
PWA: Radar fullscreen nav + contrast, Watchlist native app experience
2025-12-13 10:08:05 +01:00

275 lines
7.5 KiB
TypeScript

import Head from 'next/head'
export interface SEOProps {
title?: string
description?: string
keywords?: string[]
canonical?: string
ogImage?: string
ogType?: 'website' | 'article' | 'product'
structuredData?: object
noindex?: boolean
locale?: string
alternates?: Array<{ href: string; hreflang: string }>
}
const defaultTitle = 'Pounce - Domain Intelligence for Investors'
const defaultDescription = 'The market never sleeps. You should. Scan, track, and trade domains with real-time drops, auctions, and TLD price intelligence. Spam-filtered. 0% commission.'
const defaultKeywords = [
'domain marketplace',
'domain auctions',
'TLD pricing',
'domain investing',
'expired domains',
'domain intelligence',
'domain drops',
'premium domains',
'domain monitoring',
'domain valuation',
]
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://pounce.com'
const defaultOgImage = `${siteUrl}/og-image.png`
export function SEO({
title,
description = defaultDescription,
keywords = defaultKeywords,
canonical,
ogImage = defaultOgImage,
ogType = 'website',
structuredData,
noindex = false,
locale = 'en_US',
alternates = [],
}: SEOProps) {
const fullTitle = title ? `${title} | Pounce` : defaultTitle
const canonicalUrl = canonical || siteUrl
return (
<Head>
{/* Basic Meta Tags */}
<title>{fullTitle}</title>
<meta name="description" content={description} />
<meta name="keywords" content={keywords.join(', ')} />
{noindex && <meta name="robots" content="noindex, nofollow" />}
{/* Canonical */}
<link rel="canonical" href={canonicalUrl} />
{/* Open Graph / Facebook */}
<meta property="og:type" content={ogType} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:title" content={fullTitle} />
<meta property="og:description" content={description} />
<meta property="og:image" content={ogImage} />
<meta property="og:site_name" content="Pounce" />
<meta property="og:locale" content={locale} />
{/* Twitter */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:url" content={canonicalUrl} />
<meta name="twitter:title" content={fullTitle} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={ogImage} />
<meta name="twitter:creator" content="@pouncedomains" />
{/* Alternate Languages */}
{alternates.map((alt) => (
<link key={alt.hreflang} rel="alternate" hrefLang={alt.hreflang} href={alt.href} />
))}
{/* Structured Data (JSON-LD) */}
{structuredData && (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(structuredData),
}}
/>
)}
{/* Favicon & App Icons */}
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="manifest" href="/site.webmanifest" />
<meta name="theme-color" content="#10b981" />
</Head>
)
}
/**
* Generate Organization structured data
*/
export function getOrganizationSchema() {
return {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Pounce',
url: siteUrl,
logo: `${siteUrl}/pounce-logo.png`,
description: defaultDescription,
sameAs: [
'https://twitter.com/pouncedomains',
'https://github.com/pounce',
],
contactPoint: {
'@type': 'ContactPoint',
email: 'hello@pounce.com',
contactType: 'Customer Service',
},
}
}
/**
* Generate Product structured data for pricing page
*/
export function getPricingSchema() {
return {
'@context': 'https://schema.org',
'@type': 'ProductGroup',
name: 'Pounce Subscription Plans',
description: 'Domain intelligence and monitoring subscriptions',
brand: {
'@type': 'Brand',
name: 'Pounce',
},
offers: [
{
'@type': 'Offer',
name: 'Scout Plan',
description: 'Free domain intelligence',
price: '0',
priceCurrency: 'USD',
availability: 'https://schema.org/InStock',
},
{
'@type': 'Offer',
name: 'Trader Plan',
description: 'Professional domain intelligence',
price: '9',
priceCurrency: 'USD',
availability: 'https://schema.org/InStock',
priceValidUntil: '2025-12-31',
},
{
'@type': 'Offer',
name: 'Tycoon Plan',
description: 'Enterprise domain intelligence',
price: '29',
priceCurrency: 'USD',
availability: 'https://schema.org/InStock',
priceValidUntil: '2025-12-31',
},
],
}
}
/**
* Generate TLD Article structured data
*/
export function getTLDArticleSchema(tld: string, price: number, trend: number) {
return {
'@context': 'https://schema.org',
'@type': 'Article',
headline: `.${tld} Domain Pricing & Market Analysis`,
description: `Complete pricing intelligence for .${tld} domains including registration, renewal, and transfer costs across major registrars.`,
author: {
'@type': 'Organization',
name: 'Pounce',
},
publisher: {
'@type': 'Organization',
name: 'Pounce',
logo: {
'@type': 'ImageObject',
url: `${siteUrl}/pounce-logo.png`,
},
},
datePublished: new Date().toISOString(),
dateModified: new Date().toISOString(),
mainEntityOfPage: {
'@type': 'WebPage',
'@id': `${siteUrl}/tld-pricing/${tld}`,
},
about: {
'@type': 'Product',
name: `.${tld} Domain`,
description: `Premium .${tld} top-level domain extension`,
offers: {
'@type': 'AggregateOffer',
priceCurrency: 'USD',
lowPrice: price.toFixed(2),
offerCount: '5+',
},
},
}
}
/**
* Generate Domain Offer structured data
*/
export function getDomainOfferSchema(domain: string, price: number, description?: string) {
return {
'@context': 'https://schema.org',
'@type': 'Product',
name: domain,
description: description || `Premium domain name ${domain} for sale`,
brand: {
'@type': 'Brand',
name: 'Pounce Marketplace',
},
offers: {
'@type': 'Offer',
price: price.toFixed(2),
priceCurrency: 'USD',
availability: 'https://schema.org/InStock',
seller: {
'@type': 'Organization',
name: 'Pounce',
},
url: `${siteUrl}/domains/${domain}`,
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
reviewCount: '100',
},
}
}
/**
* Generate Breadcrumb structured data
*/
export function getBreadcrumbSchema(items: Array<{ name: string; url: string }>) {
return {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: `${siteUrl}${item.url}`,
})),
}
}
/**
* Generate FAQ structured data
*/
export function getFAQSchema(faqs: Array<{ question: string; answer: string }>) {
return {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: faqs.map((faq) => ({
'@type': 'Question',
name: faq.question,
acceptedAnswer: {
'@type': 'Answer',
text: faq.answer,
},
})),
}
}