diff --git a/Iceshrimp.Frontend/Components/Compose.razor b/Iceshrimp.Frontend/Components/Compose.razor
index 8be5430f..bc8a7690 100644
--- a/Iceshrimp.Frontend/Components/Compose.razor
+++ b/Iceshrimp.Frontend/Components/Compose.razor
@@ -63,6 +63,9 @@
Upload!
+
@@ -113,6 +116,61 @@
}
}
+ @if (NoteDraft.Poll != null)
+ {
+
+
+
+
+
+
+
+
+
+ @switch (PollExpires)
+ {
+ case PollExpire.Never:
+ break;
+ case PollExpire.ExpiresAt:
+
+ break;
+ case PollExpire.ExpiresAfter:
+
+
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+
+ }
@if (Preview)
{
@@ -147,6 +205,12 @@
private bool SendLock { get; set; } = false;
private int UploadingFiles { get; set; }
private string? AttachedQuote { get; set; }
+ private List PollChoices { get; set; } = [];
+ private string PollEntry { get; set; } = "";
+ private PollExpire PollExpires { get; set; }
+ private DateTime PollExpireTime { get; set; }
+ private int PollExpireLen { get; set; }
+ private PollExpireAfter PollExpiresAft { get; set; }
private NoteCreateRequest NoteDraft { get; set; } = new()
{
@@ -157,6 +221,25 @@
private Dictionary AvailablePlaceholders { get; set; } = new() { { "default", "What's on your mind?" }, { "reply", "Reply goes here!" }, { "quote", "Quote this post!" } };
+ private class Choice
+ {
+ public required string Value { get; set; }
+ }
+
+ private enum PollExpire
+ {
+ Never,
+ ExpiresAt,
+ ExpiresAfter
+ }
+
+ private enum PollExpireAfter
+ {
+ Minutes,
+ Hours,
+ Days,
+ }
+
private bool SendingDisabled() =>
NoteLength - ((NoteDraft.Cw?.Length ?? 0) + NoteDraft.Text.Length) < 0 || UploadingFiles != 0;
@@ -317,6 +400,24 @@
}
NoteDraft.RenoteId ??= AttachedQuote;
+
+ if (NoteDraft.Poll != null)
+ {
+ NoteDraft.Poll.Choices = PollChoices.Select(p => p.Value).ToList();
+ NoteDraft.Poll.ExpiresAt = PollExpires switch
+ {
+ PollExpire.ExpiresAt => PollExpireTime.ToUniversalTime(),
+ PollExpire.ExpiresAfter => PollExpiresAft switch
+ {
+ PollExpireAfter.Minutes => DateTime.UtcNow.AddMinutes(Math.Min(PollExpireLen, 5)),
+ PollExpireAfter.Hours => DateTime.UtcNow.AddHours(Math.Min(PollExpireLen, 1)),
+ PollExpireAfter.Days => DateTime.UtcNow.AddDays(Math.Min(PollExpireLen, 1)),
+ _ => throw new ArgumentOutOfRangeException()
+ },
+ _ => null
+ };
+ }
+
try
{
await ApiService.Notes.CreateNoteAsync(NoteDraft);
@@ -339,6 +440,29 @@
SendButton.State = StateButton.StateEnum.Initial;
// FIXME: Implement timeline refresh and call it here.
}
+
+ private void TogglePoll()
+ {
+ if (NoteDraft.Poll != null)
+ {
+ NoteDraft.Poll = null;
+ }
+ else
+ {
+ NoteDraft.Poll = new PollRequest
+ {
+ ExpiresAt = null,
+ Multiple = false,
+ Choices = []
+ };
+ PollChoices = [];
+ PollEntry = "";
+ PollExpires = PollExpire.Never;
+ PollExpireTime = DateTime.Now;
+ PollExpireLen = 7;
+ PollExpiresAft = PollExpireAfter.Days;
+ }
+ }
private void ToggleCw()
{
@@ -361,6 +485,17 @@
StateHasChanged();
}
+ private void AddPollChoice()
+ {
+ PollChoices.Add(new Choice { Value = PollEntry });
+ PollEntry = "";
+ }
+
+ private void DeletePollChoice(Choice choice)
+ {
+ PollChoices.Remove(choice);
+ }
+
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
diff --git a/Iceshrimp.Frontend/Components/Compose.razor.css b/Iceshrimp.Frontend/Components/Compose.razor.css
index ccdbf5c6..d90c5ec4 100644
--- a/Iceshrimp.Frontend/Components/Compose.razor.css
+++ b/Iceshrimp.Frontend/Components/Compose.razor.css
@@ -19,6 +19,35 @@
resize: vertical;
}
+.poll .choice {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+
+ .input {
+ width: 100%;
+ }
+}
+
+.poll .expire {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: 0.5em;
+ align-items: end;
+ margin-top: 0.5em;
+
+ select {
+ margin-bottom: 0;
+ margin-left: 0;
+ margin-right: 0;
+ }
+}
+
+input[type="checkbox"] {
+ display: inline-block;
+}
+
.compose .attachments {
display: flex;
flex-wrap: wrap;