truncateString = (str, maxLength, suffix = ' ...') => {
  if (!str || str.length <= maxLength) return str

  const effectiveLength = maxLength - suffix.length

  // Split into paragraphs and accumulate until we exceed the limit
  const paragraphs = str.split(/\n\n+/)
  let result = ''
  for (const paragraph of paragraphs) {
    if ((result + paragraph).length > effectiveLength) {
      // If this is the first paragraph and it's too long,
      // fall back to sentence/word breaking
      if (!result) {
        // Try to break at sentence
        const sentenceBreak = paragraph.slice(0, effectiveLength).match(/[.!?]\s+[A-Z]/g)
        if (sentenceBreak) {
          const lastBreak = paragraph.lastIndexOf(sentenceBreak[sentenceBreak.length - 1], effectiveLength)
          if (lastBreak > effectiveLength / 2) {
            return paragraph.slice(0, lastBreak + 1) + suffix
          }
        }

        // Try to break at word
        const wordBreak = paragraph.lastIndexOf(' ', effectiveLength)
        if (wordBreak > 0) {
          return paragraph.slice(0, wordBreak) + suffix
        }

        // Fall back to character break
        return paragraph.slice(0, effectiveLength) + suffix
      }
      return result.trim() + suffix
    }
    result += (result ? '\n\n' : '') + paragraph
  }

  return result
}
Truncates a string intelligently, trying to keep natural breaks
@param {string} str - The string to truncate
@param {number} maxLength - Maximum length of the result
@param {string} [suffix='...'] - String to append when truncated
@returns {string} Truncated string