- Desktop sidebar (262px, blue gradient, white pill nav), topbar (search + bell + avatar), responsive shell rewritten - Desktop homepage: immersive hero with Ken Burns animation, pill category chips, date badge cards matching mvnew.eventifyplus.com/home - Desktop calendar: 60/40 two-column layout with white background - Desktop profile: full-width banner + 3-column event grids - Desktop learn more: hero image + about/venue columns + gallery strip - Desktop settings/contribute: polished to match design system - Mobile hero slider: RepaintBoundary, animated dots with 44px tap targets, 5s auto-scroll, 8s post-swipe delay, shimmer loading, dynamic event type badge, human-readable dates - Guest access: requiresAuth false on read endpoints - Location fix: show place names instead of lat/lng coordinates - Version 1.6.1+17 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
142 lines
4.2 KiB
Dart
142 lines
4.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../core/app_decoration.dart';
|
|
import '../core/constants.dart';
|
|
|
|
class DesktopSidebar extends StatelessWidget {
|
|
final int selectedIndex;
|
|
final ValueChanged<int> onIndexChanged;
|
|
|
|
const DesktopSidebar({
|
|
Key? key,
|
|
required this.selectedIndex,
|
|
required this.onIndexChanged,
|
|
}) : super(key: key);
|
|
|
|
static const _navItems = <_NavDef>[
|
|
_NavDef(Icons.home_outlined, Icons.home, 'Home', 0),
|
|
_NavDef(Icons.calendar_today_outlined, Icons.calendar_today, 'Calendar', 1),
|
|
_NavDef(Icons.person_outline, Icons.person, 'Profile', 2),
|
|
];
|
|
|
|
static const _bottomItems = <_NavDef>[
|
|
_NavDef(Icons.settings_outlined, Icons.settings, 'Settings', 5),
|
|
_NavDef(Icons.help_outline, Icons.help, 'Help', -1),
|
|
];
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return RepaintBoundary(
|
|
child: Container(
|
|
width: AppConstants.sidebarExpandedWidth,
|
|
decoration: AppDecoration.blueGradient,
|
|
child: SafeArea(
|
|
child: Column(
|
|
children: [
|
|
// Logo
|
|
Padding(
|
|
padding: const EdgeInsets.only(left: 24, top: 20, right: 24),
|
|
child: Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
const Icon(
|
|
Icons.auto_awesome,
|
|
color: Colors.white,
|
|
size: 20,
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'EVENTIFY',
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: 20,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 24),
|
|
|
|
// Main nav items
|
|
Column(
|
|
children: _navItems
|
|
.map((item) => _buildNavItem(item))
|
|
.toList(),
|
|
),
|
|
|
|
const Spacer(),
|
|
|
|
// Bottom nav items
|
|
Column(
|
|
children: _bottomItems
|
|
.map((item) => _buildNavItem(item))
|
|
.toList(),
|
|
),
|
|
const SizedBox(height: 20),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildNavItem(_NavDef item) {
|
|
final selected = selectedIndex == item.index;
|
|
final icon = selected ? item.activeIcon : item.icon;
|
|
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
|
child: MouseRegion(
|
|
cursor: SystemMouseCursors.click,
|
|
child: InkWell(
|
|
onTap: () => onIndexChanged(item.index),
|
|
borderRadius: BorderRadius.circular(12),
|
|
child: AnimatedContainer(
|
|
duration: const Duration(milliseconds: 200),
|
|
height: 48,
|
|
margin: const EdgeInsets.symmetric(vertical: 2),
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
decoration: BoxDecoration(
|
|
color: selected ? Colors.white : Colors.transparent,
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Icon(
|
|
icon,
|
|
size: 22,
|
|
color: selected
|
|
? const Color(0xFF0F45CF)
|
|
: Colors.white.withValues(alpha: 0.85),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Text(
|
|
item.label,
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w500,
|
|
color: selected
|
|
? const Color(0xFF0F45CF)
|
|
: Colors.white.withValues(alpha: 0.85),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _NavDef {
|
|
final IconData icon;
|
|
final IconData activeIcon;
|
|
final String label;
|
|
final int index;
|
|
const _NavDef(this.icon, this.activeIcon, this.label, this.index);
|
|
}
|