diff --git a/JSMR.UI.Blazor/Components/SkeletonGrid.razor b/JSMR.UI.Blazor/Components/SkeletonGrid.razor new file mode 100644 index 0000000..f4de246 --- /dev/null +++ b/JSMR.UI.Blazor/Components/SkeletonGrid.razor @@ -0,0 +1,17 @@ +
+ @for (int i = 0; i < Count; i++) + { +
+ +
+ + +
+
+ } +
+ +@code { + [Parameter] + public int Count { get; set; } = 12; +} diff --git a/JSMR.UI.Blazor/Pages/VoiceWorks.razor b/JSMR.UI.Blazor/Pages/VoiceWorks.razor index 1bbb102..63d3c7d 100644 --- a/JSMR.UI.Blazor/Pages/VoiceWorks.razor +++ b/JSMR.UI.Blazor/Pages/VoiceWorks.razor @@ -15,7 +15,6 @@

Voice Works

- @if (searchResults is not null) @@ -28,7 +27,9 @@ } @code { + private bool _suppressNextLocation; private bool _isAlive = true; + //private bool IsLoading; private CancellationTokenSource _cts = new(); VoiceWorkFilterState FilterState = new(); @@ -44,21 +45,26 @@ private async void OnLocationChanged(object? sender, LocationChangedEventArgs e) { + if (_suppressNextLocation) + { + _suppressNextLocation = false; + return; + } + if (!_isAlive) return; if (!IsThisPage(e.Location)) return; - // Parse query from the new URL and update state if it actually changed. string query = NavigationManager.ToAbsoluteUri(e.Location).Query; VoiceWorkFilterState next = VoiceWorkFilterState.FromQuery(query); if (next != FilterState) { FilterState = next; - await RunSearchAsync(); await InvokeAsync(StateHasChanged); + RunSearchAsync(); } } @@ -74,7 +80,13 @@ if (next == FilterState) return; + FilterState = next; + + // Optional immediate paint if you want instant visual feedback on filters: + //await InvokeAsync(StateHasChanged); + UpdateUrl(next, false); + RunSearchAsync(); } void UpdateUrl(VoiceWorkFilterState next, bool replace) @@ -82,6 +94,8 @@ string basePath = new Uri(NavigationManager.Uri).GetLeftPart(UriPartial.Path); string uri = QueryHelpers.AddQueryString(basePath, next.ToQuery()); + _suppressNextLocation = true; + NavigationManager.NavigateTo(uri, replace: replace); } @@ -91,6 +105,9 @@ try { + //IsLoading = true; // show skeletons NOW + //StateHasChanged(); // paint immediately + _cts.Cancel(); _cts = new(); @@ -99,7 +116,15 @@ } catch (OperationCanceledException) { - + + } + finally + { + if (_isAlive) + { + //IsLoading = false; // hide skeletons + await InvokeAsync(StateHasChanged); + } } }