add multiple select list

This commit is contained in:
2025-03-11 00:14:09 +01:00
parent fbcd40834e
commit 3ba79fdf03
11 changed files with 124 additions and 20 deletions

View File

@@ -1,7 +1,7 @@
using FluentValidation; using FluentValidation;
using GameIdeas.Shared.Dto; using GameIdeas.Shared.Dto;
namespace GameIdeas.BlazorApp.Shared.Layouts.Header; namespace GameIdeas.BlazorApp.Shared.Components.Account;
public class LoginValidator : AbstractValidator<LoginDto> public class LoginValidator : AbstractValidator<LoginDto>
{ {

View File

@@ -3,14 +3,25 @@
<InputText class="search-field" <InputText class="search-field"
@bind-Value=Text /> @bind-Value=Text />
@if (!string.IsNullOrEmpty(Text))
{
<div class="clear-icon" @onclick=HandleClearClicked> <div class="clear-icon" @onclick=HandleClearClicked>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" /> <path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
</svg> </svg>
</div> </div>
}
<div type="submit" class="search-icon"> <div type="submit" class="search-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
@if (Icon == SearchInputIcon.Search)
{
<path d="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z" /> <path d="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z" />
}
else if (Icon == SearchInputIcon.Dropdown)
{
<path style="fill: var(--violet)" d="M1 3H23L12 22" />
}
</svg> </svg>
</div> </div>
</div> </div>

View File

@@ -8,6 +8,7 @@ public partial class SearchInput
{ {
[Parameter] public string? Text { get; set; } [Parameter] public string? Text { get; set; }
[Parameter] public EventCallback<string> TextChanged { get; set; } [Parameter] public EventCallback<string> TextChanged { get; set; }
[Parameter] public SearchInputIcon Icon { get; set; }
private EditContext? EditContext; private EditContext? EditContext;

View File

@@ -0,0 +1,7 @@
namespace GameIdeas.BlazorApp.Shared.Components.Search;
public enum SearchInputIcon
{
Search,
Dropdown
}

View File

@@ -11,7 +11,6 @@ public partial class SelectListElement<TItem>
{ {
if (Value != null) if (Value != null)
{ {
Value.IsSelected = true;
await ValueChanged.InvokeAsync(Value); await ValueChanged.InvokeAsync(Value);
} }
} }

View File

@@ -1,19 +1,32 @@
.select-element { .select-element {
display: flex;
flex-direction: row;
width: fit-content; width: fit-content;
width: 100%;
gap: 6px;
height: 20px;
align-items: center;
} }
.select-element:hover { .select-element:hover {
cursor: pointer; cursor: pointer;
} }
.selected {
width: 12px;
min-width: 12px;
height: 12px;
min-height: 12px;
}
.selected svg { .selected svg {
display: block;
fill: var(--white) fill: var(--white)
} }
/***** Navigation Theme *****/ /***** Navigation Theme *****/
.navigation { .navigation {
padding: 4px 8px; padding: 4px 8px;
width: 100%;
} }
.navigation .selected { .navigation .selected {
@@ -26,10 +39,6 @@
/***** Sort Theme *****/ /***** Sort Theme *****/
.sort { .sort {
gap: 6px;
display: flex;
flex-direction: row;
width: 100%;
padding: 2px 6px; padding: 2px 6px;
} }
@@ -37,11 +46,6 @@
background: var(--low-white); background: var(--low-white);
} }
.sort .selected {
width: 20px;
height: 20px;
}
.sort .select-label { .sort .select-label {
text-wrap: nowrap; text-wrap: nowrap;
margin-right: 6px; margin-right: 6px;

View File

@@ -0,0 +1,29 @@
@using GameIdeas.BlazorApp.Shared.Components.Search
@using GameIdeas.BlazorApp.Shared.Components.Select.Components
@typeparam TItem
<div class="select-list" @onclick=HandleButtonClicked>
<div class="select-button">
<SearchInput Icon="SearchInputIcon.Dropdown"
Text="Text"
TextChanged="HandleTextChanged"/>
</div>
<div @ref=Container @onfocusout=HandleFocusOut
class="select-container @(AlignRight ? "align-right" : "")"
tabindex="1000">
@if (ContentVisile)
{
<div class="select-content @(Enum.GetName(Theme)?.ToLower())">
@foreach (var item in Items)
{
<SelectListElement TItem="TItem"
Value="item"
ValueChanged="HandleItemClicked"
Theme="Theme" />
}
</div>
}
</div>
</div>

View File

@@ -0,0 +1,51 @@
using Microsoft.AspNetCore.Components;
namespace GameIdeas.BlazorApp.Shared.Components.Select;
public partial class MultipleSelectList<TItem>
{
[Parameter] public IEnumerable<TItem>? Values { get; set; }
[Parameter] public EventCallback<IEnumerable<TItem>?> ValuesChanged { get; set; }
[Parameter] public IEnumerable<SelectElement<TItem>> Items { get; set; } = [];
[Parameter] public SelectListTheme Theme { get; set; }
[Parameter] public bool AlignRight { get; set; }
private bool ContentVisile = false;
private DateTime ContentLastFocusOut = DateTime.Now;
private ElementReference Container;
private string? Text;
public async Task OpenAsync()
{
if (DateTime.Now - ContentLastFocusOut >= TimeSpan.FromSeconds(0.2))
{
await Container.FocusAsync();
ContentVisile = true;
}
}
public void Close() => ContentVisile = false;
private async Task HandleButtonClicked() => await OpenAsync();
private void HandleFocusOut()
{
ContentLastFocusOut = DateTime.Now;
ContentVisile = true;
}
private async Task HandleItemClicked(SelectElement<TItem> selectedValue)
{
selectedValue.IsSelected = !selectedValue.IsSelected;
Values = Items.Where(x => x.IsSelected && x.Item != null).Select(x => x.Item!);
Text = string.Join(", ", Values);
await ValuesChanged.InvokeAsync(Values);
}
private void HandleTextChanged(string args)
{
foreach (var item in Items)
{
item.IsSelected = false;
}
}
}

View File

@@ -0,0 +1 @@
@import "SelectList.razor.css";

View File

@@ -5,4 +5,5 @@ public class SelectElement<TItem>
public TItem? Item { get; set; } public TItem? Item { get; set; }
public string? Label { get; set; } public string? Label { get; set; }
public bool IsSelected { get; set; } = false; public bool IsSelected { get; set; } = false;
public bool IsNew { get; set; } = false;
} }

View File

@@ -34,7 +34,7 @@ public partial class SelectList<TItem>
private void HandleFocusOut() private void HandleFocusOut()
{ {
ContentLastFocusOut = DateTime.Now; ContentLastFocusOut = DateTime.Now;
ContentVisile = false; ContentVisile = true;
} }
private async Task HandleItemClicked(SelectElement<TItem> selectedValue) private async Task HandleItemClicked(SelectElement<TItem> selectedValue)