[backend/razor] Add polls to public preview notes
This commit is contained in:
parent
5f99f1d055
commit
66f3b23e46
4 changed files with 110 additions and 3 deletions
|
@ -28,13 +28,15 @@ public class NoteRenderer(
|
||||||
var emoji = await GetEmojiAsync(allNotes);
|
var emoji = await GetEmojiAsync(allNotes);
|
||||||
var users = await GetUsersAsync(allNotes);
|
var users = await GetUsersAsync(allNotes);
|
||||||
var attachments = await GetAttachmentsAsync(allNotes);
|
var attachments = await GetAttachmentsAsync(allNotes);
|
||||||
|
var polls = await GetPollsAsync(allNotes);
|
||||||
|
|
||||||
return await RenderAsync(note, users, mentions, emoji, attachments);
|
return await RenderAsync(note, users, mentions, emoji, attachments, polls);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<PreviewNote> RenderAsync(
|
private async Task<PreviewNote> RenderAsync(
|
||||||
Note note, List<PreviewUser> users, Dictionary<string, List<Note.MentionedUser>> mentions,
|
Note note, List<PreviewUser> users, Dictionary<string, List<Note.MentionedUser>> mentions,
|
||||||
Dictionary<string, List<Emoji>> emoji, Dictionary<string, List<PreviewAttachment>?> attachments
|
Dictionary<string, List<Emoji>> emoji, Dictionary<string, List<PreviewAttachment>?> attachments,
|
||||||
|
Dictionary<string, PreviewPoll> polls
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var renderedText = await mfm.RenderAsync(note.Text, note.User.Host, mentions[note.Id], emoji[note.Id], "span", attachments[note.Id]);
|
var renderedText = await mfm.RenderAsync(note.Text, note.User.Host, mentions[note.Id], emoji[note.Id], "span", attachments[note.Id]);
|
||||||
|
@ -49,6 +51,7 @@ public class NoteRenderer(
|
||||||
QuoteUrl = note.Renote?.Url ?? note.Renote?.Uri ?? note.Renote?.GetPublicUriOrNull(instance.Value),
|
QuoteUrl = note.Renote?.Url ?? note.Renote?.Uri ?? note.Renote?.GetPublicUriOrNull(instance.Value),
|
||||||
QuoteInaccessible = note.Renote?.VisibilityIsPublicOrHome == false,
|
QuoteInaccessible = note.Renote?.VisibilityIsPublicOrHome == false,
|
||||||
Attachments = attachments[note.Id]?.Where(p => !inlineMediaUrls.Contains(p.Url)).ToList(),
|
Attachments = attachments[note.Id]?.Where(p => !inlineMediaUrls.Contains(p.Url)).ToList(),
|
||||||
|
Poll = polls.GetValueOrDefault(note.Id),
|
||||||
CreatedAt = note.CreatedAt.ToDisplayStringTz(),
|
CreatedAt = note.CreatedAt.ToDisplayStringTz(),
|
||||||
UpdatedAt = note.UpdatedAt?.ToDisplayStringTz()
|
UpdatedAt = note.UpdatedAt?.ToDisplayStringTz()
|
||||||
};
|
};
|
||||||
|
@ -112,6 +115,24 @@ public class NoteRenderer(
|
||||||
.ToList());
|
.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<Dictionary<string, PreviewPoll>> GetPollsAsync(List<Note> notes)
|
||||||
|
{
|
||||||
|
if (notes is []) return new Dictionary<string, PreviewPoll>();
|
||||||
|
var ids = notes.Select(p => p.Id).ToList();
|
||||||
|
var polls = await db.Polls
|
||||||
|
.Where(p => ids.Contains(p.NoteId))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return polls.ToDictionary(p => p.NoteId,
|
||||||
|
p => new PreviewPoll
|
||||||
|
{
|
||||||
|
ExpiresAt = p.ExpiresAt,
|
||||||
|
Multiple = p.Multiple,
|
||||||
|
Choices = p.Choices.Zip(p.Votes).Select(c => (c.First, c.Second)).ToList(),
|
||||||
|
VotersCount = p.VotersCount
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<List<PreviewNote>> RenderManyAsync(List<Note> notes)
|
public async Task<List<PreviewNote>> RenderManyAsync(List<Note> notes)
|
||||||
{
|
{
|
||||||
if (notes is []) return [];
|
if (notes is []) return [];
|
||||||
|
@ -120,7 +141,8 @@ public class NoteRenderer(
|
||||||
var mentions = await GetMentionsAsync(allNotes);
|
var mentions = await GetMentionsAsync(allNotes);
|
||||||
var emoji = await GetEmojiAsync(allNotes);
|
var emoji = await GetEmojiAsync(allNotes);
|
||||||
var attachments = await GetAttachmentsAsync(allNotes);
|
var attachments = await GetAttachmentsAsync(allNotes);
|
||||||
return await notes.Select(p => RenderAsync(p, users, mentions, emoji, attachments))
|
var polls = await GetPollsAsync(allNotes);
|
||||||
|
return await notes.Select(p => RenderAsync(p, users, mentions, emoji, attachments, polls))
|
||||||
.AwaitAllAsync()
|
.AwaitAllAsync()
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ public class PreviewNote
|
||||||
public required string? QuoteUrl;
|
public required string? QuoteUrl;
|
||||||
public required bool QuoteInaccessible;
|
public required bool QuoteInaccessible;
|
||||||
public required List<PreviewAttachment>? Attachments;
|
public required List<PreviewAttachment>? Attachments;
|
||||||
|
public required PreviewPoll? Poll;
|
||||||
public required string CreatedAt;
|
public required string CreatedAt;
|
||||||
public required string? UpdatedAt;
|
public required string? UpdatedAt;
|
||||||
}
|
}
|
||||||
|
@ -23,3 +24,11 @@ public class PreviewAttachment
|
||||||
public required string? Alt;
|
public required string? Alt;
|
||||||
public required bool Sensitive;
|
public required bool Sensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PreviewPoll
|
||||||
|
{
|
||||||
|
public required DateTime? ExpiresAt { get; set; }
|
||||||
|
public required bool Multiple { get; set; }
|
||||||
|
public required List<(string Value, int Votes)> Choices { get; set; }
|
||||||
|
public required int? VotersCount { get; set; }
|
||||||
|
}
|
|
@ -30,6 +30,33 @@ else
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_note.Poll != null)
|
||||||
|
{
|
||||||
|
var total = _note.Poll.Choices.Sum(p => p.Votes);
|
||||||
|
|
||||||
|
<div class="poll-results">
|
||||||
|
@foreach (var choice in _note.Poll.Choices)
|
||||||
|
{
|
||||||
|
var percentage = Math.Floor(choice.Votes / (double)total * 100);
|
||||||
|
|
||||||
|
<span class="poll-result" style="--percentage: @percentage%;">
|
||||||
|
<span class="poll-value">@choice.Value</span>
|
||||||
|
<span class="poll-info"><span class="vote-count">@choice.Votes votes</span><span class="vote-percentage">@percentage%</span></span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
List<string> footerText = [];
|
||||||
|
@if (_note.Poll.Multiple)
|
||||||
|
footerText.Add("Multiple choice");
|
||||||
|
@if (_note.Poll.VotersCount != null)
|
||||||
|
footerText.Add($"{_note.Poll.VotersCount} users voted");
|
||||||
|
@if (_note.Poll.ExpiresAt != null)
|
||||||
|
footerText.Add(_note.Poll.ExpiresAt <= DateTime.UtcNow ? "Ended" : $"Ends at {_note.Poll.ExpiresAt.Value.ToLocalTime():G}");
|
||||||
|
|
||||||
|
<span>@string.Join(" - ", footerText)</span>
|
||||||
|
}
|
||||||
|
|
||||||
if (!ShowMedia && _note.Attachments != null)
|
if (!ShowMedia && _note.Attachments != null)
|
||||||
{
|
{
|
||||||
<p>
|
<p>
|
||||||
|
|
49
Iceshrimp.Backend/Pages/NotePreview.razor.css
Normal file
49
Iceshrimp.Backend/Pages/NotePreview.razor.css
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
.poll-results {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-result {
|
||||||
|
--percentage: 0%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
padding: 0.2rem 0.5rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background: linear-gradient(to right, var(--selection) var(--percentage), var(--background) var(--percentage), var(--background));
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-value {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-wrap: wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-info {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vote-count, .vote-percentage {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vote-count {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
font-size: 0.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.poll-result {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vote-count {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue