refactor input and replace search input

This commit is contained in:
JzoNg 2024-08-08 17:38:31 +08:00
parent 9362ae045c
commit 939df16655
18 changed files with 211 additions and 158 deletions

View File

@ -21,7 +21,7 @@ import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { CheckModal } from '@/hooks/use-pay'
import TabSliderNew from '@/app/components/base/tab-slider-new'
import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
import SearchInput from '@/app/components/base/search-input'
import Input from '@/app/components/base/input'
import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
import TagManagementModal from '@/app/components/base/tag-management'
import TagFilter from '@/app/components/base/tag-management/filter'
@ -133,7 +133,14 @@ const Apps = () => {
/>
<div className='flex items-center gap-2'>
<TagFilter type='app' value={tagFilterValue} onChange={handleTagsChange} />
<SearchInput className='w-[200px]' value={keywords} onChange={handleKeywordsChange} />
<Input
showLeftIcon
showClearIcon
wrapperClassName='w-[200px]'
value={keywords}
onChange={e => handleKeywordsChange(e.target.value)}
onClear={() => handleKeywordsChange('')}
/>
</div>
</div>
<nav className='grid content-start grid-cols-1 gap-4 px-12 pt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 grow shrink-0'>

View File

@ -13,7 +13,7 @@ import DatasetFooter from './DatasetFooter'
import ApiServer from './ApiServer'
import Doc from './Doc'
import TabSliderNew from '@/app/components/base/tab-slider-new'
import SearchInput from '@/app/components/base/search-input'
import Input from '@/app/components/base/input'
import TagManagementModal from '@/app/components/base/tag-management'
import TagFilter from '@/app/components/base/tag-management/filter'
@ -79,7 +79,14 @@ const Container = () => {
{activeTab === 'dataset' && (
<div className='flex items-center gap-2'>
<TagFilter type='knowledge' value={tagFilterValue} onChange={handleTagsChange} />
<SearchInput className='w-[200px]' value={keywords} onChange={handleKeywordsChange} />
<Input
showLeftIcon
showClearIcon
wrapperClassName='w-[200px]'
value={keywords}
onChange={e => handleKeywordsChange(e.target.value)}
onClear={() => handleKeywordsChange('')}
/>
</div>
)}
{activeTab === 'api' && data && <ApiServer apiBaseUrl={data.api_base_url || ''} />}

View File

@ -1,43 +1,84 @@
'use client'
import type { SVGProps } from 'react'
import React, { useState } from 'react'
import type { CSSProperties } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { RiCloseCircleFill, RiErrorWarningLine, RiSearchLine } from '@remixicon/react'
import { type VariantProps, cva } from 'class-variance-authority'
import cn from '@/utils/classnames'
type InputProps = {
placeholder?: string
value?: string
defaultValue?: string
onChange?: (v: string) => void
className?: string
wrapperClassName?: string
type?: string
showPrefix?: React.ReactNode
prefixIcon?: React.ReactNode
}
const GlassIcon = ({ className }: SVGProps<SVGElement>) => (
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
<path d="M12.25 12.25L10.2084 10.2083M11.6667 6.70833C11.6667 9.44675 9.44675 11.6667 6.70833 11.6667C3.96992 11.6667 1.75 9.44675 1.75 6.70833C1.75 3.96992 3.96992 1.75 6.70833 1.75C9.44675 1.75 11.6667 3.96992 11.6667 6.70833Z" stroke="#344054" strokeWidth="1.25" strokeLinecap="round" strokeLinejoin="round" />
</svg>
export const inputVariants = cva(
'',
{
variants: {
size: {
regular: 'px-3 radius-md system-sm-regular',
large: 'px-4 radius-lg system-md-regular',
},
},
defaultVariants: {
size: 'regular',
},
},
)
const Input = ({ value, defaultValue, onChange, className = '', wrapperClassName = '', placeholder, type, showPrefix, prefixIcon }: InputProps) => {
const [localValue, setLocalValue] = useState(value ?? defaultValue)
export type InputProps = {
value: string
showLeftIcon?: boolean
showClearIcon?: boolean
onClear?: () => void
disabled?: boolean
destructive?: boolean
wrapperClassName?: string
styleCss?: CSSProperties
} & React.InputHTMLAttributes<HTMLInputElement> & VariantProps<typeof inputVariants>
const Input = ({
size,
disabled,
destructive,
showLeftIcon,
showClearIcon,
onClear,
wrapperClassName,
className,
styleCss,
value,
placeholder,
onChange,
...props
}: InputProps) => {
const { t } = useTranslation()
return (
<div className={`relative inline-flex w-full ${wrapperClassName}`}>
{showPrefix && <span className={'whitespace-nowrap absolute left-2 self-center'}>{prefixIcon ?? <GlassIcon className='h-3.5 w-3.5 stroke-current text-gray-700 stroke-2' />}</span>}
<div className={cn('relative w-full', wrapperClassName)}>
{showLeftIcon && <RiSearchLine className={cn('absolute left-2 top-1/2 -translate-y-1/2 w-4 h-4 text-components-input-text-placeholder')} />}
<input
type={type ?? 'text'}
className={cn(`inline-flex h-7 w-full py-1 px-2 rounded-lg text-xs leading-normal bg-gray-100 caret-primary-600 hover:bg-gray-100 focus:ring-1 focus:ring-inset focus:ring-gray-200 focus-visible:outline-none focus:bg-white placeholder:text-gray-400 ${showPrefix ? '!pl-7' : ''}`, className)}
placeholder={placeholder ?? (showPrefix ? t('common.operation.search') ?? '' : 'please input')}
value={localValue}
onChange={(e) => {
setLocalValue(e.target.value)
onChange && onChange(e.target.value)
}}
style={styleCss}
className={cn(
'w-full py-[7px] bg-components-input-bg-normal border border-transparent text-components-input-text-filled hover:bg-components-input-bg-hover hover:border-components-input-border-hover focus:bg-components-input-bg-active focus:border-components-input-border-active focus:shadow-xs placeholder:text-components-input-text-placeholder appearance-none outline-none caret-primary-600',
inputVariants({ size }),
showLeftIcon && 'pl-[26px]',
showLeftIcon && size === 'large' && 'pl-7',
showClearIcon && value && 'pr-[26px]',
showClearIcon && value && size === 'large' && 'pr-7',
destructive && 'pr-[26px]',
destructive && size === 'large' && 'pr-7',
disabled && 'bg-components-input-bg-disabled border-transparent text-components-input-text-filled-disabled cursor-not-allowed hover:bg-components-input-bg-disabled hover:border-transparent',
destructive && 'bg-components-input-bg-destructive border-components-input-border-destructive text-components-input-text-filled hover:bg-components-input-bg-destructive hover:border-components-input-border-destructive focus:bg-components-input-bg-destructive focus:border-components-input-border-destructive',
className,
)}
placeholder={placeholder ?? (showLeftIcon ? t('common.operation.search') ?? '' : 'please input')}
value={value}
onChange={onChange}
disabled={disabled}
{...props}
/>
{showClearIcon && value && !disabled && !destructive && (
<div className={cn('absolute right-2 top-1/2 -translate-y-1/2 group p-[1px] cursor-pointer')} onClick={onClear}>
<RiCloseCircleFill className='w-3.5 h-3.5 text-text-quaternary cursor-pointer group-hover:text-text-tertiary'/>
</div>
)}
{destructive && (
<RiErrorWarningLine className='absolute right-2 top-1/2 -translate-y-1/2 w-4 h-4 text-text-destructive-secondary'/>
)}
</div>
)
}

View File

@ -1,66 +0,0 @@
import type { FC } from 'react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { RiSearchLine } from '@remixicon/react'
import cn from '@/utils/classnames'
import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
type SearchInputProps = {
placeholder?: string
className?: string
value: string
onChange: (v: string) => void
white?: boolean
}
const SearchInput: FC<SearchInputProps> = ({
placeholder,
className,
value,
onChange,
white,
}) => {
const { t } = useTranslation()
const [focus, setFocus] = useState<boolean>(false)
return (
<div className={cn(
'group flex items-center px-2 h-8 rounded-lg bg-gray-200 hover:bg-gray-300 border border-transparent overflow-hidden',
focus && '!bg-white hover:bg-white shawdow-xs !border-gray-300',
!focus && value && 'hover:!bg-gray-200 hover:!shawdow-xs hover:!border-black/5',
white && '!bg-white hover:!bg-white shawdow-xs !border-gray-300 hover:!border-gray-300',
className,
)}>
<div className="pointer-events-none shrink-0 flex items-center mr-1.5 justify-center w-4 h-4">
<RiSearchLine className="h-3.5 w-3.5 text-gray-500" aria-hidden="true" />
</div>
<input
type="text"
name="query"
className={cn(
'grow block h-[18px] bg-gray-200 border-0 text-gray-700 text-[13px] placeholder:text-gray-500 appearance-none outline-none group-hover:bg-gray-300 caret-blue-600',
focus && '!bg-white hover:bg-white group-hover:bg-white placeholder:!text-gray-400',
!focus && value && 'hover:!bg-gray-200 group-hover:!bg-gray-200',
white && '!bg-white hover:!bg-white group-hover:!bg-white placeholder:!text-gray-400',
)}
placeholder={placeholder || t('common.operation.search')!}
value={value}
onChange={(e) => {
onChange(e.target.value)
}}
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
autoComplete="off"
/>
{value && (
<div
className='shrink-0 flex items-center justify-center w-4 h-4 cursor-pointer group/clear'
onClick={() => onChange('')}
>
<XCircle className='w-3.5 h-3.5 text-gray-400 group-hover/clear:text-gray-600' />
</div>
)}
</div>
)
}
export default SearchInput

View File

@ -10,7 +10,7 @@ import {
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import SearchInput from '@/app/components/base/search-input'
import Input from '@/app/components/base/input'
import { Tag01, Tag03 } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
import { Check } from '@/app/components/base/icons/src/vender/line/general'
import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
@ -111,7 +111,13 @@ const TagFilter: FC<TagFilterProps> = ({
<PortalToFollowElemContent className='z-[1002]'>
<div className='relative w-[240px] bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg'>
<div className='p-2 border-b-[0.5px] border-black/5'>
<SearchInput white value={keywords} onChange={handleKeywordsChange} />
<Input
showLeftIcon
showClearIcon
value={keywords}
onChange={e => handleKeywordsChange(e.target.value)}
onClear={() => handleKeywordsChange('')}
/>
</div>
<div className='p-1 max-h-72 overflow-auto'>
{filteredTagList.map(tag => (

View File

@ -9,7 +9,7 @@ import cn from '@/utils/classnames'
import type { HtmlContentProps } from '@/app/components/base/popover'
import CustomPopover from '@/app/components/base/popover'
import Divider from '@/app/components/base/divider'
import SearchInput from '@/app/components/base/search-input'
import Input from '@/app/components/base/input'
import { Tag01, Tag03 } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
import type { Tag } from '@/app/components/base/tag-management/constant'
import Checkbox from '@/app/components/base/checkbox'
@ -129,7 +129,14 @@ const Panel = (props: PanelProps) => {
return (
<div className='relative w-full bg-white rounded-lg border-[0.5px] border-gray-200' onMouseLeave={onMouseLeave}>
<div className='p-2 border-b-[0.5px] border-black/5'>
<SearchInput placeholder={t('common.tag.selectorPlaceholder') || ''} white value={keywords} onChange={handleKeywordsChange} />
<Input
showLeftIcon
showClearIcon
value={keywords}
placeholder={t('common.tag.selectorPlaceholder') || ''}
onChange={e => handleKeywordsChange(e.target.value)}
onClear={() => handleKeywordsChange('')}
/>
</div>
{keywords && notExisted && (
<div className='p-1'>

View File

@ -58,7 +58,7 @@ const EmptyDatasetCreationModal = ({
<div className={s.tip}>{t('datasetCreation.stepOne.modal.tip')}</div>
<div className={s.form}>
<div className={s.label}>{t('datasetCreation.stepOne.modal.input')}</div>
<Input className='!h-8' value={inputValue} placeholder={t('datasetCreation.stepOne.modal.placeholder') || ''} onChange={setInputValue} />
<Input value={inputValue} placeholder={t('datasetCreation.stepOne.modal.placeholder') || ''} onChange={e => setInputValue(e.target.value)} />
</div>
<div className='flex flex-row-reverse'>
<Button className='w-24 ml-2' variant='primary' onClick={submit}>{t('datasetCreation.stepOne.modal.confirmButton')}</Button>

View File

@ -1,10 +1,11 @@
'use client'
import type { FC } from 'react'
import React, { memo, useEffect, useMemo, useState } from 'react'
import { useDebounceFn } from 'ahooks'
import { HashtagIcon } from '@heroicons/react/24/solid'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { debounce, isNil, omitBy } from 'lodash-es'
import { isNil, omitBy } from 'lodash-es'
import {
RiCloseLine,
RiEditLine,
@ -241,7 +242,8 @@ const Completed: FC<ICompletedProps> = ({
// the current segment id and whether to show the modal
const [currSegment, setCurrSegment] = useState<{ segInfo?: SegmentDetailModel; showModal: boolean }>({ showModal: false })
const [searchValue, setSearchValue] = useState<string>() // the search value
const [inputValue, setInputValue] = useState<string>('') // the input value
const [searchValue, setSearchValue] = useState<string>('') // the search value
const [selectedStatus, setSelectedStatus] = useState<boolean | 'all'>('all') // the selected status, enabled/disabled/undefined
const [lastSegmentsRes, setLastSegmentsRes] = useState<SegmentsResponse | undefined>(undefined)
@ -250,6 +252,15 @@ const Completed: FC<ICompletedProps> = ({
const [total, setTotal] = useState<number | undefined>()
const { eventEmitter } = useEventEmitterContextContext()
const { run: handleSearch } = useDebounceFn(() => {
setSearchValue(inputValue)
}, { wait: 500 })
const handleInputChange = (value: string) => {
setInputValue(value)
handleSearch()
}
const onChangeStatus = ({ value }: Item) => {
setSelectedStatus(value === 'all' ? 'all' : !!value)
}
@ -391,7 +402,14 @@ const Completed: FC<ICompletedProps> = ({
defaultValue={'all'}
className={s.select}
wrapperClassName='h-fit w-[120px] mr-2' />
<Input showPrefix wrapperClassName='!w-52' className='!h-8' onChange={debounce(setSearchValue, 500)} />
<Input
showLeftIcon
showClearIcon
wrapperClassName='!w-52'
value={inputValue}
onChange={e => handleInputChange(e.target.value)}
onClear={() => handleInputChange('')}
/>
</div>
<InfiniteVirtualList
embeddingAvailable={embeddingAvailable}

View File

@ -78,8 +78,7 @@ export const FieldInfo: FC<IFieldInfoProps> = ({
placeholder={`${t('datasetDocuments.metadata.placeholder.add')}${label}`}
/>
: <Input
className={s.input}
onChange={onUpdate}
onChange={e => onUpdate?.(e.target.value)}
value={value}
defaultValue={defaultValue}
placeholder={`${t('datasetDocuments.metadata.placeholder.add')}${label}`}

View File

@ -4,7 +4,8 @@ import React, { useMemo, useState } from 'react'
import useSWR from 'swr'
import { useTranslation } from 'react-i18next'
import { useRouter } from 'next/navigation'
import { debounce, groupBy, omit } from 'lodash-es'
import { useDebounceFn } from 'ahooks'
import { groupBy, omit } from 'lodash-es'
import { PlusIcon } from '@heroicons/react/24/solid'
import List from './list'
import s from './style.module.css'
@ -76,6 +77,7 @@ export const fetcher = (url: string) => get(url, {}, {})
const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
const { t } = useTranslation()
const [inputValue, setInputValue] = useState<string>('') // the input value
const [searchValue, setSearchValue] = useState<string>('')
const [currPage, setCurrPage] = React.useState<number>(0)
const router = useRouter()
@ -192,6 +194,15 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
const documentsList = isDataSourceNotion ? documentsWithProgress?.data : documentsRes?.data
const { run: handleSearch } = useDebounceFn(() => {
setSearchValue(inputValue)
}, { wait: 500 })
const handleInputChange = (value: string) => {
setInputValue(value)
handleSearch()
}
return (
<div className='flex flex-col h-full overflow-y-auto'>
<div className='flex flex-col justify-center gap-1 px-6 pt-4'>
@ -201,11 +212,12 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
<div className='flex flex-col px-6 py-4 flex-1'>
<div className='flex items-center justify-between flex-wrap'>
<Input
showPrefix
showLeftIcon
showClearIcon
wrapperClassName='!w-[200px]'
className='!h-8 !text-[13px]'
onChange={debounce(setSearchValue, 500)}
value={searchValue}
value={inputValue}
onChange={e => handleInputChange(e.target.value)}
onClear={() => handleInputChange('')}
/>
<div className='flex gap-2 justify-center items-center !h-8'>
<RetryButton datasetId={datasetId} />

View File

@ -9,7 +9,7 @@ import {
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import Avatar from '@/app/components/base/avatar'
import SearchInput from '@/app/components/base/search-input'
import Input from '@/app/components/base/input'
import { Check } from '@/app/components/base/icons/src/vender/line/general'
import { Users01, UsersPlus } from '@/app/components/base/icons/src/vender/solid/users'
import type { DatasetPermission } from '@/models/datasets'
@ -99,7 +99,7 @@ const PermissionSelector = ({ disabled, permission, value, memberList, onChange,
)}
</PortalToFollowElemTrigger>
<PortalToFollowElemContent className='z-[1002]'>
<div className='relative w-[480px] bg-white rounded-lg border-[0.5px] bg-gray-200 shadow-lg'>
<div className='relative w-[480px] rounded-lg border-[0.5px] bg-white shadow-lg'>
<div className='p-1'>
<div className='pl-3 pr-2 py-1 rounded-lg hover:bg-gray-50 cursor-pointer' onClick={() => {
onChange('only_me')
@ -139,7 +139,13 @@ const PermissionSelector = ({ disabled, permission, value, memberList, onChange,
{permission === 'partial_members' && (
<div className='max-h-[360px] border-t-[1px] border-gray-100 p-1 overflow-y-auto'>
<div className='sticky left-0 top-0 p-2 pb-1 bg-white'>
<SearchInput white value={keywords} onChange={handleKeywordsChange} />
<Input
showLeftIcon
showClearIcon
value={keywords}
onChange={e => handleKeywordsChange(e.target.value)}
onClear={() => handleKeywordsChange('')}
/>
</div>
{showMe && (
<div className='pl-3 pr-[10px] py-1 flex gap-2 items-center rounded-lg'>

View File

@ -23,7 +23,7 @@ import Loading from '@/app/components/base/loading'
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { useAppContext } from '@/context/app-context'
import { getRedirection } from '@/utils/app-redirection'
import SearchInput from '@/app/components/base/search-input'
import Input from '@/app/components/base/input'
type AppsProps = {
pageType?: PageType
@ -185,7 +185,14 @@ const Apps = ({
allCategoriesEn={allCategoriesEn}
/>
</>
<SearchInput value={keywords} onChange={handleKeywordsChange}/>
<Input
showLeftIcon
showClearIcon
wrapperClassName='w-[200px]'
value={keywords}
onChange={e => handleKeywordsChange(e.target.value)}
onClear={() => handleKeywordsChange('')}
/>
</div>

View File

@ -19,7 +19,7 @@ import { getLanguage } from '@/i18n/language'
import Drawer from '@/app/components/base/drawer'
import Button from '@/app/components/base/button'
import Loading from '@/app/components/base/loading'
import SearchInput from '@/app/components/base/search-input'
import Input from '@/app/components/base/input'
import EditCustomToolModal from '@/app/components/tools/edit-custom-collection-modal'
import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials'
import {
@ -193,7 +193,13 @@ const AddToolModal: FC<Props> = ({
<div className='relative grow bg-white rounded-r-xl overflow-y-auto'>
<div className='z-10 sticky top-0 left-0 right-0 p-2 flex items-center gap-1 bg-white'>
<div className='grow'>
<SearchInput className='w-full' value={keywords} onChange={handleKeywordsChange} />
<Input
showLeftIcon
showClearIcon
value={keywords}
onChange={e => handleKeywordsChange(e.target.value)}
onClear={() => handleKeywordsChange('')}
/>
</div>
<div className='ml-2 mr-1 w-[1px] h-4 bg-gray-200'></div>
<div className='p-2 cursor-pointer' onClick={onHide}>

View File

@ -11,7 +11,7 @@ import {
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import SearchInput from '@/app/components/base/search-input'
import Input from '@/app/components/base/input'
import { Tag01, Tag03 } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
import { Check } from '@/app/components/base/icons/src/vender/line/general'
import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
@ -113,7 +113,13 @@ const LabelFilter: FC<LabelFilterProps> = ({
<PortalToFollowElemContent className='z-[1002]'>
<div className='relative w-[240px] bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg'>
<div className='p-2 border-b-[0.5px] border-black/5'>
<SearchInput white value={keywords} onChange={handleKeywordsChange} />
<Input
showLeftIcon
showClearIcon
value={keywords}
onChange={e => handleKeywordsChange(e.target.value)}
onClear={() => handleKeywordsChange('')}
/>
</div>
<div className='p-1'>
{filteredLabelList.map(label => (

View File

@ -11,7 +11,7 @@ import {
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import SearchInput from '@/app/components/base/search-input'
import Input from '@/app/components/base/input'
import { Tag03 } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
import Checkbox from '@/app/components/base/checkbox'
import type { Label } from '@/app/components/tools/labels/constant'
@ -94,7 +94,13 @@ const LabelSelector: FC<LabelSelectorProps> = ({
<PortalToFollowElemContent className='z-[1040]'>
<div className='relative w-[591px] bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg'>
<div className='p-2 border-b-[0.5px] border-black/5'>
<SearchInput white value={keywords} onChange={handleKeywordsChange} />
<Input
showLeftIcon
showClearIcon
value={keywords}
onChange={e => handleKeywordsChange(e.target.value)}
onClear={() => handleKeywordsChange('')}
/>
</div>
<div className='p-1 max-h-[264px] overflow-y-auto'>
{filteredLabelList.map(label => (

View File

@ -7,7 +7,7 @@ import cn from '@/utils/classnames'
import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
import TabSliderNew from '@/app/components/base/tab-slider-new'
import LabelFilter from '@/app/components/tools/labels/filter'
import SearchInput from '@/app/components/base/search-input'
import Input from '@/app/components/base/input'
import { DotsGrid } from '@/app/components/base/icons/src/vender/line/general'
import { Colors } from '@/app/components/base/icons/src/vender/line/others'
import { Route } from '@/app/components/base/icons/src/vender/line/mapsAndTravel'
@ -84,7 +84,14 @@ const ProviderList = () => {
/>
<div className='flex items-center gap-2'>
<LabelFilter value={tagFilterValue} onChange={handleTagsChange} />
<SearchInput className='w-[200px]' value={keywords} onChange={handleKeywordsChange} />
<Input
showLeftIcon
showClearIcon
wrapperClassName='w-[200px]'
value={keywords}
onChange={e => handleKeywordsChange(e.target.value)}
onClear={() => handleKeywordsChange('')}
/>
</div>
</div>
<div className={cn(

View File

@ -12,9 +12,6 @@ import type {
OffsetOptions,
Placement,
} from '@floating-ui/react'
import {
RiSearchLine,
} from '@remixicon/react'
import type { BlockEnum, OnSelectBlock } from '../types'
import Tabs from './tabs'
import {
@ -22,10 +19,10 @@ import {
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import Input from '@/app/components/base/input'
import {
Plus02,
} from '@/app/components/base/icons/src/vender/line/general'
import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
type NodeSelectorProps = {
open?: boolean
@ -111,30 +108,16 @@ const NodeSelector: FC<NodeSelectorProps> = ({
</PortalToFollowElemTrigger>
<PortalToFollowElemContent className='z-[1000]'>
<div className={`rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg ${popupClassName}`}>
<div className='px-2 pt-2'>
<div
className='flex items-center px-2 rounded-lg bg-gray-100'
onClick={e => e.stopPropagation()}
>
<RiSearchLine className='shrink-0 ml-[1px] mr-[5px] w-3.5 h-3.5 text-gray-400' />
<input
value={searchText}
className='grow px-0.5 py-[7px] text-[13px] text-gray-700 bg-transparent appearance-none outline-none caret-primary-600 placeholder:text-gray-400'
placeholder={t('workflow.tabs.searchBlock') || ''}
onChange={e => setSearchText(e.target.value)}
autoFocus
/>
{
searchText && (
<div
className='flex items-center justify-center ml-[5px] w-[18px] h-[18px] cursor-pointer'
onClick={() => setSearchText('')}
>
<XCircle className='w-[14px] h-[14px] text-gray-400' />
</div>
)
}
</div>
<div className='px-2 pt-2' onClick={e => e.stopPropagation()}>
<Input
showLeftIcon
showClearIcon
autoFocus
value={searchText}
placeholder={t('workflow.tabs.searchBlock') || ''}
onChange={e => setSearchText(e.target.value)}
onClear={() => setSearchText('')}
/>
</div>
<Tabs
onSelect={handleSelect}

View File

@ -12,6 +12,7 @@ type Props = {
const FilterCondition: FC<Props> = ({
hasSubVariable,
}) => {
const [input, setInput] = React.useState('')
return (
<div>
{hasSubVariable && <SubVariablePicker className="mb-2" />}
@ -24,7 +25,7 @@ const FilterCondition: FC<Props> = ({
]}
onSelect={() => { }}
/>
<Input className='grow h-8 text-components-input-text-filled system-sm-regular !text-[13px]' />
<Input className='grow' value={input} onChange={e => setInput(e.target.value)} />
</div>
</div>
)