Merge pull request 'refactor: extract ViewModeToggle + query-param search' (#170) from feature/view-mode-toggle into develop

Reviewed-on: #170
This commit was merged in pull request #170.
This commit is contained in:
2026-08-20 15:10:36 +00:00
6 changed files with 36 additions and 81 deletions
+1 -1
View File
@@ -1 +1 @@
GIT_VERSION=v1.0.3.2-80-gfff78d7
GIT_VERSION=v1.0.3.2-91-g4bc35c0
@@ -44,16 +44,7 @@
</div>
</div>
<div class="album-detail-actions">
<div class="btn-group btn-group-sm">
<button class="btn @(viewMode == "masonry" ? "btn-primary" : "btn-secondary")"
@onclick="SetMasonry" title="Masonry">
<i class="bi bi-grid-3x2-gap"></i>
</button>
<button class="btn @(viewMode == "grid" ? "btn-primary" : "btn-secondary")"
@onclick="SetGrid" title="Grid">
<i class="bi bi-grid-3x3"></i>
</button>
</div>
<ViewModeToggle ViewMode="@viewMode" ViewModeChanged="@((string v) => viewMode = v)" />
@if (loginService.CanEdit(album?.Person)) {
@* Desktop: inline buttons *@
<div class="d-none d-md-flex gap-1 align-items-center">
@@ -252,9 +243,6 @@
string viewMode = "masonry";
bool _masonrySetup;
void SetMasonry() { viewMode = "masonry"; StateHasChanged(); }
void SetGrid() { viewMode = "grid"; StateHasChanged(); }
AlbumAssetPreviewDto? currentPreview => album?.AssetPreviews != null && selectedIndex >= 0 && selectedIndex < album.AssetPreviews.Count
? album.AssetPreviews[selectedIndex]
: null;
@@ -7,7 +7,6 @@
@inject AlbumService albumService
@inject LoginService loginService
@inject IJSRuntime jsRuntime
@inject NavigationManager navigationManager
<PageTitle>Albums</PageTitle>
@@ -102,16 +101,7 @@
</ul>
</div>
}
<div class="btn-group btn-group-sm">
<button class="btn @(viewMode == "masonry" ? "btn-primary" : "btn-secondary")"
@onclick="SetMasonry" title="Masonry">
<i class="bi bi-grid-3x2-gap"></i>
</button>
<button class="btn @(viewMode == "grid" ? "btn-primary" : "btn-secondary")"
@onclick="SetGrid" title="Grid">
<i class="bi bi-grid-3x3"></i>
</button>
</div>
<ViewModeToggle ViewMode="@viewMode" ViewModeChanged="@((string v) => viewMode = v)" />
@if (loginService.CanEditAll) {
<button class="btn btn-primary btn-sm d-none d-md-inline-block" @onclick="OpenCreateForm">
<i class="bi bi-plus-circle"></i> <span class="d-none d-sm-inline">New Album</span>
@@ -191,7 +181,7 @@
string? visibilityError;
HashSet<Guid> selectedAlbumIds = [];
bool albumsAllSelected => albumGridRef != null && selectedAlbumIds.Count == albumGridRef.GetCurrentAlbumIds().Count && selectedAlbumIds.Count > 0;
string? searchQuery;
[SupplyParameterFromQuery(Name = "search")] public string? searchQuery { get; set; }
string? sortBy;
bool sortAsc;
int loadVersion;
@@ -206,31 +196,11 @@
};
protected override async Task OnInitializedAsync() {
ParseSearchQuery();
await jsRuntime.InvokeVoidAsync("masonryObserver.unlockBodyScroll");
_loggedUserChangedHandler = (_, _) => StateHasChanged();
loginService.LoggedUserChanged += _loggedUserChangedHandler;
}
protected override void OnParametersSet() {
ParseSearchQuery();
}
void ParseSearchQuery() {
var uri = navigationManager.Uri;
var qIdx = uri.IndexOf('?');
if (qIdx < 0) return;
foreach (var part in uri[(qIdx + 1)..].Split('&'))
{
var kv = part.Split('=', 2);
if (kv.Length == 2 && kv[0] == "search")
searchQuery = Uri.UnescapeDataString(kv[1].Replace("+", " "));
}
}
void SetMasonry() => viewMode = "masonry";
void SetGrid() => viewMode = "grid";
void ToggleAlbumSelection((Guid Id, bool Shift) args) {
_albumSelectionRange.Toggle(selectedAlbumIds, albumGridRef?.GetCurrentAlbumIds() ?? [], args.Id, args.Shift);
}
@@ -100,16 +100,7 @@
SortOptions="@albumSortOptions">
<ActionButtons>
@if (person.TotalAlbums > 0) {
<div class="btn-group btn-group-sm d-none d-md-inline-flex">
<button class="btn @(viewMode == "masonry" ? "btn-primary" : "btn-secondary")"
@onclick="SetMasonry" title="Masonry">
<i class="bi bi-grid-3x2-gap"></i>
</button>
<button class="btn @(viewMode == "grid" ? "btn-primary" : "btn-secondary")"
@onclick="SetGrid" title="Grid">
<i class="bi bi-grid-3x3"></i>
</button>
</div>
<ViewModeToggle ViewMode="@viewMode" ViewModeChanged="@((string v) => viewMode = v)" Class="d-none d-md-inline-flex" />
}
@if (loginService.CanEdit(Id)) {
@* Desktop: inline buttons *@
@@ -379,9 +370,6 @@
await LoadPerson();
}
void SetMasonry() => viewMode = "masonry";
void SetGrid() => viewMode = "grid";
void CloseForm() => showForm = false;
async Task OpenAlbumAssigner() {
@@ -400,7 +388,7 @@
else assignAlbumIds.Remove(id);
}
bool albumsAllSelected => person?.Albums != null && person.Albums.Count > 0 && selectedAlbumIds.Count == person.Albums.Count;
bool albumsAllSelected => personAlbumGridRef != null && selectedAlbumIds.Count == personAlbumGridRef.GetCurrentAlbumIds().Count && selectedAlbumIds.Count > 0;
void CancelSelectMode() {
selectMode = false;
@@ -427,15 +415,16 @@
}
void ToggleSelectAllAlbums() {
if (person?.Albums == null) return;
if (personAlbumGridRef == null) return;
var allIds = personAlbumGridRef.GetCurrentAlbumIds();
if (albumsAllSelected)
selectedAlbumIds.Clear();
else
selectedAlbumIds.UnionWith(person.Albums.Select(a => a.Id));
selectedAlbumIds.UnionWith(allIds);
}
void ToggleSelectAlbum((Guid Id, bool Shift) args) {
var ordered = person?.Albums?.Select(a => a.Id).ToList() ?? [];
var ordered = personAlbumGridRef?.GetCurrentAlbumIds() ?? [];
_albumSelectionRange.Toggle(selectedAlbumIds, ordered, args.Id, args.Shift);
}
@@ -6,7 +6,6 @@
@inject PersonService personService
@inject LoginService loginService
@inject NavigationManager navigationManager
<PageTitle>Cosplayers</PageTitle>
@@ -162,7 +161,7 @@
EVisibility selectedVisibility = EVisibility.Public;
string? visibilityError;
HashSet<Guid> selectedCosplayerIds = [];
string? searchQuery;
[SupplyParameterFromQuery(Name = "search")] public string? searchQuery { get; set; }
string? sortBy;
bool sortAsc = true;
int loadVersion;
@@ -177,22 +176,6 @@
loginService.LoggedUserChanged += OnLoggedUserChanged;
}
protected override void OnParametersSet() {
ParseSearchQuery();
}
void ParseSearchQuery() {
var uri = navigationManager.Uri;
var qIdx = uri.IndexOf('?');
if (qIdx < 0) return;
foreach (var part in uri[(qIdx + 1)..].Split('&'))
{
var kv = part.Split('=', 2);
if (kv.Length == 2 && kv[0] == "search")
searchQuery = Uri.UnescapeDataString(kv[1].Replace("+", " "));
}
}
void OnLoggedUserChanged(object? _, UserInfoDto? _2) => StateHasChanged();
void ToggleCosplayerSelection((Guid Id, bool Shift) args) {
@@ -0,0 +1,25 @@
@* Toggle between masonry and grid view modes. *@
<div class="btn-group btn-group-sm @Class">
<button class="btn @(ViewMode == "masonry" ? "btn-primary" : "btn-secondary")"
@onclick="SetMasonry" title="Masonry">
<i class="bi bi-grid-3x2-gap"></i>
</button>
<button class="btn @(ViewMode == "grid" ? "btn-primary" : "btn-secondary")"
@onclick="SetGrid" title="Grid">
<i class="bi bi-grid-3x3"></i>
</button>
</div>
@code {
[Parameter] public string ViewMode { get; set; } = "masonry";
[Parameter] public EventCallback<string> ViewModeChanged { get; set; }
[Parameter] public string? Class { get; set; }
async Task SetMasonry() => await SetMode("masonry");
async Task SetGrid() => await SetMode("grid");
async Task SetMode(string mode) {
ViewMode = mode;
await ViewModeChanged.InvokeAsync(mode);
}
}