- Schema.org JSON-LD templates (product, event, local-business, faq) - Brand, UI, SEO, and decision guide rules - Working code snippets (vendor-card, schema-inject, deploy-webhook) - JSON schemas for project config validation - Client presets (slc-bride, default) - Self-update protocol with changelog tracking Made-with: Cursor
99 lines
2.5 KiB
TypeScript
99 lines
2.5 KiB
TypeScript
/**
|
|
* Schema Injection Utility
|
|
* Injects JSON-LD structured data into page head
|
|
*/
|
|
|
|
// Schema type definitions
|
|
export type SchemaType = 'Product' | 'Event' | 'LocalBusiness' | 'FAQPage' | 'Article' | 'Organization'
|
|
|
|
interface SchemaConfig {
|
|
type: SchemaType
|
|
data: Record<string, unknown>
|
|
}
|
|
|
|
/**
|
|
* Generates JSON-LD script tag for structured data
|
|
*/
|
|
export function generateSchemaScript(config: SchemaConfig | SchemaConfig[]): string {
|
|
const schemas = Array.isArray(config) ? config : [config]
|
|
|
|
const structuredData = schemas.map(({ type, data }) => ({
|
|
'@context': 'https://schema.org',
|
|
'@type': type,
|
|
...data,
|
|
}))
|
|
|
|
// Return single schema or array
|
|
const output = structuredData.length === 1 ? structuredData[0] : structuredData
|
|
|
|
return JSON.stringify(output)
|
|
}
|
|
|
|
/**
|
|
* React component for injecting schema in Next.js
|
|
*/
|
|
export function SchemaInjector({ config }: { config: SchemaConfig | SchemaConfig[] }) {
|
|
const schemaJson = generateSchemaScript(config)
|
|
|
|
return (
|
|
<script
|
|
type="application/ld+json"
|
|
dangerouslySetInnerHTML={{ __html: schemaJson }}
|
|
/>
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Server-side schema generation for getServerSideProps / getStaticProps
|
|
*/
|
|
export function getSchemaForPage(
|
|
type: SchemaType,
|
|
data: Record<string, unknown>
|
|
): { __html: string } {
|
|
return {
|
|
__html: generateSchemaScript({ type, data }),
|
|
}
|
|
}
|
|
|
|
// Example usage in Next.js page:
|
|
//
|
|
// import { SchemaInjector } from '@/lib/schema-inject'
|
|
//
|
|
// export default function VendorPage({ vendor }) {
|
|
// return (
|
|
// <>
|
|
// <Head>
|
|
// <SchemaInjector
|
|
// config={{
|
|
// type: 'LocalBusiness',
|
|
// data: {
|
|
// name: vendor.name,
|
|
// description: vendor.description,
|
|
// address: {
|
|
// '@type': 'PostalAddress',
|
|
// streetAddress: vendor.address,
|
|
// addressLocality: vendor.city,
|
|
// addressRegion: vendor.state,
|
|
// },
|
|
// aggregateRating: {
|
|
// '@type': 'AggregateRating',
|
|
// ratingValue: vendor.rating,
|
|
// reviewCount: vendor.review_count,
|
|
// },
|
|
// },
|
|
// }}
|
|
// />
|
|
// </Head>
|
|
// {/* Page content */}
|
|
// </>
|
|
// )
|
|
// }
|
|
|
|
// Example for multiple schemas on one page:
|
|
//
|
|
// <SchemaInjector
|
|
// config={[
|
|
// { type: 'LocalBusiness', data: businessData },
|
|
// { type: 'FAQPage', data: faqData },
|
|
// ]}
|
|
// />
|