mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### 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)
128 lines
3.3 KiB
TypeScript
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>
|
|
);
|
|
}
|