Merge pull request #1 from damjan1996/auto-claude/032-split-large-jsonld-tsx-component-759-lines-into-se

auto-claude: 032-split-large-jsonld-tsx-component-759-lines-into-se
This commit is contained in:
Damjan Savic
2026-01-25 19:31:06 +01:00
committed by GitHub
18 changed files with 892 additions and 759 deletions
+74
View File
@@ -0,0 +1,74 @@
{
"files_to_modify": {
"frontend": [
"src/components/seo/JsonLd.tsx",
"src/components/seo/index.ts"
]
},
"files_to_create": {
"frontend": [
"src/components/seo/schemas/PersonJsonLd.tsx",
"src/components/seo/schemas/ProfessionalServiceJsonLd.tsx",
"src/components/seo/schemas/BreadcrumbJsonLd.tsx",
"src/components/seo/schemas/WebPageJsonLd.tsx",
"src/components/seo/schemas/FAQJsonLd.tsx",
"src/components/seo/schemas/ServiceJsonLd.tsx",
"src/components/seo/schemas/OrganizationJsonLd.tsx",
"src/components/seo/schemas/ArticleJsonLd.tsx",
"src/components/seo/schemas/HowToJsonLd.tsx",
"src/components/seo/schemas/ProfilePageJsonLd.tsx",
"src/components/seo/schemas/VideoJsonLd.tsx",
"src/components/seo/schemas/SoftwareAppJsonLd.tsx",
"src/components/seo/schemas/WebSiteJsonLd.tsx",
"src/components/seo/schemas/index.ts"
]
},
"files_to_reference": [
"src/components/about/index.ts",
"src/components/layout/index.ts",
"src/components/portfolio/index.ts"
],
"patterns": {
"component_organization": "Each component type gets its own directory with multiple component files and a barrel export index.ts",
"barrel_export": "index.ts re-exports all components from the directory using named exports",
"import_paths": "Imports use path alias @/components/... for cleaner imports",
"typescript": "All components use TypeScript with proper interface definitions"
},
"existing_implementations": {
"description": "Found 14 JSON-LD schema components in a single 758-line file at src/components/seo/JsonLd.tsx",
"relevant_files": [
"src/components/seo/JsonLd.tsx",
"src/components/seo/index.ts",
"src/app/[locale]/layout.tsx (imports PersonJsonLd, ProfessionalServiceJsonLd, OrganizationJsonLd, WebSiteJsonLd)",
"src/app/[locale]/about/page.tsx (imports ProfilePageJsonLd, BreadcrumbJsonLd)",
"src/app/[locale]/blog/[slug]/page.tsx (imports BreadcrumbJsonLd, ArticleJsonLd)",
"src/app/[locale]/leistungen/page.tsx (imports BreadcrumbJsonLd, FAQJsonLd)"
],
"components_to_split": [
"PersonJsonLd",
"ProfessionalServiceJsonLd",
"BreadcrumbJsonLd",
"WebPageJsonLd",
"FAQJsonLd",
"ServiceJsonLd",
"OrganizationJsonLd",
"ArticleJsonLd",
"HowToJsonLd",
"ProfilePageJsonLd",
"VideoJsonLd",
"SoftwareAppJsonLd",
"WebSiteJsonLd"
],
"usage_locations": [
"src/app/[locale]/layout.tsx",
"src/app/[locale]/about/page.tsx",
"src/app/[locale]/blog/page.tsx",
"src/app/[locale]/blog/[slug]/page.tsx",
"src/app/[locale]/contact/page.tsx",
"src/app/[locale]/leistungen/page.tsx",
"src/app/[locale]/leistungen/[slug]/page.tsx",
"src/app/[locale]/leistungen/standort/[city]/page.tsx",
"src/app/[locale]/portfolio/[slug]/page.tsx"
]
}
}
+27
View File
@@ -0,0 +1,27 @@
{
"project_type": "single",
"services": {
"frontend": {
"path": ".",
"tech_stack": ["typescript", "react", "nextjs", "tailwindcss"],
"framework": "Next.js 15 (App Router)",
"port": 3000,
"dev_command": "npm run dev",
"build_command": "npm run build",
"test_command": "npm test"
}
},
"infrastructure": {
"docker": false,
"database": null,
"ci_cd": false
},
"conventions": {
"linter": "eslint",
"formatter": "prettier",
"testing": "vitest",
"component_pattern": "Each component directory contains multiple .tsx files with a barrel export index.ts",
"import_pattern": "Path aliases using @/ for src directory",
"export_pattern": "index.ts re-exports components using export { ComponentName } or export { default as ComponentName }"
}
}
-758
View File
@@ -1,758 +0,0 @@
import { type Locale } from '@/i18n/config';
interface JsonLdProps {
locale: Locale;
}
export function PersonJsonLd({ locale }: JsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'Person',
'@id': `${baseUrl}/#person`,
name: 'Damjan Savić',
givenName: 'Damjan',
familyName: 'Savić',
jobTitle: locale === 'de'
? 'Fullstack Entwickler'
: locale === 'sr'
? 'Fullstack Developer'
: 'Fullstack Developer',
description: locale === 'de'
? 'Fullstack Entwicklung für Websites, Apps und SaaS mit Next.js, React und TypeScript.'
: locale === 'sr'
? 'Fullstack razvoj za web stranice, aplikacije i SaaS sa Next.js, React i TypeScript.'
: 'Fullstack development for websites, apps and SaaS with Next.js, React and TypeScript.',
url: baseUrl,
image: `${baseUrl}/images/og-image.jpg`,
email: 'info@damjan-savic.com',
telephone: '+491756950979',
address: {
'@type': 'PostalAddress',
addressLocality: locale === 'sr' ? 'Keln' : locale === 'en' ? 'Cologne' : 'Köln',
addressRegion: 'NRW',
addressCountry: 'DE',
},
sameAs: [
'https://www.linkedin.com/in/damjansavic/',
'https://github.com/damjansavic',
],
knowsAbout: [
'Artificial Intelligence',
'Machine Learning',
'Process Automation',
'Voice AI',
'Web Development',
'Python',
'TypeScript',
'React',
'Next.js',
'n8n',
'SaaS Development',
],
alumniOf: [
{
'@type': 'EducationalOrganization',
name: 'FOM Hochschule für Ökonomie & Management',
},
],
hasCredential: [
{
'@type': 'EducationalOccupationalCredential',
name: 'M.A. Software Development',
credentialCategory: 'degree',
},
{
'@type': 'EducationalOccupationalCredential',
name: 'B.Sc. Wirtschaftsinformatik',
credentialCategory: 'degree',
},
],
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
export function ProfessionalServiceJsonLd({ locale }: JsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const serviceNames = {
de: [
'KI-Entwicklung',
'Prozessautomatisierung',
'Voice AI Entwicklung',
'SaaS Entwicklung',
'Fullstack Webentwicklung',
'n8n Automatisierung',
],
en: [
'AI Development',
'Process Automation',
'Voice AI Development',
'SaaS Development',
'Fullstack Web Development',
'n8n Automation',
],
sr: [
'AI Razvoj',
'Automatizacija procesa',
'Voice AI Razvoj',
'SaaS Razvoj',
'Fullstack Web Razvoj',
'n8n Automatizacija',
],
};
const schema = {
'@context': 'https://schema.org',
'@type': 'ProfessionalService',
'@id': `${baseUrl}/#business`,
name: 'Damjan Savić - AI & Automation Specialist',
description: locale === 'de'
? 'Freelance AI & Automation Specialist aus Köln. Spezialisiert auf KI-Agenten, Voice AI, Prozessautomatisierung und SaaS-Entwicklung.'
: locale === 'sr'
? 'Freelance AI & Automation Specialist iz Kelna. Specijalizovan za AI agente, Voice AI, automatizaciju procesa i SaaS razvoj.'
: 'Remote AI & Automation Specialist based in Germany, serving clients in USA, UK and Europe. Specialized in AI agents, Voice AI, n8n process automation and custom SaaS development.',
url: baseUrl,
logo: `${baseUrl}/images/og-image.jpg`,
image: `${baseUrl}/images/og-image.jpg`,
email: 'info@damjan-savic.com',
telephone: '+491756950979',
priceRange: '€€€',
address: {
'@type': 'PostalAddress',
streetAddress: 'Rotdornallee',
addressLocality: locale === 'sr' ? 'Keln' : locale === 'en' ? 'Cologne' : 'Köln',
addressRegion: 'NRW',
postalCode: '50769',
addressCountry: 'DE',
},
geo: {
'@type': 'GeoCoordinates',
latitude: 50.9375,
longitude: 6.9603,
},
areaServed: [
// Germany
{ '@type': 'City', name: 'Cologne' },
{ '@type': 'City', name: 'Düsseldorf' },
{ '@type': 'City', name: 'Frankfurt' },
{ '@type': 'City', name: 'Munich' },
{ '@type': 'City', name: 'Berlin' },
{ '@type': 'City', name: 'Hamburg' },
{ '@type': 'Country', name: 'Germany' },
// USA
{ '@type': 'City', name: 'New York' },
{ '@type': 'City', name: 'Los Angeles' },
{ '@type': 'City', name: 'San Francisco' },
{ '@type': 'City', name: 'Miami' },
{ '@type': 'City', name: 'Chicago' },
{ '@type': 'Country', name: 'United States' },
// UK
{ '@type': 'City', name: 'London' },
{ '@type': 'Country', name: 'United Kingdom' },
// Europe
{ '@type': 'Country', name: 'Austria' },
{ '@type': 'Country', name: 'Switzerland' },
],
hasOfferCatalog: {
'@type': 'OfferCatalog',
name: locale === 'de' ? 'Dienstleistungen' : locale === 'sr' ? 'Usluge' : 'Services',
itemListElement: serviceNames[locale].map((service, index) => ({
'@type': 'Offer',
itemOffered: {
'@type': 'Service',
name: service,
},
position: index + 1,
})),
},
founder: {
'@id': `${baseUrl}/#person`,
},
sameAs: [
'https://www.linkedin.com/in/damjansavic/',
'https://github.com/damjansavic',
],
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
export function BreadcrumbJsonLd({
items,
locale,
}: {
items: { name: string; url: string }[];
locale: Locale;
}) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url.startsWith('http') ? item.url : `${baseUrl}${item.url}`,
})),
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
export function WebPageJsonLd({
title,
description,
url,
locale,
}: {
title: string;
description: string;
url: string;
locale: Locale;
}) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'WebPage',
name: title,
description: description,
url: url.startsWith('http') ? url : `${baseUrl}${url}`,
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
isPartOf: {
'@type': 'WebSite',
name: 'Damjan Savić',
url: baseUrl,
},
author: {
'@id': `${baseUrl}/#person`,
},
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
interface FAQItem {
question: string;
answer: string;
}
export function FAQJsonLd({ items, locale }: { items: FAQItem[]; locale?: Locale }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
inLanguage: locale ? (locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US') : 'de-DE',
mainEntity: items.map((item) => ({
'@type': 'Question',
name: item.question,
acceptedAnswer: {
'@type': 'Answer',
text: item.answer,
},
})),
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
interface ServiceJsonLdProps {
name: string;
description: string;
url: string;
locale: Locale;
areaServed?: string[];
}
export function ServiceJsonLd({
name,
description,
url,
locale,
areaServed = ['Köln', 'Düsseldorf', 'Frankfurt', 'Deutschland'],
}: ServiceJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'Service',
name: name,
description: description,
url: url.startsWith('http') ? url : `${baseUrl}${url}`,
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
availableLanguage: ['de-DE', 'en-US', 'sr-RS'],
provider: {
'@id': `${baseUrl}/#business`,
},
areaServed: areaServed.map((area) => ({
'@type': 'City',
name: area,
})),
serviceType: name,
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
// Organization Schema
export function OrganizationJsonLd({ locale }: JsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'Organization',
'@id': `${baseUrl}/#organization`,
name: 'Damjan Savić - AI & Automation Specialist',
alternateName: 'Damjan Savić',
url: baseUrl,
logo: {
'@type': 'ImageObject',
url: `${baseUrl}/images/og-image.jpg`,
width: 1200,
height: 630,
},
image: `${baseUrl}/images/og-image.jpg`,
description: locale === 'de'
? 'Freelance KI-Entwickler und Automatisierungsspezialist aus Köln. Spezialisiert auf KI-Agenten, Voice AI, Prozessautomatisierung mit n8n und SaaS-Entwicklung.'
: locale === 'sr'
? 'Freelance AI developer i specijalista za automatizaciju iz Kelna. Specijalizovan za AI agente, Voice AI, automatizaciju procesa sa n8n i SaaS razvoj.'
: 'Remote AI developer and automation specialist based in Germany. Working with clients in USA, UK & Europe. Specialized in AI agents, Voice AI, n8n automation and SaaS development.',
email: 'info@damjan-savic.com',
telephone: '+491756950979',
address: {
'@type': 'PostalAddress',
streetAddress: 'Rotdornallee',
addressLocality: locale === 'sr' ? 'Keln' : locale === 'en' ? 'Cologne' : 'Köln',
addressRegion: 'NRW',
postalCode: '50769',
addressCountry: 'DE',
},
geo: {
'@type': 'GeoCoordinates',
latitude: 50.9375,
longitude: 6.9603,
},
areaServed: [
// DACH Region
{ '@type': 'Country', name: 'Germany' },
{ '@type': 'Country', name: 'Austria' },
{ '@type': 'Country', name: 'Switzerland' },
// International (Remote)
{ '@type': 'Country', name: 'United States' },
{ '@type': 'Country', name: 'United Kingdom' },
{ '@type': 'Country', name: 'Serbia' },
// Major International Cities
{ '@type': 'City', name: 'New York' },
{ '@type': 'City', name: 'London' },
{ '@type': 'City', name: 'San Francisco' },
{ '@type': 'City', name: 'Los Angeles' },
],
founder: {
'@id': `${baseUrl}/#person`,
},
sameAs: [
'https://www.linkedin.com/in/damjansavic/',
'https://github.com/damjansavic',
],
contactPoint: {
'@type': 'ContactPoint',
contactType: 'customer service',
email: 'info@damjan-savic.com',
telephone: '+491756950979',
availableLanguage: ['German', 'English', 'Serbian'],
},
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
// Article Schema for Blog Posts
interface ArticleJsonLdProps {
title: string;
description: string;
url: string;
imageUrl: string;
datePublished: string;
dateModified?: string;
authorName?: string;
tags?: string[];
locale: Locale;
}
export function ArticleJsonLd({
title,
description,
url,
imageUrl,
datePublished,
dateModified,
authorName = 'Damjan Savić',
tags = [],
locale,
}: ArticleJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: title,
description: description,
image: imageUrl.startsWith('http') ? imageUrl : `${baseUrl}${imageUrl}`,
url: url.startsWith('http') ? url : `${baseUrl}${url}`,
datePublished: datePublished,
dateModified: dateModified || datePublished,
author: {
'@type': 'Person',
'@id': `${baseUrl}/#person`,
name: authorName,
url: baseUrl,
},
publisher: {
'@type': 'Organization',
'@id': `${baseUrl}/#organization`,
name: 'Damjan Savić',
logo: {
'@type': 'ImageObject',
url: `${baseUrl}/images/og-image.jpg`,
},
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': url.startsWith('http') ? url : `${baseUrl}${url}`,
},
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
keywords: tags.join(', '),
articleSection: 'Technology',
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
// HowTo Schema for Tutorials
interface HowToStep {
name: string;
text: string;
url?: string;
image?: string;
}
interface HowToJsonLdProps {
name: string;
description: string;
steps: HowToStep[];
totalTime?: string; // ISO 8601 duration format, e.g., "PT30M" for 30 minutes
estimatedCost?: { currency: string; value: string };
tools?: string[];
supplies?: string[];
image?: string;
locale: Locale;
}
export function HowToJsonLd({
name,
description,
steps,
totalTime,
estimatedCost,
tools,
supplies,
image,
locale,
}: HowToJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema: Record<string, unknown> = {
'@context': 'https://schema.org',
'@type': 'HowTo',
name: name,
description: description,
step: steps.map((step, index) => ({
'@type': 'HowToStep',
position: index + 1,
name: step.name,
text: step.text,
...(step.url && { url: step.url.startsWith('http') ? step.url : `${baseUrl}${step.url}` }),
...(step.image && { image: step.image.startsWith('http') ? step.image : `${baseUrl}${step.image}` }),
})),
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
};
if (totalTime) {
schema.totalTime = totalTime;
}
if (estimatedCost) {
schema.estimatedCost = {
'@type': 'MonetaryAmount',
currency: estimatedCost.currency,
value: estimatedCost.value,
};
}
if (tools && tools.length > 0) {
schema.tool = tools.map((tool) => ({
'@type': 'HowToTool',
name: tool,
}));
}
if (supplies && supplies.length > 0) {
schema.supply = supplies.map((supply) => ({
'@type': 'HowToSupply',
name: supply,
}));
}
if (image) {
schema.image = image.startsWith('http') ? image : `${baseUrl}${image}`;
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
// ProfilePage Schema for About Page
interface ProfilePageJsonLdProps {
locale: Locale;
}
export function ProfilePageJsonLd({ locale }: ProfilePageJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'ProfilePage',
dateCreated: '2024-01-01',
dateModified: new Date().toISOString().split('T')[0],
mainEntity: {
'@id': `${baseUrl}/#person`,
},
name: locale === 'de'
? 'Über Damjan Savić - KI-Entwickler & Automatisierungsspezialist'
: locale === 'sr'
? 'O Damjanu Saviću - AI Developer & Specijalista za automatizaciju'
: 'About Damjan Savić - AI Developer & Automation Specialist',
description: locale === 'de'
? 'Erfahren Sie mehr über Damjan Savić, Freelance KI-Entwickler und Automatisierungsspezialist aus Köln. Expertise in KI-Agenten, Voice AI, n8n und SaaS-Entwicklung.'
: locale === 'sr'
? 'Saznajte više o Damjanu Saviću, freelance AI developeru i specijalisti za automatizaciju iz Kelna. Ekspertiza u AI agentima, Voice AI, n8n i SaaS razvoju.'
: 'Learn more about Damjan Savić, freelance AI developer and automation specialist from Cologne. Expertise in AI agents, Voice AI, n8n and SaaS development.',
url: `${baseUrl}/${locale}/about`,
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
// VideoObject Schema for embedded videos
interface VideoJsonLdProps {
name: string;
description: string;
thumbnailUrl: string;
uploadDate: string;
duration?: string; // ISO 8601 format, e.g., "PT1M30S"
contentUrl?: string;
embedUrl?: string;
locale: Locale;
}
export function VideoJsonLd({
name,
description,
thumbnailUrl,
uploadDate,
duration,
contentUrl,
embedUrl,
locale,
}: VideoJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema: Record<string, unknown> = {
'@context': 'https://schema.org',
'@type': 'VideoObject',
name: name,
description: description,
thumbnailUrl: thumbnailUrl.startsWith('http') ? thumbnailUrl : `${baseUrl}${thumbnailUrl}`,
uploadDate: uploadDate,
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
author: {
'@id': `${baseUrl}/#person`,
},
};
if (duration) {
schema.duration = duration;
}
if (contentUrl) {
schema.contentUrl = contentUrl;
}
if (embedUrl) {
schema.embedUrl = embedUrl;
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
// SoftwareApplication Schema for tools/projects
interface SoftwareAppJsonLdProps {
name: string;
description: string;
applicationCategory: string;
operatingSystem?: string;
offers?: {
price: string;
priceCurrency: string;
};
aggregateRating?: {
ratingValue: string;
ratingCount: string;
};
locale: Locale;
}
export function SoftwareAppJsonLd({
name,
description,
applicationCategory,
operatingSystem = 'Web',
offers,
aggregateRating,
locale,
}: SoftwareAppJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema: Record<string, unknown> = {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: name,
description: description,
applicationCategory: applicationCategory,
operatingSystem: operatingSystem,
author: {
'@id': `${baseUrl}/#person`,
},
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
};
if (offers) {
schema.offers = {
'@type': 'Offer',
price: offers.price,
priceCurrency: offers.priceCurrency,
};
}
if (aggregateRating) {
schema.aggregateRating = {
'@type': 'AggregateRating',
ratingValue: aggregateRating.ratingValue,
ratingCount: aggregateRating.ratingCount,
};
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
// WebSite Schema for Search Box
export function WebSiteJsonLd({ locale }: JsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'WebSite',
'@id': `${baseUrl}/#website`,
name: 'Damjan Savić',
alternateName: locale === 'de'
? 'Damjan Savić - KI Entwickler Köln'
: locale === 'sr'
? 'Damjan Savić - AI Developer Keln'
: 'Damjan Savić - AI Developer Cologne',
url: baseUrl,
description: locale === 'de'
? 'Portfolio und Blog von Damjan Savić - KI-Entwickler und Automatisierungsspezialist aus Köln'
: locale === 'sr'
? 'Portfolio i blog Damjana Savića - AI developer i specijalista za automatizaciju iz Kelna'
: 'Portfolio and blog of Damjan Savić - AI Developer and Automation Specialist from Cologne',
publisher: {
'@id': `${baseUrl}/#organization`,
},
inLanguage: [
{ '@type': 'Language', name: 'German', alternateName: 'de' },
{ '@type': 'Language', name: 'English', alternateName: 'en' },
{ '@type': 'Language', name: 'Serbian', alternateName: 'sr' },
],
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
+1 -1
View File
@@ -12,4 +12,4 @@ export {
ProfilePageJsonLd,
VideoJsonLd,
SoftwareAppJsonLd,
} from './JsonLd';
} from './schemas';
@@ -0,0 +1,67 @@
import { type Locale } from '@/i18n/config';
interface ArticleJsonLdProps {
title: string;
description: string;
url: string;
imageUrl: string;
datePublished: string;
dateModified?: string;
authorName?: string;
tags?: string[];
locale: Locale;
}
export function ArticleJsonLd({
title,
description,
url,
imageUrl,
datePublished,
dateModified,
authorName = 'Damjan Savić',
tags = [],
locale,
}: ArticleJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: title,
description: description,
image: imageUrl.startsWith('http') ? imageUrl : `${baseUrl}${imageUrl}`,
url: url.startsWith('http') ? url : `${baseUrl}${url}`,
datePublished: datePublished,
dateModified: dateModified || datePublished,
author: {
'@type': 'Person',
'@id': `${baseUrl}/#person`,
name: authorName,
url: baseUrl,
},
publisher: {
'@type': 'Organization',
'@id': `${baseUrl}/#organization`,
name: 'Damjan Savić',
logo: {
'@type': 'ImageObject',
url: `${baseUrl}/images/og-image.jpg`,
},
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': url.startsWith('http') ? url : `${baseUrl}${url}`,
},
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
keywords: tags.join(', '),
articleSection: 'Technology',
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,30 @@
import { type Locale } from '@/i18n/config';
export function BreadcrumbJsonLd({
items,
locale,
}: {
items: { name: string; url: string }[];
locale: Locale;
}) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url.startsWith('http') ? item.url : `${baseUrl}${item.url}`,
})),
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
+29
View File
@@ -0,0 +1,29 @@
import { type Locale } from '@/i18n/config';
interface FAQItem {
question: string;
answer: string;
}
export function FAQJsonLd({ items, locale }: { items: FAQItem[]; locale?: Locale }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
inLanguage: locale ? (locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US') : 'de-DE',
mainEntity: items.map((item) => ({
'@type': 'Question',
name: item.question,
acceptedAnswer: {
'@type': 'Answer',
text: item.answer,
},
})),
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,87 @@
import { type Locale } from '@/i18n/config';
interface HowToStep {
name: string;
text: string;
url?: string;
image?: string;
}
interface HowToJsonLdProps {
name: string;
description: string;
steps: HowToStep[];
totalTime?: string; // ISO 8601 duration format, e.g., "PT30M" for 30 minutes
estimatedCost?: { currency: string; value: string };
tools?: string[];
supplies?: string[];
image?: string;
locale: Locale;
}
export function HowToJsonLd({
name,
description,
steps,
totalTime,
estimatedCost,
tools,
supplies,
image,
locale,
}: HowToJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema: Record<string, unknown> = {
'@context': 'https://schema.org',
'@type': 'HowTo',
name: name,
description: description,
step: steps.map((step, index) => ({
'@type': 'HowToStep',
position: index + 1,
name: step.name,
text: step.text,
...(step.url && { url: step.url.startsWith('http') ? step.url : `${baseUrl}${step.url}` }),
...(step.image && { image: step.image.startsWith('http') ? step.image : `${baseUrl}${step.image}` }),
})),
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
};
if (totalTime) {
schema.totalTime = totalTime;
}
if (estimatedCost) {
schema.estimatedCost = {
'@type': 'MonetaryAmount',
currency: estimatedCost.currency,
value: estimatedCost.value,
};
}
if (tools && tools.length > 0) {
schema.tool = tools.map((tool) => ({
'@type': 'HowToTool',
name: tool,
}));
}
if (supplies && supplies.length > 0) {
schema.supply = supplies.map((supply) => ({
'@type': 'HowToSupply',
name: supply,
}));
}
if (image) {
schema.image = image.startsWith('http') ? image : `${baseUrl}${image}`;
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,81 @@
import { type Locale } from '@/i18n/config';
interface JsonLdProps {
locale: Locale;
}
export function OrganizationJsonLd({ locale }: JsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'Organization',
'@id': `${baseUrl}/#organization`,
name: 'Damjan Savić - AI & Automation Specialist',
alternateName: 'Damjan Savić',
url: baseUrl,
logo: {
'@type': 'ImageObject',
url: `${baseUrl}/images/og-image.jpg`,
width: 1200,
height: 630,
},
image: `${baseUrl}/images/og-image.jpg`,
description: locale === 'de'
? 'Freelance KI-Entwickler und Automatisierungsspezialist aus Köln. Spezialisiert auf KI-Agenten, Voice AI, Prozessautomatisierung mit n8n und SaaS-Entwicklung.'
: locale === 'sr'
? 'Freelance AI developer i specijalista za automatizaciju iz Kelna. Specijalizovan za AI agente, Voice AI, automatizaciju procesa sa n8n i SaaS razvoj.'
: 'Remote AI developer and automation specialist based in Germany. Working with clients in USA, UK & Europe. Specialized in AI agents, Voice AI, n8n automation and SaaS development.',
email: 'info@damjan-savic.com',
telephone: '+491756950979',
address: {
'@type': 'PostalAddress',
streetAddress: 'Rotdornallee',
addressLocality: locale === 'sr' ? 'Keln' : locale === 'en' ? 'Cologne' : 'Köln',
addressRegion: 'NRW',
postalCode: '50769',
addressCountry: 'DE',
},
geo: {
'@type': 'GeoCoordinates',
latitude: 50.9375,
longitude: 6.9603,
},
areaServed: [
// DACH Region
{ '@type': 'Country', name: 'Germany' },
{ '@type': 'Country', name: 'Austria' },
{ '@type': 'Country', name: 'Switzerland' },
// International (Remote)
{ '@type': 'Country', name: 'United States' },
{ '@type': 'Country', name: 'United Kingdom' },
{ '@type': 'Country', name: 'Serbia' },
// Major International Cities
{ '@type': 'City', name: 'New York' },
{ '@type': 'City', name: 'London' },
{ '@type': 'City', name: 'San Francisco' },
{ '@type': 'City', name: 'Los Angeles' },
],
founder: {
'@id': `${baseUrl}/#person`,
},
sameAs: [
'https://www.linkedin.com/in/damjansavic/',
'https://github.com/damjansavic',
],
contactPoint: {
'@type': 'ContactPoint',
contactType: 'customer service',
email: 'info@damjan-savic.com',
telephone: '+491756950979',
availableLanguage: ['German', 'English', 'Serbian'],
},
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,80 @@
import { type Locale } from '@/i18n/config';
interface JsonLdProps {
locale: Locale;
}
export function PersonJsonLd({ locale }: JsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'Person',
'@id': `${baseUrl}/#person`,
name: 'Damjan Savić',
givenName: 'Damjan',
familyName: 'Savić',
jobTitle: locale === 'de'
? 'AI & Automation Specialist | Fullstack Entwickler'
: locale === 'sr'
? 'AI & Automation Specialist | Fullstack Developer'
: 'AI & Automation Specialist | Fullstack Developer',
description: locale === 'de'
? 'Entwicklung von KI-Agenten und Automatisierungslösungen. Von Voice-AI-Plattformen bis zu autonomen Web-Agenten.'
: locale === 'sr'
? 'Razvoj AI agenata i rešenja za automatizaciju. Od voice AI platformi do autonomnih web agenata.'
: 'Remote AI developer building AI agents and automation solutions for clients in USA, UK and Europe. From voice AI platforms to autonomous web agents.',
url: baseUrl,
image: `${baseUrl}/images/og-image.jpg`,
email: 'info@damjan-savic.com',
telephone: '+491756950979',
address: {
'@type': 'PostalAddress',
addressLocality: locale === 'sr' ? 'Keln' : locale === 'en' ? 'Cologne' : 'Köln',
addressRegion: 'NRW',
addressCountry: 'DE',
},
sameAs: [
'https://www.linkedin.com/in/damjansavic/',
'https://github.com/damjansavic',
],
knowsAbout: [
'Artificial Intelligence',
'Machine Learning',
'Process Automation',
'Voice AI',
'Web Development',
'Python',
'TypeScript',
'React',
'Next.js',
'n8n',
'SaaS Development',
],
alumniOf: [
{
'@type': 'EducationalOrganization',
name: 'FOM Hochschule für Ökonomie & Management',
},
],
hasCredential: [
{
'@type': 'EducationalOccupationalCredential',
name: 'M.A. Software Development',
credentialCategory: 'degree',
},
{
'@type': 'EducationalOccupationalCredential',
name: 'B.Sc. Wirtschaftsinformatik',
credentialCategory: 'degree',
},
],
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,116 @@
import { type Locale } from '@/i18n/config';
interface JsonLdProps {
locale: Locale;
}
export function ProfessionalServiceJsonLd({ locale }: JsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const serviceNames = {
de: [
'KI-Entwicklung',
'Prozessautomatisierung',
'Voice AI Entwicklung',
'SaaS Entwicklung',
'Fullstack Webentwicklung',
'n8n Automatisierung',
],
en: [
'AI Development',
'Process Automation',
'Voice AI Development',
'SaaS Development',
'Fullstack Web Development',
'n8n Automation',
],
sr: [
'AI Razvoj',
'Automatizacija procesa',
'Voice AI Razvoj',
'SaaS Razvoj',
'Fullstack Web Razvoj',
'n8n Automatizacija',
],
};
const schema = {
'@context': 'https://schema.org',
'@type': 'ProfessionalService',
'@id': `${baseUrl}/#business`,
name: 'Damjan Savić - AI & Automation Specialist',
description: locale === 'de'
? 'Freelance AI & Automation Specialist aus Köln. Spezialisiert auf KI-Agenten, Voice AI, Prozessautomatisierung und SaaS-Entwicklung.'
: locale === 'sr'
? 'Freelance AI & Automation Specialist iz Kelna. Specijalizovan za AI agente, Voice AI, automatizaciju procesa i SaaS razvoj.'
: 'Remote AI & Automation Specialist based in Germany, serving clients in USA, UK and Europe. Specialized in AI agents, Voice AI, n8n process automation and custom SaaS development.',
url: baseUrl,
logo: `${baseUrl}/images/og-image.jpg`,
image: `${baseUrl}/images/og-image.jpg`,
email: 'info@damjan-savic.com',
telephone: '+491756950979',
priceRange: '€€€',
address: {
'@type': 'PostalAddress',
streetAddress: 'Rotdornallee',
addressLocality: locale === 'sr' ? 'Keln' : locale === 'en' ? 'Cologne' : 'Köln',
addressRegion: 'NRW',
postalCode: '50769',
addressCountry: 'DE',
},
geo: {
'@type': 'GeoCoordinates',
latitude: 50.9375,
longitude: 6.9603,
},
areaServed: [
// Germany
{ '@type': 'City', name: 'Cologne' },
{ '@type': 'City', name: 'Düsseldorf' },
{ '@type': 'City', name: 'Frankfurt' },
{ '@type': 'City', name: 'Munich' },
{ '@type': 'City', name: 'Berlin' },
{ '@type': 'City', name: 'Hamburg' },
{ '@type': 'Country', name: 'Germany' },
// USA
{ '@type': 'City', name: 'New York' },
{ '@type': 'City', name: 'Los Angeles' },
{ '@type': 'City', name: 'San Francisco' },
{ '@type': 'City', name: 'Miami' },
{ '@type': 'City', name: 'Chicago' },
{ '@type': 'Country', name: 'United States' },
// UK
{ '@type': 'City', name: 'London' },
{ '@type': 'Country', name: 'United Kingdom' },
// Europe
{ '@type': 'Country', name: 'Austria' },
{ '@type': 'Country', name: 'Switzerland' },
],
hasOfferCatalog: {
'@type': 'OfferCatalog',
name: locale === 'de' ? 'Dienstleistungen' : locale === 'sr' ? 'Usluge' : 'Services',
itemListElement: serviceNames[locale].map((service, index) => ({
'@type': 'Offer',
itemOffered: {
'@type': 'Service',
name: service,
},
position: index + 1,
})),
},
founder: {
'@id': `${baseUrl}/#person`,
},
sameAs: [
'https://www.linkedin.com/in/damjansavic/',
'https://github.com/damjansavic',
],
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,38 @@
import { type Locale } from '@/i18n/config';
interface ProfilePageJsonLdProps {
locale: Locale;
}
export function ProfilePageJsonLd({ locale }: ProfilePageJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'ProfilePage',
dateCreated: '2024-01-01',
dateModified: new Date().toISOString().split('T')[0],
mainEntity: {
'@id': `${baseUrl}/#person`,
},
name: locale === 'de'
? 'Über Damjan Savić - KI-Entwickler & Automatisierungsspezialist'
: locale === 'sr'
? 'O Damjanu Saviću - AI Developer & Specijalista za automatizaciju'
: 'About Damjan Savić - AI Developer & Automation Specialist',
description: locale === 'de'
? 'Erfahren Sie mehr über Damjan Savić, Freelance KI-Entwickler und Automatisierungsspezialist aus Köln. Expertise in KI-Agenten, Voice AI, n8n und SaaS-Entwicklung.'
: locale === 'sr'
? 'Saznajte više o Damjanu Saviću, freelance AI developeru i specijalisti za automatizaciju iz Kelna. Ekspertiza u AI agentima, Voice AI, n8n i SaaS razvoju.'
: 'Learn more about Damjan Savić, freelance AI developer and automation specialist from Cologne. Expertise in AI agents, Voice AI, n8n and SaaS development.',
url: `${baseUrl}/${locale}/about`,
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,44 @@
import { type Locale } from '@/i18n/config';
interface ServiceJsonLdProps {
name: string;
description: string;
url: string;
locale: Locale;
areaServed?: string[];
}
export function ServiceJsonLd({
name,
description,
url,
locale,
areaServed = ['Köln', 'Düsseldorf', 'Frankfurt', 'Deutschland'],
}: ServiceJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'Service',
name: name,
description: description,
url: url.startsWith('http') ? url : `${baseUrl}${url}`,
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
availableLanguage: ['de-DE', 'en-US', 'sr-RS'],
provider: {
'@id': `${baseUrl}/#business`,
},
areaServed: areaServed.map((area) => ({
'@type': 'City',
name: area,
})),
serviceType: name,
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,65 @@
import { type Locale } from '@/i18n/config';
interface SoftwareAppJsonLdProps {
name: string;
description: string;
applicationCategory: string;
operatingSystem?: string;
offers?: {
price: string;
priceCurrency: string;
};
aggregateRating?: {
ratingValue: string;
ratingCount: string;
};
locale: Locale;
}
export function SoftwareAppJsonLd({
name,
description,
applicationCategory,
operatingSystem = 'Web',
offers,
aggregateRating,
locale,
}: SoftwareAppJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema: Record<string, unknown> = {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: name,
description: description,
applicationCategory: applicationCategory,
operatingSystem: operatingSystem,
author: {
'@id': `${baseUrl}/#person`,
},
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
};
if (offers) {
schema.offers = {
'@type': 'Offer',
price: offers.price,
priceCurrency: offers.priceCurrency,
};
}
if (aggregateRating) {
schema.aggregateRating = {
'@type': 'AggregateRating',
ratingValue: aggregateRating.ratingValue,
ratingCount: aggregateRating.ratingCount,
};
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,58 @@
import { type Locale } from '@/i18n/config';
// VideoObject Schema for embedded videos
interface VideoJsonLdProps {
name: string;
description: string;
thumbnailUrl: string;
uploadDate: string;
duration?: string; // ISO 8601 format, e.g., "PT1M30S"
contentUrl?: string;
embedUrl?: string;
locale: Locale;
}
export function VideoJsonLd({
name,
description,
thumbnailUrl,
uploadDate,
duration,
contentUrl,
embedUrl,
locale,
}: VideoJsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema: Record<string, unknown> = {
'@context': 'https://schema.org',
'@type': 'VideoObject',
name: name,
description: description,
thumbnailUrl: thumbnailUrl.startsWith('http') ? thumbnailUrl : `${baseUrl}${thumbnailUrl}`,
uploadDate: uploadDate,
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
author: {
'@id': `${baseUrl}/#person`,
},
};
if (duration) {
schema.duration = duration;
}
if (contentUrl) {
schema.contentUrl = contentUrl;
}
if (embedUrl) {
schema.embedUrl = embedUrl;
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,39 @@
import { type Locale } from '@/i18n/config';
export function WebPageJsonLd({
title,
description,
url,
locale,
}: {
title: string;
description: string;
url: string;
locale: Locale;
}) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'WebPage',
name: title,
description: description,
url: url.startsWith('http') ? url : `${baseUrl}${url}`,
inLanguage: locale === 'de' ? 'de-DE' : locale === 'sr' ? 'sr-RS' : 'en-US',
isPartOf: {
'@type': 'WebSite',
name: 'Damjan Savić',
url: baseUrl,
},
author: {
'@id': `${baseUrl}/#person`,
},
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
@@ -0,0 +1,43 @@
import { type Locale } from '@/i18n/config';
interface JsonLdProps {
locale: Locale;
}
// WebSite Schema for Search Box
export function WebSiteJsonLd({ locale }: JsonLdProps) {
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://damjan-savic.com';
const schema = {
'@context': 'https://schema.org',
'@type': 'WebSite',
'@id': `${baseUrl}/#website`,
name: 'Damjan Savić',
alternateName: locale === 'de'
? 'Damjan Savić - KI Entwickler Köln'
: locale === 'sr'
? 'Damjan Savić - AI Developer Keln'
: 'Damjan Savić - AI Developer Cologne',
url: baseUrl,
description: locale === 'de'
? 'Portfolio und Blog von Damjan Savić - KI-Entwickler und Automatisierungsspezialist aus Köln'
: locale === 'sr'
? 'Portfolio i blog Damjana Savića - AI developer i specijalista za automatizaciju iz Kelna'
: 'Portfolio and blog of Damjan Savić - AI Developer and Automation Specialist from Cologne',
publisher: {
'@id': `${baseUrl}/#organization`,
},
inLanguage: [
{ '@type': 'Language', name: 'German', alternateName: 'de' },
{ '@type': 'Language', name: 'English', alternateName: 'en' },
{ '@type': 'Language', name: 'Serbian', alternateName: 'sr' },
],
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
+13
View File
@@ -0,0 +1,13 @@
export { PersonJsonLd } from './PersonJsonLd';
export { WebSiteJsonLd } from './WebSiteJsonLd';
export { ProfessionalServiceJsonLd } from './ProfessionalServiceJsonLd';
export { BreadcrumbJsonLd } from './BreadcrumbJsonLd';
export { WebPageJsonLd } from './WebPageJsonLd';
export { FAQJsonLd } from './FAQJsonLd';
export { ServiceJsonLd } from './ServiceJsonLd';
export { OrganizationJsonLd } from './OrganizationJsonLd';
export { ArticleJsonLd } from './ArticleJsonLd';
export { HowToJsonLd } from './HowToJsonLd';
export { ProfilePageJsonLd } from './ProfilePageJsonLd';
export { VideoJsonLd } from './VideoJsonLd';
export { SoftwareAppJsonLd } from './SoftwareAppJsonLd';