2 changed files with 77 additions and 56 deletions
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
import { Button } from '@/components/ui/button' |
||||
import { useEffect, useRef, useState } from 'react' |
||||
import { useTranslation } from 'react-i18next' |
||||
|
||||
export default function Collapsible({ |
||||
alwaysExpand = false, |
||||
children, |
||||
threshold = 1000, |
||||
collapsedHeight = 600, |
||||
...props |
||||
}: { |
||||
alwaysExpand?: boolean |
||||
threshold?: number |
||||
collapsedHeight?: number |
||||
} & React.HTMLProps<HTMLDivElement>) { |
||||
const { t } = useTranslation() |
||||
const containerRef = useRef<HTMLDivElement>(null) |
||||
const [expanded, setExpanded] = useState(false) |
||||
const [shouldCollapse, setShouldCollapse] = useState(false) |
||||
|
||||
useEffect(() => { |
||||
if (alwaysExpand || shouldCollapse) return |
||||
|
||||
const contentEl = containerRef.current |
||||
if (!contentEl) return |
||||
|
||||
const checkHeight = () => { |
||||
const fullHeight = contentEl.scrollHeight |
||||
if (fullHeight > threshold) { |
||||
setShouldCollapse(true) |
||||
} |
||||
} |
||||
|
||||
checkHeight() |
||||
|
||||
const observer = new ResizeObserver(() => { |
||||
checkHeight() |
||||
}) |
||||
|
||||
observer.observe(contentEl) |
||||
|
||||
return () => { |
||||
observer.disconnect() |
||||
} |
||||
}, [alwaysExpand, shouldCollapse]) |
||||
|
||||
return ( |
||||
<div ref={containerRef} {...props}> |
||||
<div |
||||
className="relative text-left overflow-hidden" |
||||
style={{ |
||||
maxHeight: !shouldCollapse || expanded ? 'none' : `${collapsedHeight}px` |
||||
}} |
||||
> |
||||
{children} |
||||
{shouldCollapse && !expanded && ( |
||||
<div className="absolute bottom-0 h-40 w-full bg-gradient-to-b from-transparent to-background/90 flex items-end justify-center pb-4"> |
||||
<div className="bg-background rounded-md"> |
||||
<Button |
||||
className="bg-foreground hover:bg-foreground/80" |
||||
onClick={(e) => { |
||||
e.stopPropagation() |
||||
setExpanded(!expanded) |
||||
}} |
||||
> |
||||
{t('Show more')} |
||||
</Button> |
||||
</div> |
||||
</div> |
||||
)} |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
Loading…
Reference in new issue