Initial commit: Svrnty Console Flutter application with GetWidget integration

- Implemented responsive dashboard UI with Material Design 3
- Integrated GetWidget 7.0.0 for modern UI components (GFAvatar, custom badges)
- Created collapsible navigation sidebar with smooth animations
- Built status cards grid with uniform badge sizing
- Added activity timeline with recent events
- Configured custom Svrnty branding (Crimson Red #F3574E, Slate Blue #5A6F7D)
- Set up development server on http://localhost:54952/
- Included Montserrat and IBM Plex Mono custom fonts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-25 13:47:58 -04:00
commit e20ea43a85
198 changed files with 10220 additions and 0 deletions
+322
View File
@@ -0,0 +1,322 @@
import 'package:flutter/material.dart';
import 'package:animate_do/animate_do.dart';
import 'package:iconsax/iconsax.dart';
import 'package:getwidget/getwidget.dart';
class NavigationSidebar extends StatefulWidget {
final bool isExpanded;
final Function(String) onNavigate;
final String currentPage;
const NavigationSidebar({
Key? key,
required this.isExpanded,
required this.onNavigate,
required this.currentPage,
}) : super(key: key);
@override
State<NavigationSidebar> createState() => _NavigationSidebarState();
}
class _NavigationSidebarState extends State<NavigationSidebar> {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final width = widget.isExpanded ? 250.0 : 70.0;
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: width,
decoration: BoxDecoration(
color: colorScheme.surfaceContainerLow,
border: Border(
right: BorderSide(
color: colorScheme.outline.withOpacity(0.2),
width: 1,
),
),
),
child: Column(
children: [
// Svrnty Logo Section
_buildLogoSection(colorScheme),
const SizedBox(height: 20),
// Navigation Menu Items
Expanded(
child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 8),
children: [
_buildMenuItem(
icon: Iconsax.home,
title: 'Dashboard',
pageId: 'dashboard',
colorScheme: colorScheme,
),
const SizedBox(height: 8),
_buildMenuItem(
icon: Iconsax.hierarchy_square,
title: 'The Architect',
pageId: 'architect',
colorScheme: colorScheme,
),
const SizedBox(height: 8),
_buildMenuItem(
icon: Iconsax.cpu,
title: 'Agents',
pageId: 'agents',
colorScheme: colorScheme,
),
const SizedBox(height: 8),
_buildMenuItem(
icon: Iconsax.chart_square,
title: 'Analytics',
pageId: 'analytics',
colorScheme: colorScheme,
),
const SizedBox(height: 8),
_buildMenuItem(
icon: Iconsax.box,
title: 'Tools',
pageId: 'tools',
colorScheme: colorScheme,
),
const SizedBox(height: 8),
_buildMenuItem(
icon: Iconsax.setting_2,
title: 'Settings',
pageId: 'settings',
colorScheme: colorScheme,
),
],
),
),
// User Profile Section (bottom)
_buildUserSection(colorScheme),
],
),
);
}
Widget _buildLogoSection(ColorScheme colorScheme) {
return Container(
padding: EdgeInsets.symmetric(
vertical: 20,
horizontal: widget.isExpanded ? 20 : 12,
),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: colorScheme.outline.withOpacity(0.2),
width: 1,
),
),
),
child: widget.isExpanded
? FadeIn(
duration: const Duration(milliseconds: 200),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: colorScheme.primary,
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'S',
style: TextStyle(
color: Colors.white,
fontSize: 23,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Svrnty',
style: TextStyle(
fontSize: 20.7,
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
),
),
Text(
'Console',
style: TextStyle(
fontSize: 12.65,
color: colorScheme.onSurfaceVariant,
),
),
],
),
),
],
),
)
: Center(
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: colorScheme.primary,
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'S',
style: TextStyle(
color: Colors.white,
fontSize: 23,
fontWeight: FontWeight.bold,
),
),
),
),
);
}
Widget _buildMenuItem({
required IconData icon,
required String title,
required String pageId,
required ColorScheme colorScheme,
}) {
final isActive = widget.currentPage == pageId;
return FadeInLeft(
duration: const Duration(milliseconds: 300),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => widget.onNavigate(pageId),
borderRadius: BorderRadius.circular(12),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: EdgeInsets.symmetric(
vertical: 14,
horizontal: widget.isExpanded ? 16 : 12,
),
decoration: BoxDecoration(
color: isActive
? colorScheme.primary.withOpacity(0.25)
: Colors.transparent,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isActive
? colorScheme.primary.withOpacity(0.7)
: Colors.transparent,
width: 2,
),
),
child: Row(
children: [
Icon(
icon,
color: isActive
? Colors.white
: colorScheme.onSurfaceVariant,
size: 24,
),
if (widget.isExpanded) ...[
const SizedBox(width: 16),
Expanded(
child: FadeIn(
duration: const Duration(milliseconds: 200),
child: Text(
title,
style: TextStyle(
fontSize: 17.25,
fontWeight:
isActive ? FontWeight.w600 : FontWeight.w400,
color: isActive
? Colors.white
: colorScheme.onSurface,
),
),
),
),
],
],
),
),
),
),
);
}
Widget _buildUserSection(ColorScheme colorScheme) {
return Container(
padding: EdgeInsets.all(widget.isExpanded ? 16 : 12),
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: colorScheme.outline.withOpacity(0.2),
width: 1,
),
),
),
child: widget.isExpanded
? FadeIn(
duration: const Duration(milliseconds: 200),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
GFAvatar(
radius: 18,
backgroundColor: colorScheme.primary.withOpacity(0.3),
child: Icon(
Iconsax.user,
color: colorScheme.primary,
size: 18,
),
shape: GFAvatarShape.circle,
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Admin',
style: TextStyle(
fontSize: 14.95,
fontWeight: FontWeight.w600,
color: colorScheme.onSurface,
),
),
Text(
'admin@svrnty.ai',
style: TextStyle(
fontSize: 11.5,
color: colorScheme.onSurfaceVariant,
),
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
)
: Center(
child: GFAvatar(
radius: 20,
backgroundColor: colorScheme.primary.withOpacity(0.2),
child: Icon(
Iconsax.user,
color: colorScheme.primary,
size: 20,
),
shape: GFAvatarShape.circle,
),
),
);
}
}
+478
View File
@@ -0,0 +1,478 @@
import 'package:flutter/material.dart';
import 'package:animate_do/animate_do.dart';
/// Svrnty Design System Components
/// Reusable, branded components for the Svrnty Console application
///
/// Brand Colors:
/// - Primary (Crimson): #C44D58
/// - Secondary (Slate Blue): #475C6C
// ============================================================================
// SVRNTY BUTTONS
// ============================================================================
enum SvrntyButtonVariant { primary, secondary, ghost, danger }
class SvrntyButton extends StatelessWidget {
final String text;
final VoidCallback? onPressed;
final SvrntyButtonVariant variant;
final IconData? icon;
final bool isLoading;
final bool fullWidth;
const SvrntyButton({
Key? key,
required this.text,
this.onPressed,
this.variant = SvrntyButtonVariant.primary,
this.icon,
this.isLoading = false,
this.fullWidth = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
Color backgroundColor;
Color textColor;
Color? borderColor;
switch (variant) {
case SvrntyButtonVariant.primary:
backgroundColor = colorScheme.primary;
textColor = Colors.white;
borderColor = null;
break;
case SvrntyButtonVariant.secondary:
backgroundColor = colorScheme.secondary;
textColor = Colors.white;
borderColor = null;
break;
case SvrntyButtonVariant.ghost:
backgroundColor = Colors.transparent;
textColor = colorScheme.primary;
borderColor = colorScheme.primary;
break;
case SvrntyButtonVariant.danger:
backgroundColor = colorScheme.error;
textColor = Colors.white;
borderColor = null;
break;
}
return FadeInUp(
duration: const Duration(milliseconds: 300),
child: SizedBox(
width: fullWidth ? double.infinity : null,
child: ElevatedButton(
onPressed: isLoading ? null : onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor,
foregroundColor: textColor,
elevation: variant == SvrntyButtonVariant.ghost ? 0 : 2,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: borderColor != null
? BorderSide(color: borderColor, width: 2)
: BorderSide.none,
),
),
child: isLoading
? SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(textColor),
),
)
: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (icon != null) ...[
Icon(icon, size: 20),
const SizedBox(width: 8),
],
Text(
text,
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
),
),
],
),
),
),
);
}
}
// ============================================================================
// SVRNTY CARDS
// ============================================================================
class SvrntyCard extends StatelessWidget {
final Widget child;
final Color? accentColor;
final VoidCallback? onTap;
final bool showBorder;
final EdgeInsetsGeometry? padding;
const SvrntyCard({
Key? key,
required this.child,
this.accentColor,
this.onTap,
this.showBorder = true,
this.padding,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final effectiveAccentColor = accentColor ?? colorScheme.primary;
return FadeInUp(
duration: const Duration(milliseconds: 400),
child: Container(
decoration: showBorder
? BoxDecoration(
borderRadius: BorderRadius.circular(16),
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
effectiveAccentColor.withOpacity(0.15),
effectiveAccentColor.withOpacity(0.05),
],
),
border: Border.all(
color: effectiveAccentColor.withOpacity(0.3),
width: 1,
),
)
: null,
child: Card(
elevation: 2,
color: showBorder ? Colors.transparent : null,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(16),
child: Container(
decoration: showBorder
? BoxDecoration(
border: Border(
left: BorderSide(
color: effectiveAccentColor,
width: 4,
),
),
)
: null,
child: Padding(
padding: padding ?? const EdgeInsets.all(20),
child: child,
),
),
),
),
),
);
}
}
// ============================================================================
// SVRNTY BADGES
// ============================================================================
enum SvrntyBadgeStatus { success, warning, error, info, neutral }
class SvrntyBadge extends StatelessWidget {
final String text;
final SvrntyBadgeStatus status;
final IconData? icon;
const SvrntyBadge({
Key? key,
required this.text,
this.status = SvrntyBadgeStatus.neutral,
this.icon,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
Color backgroundColor;
Color textColor;
switch (status) {
case SvrntyBadgeStatus.success:
backgroundColor = Colors.green;
textColor = Colors.white;
break;
case SvrntyBadgeStatus.warning:
backgroundColor = Colors.orange;
textColor = Colors.white;
break;
case SvrntyBadgeStatus.error:
backgroundColor = colorScheme.error;
textColor = Colors.white;
break;
case SvrntyBadgeStatus.info:
backgroundColor = colorScheme.primary;
textColor = Colors.white;
break;
case SvrntyBadgeStatus.neutral:
backgroundColor = colorScheme.secondary;
textColor = Colors.white;
break;
}
return Pulse(
duration: const Duration(milliseconds: 1000),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: backgroundColor.withOpacity(0.3),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (icon != null) ...[
Icon(icon, color: textColor, size: 16),
const SizedBox(width: 6),
],
Text(
text,
style: TextStyle(
color: textColor,
fontSize: 12,
fontWeight: FontWeight.bold,
fontFamily: 'Montserrat',
),
),
],
),
),
);
}
}
// ============================================================================
// SVRNTY ICON BUTTONS
// ============================================================================
class SvrntyIconButton extends StatelessWidget {
final IconData icon;
final VoidCallback? onPressed;
final Color? backgroundColor;
final Color? iconColor;
final double size;
const SvrntyIconButton({
Key? key,
required this.icon,
this.onPressed,
this.backgroundColor,
this.iconColor,
this.size = 40,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return FadeIn(
child: Container(
width: size,
height: size,
decoration: BoxDecoration(
color: backgroundColor ?? colorScheme.primary.withOpacity(0.1),
shape: BoxShape.circle,
),
child: IconButton(
icon: Icon(icon),
color: iconColor ?? colorScheme.primary,
iconSize: size * 0.5,
onPressed: onPressed,
),
),
);
}
}
// ============================================================================
// SVRNTY SECTION HEADER
// ============================================================================
class SvrntySectionHeader extends StatelessWidget {
final String title;
final String? subtitle;
final Widget? action;
const SvrntySectionHeader({
Key? key,
required this.title,
this.subtitle,
this.action,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return FadeInLeft(
duration: const Duration(milliseconds: 400),
child: Row(
children: [
Container(
width: 4,
height: 28,
decoration: BoxDecoration(
color: colorScheme.primary,
borderRadius: BorderRadius.circular(2),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
fontFamily: 'Montserrat',
),
),
if (subtitle != null) ...[
const SizedBox(height: 4),
Text(
subtitle!,
style: TextStyle(
fontSize: 14,
color: colorScheme.onSurfaceVariant,
fontFamily: 'Montserrat',
),
),
],
],
),
),
if (action != null) action!,
],
),
);
}
}
// ============================================================================
// SVRNTY INPUT FIELD
// ============================================================================
class SvrntyTextField extends StatelessWidget {
final String label;
final String? hint;
final TextEditingController? controller;
final IconData? prefixIcon;
final bool obscureText;
final TextInputType? keyboardType;
final String? Function(String?)? validator;
const SvrntyTextField({
Key? key,
required this.label,
this.hint,
this.controller,
this.prefixIcon,
this.obscureText = false,
this.keyboardType,
this.validator,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return FadeInUp(
duration: const Duration(milliseconds: 350),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: colorScheme.onSurface,
fontFamily: 'Montserrat',
),
),
const SizedBox(height: 8),
TextFormField(
controller: controller,
obscureText: obscureText,
keyboardType: keyboardType,
validator: validator,
style: const TextStyle(fontFamily: 'Montserrat'),
decoration: InputDecoration(
hintText: hint,
prefixIcon: prefixIcon != null ? Icon(prefixIcon) : null,
filled: true,
fillColor: colorScheme.surfaceContainerHighest,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: colorScheme.outline.withOpacity(0.3),
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: colorScheme.outline.withOpacity(0.2),
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: colorScheme.primary,
width: 2,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(
color: colorScheme.error,
width: 2,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
),
),
],
),
);
}
}