| import 'package:jaspr/dom.dart'; |
| import 'package:jaspr/jaspr.dart'; |
| |
| import '../../../utils/styles.dart'; |
| |
| /// A reusable toggle switch for Plan Mode. |
| /// |
| /// Renders a small toggle track/thumb with a "Plan Mode" label. |
| class PlanModeToggle extends StatelessComponent { |
| const PlanModeToggle({ |
| required this.active, |
| required this.onToggle, |
| this.disabled = false, |
| super.key, |
| }); |
| |
| /// Whether plan mode is currently enabled. |
| final bool active; |
| |
| /// Called when the user taps the toggle. |
| final void Function() onToggle; |
| |
| /// Whether the toggle is disabled (e.g. while the agent is running). |
| final bool disabled; |
| |
| @override |
| Component build(BuildContext context) { |
| return button( |
| classes: 'plan-mode-toggle${active ? ' active' : ''}', |
| attributes: { |
| 'title': active ? 'Switch to build mode' : 'Switch to plan mode', |
| if (disabled) 'disabled': 'true', |
| }, |
| onClick: disabled ? null : onToggle, |
| [ |
| const div(classes: 'plan-mode-toggle-track', [ |
| div(classes: 'plan-mode-toggle-thumb', []), |
| ]), |
| const span(classes: 'plan-mode-toggle-label', [Component.text('Plan Mode')]), |
| ], |
| ); |
| } |
| |
| @css |
| static List<StyleRule> get styles => [ |
| css('.plan-mode-toggle').styles( |
| display: .inlineFlex, |
| padding: Padding.symmetric(vertical: 3.px, horizontal: 4.px), |
| border: Border.none, |
| radius: .circular(4.px), |
| cursor: .pointer, |
| transition: Transition('opacity', duration: 150.ms, curve: .ease), |
| alignItems: .center, |
| gap: Gap.all(6.px), |
| backgroundColor: Colors.transparent, |
| ), |
| css('.plan-mode-toggle:hover:not(:disabled)').styles( |
| opacity: 0.85, |
| ), |
| css('.plan-mode-toggle:disabled').styles( |
| opacity: 0.4, |
| cursor: .notAllowed, |
| ), |
| css('.plan-mode-toggle-track').styles( |
| position: const Position.relative(), |
| width: 26.px, |
| height: 14.px, |
| radius: .circular(7.px), |
| transition: Transition('background-color', duration: 200.ms, curve: .ease), |
| backgroundColor: colorContainerHigh, |
| raw: {'flex-shrink': '0'}, |
| ), |
| css('.plan-mode-toggle.active .plan-mode-toggle-track').styles( |
| backgroundColor: colorPrimary, |
| ), |
| css('.plan-mode-toggle-thumb').styles( |
| position: Position.absolute(top: 2.px, left: 2.px), |
| width: 10.px, |
| height: 10.px, |
| radius: .circular(5.px), |
| transition: Transition('transform', duration: 200.ms, curve: .ease), |
| backgroundColor: colorOnSurfaceVariant, |
| ), |
| css('.plan-mode-toggle.active .plan-mode-toggle-thumb').styles( |
| backgroundColor: colorOnPrimary, |
| raw: {'transform': 'translateX(12px)'}, |
| ), |
| css('.plan-mode-toggle-label').styles( |
| transition: Transition('color', duration: 200.ms, curve: .ease), |
| color: colorOnSurface, |
| fontSize: 11.px, |
| fontWeight: .w500, |
| raw: {'user-select': 'none'}, |
| ), |
| ]; |
| } |