feat(editor): + Экспорт button в InfoPanel per redesign dark theme screenshot

User dropped /Users/zimin/Downloads/Ordinis (3) — full project dump.
Dark theme editor screenshot (uploads/draw-4b771386...png) показывает
INFO PANEL c двумя buttons:
  - ↓ Экспорт…
  - ⟲ Time-travel…

У нас был Time-travel + AOI — добавил Экспорт как third button.

Implementation:
  - EditorInfoPanel.actions.onExport + exportPending props
  - DownloadSimpleIcon кнопка 'Экспорт…'
  - Wired к useBulkExportRecords mutation:
    * Selection не empty -> export selected
    * Selection empty -> export all filtered records
  - disabled когда mutation pending, label 'Экспорт…'

Project dump reviewed:
  - design_handoff_dictionary_catalog — старый handoff, всё уже реализовано
    (List view MR !62, Hub MR earlier, Graph earlier)
  - patches/ — @nstart/ui patches, moot (мы dropped @nstart/ui MR !52)
  - redesign/ — уже синхронизированы colors MR !71, layout MR !69
  - uploads/ — user-provided screenshots, main delta = Export button
This commit is contained in:
Zimin A.N.
2026-05-11 18:03:52 +03:00
parent 36fb70fc00
commit e15a3916bf
2 changed files with 28 additions and 2 deletions
@@ -1,7 +1,7 @@
import { useMemo } from 'react'
import { Link } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import { ClockCounterClockwiseIcon, MapTrifoldIcon } from '@phosphor-icons/react'
import { ClockCounterClockwiseIcon, MapTrifoldIcon, DownloadSimpleIcon } from '@phosphor-icons/react'
import { Badge } from '@/ui'
import { useDictionaryDependents } from '@/api/queries'
import type { DictionaryDetail } from '@/api/client'
@@ -25,13 +25,15 @@ import { cn } from '@/lib/utils'
export type EditorInfoPanelProps = {
detail: DictionaryDetail
recordCount: number
/** Optional action buttons (Time-travel / AOI filter) — bottom of panel
/** Optional action buttons (Time-travel / AOI / Export) — bottom of panel
* per redesign prototype. Toggle handlers come from route's state. */
actions?: {
onTimeTravel?: () => void
timeTravelActive?: boolean
onAoi?: () => void
aoiActive?: boolean
onExport?: () => void
exportPending?: boolean
}
}
@@ -109,6 +111,19 @@ export function EditorInfoPanel({ detail, recordCount, actions }: EditorInfoPane
{t('aoi.button', { defaultValue: 'AOI фильтр…' })}
</button>
)}
{actions.onExport && (
<button
type="button"
onClick={actions.onExport}
disabled={actions.exportPending}
className="w-full h-8 rounded-md border border-line bg-surface text-ink-2 hover:border-line-2 hover:bg-surface-2 disabled:opacity-50 disabled:cursor-not-allowed text-cell flex items-center justify-center gap-1.5 transition-colors"
>
<DownloadSimpleIcon weight="regular" size={14} />
{actions.exportPending
? t('export.pending', { defaultValue: 'Экспорт…' })
: t('export.button', { defaultValue: '↓ Экспорт…' })}
</button>
)}
</div>
)}