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
+66
View File
@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import '../theme/app_theme.dart';
/// The service's mark: a sky-blue-to-violet disc with three rising bars. The same drawing as
/// `web/favicon.svg` (a 512 × 512 design scaled to [size]), painted natively so the top bar
/// needs neither an asset nor an SVG package.
class ServiceMark extends StatelessWidget {
const ServiceMark({this.size = 40, super.key});
final double size;
/// The far end of the gradient; the near end is the app accent, [AppTheme.seed].
static const violet = Color(0xFF7A5CFF);
@override
Widget build(BuildContext context) {
return SizedBox.square(
dimension: size,
child: CustomPaint(painter: _MarkPainter()),
);
}
}
class _MarkPainter extends CustomPainter {
// (x, y, width, height) in the 512 design grid, tallest last
static const _bars = [
Rect.fromLTWH(132, 281, 64, 100),
Rect.fromLTWH(224, 211, 64, 170),
Rect.fromLTWH(316, 131, 64, 250),
];
@override
void paint(Canvas canvas, Size size) {
final s = size.width / 512;
final disc = Offset.zero & size;
canvas.drawCircle(
disc.center,
size.width / 2,
Paint()
..shader = const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [AppTheme.seed, ServiceMark.violet],
).createShader(disc),
);
final white = Paint()..color = Colors.white;
for (final bar in _bars) {
canvas.drawRRect(
RRect.fromRectAndRadius(
Rect.fromLTWH(
bar.left * s,
bar.top * s,
bar.width * s,
bar.height * s,
),
Radius.circular(14 * s),
),
white,
);
}
}
@override
bool shouldRepaint(_MarkPainter oldDelegate) => false;
}