Skip to content

Commit a46f1f4

Browse files
author
Lukas Gundermann
committed
feat: Add technology stack section to home page
This commit introduces a new `TechnologyStack` widget to the home screen, which showcases the core technologies and libraries used in the project. ### Key Changes: * **`TechnologyStack` Widget (`lib/screens/home/widgets/technology_stack.dart`):** * A new, self-contained widget that displays the "Technologie Stack." * Features a title, a descriptive subtitle, and a responsive `GridView`. * The grid displays cards for various technology categories, such as State Management, Routing, UI, and Networking. * Each card (`_StackCard`) contains an icon, a title, and a short description of the specific libraries used. * The section's background color adapts to the current theme (light/dark mode). * **`HomeScreen` (`lib/screens/home/home_screen.dart`):** * The new `TechnologyStack` widget is integrated into the `HomeScreen`, appearing below the "Installation" section.
1 parent 1fdcc32 commit a46f1f4

2 files changed

Lines changed: 128 additions & 1 deletion

File tree

lib/screens/home/home_screen.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:police_flutter_template/screens/home/widgets/hero_section.dart';
22
import 'package:police_flutter_template/screens/home/widgets/installation.dart';
3+
import 'package:police_flutter_template/screens/home/widgets/technology_stack.dart';
34
import 'package:shadcn_flutter/shadcn_flutter.dart';
45

56
class HomeScreen extends StatelessWidget {
@@ -9,7 +10,7 @@ class HomeScreen extends StatelessWidget {
910
Widget build(BuildContext context) {
1011
return Column(
1112
mainAxisSize: MainAxisSize.max,
12-
children: [HeroSection(), Installation(), Gap(29)],
13+
children: [HeroSection(), Installation(), TechnologyStack()],
1314
);
1415
}
1516
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import 'package:flutter_bloc/flutter_bloc.dart';
2+
import 'package:shadcn_flutter/shadcn_flutter.dart';
3+
4+
import '../../../extensions/text_extensions.dart';
5+
import '../../../theme/cubit/theme_cubit.dart';
6+
7+
class TechnologyStack extends StatelessWidget {
8+
const TechnologyStack({super.key});
9+
10+
/// Static list of feature cards displayed in the hero grid.
11+
final List<_StackCard> _heroCards = const [
12+
_StackCard(title: "Flutter", text: "aktueller Stable-Channel empfohlen"),
13+
_StackCard(title: "State Management", text: "flutter_bloc, equatable"),
14+
_StackCard(title: "Routing", text: "go_router"),
15+
_StackCard(title: "Networking", text: "dio"),
16+
_StackCard(title: "Dependency Injection", text: "get_it"),
17+
_StackCard(title: "Secure Storage", text: "flutter_secure_storage"),
18+
_StackCard(
19+
title: "Logging/Observability",
20+
text: "talker_flutter, talker_bloc_logger, talker_dio_logger",
21+
),
22+
_StackCard(
23+
title: "UI",
24+
text: "shadcn_flutter, flutter_svg, flutter_animate, flutter_spinkit",
25+
),
26+
];
27+
28+
@override
29+
Widget build(BuildContext context) {
30+
final isDarkMode = context.watch<ThemeCubit>().state.isDarkMode;
31+
return Container(
32+
width: double.infinity,
33+
color: isDarkMode ? Colors.gray[950] : Colors.gray[50],
34+
child: Column(
35+
children: [
36+
Text('Technologie Stack').bold.responsive(
37+
context,
38+
mobile: (t) => t.x3Large,
39+
tablet: (t) => t.x3Large,
40+
desktop: (t) => t.x4Large,
41+
),
42+
Gap(16),
43+
Text(
44+
'Moderne und bewährte Technologien für beste Performance',
45+
).setColors(
46+
lightColor: Colors.gray[600],
47+
darkColor: Colors.gray[400],
48+
),
49+
Gap(48),
50+
Container(
51+
constraints: const BoxConstraints(maxWidth: 1000),
52+
padding: const EdgeInsets.symmetric(horizontal: 16),
53+
child: LayoutBuilder(
54+
builder: (context, constraints) {
55+
const spacing = 16.0;
56+
const minCardWidth = 200.0;
57+
const maxColumns = 6;
58+
59+
final availableWidth = constraints.maxWidth;
60+
61+
final columns =
62+
((availableWidth + spacing) / (minCardWidth + spacing))
63+
.floor()
64+
.clamp(1, maxColumns);
65+
66+
return GridView.builder(
67+
shrinkWrap: true,
68+
physics: const NeverScrollableScrollPhysics(),
69+
itemCount: _heroCards.length,
70+
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
71+
crossAxisCount: columns,
72+
crossAxisSpacing: spacing,
73+
mainAxisSpacing: spacing,
74+
mainAxisExtent: 210, // Breite/Höhe der Cards
75+
),
76+
itemBuilder: (context, index) {
77+
final card = _heroCards[index];
78+
return Card(
79+
child: Padding(
80+
padding: const EdgeInsets.all(10),
81+
child: Column(
82+
crossAxisAlignment: CrossAxisAlignment.center,
83+
children: [
84+
Icon(
85+
LucideIcons.package,
86+
size: 32,
87+
color: isDarkMode
88+
? Colors.blue[400]
89+
: Colors.blue[900],
90+
),
91+
const Gap(12),
92+
Text(card.title, textAlign: TextAlign.center).h4,
93+
const Gap(6),
94+
Flexible(
95+
child: Text(
96+
card.text,
97+
maxLines: 3,
98+
textAlign: TextAlign.center,
99+
overflow: TextOverflow.ellipsis,
100+
).muted.small,
101+
),
102+
],
103+
),
104+
),
105+
);
106+
},
107+
);
108+
},
109+
),
110+
),
111+
],
112+
).withPadding(vertical: 64),
113+
);
114+
}
115+
}
116+
117+
/// Immutable data object used to render a single hero feature card.
118+
class _StackCard {
119+
const _StackCard({required this.title, required this.text});
120+
121+
/// Feature title.
122+
final String title;
123+
124+
/// Short feature description.
125+
final String text;
126+
}

0 commit comments

Comments
 (0)