107 lines
4.0 KiB
Plaintext
107 lines
4.0 KiB
Plaintext
@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
|
||
|
|
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">
|
||
|
|
<div class="flex-1 min-w-0 overflow-x-auto">
|
||
|
|
<DTabs Active="ActiveIndex" ActiveChanged="Select" Variant="DTabsVariant.Box" Size="DSize.Sm" ContentClass="hidden" class="flex-nowrap w-max">
|
||
|
|
@foreach (var type in Types)
|
||
|
|
{
|
||
|
|
<DTab Class="gap-1 whitespace-nowrap">
|
||
|
|
<Header>
|
||
|
|
<i class="@type.GetTimelineTypeIcon()" aria-hidden="true"></i>
|
||
|
|
<span class="@(type == Filter.TimelineType ? null : "hidden xl:inline")">@TabName(type)</span>
|
||
|
|
</Header>
|
||
|
|
</DTab>
|
||
|
|
}
|
||
|
|
</DTabs>
|
||
|
|
</div>
|
||
|
|
<NerdTip Heading="@Localizer["Feed"]" Rows="Stats" Placement="DTooltipPlacement.Bottom" Align="DTooltipAlign.End">
|
||
|
|
<i class="ion-md-stats opacity-50" aria-label="@Localizer["Feed"]"></i>
|
||
|
|
</NerdTip>
|
||
|
|
<DButton Size="DSize.Sm" class="lg:hidden" Active="Filter.ShowGlobe" OnClick="ToggleGlobe" title="@Localizer["Globe"]">
|
||
|
|
<i class="ion-md-planet text-base"></i>
|
||
|
|
</DButton>
|
||
|
|
<DButton Size="DSize.Sm" Active="IsComposing" OnClick="() => OnCompose.InvokeAsync()" title="@Localizer["Post"]">
|
||
|
|
<i class="ion-md-create text-base"></i>
|
||
|
|
<span class="hidden sm:inline">@Localizer["Post"]</span>
|
||
|
|
</DButton>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
@if (Filter.TimelineType is TimelineType.Groups)
|
||
|
|
{
|
||
|
|
@if (Groups.Count == 0)
|
||
|
|
{
|
||
|
|
<p class="text-xs opacity-70">@Localizer["This persona is in no community or circle yet."]</p>
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
<DSelect TValue="string" Size="DSize.Sm" class="w-full sm:w-auto" Value="Filter.GroupId" ValueChanged="SelectGroup" ValueExpression="() => Filter.GroupId">
|
||
|
|
<Prefix><i class="@(SelectedGroup?.IsCommunity == false ? "ion-md-lock" : "ion-md-contacts")"></i></Prefix>
|
||
|
|
<ChildContent>
|
||
|
|
@foreach (var group in Groups)
|
||
|
|
{
|
||
|
|
<option value="@group.Id">@(group.IsCommunity ? "◎" : "◉") @(group.Name ?? group.UserName)</option>
|
||
|
|
}
|
||
|
|
</ChildContent>
|
||
|
|
</DSelect>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
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>
|
||
|
|
}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
@code {
|
||
|
|
[Parameter, EditorRequired] public FeedFilter Filter { get; set; }
|
||
|
|
[Parameter] public List<ViewGroup> Groups { get; set; } = [];
|
||
|
|
[Parameter] public IEnumerable<NerdRow> Stats { get; set; } = [];
|
||
|
|
[Parameter] public bool IsComposing { get; set; }
|
||
|
|
[Parameter] public EventCallback OnCompose { get; set; }
|
||
|
|
/// <summary>Raised after Filter changed (tab, group or globe).</summary>
|
||
|
|
[Parameter] public EventCallback<FeedFilter> OnChanged { get; set; }
|
||
|
|
|
||
|
|
static readonly TimelineType[] Always =
|
||
|
|
[
|
||
|
|
TimelineType.Home, TimelineType.Local, TimelineType.Federation, TimelineType.Nearby, TimelineType.Groups, TimelineType.Direct,
|
||
|
|
TimelineType.Notifications, TimelineType.Favourites, TimelineType.Bookmarks
|
||
|
|
];
|
||
|
|
|
||
|
|
List<TimelineType> Types => Filter.Tag is { Length: > 0 } ? [.. Always, TimelineType.Tag] : [.. Always];
|
||
|
|
|
||
|
|
int ActiveIndex => Types.IndexOf(Filter.TimelineType);
|
||
|
|
|
||
|
|
ViewGroup SelectedGroup => Groups.FirstOrDefault(g => g.Id == Filter.GroupId);
|
||
|
|
|
||
|
|
protected override void OnInitialized() => IsLoading = false;
|
||
|
|
|
||
|
|
string TabName(TimelineType type) => type switch
|
||
|
|
{
|
||
|
|
TimelineType.Federation => Localizer["Federated"],
|
||
|
|
TimelineType.Tag => "#" + Filter.Tag,
|
||
|
|
_ => Localizer[type.ToString()]
|
||
|
|
};
|
||
|
|
|
||
|
|
async Task Select(int index)
|
||
|
|
{
|
||
|
|
Filter.TimelineType = Types[index];
|
||
|
|
if (Filter.TimelineType is TimelineType.Groups && SelectedGroup is null)
|
||
|
|
Filter.GroupId = Groups.FirstOrDefault()?.Id;
|
||
|
|
await OnChanged.InvokeAsync(Filter);
|
||
|
|
}
|
||
|
|
|
||
|
|
async Task SelectGroup(string groupId)
|
||
|
|
{
|
||
|
|
Filter.GroupId = groupId;
|
||
|
|
await OnChanged.InvokeAsync(Filter);
|
||
|
|
}
|
||
|
|
|
||
|
|
async Task ToggleGlobe()
|
||
|
|
{
|
||
|
|
Filter.ShowGlobe = !Filter.ShowGlobe;
|
||
|
|
await OnChanged.InvokeAsync(Filter);
|
||
|
|
}
|
||
|
|
}
|