222 lines
4.9 KiB
TypeScript
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,
|
|
}
|
|
}
|