voo_dashboard 0.0.1 copy "voo_dashboard: ^0.0.1" to clipboard
voo_dashboard: ^0.0.1 copied to clipboard

A comprehensive, responsive dashboard UI kit for Flutter with sidebar/topbar navigation, stat cards, chart containers, and activity feeds.

example/lib/main.dart

import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:voo_dashboard/voo_dashboard.dart';
import 'package:voo_navigation/voo_navigation.dart' hide VooBreadcrumbs, VooBreadcrumbItem, VooQuickAction;

void main() {
  runApp(const VooDashboardExampleApp());
}

class VooDashboardExampleApp extends StatelessWidget {
  const VooDashboardExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'VooDashboard Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue, brightness: Brightness.dark),
        useMaterial3: true,
      ),
      home: const DashboardExample(),
    );
  }
}

class DashboardExample extends StatefulWidget {
  const DashboardExample({super.key});

  @override
  State<DashboardExample> createState() => _DashboardExampleState();
}

class _DashboardExampleState extends State<DashboardExample> {
  String _selectedItemId = 'dashboard';

  @override
  Widget build(BuildContext context) {
    return VooAdaptiveScaffold(
      config: VooNavigationConfig(
        items: [
          VooNavigationItem(
            id: 'dashboard',
            label: 'Dashboard',
            icon: Icons.dashboard_outlined,
            selectedIcon: Icons.dashboard,
            onTap: () => setState(() => _selectedItemId = 'dashboard'),
          ),
          VooNavigationItem(
            id: 'analytics',
            label: 'Analytics',
            icon: Icons.analytics_outlined,
            selectedIcon: Icons.analytics,
            badgeCount: 3,
            onTap: () => setState(() => _selectedItemId = 'analytics'),
          ),
          VooNavigationItem(
            id: 'reports',
            label: 'Reports',
            icon: Icons.description_outlined,
            selectedIcon: Icons.description,
            onTap: () => setState(() => _selectedItemId = 'reports'),
          ),
          VooNavigationItem(
            id: 'users',
            label: 'Users',
            icon: Icons.people_outline,
            selectedIcon: Icons.people,
            onTap: () => setState(() => _selectedItemId = 'users'),
          ),
          VooNavigationItem(
            id: 'settings',
            label: 'Settings',
            icon: Icons.settings_outlined,
            selectedIcon: Icons.settings,
            onTap: () => setState(() => _selectedItemId = 'settings'),
          ),
        ],
        selectedId: _selectedItemId,
      ),
      body: VooDashboard(body: _buildBody()),
    );
  }

  String _getPageTitle() {
    switch (_selectedItemId) {
      case 'dashboard':
        return 'Dashboard';
      case 'analytics':
        return 'Analytics';
      case 'reports':
        return 'Reports';
      case 'users':
        return 'Users';
      case 'settings':
        return 'Settings';
      default:
        return 'Dashboard';
    }
  }

  Widget _buildBody() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Breadcrumbs
          VooBreadcrumbs(
            items: [
              VooBreadcrumbItem(label: 'Home', onTap: () {}),
              VooBreadcrumbItem(label: _getPageTitle(), isActive: true),
            ],
          ),
          const SizedBox(height: 16),

          // Stat Grid
          VooStatGrid(
            spacing: 12,
            runSpacing: 12,
            children: [
              VooStatCard(value: '\$45,231', label: 'Total Revenue', icon: Icons.attach_money, trend: StatTrend.up, trendValue: 12.5, trendSuffix: 'vs last month'),
              VooStatCard(value: '2,350', label: 'New Users', icon: Icons.people, trend: StatTrend.up, trendValue: 5.2),
              VooStatCard(value: '12.5%', label: 'Conversion Rate', icon: Icons.trending_up, trend: StatTrend.down, trendValue: 2.1, positiveIsGood: false),
              VooStatCard(value: '573', label: 'Active Orders', icon: Icons.shopping_cart, trend: StatTrend.neutral),
            ],
          ),
          const SizedBox(height: 16),

