summaryrefslogtreecommitdiff
path: root/Server.Client/Pages/ViewMedia.razor
diff options
context:
space:
mode:
authorJake Mannens <jake@asger.xyz>2026-05-22 00:52:16 +1000
committerJake Mannens <jake@asger.xyz>2026-05-23 22:22:55 +1000
commit12eaa5814ef20b0910e8d64a753378b6f6797989 (patch)
tree062cf477c29054e0f089cb80f0cd79a9f3b7ccd9 /Server.Client/Pages/ViewMedia.razor
parent6de5d7f5364fe1d54703da6d6b7cb08ea26e939f (diff)
Initial commitwasm-initial
Diffstat (limited to 'Server.Client/Pages/ViewMedia.razor')
-rw-r--r--Server.Client/Pages/ViewMedia.razor270
1 files changed, 270 insertions, 0 deletions
diff --git a/Server.Client/Pages/ViewMedia.razor b/Server.Client/Pages/ViewMedia.razor
new file mode 100644
index 0000000..4c9151e
--- /dev/null
+++ b/Server.Client/Pages/ViewMedia.razor
@@ -0,0 +1,270 @@
+@page "/ViewMedia"
+@* @using HyperBooru.Util*@
+@inject HBSession hb
+@inject IJSRuntime jsRuntime
+@* @inject IDbContextFactory<HBContext> dbFactory
+@inject ITagService tagService
+@inject IMediaService mediaService
+@inject ISourceService sourceService
+ *@
+
+<PageTitle>@title</PageTitle>
+
+<script suppress-warning="BL9992">
+ function toggleSidebar() {
+ document.getElementById("hcontainer").classList.toggle("hide-metadata");
+ }
+
+ 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">
+ <div id="image-container" class="mobile-pane-image visible">
+ <img
+ src="/media/@(MediaId)"/>
+@* <img
+ src="/media/@(media.Guid)"
+ width=@media.CurrentUploadedFile.Width
+ height=@media.CurrentUploadedFile.Height/>
+ *@ </div>
+ <div id="metadata-show-button">
+ <a href="javascript:toggleSidebar();" title="Toggle sidebar (S)"></a>
+ </div>
+ <div id="metadata" class="mobile-pane-metadata">
+ <div id="metadata-container">
+ <div id="metadata-fileinfo">
+ @if(infoEditMode) {
+@* <form action="javascript:;" @onsubmit=@(() => ApplyInfoEdit(true))>
+ <table id="edit-metadata">
+ <tr>
+ <td>Title:</td>
+ <td><input type="text" @bind=shortDescription @ref=shortDescriptionInput/></td>
+ </tr>
+ <tr>
+ <td>Description:</td>
+ <td><textarea rows="4" @bind=longDescription/></td>
+ </tr>
+ </table>
+ </form>
+ *@ } else {
+ <p>Title: <i>@(media?.ShortDescription ?? "None")</i></p>
+ <p class="newlines">Description:<br/><i>@(media?.LongDescription ?? "None")</i></p>
+ }
+@* <p>Resolution: @(media.CurrentUploadedFile.Width)x@(media.CurrentUploadedFile.Height)</p>
+ <p class="heading">Upload history</p>
+ <hr/>
+ <table id="uploaded-files" class="data-table">
+ <tr>
+ <th>Created On</th>
+ <th>Last Write</th>
+ <th>Uploaded On</th>
+ <th>Filename</th>
+ <th>Size</th>
+ <th>Original Checksum</th>
+ </tr>
+ @foreach(var file in media.UploadedFiles.OrderByDescending(uf => uf.UploadTime)) {
+ string? sourceUrl = null;
+ if(file.Filename is not null)
+ sourceUrl = sourceService.GetUrlFromFilename(file.Filename);
+ <tr>
+ <td title=@file.CreateTime?.ToString()>
+ @(file.CreateTime?.ToString("d") ?? "N/A")
+ </td>
+ <td title=@file.LastWriteTime?.ToString()>
+ @(file.LastWriteTime?.ToString("d") ?? "N/A")
+ </td>
+ <td title=@file.UploadTime>@(file.UploadTime.ToString("d"))</td>
+ <td title=@(file.Path is not null ? $"{file.Path.Replace('\\', '/')}/{file.Filename}" : file.Filename)>
+ @if(sourceUrl is not null) {
+ <a class="nondecorated" target="_blank" href=@sourceUrl>@file.Filename</a>
+ } else {
+ @file.Filename
+ }
+ </td>
+ <td title=@file.Length>@file.Length.ToBytesSI()</td>
+ <td
+ title=@(file.Checksum + (file.ChecksumVerified ? " (verified)" : ""))
+ class=@(file.ChecksumVerified ? "verified" : null)>
+
+ @file.Checksum.Substring(0, 8)
+ </td>
+ </tr>
+ }
+ </table>
+ *@ </div>
+ <div id="metadata-tags">
+ <p class="heading">Tags</p>
+ <hr/>
+ <MediaTagTable MediaId=MediaId @ref=mediaTagTable/>
+ </div>
+ </div>
+ <div id="button-container">
+ <ButtonContainer>
+@* <button @onclick=@(() => deleteDialog.Show()) class="warning" data-keyboard-shortcut="d">
+ <img src="/images/trash.svg"/>
+ <p><u>D</u>elete</p>
+ </button>
+ <button @onclick=@(() => tagDialog.Show()) class="secondary" data-keyboard-shortcut="t">
+ <img src="/images/tag.svg"/>
+ <p>Add <u>T</u>ag</p>
+ </button>
+ <button @onclick=@(() => ocrDialog.Show()) class="secondary" data-keyboard-shortcut="o">
+ <img src="/images/book.svg"/>
+ <p>View <u>O</u>CR</p>
+ </button>
+ *@ @if(infoEditMode) {
+@* <button @onclick=@(() => ApplyInfoEdit(false)) class="secondary">
+ <img src="/images/cross.svg"/>
+ <p>Cancel</p>
+ </button>
+ <button @onclick=@(() => ApplyInfoEdit(true))>
+ <img src="/images/checkmark.svg"/>
+ <p>Apply</p>
+ </button>
+ *@ } else {
+ <button @onclick=@(() => InfoEditMode = true) class="secondary" data-keyboard-shortcut="e">
+ <img src="/images/edit.svg"/>
+ <p><u>E</u>dit Info</p>
+ </button>
+ }
+@* @if(media.IsIngest) {
+ <button @onclick=@(() => SetIngest(false)) data-keyboard-shortcut="c">
+ <img src="/images/checkmark.svg"/>
+ <p>Mark Tagging <u>C</u>omplete</p>
+ </button>
+ } else {
+ *@ <button class="secondary" @onclick=@(() => SetIngest(true)) data-keyboard-shortcut="c">
+ <img src="/images/cross.svg"/>
+ <p>Mark Tagging In<u>c</u>omplete</p>
+ </button>
+ @* } *@
+ </ButtonContainer>
+ </div>
+ </div>
+ </div>
+ <div id="bottom-bar">
+ <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>
+
+@* <Dialog Title="Delete this media?" @ref=deleteDialog>
+ <ButtonContainer>
+ <button @onclick=@(() => deleteDialog.Hide()) class="secondary">Cancel</button>
+ <button @onclick=DeleteMedia class="warning">Confirm</button>
+ </ButtonContainer>
+</Dialog>
+
+<Dialog Title="OCR Data" @ref=ocrDialog>
+ @if(media.OcrData is null) {
+ <p><center>This media item hasn't been scanned yet!</center></p>
+ } else {
+ <code style="max-height:400px;">@media.OcrData?.Text</code>
+ }
+ <ButtonContainer>
+ <button @onclick=@(() => ocrDialog.Hide())>Close</button>
+ </ButtonContainer>
+</Dialog>
+
+<TagSelectDialog
+ Title="Select one or more tag(s) to add"
+ OnSubmit=AddTags
+ @ref=tagDialog/>
+ *@
+@code {
+ [Parameter]
+ [SupplyParameterFromQuery(Name = "m")]
+ public Guid MediaId { get; set; }
+
+ private ApiModels.Media media;
+
+ private string title;
+
+ private bool infoEditMode = false;
+ private string? shortDescription;
+ private string? longDescription;
+
+ private MediaTagTable mediaTagTable;
+ // private Dialog deleteDialog;
+ // private Dialog ocrDialog;
+ // private TagSelectDialog tagDialog;
+
+ private ElementReference shortDescriptionInput;
+
+ protected override void OnInitialized() =>
+ LoadMedia();
+
+ protected override async void OnAfterRender(bool firstRender) {
+ if(infoEditMode)
+ await shortDescriptionInput.FocusAsync();
+ }
+
+ private async void LoadMedia() {
+ media = await hb.Media.GetAsync(MediaId);
+ // using var db = dbFactory.CreateDbContext();
+ // media = db.Media
+ // .Include(m => m.Tags)
+ // .ThenInclude(t => t.TagDefinition)
+ // .Include(m => m.CurrentUploadedFile)
+ // .Include(m => m.UploadedFiles)
+ // .Include(m => m.OcrData)
+ // .First(m => m.Guid == MediaId);
+
+ // title = media.DisplayName ?? "Media View";
+ // InvokeAsync(() => StateHasChanged());
+ }
+
+ // private void AddTags(TagDefinition[] tagDefs) {
+ // foreach(var tagDef in tagDefs)
+ // tagService.AddTag(media, tagDef);
+ // mediaTagTable.Refresh();
+ // }
+
+ private async void SetIngest(bool ingest) {
+ // mediaService.SetIngest(media, ingest);
+ LoadMedia();
+
+ if(ingest)
+ StateHasChanged();
+ else
+ await jsRuntime.InvokeVoidAsync("history.back");
+ }
+
+ private bool InfoEditMode {
+ get => infoEditMode;
+ set {
+ shortDescription = media.ShortDescription;
+ longDescription = media.LongDescription;
+ infoEditMode = value;
+ StateHasChanged();
+ }
+ }
+
+ // private void ApplyInfoEdit(bool apply) {
+ // if(apply) {
+ // mediaService.SetDescription(media, shortDescription, longDescription);
+ // LoadMedia();
+ // }
+
+ // infoEditMode = false;
+ // }
+
+ // private async void DeleteMedia() {
+ // mediaService.Delete(media);
+ // await jsRuntime.InvokeVoidAsync("history.back");
+ // }
+}