Skip to content

Commit 6c932de

Browse files
author
Lukas Gundermann
committed
feat: Add and showcase new card component variations
This commit introduces several new variations of the `Card` component and updates the component showcase screen to demonstrate their usage. ### Key Changes: * **New Card Variations (`lib/screens/components/cards/cards_screen.dart`):** * **Basic Card with Icon:** A card that includes an `IconContainer` above the standard title and content. * **Card with Hover Effect:** Demonstrates a card wrapped with the `withHoverEffect` extension, which changes the border color on mouseover. This effect is theme-aware, using different colors for light and dark modes. * **Card with Action:** A card designed to contain a form. It includes a trailing `IconButton` in the header and form fields (`FormField`) with a submit button (`PrimaryButton`) in the content area. * **`IconContainer` Theming (`lib/screens/widgets/overrides/container_themes.dart`):** * The `IconContainerTheme` is now configured with distinct `backgroundColor` and `iconColor` for both light and dark modes, improving its visual integration with the theme. * **Component Screen (`lib/screens/components/cards/cards_screen.dart`):** * The `CardsScreen` has been converted to a `StatefulWidget` to manage form field keys. * It now uses `flutter_bloc` to adapt the hover effect colors based on the current theme (light/dark mode). * The layout is updated to showcase the new card examples with corresponding code snippets.
1 parent a2f56ef commit 6c932de

3 files changed

Lines changed: 274 additions & 16 deletions

File tree

lib/screens/components/cards/cards_screen.dart

Lines changed: 265 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
1+
import 'package:flutter_bloc/flutter_bloc.dart';
2+
import 'package:police_flutter_template/extensions/widget_extensions.dart';
13
import 'package:shadcn_flutter/shadcn_flutter.dart';
24

5+
import '../../../theme/cubit/theme_cubit.dart';
36
import '../../widgets/code_card.dart';
47

