75 lines
2.9 KiB
Plaintext
75 lines
2.9 KiB
Plaintext
@inherits LocalizableComponentBase
|
|||
|
|
|
||
|
|
@* A post's pictures, one at a time, in the app (a picture used to open its file in a new tab, leaving it): the whole
|
||
|
|
screen on a phone, a large dialog from md, with its alt text, the previous and next one (buttons, or the arrow
|
||
|
|
keys), and the original in a new tab for whoever wants the file. *@
|
||
|
|
<DModal Placement="DModalPlacement.ResponsiveBottom" IsOpen="true" IsOpenChanged="Closed" CloseText="@Localizer["Close"]"
|
||
|
|
BoxClass="w-full max-w-none h-dvh max-h-dvh rounded-none p-3 md:h-auto md:max-h-[90dvh] md:max-w-5xl md:rounded-box md:p-4" data-media-viewer>
|
||
|
|
<Heading>
|
||
|
|
<span class="text-sm font-normal opacity-70">@Localizer["Picture {0} of {1}", index + 1, Pictures.Count]</span>
|
||
|
|
</Heading>
|
||
|
|
<ChildContent>
|
||
|
|
<div class="flex flex-col gap-3 mt-2" @onkeydown="OnKeyDown">
|
||
|
|
<figure class="flex flex-col gap-2 min-h-0">
|
||
|
|
<img alt="@Current.Description" class="w-full max-h-[calc(100dvh-11rem)] md:max-h-[70dvh] object-contain rounded-lg" src="@Current.Url"
|
||
|
|
data-blurhash="@Current.Blurhash" />
|
||
|
|
@if (Current.Description is { Length: > 0 } description)
|
||
|
|
{
|
||
|
|
<figcaption class="text-sm opacity-80 break-words">@description</figcaption>
|
||
|
|
}
|
||
|
|
</figure>
|
||
|
|
<div class="flex items-center justify-between gap-2">
|
||
|
|
@if (Pictures.Count > 1)
|
||
|
|
{
|
||
|
|
<DButton Shape="DButtonShape.Circle" Disabled="index == 0" OnClick="Previous" aria-label="@Localizer["Previous picture"]"
|
||
|
|
title="@Localizer["Previous picture"]" data-picture-previous>
|
||
|
|
<i class="ion-md-arrow-back" aria-hidden="true"></i>
|
||
|
|
</DButton>
|
||
|
|
}
|
||
|
|
<a class="btn btn-sm mx-auto" href="@Current.Url" target="_blank" rel="noopener noreferrer">
|
||
|
|
<i class="ion-md-open" aria-hidden="true"></i>
|
||
|
|
<span>@Localizer["Open original"]</span>
|
||
|
|
</a>
|
||
|
|
@if (Pictures.Count > 1)
|
||
|
|
{
|
||
|
|
<DButton Shape="DButtonShape.Circle" Disabled="index == Pictures.Count - 1" OnClick="Next" aria-label="@Localizer["Next picture"]"
|
||
|
|
title="@Localizer["Next picture"]" data-picture-next>
|
||
|
|
<i class="ion-md-arrow-forward" aria-hidden="true"></i>
|
||
|
|
</DButton>
|
||
|
|
}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</ChildContent>
|
||
|
|
</DModal>
|
||
|
|
|
||
|
|
@code {
|
||
|
|
/// <summary>The post's pictures, in its order.</summary>
|
||
|
|
[Parameter, EditorRequired] public List<MediaAttachment> Pictures { get; set; } = [];
|
||
|
|
/// <summary>The one opened.</summary>
|
||
|
|
[Parameter] public int Start { get; set; }
|
||
|
|
[Parameter] public EventCallback OnClose { get; set; }
|
||
|
|
|
||
|
|
int index;
|
||
|
|
|
||
|
|
MediaAttachment Current => Pictures[Math.Clamp(index, 0, Pictures.Count - 1)];
|
||
|
|
|
||
|
|
protected override void OnInitialized()
|
||
|
|
{
|
||
|
|
index = Math.Clamp(Start, 0, Math.Max(0, Pictures.Count - 1));
|
||
|
|
IsLoading = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Previous() => index = Math.Max(0, index - 1);
|
||
|
|
|
||
|
|
void Next() => index = Math.Min(Pictures.Count - 1, index + 1);
|
||
|
|
|
||
|
|
void OnKeyDown(KeyboardEventArgs e)
|
||
|
|
{
|
||
|
|
if (e.Key == "ArrowLeft")
|
||
|
|
Previous();
|
||
|
|
else if (e.Key == "ArrowRight")
|
||
|
|
Next();
|
||
|
|
}
|
||
|
|
|
||
|
|
Task Closed(bool open) => open ? Task.CompletedTask : OnClose.InvokeAsync();
|
||
|
|
}
|