neoagent 2.4.1-beta.30 → 2.4.1-beta.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/flutter_app/assets/branding/onboarding_intro.mp4 +0 -0
  2. package/flutter_app/lib/features/onboarding/onboarding_chrome.dart +391 -382
  3. package/flutter_app/lib/features/onboarding/onboarding_companion_step.dart +78 -56
  4. package/flutter_app/lib/features/onboarding/onboarding_messaging_step.dart +18 -16
  5. package/flutter_app/lib/features/onboarding/onboarding_model_step.dart +18 -17
  6. package/flutter_app/lib/features/onboarding/onboarding_shell.dart +2 -1
  7. package/flutter_app/lib/features/onboarding/onboarding_video_step.dart +16 -13
  8. package/flutter_app/lib/features/onboarding/onboarding_welcome_step.dart +15 -11
  9. package/flutter_app/lib/main_account_settings.dart +1 -1
  10. package/flutter_app/lib/main_admin.dart +1 -1
  11. package/flutter_app/lib/main_app_shell.dart +190 -191
  12. package/flutter_app/lib/main_chat.dart +381 -228
  13. package/flutter_app/lib/main_devices.dart +1 -1
  14. package/flutter_app/lib/main_launcher.dart +1 -1
  15. package/flutter_app/lib/main_operations.dart +3 -3
  16. package/flutter_app/lib/main_shared.dart +336 -340
  17. package/flutter_app/lib/main_spacing.dart +4 -4
  18. package/flutter_app/lib/main_theme.dart +20 -14
  19. package/flutter_app/lib/src/theme/palette.dart +76 -34
  20. package/flutter_app/pubspec.lock +2 -2
  21. package/flutter_app/pubspec.yaml +1 -1
  22. package/package.json +1 -1
  23. package/server/public/.last_build_id +1 -1
  24. package/server/public/assets/assets/branding/onboarding_intro.mp4 +0 -0
  25. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  26. package/server/public/flutter_bootstrap.js +1 -1
  27. package/server/public/main.dart.js +60738 -60521
@@ -1,6 +1,7 @@
1
1
  import 'package:flutter/material.dart';
2
2
  import 'package:flutter_animate/flutter_animate.dart';
3
3
 
4
+ import '../../src/theme/palette.dart';
4
5
  import 'onboarding_chrome.dart';
5
6
 
6
7
  class OnboardingWelcomeStep extends StatelessWidget {
@@ -29,17 +30,20 @@ class OnboardingWelcomeStep extends StatelessWidget {
29
30
  .slideY(begin: 0.2),
30
31
  ],
31
32
  ),
32
- child: Align(
33
- alignment: Alignment.topLeft,
34
- child: Text(
35
- 'Set up your workspace in a few steps and start using NeoAgent immediately.',
36
- style: TextStyle(
37
- color: Colors.white.withValues(alpha: 0.72),
38
- fontSize: 18,
39
- height: 1.55,
40
- fontWeight: FontWeight.w500,
41
- ),
42
- ).animate().fadeIn(duration: 600.ms, delay: 380.ms),
33
+ child: Builder(
34
+ builder: (context) {
35
+ final p = paletteOf(context);
36
+ return Align(
37
+ alignment: Alignment.topLeft,
38
+ child: Text(
39
+ 'Set up your workspace in a few steps and start using NeoAgent immediately.',
40
+ style: Theme.of(context).textTheme.bodyLarge?.copyWith(
41
+ color: p.textSecondary,
42
+ height: 1.6,
43
+ ),
44
+ ).animate().fadeIn(duration: 600.ms, delay: 380.ms),
45
+ );
46
+ },
43
47
  ),
44
48
  );
45
49
  }
