[frontend] Interactive scroller for note attachments!
This commit is contained in:
parent
ab91c20ae8
commit
ac98be4f86
10 changed files with 215 additions and 9 deletions
91
Iceshrimp.Frontend/Components/AttachmentView.razor
Normal file
91
Iceshrimp.Frontend/Components/AttachmentView.razor
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
Iceshrimp.Frontend/Components/AttachmentView.razor.css
Normal file
60
Iceshrimp.Frontend/Components/AttachmentView.razor.css
Normal 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;
|
||||||
|
}
|
18
Iceshrimp.Frontend/Components/AttachmentView.razor.js
Normal file
18
Iceshrimp.Frontend/Components/AttachmentView.razor.js
Normal 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
|
||||||
|
}
|
20
Iceshrimp.Frontend/Components/NoteAttachments.razor
Normal file
20
Iceshrimp.Frontend/Components/NoteAttachments.razor
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
16
Iceshrimp.Frontend/Components/NoteAttachments.razor.css
Normal file
16
Iceshrimp.Frontend/Components/NoteAttachments.razor.css
Normal 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;
|
||||||
|
}
|
5
Iceshrimp.Frontend/Components/NoteAttachments.razor.js
Normal file
5
Iceshrimp.Frontend/Components/NoteAttachments.razor.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export class NoteAttachments {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
window.NoteAttachments = NoteAttachments;
|
|
@ -1,4 +1,3 @@
|
||||||
@using Iceshrimp.Frontend.Pages
|
|
||||||
@using Iceshrimp.Shared.Schemas
|
@using Iceshrimp.Shared.Schemas
|
||||||
|
|
||||||
@if (NoteBase.Cw != null)
|
@if (NoteBase.Cw != null)
|
||||||
|
@ -33,12 +32,10 @@
|
||||||
}
|
}
|
||||||
@if (NoteBase.Attachments.Count > 0)
|
@if (NoteBase.Attachments.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var element in NoteBase.Attachments)
|
<NoteAttachments Attachments="NoteBase.Attachments"/>
|
||||||
{
|
|
||||||
<img class="attachment" src="@element.Url"/>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter] public required NoteBase NoteBase { get; set; }
|
[Parameter] public required NoteBase NoteBase { get; set; }
|
||||||
[Parameter] public required bool OverLength { get; set; }
|
[Parameter] public required bool OverLength { get; set; }
|
||||||
|
|
|
@ -24,6 +24,3 @@
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.attachment {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
|
@ -68,6 +68,8 @@ menu {
|
||||||
|
|
||||||
dialog {
|
dialog {
|
||||||
border: 0;
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
|
|
Loading…
Add table
Reference in a new issue