diff options
| author | Jake Mannens <jake@asger.xyz> | 2026-05-22 00:52:16 +1000 |
|---|---|---|
| committer | Jake Mannens <jake@asger.xyz> | 2026-05-23 22:22:55 +1000 |
| commit | 12eaa5814ef20b0910e8d64a753378b6f6797989 (patch) | |
| tree | 062cf477c29054e0f089cb80f0cd79a9f3b7ccd9 /Server.Client/Pages/ViewMedia.razor | |
| parent | 6de5d7f5364fe1d54703da6d6b7cb08ea26e939f (diff) | |
Initial commitwasm-initial
Diffstat (limited to 'Server.Client/Pages/ViewMedia.razor')
| -rw-r--r-- | Server.Client/Pages/ViewMedia.razor | 270 |
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"); + // } +} |