5-
class CardsScreen extends StatelessWidget {
8+
class CardsScreen extends StatefulWidget {
69
const CardsScreen({super.key});
710

11+
@override
12+
State<CardsScreen> createState() => _CardsScreenState();
13+
}
14+
15+
class _CardsScreenState extends State<CardsScreen> {
16+
final _firstnameKey = const TextFieldKey('firstname');
17+
final _lastnameKey = const TextFieldKey('lastname');
18+
819
@override
920
Widget build(BuildContext context) {
21+
final isDark = context.watch<ThemeCubit>().state.isDarkMode;
1022
return ConstrainedBox(
1123
constraints: BoxConstraints(maxWidth: 752),
1224
child: Column(
@@ -76,25 +88,264 @@ class CardsScreen extends StatelessWidget {
7688
),
7789
),
7890
],
79-
),
91+
).gap(10),
8092
),
8193
),
8294
lines: [
8395
CodeTextLine("Card("),
84-
CodeTextLine(" child: Basic("),
85-
CodeTextLine(" title: Text('Basis Card').base,"),
86-
CodeTextLine(" subtitle: Text("),
96+
CodeTextLine(" child: Column("),
97+
CodeTextLine(" crossAxisAlignment: CrossAxisAlignment.start,"),
98+
CodeTextLine(" children: ["),
8799
CodeTextLine(
88-
" 'Eine einfache Card-Komponente mit Titel und Text.'",
100+
" IconContainer(icon: Icon(LucideIcons.info)),",
89101
),
90-
CodeTextLine(" ).small,"),
91-
CodeTextLine(" titleSpacing: 20,"),
92-
CodeTextLine(" content: LinkButton("),
93-
CodeTextLine(" density: ButtonDensity.compact,"),
94-
CodeTextLine(" onPressed: () {},"),
95-
CodeTextLine(" trailing: Icon(LucideIcons.arrowRight),"),
96-
CodeTextLine(" child: Text('Mehr erfahren'),"),
97-
CodeTextLine(" ),"),
102+
CodeTextLine(" Basic("),
103+
CodeTextLine(" title: Text('Basis Card').base,"),
104+
CodeTextLine(" subtitle: Text("),
105+
CodeTextLine(
106+
" 'Eine einfache Card-Komponente mit Titel und Text.'",
107+
),
108+
CodeTextLine(" ).small,"),
109+
CodeTextLine(" titleSpacing: 20,"),
110+
CodeTextLine(" content: LinkButton("),
111+
CodeTextLine(" density: ButtonDensity.compact,"),
112+
CodeTextLine(" onPressed: () {},"),
113+
CodeTextLine(" trailing: Icon(LucideIcons.arrowRight),"),
114+
CodeTextLine(" child: Text('Mehr erfahren'),"),
115+
CodeTextLine(" ),"),
116+
CodeTextLine(" ),"),
117+
CodeTextLine(" ],"),
118+
CodeTextLine(" ),"),
119+
CodeTextLine(");"),
120+
],
121+
),
122+
CodeCard(
123+
title: "Basis Card mit Icon",
124+
example: SizedBox(
125+
width: double.infinity,
126+
child: Card(
127+
child: Column(
128+
crossAxisAlignment: CrossAxisAlignment.start,
129+
children: [
130+
IconContainer(icon: Icon(LucideIcons.info)),
131+
Basic(
132+
title: Text('Basis Card mit Icon').base,
133+
subtitle: Text(
134+
'Eine einfache Card-Komponente mit Titel und Text sowie einem Icon.',
135+
).small,
136+
titleSpacing: 20,
137+
content: LinkButton(
138+
density: ButtonDensity.compact,
139+
onPressed: () {},
140+
trailing: Icon(LucideIcons.arrowRight),
141+
child: Text('Mehr erfahren'),
142+
),
143+
),
144+
],
145+
).gap(10),
146+
),
147+
),
148+
lines: [
149+
CodeTextLine("Card("),
150+
CodeTextLine(" child: Column("),
151+
CodeTextLine(" crossAxisAlignment: CrossAxisAlignment.start,"),
152+
CodeTextLine(" children: ["),
153+
CodeTextLine(
154+
" IconContainer(icon: Icon(LucideIcons.info)),",
155+
),
156+
CodeTextLine(" Basic("),
157+
CodeTextLine(" title: Text('Basis Card').base,"),
158+
CodeTextLine(" subtitle: Text("),
159+
CodeTextLine(
160+
" 'Eine einfache Card-Komponente mit Titel und Text.'",
161+
),
162+
CodeTextLine(" ).small,"),
163+
CodeTextLine(" titleSpacing: 20,"),
164+
CodeTextLine(" content: LinkButton("),
165+
CodeTextLine(" density: ButtonDensity.compact,"),
166+
CodeTextLine(" onPressed: () {},"),
167+
CodeTextLine(" trailing: Icon(LucideIcons.arrowRight),"),
168+
CodeTextLine(" child: Text('Mehr erfahren'),"),
169+
CodeTextLine(" ),"),
170+
CodeTextLine(" ),"),
171+
CodeTextLine(" ],"),
172+
CodeTextLine(" ),"),
173+
CodeTextLine(");"),
174+
],
175+
),
176+
CodeCard(
177+
title: "Basis Card mit Icon und Hover effekt",
178+
example: SizedBox(
179+
width: double.infinity,
180+
child:
181+
Card(
182+
child: Column(
183+
crossAxisAlignment: CrossAxisAlignment.start,
184+
children: [
185+
IconContainer(icon: Icon(LucideIcons.info)),
186+
Basic(
187+
title: Text('Basis Card mit Icon').base,
188+
subtitle: Text(
189+
'Eine einfache Card-Komponente mit Titel und Text sowie einem Icon. Hover me um den Effekt zu sehen.',
190+
).small,
191+
titleSpacing: 20,
192+
content: LinkButton(
193+
density: ButtonDensity.compact,
194+
onPressed: () {},
195+
trailing: Icon(LucideIcons.arrowRight),
196+
child: Text('Mehr erfahren'),
197+
),
198+
),
199+
],
200+
).gap(10),
201+
).withHoverEffect(
202+
borderWidth: 2,
203+
borderColor: isDark ? Colors.gray[700] : Colors.gray[200],
204+
hoverBorderColor: isDark
205+
? Colors.red[900]
206+
: Colors.red[400],
207+
),
208+
),
209+
lines: [
210+
CodeTextLine("Card("),
211+
CodeTextLine(" child: Column("),
212+
CodeTextLine(" crossAxisAlignment: CrossAxisAlignment.start,"),
213+
CodeTextLine(" children: ["),
214+
CodeTextLine(
215+
" IconContainer(icon: Icon(LucideIcons.info)),",
216+
),
217+
CodeTextLine(" Basic("),
218+
CodeTextLine(" title: Text('Basis Card').base,"),
219+
CodeTextLine(" subtitle: Text("),
220+
CodeTextLine(
221+
" 'Eine einfache Card-Komponente mit Titel und Text.'",
222+
),
223+
CodeTextLine(" ).small,"),
224+
CodeTextLine(" titleSpacing: 20,"),
225+
CodeTextLine(" content: LinkButton("),
226+
CodeTextLine(" density: ButtonDensity.compact,"),
227+
CodeTextLine(" onPressed: () {},"),
228+
CodeTextLine(" trailing: Icon(LucideIcons.arrowRight),"),
229+
CodeTextLine(" child: Text('Mehr erfahren'),"),
230+
CodeTextLine(" ),"),
231+
CodeTextLine(" ),"),
232+
CodeTextLine(" ],"),
233+
CodeTextLine(" ),"),
234+
CodeTextLine(").withHoverEffect("),
235+
CodeTextLine(" borderWidth: 2,"),
236+
CodeTextLine(
237+
" borderColor: isDark ? Colors.gray[700] : Colors.gray[200],",
238+
),
239+
CodeTextLine(
240+
" hoverBorderColor: isDark ? Colors.red[900] : Colors.red[400],",
241+
),
242+
CodeTextLine(");"),
243+
],
244+
),
245+
CodeCard(
246+
title: "Basis Card mit Action",
247+
example: SizedBox(
248+
width: double.infinity,
249+
child: Card(
250+
child: Column(
251+
crossAxisAlignment: CrossAxisAlignment.stretch,
252+
children: [
253+
Basic(
254+
title: Text('Basis Card mit Action').base,
255+
trailing: IconButton.secondary(
256+
onPressed: () {},
257+
icon: Icon(LucideIcons.saveAll),
258+
),
259+
subtitle: Text(
260+
'Eine Card-Komponente in der hier im Anschluss ein Formular folgen kann. Speichern könnte man dan direkt darunter über den Speicher Button oder oben Rechts in der Ecke.',
261+
).small,
262+
titleSpacing: 20,
263+
content: Column(
264+
crossAxisAlignment: CrossAxisAlignment.start,
265+
children: [
266+
FormField<String>(
267+
key: _firstnameKey,
268+
label: Text('Vorname'),
269+
child: SizedBox(
270+
width: 400,
271+
child: TextField(initialValue: 'Jane'),
272+
),
273+
),
274+
FormField<String>(
275+
key: _lastnameKey,
276+
label: Text('Nachname'),
277+
child: SizedBox(
278+
width: 400,
279+
child: TextField(initialValue: 'Doe'),
280+
),
281+
),
282+
PrimaryButton(
283+
onPressed: () {},
284+
trailing: Icon(LucideIcons.save),
285+
child: Text('Speichern'),
286+
),
287+
],
288+
).gap(15),
289+
),
290+
],
291+
).gap(10),
292+
),
293+
),
294+
lines: [
295+
CodeTextLine("Card("),
296+
CodeTextLine(" child: Column("),
297+
CodeTextLine(
298+
" crossAxisAlignment: CrossAxisAlignment.stretch,",
299+
),
300+
CodeTextLine(" children: ["),
301+
CodeTextLine(" Basic("),
302+
CodeTextLine(
303+
" title: Text('Basis Card mit Action').base,",
304+
),
305+
CodeTextLine(" trailing: IconButton.secondary("),
306+
CodeTextLine(" onPressed: () {},"),
307+
CodeTextLine(" icon: Icon(LucideIcons.saveAll),"),
308+
CodeTextLine(" ),"),
309+
CodeTextLine(" subtitle: Text("),
310+
CodeTextLine(
311+
" 'Eine Card-Komponente in der hier im Anschluss ein Formular folgen kann. Speichern könnte man dan direkt darunter über den Speicher Button oder oben Rechts in der Ecke.'",
312+
),
313+
CodeTextLine(" ).small,"),
314+
CodeTextLine(" titleSpacing: 20,"),
315+
CodeTextLine(" content: Column("),
316+
CodeTextLine(
317+
" crossAxisAlignment: CrossAxisAlignment.start,",
318+
),
319+
CodeTextLine(" children: ["),
320+
CodeTextLine(" FormField<String>("),
321+
CodeTextLine(" key: _firstnameKey,"),
322+
CodeTextLine(" label: Text('Vorname'),"),
323+
CodeTextLine(" child: SizedBox("),
324+
CodeTextLine(" width: 400,"),
325+
CodeTextLine(
326+
" child: TextField(initialValue: 'Jane'),",
327+
),
328+
CodeTextLine(" ),"),
329+
CodeTextLine(" ),"),
330+
CodeTextLine(" FormField<String>("),
331+
CodeTextLine(" key: _lastnameKey,"),
332+
CodeTextLine(" label: Text('Nachname'),"),
333+
CodeTextLine(" child: SizedBox("),
334+
CodeTextLine(" width: 400,"),
335+
CodeTextLine(
336+
" child: TextField(initialValue: 'Doe'),",
337+
),
338+
CodeTextLine(" ),"),
339+
CodeTextLine(" ),"),
340+
CodeTextLine(" PrimaryButton("),
341+
CodeTextLine(" onPressed: () {},"),
342+
CodeTextLine(" trailing: Icon(LucideIcons.save),"),
343+
CodeTextLine(" child: Text('Speichern'),"),
344+
CodeTextLine(" ),"),
345+
CodeTextLine(" ],"),
346+
CodeTextLine(" ).gap(15),"),
347+
CodeTextLine(" ),"),
348+
CodeTextLine(" ],"),
98349
CodeTextLine(" ),"),
99350
CodeTextLine(");"),
100351
],

lib/screens/widgets/overrides/card_themes.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ class CardThemes extends StatelessWidget {
1212
Widget build(BuildContext context) {
1313
final isDark = context.watch<ThemeCubit>().state.isDarkMode;
1414
return ComponentTheme(
15-
data: CardTheme(fillColor: isDark ? Colors.gray[900] : Colors.white, filled: true, borderColor: isDark ? Colors.gray[700] : Colors.gray[200]),
15+
data: CardTheme(
16+
fillColor: isDark ? Colors.gray[900] : Colors.white,
17+
filled: true,
18+
borderColor: isDark ? Colors.gray[700] : Colors.gray[200],
19+
),
1620
child: child,
1721
);
1822
}

lib/screens/widgets/overrides/container_themes.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ class ContainerThemes extends StatelessWidget {
1313
final isDark = context.watch<ThemeCubit>().state.isDarkMode;
1414
return ComponentTheme(
1515
data: IconContainerTheme(
16-
16+
backgroundColor: isDark
17+
? Colors.blue[900].withAlpha(100)
18+
: Colors.blue[100],
19+
iconColor: isDark ? Colors.blue[400] : Colors.blue[900],
1720
),
1821
child: child,
1922
);

0 commit comments

Comments
 (0)