Minor search provider enhancement. Minor UI updates.
All checks were successful
ci / build-test (push) Successful in 3m19s
ci / publish-image (push) Has been skipped

This commit is contained in:
2025-11-23 17:14:22 -05:00
parent 8490b49354
commit 1f533c6ec1
8 changed files with 204 additions and 55 deletions

View File

@@ -89,13 +89,13 @@ public abstract class SearchProvider<TItem, TCriteria, TSortField, TBaseQuery> :
.Take(options.PageSize) .Take(options.PageSize)
.ToArrayAsync(cancellationToken); .ToArrayAsync(cancellationToken);
Dictionary<int, TItem> items = await GetItems(ids); Dictionary<int, TItem> items = await GetItems(options.Criteria, ids);
return [.. ids.Select(uniqueId => items[uniqueId])]; return [.. ids.Select(uniqueId => items[uniqueId])];
} }
else else
{ {
IQueryable<TItem> selectQuery = GetSelectQuery(orderedQuery); IQueryable<TItem> selectQuery = GetSelectQuery(options.Criteria, orderedQuery);
return await selectQuery return await selectQuery
.Skip((options.PageNumber - 1) * options.PageSize) .Skip((options.PageNumber - 1) * options.PageSize)
@@ -107,7 +107,7 @@ public abstract class SearchProvider<TItem, TCriteria, TSortField, TBaseQuery> :
protected abstract Expression<Func<TBaseQuery, object?>> GetSortExpression(TSortField field); protected abstract Expression<Func<TBaseQuery, object?>> GetSortExpression(TSortField field);
protected abstract IEnumerable<(Expression<Func<TBaseQuery, object>> Selector, SortDirection Dir)> GetDefaultSortChain(); protected abstract IEnumerable<(Expression<Func<TBaseQuery, object>> Selector, SortDirection Dir)> GetDefaultSortChain();
protected abstract IQueryable<int> GetSelectIdQuery(IOrderedQueryable<TBaseQuery> query); protected abstract IQueryable<int> GetSelectIdQuery(IOrderedQueryable<TBaseQuery> query);
protected abstract IQueryable<TItem> GetSelectQuery(IOrderedQueryable<TBaseQuery> query); protected abstract IQueryable<TItem> GetSelectQuery(TCriteria criteria, IOrderedQueryable<TBaseQuery> query);
protected abstract Task<Dictionary<int, TItem>> GetItems(int[] ids); protected abstract Task<Dictionary<int, TItem>> GetItems(TCriteria criteria, int[] ids);
protected virtual Task PostLoadAsync(IList<TItem> items, CancellationToken cancellationToken) => Task.CompletedTask; protected virtual Task PostLoadAsync(IList<TItem> items, CancellationToken cancellationToken) => Task.CompletedTask;
} }

View File

@@ -141,7 +141,7 @@ public class CircleSearchProvider(AppDbContext context) : SearchProvider<CircleS
return query.Select(x => x.Circle.CircleId); return query.Select(x => x.Circle.CircleId);
} }
protected override IQueryable<CircleSearchItem> GetSelectQuery(IOrderedQueryable<CircleQuery> query) protected override IQueryable<CircleSearchItem> GetSelectQuery(CircleSearchCriteria criteria, IOrderedQueryable<CircleQuery> query)
{ {
// Join to VoiceWorks by LatestProductId to fill HasImage / SalesDate // Join to VoiceWorks by LatestProductId to fill HasImage / SalesDate
var selected = var selected =
@@ -213,7 +213,7 @@ public class CircleSearchProvider(AppDbContext context) : SearchProvider<CircleS
return selected; return selected;
} }
protected override async Task<Dictionary<int, CircleSearchItem>> GetItems(int[] ids) protected override async Task<Dictionary<int, CircleSearchItem>> GetItems(CircleSearchCriteria criteria, int[] ids)
{ {
// Join to VoiceWorks by LatestProductId to fill HasImage / SalesDate // Join to VoiceWorks by LatestProductId to fill HasImage / SalesDate
var selected = var selected =

View File

@@ -57,7 +57,7 @@ public class CreatorSearchProvider(AppDbContext context) : SearchProvider<Creato
yield return (x => x.Name, SortDirection.Ascending); yield return (x => x.Name, SortDirection.Ascending);
} }
protected override IOrderedQueryable<CreatorSearchItem> GetSelectQuery(IOrderedQueryable<CreatorSearchItem> query) protected override IOrderedQueryable<CreatorSearchItem> GetSelectQuery(CreatorSearchCriteria criteria, IOrderedQueryable<CreatorSearchItem> query)
{ {
return query; return query;
} }
@@ -67,7 +67,7 @@ public class CreatorSearchProvider(AppDbContext context) : SearchProvider<Creato
throw new NotImplementedException(); throw new NotImplementedException();
} }
protected override Task<Dictionary<int, CreatorSearchItem>> GetItems(int[] ids) protected override Task<Dictionary<int, CreatorSearchItem>> GetItems(CreatorSearchCriteria criteria, int[] ids)
{ {
return Task.FromResult(new Dictionary<int, CreatorSearchItem>()); return Task.FromResult(new Dictionary<int, CreatorSearchItem>());
} }

