diff options
| author | Jake Mannens <jake@asger.xyz> | 2023-08-10 01:56:12 +1000 |
|---|---|---|
| committer | Jake Mannens <jake@asger.xyz> | 2025-08-18 10:59:32 +1000 |
| commit | 812eae0b5b75f24adebfe6347ecda26c04b8181b (patch) | |
| tree | e99812d57ef7ae4c8afe9bf83e61ca83ef375b36 /Pages | |
| parent | 5247aa5a136fcf48d80c8e75625ae773a14fbd26 (diff) | |
Added ability to tag media
Diffstat (limited to 'Pages')
| -rw-r--r-- | Pages/Shared/_Layout.cshtml | 2 | ||||
| -rw-r--r-- | Pages/Shared/_Layout.cshtml.css | 6 | ||||
| -rw-r--r-- | Pages/TagDefinitions.cshtml | 12 | ||||
| -rw-r--r-- | Pages/TagDefinitions.cshtml.css | 4 | ||||
| -rw-r--r-- | Pages/ViewMedia.cshtml | 66 | ||||
| -rw-r--r-- | Pages/ViewMedia.cshtml.cs | 3 | ||||
| -rw-r--r-- | Pages/ViewMedia.cshtml.css | 38 |
7 files changed, 119 insertions, 12 deletions
diff --git a/Pages/Shared/_Layout.cshtml b/Pages/Shared/_Layout.cshtml index 9cdb952..4c80500 100644 --- a/Pages/Shared/_Layout.cshtml +++ b/Pages/Shared/_Layout.cshtml @@ -18,7 +18,7 @@ <a href="/">Home</a> <a href="/TagDefinitions">Tags</a> </div> - <div id="content" style="overflow:@(ViewBag.ContentScroll ? "auto" : "hidden");margin:@(ViewBag.ContentMargin ?? "0");"> + <div id="content" style="overflow-y:@(ViewBag.ContentScroll ? "auto" : "hidden");padding:@(ViewBag.ContentMargin ?? "0");"> @RenderBody() </div> </body> diff --git a/Pages/Shared/_Layout.cshtml.css b/Pages/Shared/_Layout.cshtml.css index 5b2ba65..22e36db 100644 --- a/Pages/Shared/_Layout.cshtml.css +++ b/Pages/Shared/_Layout.cshtml.css @@ -4,15 +4,21 @@ } div#navbar > a { + color: white; display: inline-block; padding: 20px 20px 20px 20px; } div#navbar > a:hover { background: rgba(255, 255, 255, 0.4); + filter: none; } div#navbar > a:active { background: #fff; color: var(--col-navbar-bg); +} + +#content { + flex: 1 1 calc(100vh - 119px); }
\ No newline at end of file diff --git a/Pages/TagDefinitions.cshtml b/Pages/TagDefinitions.cshtml index a05f5d5..7bf1790 100644 --- a/Pages/TagDefinitions.cshtml +++ b/Pages/TagDefinitions.cshtml @@ -27,7 +27,9 @@ async function deleteTagDefinition() { var dialog = document.getElementById('delete-dialog'); - var resp = await fetch(`/api/tag/def/${dialog.dataset.guid}`, { + var tagDefId = dialog.dataset.guid; + + var resp = await fetch(`/api/tag/def/${tagDefId}`, { method: 'delete' }); @@ -35,7 +37,9 @@ alert('Error deleting tag definition!'); showDeleteDialog(false); } else { - window.location.reload() + var rows = Array.from(document.getElementsByTagName('tr')); + rows.find(r => r.dataset.guid == tagDefId).remove(); + showDeleteDialog(false); } } @@ -65,12 +69,12 @@ <th></th> </tr> @foreach(var tagDef in Model.TagDefinitions) { - <tr> + <tr data-guid="@tagDef.Guid"> <td>@tagDef.Guid</td> <td>@tagDef.Source</td> <td>@tagDef.Namespace</td> <td>@tagDef.Name</td> - <td><button onclick="showDeleteDialog('@tagDef.Guid')">Delete</button></td> + <td><a href="javascript:showDeleteDialog('@tagDef.Guid');">Delete</a></td> </tr> } </table> diff --git a/Pages/TagDefinitions.cshtml.css b/Pages/TagDefinitions.cshtml.css index 0a9e226..93001c7 100644 --- a/Pages/TagDefinitions.cshtml.css +++ b/Pages/TagDefinitions.cshtml.css @@ -9,8 +9,4 @@ div.button-container { table#tag-definitions td:first-child { font-family: 'Lucida Console'; -} - -table#tag-definitions td > button { - margin-top: 0; }
\ No newline at end of file diff --git a/Pages/ViewMedia.cshtml b/Pages/ViewMedia.cshtml index 3d0ce4a..e37bbf1 100644 --- a/Pages/ViewMedia.cshtml +++ b/Pages/ViewMedia.cshtml @@ -7,8 +7,9 @@ <link rel="stylesheet" type="text/css" href="@(nameof(HyperBooru)).styles.css"/> <script> + var mediaId = new URL(window.location.href).searchParams.get('m'); + async function deleteMedia() { - var mediaId = new URL(window.location.href).searchParams.get('m'); var resp = await fetch('/media/' + mediaId, { method: 'delete' }); if(resp.ok) { window.location.href = '/'; @@ -17,10 +18,44 @@ } } + async function applyTags() { + var checkboxes = Array.from(document + .getElementById('tag-definitions') + .getElementsByTagName('input')); + + var tagDefIds = checkboxes + .filter(cb => cb.checked) + .map(cb => cb.id.replace(/^tagdef-/, '')); + + var pendingRequests = tagDefIds + .map(id => fetch(`/api/tag/${mediaId}/${id}`, { method: 'POST' })); + + var responses = await Promise.all(pendingRequests); + + if(responses.some(r => !r.ok && r.status != 400)) { + alert('Error setting tags!'); + } + showTagDialog(false); + } + + async function removeTag(e, tagDefId) { + var resp = await fetch(`/api/tag/${mediaId}/${tagDefId}`, { method: 'DELETE' }); + if(!resp.ok && resp.status != 400) { + alert('Error removing tag!'); + } else { + e.closest('tr').remove(); + } + } + function showDeleteDialog(visible) { document.getElementById('delete-dialog').classList.toggle('visible', visible); } + function showTagDialog(visible) { + document.getElementById('tag-dialog').classList.toggle('visible', visible); + document.querySelector('div#tag-dialog input').focus(); + } + function selectPane(tab) { var tabs = Array.from(document.querySelectorAll('div#metadata-header > a')); @@ -86,11 +121,22 @@ <div id="metadata-tags"> <table class="data-table"> <tr> + <th>Source</th> + <th>Namespace</th> <th>Tag Name</th> + <th></th> </tr> + @foreach(var tag in Model.Media.Tags.Select(t => t.TagDefinition)) { + <tr> + <td>@tag.Source</td> + <td>@tag.Namespace</td> + <td>@tag.Name</td> + <td><a href="javascript:;" onclick="removeTag(this, '@tag.Guid')">Delete</a></td> + </tr> + } </table> <div class="button-container"> - <button>Add Tag</button> + <button onclick="showTagDialog(true)">Add Tag</button> </div> </div> </div> @@ -104,3 +150,19 @@ <button onclick="deleteMedia()">Confirm</button> </div> </div> + +<div id="tag-dialog" class="dialog"> + <p>Select one or more tag(s) to add</p> + <hr/> + <input type="text" placeholder="Search"/> + <div id="tag-definitions"> + @foreach(var tagdef in Model.TagDefinitions) { + <input type="checkbox" id="tagdef-@tagdef.Guid"/> + <label for="tagdef-@tagdef.Guid">@tagdef.Name</label> + } + </div> + <div class="button-container"> + <button onclick="showTagDialog(false)" class="secondary">Cancel</button> + <button onclick="applyTags()">Accept</button> + </div> +</div> diff --git a/Pages/ViewMedia.cshtml.cs b/Pages/ViewMedia.cshtml.cs index fe8d150..476ea40 100644 --- a/Pages/ViewMedia.cshtml.cs +++ b/Pages/ViewMedia.cshtml.cs @@ -6,6 +6,9 @@ namespace HyperBooru.Pages; public class ViewMediaModel : PageModel { public DbMedia Media { get; private set; } + public IEnumerable<DbTagDefinition> TagDefinitions => + db.TagDefinitions; + private HyperBooruDbContext db; public ViewMediaModel(HyperBooruDbContext db) => diff --git a/Pages/ViewMedia.cshtml.css b/Pages/ViewMedia.cshtml.css index 4041fa8..622de48 100644 --- a/Pages/ViewMedia.cshtml.css +++ b/Pages/ViewMedia.cshtml.css @@ -40,6 +40,7 @@ div#metadata-header > a.selected { div#metadata-header > a:hover { background: rgba(255, 255, 255, 0.4); + filter: none; } div#metadata-fileinfo > table th { @@ -51,7 +52,42 @@ div#metadata-fileinfo > table td { font-size: 8pt; } +div#metadata-tags > table td { + font-size: 8pt; +} + div.button-container { display: flex; justify-content: flex-end; -}
\ No newline at end of file +} + +div#tag-dialog { + max-height: 400px; +} + +div#tag-dialog div#tag-definitions { + overflow-y: auto; + user-select: none; +} + +div#tag-dialog div#tag-definitions label { + background: #555; + border-radius: 10px; + display: inline-block; + font-size: 10pt; + margin: 0 5px 5px 0; + padding: 5px 7px 5px 7px; + transition: background 0.1s linear; +} + +div#tag-dialog div#tag-definitions label:hover { + background: #777; +} + +div#tag-dialog div#tag-definitions input:checked + label { + background: #aaa; +} + +div#tag-dialog div#tag-definitions input { + display: none; +} |
