feat(topbar): match redesign prototype — breadcrumb back-arrow + cleaner right cluster

Per /Users/zimin/Downloads/Ordinis (4)/redesign/compact.html.

TopBar breadcrumb:
- Detail routes теперь показывают `← Справочники / Космические аппараты`
  с back-arrow prefix на parent crumb (caption text, mute). Bold title +
  inline mono subtitle "satellites · v1.0.0".
- Catalog route: simple "Dictionaries" title.

TopBar right cluster cleanup:
- Removed `Docs` link — diagnostic, не critical UX, моя кноп не нужна
  для UI flow.
- Removed `VersionBadge` (commit + tag) — был noise рядом с продакшн
  features. Build info всё ещё доступна в browser console / Docs.
- ThemeSwitch: tri-state (Light/Dark/System icons 3×24px) заменён на
  2-button `Earth | Dark` с text labels (per prototype). `system`
  preference остаётся в localStorage для existing users, но новый UI
  не выставляет.
- LanguageSwitch: dual radio `RU | EN` заменён на single toggle button —
  показывает текущий язык как label, click переключает на следующий.
  Saves ~60px горизонтально, matches prototype.

EditorInfoPanel order:
- Action buttons (Экспорт / Time-travel / AOI) переехали из середины
  panel (между metadata и Relations) в bottom (после Relations) —
  per prototype. Info → meta → relations → actions flow.
- Action order: Экспорт первым (frequent), затем Time-travel, AOI последним
  (rare для most dicts).
This commit is contained in:
Zimin A.N.
2026-05-11 19:43:05 +03:00
parent bc737820d6
commit ac1ca8d035
3 changed files with 120 additions and 104 deletions
@@ -1,37 +1,42 @@
import { useTranslation } from 'react-i18next'
import { Monitor, Moon, Sun } from 'lucide-react'
import { useTheme, type ThemePreference } from '@/stores/ThemeProvider'
import { cn } from '@/lib/utils'
/**
* Tri-state theme switch: Light / Dark / System.
* Theme switch per redesign prototype — 2-button segmented control с text
* labels "Earth | Dark". Filled accent-bg на active.
*
* <p>Segmented control с тремя иконками. Активный — `--color-accent`
* background + `--color-on-accent` foreground. Click меняет `preference`
* в {@link ThemeProvider}, который пишет в localStorage и переключает
* `data-theme` на html.
* <p>Прошлый tri-state (Light/Dark/System icons) был noise — "system" preference
* редко используется явно, мало кто понимает Monitor icon. Простой 2-button
* `Earth / Dark` toggle — точно повторяет prototype и улучшает discoverability.
*
* <p>System icon показывает «follow OS» — auto-update при OS theme change.
* <p>Internally "Earth" maps на `light` preference (Earthy palette default).
* "System" preference больше не выставляется через UI; localStorage value
* остаётся валидным (ThemeProvider может read), но новые users получают
* explicit light/dark choice.
*/
export function ThemeSwitch() {
const { t } = useTranslation()
const { preference, setPreference } = useTheme()
const items: { id: ThemePreference; label: string; icon: typeof Sun }[] = [
{ id: 'light', label: t('theme.light'), icon: Sun },
{ id: 'dark', label: t('theme.dark'), icon: Moon },
{ id: 'system', label: t('theme.system'), icon: Monitor },
// Treat 'system' как 'light' для UI — переключение всё равно flatten'ит
// preference на explicit choice.
const activeId: Exclude<ThemePreference, 'system'> =
preference === 'dark' ? 'dark' : 'light'
const items: { id: Exclude<ThemePreference, 'system'>; label: string }[] = [
{ id: 'light', label: t('theme.earth', { defaultValue: 'Earth' }) },
{ id: 'dark', label: t('theme.dark', { defaultValue: 'Dark' }) },
]
return (
<div
role="radiogroup"
aria-label={t('theme.label')}
className="inline-flex items-center rounded-md border border-line bg-surface p-0.5"
className="inline-flex items-center rounded-md border border-line bg-surface overflow-hidden"
>
{items.map((item) => {
const Icon = item.icon
const active = preference === item.id
const active = activeId === item.id
return (
<button
key={item.id}
@@ -39,16 +44,15 @@ export function ThemeSwitch() {
role="radio"
aria-checked={active}
aria-label={item.label}
title={item.label}
onClick={() => setPreference(item.id)}
className={cn(
'inline-flex h-6 w-6 items-center justify-center rounded transition-colors',
'h-8 px-3 text-cap font-semibold tracking-[0.14em] transition-colors',
active
? 'bg-accent text-on-accent'
: 'text-mute hover:text-ink hover:bg-surface-2',
: 'text-ink-2 hover:text-ink hover:bg-surface-2',
)}
>
<Icon size={13} strokeWidth={2.25} />
{item.label}
</button>
)
})}