update
This commit is contained in:
297
frontEnd/lib/seo/metadata.ts
Normal file
297
frontEnd/lib/seo/metadata.ts
Normal file
@@ -0,0 +1,297 @@
|
||||
import { Metadata } from 'next';
|
||||
|
||||
// Site Configuration
|
||||
export const SITE_CONFIG = {
|
||||
name: 'GNX Soft',
|
||||
shortName: 'GNX',
|
||||
description: 'Leading enterprise software development company providing custom solutions, data replication, incident management, AI-powered business intelligence, and comprehensive system integrations for modern businesses.',
|
||||
url: process.env.NEXT_PUBLIC_SITE_URL || 'https://gnxsoft.com',
|
||||
ogImage: '/images/og-image.png',
|
||||
email: 'info@gnxsoft.com',
|
||||
phone: '+359 896 13 80 30',
|
||||
address: {
|
||||
street: 'Tsar Simeon I, 56',
|
||||
city: 'Burgas',
|
||||
state: 'BG',
|
||||
zip: '8000',
|
||||
country: 'Bulgaria',
|
||||
},
|
||||
social: {
|
||||
linkedin: 'https://www.linkedin.com/company/gnxtech',
|
||||
github: 'https://github.com/gnxtech',
|
||||
},
|
||||
businessHours: 'Monday - Friday: 9:00 AM - 6:00 PM PST',
|
||||
foundedYear: 2020,
|
||||
};
|
||||
|
||||
// Default SEO Configuration
|
||||
export const DEFAULT_SEO = {
|
||||
title: `${SITE_CONFIG.name} | Enterprise Software Development & IT Solutions`,
|
||||
description: SITE_CONFIG.description,
|
||||
keywords: [
|
||||
'Enterprise Software Development',
|
||||
'Custom Software Development',
|
||||
'Data Replication Services',
|
||||
'Incident Management SaaS',
|
||||
'AI Business Intelligence',
|
||||
'Backend Engineering',
|
||||
'Frontend Engineering',
|
||||
'Systems Integration',
|
||||
'External Systems Integration',
|
||||
'Payment Terminal Integration',
|
||||
'ERP Integration',
|
||||
'Cloud Platform Integration',
|
||||
'Fiscal Printer Integration',
|
||||
'Enterprise Technology Solutions',
|
||||
'Digital Transformation',
|
||||
'Software Consulting',
|
||||
'API Development',
|
||||
'Microservices Architecture',
|
||||
'Cloud Migration',
|
||||
'DevOps Services',
|
||||
],
|
||||
};
|
||||
|
||||
// Generate metadata for pages
|
||||
interface PageMetadataProps {
|
||||
title?: string;
|
||||
description?: string;
|
||||
keywords?: string[];
|
||||
image?: string;
|
||||
url?: string;
|
||||
type?: 'website' | 'article' | 'product' | 'service';
|
||||
publishedTime?: string;
|
||||
modifiedTime?: string;
|
||||
author?: string;
|
||||
noindex?: boolean;
|
||||
nofollow?: boolean;
|
||||
}
|
||||
|
||||
export function generateMetadata({
|
||||
title,
|
||||
description,
|
||||
keywords = [],
|
||||
image,
|
||||
url,
|
||||
type = 'website',
|
||||
publishedTime,
|
||||
modifiedTime,
|
||||
author,
|
||||
noindex = false,
|
||||
nofollow = false,
|
||||
}: PageMetadataProps = {}): Metadata {
|
||||
const pageTitle = title
|
||||
? `${title} | ${SITE_CONFIG.name}`
|
||||
: DEFAULT_SEO.title;
|
||||
const pageDescription = description || DEFAULT_SEO.description;
|
||||
const pageImage = image
|
||||
? `${SITE_CONFIG.url}${image}`
|
||||
: `${SITE_CONFIG.url}${SITE_CONFIG.ogImage}`;
|
||||
const pageUrl = url ? `${SITE_CONFIG.url}${url}` : SITE_CONFIG.url;
|
||||
const allKeywords = [...DEFAULT_SEO.keywords, ...keywords];
|
||||
|
||||
const metadata: Metadata = {
|
||||
title: pageTitle,
|
||||
description: pageDescription,
|
||||
keywords: allKeywords,
|
||||
authors: [
|
||||
{
|
||||
name: author || SITE_CONFIG.name,
|
||||
url: SITE_CONFIG.url,
|
||||
},
|
||||
],
|
||||
creator: SITE_CONFIG.name,
|
||||
publisher: SITE_CONFIG.name,
|
||||
icons: {
|
||||
icon: '/images/logo-light.png',
|
||||
shortcut: '/images/logo-light.png',
|
||||
apple: '/images/logo-light.png',
|
||||
},
|
||||
formatDetection: {
|
||||
email: false,
|
||||
address: false,
|
||||
telephone: false,
|
||||
},
|
||||
metadataBase: new URL(SITE_CONFIG.url),
|
||||
alternates: {
|
||||
canonical: pageUrl,
|
||||
},
|
||||
openGraph: {
|
||||
type: type === 'article' ? 'article' : 'website',
|
||||
locale: 'en_US',
|
||||
url: pageUrl,
|
||||
siteName: SITE_CONFIG.name,
|
||||
title: pageTitle,
|
||||
description: pageDescription,
|
||||
images: [
|
||||
{
|
||||
url: pageImage,
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: title || SITE_CONFIG.name,
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: pageTitle,
|
||||
description: pageDescription,
|
||||
images: [pageImage],
|
||||
},
|
||||
robots: {
|
||||
index: !noindex,
|
||||
follow: !nofollow,
|
||||
googleBot: {
|
||||
index: !noindex,
|
||||
follow: !nofollow,
|
||||
'max-video-preview': -1,
|
||||
'max-image-preview': 'large',
|
||||
'max-snippet': -1,
|
||||
},
|
||||
},
|
||||
verification: {
|
||||
google: process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION,
|
||||
yandex: process.env.NEXT_PUBLIC_YANDEX_VERIFICATION,
|
||||
},
|
||||
};
|
||||
|
||||
// Add article-specific metadata
|
||||
if (type === 'article' && (publishedTime || modifiedTime)) {
|
||||
metadata.openGraph = {
|
||||
...metadata.openGraph,
|
||||
type: 'article',
|
||||
publishedTime,
|
||||
modifiedTime,
|
||||
authors: [author || SITE_CONFIG.name],
|
||||
};
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
// Service-specific metadata generator
|
||||
export function generateServiceMetadata(service: {
|
||||
title: string;
|
||||
description: string;
|
||||
short_description?: string;
|
||||
slug: string;
|
||||
category?: { name: string };
|
||||
technologies?: string;
|
||||
duration?: string;
|
||||
}) {
|
||||
const keywords = [
|
||||
service.title,
|
||||
`${service.title} Services`,
|
||||
service.category?.name || 'Enterprise Services',
|
||||
'Custom Development',
|
||||
'Enterprise Solutions',
|
||||
];
|
||||
|
||||
if (service.technologies) {
|
||||
const techs = service.technologies.split(',').map((t) => t.trim());
|
||||
keywords.push(...techs);
|
||||
}
|
||||
|
||||
return generateMetadata({
|
||||
title: service.title,
|
||||
description: service.short_description || service.description,
|
||||
keywords,
|
||||
url: `/services/${service.slug}`,
|
||||
type: 'service' as any,
|
||||
});
|
||||
}
|
||||
|
||||
// Blog-specific metadata generator
|
||||
export function generateBlogMetadata(post: {
|
||||
title: string;
|
||||
description?: string;
|
||||
excerpt?: string;
|
||||
slug: string;
|
||||
image?: string;
|
||||
published_at?: string;
|
||||
updated_at?: string;
|
||||
author?: { name: string };
|
||||
category?: { name: string };
|
||||
tags?: string[];
|
||||
}) {
|
||||
const keywords = [
|
||||
post.category?.name || 'Technology',
|
||||
'Blog',
|
||||
'Tech Insights',
|
||||
...(post.tags || []),
|
||||
];
|
||||
|
||||
return generateMetadata({
|
||||
title: post.title,
|
||||
description: post.description || post.excerpt,
|
||||
keywords,
|
||||
image: post.image,
|
||||
url: `/insights/${post.slug}`,
|
||||
type: 'article',
|
||||
publishedTime: post.published_at,
|
||||
modifiedTime: post.updated_at,
|
||||
author: post.author?.name,
|
||||
});
|
||||
}
|
||||
|
||||
// Case Study metadata generator
|
||||
export function generateCaseStudyMetadata(caseStudy: {
|
||||
title: string;
|
||||
description?: string;
|
||||
excerpt?: string;
|
||||
slug: string;
|
||||
image?: string;
|
||||
client_name?: string;
|
||||
industry?: string;
|
||||
technologies?: string;
|
||||
}) {
|
||||
const keywords = [
|
||||
'Case Study',
|
||||
caseStudy.client_name || '',
|
||||
caseStudy.industry || '',
|
||||
'Success Story',
|
||||
'Client Project',
|
||||
];
|
||||
|
||||
if (caseStudy.technologies) {
|
||||
const techs = caseStudy.technologies.split(',').map((t) => t.trim());
|
||||
keywords.push(...techs);
|
||||
}
|
||||
|
||||
return generateMetadata({
|
||||
title: caseStudy.title,
|
||||
description: caseStudy.description || caseStudy.excerpt,
|
||||
keywords: keywords.filter(Boolean),
|
||||
image: caseStudy.image,
|
||||
url: `/case-study/${caseStudy.slug}`,
|
||||
type: 'article',
|
||||
});
|
||||
}
|
||||
|
||||
// Career metadata generator
|
||||
export function generateCareerMetadata(job: {
|
||||
title: string;
|
||||
description?: string;
|
||||
slug: string;
|
||||
location?: string;
|
||||
department?: string;
|
||||
employment_type?: string;
|
||||
}) {
|
||||
const keywords = [
|
||||
job.title,
|
||||
'Career',
|
||||
'Job Opening',
|
||||
job.department || '',
|
||||
job.location || '',
|
||||
job.employment_type || '',
|
||||
'Join Our Team',
|
||||
].filter(Boolean);
|
||||
|
||||
return generateMetadata({
|
||||
title: `${job.title} - Careers`,
|
||||
description: job.description,
|
||||
keywords,
|
||||
url: `/career/${job.slug}`,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user