2024-11-08 09:23:57 -05:00
|
|
|
import { FC, useCallback, useRef, useState } from 'react'
|
2024-10-18 06:14:45 -04:00
|
|
|
import OLButton from '@/features/ui/components/ol/ol-button'
|
2024-08-12 05:50:54 -04:00
|
|
|
import { useTranslation } from 'react-i18next'
|
2024-11-08 09:23:57 -05:00
|
|
|
import classNames from 'classnames'
|
2024-08-12 05:50:54 -04:00
|
|
|
|
2024-11-08 09:23:57 -05:00
|
|
|
export const ExpandableContent: FC<{
|
|
|
|
className?: string
|
|
|
|
content: string
|
|
|
|
contentLimit?: number
|
|
|
|
newLineCharsLimit?: number
|
|
|
|
checkNewLines?: boolean
|
|
|
|
inline?: boolean
|
|
|
|
}> = ({
|
|
|
|
content,
|
2024-08-12 05:50:54 -04:00
|
|
|
className,
|
2024-11-08 09:23:57 -05:00
|
|
|
contentLimit = 50,
|
|
|
|
newLineCharsLimit = 3,
|
|
|
|
checkNewLines = true,
|
|
|
|
inline = false,
|
2024-08-12 05:50:54 -04:00
|
|
|
}) => {
|
|
|
|
const { t } = useTranslation()
|
|
|
|
const contentRef = useRef<HTMLDivElement>(null)
|
|
|
|
const [isExpanded, setIsExpanded] = useState(false)
|
2024-11-08 09:23:57 -05:00
|
|
|
const limit = checkNewLines
|
|
|
|
? Math.min(
|
|
|
|
contentLimit,
|
|
|
|
indexOfNthLine(content, newLineCharsLimit) ?? Infinity
|
2024-08-12 05:50:54 -04:00
|
|
|
)
|
2024-11-08 09:23:57 -05:00
|
|
|
: contentLimit
|
|
|
|
|
|
|
|
const isOverflowing = content.length > limit
|
2024-08-12 05:50:54 -04:00
|
|
|
|
|
|
|
const handleShowMore = useCallback(() => {
|
|
|
|
setIsExpanded(true)
|
|
|
|
contentRef.current?.dispatchEvent(
|
|
|
|
new CustomEvent('review-panel:position', { bubbles: true })
|
|
|
|
)
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
const handleShowLess = useCallback(() => {
|
|
|
|
setIsExpanded(false)
|
|
|
|
contentRef.current?.dispatchEvent(
|
|
|
|
new CustomEvent('review-panel:position', { bubbles: true })
|
|
|
|
)
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
return (
|
2024-11-08 09:23:57 -05:00
|
|
|
<>
|
2024-08-12 05:50:54 -04:00
|
|
|
<div
|
|
|
|
ref={contentRef}
|
2024-11-08 09:23:57 -05:00
|
|
|
className={classNames('review-panel-expandable-content', className)}
|
2024-08-12 05:50:54 -04:00
|
|
|
>
|
2024-11-08 09:23:57 -05:00
|
|
|
{isExpanded ? content : content.slice(0, limit)}
|
|
|
|
{isOverflowing && !isExpanded && '...'}
|
2024-08-12 05:50:54 -04:00
|
|
|
</div>
|
2024-11-08 09:23:57 -05:00
|
|
|
<div
|
|
|
|
className={classNames('review-panel-expandable-links', {
|
|
|
|
'review-panel-expandable-inline': inline,
|
|
|
|
})}
|
|
|
|
>
|
|
|
|
{isExpanded ? (
|
2024-10-18 06:14:45 -04:00
|
|
|
<OLButton
|
|
|
|
variant="link"
|
2024-08-12 05:50:54 -04:00
|
|
|
className="btn-inline-link"
|
2024-11-08 09:23:57 -05:00
|
|
|
onClick={handleShowLess}
|
2024-08-12 05:50:54 -04:00
|
|
|
>
|
2024-11-08 09:23:57 -05:00
|
|
|
{t('show_less')}
|
2024-10-18 06:14:45 -04:00
|
|
|
</OLButton>
|
2024-11-08 09:23:57 -05:00
|
|
|
) : (
|
|
|
|
isOverflowing && (
|
|
|
|
<OLButton
|
|
|
|
variant="link"
|
|
|
|
className="btn-inline-link"
|
|
|
|
onClick={handleShowMore}
|
|
|
|
>
|
|
|
|
{t('show_more')}
|
|
|
|
</OLButton>
|
|
|
|
)
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</>
|
2024-08-12 05:50:54 -04:00
|
|
|
)
|
|
|
|
}
|
2024-11-08 09:23:57 -05:00
|
|
|
|
|
|
|
function indexOfNthLine(content: string, n: number) {
|
|
|
|
if (n < 1) return null
|
|
|
|
|
|
|
|
let line = 0
|
|
|
|
for (let i = 0; i < content.length; i++) {
|
|
|
|
if (content[i] === '\n') {
|
|
|
|
line++
|
|
|
|
if (line === n) {
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|