diff options
| author | Jake Mannens <jake@asger.xyz> | 2026-04-16 02:22:56 +1000 |
|---|---|---|
| committer | Jake Mannens <jake@asger.xyz> | 2026-04-16 02:22:56 +1000 |
| commit | ba86ba12732b3290eaa74936950a370966b41ac5 (patch) | |
| tree | fcb1fb3df3a0edc1d0a27a5336c8cadaef593507 | |
| parent | d59e751c5b7c23f0dce2a146b6b8ced80231a0cb (diff) | |
v0.10av0.10a
| -rw-r--r-- | .editorconfig | 3 | ||||
| -rw-r--r-- | Pages/Component/MobileMenu.razor | 6 | ||||
| -rw-r--r-- | Pages/Component/TagSelectDialog.razor | 11 | ||||
| -rw-r--r-- | Pages/Component/Titlebar.razor | 9 | ||||
| -rw-r--r-- | Pages/Gallery.razor.css | 3 | ||||
| -rw-r--r-- | Pages/ViewMedia.razor | 27 | ||||
| -rw-r--r-- | Pages/ViewMedia.razor.css | 16 | ||||
| -rw-r--r-- | Program.cs | 8 | ||||
| -rw-r--r-- | Server.csproj | 4 | ||||
| -rw-r--r-- | Services/ConfigService.cs | 4 | ||||
| -rw-r--r-- | Services/MediaService.cs | 8 | ||||
| -rw-r--r-- | Todo.md | 6 | ||||
| -rw-r--r-- | wwwroot/js/keyboard.js | 3 | ||||
| -rw-r--r-- | wwwroot/styles/global.css | 4 |
14 files changed, 74 insertions, 38 deletions
diff --git a/.editorconfig b/.editorconfig index 6d8f727..913b3e5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,3 +2,6 @@ # CS8618: Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. dotnet_diagnostic.CS8618.severity = silent + +# ASP0000: Do not call 'IServiceCollection.BuildServiceProvider' in 'ConfigureServices' +dotnet_diagnostic.ASP0000.severity = silent diff --git a/Pages/Component/MobileMenu.razor b/Pages/Component/MobileMenu.razor index 6cb3281..49c45d5 100644 --- a/Pages/Component/MobileMenu.razor +++ b/Pages/Component/MobileMenu.razor @@ -14,12 +14,6 @@ <a href="javascript:logout();">Logout</a> </div> -<script suppress-error="BL9992"> - function hideMobileMenu() { - document.getElementById('mobile-menu').classList.add('hidden'); - } -</script> - @code { protected override void OnInitialized() => navigationManager.LocationChanged += LocationChanged; diff --git a/Pages/Component/TagSelectDialog.razor b/Pages/Component/TagSelectDialog.razor index 20be31e..87065d7 100644 --- a/Pages/Component/TagSelectDialog.razor +++ b/Pages/Component/TagSelectDialog.razor @@ -7,7 +7,16 @@ <link rel="stylesheet" href="@(nameof(HyperBooru)).styles.css"/> <Dialog Title=@(Title ?? "Select one or more tag(s)") @ref=dialog> - <input type="text" placeholder="Search" @ref=queryInput @oninput=QueryInput @onkeypress=QueryKey value=@query/> + <input + type="text" + placeholder="Search" + autocorrect="off" + autocapitalize="off" + autocomplete="off" + @ref=queryInput + @oninput=QueryInput + @onkeypress=QueryKey + value=@query/> <div class="tag-definitions"> @for(int i = 0; i < tagDefinitions.Count(); i++) { if(!MatchesQuery(tagDefinitions[i].tagDefinition)) diff --git a/Pages/Component/Titlebar.razor b/Pages/Component/Titlebar.razor index a0b9eec..48257b2 100644 --- a/Pages/Component/Titlebar.razor +++ b/Pages/Component/Titlebar.razor @@ -67,7 +67,14 @@ <div id="navbar"> <h2>Login</h2> <form class="login" action="javascript:login();"> - <input id="username" placeholder="Username" type="text"/> + <input + id="username" + placeholder="Username" + type="text" + autocorrect="off" + autocapitalize="off" + autocomplete="off" + autofocus/> <input id="password" placeholder="Password" type="password"/> </form> <a href="javascript:login();">Login</a> diff --git a/Pages/Gallery.razor.css b/Pages/Gallery.razor.css index 1b5ed86..6226d9b 100644 --- a/Pages/Gallery.razor.css +++ b/Pages/Gallery.razor.css @@ -1,6 +1,9 @@ img { + height: auto; margin-right: 5px; max-height: 200px; + max-width: 100%; + width: auto; } div#feed-error { diff --git a/Pages/ViewMedia.razor b/Pages/ViewMedia.razor index 27a366c..46cbc45 100644 --- a/Pages/ViewMedia.razor +++ b/Pages/ViewMedia.razor @@ -14,23 +14,34 @@ document.getElementById("hcontainer").classList.toggle("hide-metadata"); } - function showSidebar(visible) { - document.getElementById("hcontainer").classList.toggle("hide-metadata", !visible) + function setMobilePane(pane) { + var panes = Array.from(document.querySelectorAll('[class^="mobile-pane-"]')); + + panes.forEach(e => e.classList.remove('visible')); + panes + .filter(e => e.classList.contains(`mobile-pane-${pane}`)) + .forEach(e => e.classList.add('visible')); + } + + function pageKeyDownHandler(e) { + if(!e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey && !e.isComposing) + if(e.key == 's') + toggleSidebar(); } </script> <div id="vcontainer"> - <div id="hcontainer" class="hide-metadata"> - <div id="image-container"> + <div id="hcontainer"> + <div id="image-container" class="mobile-pane-image visible"> <img src="/media/@(media.Guid)" width=@media.CurrentUploadedFile.Width height=@media.CurrentUploadedFile.Height/> </div> <div id="metadata-show-button"> - <a href="javascript:toggleSidebar();"></a> + <a href="javascript:toggleSidebar();" title="Toggle sidebar (S)"></a> </div> - <div id="metadata"> + <div id="metadata" class="mobile-pane-metadata"> <div id="metadata-container"> <div id="metadata-fileinfo"> @if(infoEditMode) { @@ -143,8 +154,8 @@ </div> </div> <div id="bottom-bar"> - <img onclick="showSidebar(false);" src="/images/photo.svg" width="25" height="25"/> - <img onclick="showSidebar(true);" src="/images/info.svg" width="25" height="25"/> + <img onclick="setMobilePane('image');" src="/images/photo.svg" width="25" height="25"/> + <img onclick="setMobilePane('metadata');" src="/images/info.svg" width="25" height="25"/> </div> </div> diff --git a/Pages/ViewMedia.razor.css b/Pages/ViewMedia.razor.css index 080994a..60b04be 100644 --- a/Pages/ViewMedia.razor.css +++ b/Pages/ViewMedia.razor.css @@ -100,20 +100,12 @@ div#metadata { } @media (hover: none) and (pointer: coarse) { - div#image-container { - display: none; + [class^="mobile-pane-"] { + width: 100% !important; } - div#metadata { - width: 100%; - } - - div#hcontainer.hide-metadata > div#image-container { - display: initial; - } - - div#hcontainer.hide-metadata > div#metadata { - display: none; + [class^="mobile-pane-"]:not(.visible) { + display: none !important; } } @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using System.Text.Json.Serialization; using HyperBooru.Services; using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.DataProtection; namespace HyperBooru; @@ -30,6 +31,13 @@ public class Program { builder.Services.AddHostedService<OcrService>(); builder.Services.AddSingleton<ISourceService, SourceService>(); + // Ensure session keys are stored in a persistent location on all platforms + builder.Services.AddDataProtection() + .PersistKeysToFileSystem(new( + builder.Services.BuildServiceProvider() + .GetRequiredService<IConfigService>() + .KeyPath)); + var app = builder.Build(); // Ensure database is created and it's schema is up to date diff --git a/Server.csproj b/Server.csproj index 6e4af7d..f733581 100644 --- a/Server.csproj +++ b/Server.csproj @@ -6,9 +6,9 @@ <ImplicitUsings>enable</ImplicitUsings> <AssemblyName>HyperBooru</AssemblyName> <RootNamespace>HyperBooru</RootNamespace> - <AssemblyVersion>0.9.0.0</AssemblyVersion> + <AssemblyVersion>0.10.0.0</AssemblyVersion> <FileVersion>$(AssemblyVersion)</FileVersion> - <Version>0.9-alpha</Version> + <Version>0.10-alpha</Version> <UserSecretsId>2907567f-4640-4581-8f4d-0977952d26bd</UserSecretsId> </PropertyGroup> diff --git a/Services/ConfigService.cs b/Services/ConfigService.cs index d2d1a06..752f9f5 100644 --- a/Services/ConfigService.cs +++ b/Services/ConfigService.cs @@ -2,6 +2,7 @@ public interface IConfigService { public string DataPath { get; } + public string KeyPath { get; } public string DbConnectionString { get; } public string MediaBasePath { get; } public string ThumbnailBasePath { get; } @@ -38,6 +39,9 @@ public class ConfigService : IConfigService { } } + public string KeyPath => + Path.Join(DataPath, "keys"); + public string DbConnectionString => config.GetConnectionString("DefaultConnection") ?? throw new HBException("Unable to get default connection string"); diff --git a/Services/MediaService.cs b/Services/MediaService.cs index 2f7eac6..27c77d6 100644 --- a/Services/MediaService.cs +++ b/Services/MediaService.cs @@ -285,10 +285,10 @@ public class MediaService : IMediaService { using var image = new MagickImage(GetPath(mediaId)); - if(width > image.Width || height > image.Height) - throw new ThumbnailException( - "Requested thumbnail size is larger than original media", - mediaId); + if(width > image.Width || height > image.Height) { + width = (int) image.Width; + height = (int) image.Height; + } image.Thumbnail((uint) (width ?? -1), (uint) (height ?? -1)); image.Write(thumbPath, MagickFormat.Jpeg); @@ -1,4 +1,8 @@ # Bugs + - [X] Images in the gallery on mobile can easily exceed screen width + - [X] Images smaller than the requested thumbnail size aren't delivered + - [X] Autocorrect needs to be disabled on inputs such as username, tag name, etc + - [X] Mobile menu does not automatically hide upon page navigation - [X] Input not focused - [ ] Setting implicit tags removes builtin tags - [X] UserService listeners don't seem to be removed after disposal @@ -8,6 +12,8 @@ - [ ] Can't delete media # Short-term Features + - [ ] Ability to set password (at least via API) + - [ ] PowerShell uploading with initial tagging - [ ] Proper thumbnail generation - [ ] Video support - [ ] User/security support diff --git a/wwwroot/js/keyboard.js b/wwwroot/js/keyboard.js index 59eec4c..8b46639 100644 --- a/wwwroot/js/keyboard.js +++ b/wwwroot/js/keyboard.js @@ -49,6 +49,9 @@ async function keyDownHandler(e) { e.preventDefault(); return; } + + if(typeof pageKeyDownHandler == 'function') + pageKeyDownHandler(e); } window.onload = () => document.onkeydown = keyDownHandler;
\ No newline at end of file diff --git a/wwwroot/styles/global.css b/wwwroot/styles/global.css index 2bd24bc..9de9fc1 100644 --- a/wwwroot/styles/global.css +++ b/wwwroot/styles/global.css @@ -114,10 +114,6 @@ button > img { } @media (hover: none) and (pointer: coarse) { - button { - height: auto; - } - button > :not(:first-child) { display: none; } |
