Skip to content

feat: Add ImpaktfullUiKanbanBoard component#46

Open
vanlooverenkoen wants to merge 12 commits into
mainfrom
vibe-kanban/1b40-kanban-board
Open

feat: Add ImpaktfullUiKanbanBoard component#46
vanlooverenkoen wants to merge 12 commits into
mainfrom
vibe-kanban/1b40-kanban-board

Conversation

@vanlooverenkoen
Copy link
Copy Markdown
Member

@vanlooverenkoen vanlooverenkoen commented Jan 18, 2026

Summary

  • Added new ImpaktfullUiKanbanBoard component with full drag-and-drop support
  • Includes configurable columns with name, color, and index properties
  • Kanban cards support title, description, and optional images

Changes Made

New Components

  • ImpaktfullUiKanbanBoard - Main container widget that manages columns and items
  • ImpaktfullUiKanbanBoardColumn - Individual column with drag target and reorderable list
  • ImpaktfullUiKanbanBoardCard - Card widget displaying item content with optional image

New Models

  • ImpaktfullUiKanbanBoardColumnConfig - Configuration for columns (id, name, color, index)
  • ImpaktfullUiKanbanBoardItem - Data model for kanban items with generic data support

Theme Support

  • Full theming support following library patterns
  • Customizable assets, colors, dimensions, text styles, and shadows
  • Registered in ImpaktfullUiComponentsTheme

Features

  1. Configurable Columns - Each column has a name, color (displayed in header), and index for ordering
  2. Drag-and-Drop - Items can be dragged between columns using LongPressDraggable and DragTarget
  3. Reorderable Items - Items can be reordered within a column using ReorderableListView
  4. Cards with Images - Each kanban card supports title, description, and optional network image
  5. Generic Data Support - Items can hold custom data of any type via generics
  6. Fully Themeable - Follows the library's theming pattern with customizable colors, dimensions, text styles, and shadows

Usage Example

ImpaktfullUiKanbanBoard<MyData>(
  columns: [
    ImpaktfullUiKanbanBoardColumnConfig(
      id: 'todo',
      name: 'To Do',
      color: Colors.blue,
      index: 0,
    ),
    ImpaktfullUiKanbanBoardColumnConfig(
      id: 'done',
      name: 'Done',
      color: Colors.green,
      index: 1,
    ),
  ],
  items: [
    ImpaktfullUiKanbanBoardItem(
      id: '1',
      columnId: 'todo',
      title: 'Task 1',
      description: 'Description here',
      imageUrl: 'https://example.com/image.jpg',
    ),
  ],
  onItemMoved: (item, fromColumn, toColumn, newIndex) {
    // Handle item moved between columns
  },
  onItemReordered: (item, oldIndex, newIndex) {
    // Handle item reordered within column
  },
)

Test Plan

  • Component compiles without errors
  • Flutter analyze passes with no issues
  • Code formatted with dart format
  • CHANGELOG updated with version 0.77.0
  • Added to example component library
  • Added to README.md component list

This PR was written using Vibe Kanban

…UI library. Here's a summary of what was created:

## Kanban Board Component

### Files Created:

**Models:**
- `lib/src/components/kanban_board/model/kanban_board_column_config.dart` - Column configuration with id, name, color, and index
- `lib/src/components/kanban_board/model/kanban_board_item.dart` - Board item with id, columnId, title, description, imageUrl, and generic data

**Components:**
- `lib/src/components/kanban_board/kanban_board.dart` - Main kanban board widget
- `lib/src/components/kanban_board/kanban_board.describe.dart` - Describe file for debugging
- `lib/src/components/kanban_board/kanban_board_column.dart` - Column component with drag-and-drop target
- `lib/src/components/kanban_board/kanban_board_column.describe.dart` - Describe file
- `lib/src/components/kanban_board/kanban_board_card.dart` - Card component with image and text
- `lib/src/components/kanban_board/kanban_board_card.describe.dart` - Describe file
- `lib/src/components/kanban_board/kanban_board_style.dart` - Theme with colors, dimensions, text styles, and shadows

### Features:
1. **Configurable Columns** - Each column has a name, color (displayed in header), and index for ordering
2. **Draggable Items** - Items can be dragged between columns using `LongPressDraggable` and `DragTarget`
3. **Reorderable within Column** - Items can be reordered within a column using `ReorderableListView`
4. **Card with Image** - Each kanban card supports title, description, and optional image
5. **Fully Themeable** - Follows the library's theming pattern with customizable colors, dimensions, text styles, and shadows
6. **Generic Data Support** - Items can hold custom data of any type via generics