          // Chart and Activity Feed Row
          LayoutBuilder(
            builder: (context, constraints) {
              if (constraints.maxWidth < 800) {
                return Column(children: [_buildChartCard(), const SizedBox(height: 16), _buildActivityFeed()]);
              }
              return IntrinsicHeight(
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    Expanded(flex: 2, child: _buildChartCard()),
                    const SizedBox(width: 16),
                    Expanded(child: _buildActivityFeed()),
                  ],
                ),
              );
            },
          ),
          const SizedBox(height: 16),

          // Additional Charts Row
          LayoutBuilder(
            builder: (context, constraints) {
              if (constraints.maxWidth < 800) {
                return Column(
                  children: [
                    _buildBarChart(),
                    const SizedBox(height: 16),
                    _buildPieChart(),
                  ],
                );
              }
              return IntrinsicHeight(
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    Expanded(child: _buildBarChart()),
                    const SizedBox(width: 16),
                    Expanded(child: _buildPieChart()),
                  ],
                ),
              );
            },
          ),
          const SizedBox(height: 16),

          // Quick Actions
          Text('Quick Actions', style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)),
          const SizedBox(height: 12),
          Wrap(
            spacing: 12,
            runSpacing: 12,
            children: [
              VooQuickAction(label: 'New Report', icon: Icons.add_chart, onTap: () {}),
              VooQuickAction(label: 'Export Data', icon: Icons.download, onTap: () {}),
              VooQuickAction(label: 'Send Email', icon: Icons.email, onTap: () {}),
              VooQuickAction(label: 'Schedule', icon: Icons.schedule, onTap: () {}),
            ],
          ),
        ],
      ),
    );
  }

  Widget _buildChartCard() {
    final colorScheme = Theme.of(context).colorScheme;
    return VooChartContainer(
      title: 'Revenue Overview',
      subtitle: 'Monthly revenue for the past year',
      actions: [TextButton(onPressed: () {}, child: const Text('View Details'))],
      height: 300,
      chart: Padding(
        padding: const EdgeInsets.only(right: 16, top: 16),
        child: LineChart(
          LineChartData(
            gridData: FlGridData(
              show: true,
              drawVerticalLine: false,
              horizontalInterval: 10,
              getDrawingHorizontalLine: (value) => FlLine(
                color: colorScheme.outlineVariant.withValues(alpha: 0.3),
                strokeWidth: 1,
              ),
            ),
            titlesData: FlTitlesData(
              leftTitles: AxisTitles(
                sideTitles: SideTitles(
                  showTitles: true,
                  reservedSize: 40,
                  getTitlesWidget: (value, meta) => Text(
                    '\$${value.toInt()}k',
                    style: TextStyle(color: colorScheme.onSurfaceVariant, fontSize: 11),
                  ),
                ),
              ),
              bottomTitles: AxisTitles(
                sideTitles: SideTitles(
                  showTitles: true,
                  reservedSize: 30,
                  getTitlesWidget: (value, meta) {
                    const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
                    if (value.toInt() >= 0 && value.toInt() < months.length) {
                      return Padding(
                        padding: const EdgeInsets.only(top: 8),
                        child: Text(months[value.toInt()], style: TextStyle(color: colorScheme.onSurfaceVariant, fontSize: 11)),
                      );
                    }
                    return const SizedBox.shrink();
                  },
                ),
              ),
              topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
              rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
            ),
            borderData: FlBorderData(show: false),
            minX: 0,
            maxX: 11,
            minY: 0,
            maxY: 50,
            lineBarsData: [
              LineChartBarData(
                spots: const [
                  FlSpot(0, 25),
                  FlSpot(1, 28),
                  FlSpot(2, 32),
                  FlSpot(3, 30),
                  FlSpot(4, 35),
                  FlSpot(5, 38),
                  FlSpot(6, 33),
                  FlSpot(7, 40),
                  FlSpot(8, 42),
                  FlSpot(9, 38),
                  FlSpot(10, 45),
                  FlSpot(11, 48),
                ],
                isCurved: true,
                color: colorScheme.primary,
                barWidth: 3,
                isStrokeCapRound: true,
                dotData: const FlDotData(show: false),
                belowBarData: BarAreaData(
                  show: true,
                  color: colorScheme.primary.withValues(alpha: 0.15),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildActivityFeed() {
    return VooActivityFeed(
      title: 'Recent Activity',
      maxItems: 5,
      onViewAll: () {},
      items: [
        VooActivityItem(
          id: '1',
          title: 'New user registered',
          description: '[email protected]',
          timestamp: DateTime.now().subtract(const Duration(minutes: 5)),
          icon: Icons.person_add,
        ),
        VooActivityItem(
          id: '2',
          title: 'Order completed',
          description: 'Order #12345 was delivered',
          timestamp: DateTime.now().subtract(const Duration(hours: 1)),
          icon: Icons.check_circle,
          iconColor: Colors.green,
        ),
        VooActivityItem(
          id: '3',
          title: 'Payment received',
          description: '\$1,234.56 from Customer Corp',
          timestamp: DateTime.now().subtract(const Duration(hours: 3)),
          icon: Icons.payment,
          iconColor: Colors.blue,
        ),
        VooActivityItem(
          id: '4',
          title: 'Report generated',
          description: 'Monthly sales report',
          timestamp: DateTime.now().subtract(const Duration(days: 1)),
          icon: Icons.description,
        ),
        VooActivityItem(
          id: '5',
          title: 'System update',
          description: 'Version 2.0 deployed',
          timestamp: DateTime.now().subtract(const Duration(days: 2)),
          icon: Icons.system_update,
        ),
      ],
    );
  }

  Widget _buildBarChart() {
    final colorScheme = Theme.of(context).colorScheme;
    return VooChartContainer(
      title: 'Sales by Category',
      subtitle: 'Top performing categories this quarter',
      height: 280,
      chart: Padding(
        padding: const EdgeInsets.only(right: 16, top: 16, bottom: 8),
        child: BarChart(
          BarChartData(
            alignment: BarChartAlignment.spaceAround,
            maxY: 100,
            barTouchData: BarTouchData(enabled: true),
            titlesData: FlTitlesData(
              leftTitles: AxisTitles(
                sideTitles: SideTitles(
                  showTitles: true,
                  reservedSize: 35,
                  getTitlesWidget: (value, meta) => Text(
                    '${value.toInt()}%',
                    style: TextStyle(color: colorScheme.onSurfaceVariant, fontSize: 11),
                  ),
                ),
              ),
              bottomTitles: AxisTitles(
                sideTitles: SideTitles(
                  showTitles: true,
                  reservedSize: 30,
                  getTitlesWidget: (value, meta) {
                    const categories = ['Electronics', 'Clothing', 'Home', 'Sports', 'Books'];
                    if (value.toInt() >= 0 && value.toInt() < categories.length) {
                      return Padding(
                        padding: const EdgeInsets.only(top: 8),
                        child: Text(
                          categories[value.toInt()],
                          style: TextStyle(color: colorScheme.onSurfaceVariant, fontSize: 10),
                        ),
                      );
                    }
                    return const SizedBox.shrink();
                  },
                ),
              ),
              topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
              rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
            ),
            borderData: FlBorderData(show: false),
            gridData: FlGridData(
              show: true,
              drawVerticalLine: false,
              horizontalInterval: 25,
              getDrawingHorizontalLine: (value) => FlLine(
                color: colorScheme.outlineVariant.withValues(alpha: 0.3),
                strokeWidth: 1,
              ),
            ),
            barGroups: [
              _makeBarGroup(0, 85, colorScheme.primary),
              _makeBarGroup(1, 65, colorScheme.secondary),
              _makeBarGroup(2, 72, colorScheme.tertiary),
              _makeBarGroup(3, 48, colorScheme.primary.withValues(alpha: 0.7)),
              _makeBarGroup(4, 38, colorScheme.secondary.withValues(alpha: 0.7)),
            ],
          ),
        ),
      ),
    );
  }

  BarChartGroupData _makeBarGroup(int x, double y, Color color) => BarChartGroupData(
        x: x,
        barRods: [
          BarChartRodData(
            toY: y,
            color: color,
            width: 22,
            borderRadius: const BorderRadius.only(
              topLeft: Radius.circular(6),
              topRight: Radius.circular(6),
            ),
          ),
        ],
      );

  Widget _buildPieChart() {
    final colorScheme = Theme.of(context).colorScheme;
    return VooChartContainer(
      title: 'Traffic Sources',
      subtitle: 'Where your visitors come from',
      height: 280,
      chart: Row(
        children: [
          Expanded(
            flex: 3,
            child: PieChart(
              PieChartData(
                sectionsSpace: 2,
                centerSpaceRadius: 40,
                sections: [
                  PieChartSectionData(
                    value: 40,
                    title: '40%',
                    color: colorScheme.primary,
                    radius: 60,
                    titleStyle: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold),
                  ),
                  PieChartSectionData(
                    value: 25,
                    title: '25%',
                    color: colorScheme.secondary,
                    radius: 60,
                    titleStyle: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold),
                  ),
                  PieChartSectionData(
                    value: 20,
                    title: '20%',
                    color: colorScheme.tertiary,
                    radius: 60,
                    titleStyle: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold),
                  ),
                  PieChartSectionData(
                    value: 15,
                    title: '15%',
                    color: colorScheme.error,
                    radius: 60,
                    titleStyle: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold),
                  ),
                ],
              ),
            ),
          ),
          Expanded(
            flex: 2,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _buildLegendItem('Direct', colorScheme.primary),
                const SizedBox(height: 12),
                _buildLegendItem('Organic', colorScheme.secondary),
                const SizedBox(height: 12),
                _buildLegendItem('Referral', colorScheme.tertiary),
                const SizedBox(height: 12),
                _buildLegendItem('Social', colorScheme.error),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildLegendItem(String label, Color color) => Row(
        children: [
          Container(
            width: 12,
            height: 12,
            decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(3)),
          ),
          const SizedBox(width: 8),
          Text(label, style: Theme.of(context).textTheme.bodySmall),
        ],
      );
}
1
likes
160
points
106
downloads

Publisher

verified publishervoostack.com

Weekly Downloads

A comprehensive, responsive dashboard UI kit for Flutter with sidebar/topbar navigation, stat cards, chart containers, and activity feeds.

Homepage
Repository (GitHub)
View/report issues

Topics

#flutter #dashboard #admin-panel #responsive

Documentation

API reference

License

MIT (license)

Dependencies

collection, equatable, flutter, rxdart, voo_responsive, voo_tokens, voo_ui_core

More

Packages that depend on voo_dashboard