summaryrefslogtreecommitdiff
path: root/Pages/TagDefinitions.razor
diff options
context:
space:
mode:
authorJake Mannens <jake@asger.xyz>2026-03-17 03:04:36 +1100
committerJake Mannens <jake@asger.xyz>2026-03-25 01:57:41 +1100
commitc751709b1b4fe6f16fd84647e8e071455e7b78d6 (patch)
tree47734a083d888660606e6cf6cf158c93e69a9807 /Pages/TagDefinitions.razor
v0.1av0.1a
Diffstat (limited to 'Pages/TagDefinitions.razor')
-rw-r--r--Pages/TagDefinitions.razor187
1 files changed, 187 insertions, 0 deletions
diff --git a/Pages/TagDefinitions.razor b/Pages/TagDefinitions.razor
new file mode 100644
index 0000000..e2e4df6
--- /dev/null
+++ b/Pages/TagDefinitions.razor
@@ -0,0 +1,187 @@
+@page "/TagDefinitions"
+@inject IDbContextFactory<HBContext> dbFactory
+@inject ITagService tagService
+@inject IUserService userService
+@implements IDisposable
+@attribute [Authorize]
+
+<PageTitle>Tag Definitions</PageTitle>
+
+<div style="padding:var(--size-default-gap);">
+ <ButtonContainer>
+ <button @onclick=PromptTagCreate data-keyboard-shortcut="c"><u>C</u>reate</button>
+ </ButtonContainer>
+
+ <TabContainer @ref=tabContainer>
+ @foreach(var ns in tagNamespaces) {
+ <TabPane Title="@(ns ?? "Default")">
+ <table id="tag-definitions" class="data-table">
+ <tr>
+ <th>Alias</th>
+ <th>Name</th>
+ <th>Implicit Tags</th>
+ <th></th>
+ </tr>
+ @foreach(var tagDef in tagDefinitions.Where(td => td.Namespace == ns)) {
+ <tr data-guid="@tagDef.Guid">
+ <td>@tagDef.Alias</td>
+ <td>
+ <a href="/Gallery?q=@tagDef.Name" class="nondecorated">
+ @tagDef.Name
+ </a>
+ </td>
+ <td>
+ <i>
+ @{
+ var implicitTags = tagDef.ImplicitTags
+ .Where(td => td.Source == TagSource.UserTag);
+ foreach(var tag in implicitTags) {
+ <a href="/Gallery?q=@tag.Name" class="nondecorated">
+ @tag.Name
+ </a>
+ if(tag != implicitTags.Last())
+ @(", ")
+ }
+ }
+ </i>
+ </td>
+ <td class="actions">
+ <a href="javascript:;" @onclick=@(() => tagEditDialog.Show(tagDef))>Edit</a>
+ <a href="javascript:;" @onclick=@(() => PromptToDelete(tagDef))>
+ Delete
+ </a>
+ <a href="javascript:;" @onclick=@(() => PromptImplicitTags(tagDef))>
+ Implicit Tags
+ </a>
+ @if(tagDef.ImplicitTags.Select(td => td.Guid).Contains(HBContext.NsfwTag)) {
+ <a href="javascript:;" @onclick=@(() => SetNsfw(tagDef, false))>Make SFW</a>
+ } else {
+ <a href="javascript:;" @onclick=@(() => SetNsfw(tagDef, true))>Make NSFW</a>
+ }
+ </td>
+ </tr>
+ }
+ </table>
+ </TabPane>
+ }
+ </TabContainer>
+</div>
+
+<Dialog Title="Are you sure you want to delete this tag definition?" @ref=deleteTagDialog>
+ <ButtonContainer>
+ <button @onclick=@(() => deleteTagDialog.Hide()) class="secondary">Cancel</button>
+ <button @onclick=@(() => DeleteTagDefinition()) class="warning">Confirm</button>
+ </ButtonContainer>
+</Dialog>
+
+<TagEditDialog OnTagUpdate=TagUpdated @ref=tagEditDialog/>
+
+<TagSelectDialog
+ OnSubmit=SetImplicitTags
+ @ref=implicitTagDialog />
+
+@code {
+ private TabContainer tabContainer;
+ private Dialog deleteTagDialog;
+ private TagEditDialog tagEditDialog;
+ private TagSelectDialog implicitTagDialog;
+
+ private TagDefinition? toDelete;
+ private TagDefinition? toEditImplicit;
+
+ private TagDefinition[] tagDefinitions;
+
+ private string?[] tagNamespaces;
+
+ protected override void OnInitialized() =>
+ userService.UserSessionState.OnStateChange += ShowNsfwChanged;
+
+ protected override void OnParametersSet() =>
+ LoadTags();
+
+ private void LoadTags() {
+ int[] nsfwTags = Array.Empty<int>();
+ if(!userService.UserSessionState.ShowNsfw)
+ nsfwTags = tagService.TagsThatImply(HBContext.NsfwTag)
+ .Select(td => td.ObjectId)
+ .ToArray();
+
+ tagDefinitions = dbFactory.CreateDbContext().TagDefinitions
+ .Include(td => td.ImplicitTags)
+ .Where(td => td.Source == TagSource.UserTag)
+ .OrderBy(td => td.Namespace)
+ .ThenBy(td => td.Name)
+ .AsEnumerable()
+ .Where(td => userService.UserSessionState.ShowNsfw || !td.ImplicitTags
+ .IntersectBy(nsfwTags, td => td.ObjectId)
+ .Any())
+ .ToArray();
+
+ tagNamespaces = tagDefinitions
+ .Select(td => td.Namespace)
+ .Order()
+ .Distinct()
+ .ToArray();
+ }
+
+ private void PromptToDelete(TagDefinition toDelete) {
+ this.toDelete = toDelete;
+ deleteTagDialog.Show();
+ }
+
+ private void DeleteTagDefinition() {
+ if(toDelete is null)
+ return;
+
+ tagService.DeleteTagDefinition(toDelete);
+ deleteTagDialog.Hide();
+ LoadTags();
+ StateHasChanged();
+ }
+
+ private void PromptTagCreate() {
+ string? ns = tabContainer.ActivePane?.Title;
+ if(ns == "Default")
+ ns = null;
+ tagEditDialog.Show(ns);
+ }
+
+ private void TagUpdated(object? sender, EventArgs e) {
+ LoadTags();
+ StateHasChanged();
+ }
+
+ private void PromptImplicitTags(TagDefinition toEditImplicit) {
+ this.toEditImplicit = toEditImplicit;
+ implicitTagDialog.SelectedTags =
+ toEditImplicit.ImplicitTags.ToArray();
+ implicitTagDialog.Show();
+ }
+
+ private void SetImplicitTags(TagDefinition[] tagDefs) {
+ if(toEditImplicit is null)
+ return;
+
+ tagService.SetImplicitTags(toEditImplicit, tagDefs);
+ LoadTags();
+ StateHasChanged();
+ }
+
+ private void SetNsfw(TagDefinition tagDef, bool nsfw) {
+ if(nsfw)
+ tagService.AddImplicitTag(tagDef.Guid, HBContext.NsfwTag);
+ else
+ tagService.RemoveImplicitTag(tagDef.Guid, HBContext.NsfwTag);
+ LoadTags();
+ StateHasChanged();
+ }
+
+ private async void ShowNsfwChanged(UserSessionState userSessionState) =>
+ await InvokeAsync(() => {
+ LoadTags();
+ StateHasChanged();
+ });
+
+ public void Dispose() =>
+ userService.UserSessionState.OnStateChange -= ShowNsfwChanged;
+}