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:
Harrison Deng 2021-05-10 00:30:40 -05:00
parent 9dc8917aa5
commit 99656133c9
11 changed files with 84 additions and 136 deletions

@ -1 +1 @@
Subproject commit f275ff330db936d7eabc6dc435952ec0752edbc9
Subproject commit 3049cccc3efa3323a85f1ae591969b8f5d35be5d

View File

@ -1,7 +1,7 @@
using System.Collections.Generic;
using MultiShop.ShopFramework;
namespace MultiShop.SearchStructures
namespace MultiShop.DataStructures
{
public class ProductListingInfo
{

View File

@ -2,7 +2,7 @@ using System;
using System.ComponentModel;
using MultiShop.ShopFramework;
namespace MultiShop.SearchStructures
namespace MultiShop.DataStructures
{
public static class ResultCategoryExtensions
{

View File

@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
namespace MultiShop.SearchStructures
namespace MultiShop.DataStructures
{
public class ResultsProfile
{

View File

@ -1,7 +1,7 @@
using System.Collections.Generic;
using MultiShop.ShopFramework;
namespace MultiShop.SearchStructures
namespace MultiShop.DataStructures
{
public class SearchProfile
{

View File

@ -1,3 +1,3 @@
@page "/"
<h1>Welcome to MultiShop!</h1>
<h1>Welcome to MultiShop!</h1>

View File

@ -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;
});

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -1,5 +1,4 @@
@using ShopFramework
@using SearchStructures
@using DataStructures
<div class="table-responsive">
<table class="table table-top-borderless">

View File

@ -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");
});
}
}