style(frontend): polish student workspace

This commit is contained in:
SaidSoighiri94
2026-07-23 10:27:27 +02:00
parent 1c8ed77ebf
commit 695b0d3965
12 changed files with 1162 additions and 484 deletions
+93 -42
View File
@@ -3,7 +3,7 @@ import "package:google_fonts/google_fonts.dart";
import "../theme/ensup_colors.dart";
/// Grande carte d'action de l'accueil (Emprunter / Restituer).
class ActionCard extends StatelessWidget {
class ActionCard extends StatefulWidget {
const ActionCard({
super.key,
required this.icon,
@@ -19,56 +19,107 @@ class ActionCard extends StatelessWidget {
final Color color;
final VoidCallback? onTap;
@override
State<ActionCard> createState() => _ActionCardState();
}
class _ActionCardState extends State<ActionCard> {
bool _hovered = false;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(16),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
final color = widget.color;
return MouseRegion(
onEnter: (_) => setState(() => _hovered = true),
onExit: (_) => setState(() => _hovered = false),
cursor: SystemMouseCursors.click,
child: AnimatedContainer(
duration: const Duration(milliseconds: 180),
curve: Curves.easeOut,
constraints: const BoxConstraints(minHeight: 230),
decoration: BoxDecoration(
color: color.withValues(alpha: 0.07),
color: _hovered
? color.withValues(alpha: 0.1)
: color.withValues(alpha: 0.06),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: color.withValues(alpha: 0.2), width: 2),
border: Border.all(
color: color.withValues(alpha: _hovered ? 0.55 : 0.22),
width: _hovered ? 2 : 1.5,
),
boxShadow: [
BoxShadow(
color: color.withValues(alpha: _hovered ? 0.16 : 0.06),
blurRadius: _hovered ? 22 : 10,
offset: Offset(0, _hovered ? 8 : 3),
),
],
),
child: Column(
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [color, color.withValues(alpha: 0.75)]),
borderRadius: BorderRadius.circular(18),
boxShadow: [
BoxShadow(
color: color.withValues(alpha: 0.35),
blurRadius: 16,
offset: const Offset(0, 4),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: widget.onTap,
borderRadius: BorderRadius.circular(16),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 28),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 180),
width: 60,
height: 60,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(18),
boxShadow: [
BoxShadow(
color: color.withValues(alpha: 0.3),
blurRadius: _hovered ? 18 : 12,
offset: const Offset(0, 5),
),
],
),
child: Icon(widget.icon, color: Colors.white, size: 28),
),
const SizedBox(height: 16),
Text(
widget.title,
textAlign: TextAlign.center,
style: GoogleFonts.darkerGrotesque(
fontSize: 25,
height: 1,
fontWeight: FontWeight.w900,
color: EnsupColors.text,
),
),
const SizedBox(height: 8),
Text(
widget.description,
textAlign: TextAlign.center,
style: GoogleFonts.titilliumWeb(
fontSize: 13,
color: EnsupColors.muted,
height: 1.45,
),
),
const SizedBox(height: 16),
Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: color.withValues(alpha: 0.12),
shape: BoxShape.circle,
),
child: Icon(
Icons.arrow_forward_rounded,
size: 17,
color: color,
),
),
],
),
child: Icon(icon, color: Colors.white, size: 28),
),
const SizedBox(height: 14),
Text(
title,
style: GoogleFonts.darkerGrotesque(
fontSize: 26,
fontWeight: FontWeight.w900,
color: EnsupColors.text,
),
),
const SizedBox(height: 6),
Text(
description,
textAlign: TextAlign.center,
style: GoogleFonts.titilliumWeb(
fontSize: 13,
color: EnsupColors.muted,
height: 1.5,
),
),
],
),
),
),
);
+95 -66
View File
@@ -27,96 +27,122 @@ class EnsupTopBar extends StatelessWidget {
final onBack = this.onBack;
return Container(
height: 56,
padding: const EdgeInsets.symmetric(horizontal: 20),
height: 60,
padding: const EdgeInsets.symmetric(horizontal: 18),
color: EnsupColors.blue3,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
child: LayoutBuilder(
builder: (context, constraints) {
final compact = constraints.maxWidth < 620;
final showCampus = constraints.maxWidth >= 520;
final showName = constraints.maxWidth >= 760;
return Row(
children: [
if (onBack != null) ...[
_BackButton(onTap: onBack),
const SizedBox(width: 8),
_BackButton(onTap: onBack, compact: compact),
SizedBox(width: compact ? 5 : 8),
],
const Icon(Icons.badge_outlined, color: Colors.white, size: 18),
const SizedBox(width: 10),
Text(
brandText,
style: GoogleFonts.darkerGrotesque(
color: Colors.white,
fontWeight: FontWeight.w900,
fontSize: 22,
letterSpacing: 0.3,
),
),
],
),
Row(
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(999),
border: Border.all(color: Colors.white.withValues(alpha: 0.2)),
),
const SizedBox(width: 9),
Expanded(
child: Text(
campusTag,
style: GoogleFonts.titilliumWeb(
brandText,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.darkerGrotesque(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w600,
fontWeight: FontWeight.w900,
fontSize: compact ? 18 : 21,
),
),
),
if (name != null && initials != null) ...[
const SizedBox(width: 12),
_Avatar(initials: initials),
const SizedBox(width: 8),
Text(
name,
style: GoogleFonts.titilliumWeb(
color: Colors.white,
fontSize: 13,
fontWeight: FontWeight.w600,
const SizedBox(width: 10),
if (showCampus)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 11,
vertical: 5,
),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.14),
borderRadius: BorderRadius.circular(999),
border: Border.all(
color: Colors.white.withValues(alpha: 0.2),
),
),
child: Text(
campusTag,
style: GoogleFonts.titilliumWeb(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.w600,
),
),
),
if (name != null && initials != null) ...[
const SizedBox(width: 10),
_Avatar(initials: initials),
if (showName) ...[
const SizedBox(width: 8),
Text(
name,
style: GoogleFonts.titilliumWeb(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
],
],
],
),
],
);
},
),
);
}
}
class _BackButton extends StatelessWidget {
const _BackButton({required this.onTap});
const _BackButton({required this.onTap, required this.compact});
final VoidCallback onTap;
final bool compact;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.arrow_back, size: 16, color: Colors.white.withValues(alpha: 0.85)),
const SizedBox(width: 6),
Text(
"Retour",
style: GoogleFonts.titilliumWeb(
color: Colors.white.withValues(alpha: 0.85),
fontSize: 13,
fontWeight: FontWeight.w600,
return Tooltip(
message: "Retour",
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(7),
child: Container(
height: 34,
padding: EdgeInsets.symmetric(horizontal: compact ? 8 : 10),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(7),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.arrow_back_rounded,
size: 17,
color: Colors.white.withValues(alpha: 0.9),
),
),
],
if (!compact) ...[
const SizedBox(width: 6),
Text(
"Retour",
style: GoogleFonts.titilliumWeb(
color: Colors.white.withValues(alpha: 0.9),
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
],
],
),
),
),
);
@@ -135,8 +161,11 @@ class _Avatar extends StatelessWidget {
height: 30,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: const LinearGradient(colors: [EnsupColors.teal, EnsupColors.cyan]),
border: Border.all(color: Colors.white.withValues(alpha: 0.3), width: 2),
color: EnsupColors.purple,
border: Border.all(
color: Colors.white.withValues(alpha: 0.3),
width: 2,
),
),
alignment: Alignment.center,
child: Text(
+74 -24
View File
@@ -37,7 +37,11 @@ class EtatBox extends StatelessWidget {
case EtatChecklist.deteriore:
background = const Color(0xFFFFFBEB);
border = const Color(0xFFFDE68A);
contenu = const Icon(Icons.priority_high, size: 16, color: Color(0xFFD97706));
contenu = const Icon(
Icons.priority_high,
size: 16,
color: Color(0xFFD97706),
);
}
}
@@ -73,15 +77,36 @@ class ChecklistTableau extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
_entete(),
for (var i = 0; i < accessoires.length; i++) _ligne(i),
],
return LayoutBuilder(
builder: (context, constraints) {
final columnWidth = constraints.maxWidth < 520 ? 58.0 : 72.0;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: EnsupColors.line, width: 1.5),
boxShadow: [
BoxShadow(
color: EnsupColors.text.withValues(alpha: 0.035),
blurRadius: 10,
offset: const Offset(0, 3),
),
],
),
child: Column(
children: [
_entete(columnWidth),
for (var i = 0; i < accessoires.length; i++)
_ligne(i, columnWidth),
],
),
);
},
);
}
Widget _entete() {
Widget _entete(double columnWidth) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: const BoxDecoration(
@@ -90,9 +115,9 @@ class ChecklistTableau extends StatelessWidget {
child: Row(
children: [
Expanded(child: _texteEntete("ÉLÉMENT")),
_colonneEntete("PRÉSENT"),
_colonneEntete("ABSENT"),
_colonneEntete("DÉTÉRIORÉ"),
_colonneEntete("PRÉSENT", columnWidth),
_colonneEntete("ABSENT", columnWidth),
_colonneEntete("DÉTÉRIORÉ", columnWidth),
],
),
);
@@ -110,11 +135,16 @@ class ChecklistTableau extends StatelessWidget {
);
}
Widget _colonneEntete(String label) {
return SizedBox(width: 72, child: Center(child: _texteEntete(label)));
Widget _colonneEntete(String label, double width) {
return SizedBox(
width: width,
child: Center(
child: FittedBox(fit: BoxFit.scaleDown, child: _texteEntete(label)),
),
);
}
Widget _ligne(int index) {
Widget _ligne(int index, double columnWidth) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: const BoxDecoration(
@@ -125,20 +155,23 @@ class ChecklistTableau extends StatelessWidget {
Expanded(
child: Text(
accessoires[index],
style: GoogleFonts.titilliumWeb(fontSize: 14, color: EnsupColors.text2),
style: GoogleFonts.titilliumWeb(
fontSize: 14,
color: EnsupColors.text2,
),
),
),
_case(index, EtatChecklist.present),
_case(index, EtatChecklist.absent),
_case(index, EtatChecklist.deteriore),
_case(index, EtatChecklist.present, columnWidth),
_case(index, EtatChecklist.absent, columnWidth),
_case(index, EtatChecklist.deteriore, columnWidth),
],
),
);
}
Widget _case(int index, EtatChecklist type) {
Widget _case(int index, EtatChecklist type, double width) {
return SizedBox(
width: 72,
width: width,
child: Center(
child: EtatBox(
type: type,
@@ -152,7 +185,11 @@ class ChecklistTableau extends StatelessWidget {
/// Encadré d'instructions / rappel à côté d'une checklist.
class ChecklistInstructions extends StatelessWidget {
const ChecklistInstructions({super.key, required this.titre, required this.texte});
const ChecklistInstructions({
super.key,
required this.titre,
required this.texte,
});
final String titre;
final String texte;
@@ -164,7 +201,10 @@ class ChecklistInstructions extends StatelessWidget {
decoration: BoxDecoration(
color: EnsupColors.blue2.withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: EnsupColors.blue2.withValues(alpha: 0.15), width: 1.5),
border: Border.all(
color: EnsupColors.blue2.withValues(alpha: 0.15),
width: 1.5,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -181,7 +221,11 @@ class ChecklistInstructions extends StatelessWidget {
const SizedBox(height: 8),
Text(
texte,
style: GoogleFonts.titilliumWeb(fontSize: 13, color: EnsupColors.text2, height: 1.6),
style: GoogleFonts.titilliumWeb(
fontSize: 13,
color: EnsupColors.text2,
height: 1.6,
),
),
],
),
@@ -208,10 +252,16 @@ class ChecklistCommentaire extends StatelessWidget {
style: GoogleFonts.titilliumWeb(fontSize: 13, color: EnsupColors.text),
decoration: InputDecoration(
hintText: hint,
hintStyle: GoogleFonts.titilliumWeb(fontSize: 13, color: EnsupColors.muted),
hintStyle: GoogleFonts.titilliumWeb(
fontSize: 13,
color: EnsupColors.muted,
),
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
contentPadding: const EdgeInsets.symmetric(
horizontal: 14,
vertical: 12,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(9),
borderSide: const BorderSide(color: EnsupColors.line, width: 1.5),
@@ -3,7 +3,7 @@ import "package:google_fonts/google_fonts.dart";
import "../theme/ensup_colors.dart";
/// Option d'identification de l'écran de connexion (QR ou mail ENSUP).
class IdentificationOption extends StatelessWidget {
class IdentificationOption extends StatefulWidget {
const IdentificationOption({
super.key,
required this.icon,
@@ -19,56 +19,102 @@ class IdentificationOption extends StatelessWidget {
final String description;
final VoidCallback? onTap;
@override
State<IdentificationOption> createState() => _IdentificationOptionState();
}
class _IdentificationOptionState extends State<IdentificationOption> {
bool _hovered = false;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 18),
return MouseRegion(
onEnter: (_) => setState(() => _hovered = true),
onExit: (_) => setState(() => _hovered = false),
cursor: SystemMouseCursors.click,
child: AnimatedContainer(
duration: const Duration(milliseconds: 160),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: EnsupColors.line, width: 2),
),
child: Row(
children: [
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: iconColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: _hovered ? widget.iconColor : EnsupColors.line,
width: 1.5,
),
boxShadow: [
BoxShadow(
color: widget.iconColor.withValues(
alpha: _hovered ? 0.12 : 0.035,
),
child: Icon(icon, color: iconColor, size: 24),
blurRadius: _hovered ? 16 : 8,
offset: const Offset(0, 4),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: widget.onTap,
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 17),
child: Row(
children: [
Text(
label,
style: GoogleFonts.darkerGrotesque(
fontWeight: FontWeight.w700,
fontSize: 18,
color: EnsupColors.text,
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: widget.iconColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(widget.icon, color: widget.iconColor, size: 24),
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.label,
style: GoogleFonts.darkerGrotesque(
fontWeight: FontWeight.w800,
fontSize: 18,
height: 1.05,
color: EnsupColors.text,
),
),
const SizedBox(height: 4),
Text(
widget.description,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.muted,
height: 1.35,
),
),
],
),
),
const SizedBox(height: 3),
Text(
description,
style: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.muted,
height: 1.4,
const SizedBox(width: 8),
Container(
width: 28,
height: 28,
decoration: BoxDecoration(
color: widget.iconColor.withValues(alpha: 0.08),
shape: BoxShape.circle,
),
child: Icon(
Icons.chevron_right_rounded,
color: widget.iconColor,
size: 19,
),
),
],
),
),
const Icon(Icons.chevron_right, color: EnsupColors.muted, size: 20),
],
),
),
),
);
+129 -52
View File
@@ -24,65 +24,142 @@ class MaterielCard extends StatelessWidget {
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: EnsupColors.line, width: 1.5),
),
child: Row(
children: [
Container(
width: 44,
height: 44,
decoration: BoxDecoration(
color: accent.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(10),
),
child: Icon(item.icon, color: accent, size: 20),
boxShadow: [
BoxShadow(
color: EnsupColors.text.withValues(alpha: 0.035),
blurRadius: 10,
offset: const Offset(0, 3),
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
],
),
child: LayoutBuilder(
builder: (context, constraints) {
final compact = constraints.maxWidth < 620;
final information = Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 46,
height: 46,
decoration: BoxDecoration(
color: accent.withValues(alpha: 0.09),
borderRadius: BorderRadius.circular(10),
),
child: Icon(item.icon, color: accent, size: 21),
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.nom,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.darkerGrotesque(
fontWeight: FontWeight.w800,
fontSize: 17,
height: 1.05,
color: EnsupColors.text,
),
),
const SizedBox(height: 4),
Text(
"${item.categorie} · Réf. ${item.reference}",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.muted,
),
),
const SizedBox(height: 3),
Row(
children: [
const Icon(
Icons.location_on_outlined,
size: 13,
color: EnsupColors.muted,
),
const SizedBox(width: 4),
Expanded(
child: Text(
item.campus,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.titilliumWeb(
fontSize: 11,
color: EnsupColors.muted,
),
),
),
],
),
],
),
),
],
);
final actions = Wrap(
spacing: 10,
runSpacing: 8,
crossAxisAlignment: WrapCrossAlignment.center,
alignment: WrapAlignment.end,
children: [
StatusPill(disponible: disponible),
if (disponible)
FilledButton.icon(
onPressed: onSelect,
style: FilledButton.styleFrom(
backgroundColor: EnsupColors.cyan,
padding: const EdgeInsets.symmetric(
horizontal: 15,
vertical: 11,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(9),
),
),
icon: const Icon(Icons.arrow_forward_rounded, size: 16),
label: Text(
"Sélectionner",
style: GoogleFonts.darkerGrotesque(
fontWeight: FontWeight.w700,
fontSize: 14,
),
),
)
else
Text(
item.nom,
"Indisponible",
style: GoogleFonts.darkerGrotesque(
fontWeight: FontWeight.w700,
fontSize: 16,
color: EnsupColors.text,
fontSize: 14,
color: EnsupColors.muted,
),
),
const SizedBox(height: 2),
Text(
"${item.categorie} · Réf. ${item.reference} · ${item.campus}",
style: GoogleFonts.titilliumWeb(fontSize: 12, color: EnsupColors.muted),
),
],
);
if (compact) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
information,
const SizedBox(height: 14),
Align(alignment: Alignment.centerRight, child: actions),
],
),
),
const SizedBox(width: 10),
StatusPill(disponible: disponible),
const SizedBox(width: 12),
if (disponible)
FilledButton(
onPressed: onSelect,
style: FilledButton.styleFrom(
backgroundColor: EnsupColors.cyan,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
child: Text(
"Sélectionner",
style: GoogleFonts.darkerGrotesque(fontWeight: FontWeight.w700, fontSize: 14),
),
)
else
Text(
"Indisponible",
style: GoogleFonts.darkerGrotesque(
fontWeight: FontWeight.w700,
fontSize: 14,
color: EnsupColors.muted,
),
),
],
);
}
return Row(
children: [
Expanded(child: information),
const SizedBox(width: 16),
actions,
],
);
},
),
),
);
+109 -63
View File
@@ -18,74 +18,120 @@ class ProfileCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14),
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
EnsupColors.cyan.withValues(alpha: 0.06),
EnsupColors.teal.withValues(alpha: 0.04),
],
),
color: EnsupColors.cyan.withValues(alpha: 0.055),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: EnsupColors.cyan.withValues(alpha: 0.15), width: 1.5),
),
child: Row(
children: [
Container(
width: 48,
height: 48,
decoration: const BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(colors: [EnsupColors.teal, EnsupColors.cyan]),
),
alignment: Alignment.center,
child: Text(
initials,
style: GoogleFonts.darkerGrotesque(
color: Colors.white,
fontWeight: FontWeight.w900,
fontSize: 18,
),
),
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: GoogleFonts.darkerGrotesque(
fontWeight: FontWeight.w800,
fontSize: 20,
color: EnsupColors.text,
),
),
const SizedBox(height: 2),
Text(
subtitle,
style: GoogleFonts.titilliumWeb(fontSize: 12, color: EnsupColors.muted),
),
],
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5),
decoration: BoxDecoration(
color: EnsupColors.green.withValues(alpha: 0.12),
borderRadius: BorderRadius.circular(999),
),
child: Text(
"Connecté",
style: GoogleFonts.titilliumWeb(
fontSize: 12,
fontWeight: FontWeight.w600,
color: EnsupColors.green,
),
),
border: Border.all(
color: EnsupColors.cyan.withValues(alpha: 0.15),
width: 1.5,
),
boxShadow: [
BoxShadow(
color: EnsupColors.blue3.withValues(alpha: 0.045),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
),
child: LayoutBuilder(
builder: (context, constraints) {
final showStatus = constraints.maxWidth >= 430;
return Row(
children: [
Container(
width: 50,
height: 50,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: EnsupColors.teal,
border: Border.all(color: Colors.white, width: 3),
boxShadow: [
BoxShadow(
color: EnsupColors.teal.withValues(alpha: 0.22),
blurRadius: 10,
offset: const Offset(0, 3),
),
],
),
alignment: Alignment.center,
child: Text(
initials,
style: GoogleFonts.darkerGrotesque(
color: Colors.white,
fontWeight: FontWeight.w900,
fontSize: 18,
),
),
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.darkerGrotesque(
fontWeight: FontWeight.w800,
fontSize: 20,
height: 1,
color: EnsupColors.text,
),
),
const SizedBox(height: 4),
Text(
subtitle,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.muted,
),
),
],
),
),
if (showStatus) ...[
const SizedBox(width: 12),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 11,
vertical: 6,
),
decoration: BoxDecoration(
color: EnsupColors.green.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(999),
border: Border.all(
color: EnsupColors.green.withValues(alpha: 0.18),
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.check_circle,
size: 13,
color: EnsupColors.green,
),
const SizedBox(width: 5),
Text(
"Identifié",
style: GoogleFonts.titilliumWeb(
fontSize: 11,
fontWeight: FontWeight.w700,
color: EnsupColors.green,
),
),
],
),
),
],
],
);
},
),
);
}
}