From ad7c51d93fe73c8af4c91464637992ef758d9b48 Mon Sep 17 00:00:00 2001 From: "Zimin A.N." Date: Mon, 11 May 2026 19:09:39 +0300 Subject: [PATCH] feat(catalog): toolbar layout per redesign prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Match handoff screenshot: - Title "Справочники" + inline "N шт." count caption (no description text) - Remove page-level SearchInput (TopBar already has global search ⌘K) - Reorder toolbar to single row: [scope pills PUBLIC|INTERNAL|RESTRICTED] | divider | [bundle pills все|cuod|geo|i18n|core] | spacer | N/M counter [Граф ⇄] (→ /graph) [+ Создать] (moved here from PageHeader actions) - Scope/bundle pills are bordered chips с ring-1 для active state - Drop deps-only toggle (not in redesign) - Drop scopeCounts useMemo (counts moved out of chip labels per design) --- .../src/routes/dictionaries.index.tsx | 115 ++++++++---------- 1 file changed, 48 insertions(+), 67 deletions(-) diff --git a/ordinis-admin-ui/src/routes/dictionaries.index.tsx b/ordinis-admin-ui/src/routes/dictionaries.index.tsx index 25916dd..04f3521 100644 --- a/ordinis-admin-ui/src/routes/dictionaries.index.tsx +++ b/ordinis-admin-ui/src/routes/dictionaries.index.tsx @@ -16,7 +16,7 @@ import { useDeferredValue, useMemo, useState } from 'react' import { createFileRoute, useNavigate } from '@tanstack/react-router' import { useTranslation } from 'react-i18next' -import { Alert, Badge, Button, EmptyState, LoadingBlock, PageHeader, SearchInput } from '@/ui' +import { Alert, Badge, Button, EmptyState, LoadingBlock, PageHeader } from '@/ui' import { PlusIcon } from '@phosphor-icons/react' import { useQueries } from '@tanstack/react-query' import { dictionaryDependentsQuery, useDictionaries, useDictionaryDependents } from '@/api/queries' @@ -167,11 +167,6 @@ function DictionariesPage() { return out }, [data]) - const scopeCounts = useMemo(() => { - const out: Record = { PUBLIC: 0, INTERNAL: 0, RESTRICTED: 0 } - if (data) for (const d of data) out[d.scope]++ - return out - }, [data]) const filtersActive = Boolean(q) || scopeFilter.size > 0 || bundleFilter || withDepsOnly const resetFilters = () => navigate({ search: {} }) @@ -223,40 +218,27 @@ function DictionariesPage() { return (
- - - {/* Compact toolbar: всё в одной строке (wraps на narrow viewport). - Tradeoff: scope/bundle chips меньше padding'а + краткие labels. - UPPERCASE labels оставлены для consistency с brand voice (Tektur-like). */} -
-
- setSearch({ q: e.target.value })} - placeholder={t('dict.list.search.placeholder')} - aria-label={t('dict.list.search.placeholder')} - /> -
- - - {filtered.length}/{data.length} + {/* PageHeader per redesign: title + inline "N шт." count, без description. + Actions удалены — + Создать переехала в toolbar справа от Граф ⇄. */} +
+

{t('nav.dictionaries')}

+ + {data.length} {t('dict.list.countSuffix', { defaultValue: 'шт.' })} +
- {/* Scope chips: компактные, dot + count, full label по hover'у через title */} + {/* Toolbar per redesign prototype: [scope pills] | [bundle pills] [...] N/M [Граф ⇄] [+ Создать] */} +
+ {/* Scope filter: PUBLIC / INTERNAL / RESTRICTED — pill chips с border */}
{SCOPE_ORDER.map((scope) => { const selected = scopeFilter.has(scope) - const count = scopeCounts[scope] return ( ) })}
- {/* Vertical divider */} -
{/* Empty state */}