Build / Build (push) Successful in 1m8s
Follow requests answered on the persona's own profile and from the Notifications tab; its followers and the accounts it follows listed there, a follower removed (asked first). Downvotes on threadiverse posts, after the public-vote notice. A notification dismissed from its line. "Filter this post" from a card's menu, and the Filters page showing the posts a filter holds. Who may quote the persona's own posts, and revoking a quote of one. Statistics: a server in detail with "describe again", the ledger's events, the server's own days. The composer deletes an upload taken out before posting. MediaType.Documents goes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
89 lines
2.9 KiB
Plaintext
89 lines
2.9 KiB
Plaintext
@inherits LocalizableComponentBase
|
|
|
|
@* "Filter this post", from a card's menu: the persona's filters (/api/v2/filters), one of which takes the post (POST
|
|
/api/v2/filters/:id/statuses); a filter that holds it already says so. Filters are made and changed on /filters. The
|
|
card reads the post again afterwards, so the filter applies to it at once. *@
|
|
<DModal Placement="DModalPlacement.ResponsiveBottom" IsOpen="true" IsOpenChanged="Closed" CloseText="@Localizer["Close"]" data-filter-post-dialog>
|
|
<Heading>@Localizer["Filter this post"]</Heading>
|
|
<ChildContent>
|
|
@if (IsLoading)
|
|
{
|
|
<p class="flex items-center gap-2 mt-3"><DLoading Variant="DLoadingVariant.Dots" LabelText="@Localizer["loading"]" />@Localizer["loading"]</p>
|
|
}
|
|
else if (filters.Count == 0)
|
|
{
|
|
<p class="text-sm opacity-70 mt-3">@Localizer["This persona has no filter yet."]</p>
|
|
}
|
|
<div class="flex flex-col gap-2 mt-3">
|
|
@foreach (var filter in filters)
|
|
{
|
|
<DButton Size="DSize.Sm" class="justify-start" Disabled="@(IsDefaultDisabled || isSaving || Holds(filter))" OnClick="() => Add(filter)"
|
|
data-filter-choice="@filter.Id">
|
|
<i class="ion-md-funnel" aria-hidden="true"></i>
|
|
<span class="flex-1 min-w-0 truncate text-left">@filter.Title</span>
|
|
<span class="text-xs opacity-70">@Description(filter)</span>
|
|
</DButton>
|
|
}
|
|
<a class="btn btn-sm justify-start" href="filters" data-filter-post-manage>
|
|
<i class="ion-md-create" aria-hidden="true"></i><span>@Localizer["Make a filter"]</span>
|
|
</a>
|
|
</div>
|
|
</ChildContent>
|
|
</DModal>
|
|
|
|
@code {
|
|
[Inject] FilterService FilterService { get; set; }
|
|
|
|
[Parameter, EditorRequired] public string StatusId { get; set; }
|
|
[Parameter] public EventCallback OnClosed { get; set; }
|
|
/// <summary>The post went into a filter.</summary>
|
|
[Parameter] public EventCallback OnFiltered { get; set; }
|
|
|
|
List<Filter> filters = [];
|
|
bool isSaving;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
if (CascadingState.IsOffline)
|
|
{
|
|
WhenOnline(LoadData);
|
|
StartOnlinePolling();
|
|
IsLoading = false;
|
|
return;
|
|
}
|
|
|
|
await LoadData();
|
|
IsLoading = false;
|
|
}
|
|
|
|
async Task LoadData() => filters = await FilterService.All();
|
|
|
|
bool Holds(Filter filter) => filter.Statuses.Any(s => s.StatusId == StatusId);
|
|
|
|
string Description(Filter filter) => Holds(filter) ? Localizer["Already in it"]
|
|
: !filter.IsActive ? Localizer["Expired"]
|
|
: filter.FilterAction switch
|
|
{
|
|
FilterAction.Hide => Localizer["Hide"],
|
|
FilterAction.Blur => Localizer["Blur"],
|
|
_ => Localizer["Warn"]
|
|
};
|
|
|
|
async Task Add(Filter filter)
|
|
{
|
|
isSaving = true;
|
|
var result = await FilterService.AddStatus(filter.Id, StatusId);
|
|
isSaving = false;
|
|
if (result.IsInvalid)
|
|
{
|
|
Toast.AddResponseError(result);
|
|
return;
|
|
}
|
|
|
|
Toast.AddResponseSuccess(Localizer["Added to {0}.", filter.Title]);
|
|
await OnFiltered.InvokeAsync();
|
|
}
|
|
|
|
Task Closed(bool open) => open ? Task.CompletedTask : OnClosed.InvokeAsync();
|
|
}
|