diff --git a/context.json b/context.json
new file mode 100644
index 0000000..a4607ec
--- /dev/null
+++ b/context.json
@@ -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"
+ ]
+ }
+}
diff --git a/project_index.json b/project_index.json
new file mode 100644
index 0000000..fe6dec7
--- /dev/null
+++ b/project_index.json
@@ -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 }"
+ }
+}
diff --git a/src/components/seo/JsonLd.tsx b/src/components/seo/JsonLd.tsx
deleted file mode 100644
index bf55752..0000000
--- a/src/components/seo/JsonLd.tsx
+++ /dev/null
@@ -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 (
-
- );
-}
-
-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 (
-
- );
-}
-
-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 (
-
- );
-}
-
-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 (
-
- );
-}
-
-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 (
-
- );
-}
-
-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 (
-
- );
-}
-
-// 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 (
-
- );
-}
-
-// 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 (
-
- );
-}
-
-// 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 = {
- '@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 (
-
- );
-}
-
-// 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 (
-
- );
-}
-
-// 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 = {
- '@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 (
-
- );
-}
-
-// 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 = {
- '@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 (
-
- );
-}
-
-// 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 (
-
- );
-}
diff --git a/src/components/seo/index.ts b/src/components/seo/index.ts
index ef4bc7f..76f1740 100644
--- a/src/components/seo/index.ts
+++ b/src/components/seo/index.ts
@@ -12,4 +12,4 @@ export {
ProfilePageJsonLd,
VideoJsonLd,
SoftwareAppJsonLd,
-} from './JsonLd';
+} from './schemas';
diff --git a/src/components/seo/schemas/ArticleJsonLd.tsx b/src/components/seo/schemas/ArticleJsonLd.tsx
new file mode 100644
index 0000000..c3ea997
--- /dev/null
+++ b/src/components/seo/schemas/ArticleJsonLd.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/BreadcrumbJsonLd.tsx b/src/components/seo/schemas/BreadcrumbJsonLd.tsx
new file mode 100644
index 0000000..7765e86
--- /dev/null
+++ b/src/components/seo/schemas/BreadcrumbJsonLd.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/FAQJsonLd.tsx b/src/components/seo/schemas/FAQJsonLd.tsx
new file mode 100644
index 0000000..f6db9d0
--- /dev/null
+++ b/src/components/seo/schemas/FAQJsonLd.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/HowToJsonLd.tsx b/src/components/seo/schemas/HowToJsonLd.tsx
new file mode 100644
index 0000000..98d022b
--- /dev/null
+++ b/src/components/seo/schemas/HowToJsonLd.tsx
@@ -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 = {
+ '@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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/OrganizationJsonLd.tsx b/src/components/seo/schemas/OrganizationJsonLd.tsx
new file mode 100644
index 0000000..049fe90
--- /dev/null
+++ b/src/components/seo/schemas/OrganizationJsonLd.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/PersonJsonLd.tsx b/src/components/seo/schemas/PersonJsonLd.tsx
new file mode 100644
index 0000000..9cd9aba
--- /dev/null
+++ b/src/components/seo/schemas/PersonJsonLd.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/ProfessionalServiceJsonLd.tsx b/src/components/seo/schemas/ProfessionalServiceJsonLd.tsx
new file mode 100644
index 0000000..e272b68
--- /dev/null
+++ b/src/components/seo/schemas/ProfessionalServiceJsonLd.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/ProfilePageJsonLd.tsx b/src/components/seo/schemas/ProfilePageJsonLd.tsx
new file mode 100644
index 0000000..3da5ab2
--- /dev/null
+++ b/src/components/seo/schemas/ProfilePageJsonLd.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/ServiceJsonLd.tsx b/src/components/seo/schemas/ServiceJsonLd.tsx
new file mode 100644
index 0000000..4fcffd5
--- /dev/null
+++ b/src/components/seo/schemas/ServiceJsonLd.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/SoftwareAppJsonLd.tsx b/src/components/seo/schemas/SoftwareAppJsonLd.tsx
new file mode 100644
index 0000000..f355ec0
--- /dev/null
+++ b/src/components/seo/schemas/SoftwareAppJsonLd.tsx
@@ -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 = {
+ '@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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/VideoJsonLd.tsx b/src/components/seo/schemas/VideoJsonLd.tsx
new file mode 100644
index 0000000..0fddfb3
--- /dev/null
+++ b/src/components/seo/schemas/VideoJsonLd.tsx
@@ -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 = {
+ '@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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/WebPageJsonLd.tsx b/src/components/seo/schemas/WebPageJsonLd.tsx
new file mode 100644
index 0000000..67a0127
--- /dev/null
+++ b/src/components/seo/schemas/WebPageJsonLd.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/WebSiteJsonLd.tsx b/src/components/seo/schemas/WebSiteJsonLd.tsx
new file mode 100644
index 0000000..b1d4916
--- /dev/null
+++ b/src/components/seo/schemas/WebSiteJsonLd.tsx
@@ -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 (
+
+ );
+}
diff --git a/src/components/seo/schemas/index.ts b/src/components/seo/schemas/index.ts
new file mode 100644
index 0000000..74216ae
--- /dev/null
+++ b/src/components/seo/schemas/index.ts
@@ -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';