Тема и общие виджеты (AssetIcon, ServiceMark, HelpTip, глоссарий), верхняя панель TopNav и вкладки Аналитики вместо NavSidebar, иконки PWA. Экраны: портфели, создание брокерского счёта, ручное событие, правка инструмента, Обзор карточками по скоупам и таблица активов, пересчёт метрик с опросом /metrics/status. design-system.md обновлён.
137 lines
3.4 KiB
Dart
137 lines
3.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
/// The groups destinations belong to: the main tabs, the ledger screens behind «Операции», and
|
|
/// the system ones (Здоровье, Настройки) that sit as icons on the right of the top bar.
|
|
enum NavGroup { overview, ledger, system }
|
|
|
|
class NavDestination {
|
|
const NavDestination(
|
|
this.path,
|
|
this.icon,
|
|
this.selectedIcon,
|
|
this.label,
|
|
this.group, {
|
|
this.alsoMatches = const [],
|
|
this.primary = false,
|
|
});
|
|
final String path;
|
|
final IconData icon;
|
|
final IconData selectedIcon;
|
|
final String label;
|
|
final NavGroup group;
|
|
|
|
/// Extra route prefixes that belong to this destination but do not start with [path] —
|
|
/// `/instruments/pending` is reached from Импорт and must keep it highlighted, and the
|
|
/// four phase-4 screens are reached from Аналитика the same way.
|
|
final List<String> alsoMatches;
|
|
|
|
/// Shown directly in the bottom bar on a phone. Everything else moves behind «Ещё».
|
|
final bool primary;
|
|
|
|
/// The longest prefix of [location] this destination claims, or -1 for no match.
|
|
int matchLength(String location) {
|
|
var best = -1;
|
|
for (final p in [path, ...alsoMatches]) {
|
|
final hit = p == '/' ? location == '/' : location.startsWith(p);
|
|
if (hit && p.length > best) best = p.length;
|
|
}
|
|
return best;
|
|
}
|
|
}
|
|
|
|
const navDestinations = [
|
|
NavDestination(
|
|
'/',
|
|
Icons.dashboard_outlined,
|
|
Icons.dashboard,
|
|
'Обзор',
|
|
NavGroup.overview,
|
|
primary: true,
|
|
),
|
|
// One entry for the phase-4 screens. They keep their own top-level routes from the
|
|
// contract and stay deep-linkable; `/analytics` is what the bars point at, and
|
|
// `alsoMatches` keeps it highlighted while you are inside any of them.
|
|
NavDestination(
|
|
'/analytics',
|
|
Icons.insights_outlined,
|
|
Icons.insights,
|
|
'Аналитика',
|
|
NavGroup.overview,
|
|
alsoMatches: ['/income', '/rebalance', '/goals', '/tax', '/portfolios'],
|
|
primary: true,
|
|
),
|
|
NavDestination(
|
|
'/portfolio',
|
|
Icons.pie_chart_outline,
|
|
Icons.pie_chart,
|
|
'Портфель',
|
|
NavGroup.overview,
|
|
primary: true,
|
|
),
|
|
NavDestination(
|
|
'/accounts',
|
|
Icons.account_balance_outlined,
|
|
Icons.account_balance,
|
|
'Счета',
|
|
NavGroup.overview,
|
|
primary: true,
|
|
),
|
|
NavDestination(
|
|
'/events',
|
|
Icons.event_note_outlined,
|
|
Icons.event_note,
|
|
'События',
|
|
NavGroup.ledger,
|
|
),
|
|
NavDestination(
|
|
'/imports',
|
|
Icons.upload_file_outlined,
|
|
Icons.upload_file,
|
|
'Импорт',
|
|
NavGroup.ledger,
|
|
alsoMatches: ['/instruments/pending'],
|
|
),
|
|
NavDestination(
|
|
'/cashflow',
|
|
Icons.swap_horiz_outlined,
|
|
Icons.swap_horiz,
|
|
'Потоки',
|
|
NavGroup.ledger,
|
|
),
|
|
NavDestination(
|
|
'/categories',
|
|
Icons.category_outlined,
|
|
Icons.category,
|
|
'Категории',
|
|
NavGroup.ledger,
|
|
),
|
|
NavDestination(
|
|
'/transactions',
|
|
Icons.receipt_long_outlined,
|
|
Icons.receipt_long,
|
|
'Операции',
|
|
NavGroup.ledger,
|
|
),
|
|
NavDestination(
|
|
'/rules',
|
|
Icons.rule_folder_outlined,
|
|
Icons.rule_folder,
|
|
'Правила',
|
|
NavGroup.ledger,
|
|
),
|
|
NavDestination(
|
|
'/health',
|
|
Icons.monitor_heart_outlined,
|
|
Icons.monitor_heart,
|
|
'Здоровье',
|
|
NavGroup.system,
|
|
),
|
|
NavDestination(
|
|
'/settings',
|
|
Icons.settings_outlined,
|
|
Icons.settings,
|
|
'Настройки',
|
|
NavGroup.system,
|
|
),
|
|
];
|