mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
Fix:Add a component of calendar (#8923)
### What problem does this PR solve? fix:Add a component of calendar [#3221](https://github.com/infiniflow/ragflow/issues/3221) ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -85,6 +85,7 @@
|
|||||||
"rc-tween-one": "^3.0.6",
|
"rc-tween-one": "^3.0.6",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-copy-to-clipboard": "^5.1.0",
|
"react-copy-to-clipboard": "^5.1.0",
|
||||||
|
"react-day-picker": "^9.8.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-dropzone": "^14.3.5",
|
"react-dropzone": "^14.3.5",
|
||||||
"react-error-boundary": "^4.0.13",
|
"react-error-boundary": "^4.0.13",
|
||||||
|
|||||||
19
web/src/components/originui/calendar/index.less
Normal file
19
web/src/components/originui/calendar/index.less
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
.rdp-selected {
|
||||||
|
background-color: #f5f5f529;
|
||||||
|
}
|
||||||
|
.range-start {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
|
button {
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.range-end {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
button {
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
95
web/src/components/originui/calendar/index.tsx
Normal file
95
web/src/components/originui/calendar/index.tsx
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { DayPicker } from 'react-day-picker';
|
||||||
|
import { buttonVariants } from '../../ui/button';
|
||||||
|
import './index.less';
|
||||||
|
type DateRange = {
|
||||||
|
from: Date;
|
||||||
|
to?: Date;
|
||||||
|
};
|
||||||
|
function Calendar({
|
||||||
|
className,
|
||||||
|
classNames,
|
||||||
|
showOutsideDays = true,
|
||||||
|
components: userComponents,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof DayPicker>) {
|
||||||
|
const defaultClassNames = {
|
||||||
|
months: 'relative flex flex-col sm:flex-row gap-4',
|
||||||
|
month: 'w-full',
|
||||||
|
month_caption:
|
||||||
|
'relative mx-10 mb-1 flex h-9 items-center justify-center z-20',
|
||||||
|
caption_label: 'text-sm font-medium',
|
||||||
|
nav: 'absolute top-0 flex w-full justify-between z-10',
|
||||||
|
button_previous: cn(
|
||||||
|
buttonVariants({ variant: 'ghost' }),
|
||||||
|
'size-9 text-muted-foreground/80 hover:text-foreground p-0',
|
||||||
|
),
|
||||||
|
button_next: cn(
|
||||||
|
buttonVariants({ variant: 'ghost' }),
|
||||||
|
'size-9 text-muted-foreground/80 hover:text-foreground p-0',
|
||||||
|
),
|
||||||
|
weekday: 'size-9 p-0 text-xs font-medium text-muted-foreground/80',
|
||||||
|
day_button:
|
||||||
|
'relative flex size-9 items-center justify-center whitespace-nowrap rounded-md p-0 text-foreground group-[[data-selected]:not(.range-middle)]:[transition-property:color,background-color,border-radius,box-shadow] group-[[data-selected]:not(.range-middle)]:duration-150 group-data-disabled:pointer-events-none focus-visible:z-10 hover:not-in-data-selected:bg-accent group-data-selected:bg-primary hover:not-in-data-selected:text-foreground group-data-selected:text-primary-foreground group-data-disabled:text-foreground/30 group-data-disabled:line-through group-data-outside:text-foreground/30 group-data-selected:group-data-outside:text-primary-foreground outline-none focus-visible:ring-ring/50 focus-visible:ring-[3px] group-[.range-start:not(.range-end)]:rounded-e-none group-[.range-end:not(.range-start)]:rounded-s-none group-[.range-middle]:rounded-none group-[.range-middle]:group-data-selected:bg-accent group-[.range-middle]:group-data-selected:text-foreground',
|
||||||
|
day: 'group size-9 px-0 py-px text-sm',
|
||||||
|
range_start: 'range-start',
|
||||||
|
range_end: 'range-end',
|
||||||
|
range_middle: 'range-middle',
|
||||||
|
today:
|
||||||
|
'*:after:pointer-events-none *:after:absolute *:after:bottom-1 *:after:start-1/2 *:after:z-10 *:after:size-[3px] *:after:-translate-x-1/2 *:after:rounded-full *:after:bg-primary [&[data-selected]:not(.range-middle)>*]:after:bg-background [&[data-disabled]>*]:after:bg-foreground/30 *:after:transition-colors',
|
||||||
|
outside:
|
||||||
|
'text-muted-foreground data-selected:bg-accent/50 data-selected:text-muted-foreground',
|
||||||
|
hidden: 'invisible',
|
||||||
|
week_number: 'size-9 p-0 text-xs font-medium text-muted-foreground/80',
|
||||||
|
};
|
||||||
|
|
||||||
|
const mergedClassNames: typeof defaultClassNames = Object.keys(
|
||||||
|
defaultClassNames,
|
||||||
|
).reduce(
|
||||||
|
(acc, key) => ({
|
||||||
|
...acc,
|
||||||
|
[key]: classNames?.[key as keyof typeof classNames]
|
||||||
|
? cn(
|
||||||
|
defaultClassNames[key as keyof typeof defaultClassNames],
|
||||||
|
classNames[key as keyof typeof classNames],
|
||||||
|
)
|
||||||
|
: defaultClassNames[key as keyof typeof defaultClassNames],
|
||||||
|
}),
|
||||||
|
{} as typeof defaultClassNames,
|
||||||
|
);
|
||||||
|
|
||||||
|
const defaultComponents = {
|
||||||
|
Chevron: (props: {
|
||||||
|
className?: string;
|
||||||
|
size?: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
orientation?: 'left' | 'right' | 'up' | 'down';
|
||||||
|
}) => {
|
||||||
|
if (props.orientation === 'left') {
|
||||||
|
return <ChevronLeftIcon size={16} {...props} aria-hidden="true" />;
|
||||||
|
}
|
||||||
|
return <ChevronRightIcon size={16} {...props} aria-hidden="true" />;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mergedComponents = {
|
||||||
|
...defaultComponents,
|
||||||
|
...userComponents,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DayPicker
|
||||||
|
showOutsideDays={showOutsideDays}
|
||||||
|
className={cn('w-fit', className)}
|
||||||
|
classNames={mergedClassNames}
|
||||||
|
components={mergedComponents}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Calendar, DateRange };
|
||||||
@ -10,6 +10,7 @@ interface ModalProps {
|
|||||||
title?: ReactNode;
|
title?: ReactNode;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
footer?: ReactNode;
|
footer?: ReactNode;
|
||||||
|
showfooter?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
size?: 'small' | 'default' | 'large';
|
size?: 'small' | 'default' | 'large';
|
||||||
closable?: boolean;
|
closable?: boolean;
|
||||||
@ -30,6 +31,7 @@ export const Modal: FC<ModalProps> = ({
|
|||||||
title,
|
title,
|
||||||
children,
|
children,
|
||||||
footer,
|
footer,
|
||||||
|
showfooter = true,
|
||||||
className = '',
|
className = '',
|
||||||
size = 'default',
|
size = 'default',
|
||||||
closable = true,
|
closable = true,
|
||||||
@ -80,6 +82,9 @@ export const Modal: FC<ModalProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const footEl = useMemo(() => {
|
const footEl = useMemo(() => {
|
||||||
|
if (showfooter === false) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
let footerTemp;
|
let footerTemp;
|
||||||
if (footer) {
|
if (footer) {
|
||||||
footerTemp = footer;
|
footerTemp = footer;
|
||||||
@ -112,7 +117,16 @@ export const Modal: FC<ModalProps> = ({
|
|||||||
{footerTemp}
|
{footerTemp}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}, [footer, cancelText, t, confirmLoading, okText, handleCancel, handleOk]);
|
}, [
|
||||||
|
footer,
|
||||||
|
cancelText,
|
||||||
|
t,
|
||||||
|
confirmLoading,
|
||||||
|
okText,
|
||||||
|
handleCancel,
|
||||||
|
handleOk,
|
||||||
|
showfooter,
|
||||||
|
]);
|
||||||
return (
|
return (
|
||||||
<DialogPrimitive.Root open={open} onOpenChange={handleChange}>
|
<DialogPrimitive.Root open={open} onOpenChange={handleChange}>
|
||||||
<DialogPrimitive.Portal>
|
<DialogPrimitive.Portal>
|
||||||
@ -121,7 +135,7 @@ export const Modal: FC<ModalProps> = ({
|
|||||||
onClick={() => maskClosable && onOpenChange?.(false)}
|
onClick={() => maskClosable && onOpenChange?.(false)}
|
||||||
>
|
>
|
||||||
<DialogPrimitive.Content
|
<DialogPrimitive.Content
|
||||||
className={`relative w-[700px] ${full ? 'max-w-full' : sizeClasses[size]} ${className} bg-colors-background-neutral-standard rounded-lg shadow-lg transition-all`}
|
className={`relative w-[700px] ${full ? 'max-w-full' : sizeClasses[size]} ${className} bg-colors-background-neutral-standard rounded-lg shadow-lg transition-all focus-visible:!outline-none`}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{/* title */}
|
{/* title */}
|
||||||
@ -142,9 +156,13 @@ export const Modal: FC<ModalProps> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{/* title */}
|
||||||
|
{!title && (
|
||||||
|
<DialogPrimitive.Title className="text-lg font-medium text-foreground"></DialogPrimitive.Title>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* content */}
|
{/* content */}
|
||||||
<div className="p-6 overflow-y-auto max-h-[80vh]">
|
<div className="p-6 overflow-y-auto max-h-[80vh] focus-visible:!outline-none">
|
||||||
{destroyOnClose && !open ? null : children}
|
{destroyOnClose && !open ? null : children}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user