feat(ui): row click opens edit + wide-mode left section rail in drawer

Two improvements per user feedback ('по клику открывается редактирование и
в развернутом виде слева навигация'):

## 1. Row click → edit drawer

TableRow в /dictionaries/$name теперь имеет onClick={setEdit({kind:'edit',
record:r})} когда canMutate. cursor-pointer + bubbling guards:
- Checkbox cell и Actions cell имеют onClick stopPropagation чтобы
  внутренние controls не открывали drawer случайно.
- Anonymous users (no canMutate) — row не clickable (read-only, no drawer).

## 2. Wide-mode left rail в drawer

SchemaDrivenForm в sections layout теперь умеет ResizeObserver-based detection
своей ширины. Когда контейнер ≥720px (drawer wide mode = 880px) → render'ит
180px sticky left rail с section list + per-section field counts. Click rail
item → smooth scroll к section anchor. Иначе chip strip сверху, как раньше.

Container-based (не viewport-based) чтобы narrow drawer на wide viewport не
рендерил rail (520px не fits 180+1fr grid).
This commit is contained in:
Zimin A.N.
2026-05-11 23:51:03 +03:00
parent ac5f5bea01
commit 54cf563162
2 changed files with 80 additions and 23 deletions
@@ -905,10 +905,18 @@ function DictionaryDetail() {
<TableRow
key={r.id}
data-selected={selection.has(r.businessKey)}
className={rowCursor === idx ? 'bg-accent-bg/40 outline outline-1 outline-accent/30' : undefined}
// Row-wide click → open edit drawer (только для canMutate).
// Anonymous users — read-only, click no-op чтобы не путать.
// Bubbling: nested buttons (checkbox, action icons) делают
// stopPropagation чтобы они не открывали drawer случайно.
onClick={canMutate ? () => setEdit({ kind: 'edit', record: r }) : undefined}
className={[
canMutate ? 'cursor-pointer' : '',
rowCursor === idx ? 'bg-accent-bg/40 outline outline-1 outline-accent/30' : '',
].filter(Boolean).join(' ') || undefined}
>
{canMutate && (
<TableCell>
<TableCell onClick={(e) => e.stopPropagation()}>
<Checkbox
aria-label={`${t('dict.bulk.selectRow')} ${r.businessKey}`}
checked={selection.has(r.businessKey)}
@@ -967,7 +975,7 @@ function DictionaryDetail() {
{new Date(r.validFrom).toLocaleDateString()}
</span>
</TableCell>
<TableCell align="right">
<TableCell align="right" onClick={(e) => e.stopPropagation()}>
<div className="flex items-center justify-end gap-1">
<IconButton
label={t('history.title')}