feat(app): новый визуальный язык, верхняя навигация, портфели, создание счетов и ручные события

Тема и общие виджеты (AssetIcon, ServiceMark, HelpTip, глоссарий), верхняя панель TopNav и вкладки Аналитики вместо NavSidebar, иконки PWA. Экраны: портфели, создание брокерского счёта, ручное событие, правка инструмента, Обзор карточками по скоупам и таблица активов, пересчёт метрик с опросом /metrics/status. design-system.md обновлён.
This commit is contained in:
Dmitry
2026-09-19 22:14:21 +03:00
parent a559d6de3e
commit 62d36aa3e8
73 changed files with 6406 additions and 1192 deletions
+34 -29
View File
@@ -1,21 +1,22 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'analytics_tabs.dart';
import 'nav_destinations.dart';
import 'nav_sidebar.dart';
import 'top_nav.dart';
/// Breakpoints per the plan: bottom bar under 600, collapsed rail 6001200,
/// extended rail at 1200 and above.
/// Below this width the shell falls back to a bottom [NavigationBar]; from here up it is the
/// [TopNav] bar.
const _narrowBreakpoint = 600.0;
const _wideBreakpoint = 1200.0;
/// Adaptive navigation shell around the current route: a bottom
/// [NavigationBar] on narrow surfaces, a collapsed [NavigationRail] on medium
/// ones, and the grouped [NavSidebar] on wide ones.
/// Adaptive navigation shell around the current route: a bottom [NavigationBar] on narrow
/// surfaces and the [TopNav] bar on wider ones, with the Аналитика tab strip under it while
/// one of the analytics screens is open.
///
/// The rail and the sidebar show every destination. The bottom bar shows the four primary
/// ones plus «Ещё», which opens the rest in a sheet: twelve destinations in a phone-width
/// bar would leave about 30 px per label, which is not navigation but decoration.
/// The top bar shows every destination (the ledger ones behind «Операции»). The bottom bar
/// shows the four primary ones plus «Ещё», which opens the rest in a sheet: twelve
/// destinations in a phone-width bar would leave about 30 px per label, which is not
/// navigation but decoration.
class AppShell extends StatelessWidget {
const AppShell({required this.location, required this.child, super.key});
@@ -80,28 +81,32 @@ class AppShell extends StatelessWidget {
);
}
final extended = width >= _wideBreakpoint;
return Scaffold(
body: Row(
body: Column(
children: [
if (extended)
NavSidebar(selectedIndex: _selectedIndex, onSelect: (i) => _onSelect(context, i))
else
NavigationRail(
selectedIndex: _selectedIndex,
onDestinationSelected: (i) => _onSelect(context, i),
labelType: NavigationRailLabelType.selected,
destinations: [
for (final d in navDestinations)
NavigationRailDestination(
icon: Icon(d.icon),
selectedIcon: Icon(d.selectedIcon),
label: Text(d.label),
),
],
TopNav(
selectedIndex: _selectedIndex,
onSelect: (i) => _onSelect(context, i),
),
Expanded(
child: Align(
alignment: Alignment.topCenter,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: kContentMaxWidth),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (AnalyticsTabs.contains(location))
Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
child: AnalyticsTabs(location: location),
),
Expanded(child: child),
],
),
),
),
const VerticalDivider(width: 1),
Expanded(child: SafeArea(child: child)),
),
],
),
);