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
275 lines
7.5 KiB
TypeScript
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,
|
|
},
|
|
})),
|
|
}
|
|
}
|
|
|