diff --git a/src/lib/utils/content.ts b/src/lib/utils/content.ts index b3043cf..8f76037 100644 --- a/src/lib/utils/content.ts +++ b/src/lib/utils/content.ts @@ -1,3 +1,5 @@ +import type { TiptapNode, EditorData } from '$lib/types/editor' + // Content node types for rendering interface ContentNode { type: string @@ -10,9 +12,16 @@ interface ContentNode { caption?: string language?: string mediaId?: number + marks?: Mark[] [key: string]: unknown } +// Mark types (bold, italic, link, etc.) +interface Mark { + type: string + attrs?: Record +} + // Render Edra/BlockNote JSON content to HTML export const renderEdraContent = (content: unknown, options: { albumSlug?: string } = {}): string => { if (!content) return '' @@ -290,15 +299,15 @@ function renderTiptapContent(doc: Record): string { } // Render inline content (text nodes with marks) - const renderInlineContent = (content: any[]): string => { + const renderInlineContent = (content: ContentNode[]): string => { return content - .map((node: any) => { + .map((node: ContentNode) => { if (node.type === 'text') { let text = escapeHtml(node.text || '') // Apply marks (bold, italic, etc.) if (node.marks) { - node.marks.forEach((mark: any) => { + node.marks.forEach((mark: Mark) => { switch (mark.type) { case 'bold': text = `${text}` @@ -351,16 +360,19 @@ function renderTiptapContent(doc: Record): string { } // Extract text content from Edra JSON for excerpt -export const getContentExcerpt = (content: any, maxLength = 200): string => { +export const getContentExcerpt = (content: EditorData | unknown, maxLength = 200): string => { if (!content) return '' + // Type guard for content object + const contentObj = content as Record + // Handle Tiptap format first (has type: 'doc') - if (content.type === 'doc' && content.content) { - return extractTiptapText(content, maxLength) + if (contentObj.type === 'doc' && contentObj.content) { + return extractTiptapText(contentObj, maxLength) } // Handle both { blocks: [...] } and { content: [...] } formats - const blocks = content.blocks || content.content || [] + const blocks = (contentObj.blocks || contentObj.content || []) as ContentNode[] if (!Array.isArray(blocks)) return '' const extractText = (node: ContentNode): string => { @@ -383,8 +395,8 @@ export const getContentExcerpt = (content: any, maxLength = 200): string => { } // Extract text from Tiptap content -function extractTiptapText(doc: any, maxLength: number): string { - const extractFromNode = (node: any): string => { +function extractTiptapText(doc: Record, maxLength: number): string { + const extractFromNode = (node: ContentNode): string => { if (node.type === 'text') { return node.text || '' } @@ -396,7 +408,8 @@ function extractTiptapText(doc: any, maxLength: number): string { return '' } - const text = doc.content.map(extractFromNode).join(' ').trim() + const content = doc.content as ContentNode[] + const text = content.map(extractFromNode).join(' ').trim() if (text.length <= maxLength) return text return text.substring(0, maxLength).trim() + '...' } diff --git a/src/lib/utils/metadata.ts b/src/lib/utils/metadata.ts index b768491..de3ce44 100644 --- a/src/lib/utils/metadata.ts +++ b/src/lib/utils/metadata.ts @@ -1,3 +1,6 @@ +// JSON-LD structured data object type +type JsonLdObject = Record + interface MetaTagsOptions { title?: string description?: string @@ -16,7 +19,7 @@ interface MetaTagsOptions { locale?: string canonicalUrl?: string noindex?: boolean - jsonLd?: Record + jsonLd?: JsonLdObject } interface GeneratedMetaTags { @@ -25,7 +28,7 @@ interface GeneratedMetaTags { openGraph: Record twitter: Record other: Record - jsonLd?: Record + jsonLd?: JsonLdObject } const DEFAULTS = { @@ -197,10 +200,10 @@ export function generatePersonJsonLd(options: { jobTitle?: string description?: string sameAs?: string[] -}): Record { +}): JsonLdObject { const { name, url = DEFAULTS.siteUrl, image, jobTitle, description, sameAs = [] } = options - const jsonLd: Record = { + const jsonLd: JsonLdObject = { '@context': 'https://schema.org', '@type': 'Person', name, @@ -237,10 +240,10 @@ export function generateArticleJsonLd(options: { datePublished?: string dateModified?: string author?: string -}): Record { +}): JsonLdObject { const { title, description, url, image, datePublished, dateModified, author } = options - const jsonLd: Record = { + const jsonLd: JsonLdObject = { '@context': 'https://schema.org', '@type': 'Article', headline: title, @@ -291,10 +294,10 @@ export function generateImageGalleryJsonLd(options: { url: string caption?: string }> -}): Record { +}): JsonLdObject { const { name, description, url, images } = options - const jsonLd: Record = { + const jsonLd: JsonLdObject = { '@context': 'https://schema.org', '@type': 'ImageGallery', name, @@ -327,10 +330,10 @@ export function generateCreativeWorkJsonLd(options: { creator?: string dateCreated?: string keywords?: string[] -}): Record { +}): JsonLdObject { const { name, description, url, image, creator, dateCreated, keywords = [] } = options - const jsonLd: Record = { + const jsonLd: JsonLdObject = { '@context': 'https://schema.org', '@type': 'CreativeWork', name,