fix(admin-ui): IconButton icon prop + compact 2-col form layout

Bugs:
- IconButton @nstart/ui принимает icon={} prop, не children — иконки рендерились
  пустыми квадратами (видно «Изменить» tooltip без значка карандашика).
  Перевёл оба IconButton на icon={<PencilSimpleIcon/>} / icon={<XCircleIcon/>}.

UX:
- Modal max-w-2xl → max-w-4xl (форма дышит, ru-RU/en-US labels не оборачиваются).
- SchemaDrivenForm: scalar поля теперь в 2-колоночной grid, full-width
  (i18n / array / textarea / nested object) занимают sm:col-span-2.
- Локальные ярлыки i18n: tracking-normal + whitespace-nowrap, w-14 — больше не
  ломаются «ru-» «RU» из-за inherited tracking-label.
This commit is contained in:
Zimin A.N.
2026-05-04 02:37:13 +03:00
parent 4f04872de8
commit 7aed67fce5
2 changed files with 41 additions and 26 deletions
@@ -96,19 +96,19 @@ export const SchemaDrivenForm = ({
}
return (
<form onSubmit={handleSubmit(submit)} className="space-y-6">
<form onSubmit={handleSubmit(submit)} className="space-y-4">
<FormSection title={t('form.identity')}>
<FormGrid columns={1}>
<TextInput
label={t('form.businessKey')}
required
disabled={mode === 'edit'}
placeholder="MY_RECORD_KEY"
error={formState.errors.businessKey ? t('form.error.required') : undefined}
{...register('businessKey', { required: true, minLength: 1 })}
/>
</FormGrid>
<FormGrid columns={2}>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div className="sm:col-span-2">
<TextInput
label={t('form.businessKey')}
required
disabled={mode === 'edit'}
placeholder="MY_RECORD_KEY"
error={formState.errors.businessKey ? t('form.error.required') : undefined}
{...register('businessKey', { required: true, minLength: 1 })}
/>
</div>
<TextInput
type="datetime-local"
label={t('form.validFrom')}
@@ -119,11 +119,11 @@ export const SchemaDrivenForm = ({
label={t('form.validTo')}
{...register('validTo')}
/>
</FormGrid>
</div>
</FormSection>
<FormSection title={t('form.dataFields')}>
<FormGrid columns={1}>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
{Object.entries(properties).map(([key, propSchema]) => (
<FieldRenderer
key={key}
@@ -136,7 +136,7 @@ export const SchemaDrivenForm = ({
fieldError={formState.errors.data?.[key as keyof FormValues['data']]}
/>
))}
</FormGrid>
</div>
</FormSection>
{serverError && <Alert variant="error">{serverError}</Alert>}
@@ -153,6 +153,14 @@ export const SchemaDrivenForm = ({
)
}
const isFullWidth = (s: JsonSchema): boolean => {
if (s['x-localized']) return true
if (s.type === 'array') return true
if ((s.maxLength ?? 0) > 200) return true
if (s.type === 'object') return true
return false
}
type FieldRendererProps = {
fieldKey: string
schema: JsonSchema
@@ -163,7 +171,16 @@ type FieldRendererProps = {
fieldError?: unknown
}
const FieldRenderer = ({
const FieldRenderer = (props: FieldRendererProps) => {
const wrapperClass = isFullWidth(props.schema) ? 'sm:col-span-2' : ''
return (
<div className={wrapperClass}>
<FieldBody {...props} />
</div>
)
}
const FieldBody = ({
fieldKey,
schema,
required,
@@ -188,11 +205,11 @@ const FieldRenderer = ({
control={control}
name={`data.${fieldKey}.${loc}` as `data.${string}`}
render={({ field }) => (
<div className="flex items-center gap-2">
<span className="text-2xs font-mono text-carbon/70 w-12 shrink-0">
<div className="flex items-center gap-3">
<span className="text-xs font-mono text-carbon/70 normal-case tracking-normal whitespace-nowrap shrink-0 w-14">
{loc === defaultLocale ? <strong>{loc}</strong> : loc}
</span>
<div className="flex-1">
<div className="flex-1 min-w-0">
<TextInput {...field} value={(field.value as string | undefined) ?? ''} />
</div>
</div>
@@ -156,17 +156,15 @@ function DictionaryDetail() {
<IconButton
label={t('dict.action.edit')}
variant="default"
icon={<PencilSimpleIcon weight="regular" />}
onClick={() => setEdit({ kind: 'edit', record: r })}
>
<PencilSimpleIcon size={16} />
</IconButton>
/>
<IconButton
label={t('dict.action.close')}
variant="danger"
icon={<XCircleIcon weight="regular" />}
onClick={() => setEdit({ kind: 'close-confirm', record: r })}
>
<XCircleIcon size={16} />
</IconButton>
/>
</div>
</TableCell>
</TableRow>
@@ -186,7 +184,7 @@ function DictionaryDetail() {
? `${t('dict.action.edit')}: ${edit.record.businessKey}`
: ''
}
maxWidth="max-w-2xl"
maxWidth="max-w-4xl"
>
{detailQuery.data && (edit.kind === 'create' || edit.kind === 'edit') && (
<SchemaDrivenForm