Add multiple select component
This commit is contained in:
@@ -35,6 +35,12 @@
|
|||||||
|
|
||||||
<SearchInput @bind-Text=GameFilterParams.SearchName />
|
<SearchInput @bind-Text=GameFilterParams.SearchName />
|
||||||
|
|
||||||
|
<MultipleSelectList TItem="string"
|
||||||
|
Items="Plateforms"
|
||||||
|
@bind-Values=GameFilterParams.Plateforms
|
||||||
|
Theme="SelectListTheme.Filter"/>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</EditForm>
|
</EditForm>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using GameIdeas.BlazorApp.Pages.Games.Models;
|
using GameIdeas.BlazorApp.Pages.Games.Models;
|
||||||
using GameIdeas.BlazorApp.Shared.Components.Select;
|
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||||
using GameIdeas.Shared.Dto;
|
using GameIdeas.Shared.Dto;
|
||||||
using GameIdeas.Shared.Enum;
|
using GameIdeas.Shared.Enum;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
@@ -24,6 +24,13 @@ public partial class GameFilter
|
|||||||
new() { Item = game => game?.ReleaseDate, Label = "Date de parution" }
|
new() { Item = game => game?.ReleaseDate, Label = "Date de parution" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private readonly IEnumerable<SelectElement<string>> Plateforms = [
|
||||||
|
new() { Item = "Steam", Label = "Steam" },
|
||||||
|
new() { Item = "GOG", Label = "GOG" },
|
||||||
|
new() { Item = "Epic games", Label = "Epic games" },
|
||||||
|
new() { Item = "Ubisoft", Label = "Ubisoft" },
|
||||||
|
];
|
||||||
|
|
||||||
private EditContext? EditContext;
|
private EditContext? EditContext;
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
|
|||||||
@@ -8,4 +8,7 @@ public class GameFilterParams
|
|||||||
public SortType? SortType { get; set; }
|
public SortType? SortType { get; set; }
|
||||||
public Func<GameDto?, object?>? SortProperty { get; set; }
|
public Func<GameDto?, object?>? SortProperty { get; set; }
|
||||||
public string? SearchName { get; set; }
|
public string? SearchName { get; set; }
|
||||||
|
public IEnumerable<string>? Plateforms { get; set; }
|
||||||
|
public IEnumerable<string>? Genres { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||||
"applicationUrl": "http://localhost:5172",
|
"applicationUrl": "http://localhost:5172",
|
||||||
|
"launchUrl": "http://localhost:5172/Games",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||||
"applicationUrl": "https://localhost:7060;http://localhost:5172",
|
"applicationUrl": "https://localhost:7060;http://localhost:5172",
|
||||||
|
"launchUrl": "http://localhost:7060/Games",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
<EditForm EditContext="EditContext">
|
<div class="search-container">
|
||||||
<div class="search-container">
|
<input type="text"
|
||||||
<InputText class="search-field"
|
class="search-field"
|
||||||
@bind-Value=Text />
|
@bind=@Text
|
||||||
|
@bind:event="oninput"
|
||||||
|
@bind:after=HandleTextChanged />
|
||||||
|
|
||||||
@if (!string.IsNullOrEmpty(Text))
|
@if (!string.IsNullOrEmpty(Text))
|
||||||
{
|
{
|
||||||
@@ -12,7 +14,7 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div type="submit" class="search-icon">
|
<div class="search-icon @(Enum.GetName(Icon)?.ToLower())" @onclick=HandleSearchClicked>
|
||||||
<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)
|
@if (Icon == SearchInputIcon.Search)
|
||||||
{
|
{
|
||||||
@@ -20,10 +22,9 @@
|
|||||||
}
|
}
|
||||||
else if (Icon == SearchInputIcon.Dropdown)
|
else if (Icon == SearchInputIcon.Dropdown)
|
||||||
{
|
{
|
||||||
<path style="fill: var(--violet)" d="M1 3H23L12 22" />
|
<path d="M1 3H23L12 22" />
|
||||||
}
|
}
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</EditForm>
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Forms;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Shared.Components.Search;
|
namespace GameIdeas.BlazorApp.Shared.Components.Search;
|
||||||
|
|
||||||
@@ -8,23 +6,32 @@ 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 EventCallback ClearClicked { get; set; }
|
||||||
|
[Parameter] public EventCallback SearchClicked { get; set; }
|
||||||
[Parameter] public SearchInputIcon Icon { get; set; }
|
[Parameter] public SearchInputIcon Icon { get; set; }
|
||||||
|
|
||||||
private EditContext? EditContext;
|
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
Text = string.Empty;
|
Text = string.Empty;
|
||||||
EditContext = new EditContext(Text);
|
}
|
||||||
|
|
||||||
EditContext.OnFieldChanged += async (s, e) =>
|
public void SetText(string str)
|
||||||
|
{
|
||||||
|
Text = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleTextChanged()
|
||||||
{
|
{
|
||||||
await TextChanged.InvokeAsync(Text);
|
await TextChanged.InvokeAsync(Text);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleClearClicked()
|
private async Task HandleClearClicked()
|
||||||
{
|
{
|
||||||
Text = string.Empty;
|
Text = string.Empty;
|
||||||
|
await ClearClicked.InvokeAsync();
|
||||||
|
}
|
||||||
|
private async Task HandleSearchClicked()
|
||||||
|
{
|
||||||
|
await SearchClicked.InvokeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,3 +51,8 @@
|
|||||||
.search-icon svg {
|
.search-icon svg {
|
||||||
fill: var(--white);
|
fill: var(--white);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-icon.dropdown svg {
|
||||||
|
fill: var(--violet);
|
||||||
|
transform: scale(.8, .5);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Shared.Components.Select.Components;
|
namespace GameIdeas.BlazorApp.Shared.Components.Select.Components;
|
||||||
@@ -11,6 +12,7 @@ public partial class SelectListElement<TItem>
|
|||||||
{
|
{
|
||||||
if (Value != null)
|
if (Value != null)
|
||||||
{
|
{
|
||||||
|
Value.IsSelected = true;
|
||||||
await ValueChanged.InvokeAsync(Value);
|
await ValueChanged.InvokeAsync(Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,15 +28,14 @@
|
|||||||
.navigation {
|
.navigation {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
}
|
}
|
||||||
|
.navigation:hover {
|
||||||
|
background: var(--violet-selected);
|
||||||
|
}
|
||||||
|
|
||||||
.navigation .selected {
|
.navigation .selected {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation:hover {
|
|
||||||
background: var(--violet-selected);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***** Sort Theme *****/
|
/***** Sort Theme *****/
|
||||||
.sort {
|
.sort {
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
@@ -51,4 +50,18 @@
|
|||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***** Filter Theme *****/
|
||||||
|
.filter {
|
||||||
|
padding: 2px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter:hover {
|
||||||
|
background: var(--low-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter .select-label {
|
||||||
|
text-wrap: nowrap;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace GameIdeas.BlazorApp.Shared.Components.Select;
|
namespace GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||||
|
|
||||||
public class SelectElement<TItem>
|
public class SelectElement<TItem>
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace GameIdeas.BlazorApp.Shared.Components.Select;
|
namespace GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||||
|
|
||||||
public enum SelectListTheme
|
public enum SelectListTheme
|
||||||
{
|
{
|
||||||
@@ -2,13 +2,15 @@
|
|||||||
@using GameIdeas.BlazorApp.Shared.Components.Select.Components
|
@using GameIdeas.BlazorApp.Shared.Components.Select.Components
|
||||||
@typeparam TItem
|
@typeparam TItem
|
||||||
|
|
||||||
<div class="select-list" @onclick=HandleButtonClicked>
|
<div class="select-list">
|
||||||
<div class="select-button">
|
<div class="select-button" @onfocusin=HandleFocusIn>
|
||||||
<SearchInput Icon="SearchInputIcon.Dropdown"
|
<SearchInput @ref=SearchInput
|
||||||
Text="Text"
|
Icon="SearchInputIcon.Dropdown"
|
||||||
TextChanged="HandleTextChanged"/>
|
TextChanged="HandleTextChanged"
|
||||||
|
ClearClicked="HandleTextChanged"
|
||||||
|
SearchClicked="Open" />
|
||||||
</div>
|
</div>
|
||||||
<div @ref=Container @onfocusout=HandleFocusOut
|
<div @onfocusout=HandleFocusOut
|
||||||
class="select-container @(AlignRight ? "align-right" : "")"
|
class="select-container @(AlignRight ? "align-right" : "")"
|
||||||
tabindex="1000">
|
tabindex="1000">
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using GameIdeas.BlazorApp.Shared.Components.Search;
|
||||||
|
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Shared.Components.Select;
|
namespace GameIdeas.BlazorApp.Shared.Components.Select;
|
||||||
@@ -11,41 +13,31 @@ public partial class MultipleSelectList<TItem>
|
|||||||
[Parameter] public bool AlignRight { get; set; }
|
[Parameter] public bool AlignRight { get; set; }
|
||||||
|
|
||||||
private bool ContentVisile = false;
|
private bool ContentVisile = false;
|
||||||
private DateTime ContentLastFocusOut = DateTime.Now;
|
private SearchInput? SearchInput;
|
||||||
private ElementReference Container;
|
|
||||||
private string? Text;
|
|
||||||
|
|
||||||
public async Task OpenAsync()
|
public void Open() => ContentVisile = true;
|
||||||
{
|
|
||||||
if (DateTime.Now - ContentLastFocusOut >= TimeSpan.FromSeconds(0.2))
|
|
||||||
{
|
|
||||||
await Container.FocusAsync();
|
|
||||||
ContentVisile = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close() => ContentVisile = false;
|
public void Close() => ContentVisile = false;
|
||||||
|
|
||||||
private async Task HandleButtonClicked() => await OpenAsync();
|
private void HandleFocusOut() => Close();
|
||||||
|
|
||||||
private void HandleFocusOut()
|
private void HandleFocusIn() => Open();
|
||||||
{
|
|
||||||
ContentLastFocusOut = DateTime.Now;
|
|
||||||
ContentVisile = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HandleItemClicked(SelectElement<TItem> selectedValue)
|
private async Task HandleItemClicked(SelectElement<TItem> selectedValue)
|
||||||
{
|
{
|
||||||
selectedValue.IsSelected = !selectedValue.IsSelected;
|
selectedValue.IsSelected = !selectedValue.IsSelected;
|
||||||
Values = Items.Where(x => x.IsSelected && x.Item != null).Select(x => x.Item!);
|
Values = Items.Where(x => x.IsSelected && x.Item != null).Select(x => x.Item!);
|
||||||
Text = string.Join(", ", Values);
|
SearchInput?.SetText(string.Join(", ", Values));
|
||||||
await ValuesChanged.InvokeAsync(Values);
|
await ValuesChanged.InvokeAsync(Values);
|
||||||
}
|
}
|
||||||
private void HandleTextChanged(string args)
|
|
||||||
|
private void HandleTextChanged()
|
||||||
{
|
{
|
||||||
foreach (var item in Items)
|
foreach (var item in Items)
|
||||||
{
|
{
|
||||||
item.IsSelected = false;
|
item.IsSelected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1 +1,49 @@
|
|||||||
@import "SelectList.razor.css";
|
.select-list {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-container {
|
||||||
|
margin-top: 4px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-right {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-content {
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: var(--small-radius);
|
||||||
|
animation-name: fade-in;
|
||||||
|
animation-duration: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
margin: 2px 6px;
|
||||||
|
border-bottom: 2px solid var(--low-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***** Navigation Theme *****/
|
||||||
|
.select-content.navigation {
|
||||||
|
background: var(--violet);
|
||||||
|
box-shadow: var(--drop-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Sort Theme *****/
|
||||||
|
.select-content.sort {
|
||||||
|
background: var(--semi-black);
|
||||||
|
box-shadow: var(--drop-shadow);
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Filter Theme *****/
|
||||||
|
.select-content.filter {
|
||||||
|
background: var(--semi-black);
|
||||||
|
box-shadow: var(--drop-shadow);
|
||||||
|
padding: 4px 0;
|
||||||
|
min-width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Shared.Components.Select;
|
namespace GameIdeas.BlazorApp.Shared.Components.Select;
|
||||||
@@ -34,7 +35,7 @@ public partial class SelectList<TItem>
|
|||||||
private void HandleFocusOut()
|
private void HandleFocusOut()
|
||||||
{
|
{
|
||||||
ContentLastFocusOut = DateTime.Now;
|
ContentLastFocusOut = DateTime.Now;
|
||||||
ContentVisile = true;
|
ContentVisile = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleItemClicked(SelectElement<TItem> selectedValue)
|
private async Task HandleItemClicked(SelectElement<TItem> selectedValue)
|
||||||
|
|||||||
@@ -38,4 +38,3 @@
|
|||||||
box-shadow: var(--drop-shadow);
|
box-shadow: var(--drop-shadow);
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using GameIdeas.BlazorApp.Pages.Games.Models;
|
using GameIdeas.BlazorApp.Pages.Games.Models;
|
||||||
using GameIdeas.BlazorApp.Shared.Components.Account;
|
using GameIdeas.BlazorApp.Shared.Components.Account;
|
||||||
using GameIdeas.BlazorApp.Shared.Components.Select;
|
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||||
using GameIdeas.Resources;
|
using GameIdeas.Resources;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user