| import 'package:jaspr/dom.dart'; |
| import 'package:jaspr/jaspr.dart'; |
| |
| import '../../../utils/styles.dart'; |
| |
| /// A fullscreen loading overlay with a spinner and configurable text. |
| /// |
| /// Use this component to show a blocking loading state on top of a page. |
| /// The overlay is absolutely positioned and covers its parent container. |
| class LoadingOverlay extends StatelessComponent { |
| const LoadingOverlay({required this.text, super.key}); |
| |
| /// The message displayed below the spinner. |
| final String text; |
| |
| @override |
| Component build(BuildContext context) { |
| return div(classes: 'loading-overlay', [ |
| const div(classes: 'loading-overlay-spinner', []), |
| span(classes: 'loading-overlay-text', [.text(text)]), |
| ]); |
| } |
| |
| @css |
| static List<StyleRule> get styles => [ |
| css.keyframes('loading-overlay-spin', { |
| '0%': const Styles(raw: {'transform': 'rotate(0deg)'}), |
| '100%': const Styles(raw: {'transform': 'rotate(360deg)'}), |
| }), |
| css('.loading-overlay').styles( |
| display: .flex, |
| position: const Position.absolute(top: Unit.zero, left: Unit.zero), |
| zIndex: const ZIndex(1000), |
| width: 100.percent, |
| height: 100.percent, |
| flexDirection: .column, |
| justifyContent: .center, |
| alignItems: .center, |
| gap: Gap.all(16.px), |
| raw: { |
| 'background-color': 'color-mix(in srgb, var(--color-surface) 75%, transparent)', |
| 'backdrop-filter': 'blur(4px)', |
| }, |
| ), |
| css('.loading-overlay-spinner').styles( |
| width: 32.px, |
| height: 32.px, |
| border: Border.all(color: colorBorder, width: 3.px), |
| radius: .circular(999.px), |
| raw: { |
| 'border-top-color': 'transparent', |
| 'animation': 'loading-overlay-spin 0.8s linear infinite', |
| }, |
| ), |
| css('.loading-overlay-text').styles( |
| color: colorOnSurfaceVariant, |
| fontSize: 14.px, |
| fontWeight: .w500, |
| ), |
| ]; |
| } |