### Usage Example:
```dart
ImpaktfullUiKanbanBoard<MyData>(
  columns: [
    ImpaktfullUiKanbanBoardColumnConfig(
      id: 'todo',
      name: 'To Do',
      color: Colors.blue,
      index: 0,
    ),
    ImpaktfullUiKanbanBoardColumnConfig(
      id: 'done',
      name: 'Done',
      color: Colors.green,
      index: 1,
    ),
  ],
  items: [
    ImpaktfullUiKanbanBoardItem(
      id: '1',
      columnId: 'todo',
      title: 'Task 1',
      description: 'Description here',
      imageUrl: 'https://example.com/image.jpg',
    ),
  ],
  onItemMoved: (item, fromColumn, toColumn, newIndex) {
    // Handle item moved between columns
  },
  onItemReordered: (item, oldIndex, newIndex) {
    // Handle item reordered within column
  },
)
```
## Summary

I've created a complete Kanban Board component following the library's patterns and updated based on the CLAUDE.md guidelines.

### Files Created:
- `lib/src/components/kanban_board/kanban_board.dart` - Main board widget
- `lib/src/components/kanban_board/kanban_board.describe.dart` - Describe mixin
- `lib/src/components/kanban_board/kanban_board_column.dart` - Column widget with drag target
- `lib/src/components/kanban_board/kanban_board_column.describe.dart` - Describe mixin
- `lib/src/components/kanban_board/kanban_board_card.dart` - Card widget with image support
- `lib/src/components/kanban_board/kanban_board_card.describe.dart` - Describe mixin
- `lib/src/components/kanban_board/kanban_board_style.dart` - Theme classes
- `lib/src/components/kanban_board/model/kanban_board_column_config.dart` - Column config model
- `lib/src/components/kanban_board/model/kanban_board_item.dart` - Item model

### Files Modified:
- `lib/src/theme/component_theme.dart` - Added kanban board theme registration
- `lib/src/theme/theme_default.dart` - Added default kanban board theme
- `lib/impaktfull_ui.dart` - Added kanban board export
- `CHANGELOG.md` - Added version 0.77.0 with new feature

### Features:
1. **Configurable Columns** - name, color, index
2. **Drag-and-Drop** - Items can be dragged between columns
3. **Reorderable** - Items can be reordered within columns
4. **Cards with Images** - Title, description, and optional image
5. **Fully Themeable** - Colors, dimensions, text styles, shadows
6. **Generic Data** - Items support custom data types via generics
Copilot AI review requested due to automatic review settings January 18, 2026 17:45
- Resolved merge conflicts with main branch
- Added AssetsTheme to kanban board style (following skill guidelines)
- Added kanban board to example component library
- Added kanban board to README.md component list
- All formatting and analysis passes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vanlooverenkoen vanlooverenkoen changed the title Kanban Board (vibe-kanban) feat: Add ImpaktfullUiKanbanBoard component (Vibe Kanban) Jan 18, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds a new kanban board component (ImpaktfullUiKanbanBoard) to the UI library, providing drag-and-drop functionality for organizing items across configurable columns. The implementation includes comprehensive theming support and follows the existing component architecture patterns in the codebase.

