feat(app): новый визуальный язык, верхняя навигация, портфели, создание счетов и ручные события
Тема и общие виджеты (AssetIcon, ServiceMark, HelpTip, глоссарий), верхняя панель TopNav и вкладки Аналитики вместо NavSidebar, иконки PWA. Экраны: портфели, создание брокерского счёта, ручное событие, правка инструмента, Обзор карточками по скоупам и таблица активов, пересчёт метрик с опросом /metrics/status. design-system.md обновлён.
This commit is contained in:
@@ -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 600–1200,
|
||||
/// 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)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user