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 System.Collections.Generic;
|
||||||
using MultiShop.ShopFramework;
|
using MultiShop.ShopFramework;
|
||||||
|
|
||||||
namespace MultiShop.SearchStructures
|
namespace MultiShop.DataStructures
|
||||||
{
|
{
|
||||||
public class ProductListingInfo
|
public class ProductListingInfo
|
||||||
{
|
{
|
@ -2,7 +2,7 @@ using System;
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using MultiShop.ShopFramework;
|
using MultiShop.ShopFramework;
|
||||||
|
|
||||||
namespace MultiShop.SearchStructures
|
namespace MultiShop.DataStructures
|
||||||
{
|
{
|
||||||
public static class ResultCategoryExtensions
|
public static class ResultCategoryExtensions
|
||||||
{
|
{
|
@ -2,7 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace MultiShop.SearchStructures
|
namespace MultiShop.DataStructures
|
||||||
{
|
{
|
||||||
public class ResultsProfile
|
public class ResultsProfile
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MultiShop.ShopFramework;
|
using MultiShop.ShopFramework;
|
||||||
|
|
||||||
namespace MultiShop.SearchStructures
|
namespace MultiShop.DataStructures
|
||||||
{
|
{
|
||||||
public class SearchProfile
|
public class SearchProfile
|
||||||
{
|
{
|
@ -1,3 +1,3 @@
|
|||||||
@page "/"
|
@page "/"
|
||||||
|
|
||||||
<h1>Welcome to MultiShop!</h1>
|
<h1>Welcome to MultiShop!</h1>
|
@ -2,12 +2,12 @@
|
|||||||
@using Microsoft.Extensions.Configuration
|
@using Microsoft.Extensions.Configuration
|
||||||
@using ShopFramework
|
@using ShopFramework
|
||||||
@using SimpleLogger
|
@using SimpleLogger
|
||||||
@using SearchStructures
|
@using DataStructures
|
||||||
@inject HttpClient Http
|
@inject HttpClient Http
|
||||||
@inject IConfiguration Configuration
|
@inject IConfiguration Configuration
|
||||||
@inject IJSRuntime js
|
@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="my-2">
|
||||||
<div class="input-group my-2">
|
<div class="input-group my-2">
|
||||||
@ -178,7 +178,28 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-3 py-2">
|
<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">
|
<div class="align-self-end">
|
||||||
@if (searching)
|
@if (searching)
|
||||||
{
|
{
|
||||||
@ -220,19 +241,6 @@
|
|||||||
<span class="text-muted">Search for something to see the results!</span>
|
<span class="text-muted">Search for something to see the results!</span>
|
||||||
}
|
}
|
||||||
</div>
|
</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>
|
||||||
<div>
|
<div>
|
||||||
<ListingTableView Products="@listings" />
|
<ListingTableView Products="@listings" />
|
||||||
@ -251,11 +259,17 @@
|
|||||||
private ResultsProfile activeResultsProfile = new ResultsProfile();
|
private ResultsProfile activeResultsProfile = new ResultsProfile();
|
||||||
|
|
||||||
private bool showSearchConfiguration = false;
|
private bool showSearchConfiguration = false;
|
||||||
|
private bool showResultsConfiguration = false;
|
||||||
|
|
||||||
private string ToggleSearchConfigButtonCss
|
private string ToggleSearchConfigButtonCss
|
||||||
{
|
{
|
||||||
get => "btn btn-outline-secondary" + (showSearchConfiguration ? " active" : "");
|
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 searched = false;
|
||||||
private bool searching = false;
|
private bool searching = false;
|
||||||
private bool organizing = false;
|
private bool organizing = false;
|
||||||
@ -306,7 +320,8 @@
|
|||||||
await foreach (ProductListing listing in Shops[shopName])
|
await foreach (ProductListing listing in Shops[shopName])
|
||||||
{
|
{
|
||||||
resultsChecked += 1;
|
resultsChecked += 1;
|
||||||
if (resultsChecked % 50 == 0) {
|
if (resultsChecked % 50 == 0)
|
||||||
|
{
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
}
|
}
|
||||||
@ -355,7 +370,7 @@
|
|||||||
}
|
}
|
||||||
searching = false;
|
searching = false;
|
||||||
searched = true;
|
searched = true;
|
||||||
|
|
||||||
foreach (ResultsProfile.Category c in greatest.Keys)
|
foreach (ResultsProfile.Category c in greatest.Keys)
|
||||||
{
|
{
|
||||||
foreach (ProductListingInfo info in greatest[c])
|
foreach (ProductListingInfo info in greatest[c])
|
||||||
@ -373,19 +388,20 @@
|
|||||||
organizing = true;
|
organizing = true;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
|
||||||
List<ProductListingInfo> sortedResults = await Task.Run<List<ProductListingInfo>>(() => {
|
List<ProductListingInfo> sortedResults = await Task.Run<List<ProductListingInfo>>(() =>
|
||||||
|
{
|
||||||
List<ProductListingInfo> sorted = new List<ProductListingInfo>(listings);
|
List<ProductListingInfo> sorted = new List<ProductListingInfo>(listings);
|
||||||
sorted.Sort((a, b) =>
|
sorted.Sort((a, b) =>
|
||||||
{
|
{
|
||||||
foreach (ResultsProfile.Category category in activeResultsProfile.Order)
|
foreach (ResultsProfile.Category category in activeResultsProfile.Order)
|
||||||
{
|
{
|
||||||
int? compareResult = category.CompareListings(a, b);
|
int? compareResult = category.CompareListings(a, b);
|
||||||
if (compareResult.HasValue && compareResult.Value != 0)
|
if (compareResult.HasValue && compareResult.Value != 0)
|
||||||
{
|
{
|
||||||
return -compareResult.Value;
|
return -compareResult.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
return sorted;
|
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">
|
<ul class=@ListGroupCss style="width: max-content;" @ref="dragAndDrop">
|
||||||
@foreach (TItem item in Items)
|
@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))">
|
<li class="list-group-item" draggable=@((!processingDropChange).ToString()) @ondragstart="@(() => itemDraggedIndex = Items.IndexOf(item))" @ondrop="@(async () => await OnDrop(item))">
|
||||||
<span class="mx-1 oi oi-elevator"></span>
|
<div class="d-inline-flex">
|
||||||
@DraggableItem(item)
|
<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>
|
</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
@ -29,6 +36,7 @@
|
|||||||
private ElementReference dragAndDrop;
|
private ElementReference dragAndDrop;
|
||||||
|
|
||||||
private int itemDraggedIndex = -1;
|
private int itemDraggedIndex = -1;
|
||||||
|
private bool processingDropChange = false;
|
||||||
|
|
||||||
|
|
||||||
private string ListGroupCss
|
private string ListGroupCss
|
||||||
@ -54,12 +62,28 @@
|
|||||||
|
|
||||||
private async Task OnDrop(TItem dropped)
|
private async Task OnDrop(TItem dropped)
|
||||||
{
|
{
|
||||||
TItem item = Items[itemDraggedIndex];
|
int dragIndex = itemDraggedIndex;
|
||||||
if (item.Equals(dropped)) return;
|
|
||||||
int indexOfDrop = Items.IndexOf(dropped);
|
|
||||||
Items.RemoveAt(itemDraggedIndex);
|
|
||||||
Items.Insert(indexOfDrop, item);
|
|
||||||
itemDraggedIndex = -1;
|
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();
|
await OnOrderChange.InvokeAsync();
|
||||||
|
processingDropChange = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
@using ShopFramework
|
@using DataStructures
|
||||||
@using SearchStructures
|
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-top-borderless">
|
<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) {
|
function dragAndDropList(elem) {
|
||||||
elem.addEventListener("dragover", (e) => {
|
elem.addEventListener("dragover", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -49,21 +8,16 @@ function dragAndDropList(elem) {
|
|||||||
e.addEventListener("dragstart", () => {
|
e.addEventListener("dragstart", () => {
|
||||||
itemDragged = e;
|
itemDragged = e;
|
||||||
e.classList.add("list-group-item-secondary");
|
e.classList.add("list-group-item-secondary");
|
||||||
e.classList.remove("list-group-item-hover");
|
|
||||||
});
|
});
|
||||||
e.addEventListener("dragenter", () => {
|
e.addEventListener("dragenter", () => {
|
||||||
e.classList.add("list-group-item-primary");
|
e.classList.add("list-group-item-primary");
|
||||||
e.classList.remove("list-group-item-hover");
|
|
||||||
});
|
});
|
||||||
e.addEventListener("dragleave", () => {
|
e.addEventListener("dragleave", () => {
|
||||||
e.classList.remove("list-group-item-primary");
|
e.classList.remove("list-group-item-primary");
|
||||||
e.classList.add("list-group-item-hover");
|
|
||||||
});
|
});
|
||||||
e.addEventListener("drop", () => {
|
e.addEventListener("drop", () => {
|
||||||
e.classList.add("list-group-item-hover");
|
|
||||||
e.classList.remove("list-group-item-primary");
|
e.classList.remove("list-group-item-primary");
|
||||||
itemDragged.classList.remove("list-group-item-secondary");
|
itemDragged.classList.remove("list-group-item-secondary");
|
||||||
itemDragged.classList.add("list-group-item-hover");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user