From e38ed33a45de8ea6e4030a177b83e0ba813253ed Mon Sep 17 00:00:00 2001 From: pphatdev Date: Fri, 13 Mar 2026 10:40:45 +0700 Subject: [PATCH 1/6] fix: update structured data type and properties in AboutStructuredData component --- src/components/about-structured-data.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/about-structured-data.tsx b/src/components/about-structured-data.tsx index d068f2c..3e2af7b 100644 --- a/src/components/about-structured-data.tsx +++ b/src/components/about-structured-data.tsx @@ -13,9 +13,16 @@ import { export default function AboutStructuredData() { const structuredData = { "@context": "https://schema.org", - "@type": "AboutPage", + "@type": "ProfilePage", + "@id": `${NEXT_PUBLIC_APP_URL}/about`, + "name": `About ${appName}`, + "description": `I'm ${PERSON_NAME} (${PERSON_ALTERNATE_NAME}), a ${PERSON_JOB_TITLE}.`, + "url": `${NEXT_PUBLIC_APP_URL}/about`, + "dateCreated": "2021-01-01", + "dateModified": new Date().toISOString().split('T')[0], "mainEntity": { "@type": "Person", + "@id": `${NEXT_PUBLIC_APP_URL}#person`, "name": PERSON_NAME, "alternateName": PERSON_ALTERNATE_NAME, "description": `I'm ${PERSON_NAME} (${PERSON_ALTERNATE_NAME}), a ${PERSON_JOB_TITLE}.`, @@ -29,10 +36,7 @@ export default function AboutStructuredData() { GITHUB_URL, LINKEDIN_URL ] - }, - "name": `About ${appName}`, - "description": `I'm ${PERSON_NAME} (${PERSON_ALTERNATE_NAME}), a ${PERSON_JOB_TITLE}.`, - "url": `${NEXT_PUBLIC_APP_URL}/about` + } }; return ( From eda1f4fd9732fe2a873cead12c0996f7d4cdaf53 Mon Sep 17 00:00:00 2001 From: pphatdev Date: Fri, 13 Mar 2026 10:40:55 +0700 Subject: [PATCH 2/6] feat: add SoftwareApplicationStructuredData component for structured data integration --- .../data-structured/software-application.tsx | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/components/data-structured/software-application.tsx diff --git a/src/components/data-structured/software-application.tsx b/src/components/data-structured/software-application.tsx new file mode 100644 index 0000000..20acc41 --- /dev/null +++ b/src/components/data-structured/software-application.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import { NEXT_PUBLIC_APP_URL, PERSON_NAME, appName } from '@lib/constants'; + +interface SoftwareApplicationStructuredDataProps { + name: string; + description: string; + url: string; + repositoryUrl?: string; + applicationCategory?: string; + operatingSystem?: string; + screenshots?: string[]; + datePublished?: string; + keywords?: string[]; +} + +export default function SoftwareApplicationStructuredData({ + name, + description, + url, + repositoryUrl, + applicationCategory = 'WebApplication', + operatingSystem = 'Web Browser', + screenshots = [], + datePublished, + keywords = [] +}: SoftwareApplicationStructuredDataProps) { + const structuredData = { + "@context": "https://schema.org", + "@type": "SoftwareApplication", + "name": name, + "description": description, + "url": url, + "applicationCategory": applicationCategory, + "operatingSystem": operatingSystem, + "offers": { + "@type": "Offer", + "price": "0", + "priceCurrency": "USD" + }, + "author": { + "@type": "Person", + "@id": `${NEXT_PUBLIC_APP_URL}#person`, + "name": PERSON_NAME + }, + "creator": { + "@type": "Person", + "@id": `${NEXT_PUBLIC_APP_URL}#person`, + "name": PERSON_NAME + }, + "publisher": { + "@type": "Person", + "name": appName, + "url": NEXT_PUBLIC_APP_URL + }, + ...(datePublished && { "datePublished": datePublished }), + ...(keywords.length > 0 && { "keywords": keywords.join(', ') }), + ...(repositoryUrl && { "codeRepository": repositoryUrl }), + ...(screenshots.length > 0 && { + "screenshot": screenshots.map(src => ({ + "@type": "ImageObject", + "url": src.startsWith('http') ? src : `${NEXT_PUBLIC_APP_URL}${src}` + })) + }) + }; + + return ( +