// SPDX-FileCopyrightText: 2026 FocusFlow contributors // SPDX-License-Identifier: AGPL-3.0-only /// Renders the Sidebar widget for the FocusFlow Flutter UI. library; import 'package:flutter/material.dart'; import '../theme/focus_flow_tokens.dart'; /// Static sidebar for primary FocusFlow navigation. class Sidebar extends StatelessWidget { /// Creates the FocusFlow sidebar. const Sidebar({super.key}); /// Builds the widget subtree for this component. /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @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: () {}), ], ), ), ); } } /// Private implementation type for `_WindowControls` in this library. /// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _WindowControls extends StatelessWidget { /// Creates a `_WindowControls` instance with the values required by its invariants. /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _WindowControls(); /// Builds the widget subtree for this component. /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @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)), ], ); } } /// Private implementation type for `_WindowDot` in this library. /// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _WindowDot extends StatelessWidget { /// Creates a `_WindowDot` instance with the values required by its invariants. /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _WindowDot({required this.color}); /// Stores the `color` value for this object. /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final Color color; /// Builds the widget subtree for this component. /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @override Widget build(BuildContext context) { return DecoratedBox( decoration: BoxDecoration(color: color, shape: BoxShape.circle), child: const SizedBox(width: 16, height: 16), ); } } /// Private implementation type for `_BrandRow` in this library. /// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _BrandRow extends StatelessWidget { /// Creates a `_BrandRow` instance with the values required by its invariants. /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _BrandRow(); /// Builds the widget subtree for this component. /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @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, ), ), ], ); } } /// Private implementation type for `_NavItem` in this library. /// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly. class _NavItem extends StatelessWidget { /// Creates a `_NavItem` instance with the values required by its invariants. /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code. const _NavItem({ required this.label, required this.icon, required this.onTap, this.active = false, }); /// Stores the `label` value for this object. /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final String label; /// Stores the `icon` value for this object. /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final IconData icon; /// Stores the `onTap` value for this object. /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final VoidCallback onTap; /// Stores the `active` value for this object. /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior. final bool active; /// Builds the widget subtree for this component. /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data. @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, ), ), ), ], ), ), ), ); } }