Files
ragflow/web/src/components/collapse.tsx
balibabu 4910146149 Feat: Display the video field in the parser operator #9869 (#10728)
### What problem does this PR solve?

Feat: Display the video field in the parser operator #9869

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
2025-10-22 18:59:20 +08:00

128 lines
3.3 KiB
TypeScript

import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from '@/components/ui/collapsible';
import { cn } from '@/lib/utils';
import { CollapsibleProps } from '@radix-ui/react-collapsible';
import { ChevronDown, ChevronUp } from 'lucide-react';
import * as React from 'react';
import {
PropsWithChildren,
ReactNode,
useCallback,
useEffect,
useState,
} from 'react';
import { IconFontFill } from './icon-font';
type CollapseProps = Omit<CollapsibleProps, 'title'> & {
title?: ReactNode;
rightContent?: ReactNode;
} & PropsWithChildren;
export function Collapse({
title,
children,
rightContent,
open = true,
defaultOpen = false,
onOpenChange,
disabled,
}: CollapseProps) {
const [currentOpen, setCurrentOpen] = useState(open);
useEffect(() => {
setCurrentOpen(open);
}, [open]);
const handleOpenChange = useCallback(
(open: boolean) => {
setCurrentOpen(open);
onOpenChange?.(open);
},
[onOpenChange],
);
return (
<Collapsible
defaultOpen={defaultOpen}
open={currentOpen}
onOpenChange={handleOpenChange}
disabled={disabled}
>
<CollapsibleTrigger className={'w-full'}>
<section className="flex justify-between items-center">
<div className="flex items-center gap-1">
<IconFontFill
name={`more`}
className={cn('size-4', {
'rotate-90': !currentOpen,
})}
></IconFontFill>
<div
className={cn('text-text-secondary', {
'text-text-primary': open,
})}
>
{title}
</div>
</div>
<div>{rightContent}</div>
</section>
</CollapsibleTrigger>
<CollapsibleContent className="pt-2">{children}</CollapsibleContent>
</Collapsible>
);
}
export type NodeCollapsibleProps<T extends any[]> = {
items?: T;
children: (item: T[0], idx: number) => ReactNode;
className?: string;
};
export function NodeCollapsible<T extends any[]>({
items = [] as unknown as T,
children,
className,
}: NodeCollapsibleProps<T>) {
const [isOpen, setIsOpen] = React.useState(false);
const nextClassName = cn('space-y-2', className);
const nextItems = items.every((x) => Array.isArray(x)) ? items.flat() : items;
return (
<Collapsible
open={isOpen}
onOpenChange={setIsOpen}
className={cn('relative', nextClassName)}
>
{nextItems.slice(0, 3).map(children)}
<CollapsibleContent className={nextClassName}>
{nextItems.slice(3).map((x, idx) => children(x, idx + 3))}
</CollapsibleContent>
{nextItems.length > 3 && (
<CollapsibleTrigger
asChild
onClick={(e) => e.stopPropagation()}
className="absolute left-1/2 -translate-x-1/2 bottom-0 translate-y-1/2 cursor-pointer"
>
<div
className={cn(
'size-3 bg-text-secondary rounded-full flex items-center justify-center',
{ 'bg-text-primary': isOpen },
)}
>
{isOpen ? (
<ChevronUp className="stroke-bg-component" />
) : (
<ChevronDown className="stroke-bg-component" />
)}
</div>
</CollapsibleTrigger>
)}
</Collapsible>
);
}