Changed up results configuration layout.
Removed dropdown portion. Added buttons to change sort order. Visual indicator for disabling changes to sort order list. Renamed a namespace.
This commit is contained in:
parent
9dc8917aa5
commit
99656133c9
@ -1 +1 @@
|
||||
Subproject commit f275ff330db936d7eabc6dc435952ec0752edbc9
|
||||
Subproject commit 3049cccc3efa3323a85f1ae591969b8f5d35be5d
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using MultiShop.ShopFramework;
|
||||
|
||||
namespace MultiShop.SearchStructures
|
||||
namespace MultiShop.DataStructures
|
||||
{
|
||||
public class ProductListingInfo
|
||||
{
|
@ -2,7 +2,7 @@ using System;
|
||||
using System.ComponentModel;
|
||||
using MultiShop.ShopFramework;
|
||||
|
||||
namespace MultiShop.SearchStructures
|
||||
namespace MultiShop.DataStructures
|
||||
{
|
||||
public static class ResultCategoryExtensions
|
||||
{
|
@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MultiShop.SearchStructures
|
||||
namespace MultiShop.DataStructures
|
||||
{
|
||||
public class ResultsProfile
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using MultiShop.ShopFramework;
|
||||
|
||||
namespace MultiShop.SearchStructures
|
||||
namespace MultiShop.DataStructures
|
||||
{
|
||||
public class SearchProfile
|
||||
{
|
@ -1,3 +1,3 @@
|
||||
@page "/"
|
||||
|
||||
<h1>Welcome to MultiShop!</h1>
|
||||
<h1>Welcome to MultiShop!</h1>
|
@ -2,12 +2,12 @@
|
||||
@using Microsoft.Extensions.Configuration
|
||||
@using ShopFramework
|
||||
@using SimpleLogger
|
||||
@using SearchStructures
|
||||
@using DataStructures
|
||||
@inject HttpClient Http
|
||||
@inject IConfiguration Configuration
|
||||
@inject IJSRuntime js
|
||||
|
||||
@* TODO: Finish sorting, move things to individual components where possible, key search results. *@
|
||||
@* TODO: Add buttons for the order changing. Add main page. *@
|
||||
|
||||
<div class="my-2">
|
||||
<div class="input-group my-2">
|
||||
@ -178,7 +178,28 @@
|
||||
</div>
|
||||
|
||||
<div class="my-3 py-2">
|
||||
<div class="d-flex flex-wrap justify-content-between" style="width: 100%; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: lightgray;">
|
||||
<div class="d-inline-flex" style="width: 100%; border-bottom-style: solid; border-bottom-width: 1px; border-color: lightgray;">
|
||||
<button type="button" class=@ToggleResultsConfigurationcss @onclick="@(() => showResultsConfiguration = !showResultsConfiguration)"><span class="oi oi-sort-descending"></span></button>
|
||||
</div>
|
||||
@if (showResultsConfiguration)
|
||||
{
|
||||
<div style="border-color: lightgray;" class="p-1">
|
||||
<div class="card m-2" style="max-width: 23em;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Results Order</h5>
|
||||
<h6 class="card-subtitle mb-2 text-muted">What's important to you?</h6>
|
||||
<p class="card-text">The results will be sorted by the top category. If the compared results are equal or don't have a value for that category, the next category on the list will be used and so on.</p>
|
||||
<DragAndDropList Items="@(activeResultsProfile.Order)" Context="item" AdditionalListClasses="mx-auto" OnOrderChange="@(async () => await Organize(activeResultsProfile.Order))">
|
||||
<DraggableItem>
|
||||
@(item.FriendlyName())
|
||||
</DraggableItem>
|
||||
</DragAndDropList>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="d-flex flex-wrap" style="width: 100%; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: lightgray;">
|
||||
<div class="align-self-end">
|
||||
@if (searching)
|
||||
{
|
||||
@ -220,19 +241,6 @@
|
||||
<span class="text-muted">Search for something to see the results!</span>
|
||||
}
|
||||
</div>
|
||||
<CustomDropdown AdditionalButtonClasses="btn-outline-secondary btn-tab" Justify="right">
|
||||
<ButtonContent>
|
||||
<span class="oi oi-sort-descending"></span>
|
||||
</ButtonContent>
|
||||
<DropdownContent>
|
||||
<DragAndDropList Items="@(activeResultsProfile.Order)" Context="item" AdditionalListClasses="list-group-empty-top-left" OnOrderChange="@(async () => await Organize(activeResultsProfile.Order))">
|
||||
<DraggableItem>
|
||||
@(item.FriendlyName())
|
||||
</DraggableItem>
|
||||
</DragAndDropList>
|
||||
</DropdownContent>
|
||||
</CustomDropdown>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<ListingTableView Products="@listings" />
|
||||
@ -251,11 +259,17 @@
|
||||
private ResultsProfile activeResultsProfile = new ResultsProfile();
|
||||
|
||||
private bool showSearchConfiguration = false;
|
||||
private bool showResultsConfiguration = false;
|
||||
|
||||
private string ToggleSearchConfigButtonCss
|
||||
{
|
||||
get => "btn btn-outline-secondary" + (showSearchConfiguration ? " active" : "");
|
||||
}
|
||||
|
||||
private string ToggleResultsConfigurationcss {
|
||||
get => "btn btn-outline-secondary btn-tab" + (showResultsConfiguration ? " active" : "");
|
||||
}
|
||||
|
||||
private bool searched = false;
|
||||
private bool searching = false;
|
||||
private bool organizing = false;
|
||||
@ -306,7 +320,8 @@
|
||||
await foreach (ProductListing listing in Shops[shopName])
|
||||
{
|
||||
resultsChecked += 1;
|
||||
if (resultsChecked % 50 == 0) {
|
||||
if (resultsChecked % 50 == 0)
|
||||
{
|
||||
StateHasChanged();
|
||||
await Task.Yield();
|
||||
}
|
||||
@ -355,7 +370,7 @@
|
||||
}
|
||||
searching = false;
|
||||
searched = true;
|
||||
|
||||
|
||||
foreach (ResultsProfile.Category c in greatest.Keys)
|
||||
{
|
||||
foreach (ProductListingInfo info in greatest[c])
|
||||
@ -373,19 +388,20 @@
|
||||
organizing = true;
|
||||
StateHasChanged();
|
||||
|
||||
List<ProductListingInfo> sortedResults = await Task.Run<List<ProductListingInfo>>(() => {
|
||||
List<ProductListingInfo> sortedResults = await Task.Run<List<ProductListingInfo>>(() =>
|
||||
{
|
||||
List<ProductListingInfo> sorted = new List<ProductListingInfo>(listings);
|
||||
sorted.Sort((a, b) =>
|
||||
{
|
||||
foreach (ResultsProfile.Category category in activeResultsProfile.Order)
|
||||
{
|
||||
int? compareResult = category.CompareListings(a, b);
|
||||
if (compareResult.HasValue && compareResult.Value != 0)
|
||||
{
|
||||
return -compareResult.Value;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
{
|
||||
foreach (ResultsProfile.Category category in activeResultsProfile.Order)
|
||||
{
|
||||
int? compareResult = category.CompareListings(a, b);
|
||||
if (compareResult.HasValue && compareResult.Value != 0)
|
||||
{
|
||||
return -compareResult.Value;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return sorted;
|
||||
});
|
||||
|
@ -1,45 +0,0 @@
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<div style="position: relative;" @ref="dropdown">
|
||||
<button type="button" class=@ButtonCss>@ButtonContent</button>
|
||||
<div class="invisible" style="position: absolute;" tabindex="0">
|
||||
@DropdownContent
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public RenderFragment ButtonContent { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment DropdownContent { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string AdditionalButtonClasses { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Justify { get; set; }
|
||||
|
||||
private ElementReference dropdown;
|
||||
private string ButtonCss
|
||||
{
|
||||
get => "btn " + AdditionalButtonClasses;
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
AdditionalButtonClasses = AdditionalButtonClasses ?? "";
|
||||
Justify = Justify ?? "center";
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await JS.InvokeVoidAsync("customDropdown", dropdown, Justify);
|
||||
}
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
}
|
@ -5,9 +5,16 @@
|
||||
<ul class=@ListGroupCss style="width: max-content;" @ref="dragAndDrop">
|
||||
@foreach (TItem item in Items)
|
||||
{
|
||||
<li class="list-group-item list-group-item-hover" draggable="true" @ondragstart="@(() => itemDraggedIndex = Items.IndexOf(item))" @ondrop="@(async () => await OnDrop(item))">
|
||||
<span class="mx-1 oi oi-elevator"></span>
|
||||
@DraggableItem(item)
|
||||
<li class="list-group-item" draggable=@((!processingDropChange).ToString()) @ondragstart="@(() => itemDraggedIndex = Items.IndexOf(item))" @ondrop="@(async () => await OnDrop(item))">
|
||||
<div class="d-inline-flex">
|
||||
<div class="mr-3">
|
||||
<button class="btn" type="button" style="padding: 0px;" @onclick="@(() => OnButtonClickMove(Items.IndexOf(item), true))" disabled="@(processingDropChange || Items.IndexOf(item) <= 0)"><span class="oi oi-caret-top"></span></button>
|
||||
<button class="btn" type="button" style="padding: 0px;" @onclick="@(() => OnButtonClickMove(Items.IndexOf(item), false))" disabled="@(processingDropChange || Items.IndexOf(item) >= Items.Count - 1)"><span class="oi oi-caret-bottom"></span></button>
|
||||
</div>
|
||||
<div>
|
||||
@DraggableItem(item)
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
@ -29,6 +36,7 @@
|
||||
private ElementReference dragAndDrop;
|
||||
|
||||
private int itemDraggedIndex = -1;
|
||||
private bool processingDropChange = false;
|
||||
|
||||
|
||||
private string ListGroupCss
|
||||
@ -54,12 +62,28 @@
|
||||
|
||||
private async Task OnDrop(TItem dropped)
|
||||
{
|
||||
TItem item = Items[itemDraggedIndex];
|
||||
if (item.Equals(dropped)) return;
|
||||
int indexOfDrop = Items.IndexOf(dropped);
|
||||
Items.RemoveAt(itemDraggedIndex);
|
||||
Items.Insert(indexOfDrop, item);
|
||||
int dragIndex = itemDraggedIndex;
|
||||
itemDraggedIndex = -1;
|
||||
await MoveOrder(dragIndex, Items.IndexOf(dropped));
|
||||
}
|
||||
|
||||
private async Task OnButtonClickMove(int index, bool up) {
|
||||
if (up) {
|
||||
await MoveOrder(index, index - 1);
|
||||
} else {
|
||||
await MoveOrder(index, index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task MoveOrder(int from, int to)
|
||||
{
|
||||
Logger.Log($"Attempting to move from {from} to {to}.", LogLevel.Debug);
|
||||
if (from == to || from >= Items.Count || from < 0 || to > Items.Count || to < 0) return;
|
||||
TItem item = Items[from];
|
||||
Items.RemoveAt(from);
|
||||
Items.Insert(to, item);
|
||||
processingDropChange = true;
|
||||
await OnOrderChange.InvokeAsync();
|
||||
processingDropChange = false;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
@using ShopFramework
|
||||
@using SearchStructures
|
||||
@using DataStructures
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-top-borderless">
|
||||
|
@ -1,44 +1,3 @@
|
||||
function customDropdown(elem, justify) {
|
||||
let btn = elem.querySelector("button");
|
||||
let dropdown = elem.querySelector("div");
|
||||
if (justify.toLowerCase() == "left") {
|
||||
dropdown.style.left = "0px";
|
||||
} else if (justify.toLowerCase() == "center") {
|
||||
dropdown.style.left = "50%";
|
||||
} else if (justify.toLowerCase() == "right") {
|
||||
dropdown.style.right = "0px";
|
||||
}
|
||||
|
||||
let openFunc = () => {
|
||||
btn.classList.add("active");
|
||||
dropdown.classList.remove("invisible");
|
||||
dropdown.focus();
|
||||
}
|
||||
|
||||
let closeFunc = () => {
|
||||
btn.classList.remove("active");
|
||||
dropdown.classList.add("invisible");
|
||||
}
|
||||
|
||||
btn.addEventListener("click", () => {
|
||||
if (!btn.classList.contains("active")) {
|
||||
openFunc();
|
||||
} else {
|
||||
closeFunc();
|
||||
}
|
||||
});
|
||||
dropdown.addEventListener("focusout", (e) => {
|
||||
if (e.relatedTarget != btn) {
|
||||
closeFunc();
|
||||
}
|
||||
});
|
||||
dropdown.addEventListener("keyup", (e) => {
|
||||
if (e.code == "Escape") {
|
||||
dropdown.blur();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function dragAndDropList(elem) {
|
||||
elem.addEventListener("dragover", (e) => {
|
||||
e.preventDefault();
|
||||
@ -49,21 +8,16 @@ function dragAndDropList(elem) {
|
||||
e.addEventListener("dragstart", () => {
|
||||
itemDragged = e;
|
||||
e.classList.add("list-group-item-secondary");
|
||||
e.classList.remove("list-group-item-hover");
|
||||
});
|
||||
e.addEventListener("dragenter", () => {
|
||||
e.classList.add("list-group-item-primary");
|
||||
e.classList.remove("list-group-item-hover");
|
||||
});
|
||||
e.addEventListener("dragleave", () => {
|
||||
e.classList.remove("list-group-item-primary");
|
||||
e.classList.add("list-group-item-hover");
|
||||
});
|
||||
e.addEventListener("drop", () => {
|
||||
e.classList.add("list-group-item-hover");
|
||||
e.classList.remove("list-group-item-primary");
|
||||
itemDragged.classList.remove("list-group-item-secondary");
|
||||
itemDragged.classList.add("list-group-item-hover");
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user