7e44df3493
Follow-up к MR !90 per user feedback iterations: 1) "в поиске по справочникам два крестика" — fixed в SearchInput: `type="search"` (native browser X) → `type="text"`. Custom onClear X остаётся единственным. Catalog input тоже type="text". 2) "блин два крестика было на топбар поиске а тут норм все. верни" — restore TopBar search input. Context-aware behavior сохранён: - На /dictionaries → live filter каталога через URL ?q= - На остальных routes → submit (Enter) → /search records search Single X confirmed by visual test. 3) "свитч темы можно тоже в профиль перенести" — ThemeSwitch переехал в Sidebar footer (рядом с RU/EN button). Right row в footer: lang button слева, theme switch (3 icons sun/moon/monitor) справа через ml-auto. 4) "руководство и версию оставить в топбар чтобы подсвечивать новинки" — Docs + VersionBadge stays in TopBar. Туда же добавлена NotificationsBell (placeholder Bell icon) — broadcast slot для webhook errors / draft reviews / system notices когда backend notifications stream появится.
48 lines
1.7 KiB
TypeScript
48 lines
1.7 KiB
TypeScript
import * as React from 'react'
|
||
import { Search, X } from 'lucide-react'
|
||
import { cn } from '@/lib/utils'
|
||
import { Input } from './input'
|
||
|
||
/**
|
||
* SearchInput — Input с magnifying-glass иконкой слева и optional clear button
|
||
* справа когда есть value. Заменяет {@code @nstart/ui} SearchInput.
|
||
*/
|
||
export type SearchInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> & {
|
||
onClear?: () => void
|
||
}
|
||
|
||
export const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
|
||
function SearchInput({ className, value, onClear, ...props }, ref) {
|
||
const hasValue = value !== undefined && value !== ''
|
||
return (
|
||
<div className="relative w-full">
|
||
<Search
|
||
size={14}
|
||
strokeWidth={2}
|
||
className="pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-mute"
|
||
/>
|
||
<Input
|
||
ref={ref}
|
||
// type="text" вместо "search" — native browser X (Chrome/Safari)
|
||
// дублировал custom onClear X справа ("два крестика"). Custom X
|
||
// имеет правильный onClick handler и tracks state, native — нет.
|
||
type="text"
|
||
value={value}
|
||
className={cn('pl-8', hasValue && onClear && 'pr-8', className)}
|
||
{...props}
|
||
/>
|
||
{hasValue && onClear && (
|
||
<button
|
||
type="button"
|
||
aria-label="Очистить"
|
||
onClick={onClear}
|
||
className="absolute right-2 top-1/2 -translate-y-1/2 text-mute hover:text-ink rounded-sm p-0.5 hover:bg-surface-2"
|
||
>
|
||
<X size={13} strokeWidth={2} />
|
||
</button>
|
||
)}
|
||
</div>
|
||
)
|
||
},
|
||
)
|