View File

@@ -62,7 +62,7 @@ public class TagSearchProvider(AppDbContext context) : SearchProvider<TagSearchI
yield return (x => x.Name, SortDirection.Ascending); yield return (x => x.Name, SortDirection.Ascending);
} }
protected override IOrderedQueryable<TagSearchItem> GetSelectQuery(IOrderedQueryable<TagSearchItem> query) protected override IOrderedQueryable<TagSearchItem> GetSelectQuery(TagSearchCriteria criteria, IOrderedQueryable<TagSearchItem> query)
{ {
return query; return query;
} }
@@ -72,7 +72,7 @@ public class TagSearchProvider(AppDbContext context) : SearchProvider<TagSearchI
throw new NotImplementedException(); throw new NotImplementedException();
} }
protected override Task<Dictionary<int, TagSearchItem>> GetItems(int[] ids) protected override Task<Dictionary<int, TagSearchItem>> GetItems(TagSearchCriteria criteria, int[] ids)
{ {
return Task.FromResult(new Dictionary<int, TagSearchItem>()); return Task.FromResult(new Dictionary<int, TagSearchItem>());
} }

View File

@@ -1,4 +1,5 @@
using JSMR.Application.Common.Search; using JSMR.Application.Common.Search;
using JSMR.Application.Enums;
using JSMR.Application.VoiceWorks.Queries.Search; using JSMR.Application.VoiceWorks.Queries.Search;
using JSMR.Domain.Entities; using JSMR.Domain.Entities;
using JSMR.Domain.Enums; using JSMR.Domain.Enums;
@@ -355,7 +356,7 @@ public class VoiceWorkSearchProvider(AppDbContext context, IVoiceWorkFullTextSea
return query.Select(x => x.VoiceWork.VoiceWorkId); return query.Select(x => x.VoiceWork.VoiceWorkId);
} }
protected override IQueryable<VoiceWorkSearchResult> GetSelectQuery(IOrderedQueryable<VoiceWorkQuery> query) protected override IQueryable<VoiceWorkSearchResult> GetSelectQuery(VoiceWorkSearchCriteria criteria, IOrderedQueryable<VoiceWorkQuery> query)
{ {
var result = var result =
from q in query from q in query
@@ -368,9 +369,9 @@ public class VoiceWorkSearchProvider(AppDbContext context, IVoiceWorkFullTextSea
VoiceWorkId = voiceWork.VoiceWorkId, VoiceWorkId = voiceWork.VoiceWorkId,
ProductId = voiceWork.ProductId, ProductId = voiceWork.ProductId,
OriginalProductId = voiceWork.OriginalProductId, OriginalProductId = voiceWork.OriginalProductId,
ProductName = englishVoiceWork != null ? englishVoiceWork.ProductName : voiceWork.ProductName, ProductName = criteria.Locale == Locale.English && englishVoiceWork != null ? englishVoiceWork.ProductName : voiceWork.ProductName,
ProductUrl = "http://www.dlsite.com/maniax/" + productLinkPage + "/=/product_id/" + voiceWork.ProductId + ".html", ProductUrl = "http://www.dlsite.com/maniax/" + productLinkPage + "/=/product_id/" + voiceWork.ProductId + ".html",
Description = englishVoiceWork != null ? englishVoiceWork.Description : voiceWork.Description, Description = criteria.Locale == Locale.English && englishVoiceWork != null ? englishVoiceWork.Description : voiceWork.Description,
Favorite = voiceWork.Favorite, Favorite = voiceWork.Favorite,
HasImage = voiceWork.HasImage, HasImage = voiceWork.HasImage,
Maker = circle.Name, Maker = circle.Name,
@@ -390,7 +391,7 @@ public class VoiceWorkSearchProvider(AppDbContext context, IVoiceWorkFullTextSea
return result; return result;
} }
protected override async Task<Dictionary<int, VoiceWorkSearchResult>> GetItems(int[] ids) protected override async Task<Dictionary<int, VoiceWorkSearchResult>> GetItems(VoiceWorkSearchCriteria criteria, int[] ids)
{ {
var result = var result =
from voiceWork in context.VoiceWorks.AsNoTracking() from voiceWork in context.VoiceWorks.AsNoTracking()
@@ -405,9 +406,9 @@ public class VoiceWorkSearchProvider(AppDbContext context, IVoiceWorkFullTextSea
VoiceWorkId = voiceWork.VoiceWorkId, VoiceWorkId = voiceWork.VoiceWorkId,
ProductId = voiceWork.ProductId, ProductId = voiceWork.ProductId,
OriginalProductId = voiceWork.OriginalProductId, OriginalProductId = voiceWork.OriginalProductId,
ProductName = englishVoiceWork != null ? englishVoiceWork.ProductName : voiceWork.ProductName, ProductName = criteria.Locale == Locale.English && englishVoiceWork != null ? englishVoiceWork.ProductName : voiceWork.ProductName,
ProductUrl = "http://www.dlsite.com/maniax/" + productLinkPage + "/=/product_id/" + voiceWork.ProductId + ".html", ProductUrl = "http://www.dlsite.com/maniax/" + productLinkPage + "/=/product_id/" + voiceWork.ProductId + ".html",
Description = englishVoiceWork != null ? englishVoiceWork.Description : voiceWork.Description, Description = criteria.Locale == Locale.English && englishVoiceWork != null ? englishVoiceWork.Description : voiceWork.Description,
Favorite = voiceWork.Favorite, Favorite = voiceWork.Favorite,
HasImage = voiceWork.HasImage, HasImage = voiceWork.HasImage,
Maker = circle.Name, Maker = circle.Name,

View File

@@ -1,5 +1,8 @@
@page "/voiceworks" @page "/voiceworks"
@using JSMR.Application.Common.Search @using JSMR.Application.Common.Search
@using JSMR.Application.Creators.Queries.Search
@using JSMR.Application.Enums
@using JSMR.Application.Tags.Queries.Search
@using JSMR.Application.VoiceWorks.Queries.Search @using JSMR.Application.VoiceWorks.Queries.Search
@using JSMR.Domain.Enums @using JSMR.Domain.Enums
@using JSMR.Domain.ValueObjects @using JSMR.Domain.ValueObjects
@@ -13,16 +16,35 @@
<h3>Voice Works</h3> <h3>Voice Works</h3>
<div class="search-filter-control-container"> <div class="search-filter-control-container">
<div class="search-filter-control-span-4"> @* <div class="search-filter-control-span-4">
<JTextBox Label="Keywords" Value="@Keywords" ValueChanged="OnKeywordsChanged" Immediate="true" DebounceInterval="1500" /> <JTextBox Label="Keywords" Value="@Keywords" ValueChanged="OnKeywordsChanged" Immediate="true" DebounceInterval="1500" />
</div> *@
<div class="search-filter-control-span-2">
<BitTextField Prefix="Keywords" Value="@Keywords" ValueChanged="OnKeywordsChanged" Immediate="true" DebounceTime="500" />
</div> </div>
<div class="search-filter-control-span-4"> <div class="search-filter-control-span-1">
<BitTextField Label="Keywords" Value="@Keywords" ValueChanged="OnKeywordsChanged" Immediate="true" DebounceTime="500" /> <BitDropdown Prefix="Languages"
MultiSelect
Items="Languages"
Placeholder="Select..."
TItem="BitDropdownItem<Language>"
TValue="Language"
Values="SupportedLanguages"
ValuesChanged="OnSupportedLanguagesChanged" />
</div>
<div class="search-filter-control-span-1">
<BitDropdown Prefix="Locale"
Items="Locales"
Placeholder="Select..."
TItem="BitDropdownItem<Locale>"
TValue="Locale"
Value="Locale"
ValueChanged="OnLocaleChanged" />
</div> </div>
<!-- Row 2 --> <!-- Row 2 -->
<div class="search-filter-control-span-1"> <div class="search-filter-control-span-1">
<BitDropdown Label="Sale Status" <BitDropdown Prefix="Sale Status"
Items="BasicItems" Items="SaleStatuses"
Placeholder="Select..." Placeholder="Select..."
TItem="BitDropdownItem<SaleStatus?>" TItem="BitDropdownItem<SaleStatus?>"
TValue="SaleStatus?" TValue="SaleStatus?"
@@ -30,7 +52,7 @@
ValueChanged="OnSaleStatusChanged" /> ValueChanged="OnSaleStatusChanged" />
</div> </div>
<div class="search-filter-control-span-1"> <div class="search-filter-control-span-1">
<BitDropdown Label="Circle Status" <BitDropdown Prefix="Circles"
Items="CircleStatuses" Items="CircleStatuses"
Placeholder="Select..." Placeholder="Select..."
TItem="BitDropdownItem<CircleStatus?>" TItem="BitDropdownItem<CircleStatus?>"
@@ -39,7 +61,7 @@
ValueChanged="OnCircleStatusChanged" /> ValueChanged="OnCircleStatusChanged" />
</div> </div>
<div class="search-filter-control-span-1"> <div class="search-filter-control-span-1">
<BitDropdown Label="Tag Status" <BitDropdown Prefix="Tags"
Items="TagStatuses" Items="TagStatuses"
Placeholder="Select..." Placeholder="Select..."
TItem="BitDropdownItem<TagStatus?>" TItem="BitDropdownItem<TagStatus?>"
@@ -48,7 +70,7 @@
ValueChanged="OnTagStatusChanged" /> ValueChanged="OnTagStatusChanged" />
</div> </div>
<div class="search-filter-control-span-1"> <div class="search-filter-control-span-1">
<BitDropdown Label="Creator Status" <BitDropdown Prefix="Creators"
Items="CreatorStatuses" Items="CreatorStatuses"
Placeholder="Select..." Placeholder="Select..."
TItem="BitDropdownItem<CreatorStatus?>" TItem="BitDropdownItem<CreatorStatus?>"
@@ -58,30 +80,40 @@
</div> </div>
<!-- Row 3 --> <!-- Row 3 -->
<div class="search-filter-control-span-2"> <div class="search-filter-control-span-2">
<BitDropdown Label="Creator Status 2" <BitDropdown Prefix="Tags"
Items="CreatorStatuses" Items="Tags"
MultiSelect
Virtualize
ShowSearchBox
AutoFocusSearchBox
Chips
Placeholder="Select..." Placeholder="Select..."
TItem="BitDropdownItem<CreatorStatus?>" TItem="BitDropdownItem<int>"
TValue="CreatorStatus ?" TValue="int"
Value="SelectedCreatorStatus" Values="SelectedTagIds"
ValueChanged="OnCreatorStatusChanged" /> ValuesChanged="OnTagIdsChanged" />
</div> </div>
<div class="search-filter-control-span-1"> <div class="search-filter-control-span-1">
<BitCheckbox Label="Show Only Favorite Works" Value="ShowOnlyFavoriteWorks" ValueChanged="OnShowOnlyFavoriteWorksChanged" /> <BitCheckbox Label="Include All Tags" Value="IncludeAllTags" ValueChanged="OnIncludeAllTagsChanged" />
</div> </div>
<div class="search-filter-control-span-1"></div> <div class="search-filter-control-span-1"></div>
<!-- Row 4 --> <!-- Row 4 -->
<div class="search-filter-control-span-2"> <div class="search-filter-control-span-2">
<BitDropdown Label="Creator Status 2" <BitDropdown Prefix="Creators"
Items="CreatorStatuses" Items="Creators"
MultiSelect
Virtualize
ShowSearchBox
AutoFocusSearchBox
Chips
Placeholder="Select..." Placeholder="Select..."
TItem="BitDropdownItem<CreatorStatus?>" TItem="BitDropdownItem<int>"
TValue="CreatorStatus ?" TValue="int"
Value="SelectedCreatorStatus" Values="SelectedCreatorIds"
ValueChanged="OnCreatorStatusChanged" /> ValuesChanged="OnCreatorIdsChanged" />
</div> </div>
<div class="search-filter-control-span-1"> <div class="search-filter-control-span-1">
<BitCheckbox Label="Show Only Favorite Works" Value="ShowOnlyFavoriteWorks" ValueChanged="OnShowOnlyFavoriteWorksChanged" /> <BitCheckbox Label="Include All Creators" Value="IncludeAllCreators" ValueChanged="OnIncludeAllCreatorsChanged" />
</div> </div>
<div class="search-filter-control-span-1"></div> <div class="search-filter-control-span-1"></div>
<!-- Row 5 --> <!-- Row 5 -->
@@ -92,16 +124,6 @@
<BitCheckbox Label="Show Only Invalid Works" Value="ShowOnlyInvalidWorks" ValueChanged="OnShowOnlyInvalidWorksChanged" /> <BitCheckbox Label="Show Only Invalid Works" Value="ShowOnlyInvalidWorks" ValueChanged="OnShowOnlyInvalidWorksChanged" />
</div> </div>
<div class="search-filter-control-span-2"></div> <div class="search-filter-control-span-2"></div>
<div class="search-filter-control-span-1">
<BitDropdown Label="Supported Languages"
MultiSelect
Items="Languages"
Placeholder="Select..."
TItem="BitDropdownItem<Language>"
TValue="Language"
Values="SupportedLanguages"
ValuesChanged="OnSupportedLanguagesChanged" />
</div>
<div class="search-filter-control-span-1"> <div class="search-filter-control-span-1">
<BitDropdown Label="Age Ratings" <BitDropdown Label="Age Ratings"
MultiSelect MultiSelect
@@ -118,6 +140,9 @@
<div class="search-filter-control-span-1"> <div class="search-filter-control-span-1">
<BitDatePicker Label="Release Date End" ShowClearButton="true" Value="ReleaseDateEnd" ValueChanged="OnReleaseDateEndChanged" /> <BitDatePicker Label="Release Date End" ShowClearButton="true" Value="ReleaseDateEnd" ValueChanged="OnReleaseDateEndChanged" />
</div> </div>
@* <div class="search-filter-control-span-1">
<BitSlider Label="Downloads" Min="0" Max="100000" Value="MinDownloads" ValueChanged="OnMinDownloadsChanged" />
</div> *@
</div> </div>
<JProductCollection Products="searchResults?.Items"></JProductCollection> <JProductCollection Products="searchResults?.Items"></JProductCollection>
@@ -129,27 +154,32 @@
@code { @code {
public string? Keywords { get; set; } public string? Keywords { get; set; }
public Locale Locale { get; set; } = Locale.English;
public SaleStatus? SelectedSaleStatus { get; set; } public SaleStatus? SelectedSaleStatus { get; set; }
public CircleStatus? SelectedCircleStatus { get; set; } public CircleStatus? SelectedCircleStatus { get; set; }
public TagStatus? SelectedTagStatus { get; set; } public TagStatus? SelectedTagStatus { get; set; }
public CreatorStatus? SelectedCreatorStatus { get; set; } public CreatorStatus? SelectedCreatorStatus { get; set; }
public int[] SelectedTagIds { get; set; } = [];
public bool IncludeAllTags { get; set; }
public int[] SelectedCreatorIds { get; set; } = [];
public bool IncludeAllCreators { get; set; }
public bool ShowOnlyFavoriteWorks { get; set; } public bool ShowOnlyFavoriteWorks { get; set; }
public bool ShowOnlyInvalidWorks { get; set; } public bool ShowOnlyInvalidWorks { get; set; }
public IEnumerable<Language> SupportedLanguages { get; set; } = []; public IEnumerable<Language> SupportedLanguages { get; set; } = [];
public IEnumerable<AgeRating> SelectedAgeRatings { get; set; } = []; public IEnumerable<AgeRating> SelectedAgeRatings { get; set; } = [];
public DateTimeOffset? ReleaseDateStart { get; set; } public DateTimeOffset? ReleaseDateStart { get; set; }
public DateTimeOffset? ReleaseDateEnd { get; set; } public DateTimeOffset? ReleaseDateEnd { get; set; }
public int MinDownloads { get; set; }
public int PageNumber { get; set; } = 1; public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 100; public int PageSize { get; set; } = 100;
IEnumerable<Tuple<SaleStatus?, string>> SaleStatuses = List<BitDropdownItem<Locale>> Locales =
[ [
new(SaleStatus.Available, "Available"), new() { Text = "Japanese", Value = Locale.Japanese },
new(SaleStatus.Upcoming, "Upcoming"), new() { Text = "English", Value = Locale.English }
new(null, "All")
]; ];
List<BitDropdownItem<SaleStatus?>> BasicItems = List<BitDropdownItem<SaleStatus?>> SaleStatuses =
[ [
new() { Text = "Available", Value = SaleStatus.Available }, new() { Text = "Available", Value = SaleStatus.Available },
new() { Text = "Upcoming", Value = SaleStatus.Upcoming }, new() { Text = "Upcoming", Value = SaleStatus.Upcoming },
@@ -198,11 +228,55 @@
new() { Text = "R18", Value = AgeRating.R18 } new() { Text = "R18", Value = AgeRating.R18 }
]; ];
List<BitDropdownItem<int>> Tags = [];
List<BitDropdownItem<int>> Creators = [];
SearchResult<VoiceWorkSearchResult>? searchResults; SearchResult<VoiceWorkSearchResult>? searchResults;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
await UpdateDataAsync(true); await UpdateDataAsync(true);
await GetTags();
await GetCreators();
}
private async Task GetTags()
{
SearchTagsRequest request = new(
Options: new()
{
PageNumber = 1,
PageSize = 99999
}
);
SearchTagsResponse? response = await Client.SearchAsync(request);
if (response is null)
return;
Tags = response.Results.Items
.OrderByDescending(x => x.Favorite)
.ThenBy(x => x.EnglishName ?? x.Name)
.Select(x => new BitDropdownItem<int>() { Text = x.EnglishName ?? x.Name, Value = x.TagId }).ToList();
}
private async Task GetCreators()
{
SearchCreatorsRequest request = new(
Options: new()
{
PageNumber = 1,
PageSize = 99999
}
);
SearchCreatorsResponse? response = await Client.SearchAsync(request);
if (response is null)
return;
Creators = response.Results.Items.Select(x => new BitDropdownItem<int>() { Text = x.Name, Value = x.CreatorId }).ToList();
} }
private async Task UpdateDataAsync(bool resetPageNumber) private async Task UpdateDataAsync(bool resetPageNumber)
@@ -218,16 +292,22 @@
Criteria = new() Criteria = new()
{ {
Keywords = Keywords, Keywords = Keywords,
Locale = Locale,
SaleStatus = SelectedSaleStatus, SaleStatus = SelectedSaleStatus,
CircleStatus = SelectedCircleStatus, CircleStatus = SelectedCircleStatus,
TagStatus = SelectedTagStatus, TagStatus = SelectedTagStatus,
CreatorStatus = SelectedCreatorStatus, CreatorStatus = SelectedCreatorStatus,
TagIds = [.. SelectedTagIds],
IncludeAllTags = IncludeAllTags,
CreatorIds = [.. SelectedCreatorIds],
IncludeAllCreators = IncludeAllCreators,
ShowFavoriteVoiceWorks = ShowOnlyFavoriteWorks, ShowFavoriteVoiceWorks = ShowOnlyFavoriteWorks,
ShowInvalidVoiceWorks = ShowOnlyInvalidWorks, ShowInvalidVoiceWorks = ShowOnlyInvalidWorks,
SupportedLanguages = [.. SupportedLanguages], SupportedLanguages = [.. SupportedLanguages],
AgeRatings = [.. SelectedAgeRatings], AgeRatings = [.. SelectedAgeRatings],
ReleaseDateStart = ReleaseDateStart != null ? DateOnly.FromDateTime(ReleaseDateStart.Value.Date) : null, ReleaseDateStart = ReleaseDateStart != null ? DateOnly.FromDateTime(ReleaseDateStart.Value.Date) : null,
ReleaseDateEnd = ReleaseDateEnd != null ? DateOnly.FromDateTime(ReleaseDateEnd.Value.Date) : null ReleaseDateEnd = ReleaseDateEnd != null ? DateOnly.FromDateTime(ReleaseDateEnd.Value.Date) : null,
//MinDownloads = MinDownloads
}, },
SortOptions = SortOptions =
[ [
@@ -249,6 +329,12 @@
await UpdateDataAsync(true); await UpdateDataAsync(true);
} }
public async Task OnLocaleChanged(Locale locale)
{
Locale = locale;
await UpdateDataAsync(true);
}
public async Task OnSaleStatusChanged(SaleStatus? saleStatus) public async Task OnSaleStatusChanged(SaleStatus? saleStatus)
{ {
SelectedSaleStatus = saleStatus; SelectedSaleStatus = saleStatus;
@@ -273,6 +359,30 @@
await UpdateDataAsync(true); await UpdateDataAsync(true);
} }
public async Task OnTagIdsChanged(IEnumerable<int> tagIds)
{
SelectedTagIds = [..tagIds];
await UpdateDataAsync(true);
}
public async Task OnIncludeAllTagsChanged(bool includeAllTags)
{
IncludeAllTags = includeAllTags;
await UpdateDataAsync(true);
}
public async Task OnCreatorIdsChanged(IEnumerable<int> creatorIds)
{
SelectedCreatorIds = [..creatorIds];
await UpdateDataAsync(true);
}
public async Task OnIncludeAllCreatorsChanged(bool includeAllCreators)
{
IncludeAllCreators = includeAllCreators;
await UpdateDataAsync(true);
}
public async Task OnSupportedLanguagesChanged(IEnumerable<Language> languages) public async Task OnSupportedLanguagesChanged(IEnumerable<Language> languages)
{ {
SupportedLanguages = languages; SupportedLanguages = languages;
@@ -309,6 +419,12 @@
await UpdateDataAsync(true); await UpdateDataAsync(true);
} }
public async Task OnMinDownloadsChanged(double minDownloads)
{
MinDownloads = (int)minDownloads;
await UpdateDataAsync(true);
}
public async Task OnPageNumberChanged(int newPageNumber) public async Task OnPageNumberChanged(int newPageNumber)
{ {
PageNumber = newPageNumber; PageNumber = newPageNumber;

View File

@@ -132,6 +132,11 @@ code {
align-items: center; align-items: center;
} }
.search-filter-control-container > .search-filter-control-span-1 {
display: flex;
align-items: center;
}
.search-filter-control-container > .search-filter-control-span-2 { .search-filter-control-container > .search-filter-control-span-2 {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -4,7 +4,7 @@
border: 1px solid var(--input-border-color); border: 1px solid var(--input-border-color);
background-color: var(--input-background-color); background-color: var(--input-background-color);
transition: background-color .2s,color .2s,border-color .2s,box-shadow .2s; transition: background-color .2s,color .2s,border-color .2s,box-shadow .2s;
padding: .25rem .5rem; /*padding: .25rem .5rem;*/
} }
.bit-tfl-fgp { .bit-tfl-fgp {
@@ -25,6 +25,14 @@
} }
/* DropDownList */ /* DropDownList */
.bit-drp {
font-family: var(--font-family);
}
.bit-drp-lbl {
font-weight: 500;
}
.bit-drp-cal { .bit-drp-cal {
background-color: var(--input-background-color); background-color: var(--input-background-color);
} }
@@ -39,3 +47,22 @@
color: #ffffffde; color: #ffffffde;
background: rgba(100,181,246,.16); background: rgba(100,181,246,.16);
} }
.bit-drp-scn {
max-height: 200px !important;
padding: .5rem 0;
}
.bit-drp-itm,
.bit-drp-mcn {
justify-content: flex-start; /* To get around Mud Blazor, until Mud Blazor is removed */
padding: .5rem 1rem;
}
.bit-drp-sch .bit-drp-tcn {
padding: 0;
}
.bit-drp-pre, .bit-drp-suf {
background: rgb(57, 79, 94);
}