fix(skill): use SearchInput with debounce and align card to Figma

Replace custom search input with SearchInput component (built-in clear
button) and add 300ms debounce. Fix template card: use Tailwind token
for icon background, fix Badge to use children with badge-s class and
uppercase, match empty-tag fallback height to badge size.
This commit is contained in:
yyh
2026-01-30 15:30:28 +08:00
parent c33d27938d
commit abe2b37e3a
3 changed files with 24 additions and 25 deletions

View File

@ -17,7 +17,7 @@ import { buildUploadDataFromTemplate } from './templates/template-to-upload'
const SkillTemplatesSection = () => {
const { t } = useTranslation('workflow')
const [activeCategory, setActiveCategory] = useState('all')
const [searchValue, setSearchValue] = useState('')
const [searchQuery, setSearchQuery] = useState('')
const [loadingId, setLoadingId] = useState<string | null>(null)
const appDetail = useAppStore(s => s.appDetail)
@ -65,14 +65,14 @@ const SkillTemplatesSection = () => {
}, [appId, storeApi])
const filtered = useMemo(() => SKILL_TEMPLATES.filter((entry) => {
if (searchValue) {
const q = searchValue.toLowerCase()
if (searchQuery) {
const q = searchQuery.toLowerCase()
return entry.name.toLowerCase().includes(q) || entry.description.toLowerCase().includes(q)
}
if (activeCategory !== 'all')
return entry.tags?.some(tag => tag.toLowerCase() === activeCategory.toLowerCase())
return true
}), [searchValue, activeCategory])
}), [searchQuery, activeCategory])
return (
<section className="flex flex-col gap-3 px-6 py-2">
@ -86,8 +86,7 @@ const SkillTemplatesSection = () => {
onCategoryChange={setActiveCategory}
/>
<TemplateSearch
value={searchValue}
onChange={setSearchValue}
onChange={setSearchQuery}
/>
</div>
<div className="grid grid-cols-3 gap-3">

View File

@ -22,7 +22,7 @@ const TemplateCard = ({ template, onUse }: TemplateCardProps) => {
<AppIcon
size="large"
icon={template.icon || '📁'}
background="#f5f3ff"
className="!bg-components-icon-bg-violet-soft"
/>
<div className="flex min-w-0 flex-1 flex-col gap-0.5 py-px">
<span className="system-md-semibold truncate text-text-secondary">
@ -43,11 +43,11 @@ const TemplateCard = ({ template, onUse }: TemplateCardProps) => {
? (
<div className="flex flex-wrap gap-1 transition-opacity group-hover:opacity-0">
{template.tags.map(tag => (
<Badge key={tag} text={tag} />
<Badge key={tag} className="badge-s" uppercase>{tag}</Badge>
))}
</div>
)
: <div className="h-5" />}
: <div className="h-[18px]" />}
<div className="pointer-events-none absolute inset-0 flex items-end px-4 pb-4 opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100">
<Button
variant="primary"

View File

@ -1,33 +1,33 @@
'use client'
import { RiSearchLine } from '@remixicon/react'
import { memo } from 'react'
import { useDebounceFn } from 'ahooks'
import { memo, useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import SearchInput from '@/app/components/base/search-input'
type TemplateSearchProps = {
value: string
onChange: (value: string) => void
}
const TemplateSearch = ({
value,
onChange,
}: TemplateSearchProps) => {
const { t } = useTranslation('workflow')
const [localValue, setLocalValue] = useState('')
const { run: debouncedOnChange } = useDebounceFn(onChange, { wait: 300 })
const handleChange = useCallback((v: string) => {
setLocalValue(v)
debouncedOnChange(v)
}, [debouncedOnChange])
return (
<div className="flex shrink-0 items-center gap-0.5 rounded-md bg-components-input-bg-normal p-2">
<RiSearchLine className="size-4 shrink-0 text-text-placeholder" aria-hidden="true" />
<input
type="text"
name="template-search"
aria-label={t('skill.startTab.searchPlaceholder')}
className="system-sm-regular min-w-0 flex-1 bg-transparent px-1 text-text-secondary placeholder:text-components-input-text-placeholder focus:outline-none"
placeholder={t('skill.startTab.searchPlaceholder')}
value={value}
onChange={e => onChange(e.target.value)}
/>
</div>
<SearchInput
className="!h-7"
placeholder={t('skill.startTab.searchPlaceholder')}
value={localValue}
onChange={handleChange}
/>
)
}