wip: start fixing server utility any types
- add ContentNode interface for content rendering - replace any with proper types in content.ts (15 -> 6 errors) - use Record<string, unknown> for dynamic content objects - add type assertions for content arrays
This commit is contained in:
parent
93795577cd
commit
6408e7f85d
1 changed files with 29 additions and 13 deletions
|
|
@ -1,5 +1,20 @@
|
||||||
|
// Content node types for rendering
|
||||||
|
interface ContentNode {
|
||||||
|
type: string
|
||||||
|
attrs?: Record<string, unknown>
|
||||||
|
content?: ContentNode[] | string
|
||||||
|
text?: string
|
||||||
|
level?: number
|
||||||
|
src?: string
|
||||||
|
alt?: string
|
||||||
|
caption?: string
|
||||||
|
language?: string
|
||||||
|
mediaId?: number
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
|
||||||
// Render Edra/BlockNote JSON content to HTML
|
// Render Edra/BlockNote JSON content to HTML
|
||||||
export const renderEdraContent = (content: any, options: { albumSlug?: string } = {}): string => {
|
export const renderEdraContent = (content: unknown, options: { albumSlug?: string } = {}): string => {
|
||||||
if (!content) return ''
|
if (!content) return ''
|
||||||
|
|
||||||
// Handle Tiptap format first (has type: 'doc')
|
// Handle Tiptap format first (has type: 'doc')
|
||||||
|
|
@ -8,10 +23,11 @@ export const renderEdraContent = (content: any, options: { albumSlug?: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle both { blocks: [...] } and { content: [...] } formats
|
// Handle both { blocks: [...] } and { content: [...] } formats
|
||||||
const blocks = content.blocks || content.content || []
|
const contentObj = content as Record<string, unknown>
|
||||||
|
const blocks = (contentObj.blocks || contentObj.content || []) as ContentNode[]
|
||||||
if (!Array.isArray(blocks)) return ''
|
if (!Array.isArray(blocks)) return ''
|
||||||
|
|
||||||
const renderBlock = (block: any): string => {
|
const renderBlock = (block: ContentNode): string => {
|
||||||
switch (block.type) {
|
switch (block.type) {
|
||||||
case 'heading': {
|
case 'heading': {
|
||||||
const level = block.attrs?.level || block.level || 1
|
const level = block.attrs?.level || block.level || 1
|
||||||
|
|
@ -28,7 +44,7 @@ export const renderEdraContent = (content: any, options: { albumSlug?: string }
|
||||||
case 'bulletList':
|
case 'bulletList':
|
||||||
case 'ul': {
|
case 'ul': {
|
||||||
const listItems = (block.content || [])
|
const listItems = (block.content || [])
|
||||||
.map((item: any) => {
|
.map((item) => {
|
||||||
const itemText = item.content || item.text || ''
|
const itemText = item.content || item.text || ''
|
||||||
return `<li>${itemText}</li>`
|
return `<li>${itemText}</li>`
|
||||||
})
|
})
|
||||||
|
|
@ -39,7 +55,7 @@ export const renderEdraContent = (content: any, options: { albumSlug?: string }
|
||||||
case 'orderedList':
|
case 'orderedList':
|
||||||
case 'ol': {
|
case 'ol': {
|
||||||
const orderedItems = (block.content || [])
|
const orderedItems = (block.content || [])
|
||||||
.map((item: any) => {
|
.map((item) => {
|
||||||
const itemText = item.content || item.text || ''
|
const itemText = item.content || item.text || ''
|
||||||
return `<li>${itemText}</li>`
|
return `<li>${itemText}</li>`
|
||||||
})
|
})
|
||||||
|
|
@ -97,10 +113,10 @@ export const renderEdraContent = (content: any, options: { albumSlug?: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render Tiptap JSON content to HTML
|
// Render Tiptap JSON content to HTML
|
||||||
function renderTiptapContent(doc: any): string {
|
function renderTiptapContent(doc: Record<string, unknown>): string {
|
||||||
if (!doc || !doc.content) return ''
|
if (!doc || !doc.content) return ''
|
||||||
|
|
||||||
const renderNode = (node: any): string => {
|
const renderNode = (node: ContentNode): string => {
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'paragraph': {
|
case 'paragraph': {
|
||||||
const content = renderInlineContent(node.content || [])
|
const content = renderInlineContent(node.content || [])
|
||||||
|
|
@ -116,8 +132,8 @@ function renderTiptapContent(doc: any): string {
|
||||||
|
|
||||||
case 'bulletList': {
|
case 'bulletList': {
|
||||||
const items = (node.content || [])
|
const items = (node.content || [])
|
||||||
.map((item: any) => {
|
.map((item) => {
|
||||||
const itemContent = item.content?.map(renderNode).join('') || ''
|
const itemContent = item.content ? (item.content as ContentNode[]).map(renderNode) : [].join('') || ''
|
||||||
return `<li>${itemContent}</li>`
|
return `<li>${itemContent}</li>`
|
||||||
})
|
})
|
||||||
.join('')
|
.join('')
|
||||||
|
|
@ -126,8 +142,8 @@ function renderTiptapContent(doc: any): string {
|
||||||
|
|
||||||
case 'orderedList': {
|
case 'orderedList': {
|
||||||
const items = (node.content || [])
|
const items = (node.content || [])
|
||||||
.map((item: any) => {
|
.map((item) => {
|
||||||
const itemContent = item.content?.map(renderNode).join('') || ''
|
const itemContent = item.content ? (item.content as ContentNode[]).map(renderNode) : [].join('') || ''
|
||||||
return `<li>${itemContent}</li>`
|
return `<li>${itemContent}</li>`
|
||||||
})
|
})
|
||||||
.join('')
|
.join('')
|
||||||
|
|
@ -266,7 +282,7 @@ function renderTiptapContent(doc: any): string {
|
||||||
default: {
|
default: {
|
||||||
// For any unknown block types, try to render their content
|
// For any unknown block types, try to render their content
|
||||||
if (node.content) {
|
if (node.content) {
|
||||||
return node.content.map(renderNode).join('')
|
return Array.isArray(node.content) ? node.content.map(renderNode as (node: unknown) => string) : [].join('')
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
@ -346,7 +362,7 @@ export const getContentExcerpt = (content: any, maxLength = 200): string => {
|
||||||
const blocks = content.blocks || content.content || []
|
const blocks = content.blocks || content.content || []
|
||||||
if (!Array.isArray(blocks)) return ''
|
if (!Array.isArray(blocks)) return ''
|
||||||
|
|
||||||
const extractText = (node: any): string => {
|
const extractText = (node: ContentNode): string => {
|
||||||
// For block-level content
|
// For block-level content
|
||||||
if (node.type && node.content && typeof node.content === 'string') {
|
if (node.type && node.content && typeof node.content === 'string') {
|
||||||
return node.content
|
return node.content
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue