Files
web-temp/layers/composables/useSchema.ts

222 lines
4.9 KiB
TypeScript

/**
* Schema.org 구조화된 데이터 유틸리티
*
* Schema.org 마크업을 쉽게 추가하고 관리하기 위한 composable
*
* @example
* ```ts
* const { addSchema, addVideoSchema, addImageGallerySchema } = useSchema()
*
* // 커스텀 스키마 추가
* addSchema({
* '@context': 'https://schema.org',
* '@type': 'Article',
* headline: 'My Article'
* })
*
* // 비디오 스키마 추가
* addVideoSchema({
* name: 'Video Title',
* description: 'Video Description',
* thumbnailUrl: 'https://example.com/thumb.jpg',
* uploadDate: '2025-01-01',
* contentUrl: 'https://youtube.com/watch?v=xxx'
* })
* ```
*/
export const useSchema = () => {
const gameDataStore = useGameDataStore()
const { gameName } = storeToRefs(gameDataStore)
/**
* 커스텀 Schema.org JSON-LD를 head에 추가
*/
const addSchema = (schema: Record<string, any>) => {
useHead({
script: [
{
type: 'application/ld+json',
innerHTML: JSON.stringify(schema),
},
],
})
}
/**
* VideoObject Schema 생성 및 추가
*/
const addVideoSchema = (options: {
name: string
description?: string
thumbnailUrl: string
uploadDate: string
contentUrl: string
embedUrl?: string
}) => {
const schema = {
'@context': 'https://schema.org',
'@type': 'VideoObject',
name: options.name,
description: options.description || options.name,
thumbnailUrl: options.thumbnailUrl,
uploadDate: options.uploadDate,
contentUrl: options.contentUrl,
embedUrl: options.embedUrl || options.contentUrl,
publisher: {
'@type': 'Organization',
name: gameName.value,
},
}
addSchema(schema)
}
/**
* ImageGallery Schema 생성 및 추가
*/
const addImageGallerySchema = (
images: Array<{
contentUrl: string
caption?: string
}>
) => {
const schema = {
'@context': 'https://schema.org',
'@type': 'ImageGallery',
image: images.map(img => ({
'@type': 'ImageObject',
contentUrl: img.contentUrl,
caption: img.caption || '',
})),
}
addSchema(schema)
}
/**
* SoftwareApplication Schema 생성 및 추가
*/
const addSoftwareApplicationSchema = (options: {
name: string
operatingSystem: string
description?: string
price?: string
priceCurrency?: string
}) => {
const schema: Record<string, any> = {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: options.name,
operatingSystem: options.operatingSystem,
applicationCategory: 'GameApplication',
}
if (options.description) {
schema.description = options.description
}
if (options.price !== undefined) {
schema.offers = {
'@type': 'Offer',
price: options.price,
priceCurrency: options.priceCurrency || 'USD',
}
}
addSchema(schema)
}
/**
* Event Schema 생성 및 추가
*/
const addEventSchema = (options: {
name: string
startDate: string
endDate?: string
eventStatus?:
| 'EventScheduled'
| 'EventCancelled'
| 'EventMovedOnline'
| 'EventPostponed'
| 'EventRescheduled'
description?: string
image?: string
location?: string
}) => {
const schema: Record<string, any> = {
'@context': 'https://schema.org',
'@type': 'Event',
name: options.name,
startDate: options.startDate,
eventStatus: `https://schema.org/${options.eventStatus || 'EventScheduled'}`,
}
if (options.endDate) {
schema.endDate = options.endDate
}
if (options.description) {
schema.description = options.description
}
if (options.image) {
schema.image = options.image
}
if (options.location) {
schema.location = {
'@type': 'VirtualLocation',
url: options.location,
}
}
addSchema(schema)
}
/**
* Article Schema 생성 및 추가
*/
const addArticleSchema = (options: {
headline: string
datePublished: string
dateModified?: string
author?: string
description?: string
image?: string
}) => {
const schema: Record<string, any> = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: options.headline,
datePublished: options.datePublished,
author: {
'@type': 'Organization',
name: options.author || gameName.value,
},
}
if (options.dateModified) {
schema.dateModified = options.dateModified
}
if (options.description) {
schema.description = options.description
}
if (options.image) {
schema.image = options.image
}
addSchema(schema)
}
return {
addSchema,
addVideoSchema,
addImageGallerySchema,
addSoftwareApplicationSchema,
addEventSchema,
addArticleSchema,
}
}