summaryrefslogtreecommitdiff
path: root/Pages/Gallery.razor
diff options
context:
space:
mode:
authorJake Mannens <jake@asger.xyz>2026-03-17 03:04:36 +1100
committerJake Mannens <jake@asger.xyz>2026-06-07 12:32:37 +1000
commitc51ff4e755f009ca0bc8e935a92c04e583c4ee8a (patch)
tree0a9a311c5404a96495df1047e613dc3aea3d0f15 /Pages/Gallery.razor
Initial commit
Diffstat (limited to 'Pages/Gallery.razor')
-rw-r--r--Pages/Gallery.razor141
1 files changed, 141 insertions, 0 deletions
diff --git a/Pages/Gallery.razor b/Pages/Gallery.razor
new file mode 100644
index 0000000..743485e
--- /dev/null
+++ b/Pages/Gallery.razor
@@ -0,0 +1,141 @@
+@page "/"
+@page "/Gallery"
+@inject ITagService tagService
+@inject IFeedService feedService
+@inject IUserService userService
+@inject IJSRuntime jsRuntime
+@implements IDisposable
+@attribute [Authorize]
+
+<PageTitle>@Title</PageTitle>
+
+@if(Ingest && !userService.UserSessionState.ShowNsfw) {
+ <div id="feed-error">
+ <p><center>Ingest feed is not available unless NSFW mode is enabled!</center></p>
+ <p><center><i>You must enable NSFW mode to continue...</i></center></p>
+ </div>
+} else if(TagId is not null && Query is not null) {
+ <div id="feed-error">
+ <p><center>Invalid query parameters! Both a search query and</center></p>
+ <p><center>a tag ID have been specified!</center></p>
+ </div>
+} else {
+ <div style="padding:var(--size-default-gap);">
+ @foreach(var media in displayMedia) {
+ // Precalculate thumbnail size to help the browser
+ // lay out the images during initial page load
+ int width = (int) media.CurrentUploadedFile!.Width! * 200 / (int) media.CurrentUploadedFile.Height!;
+ <a href="/ViewMedia?m=@(media.Guid)">
+ <img src="/media/thumb/@(media.Guid)?h=200" width=@width height="200"/>
+ </a>
+ }
+ <div id="canary" style="height:1px;"></div>
+ </div>
+}
+
+<script suppress-error="BL9992">
+ function registerScrollObserver(dotNetObject) {
+ var scrollObserver = new IntersectionObserver(
+ async (e) => {
+ if(e[0].isIntersecting) {
+ await dotNetObject.invokeMethodAsync('LoadMedia', false);
+ }
+ },
+ {
+ root: document.getElementById('content'),
+ threshold: 0
+ });
+ scrollObserver.observe(document.getElementById("canary"));
+ }
+</script>
+
+@code {
+ [Parameter]
+ [SupplyParameterFromQuery(Name = "t")]
+ public Guid? TagId { get; set; }
+
+ [Parameter]
+ [SupplyParameterFromQuery(Name = "q")]
+ public string? Query { get; set; }
+
+ [Parameter]
+ [SupplyParameterFromQuery(Name = "s")]
+ public string? SortOrder { get; set; }
+
+ [Parameter]
+ [SupplyParameterFromQuery]
+ public bool Ingest { get; set; } = false;
+
+ public const int PageSize = 50;
+
+ private string Title {
+ get {
+ if(Query is null)
+ return Ingest ? "Ingest Feed" : "Gallery";
+ else
+ return "Search Results";
+ }
+ }
+
+ private List<Media> displayMedia;
+
+ protected override void OnInitialized() =>
+ userService.UserSessionState.OnStateChange += ShowNsfwChanged;
+
+ protected override void OnParametersSet() => LoadMedia(true);
+
+ protected override void OnAfterRender(bool firstRender) {
+ if(firstRender)
+ jsRuntime.InvokeVoidAsync(
+ "registerScrollObserver",
+ DotNetObjectReference.Create(this));
+ }
+
+ [JSInvokable("LoadMedia")]
+ public void LoadMedia(bool initial = false) {
+ Media? key = displayMedia?.Any() ?? false && !initial ? displayMedia.Last() : null;
+
+ if(initial)
+ displayMedia = new();
+
+ ApiModels.SortOrder? sortOrder = null;
+ if(Enum.TryParse<ApiModels.SortOrder>(SortOrder, true, out var so))
+ sortOrder = so;
+
+ if(TagId is not null && Query is null) {
+ displayMedia!.AddRange(feedService.LoadChunk(
+ selectIngest: Ingest,
+ includeNsfw: userService.UserSessionState.ShowNsfw,
+ tagId: (Guid) TagId!,
+ key: key,
+ count: PageSize,
+ sortOrder: sortOrder ?? default));
+ } else if(Query is not null && TagId is null) {
+ displayMedia!.AddRange(feedService.LoadChunk(
+ selectIngest: Ingest,
+ includeNsfw: userService.UserSessionState.ShowNsfw,
+ query: string.IsNullOrWhiteSpace(Query) ? null : Query,
+ key: key,
+ count: PageSize,
+ sortOrder: sortOrder ?? default));
+ } else {
+ displayMedia!.AddRange(feedService.LoadChunk(
+ selectIngest: Ingest,
+ includeNsfw: userService.UserSessionState.ShowNsfw,
+ key: key,
+ count: PageSize,
+ sortOrder: sortOrder ?? default));
+ }
+
+ StateHasChanged();
+ }
+
+ private async void ShowNsfwChanged(UserSessionState userSessionState) {
+ await InvokeAsync(() => {
+ LoadMedia(true);
+ });
+ }
+
+ public void Dispose() =>
+ userService.UserSessionState.OnStateChange -= ShowNsfwChanged;
+}