Changes:

  • Added kanban board component with configurable columns (name, color, index) and drag-and-drop support
  • Created model classes for board items and column configuration
  • Integrated complete theming support including colors, dimensions, text styles, and shadows

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
lib/src/components/kanban_board/kanban_board.dart Main kanban board component with state management for item movement and reordering
lib/src/components/kanban_board/kanban_board_column.dart Column component implementing drag target and reorderable list
lib/src/components/kanban_board/kanban_board_card.dart Card component displaying item title, description, and optional image
lib/src/components/kanban_board/model/kanban_board_item.dart Model class for kanban board items with generic data support
lib/src/components/kanban_board/model/kanban_board_column_config.dart Model class for column configuration
lib/src/components/kanban_board/kanban_board_style.dart Complete theme definitions for the kanban board component
lib/src/components/kanban_board/*.describe.dart Component descriptor files for debugging support
lib/src/theme/theme_default.dart Integration of kanban board theme into default theme
lib/src/theme/component_theme.dart Registration of kanban board theme in component theme system
lib/impaktfull_ui.dart Public export of kanban board component
example/pubspec.lock Updated dependency versions and Flutter SDK requirements
example/macos/Podfile Updated macOS deployment target to 10.15
example/macos/Runner.xcodeproj/project.pbxproj Updated macOS deployment target in Xcode project
example/macos/Podfile.lock Updated pod checksums
CHANGELOG.md Added release notes for version 0.77.0
CLAUDE.md Empty file added

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/src/components/kanban_board/kanban_board.dart Outdated
Comment on lines +55 to +60
List<ImpaktfullUiKanbanBoardColumnConfig> get _sortedColumns {
final sorted =
List<ImpaktfullUiKanbanBoardColumnConfig>.from(widget.columns);
sorted.sort((a, b) => a.index.compareTo(b.index));
return sorted;
}
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _sortedColumns getter creates a new list and sorts it on every access. Since it's accessed multiple times in the build method (lines 107, 114, 120, 123), this could impact performance with many columns. Consider computing the sorted columns once, either by caching the result or making it a late final variable that's computed once.

Copilot uses AI. Check for mistakes.
Comment thread lib/src/components/kanban_board/kanban_board_column.dart Outdated
Comment thread lib/src/components/kanban_board/kanban_board_column.dart
Comment on lines +66 to +78
void _handleItemDropped(
ImpaktfullUiKanbanBoardItem<T> item,
String targetColumnId,
) {
if (item.columnId != targetColumnId) {
final targetColumnItems = _getItemsForColumn(targetColumnId);
widget.onItemMoved?.call(
item,
item.columnId,
targetColumnId,
targetColumnItems.length,
);
}
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The onItemMoved callback receives item.columnId as the fromColumnId parameter (line 74), but at this point the item still belongs to the old column. This is correct behavior, but the API design is potentially confusing. Consider adding a clarifying comment or renaming the parameter in the item model to make it clearer that columnId represents the current/from column when the callback is invoked.

Copilot uses AI. Check for mistakes.
Comment thread lib/src/components/kanban_board/kanban_board_column.dart
Comment thread lib/src/components/kanban_board/kanban_board_column.dart Outdated
Comment thread lib/src/components/kanban_board/model/kanban_board_item.dart
Comment on lines +1 to +136
import 'package:flutter/material.dart';
import 'package:impaktfull_ui/src/components/kanban_board/kanban_board_column.dart';
import 'package:impaktfull_ui/src/components/kanban_board/kanban_board_style.dart';
import 'package:impaktfull_ui/src/components/kanban_board/model/kanban_board_column_config.dart';
import 'package:impaktfull_ui/src/components/kanban_board/model/kanban_board_item.dart';
import 'package:impaktfull_ui/src/util/descriptor/component_descriptor_mixin.dart';
import 'package:impaktfull_ui/src/widget/override_components/overridable_component_builder.dart';

export 'kanban_board_card.dart';
export 'kanban_board_column.dart';
export 'kanban_board_style.dart';
export 'model/kanban_board_column_config.dart';
export 'model/kanban_board_item.dart';

part 'kanban_board.describe.dart';

class ImpaktfullUiKanbanBoard<T> extends StatefulWidget
with ComponentDescriptorMixin {
final List<ImpaktfullUiKanbanBoardColumnConfig> columns;
final List<ImpaktfullUiKanbanBoardItem<T>> items;
final Widget Function(ImpaktfullUiKanbanBoardItem<T> item)? itemBuilder;
final void Function(
ImpaktfullUiKanbanBoardItem<T> item,
String fromColumnId,
String toColumnId,
int newIndex,
)? onItemMoved;
final void Function(
ImpaktfullUiKanbanBoardItem<T> item,
int oldIndex,
int newIndex,
)? onItemReordered;
final ImpaktfullUiKanbanBoardTheme? theme;

const ImpaktfullUiKanbanBoard({
required this.columns,
required this.items,
this.itemBuilder,
this.onItemMoved,
this.onItemReordered,
this.theme,
super.key,
});

@override
State<ImpaktfullUiKanbanBoard<T>> createState() =>
_ImpaktfullUiKanbanBoardState<T>();

@override
String describe(BuildContext context) => _describeInstance(context, this);
}

class _ImpaktfullUiKanbanBoardState<T>
extends State<ImpaktfullUiKanbanBoard<T>> {
List<ImpaktfullUiKanbanBoardColumnConfig> get _sortedColumns {
final sorted =
List<ImpaktfullUiKanbanBoardColumnConfig>.from(widget.columns);
sorted.sort((a, b) => a.index.compareTo(b.index));
return sorted;
}

List<ImpaktfullUiKanbanBoardItem<T>> _getItemsForColumn(String columnId) {
return widget.items.where((item) => item.columnId == columnId).toList();
}

void _handleItemDropped(
ImpaktfullUiKanbanBoardItem<T> item,
String targetColumnId,
) {
if (item.columnId != targetColumnId) {
final targetColumnItems = _getItemsForColumn(targetColumnId);
widget.onItemMoved?.call(
item,
item.columnId,
targetColumnId,
targetColumnItems.length,
);
}
}

void _handleItemReordered(
ImpaktfullUiKanbanBoardItem<T> item,
int newIndex,
String columnId,
) {
final columnItems = _getItemsForColumn(columnId);
final oldIndex = columnItems.indexWhere((i) => i.id == item.id);
if (oldIndex != -1 && oldIndex != newIndex) {
widget.onItemReordered?.call(item, oldIndex, newIndex);
}
}

@override
Widget build(BuildContext context) {
return ImpaktfullUiOverridableComponentBuilder(
component: widget,
overrideComponentTheme: widget.theme,
builder: (context, componentTheme) {
return LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: componentTheme.dimens.boardPadding,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (var i = 0; i < _sortedColumns.length; i++) ...[
if (i > 0)
SizedBox(width: componentTheme.dimens.columnSpacing),
SizedBox(
height: constraints.maxHeight -
componentTheme.dimens.boardPadding.vertical,
child: ImpaktfullUiKanbanBoardColumn<T>(
config: _sortedColumns[i],
items: _getItemsForColumn(_sortedColumns[i].id),
itemBuilder: widget.itemBuilder,
theme: widget.theme,
onItemReordered: (item, newIndex) {
_handleItemReordered(
item, newIndex, _sortedColumns[i].id);
},
onItemDropped: (item) {
_handleItemDropped(item, _sortedColumns[i].id);
},
),
),
],
],
),
);
},
);
},
);
}
}
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new kanban board component lacks test coverage. Given that the repository contains golden tests for other components (e.g., button tests in test/src/components/button/), the kanban board should also have corresponding test coverage to ensure functionality and visual consistency.

Copilot uses AI. Check for mistakes.
vanlooverenkoen and others added 9 commits January 18, 2026 19:10
The previous implementation used ReorderableListView which captured
drag gestures and prevented cross-column dragging. This change:

- Replaced ReorderableListView with regular ListView + DragTarget
- Each column is now a DragTarget that accepts items from any column
- Added visual drop indicator showing where items will be placed
- Items can now be dragged between columns and dropped at specific positions
- Within-column reordering still works via the same drag mechanism

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
## Summary of Changes

I've addressed all three issues you identified:

### 1. Card Subtitle Styling (Fixed)
- Updated `kanban_board_style.dart` to use the correct text style pattern
- Changed from `textStyles.onCardSecondary.text.small` to `textStyles.onCard.text.small.light`
- This matches how other components like `SimpleListItem` handle subtitle styling
- Also updated `cardTitle` to use `textStyles.onCard.text.small.medium` for consistency

### 2. Card Image Display (Fixed)
- The issue was passing `double.infinity` as width to `ImpaktfullUiNetworkImage`
- When the network image component handles picsum.photos URLs, it tries to convert width to int, causing issues with infinity
- Fixed by wrapping the image in `LayoutBuilder` to get the actual constraint width

### 3. Example State Changes (Fixed)
- Created a new `KanbanBoardStateConfigurator` widget at `example/lib/src/component_library/items/kanban_board/widget/kanban_board_state_configurator.dart`
- This StatefulWidget manages the kanban items list and properly handles:
  - `onItemMoved`: Updates the item's columnId when moved between columns
  - `onItemReordered`: Reorders items within the same column
- Updated `kanban_board_library_variant.dart` to use this stateful configurator

The code passes both format and analyze checks.
- Increased the height of the kanban board to 850 for better visibility.
- Simplified the builder function in `KanbanBoardStateConfigurator` for improved readability.
- Updated the image URL handling in `kanban_board_state_configurator.dart` to remove unnecessary dimensions.
- Refactored `kanban_board_card.dart` to utilize `ImpaktfullUiAutoLayout` for better layout management and removed the descriptor mixin.
- Streamlined the column widget in `kanban_board_column.dart` to use `ImpaktfullUiAutoLayout` for vertical and horizontal arrangements, enhancing layout consistency.
- Removed unused descriptor files for `kanban_board_card` and `kanban_board_column` to clean up the codebase.

These changes improve the overall structure and maintainability of the kanban board component.
@vanlooverenkoen vanlooverenkoen changed the title feat: Add ImpaktfullUiKanbanBoard component (Vibe Kanban) feat: Add ImpaktfullUiKanbanBoard component Jan 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants