From 6fed3a0d64cbff1aabd443038edab739aa884e03 Mon Sep 17 00:00:00 2001 From: zardol Date: Wed, 7 Oct 2026 23:21:40 +0500 Subject: [PATCH] Add multilingual themes and stabilize shop floor navigation --- README.md | 2 + apps/web/index.html | 9 +- apps/web/src/App.tsx | 32 +- apps/web/src/ai.css | 24 +- apps/web/src/appearance.css | 71 + apps/web/src/case-panel.css | 28 +- apps/web/src/comparison.css | 172 +- apps/web/src/components/AiWorkspace.tsx | 72 +- apps/web/src/components/CasePanel.tsx | 111 +- apps/web/src/components/ClockCard.tsx | 15 +- apps/web/src/components/ComparisonPanel.tsx | 134 +- apps/web/src/components/ControlBar.tsx | 24 +- apps/web/src/components/DataWorkspace.tsx | 90 +- apps/web/src/components/FactoryView.tsx | 85 +- apps/web/src/components/FlowDiagram.tsx | 81 +- apps/web/src/components/ForecastCard.tsx | 21 +- apps/web/src/components/HistoricalViewer.tsx | 206 +- apps/web/src/components/IncidentTimeline.tsx | 24 +- apps/web/src/components/KpiGrid.tsx | 33 +- apps/web/src/components/Legend.tsx | 33 +- apps/web/src/components/OverviewPage.tsx | 33 +- apps/web/src/components/ProductionChart.tsx | 50 +- apps/web/src/components/ScenarioInfo.tsx | 47 + apps/web/src/components/ShiftFocus.tsx | 13 +- apps/web/src/components/Sidebar.tsx | 11 +- apps/web/src/components/StateScreens.tsx | 23 +- apps/web/src/components/StationDetails.tsx | 47 +- apps/web/src/components/StatusBadge.tsx | 3 +- apps/web/src/components/TopBar.tsx | 18 +- apps/web/src/components/interface.test.ts | 74 + apps/web/src/data-workspace.css | 16 +- apps/web/src/factory3d.css | 78 +- apps/web/src/format.ts | 26 +- apps/web/src/history-viewer.css | 10 +- apps/web/src/i18n.test.ts | 65 + apps/web/src/i18n.ts | 36 + apps/web/src/locales/catalog.json | 3554 ++++++++++++++++++ apps/web/src/preferences.ts | 36 + apps/web/src/stage2-flow.css | 138 +- apps/web/src/stage2-layout.css | 6 +- apps/web/src/styles.css | 60 +- apps/web/src/three/CameraRig.test.ts | 59 + apps/web/src/three/CameraRig.tsx | 86 + apps/web/src/three/ConveyorFleet.tsx | 2 +- apps/web/src/three/FactoryCanvas.tsx | 86 +- apps/web/src/three/cameraGeometry.test.ts | 29 + apps/web/src/three/cameraGeometry.ts | 24 + apps/web/src/workspaces.css | 180 +- docs/INTERFACE.md | 23 + package-lock.json | 506 +++ package.json | 1 + 51 files changed, 5587 insertions(+), 1020 deletions(-) create mode 100644 apps/web/src/appearance.css create mode 100644 apps/web/src/components/ScenarioInfo.tsx create mode 100644 apps/web/src/components/interface.test.ts create mode 100644 apps/web/src/i18n.test.ts create mode 100644 apps/web/src/i18n.ts create mode 100644 apps/web/src/locales/catalog.json create mode 100644 apps/web/src/preferences.ts create mode 100644 apps/web/src/three/CameraRig.test.ts create mode 100644 apps/web/src/three/CameraRig.tsx create mode 100644 apps/web/src/three/cameraGeometry.test.ts create mode 100644 apps/web/src/three/cameraGeometry.ts create mode 100644 docs/INTERFACE.md diff --git a/README.md b/README.md index faac7b8..79c6c60 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,8 @@ npm run check Смена сценария и сброс обнуляют симуляцию, сохраняя конфигурацию, выбранную скорость и состояние воспроизведения. По завершении заданной смены симуляция останавливается; по умолчанию смена длится восемь часов. Обновление страницы публичного стенда возвращает конфигурацию тестового кейса. В серверном режиме конфигурация живёт до удаления сессии. Межсменный перенос НЗП пока не моделируется. +Настройки RU / KZ / ENG, тёмная тема и управление камерой: [docs/INTERFACE.md](docs/INTERFACE.md). + ## Разработка | Область | Назначение | diff --git a/apps/web/index.html b/apps/web/index.html index 1f747c2..22f49f0 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -3,7 +3,7 @@ - + + DriveIndUI — Drive Industrial UI diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 88c9ec5..f295571 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -1,3 +1,4 @@ +import { t } from './i18n'; import { useEffect, useRef, useState } from 'react'; import { ArrowUpRight } from 'lucide-react'; import { ControlBar } from './components/ControlBar'; @@ -17,8 +18,11 @@ import { OverviewPage } from './components/OverviewPage'; import { AiWorkspace } from './components/AiWorkspace'; import { WORKSPACES, pageFromHash, pageHref, type WorkspacePage } from './navigation'; import './workspaces.css'; +import './appearance.css'; +import { usePreferences } from './preferences'; export default function App() { + const { language } = usePreferences(); const session = useSession(); const { snapshot, connection } = session; const [page, setPage] = useState(() => pageFromHash(window.location.hash)); @@ -48,33 +52,33 @@ export default function App() { return () => window.removeEventListener('hashchange', change); }, []); useEffect(() => { - document.title = `${meta.label} · DriveIndUI`; - heading.current?.focus({ preventScroll: true }); - }, [page, meta.label]); + document.title = `${t(meta.label)} · DriveIndUI`; + }, [page, meta.label, language]); + useEffect(() => { heading.current?.focus({ preventScroll: true }); }, [page]); return
- { event.preventDefault(); heading.current?.focus(); }}>К содержимому + { event.preventDefault(); heading.current?.focus(); }}>{t("К содержимому")}
-

{meta.number} / {meta.caption}

{meta.title}

- {page === 'overview' && Открыть цех } +

{t(meta.number)} / {t(meta.caption)}

{t(meta.title)}

+ {page === 'overview' && {t("Открыть цех ")}}
{!snapshot ? (stale ? : ) : <> {stale && } {page !== 'data' && } - {page === 'data' && session.controlError &&

{session.controlError}

} + {page === 'data' && session.controlError &&

{t(session.controlError)}

} {page === 'overview' && { selectStation(id); setStationFocus(value => value + 1); navigate('factory'); }} />}