Polls, quotes and edits from the composer

The composer can hold a poll instead of media (two to four choices, a
length, one choice or several), quote a post (offered on a card when the
server says the persona may quote it), and edit the persona's own post: its
words and warning come from /source, and saving keeps its media,
visibility and poll. A card's menu offers Edit and Quote, and now opens
sideways: upwards, the first card's menu was cut off by the top of the
feed. The e2e tests publish a poll, edit a post and quote it, each checked
on PrivaPub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-05 04:42:42 +02:00
1 parent a4d9831691
commit 5c11727f58
12 files changed
+434 -12

No files matched your search

+46 -2
View File
@@ -195,9 +195,10 @@
</div>
<div class="flex gap-2">
<DDropdown @bind-IsOpen="isOptionsOpen" Align="DDropdownAlign.End" CloseOnContentClick="true" Placement="DDropdownPlacement.Top"
@* opens sideways and downwards: opened upwards, the first card's menu was cut off by the top of the feed *@
<DDropdown @bind-IsOpen="isOptionsOpen" Align="DDropdownAlign.Start" CloseOnContentClick="true" Placement="DDropdownPlacement.Left"
TriggerClass="@(isOptionsOpen ? "btn btn-sm btn-active" : "btn btn-sm")"
ContentClass="mb-2 flex flex-col gap-2 p-2 rounded-box" title="@Localizer["Other"]">
ContentClass="mr-2 flex flex-col gap-2 p-2 rounded-box" title="@Localizer["Other"]">
<Trigger>
<i aria-hidden="true" class="ion-md-more text-lg"></i>
</Trigger>
@@ -209,6 +210,13 @@
<span>@Localizer["Open original"]</span>
</a>
}
@if (CanQuote(status))
{
<DButton Size="DSize.Sm" class="justify-start whitespace-nowrap" Disabled="IsDefaultDisabled" OnClick="ToggleQuote" data-quote>
<i aria-hidden="true" class="ion-md-quote text-base"></i>
<span>@Localizer["Quote"]</span>
</DButton>
}
@if (!IsOwn)
{
<DButton Size="DSize.Sm" class="justify-start whitespace-nowrap" Disabled="IsDefaultDisabled || isActing" OnClick="@(() => AccountAction("mute"))">
@@ -222,6 +230,10 @@
}
else
{
<DButton Size="DSize.Sm" class="justify-start whitespace-nowrap" Disabled="IsDefaultDisabled" OnClick="ToggleEdit" data-edit>
<i aria-hidden="true" class="ion-md-create text-base"></i>
<span>@Localizer["Edit"]</span>
</DButton>
<DButton Size="DSize.Sm" class="justify-start whitespace-nowrap" Disabled="IsDefaultDisabled || isActing" OnClick="Delete">
<i aria-hidden="true" class="ion-md-trash text-base text-error"></i>
<span>@Localizer["Delete"]</span>
@@ -242,6 +254,14 @@
{
<Composer InReplyTo="status" OnPublished="Replied" />
}
@if (isQuoting)
{
<Composer Quoting="status" OnPublished="Quoted" />
}
@if (isEditing)
{
<Composer Editing="status" OnPublished="Edited" />
}
}
}
}
@@ -292,6 +312,8 @@
[Parameter] public FilterContext? FilterIn { get; set; }
bool isReplying;
bool isQuoting;
bool isEditing;
bool isActing;
bool isOptionsOpen;
bool isSpoilerOpen;
@@ -585,6 +607,28 @@
void ToggleReply() => isReplying = !isReplying;
void ToggleQuote() => isQuoting = !isQuoting;
void ToggleEdit() => isEditing = !isEditing;
// the server says whether the persona may quote it; without that, a public or unlisted post may be asked
static bool CanQuote(Status status) => status.QuoteApproval?.CurrentUser is { } answer
? answer is "automatic" or "manual"
: status.Visibility is "public" or "unlisted";
async Task Quoted(FeedPost quote)
{
isQuoting = false;
await OnReplied.InvokeAsync(quote);
}
void Edited(FeedPost edited)
{
isEditing = false;
if (edited?.Status is { } status)
Post.Status = status;
}
async Task Replied(FeedPost reply)
{
isReplying = false;