focus-flow/apps/focus_flow_flutter/lib/widgets/sidebar.dart

170 lines
4.7 KiB
Dart

/// Renders the Sidebar widget for the FocusFlow Flutter UI.
library;
import 'package:flutter/material.dart';
import '../theme/focus_flow_tokens.dart';
class Sidebar extends StatelessWidget {
const Sidebar({super.key});
@override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: const BoxDecoration(color: FocusFlowTokens.sidebarBackground),
child: Padding(
padding: const EdgeInsets.fromLTRB(18, 22, 18, 28),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const _WindowControls(),
const SizedBox(height: 34),
const _BrandRow(),
const SizedBox(height: 34),
_NavItem(
label: 'Today',
icon: Icons.calendar_today,
active: true,
onTap: () {},
),
const SizedBox(height: 16),
_NavItem(label: 'Backlog', icon: Icons.layers, onTap: () {}),
const SizedBox(height: 16),
_NavItem(label: 'Projects', icon: Icons.work_outline, onTap: () {}),
const SizedBox(height: 16),
_NavItem(label: 'Reports', icon: Icons.bar_chart, onTap: () {}),
const SizedBox(height: 30),
const Divider(color: FocusFlowTokens.subtleBorder),
const SizedBox(height: 18),
_NavItem(label: 'Settings', icon: Icons.settings, onTap: () {}),
],
),
),
);
}
}
class _WindowControls extends StatelessWidget {
const _WindowControls();
@override
Widget build(BuildContext context) {
return const Row(
children: [
_WindowDot(color: Color(0xFFFF5F57)),
SizedBox(width: 12),
_WindowDot(color: Color(0xFFFFBD2E)),
SizedBox(width: 12),
_WindowDot(color: Color(0xFF28C840)),
],
);
}
}
class _WindowDot extends StatelessWidget {
const _WindowDot({required this.color});
final Color color;
@override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
child: const SizedBox(width: 16, height: 16),
);
}
}
class _BrandRow extends StatelessWidget {
const _BrandRow();
@override
Widget build(BuildContext context) {
return Row(
children: [
Container(
width: 42,
height: 42,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: FocusFlowTokens.accentMagenta),
color: FocusFlowTokens.glassPanelStrong,
),
child: const Icon(
Icons.auto_awesome,
color: FocusFlowTokens.accentMagenta,
),
),
const SizedBox(width: 14),
Expanded(
child: Text(
'FocusFlow',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.titleMedium,
),
),
],
);
}
}
class _NavItem extends StatelessWidget {
const _NavItem({
required this.label,
required this.icon,
required this.onTap,
this.active = false,
});
final String label;
final IconData icon;
final VoidCallback onTap;
final bool active;
@override
Widget build(BuildContext context) {
final color = active
? FocusFlowTokens.accentMagenta
: FocusFlowTokens.textPrimary;
return Material(
color: Colors.transparent,
child: InkWell(
key: active ? const ValueKey('nav-today-active') : null,
borderRadius: BorderRadius.circular(FocusFlowTokens.navRadius),
onTap: onTap,
child: Container(
height: 54,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(FocusFlowTokens.navRadius),
border: Border.all(
color: active ? FocusFlowTokens.navBorder : Colors.transparent,
),
color: active
? FocusFlowTokens.glassPanelStrong
: Colors.transparent,
),
child: Row(
children: [
Icon(icon, color: color, size: 24),
const SizedBox(width: 16),
Expanded(
child: Text(
label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: color.withValues(alpha: active ? 1 : 0.88),
fontSize: FocusFlowTokens.sidebarNavSize,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
),
);
}
}