Files
decePubClient/Components/Feed/FeedTabs.razor
T

107 lines
4.0 KiB
Plaintext
Raw Normal View History

@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);
}
}