Skip to content

Commit 5572475

Browse files
xsahil03xclaude
andauthored
feat(ui): stream network image and retry badge (#81)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent cd48ab5 commit 5572475

15 files changed

Lines changed: 1455 additions & 156 deletions

apps/design_system_gallery/lib/app/gallery_app.directories.g.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import 'package:design_system_gallery/components/badge/stream_badge_notification
2828
as _design_system_gallery_components_badge_stream_badge_notification;
2929
import 'package:design_system_gallery/components/badge/stream_online_indicator.dart'
3030
as _design_system_gallery_components_badge_stream_online_indicator;
31+
import 'package:design_system_gallery/components/badge/stream_retry_badge.dart'
32+
as _design_system_gallery_components_badge_stream_retry_badge;
3133
import 'package:design_system_gallery/components/buttons/button.dart'
3234
as _design_system_gallery_components_buttons_button;
3335
import 'package:design_system_gallery/components/buttons/stream_emoji_button.dart'
@@ -38,6 +40,8 @@ import 'package:design_system_gallery/components/common/stream_flex.dart'
3840
as _design_system_gallery_components_common_stream_flex;
3941
import 'package:design_system_gallery/components/common/stream_loading_spinner.dart'
4042
as _design_system_gallery_components_common_stream_loading_spinner;
43+
import 'package:design_system_gallery/components/common/stream_network_image.dart'
44+
as _design_system_gallery_components_common_stream_network_image;
4145
import 'package:design_system_gallery/components/common/stream_progress_bar.dart'
4246
as _design_system_gallery_components_common_stream_progress_bar;
4347
import 'package:design_system_gallery/components/common/stream_skeleton_loading.dart'
@@ -365,6 +369,23 @@ final directories = <_widgetbook.WidgetbookNode>[
365369
),
366370
],
367371
),
372+
_widgetbook.WidgetbookComponent(
373+
name: 'StreamRetryBadge',
374+
useCases: [
375+
_widgetbook.WidgetbookUseCase(
376+
name: 'Playground',
377+
builder:
378+
_design_system_gallery_components_badge_stream_retry_badge
379+
.buildStreamRetryBadgePlayground,
380+
),
381+
_widgetbook.WidgetbookUseCase(
382+
name: 'Showcase',
383+
builder:
384+
_design_system_gallery_components_badge_stream_retry_badge
385+
.buildStreamRetryBadgeShowcase,
386+
),
387+
],
388+
),
368389
],
369390
),
370391
_widgetbook.WidgetbookFolder(
@@ -456,6 +477,23 @@ final directories = <_widgetbook.WidgetbookNode>[
456477
),
457478
],
458479
),
480+
_widgetbook.WidgetbookComponent(
481+
name: 'StreamNetworkImage',
482+
useCases: [
483+
_widgetbook.WidgetbookUseCase(
484+
name: 'Playground',
485+
builder:
486+
_design_system_gallery_components_common_stream_network_image
487+
.buildStreamNetworkImagePlayground,
488+
),
489+
_widgetbook.WidgetbookUseCase(
490+
name: 'Showcase',
491+
builder:
492+
_design_system_gallery_components_common_stream_network_image
493+
.buildStreamNetworkImageShowcase,
494+
),
495+
],
496+
),
459497
_widgetbook.WidgetbookComponent(
460498
name: 'StreamProgressBar',
461499
useCases: [
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:stream_core_flutter/stream_core_flutter.dart';
3+
import 'package:widgetbook/widgetbook.dart';
4+
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;
5+
6+
// =============================================================================
7+
// Playground
8+
// =============================================================================
9+
10+
@widgetbook.UseCase(
11+
name: 'Playground',
12+
type: StreamRetryBadge,
13+
path: '[Components]/Badge',
14+
)
15+
Widget buildStreamRetryBadgePlayground(BuildContext context) {
16+
final size = context.knobs.object.dropdown<StreamRetryBadgeSize>(
17+
label: 'Size',
18+
options: StreamRetryBadgeSize.values,
19+
initialOption: StreamRetryBadgeSize.md,
20+
labelBuilder: (option) => '${option.name.toUpperCase()} (${option.value.toInt()}px)',
21+
description: 'The diameter of the badge.',
22+
);
23+
24+
return Center(
25+
child: StreamRetryBadge(size: size),
26+
);
27+
}
28+
29+
// =============================================================================
30+
// Showcase
31+
// =============================================================================
32+
33+
@widgetbook.UseCase(
34+
name: 'Showcase',
35+
type: StreamRetryBadge,
36+
path: '[Components]/Badge',
37+
)
38+
Widget buildStreamRetryBadgeShowcase(BuildContext context) {
39+
final colorScheme = context.streamColorScheme;
40+
final textTheme = context.streamTextTheme;
41+
final spacing = context.streamSpacing;
42+
43+
return DefaultTextStyle(
44+
style: textTheme.bodyDefault.copyWith(color: colorScheme.textPrimary),
45+
child: SingleChildScrollView(
46+
padding: EdgeInsets.all(spacing.lg),
47+
child: const Column(
48+
crossAxisAlignment: CrossAxisAlignment.start,
49+
children: [
50+
_SizeVariantsSection(),
51+
],
52+
),
53+
),
54+
);
55+
}
56+
57+
// =============================================================================
58+
// Size Variants Section
59+
// =============================================================================
60+
61+
class _SizeVariantsSection extends StatelessWidget {
62+
const _SizeVariantsSection();
63+
64+
@override
65+
Widget build(BuildContext context) {
66+
final colorScheme = context.streamColorScheme;
67+
final textTheme = context.streamTextTheme;
68+
final boxShadow = context.streamBoxShadow;
69+
final radius = context.streamRadius;
70+
final spacing = context.streamSpacing;
71+
72+
return Column(
73+
crossAxisAlignment: CrossAxisAlignment.start,
74+
children: [
75+
const _SectionLabel(label: 'SIZE VARIANTS'),
76+
SizedBox(height: spacing.md),
77+
Container(
78+
width: double.infinity,
79+
clipBehavior: Clip.antiAlias,
80+
padding: EdgeInsets.all(spacing.md),
81+
decoration: BoxDecoration(
82+
color: colorScheme.backgroundSurface,
83+
borderRadius: BorderRadius.all(radius.lg),
84+
boxShadow: boxShadow.elevation1,
85+
),
86+
foregroundDecoration: BoxDecoration(
87+
borderRadius: BorderRadius.all(radius.lg),
88+
border: Border.all(color: colorScheme.borderSubtle),
89+
),
90+
child: Column(
91+
crossAxisAlignment: CrossAxisAlignment.start,
92+
children: [
93+
Text(
94+
'Two sizes for different contexts',
95+
style: textTheme.captionDefault.copyWith(
96+
color: colorScheme.textSecondary,
97+
),
98+
),
99+
SizedBox(height: spacing.md),
100+
Row(
101+
children: [
102+
for (final (index, size) in StreamRetryBadgeSize.values.indexed) ...[
103+
_SizeDemo(size: size),
104+
if (index < StreamRetryBadgeSize.values.length - 1) SizedBox(width: spacing.xl),
105+
],
106+
],
107+
),
108+
],
109+
),
110+
),
111+
],
112+
);
113+
}
114+
}
115+
116+
class _SizeDemo extends StatelessWidget {
117+
const _SizeDemo({required this.size});
118+
119+
final StreamRetryBadgeSize size;
120+
121+
@override
122+
Widget build(BuildContext context) {
123+
final colorScheme = context.streamColorScheme;
124+
final textTheme = context.streamTextTheme;
125+
final spacing = context.streamSpacing;
126+
127+
return Column(
128+
children: [
129+
SizedBox(
130+
width: 48,
131+
height: 48,
132+
child: Center(
133+
child: StreamRetryBadge(size: size),
134+
),
135+
),
136+
SizedBox(height: spacing.sm),
137+
Text(
138+
size.name.toUpperCase(),
139+
style: textTheme.metadataEmphasis.copyWith(
140+
color: colorScheme.accentPrimary,
141+
fontFamily: 'monospace',
142+
),
143+
),
144+
Text(
145+
'${size.value.toInt()}px',
146+
style: textTheme.metadataDefault.copyWith(
147+
color: colorScheme.textTertiary,
148+
fontFamily: 'monospace',
149+
fontSize: 10,
150+
),
151+
),
152+
],
153+
);
154+
}
155+
}
156+
157+
// =============================================================================
158+
// Shared Widgets
159+
// =============================================================================
160+
161+
class _SectionLabel extends StatelessWidget {
162+
const _SectionLabel({required this.label});
163+
164+
final String label;
165+
166+
@override
167+
Widget build(BuildContext context) {
168+
final colorScheme = context.streamColorScheme;
169+
final textTheme = context.streamTextTheme;
170+
final radius = context.streamRadius;
171+
final spacing = context.streamSpacing;
172+
173+
return Container(
174+
padding: EdgeInsets.symmetric(horizontal: spacing.sm, vertical: spacing.xs),
175+
decoration: BoxDecoration(
176+
color: colorScheme.accentPrimary,
177+
borderRadius: BorderRadius.all(radius.xs),
178+
),
179+
child: Text(
180+
label,
181+
style: textTheme.metadataEmphasis.copyWith(
182+
color: colorScheme.textOnAccent,
183+
letterSpacing: 1,
184+
fontSize: 9,
185+
),
186+
),
187+
);
188+
}
189+
}

0 commit comments

Comments
 (0)