[frontend] Interactive scroller for note attachments!

This commit is contained in:
Lilian 2024-04-24 03:20:55 +02:00
parent ab91c20ae8
commit ac98be4f86
No known key found for this signature in database
GPG key ID: 007CA12D692829E1
10 changed files with 215 additions and 9 deletions

View file

@ -0,0 +1,91 @@
@using Iceshrimp.Shared.Schemas
@using Iceshrimp.Assets.PhosphorIcons
@inject IJSRuntime Js
<dialog class="attachment-view" @ref="Dialog">
<button @onclick="CloseDialog" class="close"><Icon Name="Icons.X" Size="5rem"></Icon></button>
@if (Focused < _refs.Count -1 )
{
<button @onclick="Next" class="next"><Icon Name="Icons.ArrowRight" Size="5rem"></Icon></button>
}
@if (Focused > 0)
{
<button @onclick="Prev" class="prev"><Icon Name="Icons.ArrowLeft" Size="5rem"></Icon></button>
}
<div class="wrap" @ref="Scroller" @onscroll="Scroll">
@foreach (var element in Attachments)
{
<div class="container" @ref="@Ref">
<img class="attachment" src="@element.Url" alt="@element.AltText"/>
</div>
}
</div>
</dialog>
@code {
[Parameter][EditorRequired] public IList<NoteAttachment> Attachments { get; set; }
private ElementReference Dialog { get; set; }
private IJSObjectReference? Module { get; set; }
private int Focused { get; set; }
private List<ElementReference> _refs = [];
public ElementReference Ref { set => _refs.Add(value); }
private ElementReference Scroller { get; set; }
private int ScrollWidth { get; set; }
private int ScrollLeft { get; set; }
protected override void OnParametersSet()
{
Focused = 0;
}
private async Task Scroll()
{
// This should probably be moved to floating point.
// So the state transition happens sooner, i.e. at 2.5 vs 3?
ScrollLeft = await Module.InvokeAsync<int>("getScrollLeft", Scroller);
var fraction = ScrollWidth / _refs.Count;
var section = ScrollLeft / fraction;
Focused = section;
}
private async Task Next()
{
if (Focused >= _refs.Count)
{
return;
}
Focused += 1;
await Module.InvokeVoidAsync("scrollTo", _refs[Focused]);
}
private async Task Prev()
{
if (Focused <= 0)
{
return;
}
Focused -= 1;
await Module.InvokeVoidAsync("scrollTo", _refs[Focused]);
}
public async Task OpenDialog()
{
await Module.InvokeVoidAsync("openDialog", Dialog);
ScrollWidth = await Module.InvokeAsync<int>("getScrollWidth", Scroller);
}
private async Task CloseDialog()
{
await Module.InvokeVoidAsync("closeDialog", Dialog);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
Module = await Js.InvokeAsync<IJSObjectReference>("import",
"./Components/AttachmentView.razor.js");
}
}
}

View file

@ -0,0 +1,60 @@
.attachment-view {
background-color: transparent;
max-height: 100vh;
max-width: 100vw;
}
.container {
display: flex;
flex: 0 0 auto;
width: 100%;
height: 100%;
scroll-snap-align: center;
justify-content: center;
align-content: center;
background-color: transparent;
}
.attachment {
max-width: 85%;
max-height: 85%;
object-fit: contain;
margin: auto;
}
.wrap {
background-color: transparent;
scroll-snap-type: x mandatory;
width: 100vw;
height: 100vh;
display: flex;
overflow: scroll;
flex-wrap: nowrap;
}
::backdrop{
opacity: 50%;
background-color: black;
}
.close{
position: absolute;
top: 0%;
right: 0%;
background-color: transparent;
color: white;
}
.next {
position: absolute;
top: 50%;
right: 0%;
background-color: transparent;
color: white;
}
.prev {
position: absolute;
top: 50%;
left: 0%;
background-color: transparent;
color: white;
}

View file

@ -0,0 +1,18 @@
export function openDialog(element){
element.showModal()
}
export function closeDialog(element){
element.close()
}
export function scrollTo(element) {
element.scrollIntoView()
}
export function getScrollLeft(element){
return element.scrollLeft
}
export function getScrollWidth(element){
return element.scrollWidth
}

View file

@ -0,0 +1,20 @@
@using Iceshrimp.Shared.Schemas
<div class="attachment-container">
@foreach (var element in Attachments)
{
<div class="wrapper" @onclick="Open">
<img class="attachment" src="@element.Url" alt="@element.AltText"/>
</div>
}
<AttachmentView @ref="View" Attachments="Attachments"></AttachmentView>
</div>
@code {
[Parameter] [EditorRequired] public IList<NoteAttachment> Attachments { get; set; }
private AttachmentView View { get; set; }
private void Open()
{
View.OpenDialog();
}
}

View file

@ -0,0 +1,16 @@
.attachment {
max-width: 100%;
object-fit: contain;
max-height: 25rem;
border-radius: 0.5rem;
}
.wrapper {
flex: 1 1 48%;
margin-right: 0.2em;
margin-left: 0.2em;
text-align: center;
}
.attachment-container {
display: flex;
flex-wrap: wrap;
}

View file

@ -0,0 +1,5 @@
export class NoteAttachments {
}
window.NoteAttachments = NoteAttachments;

View file

@ -1,4 +1,3 @@
@using Iceshrimp.Frontend.Pages
@using Iceshrimp.Shared.Schemas
@if (NoteBase.Cw != null)
@ -33,12 +32,10 @@
}
@if (NoteBase.Attachments.Count > 0)
{
foreach (var element in NoteBase.Attachments)
{
<img class="attachment" src="@element.Url"/>
}
<NoteAttachments Attachments="NoteBase.Attachments"/>
}
@code {
[Parameter] public required NoteBase NoteBase { get; set; }
[Parameter] public required bool OverLength { get; set; }

View file

@ -24,6 +24,3 @@
.hidden {
display: none;
}
.attachment {
max-width: 100%;
}

View file

@ -13,4 +13,4 @@
}
.like-count{
margin-left: 0.3em;
}
}

View file

@ -68,6 +68,8 @@ menu {
dialog {
border: 0;
margin: 0;
padding: 0;
}
button {