diff --git a/ordinis-admin-ui/package.json b/ordinis-admin-ui/package.json index 720e52a..281f70c 100644 --- a/ordinis-admin-ui/package.json +++ b/ordinis-admin-ui/package.json @@ -1,7 +1,7 @@ { "name": "ordinis-admin-ui", "private": true, - "version": "0.1.0", + "version": "1.2.0", "type": "module", "scripts": { "dev": "vite", diff --git a/ordinis-admin-ui/src/components/layout/TopBar.tsx b/ordinis-admin-ui/src/components/layout/TopBar.tsx index 065cfa6..182fd2a 100644 --- a/ordinis-admin-ui/src/components/layout/TopBar.tsx +++ b/ordinis-admin-ui/src/components/layout/TopBar.tsx @@ -5,7 +5,7 @@ import { AuthBadge } from '@/auth/AuthBadge' import { ThemeSwitch } from '@/components/layout/ThemeSwitch' import { VersionBadge } from '@/components/version/VersionBadge' import { SearchInput } from '@/ui/components/search-input' -import { useState } from 'react' +import { useEffect, useRef, useState } from 'react' /** * TopBar — sticky header (h=56) per handoff design. @@ -13,9 +13,8 @@ import { useState } from 'react' * Structure: * - Left: dynamic breadcrumb based on current route * - Center: global SearchInput → submits → navigates to /search?q= + * + ⌘K / Ctrl+K shortcut focuses input from anywhere * - Right: VersionBadge · ThemeSwitch · LanguageSwitch · Docs · AuthBadge - * - * Mobile (lg:): на узких экранах sidebar скрывается, breadcrumb sustaiable. */ const LANG_OPTIONS = [ { id: 'ru-RU', label: 'RU' }, @@ -26,15 +25,36 @@ export function TopBar() { const { t, i18n } = useTranslation() const navigate = useNavigate() const [searchValue, setSearchValue] = useState('') + const inputRef = useRef(null) const breadcrumb = useBreadcrumb() + // ⌘K / Ctrl+K shortcut — focus search input from anywhere. Skip когда + // активен другой input/textarea (юзер печатает в record edit form). + useEffect(() => { + const handler = (e: KeyboardEvent) => { + if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') { + const target = e.target as HTMLElement + if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')) { + // Уже в input — пусть default browser shortcut работает. + if (target === inputRef.current) return + } + e.preventDefault() + inputRef.current?.focus() + inputRef.current?.select() + } + } + window.addEventListener('keydown', handler) + return () => window.removeEventListener('keydown', handler) + }, []) + const handleSearchSubmit = (e: React.FormEvent) => { e.preventDefault() const q = searchValue.trim() - if (q.length >= 3) { - navigate({ to: '/search', search: { q } }) - } + if (q.length === 0) return + // Navigate даже если q < 3 — search route сам покажет "min 3 chars" hint. + // Раньше блокировал в TopBar → юзер думал «поиск не работает». + void navigate({ to: '/search', search: { q } }) } return ( @@ -66,6 +86,7 @@ export function TopBar() { {/* Search — center, max-width per handoff */}
setSearchValue(e.target.value)} @@ -99,8 +120,6 @@ export function TopBar() { /** * Breadcrumb из current route — простой mapping для типичных страниц. - * Сложные breadcrumbs (dict name, record bk) — фактически TopBar shows - * generic, а более детальный crumb рендерит сам route через PageHeader. */ function useBreadcrumb(): { label: string; to?: string }[] { const { t } = useTranslation() @@ -131,7 +150,6 @@ function useBreadcrumb(): { label: string; to?: string }[] { ] if (segments.length >= 2) { - // Второй сегмент — id / name. Не маппим, оставляем raw. crumbs.push({ label: decodeURIComponent(segments[1]) }) } diff --git a/ordinis-admin-ui/src/components/version/VersionBadge.tsx b/ordinis-admin-ui/src/components/version/VersionBadge.tsx index e4011a2..36be395 100644 --- a/ordinis-admin-ui/src/components/version/VersionBadge.tsx +++ b/ordinis-admin-ui/src/components/version/VersionBadge.tsx @@ -38,9 +38,11 @@ export function VersionBadge() { className="inline-block w-1.5 h-1.5 rounded-full bg-accent animate-pulse" /> )} - v{clientVersion} + {/* Prefer server tag (v1.2.0 etc.) над package.json clientVersion (0.1.0). + serverTag только при tag build'е — на branch builds показываем clientVersion. */} + {serverTag && serverTag !== 'none' ? serverTag : `v${clientVersion}`} · - {clientCommit.substring(0, 7)} + {(serverCommit || clientCommit).substring(0, 7)} ) }