Lists: made on /lists, read as a tab of the feed
A persona's lists (PrivaPub's /api/v1/lists): made, renamed, given a replies policy and made exclusive on /lists, filled from the accounts it follows (accounts/search?following=true), and read as the feed's Lists tab. A followed account's profile has a Lists menu to put it in or take it out. ListService does the calls; the e2e tests check each step against PrivaPub's own answer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
011bafb6af
commit
e2491de16e
18 files changed
+914
-9
No files matched your search
@@ -1,7 +1,8 @@
|
||||
@inherits LocalizableComponentBase
|
||||
|
||||
@* The feed page's tabs, one per kind of feed, scrolling sideways on narrow screens. Groups adds a choice of the
|
||||
persona's communities and circles, Tag the hashtag being followed. The stats icon shows how the current feed was
|
||||
persona's communities and circles, Lists a choice of its lists (made and filled on /lists), Tag the hashtag being
|
||||
followed. The stats icon shows how the current feed was
|
||||
read; the buttons on the right open the composer and, on narrow screens, the globe. *@
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
@@ -49,6 +50,28 @@
|
||||
</DSelect>
|
||||
}
|
||||
}
|
||||
else if (Filter.TimelineType is TimelineType.Lists)
|
||||
{
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
@if (Lists.Count == 0)
|
||||
{
|
||||
<p class="text-xs opacity-70">@Localizer["This persona has no list yet."]</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<DSelect TValue="string" Size="DSize.Sm" class="w-full sm:w-auto" Value="Filter.ListId" ValueChanged="SelectList" ValueExpression="() => Filter.ListId">
|
||||
<Prefix><i class="ion-md-list"></i></Prefix>
|
||||
<ChildContent>
|
||||
@foreach (var list in Lists)
|
||||
{
|
||||
<option value="@list.Id">@list.Title</option>
|
||||
}
|
||||
</ChildContent>
|
||||
</DSelect>
|
||||
}
|
||||
<a class="btn btn-sm" href="lists"><i class="ion-md-create"></i><span>@Localizer["Manage lists"]</span></a>
|
||||
</div>
|
||||
}
|
||||
else if (Filter.TimelineType is TimelineType.Tag)
|
||||
{
|
||||
<p class="text-sm inline-flex items-center gap-2"><i class="ion-md-pricetag"></i><b>#@Filter.Tag</b></p>
|
||||
@@ -58,6 +81,7 @@
|
||||
@code {
|
||||
[Parameter, EditorRequired] public FeedFilter Filter { get; set; }
|
||||
[Parameter] public List<ViewGroup> Groups { get; set; } = [];
|
||||
[Parameter] public List<MastodonList> Lists { get; set; } = [];
|
||||
[Parameter] public IEnumerable<NerdRow> Stats { get; set; } = [];
|
||||
[Parameter] public bool IsComposing { get; set; }
|
||||
[Parameter] public EventCallback OnCompose { get; set; }
|
||||
@@ -67,7 +91,7 @@
|
||||
static readonly TimelineType[] Always =
|
||||
[
|
||||
TimelineType.Home, TimelineType.Local, TimelineType.Federation, TimelineType.Nearby, TimelineType.Groups, TimelineType.Direct,
|
||||
TimelineType.Notifications, TimelineType.Favourites, TimelineType.Bookmarks
|
||||
TimelineType.Notifications, TimelineType.Favourites, TimelineType.Bookmarks, TimelineType.Lists
|
||||
];
|
||||
|
||||
List<TimelineType> Types => Filter.Tag is { Length: > 0 } ? [.. Always, TimelineType.Tag] : [.. Always];
|
||||
@@ -90,6 +114,14 @@
|
||||
Filter.TimelineType = Types[index];
|
||||
if (Filter.TimelineType is TimelineType.Groups && SelectedGroup is null)
|
||||
Filter.GroupId = Groups.FirstOrDefault()?.Id;
|
||||
if (Filter.TimelineType is TimelineType.Lists && Lists.All(l => l.Id != Filter.ListId))
|
||||
Filter.ListId = Lists.FirstOrDefault()?.Id;
|
||||
await OnChanged.InvokeAsync(Filter);
|
||||
}
|
||||
|
||||
async Task SelectList(string listId)
|
||||
{
|
||||
Filter.ListId = listId;
|
||||
await OnChanged.InvokeAsync(Filter);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user