@@ -1173,7 +1173,7 @@ class _QrLoginScannerDialogState extends State<_QrLoginScannerDialog> {
1173
1173
  const SizedBox(height: 28),
1174
1174
  Text(
1175
1175
  'Scan a NeoAgent login QR',
1176
- style: GoogleFonts.spaceGrotesk(
1176
+ style: GoogleFonts.geist(
1177
1177
  fontSize: 28,
1178
1178
  fontWeight: FontWeight.w700,
1179
1179
  color: Colors.white,
@@ -437,7 +437,7 @@ class McpPanel extends StatelessWidget {
437
437
  Text(
438
438
  server.command,
439
439
  style: TextStyle(
440
- fontFamily: GoogleFonts.jetBrainsMono().fontFamily,
440
+ fontFamily: GoogleFonts.geistMono().fontFamily,
441
441
  color: _textSecondary,
442
442
  ),
443
443
  ),
@@ -769,7 +769,7 @@ class _AuthViewState extends State<AuthView> {
769
769
  Text(
770
770
  'Scan with NeoAgent on your phone',
771
771
  textAlign: titleAlignment,
772
- style: GoogleFonts.spaceGrotesk(
772
+ style: GoogleFonts.geist(
773
773
  fontSize: titleSize,
774
774
  fontWeight: FontWeight.w700,
775
775
  letterSpacing: compact ? -0.3 : -0.6,
@@ -1202,70 +1202,54 @@ class _HomeViewState extends State<HomeView> {
1202
1202
  final wide = MediaQuery.sizeOf(context).width >= 1080;
1203
1203
 
1204
1204
  if (wide) {
1205
- return _AmbientBackdrop(
1205
+ return _ControlSurfaceBackdrop(
1206
1206
  child: Scaffold(
1207
1207
  backgroundColor: Colors.transparent,
1208
- body: SafeArea(
1209
- child: Padding(
1210
- padding: const EdgeInsets.all(14),
1211
- child: Row(
1212
- children: <Widget>[
1213
- _Sidebar(
1214
- controller: controller,
1215
- expandedGroup: _expandedSidebarGroup,
1216
- onToggleGroup: _toggleSidebarGroup,
1217
- ),
1218
- const SizedBox(width: 14),
1219
- Expanded(
1220
- child: _GlassSurface(
1221
- borderRadius: BorderRadius.circular(32),
1222
- blurSigma: 28,
1223
- boxShadow: _softPanelShadow,
1224
- overlayGradient: _panelGradient,
1225
- fillColor: _glassFill,
1226
- child: ClipRRect(
1227
- borderRadius: BorderRadius.circular(32),
1228
- child: AnimatedSwitcher(
1229
- duration: const Duration(milliseconds: 320),
1230
- switchInCurve: Curves.easeOutBack,
1231
- switchOutCurve: Curves.easeInCubic,
1232
- transitionBuilder: (child, animation) {
1233
- final offset = Tween<Offset>(
1234
- begin: const Offset(0.018, 0.026),
1235
- end: Offset.zero,
1236
- ).animate(animation);
1237
- final scale = Tween<double>(
1238
- begin: 0.992,
1239
- end: 1,
1240
- ).animate(animation);
1241
- return ScaleTransition(
1242
- scale: scale,
1243
- alignment: Alignment.topCenter,
1244
- child: FadeTransition(
1245
- opacity: animation,
1246
- child: SlideTransition(
1247
- position: offset,
1248
- child: child,
1249
- ),
1250
- ),
1251
- );
1252
- },
1253
- child: KeyedSubtree(
1254
- key: ValueKey<AppSection>(
1255
- controller.selectedSection,
1256
- ),
1257
- child: _SectionBody(
1258
- controller: controller,
1259
- devicesPanelKey: _devicesPanelKey,
1260
- ),
1208
+ body: Row(
1209
+ children: <Widget>[
1210
+ _Sidebar(
1211
+ controller: controller,
1212
+ expandedGroup: _expandedSidebarGroup,
1213
+ onToggleGroup: _toggleSidebarGroup,
1214
+ ),
1215
+ Expanded(
1216
+ child: ClipRect(
1217
+ child: AnimatedSwitcher(
1218
+ duration: const Duration(milliseconds: 320),
1219
+ switchInCurve: Curves.easeOutBack,
1220
+ switchOutCurve: Curves.easeInCubic,
1221
+ transitionBuilder: (child, animation) {
1222
+ final offset = Tween<Offset>(
1223
+ begin: const Offset(0.018, 0.026),
1224
+ end: Offset.zero,
1225
+ ).animate(animation);
1226
+ final scale = Tween<double>(
1227
+ begin: 0.992,
1228
+ end: 1,
1229
+ ).animate(animation);
1230
+ return ScaleTransition(
1231
+ scale: scale,
1232
+ alignment: Alignment.topCenter,
1233
+ child: FadeTransition(
1234
+ opacity: animation,
1235
+ child: SlideTransition(
1236
+ position: offset,
1237
+ child: child,
1261
1238
  ),
1262
1239
  ),
1240
+ );
1241
+ },
1242
+ child: KeyedSubtree(
1243
+ key: ValueKey<AppSection>(controller.selectedSection),
1244
+ child: _SectionBody(
1245
+ controller: controller,
1246
+ devicesPanelKey: _devicesPanelKey,
1263
1247
  ),
1264
1248
  ),
1265
1249
  ),
1266
- ],
1250
+ ),
1267
1251
  ),
1268
- ),
1252
+ ],
1269
1253
  ),
1270
1254
  ),
1271
1255
  );
@@ -1293,14 +1277,16 @@ class _HomeViewState extends State<HomeView> {
1293
1277
  body: SafeArea(
1294
1278
  child: Padding(
1295
1279
  padding: const EdgeInsets.fromLTRB(12, 0, 12, 10),
1296
- child: _GlassSurface(
1297
- borderRadius: BorderRadius.circular(26),
1298
- blurSigma: 24,
1299
- boxShadow: _softPanelShadow,
1300
- overlayGradient: _panelGradient,
1301
- fillColor: _glassFill,
1280
+ child: Container(
1281
+ decoration: BoxDecoration(
1282
+ color: _bgPrimary,
1283
+ borderRadius: BorderRadius.circular(22),
1284
+ border: Border.all(color: _border),
1285
+ boxShadow: _softPanelShadow,
1286
+ ),
1287
+ clipBehavior: Clip.antiAlias,
1302
1288
  child: ClipRRect(
1303
- borderRadius: BorderRadius.circular(26),
1289
+ borderRadius: BorderRadius.circular(22),
1304
1290
  child: AnimatedSwitcher(
1305
1291
  duration: const Duration(milliseconds: 280),
1306
1292
  switchInCurve: Curves.easeOutBack,
@@ -1436,55 +1422,58 @@ class _Sidebar extends StatelessWidget {
1436
1422
 
1437
1423
  @override
1438
1424
  Widget build(BuildContext context) {
1439
- return _GlassSurface(
1440
- width: 254,
1441
- borderRadius: BorderRadius.circular(30),
1442
- blurSigma: 26,
1443
- boxShadow: _softPanelShadow,
1444
- fillColor: _bgSecondary.withValues(alpha: 0.34),
1445
- overlayGradient: LinearGradient(
1446
- colors: <Color>[
1447
- _bgSecondary.withValues(alpha: 0.96),
1448
- _bgTertiary.withValues(alpha: 0.88),
1449
- ],
1450
- begin: Alignment.topCenter,
1451
- end: Alignment.bottomCenter,
1425
+ return Container(
1426
+ width: 268,
1427
+ decoration: BoxDecoration(
1428
+ color: _bgSecondary,
1429
+ border: Border(right: BorderSide(color: _border)),
1452
1430
  ),
1453
1431
  child: Column(
1454
1432
  children: <Widget>[
1455
- Container(
1456
- padding: const EdgeInsets.fromLTRB(18, 20, 18, 18),
1457
- decoration: BoxDecoration(
1458
- border: Border(bottom: BorderSide(color: _border)),
1459
- ),
1460
- child: Column(
1461
- crossAxisAlignment: CrossAxisAlignment.start,
1433
+ Padding(
1434
+ padding: const EdgeInsets.fromLTRB(20, 18, 18, 12),
1435
+ child: Row(
1462
1436
  children: <Widget>[
1463
- Row(
1464
- children: <Widget>[
1465
- Expanded(
1466
- child: const _BrandLockup(
1467
- logoSize: 34,
1468
- titleFontSize: 18,
1469
- direction: Axis.horizontal,
1470
- spacing: 12,
1471
- alignment: CrossAxisAlignment.start,
1437
+ const _LogoBadge(size: 38),
1438
+ const SizedBox(width: 11),
1439
+ Expanded(
1440
+ child: Column(
1441
+ crossAxisAlignment: CrossAxisAlignment.start,
1442
+ mainAxisSize: MainAxisSize.min,
1443
+ children: <Widget>[
1444
+ Text(
1445
+ 'NeoAgent',
1446
+ style: GoogleFonts.geist(
1447
+ fontSize: 17,
1448
+ fontWeight: FontWeight.w600,
1449
+ color: _textPrimary,
1450
+ letterSpacing: -0.3,
1451
+ ),
1472
1452
  ),
1473
- ),
1474
- ],
1453
+ const SizedBox(height: 2),
1454
+ Text(
1455
+ 'CONTROL SURFACE',
1456
+ style: GoogleFonts.geistMono(
1457
+ fontSize: 9.5,
1458
+ fontWeight: FontWeight.w600,
1459
+ color: _textMuted,
1460
+ letterSpacing: 1.8,
1461
+ ),
1462
+ ),
1463
+ ],
1464
+ ),
1475
1465
  ),
1476
1466
  ],
1477
1467
  ),
1478
1468
  ),
1479
- if (controller.agentProfiles.isNotEmpty) ...<Widget>[
1469
+ if (controller.agentProfiles.isNotEmpty)
1480
1470
  Padding(
1481
- padding: const EdgeInsets.fromLTRB(14, 12, 14, 12),
1471
+ padding: const EdgeInsets.fromLTRB(14, 2, 14, 14),
1482
1472
  child: _AgentSwitcher(controller: controller),
1483
1473
  ),
1484
- ],
1485
1474
  Expanded(
1486
1475
  child: ListView(
1487
- padding: const EdgeInsets.all(8),
1476
+ padding: const EdgeInsets.fromLTRB(12, 0, 12, 8),
1488
1477
  children: _buildSidebarItems(
1489
1478
  controller,
1490
1479
  onSelect: controller.setSelectedSection,
@@ -1494,40 +1483,42 @@ class _Sidebar extends StatelessWidget {
1494
1483
  ),
1495
1484
  ),
1496
1485
  Container(
1497
- padding: const EdgeInsets.all(10),
1486
+ padding: const EdgeInsets.fromLTRB(16, 12, 12, 14),
1498
1487
  decoration: BoxDecoration(
1499
1488
  border: Border(top: BorderSide(color: _border)),
1500
1489
  ),
1501
- child: Column(
1490
+ child: Row(
1502
1491
  children: <Widget>[
1503
- Row(
1504
- children: <Widget>[
1505
- Expanded(
1506
- child: Text(
1507
- controller.accountLabel,
1508
- maxLines: 1,
1509
- overflow: TextOverflow.ellipsis,
1510
- style: TextStyle(
1511
- color: _textSecondary,
1512
- fontSize: 12,
1513
- fontWeight: FontWeight.w600,
1514
- ),
1515
- ),
1516
- ),
1517
- const SizedBox(width: 8),
1518
- _ProfileSettingsButton(
1519
- controller: controller,
1520
- onTap: () => controller.setSelectedSection(
1521
- AppSection.accountSettings,
1522
- ),
1523
- ),
1524
- const SizedBox(width: 8),
1525
- _SidebarIconButton(
1526
- tooltip: 'Logout',
1527
- icon: Icons.logout,
1528
- onTap: controller.logout,
1492
+ _SidebarAccountAvatar(
1493
+ controller: controller,
1494
+ onTap: () =>
1495
+ controller.setSelectedSection(AppSection.accountSettings),
1496
+ ),
1497
+ const SizedBox(width: 10),
1498
+ Expanded(
1499
+ child: Text(
1500
+ controller.accountLabel,
1501
+ maxLines: 1,
1502
+ overflow: TextOverflow.ellipsis,
1503
+ style: GoogleFonts.geist(
1504
+ color: _textSecondary,
1505
+ fontSize: 12.5,
1506
+ fontWeight: FontWeight.w500,
1529
1507
  ),
1530
- ],
1508
+ ),
1509
+ ),
1510
+ const SizedBox(width: 8),
1511
+ _SidebarIconButton(
1512
+ tooltip: 'Settings',
1513
+ icon: Icons.settings_outlined,
1514
+ onTap: () =>
1515
+ controller.setSelectedSection(AppSection.accountSettings),
1516
+ ),
1517
+ const SizedBox(width: 2),
1518
+ _SidebarIconButton(
1519
+ tooltip: 'Logout',
1520
+ icon: Icons.logout,
1521
+ onTap: controller.logout,
1531
1522
  ),
1532
1523
  ],
1533
1524
  ),
@@ -1597,27 +1588,14 @@ class _AgentSwitcherState extends State<_AgentSwitcher> {
1597
1588
  menuChildren: <Widget>[
1598
1589
  SizedBox(
1599
1590
  width: 320,
1600
- child: _GlassSurface(
1601
- borderRadius: BorderRadius.circular(24),
1602
- blurSigma: 28,
1603
- fillColor: _bgCard.withValues(alpha: 0.9),
1604
- overlayGradient: LinearGradient(
1605
- colors: <Color>[
1606
- Colors.white.withValues(alpha: 0.1),
1607
- _bgSecondary.withValues(alpha: 0.92),
1608
- _bgPrimary.withValues(alpha: 0.94),
1609
- ],
1610
- begin: Alignment.topLeft,
1611
- end: Alignment.bottomRight,
1591
+ child: Container(
1592
+ decoration: BoxDecoration(
1593
+ color: _bgCard,
1594
+ borderRadius: BorderRadius.circular(18),
1595
+ border: Border.all(color: _border),
1596
+ boxShadow: _softPanelShadow,
1612
1597
  ),
1613
- boxShadow: <BoxShadow>[
1614
- ..._softPanelShadow,
1615
- BoxShadow(
1616
- color: Colors.black.withValues(alpha: 0.22),
1617
- blurRadius: 28,
1618
- offset: const Offset(0, 16),
1619
- ),
1620
- ],
1598
+ clipBehavior: Clip.antiAlias,
1621
1599
  child: Padding(
1622
1600
  padding: const EdgeInsets.all(10),
1623
1601
  child: Column(
@@ -1645,37 +1623,27 @@ class _AgentSwitcherState extends State<_AgentSwitcher> {
1645
1623
  child: Tooltip(
1646
1624
  message: 'Switch agent',
1647
1625
  child: InkWell(
1648
- borderRadius: BorderRadius.circular(24),
1626
+ borderRadius: BorderRadius.circular(14),
1649
1627
  onTap: _toggleMenu,
1650
1628
  child: AnimatedContainer(
1651
1629
  duration: const Duration(milliseconds: 180),
1652
1630
  curve: Curves.easeOutCubic,
1653
- padding: const EdgeInsets.fromLTRB(12, 9, 12, 9),
1631
+ padding: const EdgeInsets.all(12),
1654
1632
  decoration: BoxDecoration(
1655
- borderRadius: BorderRadius.circular(24),
1656
- gradient: LinearGradient(
1657
- colors: <Color>[
1658
- Colors.white.withValues(alpha: isMenuOpen ? 0.13 : 0.08),
1659
- _accentMuted.withValues(alpha: isMenuOpen ? 0.24 : 0.14),
1660
- _bgSecondary.withValues(alpha: isMenuOpen ? 0.92 : 0.84),
1661
- ],
1662
- begin: Alignment.topLeft,
1663
- end: Alignment.bottomRight,
1664
- ),
1633
+ borderRadius: BorderRadius.circular(14),
1634
+ color: _bgCard,
1665
1635
  border: Border.all(
1666
1636
  color: isMenuOpen
1667
- ? _accent.withValues(alpha: 0.65)
1637
+ ? _accent.withValues(alpha: 0.45)
1668
1638
  : _borderLight,
1669
1639
  ),
1670
- boxShadow: isMenuOpen
1671
- ? <BoxShadow>[
1672
- BoxShadow(
1673
- color: _accent.withValues(alpha: 0.16),
1674
- blurRadius: 24,
1675
- offset: const Offset(0, 10),
1676
- ),
1677
- ]
1678
- : null,
1640
+ boxShadow: <BoxShadow>[
1641
+ BoxShadow(
1642
+ color: Colors.black.withValues(alpha: 0.05),
1643
+ blurRadius: 8,
1644
+ offset: const Offset(0, 1),
1645
+ ),
1646
+ ],
1679
1647
  ),
1680
1648
  child: Row(
1681
1649
  children: <Widget>[
@@ -1781,24 +1749,16 @@ class _AgentSwitcherMenuItem extends StatelessWidget {
1781
1749
  child: Tooltip(
1782
1750
  message: agent.displayName,
1783
1751
  child: InkWell(
1784
- borderRadius: BorderRadius.circular(18),
1752
+ borderRadius: BorderRadius.circular(14),
1785
1753
  onTap: onTap,
1786
1754
  child: Ink(
1787
1755
  decoration: BoxDecoration(
1788
- borderRadius: BorderRadius.circular(18),
1789
- gradient: selected
1790
- ? LinearGradient(
1791
- colors: <Color>[
1792
- _accent.withValues(alpha: 0.18),
1793
- _accentMuted.withValues(alpha: 0.3),
1794
- ],
1795
- begin: Alignment.topLeft,
1796
- end: Alignment.bottomRight,
1797
- )
1798
- : null,
1799
- color: selected ? null : Colors.white.withValues(alpha: 0.025),
1756
+ borderRadius: BorderRadius.circular(14),
1757
+ color: selected ? _accent.withValues(alpha: 0.10) : _bgSecondary,
1800
1758
  border: Border.all(
1801
- color: selected ? _accent.withValues(alpha: 0.5) : _borderLight,
1759
+ color: selected
1760
+ ? _accent.withValues(alpha: 0.55)
1761
+ : _borderLight,
1802
1762
  ),
1803
1763
  ),
1804
1764
  child: Padding(
@@ -1900,12 +1860,12 @@ class _AgentGlyph extends StatelessWidget {
1900
1860
  Widget build(BuildContext context) {
1901
1861
  final baseColor = agent.isDefault ? _accent : _accentAlt;
1902
1862
  final initials = _agentInitials(agent.displayName);
1903
- final size = compact ? 42.0 : 44.0;
1863
+ final size = compact ? 38.0 : 42.0;
1904
1864
  return Container(
1905
1865
  width: size,
1906
1866
  height: size,
1907
1867
  decoration: BoxDecoration(
1908
- shape: BoxShape.circle,
1868
+ borderRadius: BorderRadius.circular(compact ? 11 : 12),
1909
1869
  gradient: LinearGradient(
1910
1870
  colors: <Color>[
1911
1871
  baseColor.withValues(alpha: selected ? 0.85 : 0.65),
@@ -1966,9 +1926,9 @@ class _AgentTag extends StatelessWidget {
1966
1926
  @override
1967
1927
  Widget build(BuildContext context) {
1968
1928
  return Container(
1969
- padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 4),
1929
+ padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
1970
1930
  decoration: BoxDecoration(
1971
- borderRadius: BorderRadius.circular(999),
1931
+ borderRadius: BorderRadius.circular(5),
1972
1932
  color: color.withValues(alpha: 0.14),
1973
1933
  border: Border.all(color: color.withValues(alpha: 0.3)),
1974
1934
  ),
@@ -1976,9 +1936,9 @@ class _AgentTag extends StatelessWidget {
1976
1936
  label,
1977
1937
  style: TextStyle(
1978
1938
  color: foreground,
1979
- fontSize: 9.5,
1980
- fontWeight: FontWeight.w800,
1981
- letterSpacing: 0.6,
1939
+ fontSize: 9,
1940
+ fontWeight: FontWeight.w600,
1941
+ letterSpacing: 1,
1982
1942
  ),
1983
1943
  ),
1984
1944
  );
@@ -2061,6 +2021,45 @@ class _ProfileSettingsButton extends StatelessWidget {
2061
2021
  }
2062
2022
  }
2063
2023
 
2024
+ class _SidebarAccountAvatar extends StatelessWidget {
2025
+ const _SidebarAccountAvatar({required this.controller, required this.onTap});
2026
+
2027
+ final NeoAgentController controller;
2028
+ final VoidCallback onTap;
2029
+
2030
+ @override
2031
+ Widget build(BuildContext context) {
2032
+ final label = controller.accountLabel.trim();
2033
+ final initial = label.isEmpty ? 'N' : label.characters.first.toUpperCase();
2034
+ final active = controller.selectedSection == AppSection.accountSettings;
2035
+ return Tooltip(
2036
+ message: 'Account settings',
2037
+ child: InkWell(
2038
+ borderRadius: BorderRadius.circular(999),
2039
+ onTap: onTap,
2040
+ child: Container(
2041
+ width: 30,
2042
+ height: 30,
2043
+ decoration: BoxDecoration(
2044
+ shape: BoxShape.circle,
2045
+ color: active ? _accentMuted : _bgCard,
2046
+ border: Border.all(color: active ? _accent : _borderLight),
2047
+ ),
2048
+ alignment: Alignment.center,
2049
+ child: Text(
2050
+ initial,
2051
+ style: TextStyle(
2052
+ color: active ? _accentHover : _textPrimary,
2053
+ fontWeight: FontWeight.w700,
2054
+ fontSize: 11,
2055
+ ),
2056
+ ),
2057
+ ),
2058
+ ),
2059
+ );
2060
+ }
2061
+ }
2062
+
2064
2063
  class _MobileDrawer extends StatelessWidget {
2065
2064
  const _MobileDrawer({
2066
2065
  required this.controller,