mirror of https://github.com/langgenius/dify.git
feat: range picker
This commit is contained in:
parent
92ab453a5a
commit
56dd17cdaa
|
|
@ -4,13 +4,17 @@ import type { FC } from 'react'
|
|||
import React, { useCallback } from 'react'
|
||||
import { SimpleSelect } from '@/app/components/base/select'
|
||||
import type { Item } from '@/app/components/base/select'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import dayjs from 'dayjs'
|
||||
import { HourglassShape } from '@/app/components/base/icons/src/vender/other'
|
||||
import TimePicker from '@/app/components/base/date-and-time-picker/time-picker'
|
||||
import { noop } from 'lodash-es'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import cn from '@/utils/classnames'
|
||||
import { RiArrowDownSLine, RiCheckLine } from '@remixicon/react'
|
||||
import { RiArrowDownSLine, RiCalendarLine, RiCheckLine } from '@remixicon/react'
|
||||
import DatePicker from '@/app/components/base/date-and-time-picker/date-picker'
|
||||
import 'dayjs/locale/zh-cn'
|
||||
import { formatToLocalTime } from '@/utils/format'
|
||||
import { useI18N } from '@/context/i18n'
|
||||
|
||||
const today = dayjs()
|
||||
|
||||
|
|
@ -68,6 +72,17 @@ const TimeRangePicker: FC<Props> = ({
|
|||
}
|
||||
onSelect({ query: period!, name })
|
||||
}, [onSelect])
|
||||
|
||||
const { locale } = useI18N()
|
||||
|
||||
const renderDate = useCallback(({ value, handleClickTrigger, isOpen }: { value?: Dayjs, handleClickTrigger: () => void, isOpen: boolean }) => {
|
||||
return (
|
||||
<div className={cn('system-sm-regular flex h-7 cursor-pointer items-center rounded-lg px-1 text-components-input-text-filled hover:bg-state-base-hover', isOpen && 'bg-state-base-hover')} onClick={handleClickTrigger}>
|
||||
{value ? formatToLocalTime(value, locale, 'MMM D') : ''}
|
||||
</div>
|
||||
)
|
||||
}, [locale])
|
||||
|
||||
return (
|
||||
<div className='flex items-center'>
|
||||
<SimpleSelect
|
||||
|
|
@ -83,10 +98,23 @@ const TimeRangePicker: FC<Props> = ({
|
|||
renderOption={renderOption}
|
||||
/>
|
||||
<HourglassShape className='h-3.5 w-2 text-components-input-bg-normal' />
|
||||
<TimePicker
|
||||
value={today}
|
||||
onChange={noop}
|
||||
/>
|
||||
<div className='flex h-8 items-center space-x-0.5 rounded-lg bg-components-input-bg-normal px-2'>
|
||||
<RiCalendarLine className='size-3.5 text-text-tertiary' />
|
||||
<DatePicker
|
||||
value={today}
|
||||
onChange={noop}
|
||||
renderTrigger={renderDate}
|
||||
needTimePicker={false}
|
||||
/>
|
||||
<span className='system-sm-regular text-text-tertiary'>-</span>
|
||||
<DatePicker
|
||||
value={today}
|
||||
onChange={noop}
|
||||
renderTrigger={renderDate}
|
||||
needTimePicker={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ const Calendar: FC<CalendarProps> = ({
|
|||
selectedDate,
|
||||
onDateClick,
|
||||
wrapperClassName,
|
||||
getIsDateDisabled,
|
||||
}) => {
|
||||
return <div className={wrapperClassName}>
|
||||
<DaysOfWeek/>
|
||||
<DaysOfWeek />
|
||||
<div className='grid grid-cols-7 gap-0.5 p-2'>
|
||||
{
|
||||
days.map(day => <CalendarItem
|
||||
|
|
@ -18,6 +19,7 @@ const Calendar: FC<CalendarProps> = ({
|
|||
day={day}
|
||||
selectedDate={selectedDate}
|
||||
onClick={onDateClick}
|
||||
isDisabled={getIsDateDisabled ? getIsDateDisabled(day.date) : false}
|
||||
/>)
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ const Item: FC<CalendarItemProps> = ({
|
|||
day,
|
||||
selectedDate,
|
||||
onClick,
|
||||
isDisabled,
|
||||
}) => {
|
||||
const { date, isCurrentMonth } = day
|
||||
const isSelected = selectedDate?.isSame(date, 'date')
|
||||
|
|
@ -14,11 +15,12 @@ const Item: FC<CalendarItemProps> = ({
|
|||
|
||||
return (
|
||||
<button type="button"
|
||||
onClick={() => onClick(date)}
|
||||
onClick={() => !isDisabled && onClick(date)}
|
||||
className={cn(
|
||||
'system-sm-medium relative flex items-center justify-center rounded-lg px-1 py-2',
|
||||
isCurrentMonth ? 'text-text-secondary' : 'text-text-quaternary hover:text-text-secondary',
|
||||
isSelected ? 'system-sm-medium bg-components-button-primary-bg text-components-button-primary-text' : 'hover:bg-state-base-hover',
|
||||
isDisabled && 'cursor-not-allowed text-text-quaternary hover:bg-transparent',
|
||||
)}
|
||||
>
|
||||
{date.date()}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ const DatePicker = ({
|
|||
renderTrigger,
|
||||
triggerWrapClassName,
|
||||
popupZIndexClassname = 'z-[11]',
|
||||
getIsDateDisabled,
|
||||
}: DatePickerProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
|
|
@ -270,6 +271,7 @@ const DatePicker = ({
|
|||
days={days}
|
||||
selectedDate={selectedDate}
|
||||
onDateClick={handleDateSelect}
|
||||
getIsDateDisabled={getIsDateDisabled}
|
||||
/>
|
||||
) : view === ViewType.yearMonth ? (
|
||||
<YearAndMonthPickerOptions
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export type DatePickerProps = {
|
|||
renderTrigger?: (props: TriggerProps) => React.ReactNode
|
||||
minuteFilter?: (minutes: string[]) => string[]
|
||||
popupZIndexClassname?: string
|
||||
getIsDateDisabled?: (date: Dayjs) => boolean
|
||||
}
|
||||
|
||||
export type DatePickerHeaderProps = {
|
||||
|
|
@ -80,12 +81,14 @@ export type CalendarProps = {
|
|||
selectedDate: Dayjs | undefined
|
||||
onDateClick: (date: Dayjs) => void
|
||||
wrapperClassName?: string
|
||||
getIsDateDisabled?: (date: Dayjs) => boolean
|
||||
}
|
||||
|
||||
export type CalendarItemProps = {
|
||||
day: Day
|
||||
selectedDate: Dayjs | undefined
|
||||
onClick: (date: Dayjs) => void
|
||||
isDisabled: boolean
|
||||
}
|
||||
|
||||
export type TimeOptionsProps = {
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ const translation = {
|
|||
quarterToDate: '四半期初から今日まで',
|
||||
yearToDate: '年初から今日まで',
|
||||
allTime: 'すべての期間',
|
||||
custom: 'カスタム',
|
||||
},
|
||||
annotation: {
|
||||
all: 'すべて',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,50 @@
|
|||
import type { Locale } from '@/i18n-config'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import 'dayjs/locale/de'
|
||||
import 'dayjs/locale/es'
|
||||
import 'dayjs/locale/fa'
|
||||
import 'dayjs/locale/fr'
|
||||
import 'dayjs/locale/hi'
|
||||
import 'dayjs/locale/id'
|
||||
import 'dayjs/locale/it'
|
||||
import 'dayjs/locale/ja'
|
||||
import 'dayjs/locale/ko'
|
||||
import 'dayjs/locale/pl'
|
||||
import 'dayjs/locale/pt-br'
|
||||
import 'dayjs/locale/ro'
|
||||
import 'dayjs/locale/ru'
|
||||
import 'dayjs/locale/sl'
|
||||
import 'dayjs/locale/th'
|
||||
import 'dayjs/locale/tr'
|
||||
import 'dayjs/locale/uk'
|
||||
import 'dayjs/locale/vi'
|
||||
import 'dayjs/locale/zh-cn'
|
||||
import 'dayjs/locale/zh-tw'
|
||||
|
||||
const localeMap: Record<Locale, string> = {
|
||||
'en-US': 'en',
|
||||
'zh-Hans': 'zh-cn',
|
||||
'zh-Hant': 'zh-tw',
|
||||
'pt-BR': 'pt-br',
|
||||
'es-ES': 'es',
|
||||
'fr-FR': 'fr',
|
||||
'de-DE': 'de',
|
||||
'ja-JP': 'ja',
|
||||
'ko-KR': 'ko',
|
||||
'ru-RU': 'ru',
|
||||
'it-IT': 'it',
|
||||
'th-TH': 'th',
|
||||
'id-ID': 'id',
|
||||
'uk-UA': 'uk',
|
||||
'vi-VN': 'vi',
|
||||
'ro-RO': 'ro',
|
||||
'pl-PL': 'pl',
|
||||
'hi-IN': 'hi',
|
||||
'tr-TR': 'tr',
|
||||
'fa-IR': 'fa',
|
||||
'sl-SI': 'sl',
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a number with comma separators.
|
||||
* @example formatNumber(1234567) will return '1,234,567'
|
||||
|
|
@ -90,3 +137,7 @@ export const formatNumberAbbreviated = (num: number) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const formatToLocalTime = (time: Dayjs, local: string, format: string) => {
|
||||
return time.locale(localeMap[local] ?? 'en').format(format)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue