From 43a06d1a7b55bb259db72626318fff7b51471daa Mon Sep 17 00:00:00 2001 From: "Zimin A.N." Date: Mon, 4 May 2026 02:47:06 +0300 Subject: [PATCH] fix(admin-ui): translate field labels + responsive header + modal max-h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issues: - Field labels (ORBIT/STATUS/COUNTRY/MASS_KG/...) показывались raw'ом потому что backend schema не присылает title. Добавил humanize() (snake_case → 'Snake Case') + i18n fallback t('field.$key') для известных полей spacecraft/satellite_type/ ground_station: name, designator, norad_id, status, country, operator, mass_kg, mission, orbit, launch_date, decay_date, spectrum_bands, satellite_type_code, etc. - Modal panel рос в высоту бесконечно (nstart-ui Modal не клампит max-h), на iPad портрете форма уходила за viewport. panelClassName=max-h-[calc(100vh-2rem)] flex flex-col + bodyClassName=overflow-y-auto flex-1. - Header в __root: padding/gap responsive (px-4 sm:px-6, py-3 sm:py-4, gap-3 sm:gap-6), flex-wrap чтобы LanguageSwitch на узких экранах переносился под навигацию. - Main container: px-4 sm:px-6 + py-4 sm:py-8. --- .../src/components/form/SchemaDrivenForm.tsx | 11 ++++-- ordinis-admin-ui/src/i18n.ts | 36 +++++++++++++++++++ ordinis-admin-ui/src/routes/__root.tsx | 6 ++-- .../src/routes/dictionaries.$name.tsx | 2 ++ 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/ordinis-admin-ui/src/components/form/SchemaDrivenForm.tsx b/ordinis-admin-ui/src/components/form/SchemaDrivenForm.tsx index 0f2fe79..c302f82 100644 --- a/ordinis-admin-ui/src/components/form/SchemaDrivenForm.tsx +++ b/ordinis-admin-ui/src/components/form/SchemaDrivenForm.tsx @@ -43,7 +43,11 @@ const ajv = new Ajv({ allErrors: true, strict: false }) addFormats(ajv) const isLocalized = (s: JsonSchema): boolean => Boolean(s['x-localized']) -const fieldLabel = (key: string, schema: JsonSchema): string => schema.title ?? key + +const humanize = (key: string): string => + key + .replace(/[_-]+/g, ' ') + .replace(/\b\w/g, (ch) => ch.toUpperCase()) export const SchemaDrivenForm = ({ schema, @@ -134,6 +138,7 @@ export const SchemaDrivenForm = ({ supportedLocales={supportedLocales} defaultLocale={defaultLocale} fieldError={formState.errors.data?.[key as keyof FormValues['data']]} + labelOf={(k, s) => s.title ?? t(`field.${k}`, { defaultValue: humanize(k) })} /> ))} @@ -169,6 +174,7 @@ type FieldRendererProps = { supportedLocales: string[] defaultLocale: string fieldError?: unknown + labelOf: (key: string, schema: JsonSchema) => string } const FieldRenderer = (props: FieldRendererProps) => { @@ -188,8 +194,9 @@ const FieldBody = ({ supportedLocales, defaultLocale, fieldError, + labelOf, }: FieldRendererProps) => { - const label = fieldLabel(fieldKey, schema) + const label = labelOf(fieldKey, schema) const errorMsg = (fieldError as { message?: string } | undefined)?.message if (isLocalized(schema)) { diff --git a/ordinis-admin-ui/src/i18n.ts b/ordinis-admin-ui/src/i18n.ts index fc36c87..af4fd94 100644 --- a/ordinis-admin-ui/src/i18n.ts +++ b/ordinis-admin-ui/src/i18n.ts @@ -40,6 +40,24 @@ i18n 'form.save': 'Сохранить', 'form.saving': 'Сохранение...', 'form.error.required': 'Обязательное поле', + 'field.name': 'Наименование', + 'field.designator': 'Designator (COSPAR)', + 'field.norad_id': 'NORAD ID', + 'field.status': 'Статус', + 'field.country': 'Страна', + 'field.operator': 'Оператор', + 'field.mass_kg': 'Масса (кг)', + 'field.mission': 'Миссия', + 'field.orbit': 'Орбита', + 'field.launch_date': 'Дата запуска', + 'field.decay_date': 'Дата схода', + 'field.spectrum_bands': 'Спектральные диапазоны', + 'field.satellite_type_code': 'Тип КА (код)', + 'field.code': 'Код', + 'field.description': 'Описание', + 'field.location': 'Местоположение', + 'field.coordinates': 'Координаты', + 'field.frequency_bands': 'Частотные диапазоны', 'loading': 'Загрузка...', 'error.failed': 'Не удалось загрузить данные', }, @@ -74,6 +92,24 @@ i18n 'form.save': 'Save', 'form.saving': 'Saving...', 'form.error.required': 'Required field', + 'field.name': 'Name', + 'field.designator': 'Designator (COSPAR)', + 'field.norad_id': 'NORAD ID', + 'field.status': 'Status', + 'field.country': 'Country', + 'field.operator': 'Operator', + 'field.mass_kg': 'Mass (kg)', + 'field.mission': 'Mission', + 'field.orbit': 'Orbit', + 'field.launch_date': 'Launch date', + 'field.decay_date': 'Decay date', + 'field.spectrum_bands': 'Spectrum bands', + 'field.satellite_type_code': 'Satellite type code', + 'field.code': 'Code', + 'field.description': 'Description', + 'field.location': 'Location', + 'field.coordinates': 'Coordinates', + 'field.frequency_bands': 'Frequency bands', 'loading': 'Loading...', 'error.failed': 'Failed to load data', }, diff --git a/ordinis-admin-ui/src/routes/__root.tsx b/ordinis-admin-ui/src/routes/__root.tsx index c27aaa4..41411d1 100644 --- a/ordinis-admin-ui/src/routes/__root.tsx +++ b/ordinis-admin-ui/src/routes/__root.tsx @@ -17,8 +17,8 @@ function RootLayout() { return (
-
- +
+ {t('app.title')}
-
+
diff --git a/ordinis-admin-ui/src/routes/dictionaries.$name.tsx b/ordinis-admin-ui/src/routes/dictionaries.$name.tsx index ab66cb0..5c1a2a3 100644 --- a/ordinis-admin-ui/src/routes/dictionaries.$name.tsx +++ b/ordinis-admin-ui/src/routes/dictionaries.$name.tsx @@ -185,6 +185,8 @@ function DictionaryDetail() { : '' } maxWidth="max-w-4xl" + panelClassName="max-h-[calc(100vh-2rem)] my-4 flex flex-col" + bodyClassName="overflow-y-auto flex-1" > {detailQuery.data && (edit.kind === 'create' || edit.kind === 'edit') && (