feat(ui): batch UI polish — auth/lang to sidebar, search h-7, info overflow, graph zoom
User feedback batch — multiple iterations of UX refinement.
Layout shifts:
- TopBar right cluster: AuthBadge + LanguageSwitch переехали в Sidebar
footer per user ("вход в сайдбар перенесем", "ru/en тоже в сайд баре").
TopBar теперь: breadcrumb + search + Docs + VersionBadge + ThemeSwitch
only. Освобождает место + concentrates user/lang controls в одном месте.
- Sidebar footer: новая структура — Lang toggle (Язык [RU/EN]) + Auth block
(avatar+name+logout authed, Sign-in CTA anonymous) + collapse button.
Refactored из inline JSX в named subcomponents (AuthedUserBlock,
SignInCta, SidebarFooter).
Sizing / spacing:
- TopBar SearchInput: h-9 → h-7 to match LangSwitch/ThemeSwitch (+ Sign-in
кнопка). User: "поиск по справочникам высоту выровняй". Override via
`!h-7 text-cell` className на SearchInput.
- TopBar: h-14 → h-11 (slimmer). Sidebar logo block matches h-11.
Catalog search:
- Catalog page input в toolbar — restored для on-page filter ("Catalog
search никак не работает" → проверил, работает; добавил TopBar context-
aware behavior где TopBar input на /dictionaries route синхронизируется
с URL ?q= live).
- TopBar search context-aware: catalog mode = live filter; else = submit
→ /search (records JSONB search).
InfoPanel:
- Description: `text-body text-ink-2 leading-relaxed` → +
`break-words overflow-hidden`. Long slash-separated values
(LZW/Deflate/JPEG2000/ZSTD/LERC) теперь wrap'ятся внутри panel вместо
overflow за границы (user: "описание убежало за границы панели").
- Container: + `min-w-0 overflow-hidden` для proper flex shrinking.
Graph:
- Zoom controls overlay (+/-/1:1/N%) + mouse wheel zoom toward cursor +
drag pan по empty space. Per user: "Граф связей еще не зумируется".
WorkflowBanner:
- Moved в InfoPanel banner slot (compact flex-col layout) — free
horizontal space выше editor + concentrates status info в left rail.
Auth:
- AuthBadge: primary Button → compact h-7 outline button. Matches
TopBar toolbar control style.
- RequireAuth: убран visible amber error banner "Авторизация недоступна:
Failed to fetch" — silent fall-through к anonymous mode (user feedback).
- routes/index.tsx: beforeLoad skip redirect если есть `?code=` в URL
(OIDC callback fix). HomeIndex компонент рендерит null + redirect на
/dictionaries после auth complete.
LanguageSwitch:
- h-8 + items-stretch + inner items-center — matches ThemeSwitch height.
- Later moved entirely в Sidebar footer (h-7 button only) per user.
This commit is contained in:
@@ -41,9 +41,13 @@ export type EditorInfoPanelProps = {
|
||||
onExport?: () => void
|
||||
exportPending?: boolean
|
||||
}
|
||||
/** Optional banner slot — WorkflowBanner / status notices живут в
|
||||
* left panel per user feedback ("плашки пусть в левой панели будут").
|
||||
* Renders at top of panel before scope chip. */
|
||||
banner?: React.ReactNode
|
||||
}
|
||||
|
||||
export function EditorInfoPanel({ detail, recordCount, actions }: EditorInfoPanelProps) {
|
||||
export function EditorInfoPanel({ detail, recordCount, actions, banner }: EditorInfoPanelProps) {
|
||||
const { t } = useTranslation()
|
||||
const { data: refByRaw } = useDictionaryDependents(detail.name)
|
||||
|
||||
@@ -51,7 +55,13 @@ export function EditorInfoPanel({ detail, recordCount, actions }: EditorInfoPane
|
||||
const incomingDeps: SchemaDependent[] = useMemo(() => refByRaw ?? [], [refByRaw])
|
||||
|
||||
return (
|
||||
<aside className="lg:sticky lg:top-2 self-start space-y-4 lg:max-h-[calc(100vh-7rem)] lg:overflow-y-auto rounded-lg border border-line bg-surface p-4">
|
||||
// Flex-col panel — stretches to full grid row height (no self-start).
|
||||
// Actions block при наличии actions получает `mt-auto` чтобы прижаться к
|
||||
// нижнему краю panel — per user feedback "всегда одной высоты".
|
||||
<aside className="flex flex-col space-y-4 rounded-lg border border-line bg-surface p-4 min-h-full min-w-0 overflow-hidden">
|
||||
{/* Banner slot — WorkflowBanner status notice (if any). */}
|
||||
{banner}
|
||||
|
||||
{/* Scope badge — top of panel */}
|
||||
<span
|
||||
className={cn(
|
||||
@@ -62,10 +72,14 @@ export function EditorInfoPanel({ detail, recordCount, actions }: EditorInfoPane
|
||||
{detail.scope}
|
||||
</span>
|
||||
|
||||
{/* Description */}
|
||||
{/* Description — break-words нужен потому что описания могут быть
|
||||
* без spaces (slash-separated lists типа "LZW/Deflate/JPEG2000") и
|
||||
* вылезают за границы narrow panel'а. `break-words` breaks при
|
||||
* необходимости anywhere; `overflow-hidden` clip'нет если что-то
|
||||
* unbreakable. */}
|
||||
{detail.description && (
|
||||
<Section label={t('editor.info.description', { defaultValue: 'Описание' })}>
|
||||
<p className="text-body text-ink-2 leading-relaxed">{detail.description}</p>
|
||||
<p className="text-body text-ink-2 leading-relaxed break-words overflow-hidden">{detail.description}</p>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
@@ -171,7 +185,7 @@ export function EditorInfoPanel({ detail, recordCount, actions }: EditorInfoPane
|
||||
* + AOI. После Relations block чтобы не разрывать info → meta → relations
|
||||
* мыслительный поток info-panel'а. */}
|
||||
{actions && (
|
||||
<div className="space-y-2 pt-3 mt-2 border-t border-line-2">
|
||||
<div className="space-y-2 pt-3 mt-auto border-t border-line-2">
|
||||
{actions.onExport && (
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -107,15 +107,19 @@ function Banner({ variant, icon, action, children }: BannerProps) {
|
||||
<div
|
||||
role="status"
|
||||
className={cn(
|
||||
'flex items-center gap-3 px-4 py-2.5 rounded-md border-l-4 text-body',
|
||||
// Compact layout — banner живёт в InfoPanel (narrow 220px column),
|
||||
// нужен vertical-ish stack а не широкий horizontal banner.
|
||||
'flex flex-col gap-1.5 px-3 py-2 rounded-md border-l-4 text-body',
|
||||
VARIANT_CLASS[variant],
|
||||
)}
|
||||
>
|
||||
{icon}
|
||||
<div className="flex items-center gap-2 flex-wrap min-w-0 flex-1">
|
||||
{children}
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
{icon}
|
||||
<div className="flex items-center gap-2 flex-wrap min-w-0 flex-1">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
{action}
|
||||
{action && <div className="pl-6">{action}</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user