diff --git a/LANCommander.UI/Components/DataList/DataList.razor b/LANCommander.UI/Components/DataList/DataList.razor
new file mode 100644
index 00000000..c84fb531
--- /dev/null
+++ b/LANCommander.UI/Components/DataList/DataList.razor
@@ -0,0 +1,65 @@
+@namespace LANCommander.UI.Components
+@typeparam TItem
+
+
+
+
+ @foreach (var item in DataSource)
+ {
+
+
+
+ }
+
+
+
+
+@code {
+ [Parameter] public IEnumerable DataSource { get; set; }
+ [Parameter] public TItem Value { get; set; }
+ [Parameter] public EventCallback ValueChanged { get; set; }
+ [Parameter] public IEnumerable Values { get; set; }
+ [Parameter] public EventCallback> ValuesChanged { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ [Parameter] public RenderFragment ItemTemplate { get; set; }
+
+ bool _radio;
+ bool _checkbox;
+
+ List _selectedValues = new();
+
+ protected override void OnInitialized()
+ {
+ if (ValueChanged.HasDelegate)
+ _radio = true;
+ else if (ValuesChanged.HasDelegate)
+ _checkbox = true;
+
+ if (ChildContent == null && ItemTemplate != null)
+ ChildContent = ItemTemplate;
+ }
+
+ async Task SelectionChanged(TItem item, bool selected)
+ {
+ if (_radio && selected)
+ {
+ Value = item;
+
+ await ValueChanged.InvokeAsync(Value);
+ }
+ else if (_checkbox)
+ {
+ _selectedValues.Remove(item);
+
+ if (selected)
+ _selectedValues.Add(item);
+
+ Values = _selectedValues;
+
+ await ValuesChanged.InvokeAsync(Values);
+ }
+ }
+}
\ No newline at end of file
diff --git a/LANCommander.UI/Components/DataList/DataListInputPosition.cs b/LANCommander.UI/Components/DataList/DataListInputPosition.cs
index 1704e316..16839717 100644
--- a/LANCommander.UI/Components/DataList/DataListInputPosition.cs
+++ b/LANCommander.UI/Components/DataList/DataListInputPosition.cs
@@ -1,6 +1,7 @@
-namespace LANCommander.UI.Components.DataList;
+namespace LANCommander.UI.Components;
-public class DataListInputPosition
+public enum DataListInputPosition
{
-
+ Left,
+ Right,
}
\ No newline at end of file
diff --git a/LANCommander.UI/Components/DataList/DataListItem.razor b/LANCommander.UI/Components/DataList/DataListItem.razor
new file mode 100644
index 00000000..f3cff779
--- /dev/null
+++ b/LANCommander.UI/Components/DataList/DataListItem.razor
@@ -0,0 +1,48 @@
+@namespace LANCommander.UI.Components
+@typeparam TItem
+
+
+
+ @if (InputPosition == DataListInputPosition.Left)
+ {
+
+ }
+
+ @ItemTemplate(Item)
+
+ @if (InputPosition == DataListInputPosition.Right)
+ {
+
+ }
+
+
+
+@code {
+ [CascadingParameter(Name = "Selected")]
+ public bool Selected { get; set; }
+
+ [CascadingParameter(Name = "Radio")]
+ public bool Radio { get; set; }
+
+ [CascadingParameter(Name = "Checkbox")]
+ public bool Checkbox { get; set; }
+
+ [CascadingParameter(Name = "InputPosition")]
+ public DataListInputPosition InputPosition { get; set; }
+
+ [CascadingParameter(Name = "SelectionTemplate")]
+ public RenderFragment SelectionTemplate { get; set; }
+
+ [Parameter] public TItem Item { get; set; }
+ [Parameter] public RenderFragment ItemTemplate { get; set; }
+ [Parameter] public EventCallback OnSelectedChanged { get; set; }
+ [Parameter] public FlexAlign Align { get; set; } = FlexAlign.Normal;
+ [Parameter] public FlexJustify Justify { get; set; } = FlexJustify.Center;
+ [Parameter] public FlexGap Gap { get; set; } = FlexGap.Normal;
+
+ private async Task ToggleSelection()
+ {
+ if (OnSelectedChanged.HasDelegate)
+ await OnSelectedChanged.InvokeAsync(!Selected);
+ }
+}
\ No newline at end of file
diff --git a/LANCommander.UI/Components/DataList/DataListItemInput.razor b/LANCommander.UI/Components/DataList/DataListItemInput.razor
new file mode 100644
index 00000000..0eeccd22
--- /dev/null
+++ b/LANCommander.UI/Components/DataList/DataListItemInput.razor
@@ -0,0 +1,31 @@
+@namespace LANCommander.UI.Components
+@typeparam TItem
+
+@if (SelectionTemplate != null)
+{
+ @SelectionTemplate((Item, Selected))
+}
+else if (Radio)
+{
+
+}
+else if (Checkbox)
+{
+
+}
+
+@code {
+ [CascadingParameter(Name = "Item")]
+ public TItem Item { get; set; }
+
+ [CascadingParameter(Name = "Selected")]
+ public bool Selected { get; set; }
+
+ [CascadingParameter(Name = "Radio")]
+ public bool Radio { get; set; }
+
+ [CascadingParameter(Name = "Checkbox")]
+ public bool Checkbox { get; set; }
+
+ [Parameter] public RenderFragment<(TItem, bool)> SelectionTemplate { get; set; }
+}
\ No newline at end of file